学习自https://cloud.tencent.com/developer/article/1452451
现在是晚上22点,刚刚和我们的前端交流完了富文本编辑器的一些意见和看法
还是老样子
需求
我们的团队官网需要不定期发布团队视频,团队风采以及团队获奖情况等,第一版的时候,我的数据库还是以普通的文本模式做的,比如视频url,图片url都有,但是前端已经使用富文本编辑器进行整体的保存,这样我的一些属性就处于没有用的状态,同时这样做,那些属性却依旧需要修改,他特别是更改头像和视频的时候,这就太麻烦和重复了。另外,前端应该也不是太会,当时是整体,连同资源本身传过来的,我甚至只能用longtext来存储,这样查询的时候也是特别的慢.另外当时的资源也是存储在服务器上,而且不是网络资源,需要首先读取,这样在播放和swagger文档查询的时候就非常缓慢了。所以现在准备重做第二版,实现的方案也优化一下,选择富文本编辑器以及阿里云OSS共同实现。
实现
- 下载链接
我选择的是Ueditor,因为比较好(主要是大家都在用),但是第一版的时候前端他们用的是wangeditor。这里先不管了
官网链接:
ueditor
选择最新版(已经停止更新了)jSP+UTF-8
下载解压效果图,文件名
这个时候用浏览器打开index.html应该可以看到效果
- 集成到Spring Boot项目中
我是直接把文件复制到resource文件夹之中
同时把index.html放到templates中
网上一般的教程,只要导入到项目中,然后运行就可以看到主页的内容
但是我集成了Spring Security Oauth2以及发现缺少Ueditor依赖所以还要做很多东西
- 集成Ueditor依赖
<!--Ueditor依赖的jar包-->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
<dependency>
<groupId>com.gitee.qdbp.thirdparty</groupId>
<artifactId>ueditor</artifactId>
<version>1.4.3.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
其中Ueditor依赖因为官放没有集成,使用的是一个私人的把
其他commons开头的关于文件的尽量与jar/lib的版本保持一致
- 解决Spring Security 静态资源拒绝访问问题
- 首先配置忽略资源访问限制
//开启全局方法验证
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class GlobalMethodSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**");
}
}
因为我这是一个oss的资源服务器,所以新建一个Security配置类
2. 然后设置资源映射
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 配置静态资源
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
//super.addResourceHandlers(registry);
}
}
- 设置全局跨域许可
我设置完静态资源后,依旧显示401,这让我就结了很久,最后发现是跨域问题
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedOrigins("*")
.allowedMethods("*");
}}
- 解决控制台报错
Refused to display ‘http://localhost/xxxx’ in a frame because it…
http.headers().frameOptions().disable();
- 运行程序已经能够正常访问
但是上传文件显示
这张图我是直接拿了别人的
开始解决文件上传问题
- 创建Ueditor对象
package cn.hcnet2006.blog.hcnetwebsite.ueditor;
public class Ueditor {
private String state;
private String url;
private String title;
private String original;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getOriginal() {
return original;
}
public void setOriginal(String original) {
this.original = original;
}
}
- 创建PublicMsg类,替代config.json
package cn.hcnet2006.blog.hcnetwebsite.ueditor;
public class PublicMsg {
public final static String UEDITOR_CONFIG = "{\n" +
" \"imageActionName\": \"uploadimage\",\n" +
" \"imageFieldName\": \"upfile\",\n" +
" \"imageMaxSize\": 2048000,\n" +
" \"imageAllowFiles\": [\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"],\n" +
" \"imageCompressEnable\": true,\n" +
" \"imageCompressBorder\": 1600,\n" +
" \"imageInsertAlign\": \"none\",\n" +
" \"imageUrlPrefix\": \"\",\n" +
" \"imagePathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\",\n" +
"\n" +
" \"scrawlActionName\": \"uploadscrawl\",\n" +
" \"scrawlFieldName\": \"upfile\",\n" +
" \"scrawlPathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\",\n" +
" \"scrawlMaxSize\": 2048000,\n" +
" \"scrawlUrlPrefix\": \"\",\n" +
" \"scrawlInsertAlign\": \"none\",\n" +
"\n" +
" \"snapscreenActionName\": \"uploadimage\",\n" +
" \"snapscreenPathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\",\n" +
" \"snapscreenUrlPrefix\": \"\",\n" +
" \"snapscreenInsertAlign\": \"none\",\n" +
"\n" +
" \"catcherLocalDomain\": [\"127.0.0.1\", \"localhost\", \"img.baidu.com\"],\n" +
" \"catcherActionName\": \"catchimage\",\n" +
" \"catcherFieldName\": \"source\",\n" +
" \"catcherPathFormat\": \"/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}\",\n" +
" \"catcherUrlPrefix\": \"\",\n" +
" \"catcherMaxSize\": 2048000,\n" +
" \"catcherAllowFiles\": [\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"],\n" +
"\n" +
" \"videoActionName\": \"uploadvideo\",\n" +
" \"videoFieldName\": \"upfile\",\n" +
" \"videoPathFormat\": \"/ueditor/jsp/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}\",\n" +
" \"videoUrlPrefix\": \"\",\n" +
" \"videoMaxSize\": 102400000,\n" +
" \"videoAllowFiles\": [\n" +
" \".flv\", \".swf\", \".mkv\", \".avi\", \".rm\", \".rmvb\", \".mpeg\", \".mpg\",\n" +
" \".ogg\", \".ogv\", \".mov\", \".wmv\", \".mp4\", \".webm\", \".mp3\", \".wav\", \".mid\"],\n" +
"\n" +
" \"fileActionName\": \"uploadfile\",\n" +
" \"fileFieldName\": \"upfile\",\n" +
" \"filePathFormat\": \"/ueditor/jsp/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}\",\n" +
" \"fileUrlPrefix\": \"\",\n" +
" \"fileMaxSize\": 51200000,\n" +
" \"fileAllowFiles\": [\n" +
" \".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\",\n" +
" \".flv\", \".swf\", \".mkv\", \".avi\", \".rm\", \".rmvb\", \".mpeg\", \".mpg\",\n" +
" \".ogg\", \".ogv\", \".mov\", \".wmv\", \".mp4\", \".webm\", \".mp3\", \".wav\", \".mid\",\n" +
" \".rar\", \".zip\", \".tar\", \".gz\", \".7z\", \".bz2\", \".cab\", \".iso\",\n" +
" \".doc\", \".docx\", \".xls\", \".xlsx\", \".ppt\", \".pptx\", \".pdf\", \".txt\", \".md\", \".xml\"\n" +
" ],\n" +
"\n" +
" \"imageManagerActionName\": \"listimage\",\n" +
" \"imageManagerListPath\": \"/ueditor/jsp/upload/image/\",\n" +
" \"imageManagerListSize\": 20,\n" +
" \"imageManagerUrlPrefix\": \"\",\n" +
" \"imageManagerInsertAlign\": \"none\",\n" +
" \"imageManagerAllowFiles\": [\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"],\n" +
"\n" +
" \"fileManagerActionName\": \"listfile\",\n" +
" \"fileManagerListPath\": \"/ueditor/jsp/upload/file/\",\n" +
" \"fileManagerUrlPrefix\": \"\",\n" +
" \"fileManagerListSize\": 20,\n" +
" \"fileManagerAllowFiles\": [\n" +
" \".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\",\n" +
" \".flv\", \".swf\", \".mkv\", \".avi\", \".rm\", \".rmvb\", \".mpeg\", \".mpg\",\n" +
" \".ogg\", \".ogv\", \".mov\", \".wmv\", \".mp4\", \".webm\", \".mp3\", \".wav\", \".mid\",\n" +
" \".rar\", \".zip\", \".tar\", \".gz\", \".7z\", \".bz2\", \".cab\", \".iso\",\n" +
" \".doc\", \".docx\", \".xls\", \".xlsx\", \".ppt\", \".pptx\", \".pdf\", \".txt\", \".md\", \".xml\"\n" +
" ] \n" +
"\n" +
"}";
/**
* Ueditor的返回状态类型
*/
public enum UeditorMsg{
SUCCESS("SUCCESS"),ERROR("上传失败");
private String v;
UeditorMsg(String v){
this.v =v;
}
public String get(){
return this.v;
}
}
}
- 在UeditorController上添加获得上传图片的方法
@Controller
public class UeditorController {
@RequestMapping("/")
private String showPage(){
return "index";
}
@RequestMapping(value="/ueditor")
@ResponseBody
public String ueditor(HttpServletRequest request) {
return PublicMsg.UEDITOR_CONFIG;
}
@RequestMapping(value="/imgUpload")
@ResponseBody
public Map<String, Object> images (MultipartFile upfile, HttpServletRequest request, HttpServletResponse response){
Map<String, Object> params = new HashMap<String, Object>();
System.out.println("1111111111111");
try{
String url = ResourceUtils.getURL("").getPath()+upfile.getOriginalFilename();
File folder = new File(url);
upfile.transferTo(folder);
url = OSSUtils.upload(folder, UUID.randomUUID().toString()+upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")));
System.out.println(UUID.randomUUID().toString()+upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")));
folder.delete();
String fileName = upfile.getOriginalFilename();
params.put("state", "SUCCESS");
params.put("url", url);
params.put("size", upfile.getSize());
params.put("original", fileName);
params.put("type", upfile.getContentType());
} catch (Exception e){
params.put("state", "ERROR");
}
return params;
}
}
https://cloud.tencent.com/developer/article/1452451
自己摸索了一下:
window.UEDITOR_CONFIG = {
//为编辑器实例添加一个路径,这个不能被注释
UEDITOR_HOME_URL: URL
// 服务器统一请求接口路径
//, serverUrl: URL + "jsp/controller.jsp"
, serverUrl: "/ueditor"
- 配置Ueditor.config.js
这里有一个坑,不是这样
将:
, serverUrl: URL + "jsp/controller.jsp"
替换为:
, serverUrl: "/ueditor"
而是这样
// 服务器统一请求接口路径
//, serverUrl: URL + "jsp/controller.jsp"
, serverUrl: "/ueditor"
- 设置url控制忽略
没有安全限制可以忽略
.antMatchers("/imgUpload").permitAll()
.antMatchers("/videoUpload").permitAll()
.antMatchers("/ueditor").permitAll()
.antMatchers("/content").permitAll()
到了这里,后端资源就配置完毕
11. 打开index.html进行图片上传设置
var ue = UE.getEditor('editor');
UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;
UE.Editor.prototype.getActionUrl = function(action) {
if (action == 'uploadimage' || action == 'uploadscrawl' || action == 'uploadimage') {
return 'http://localhost:8211/imgUpload';
//'http://localhost:8080/imgUpload';为方法imgUpload的访问地址
else {
return this._bkGetActionUrl.call(this, action);
}
}
运行项目,发现上传正常
12. 设置上传图片返回阿里云OSS链接
@RequestMapping(value="/imgUpload")
@ResponseBody
public Map<String, Object> images (MultipartFile upfile, HttpServletRequest request, HttpServletResponse response){
Map<String, Object> params = new HashMap<String, Object>();
System.out.println("1111111111111");
try{
String url = ResourceUtils.getURL("").getPath()+upfile.getOriginalFilename();
File folder = new File(url);
upfile.transferTo(folder);
url = OSSUtils.upload(folder, UUID.randomUUID().toString()+upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")));
System.out.println(UUID.randomUUID().toString()+upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")));
folder.delete();
String fileName = upfile.getOriginalFilename();
params.put("state", "SUCCESS");
params.put("url", url);
params.put("size", upfile.getSize());
params.put("original", fileName);
params.put("type", upfile.getContentType());
} catch (Exception e){
params.put("state", "ERROR");
}
return params;
}
- 设置富文本表单提交
<div>
<h1>完整demo</h1>
<!-- <script id="editor" type="text/plain" style="width:1024px;height:500px;"></script>-->
<form action="/content" method="post" >
<textarea id="editor" name="content" type="text/plain" style="width:1024px;height:500px;">这里写你的初始化内容</textarea>
<input type="hidden", id="content1" name="content1" >
<button id="btn" onclick="getContent1()">提交</button>
</form>
</div>
- 表单提交设置返回带完全htnl标签与标签两种
//这是我写的,其他的不是
function getContent1(){
var arr = UE.getEditor('editor').getAllHtml();
document.getElementById("content1").value = arr;
//return UE.getEditor('editor').getContent();
}
顺便学了一点JS知识
15. 设置上传视频并返回阿里云OSS链接
- 首先设置index.html
if (action == 'uploadimage' || action == 'uploadscrawl' || action == 'uploadimage') {
return 'http://localhost:8211/imgUpload';
//'http://localhost:8080/imgUpload';为方法imgUpload的访问地址
}else if(action == "uploadvideo"){
return 'http://localhost:8211/videoUpload';
}
else {
return this._bkGetActionUrl.call(this, action);
}
- 设置后端控制层
@RequestMapping(value="/videoUpload")
@ResponseBody
public Map<String, Object> videos (MultipartFile upfile, HttpServletRequest request, HttpServletResponse response){
Map<String, Object> params = new HashMap<String, Object>();
System.out.println("1111111111111");
try{
String url = ResourceUtils.getURL("").getPath()+upfile.getOriginalFilename();
File folder = new File(url);
upfile.transferTo(folder);
url = OSSUtils.upload(folder, UUID.randomUUID().toString()+upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")));
System.out.println(UUID.randomUUID().toString()+upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")));
folder.delete();
String fileName = upfile.getOriginalFilename();
params.put("state", "SUCCESS");
params.put("url", url);
params.put("size", upfile.getSize());
params.put("original", fileName);
params.put("type", upfile.getContentType());
} catch (Exception e){
params.put("state", "ERROR");
}
return params;
}
- 返回富文本内容,并且设置成htnl文件上传到阿里云OSS最后返回链接
@RequestMapping("/content")
@ResponseBody
public String findContent(String content, String content1) throws IOException {
System.out.println("content1:"+content1);
String url = ResourceUtils.getURL("").getPath()+UUID.randomUUID().toString()+".html";
File folder = new File(url);
FileWriter fileWriter = new FileWriter(folder);
fileWriter.write(content1);
fileWriter.flush();
fileWriter.close();
url = OSSUtils.upload(folder,UUID.randomUUID().toString()+".html");
System.out.println("content:"+url);
return url;
}
需要说明只需要《P》标签的文件前端就可以正常显示,并且比带html完整标签的文件小至少10倍。
总结
根据别人的说明和自己的扩展实践(别人的说明啦)主要难题是config。json的路径配置出错,后来通过一个类来存储该json,不使用自带的config.json
- 自己的总结
现在基本的功能搜已经实现了,主要是还是集成在前端比较好,方便交互,后端直接写接口就可以,现在他们应该是在决定用哪一个富文本编辑器以及最终要的把我需要的接口给我