前言
春节无聊,就去弄一下富文本编辑器,然后百度了一番,很多说百度的UEditor不错,然后去官网照着文档弄一遍,是挺简单好用的。然后想把这玩意结合到自己的一个spring项目里面,果然还是在点上传图片的时候GG了,百度谷歌了一遍,现在只能做到前后台一起时上传图片可用,如果有jsp 的 UEditor跨域能上传图片的告诉小弟一声,这里就总结一下这几天遇到的各种问题。
PS:话说博客园这里的富文本编辑器好像还可以。。。。
简介
UEditor是百度开发的一个开源html富文本编辑器,界面的确是好看一点,文档方面还算齐全,虽然跨域上传这块留了个坑让我们发挥想象力ヾ( ̄▽ ̄),所以为了防止UEditor有坑,需要改动UEditor的源码,这里建议下载UEditor的源码放到自己项目里面,UEditor的源码挺简单的,只要跟踪Debug一下很容易可以看出问题。
这里演示的spring项目集成了spring security和Thymeleaf,构建用maven构建,UEditor的后台控制器改成spring mvc的controller,原本想用Servlet,找了很多资料,貌似没看到spring mvc项目可以集成源生Servlet,但是spring boot通过@ServletComponentScan可以注册Servlet,用spring boot集成UEditor最是方便,基本没坑,一路畅通,这一点我已经试过。下面主要说spring项目如何集成UEditor后台。
正文
UEditor的下载安装什么的就不说了,直接上图。
前端文件目录:
把UEditor后台的源码放到自己项目里:
添加UEditor后台的依赖:
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20160810</version> </dependency>
由于我们用spring mvc,所以UEditor的controller.jsp要改成Controller的形式,基本把UEditor的controller代码复制过来就是了。
1 @Controller 2 public class UEditorController { 3 @RequestMapping("/ued/config") 4 public void service(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException { 5 6 request.setCharacterEncoding("utf-8"); 7 response.setHeader("Content-Type" , "text/html"); 8 String rootPath = request.getSession() 9 .getServletContext().getRealPath("/"); 10 11 try { 12 String exec = new ActionEnter(request, rootPath).exec(); 13 PrintWriter writer = response.getWriter(); 14 writer.write(exec); 15 writer.flush(); 16 writer.close(); 17 } catch (IOException e) { 18 e.printStackTrace(); 19 } 20 } 21 22 }
Controller
然后我们改一下UEditor的后台接口,把它改成我们的Controller
到这里,如果我们尝试去用UEditor,会出现找不到后台配置的错误,这是由于默认controller.jsp和config.json是同一目录,UEditor的后台代码无法找到config.json的缘故,这里我们找到UEditor的后台源码里面的ConfigManager,将getConfigPath()方法改一下,这里我是把config.json放到了maven src/main/resources,也就是classpath路径下,如有不同,则相应改变即可。
这样,UEditor算是找到config.json,然而上传图片功能依然不行,这里主要是因为spring mvc在controller注入的request对象和UEditor用的commons-fileupload有冲突,导致commons-fileload无法获取request里面的文件字节流,通过debug(所以说要下载源码),然后我们只需要把com.baidu.ueditor.upload.BinaryUploader类的上传文件方法改一下。
这里我主要改动了关键的FileItemIterator iterator = upload.getItemIterator(request); 尽量保持源码的样子。
public static final State save(HttpServletRequest request, Map<String, Object> conf) { boolean isAjaxUpload = request.getHeader( "X_Requested_With" ) != null; if (!ServletFileUpload.isMultipartContent(request)) { return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT); } ServletFileUpload upload = new ServletFileUpload( new DiskFileItemFactory()); if ( isAjaxUpload ) { upload.setHeaderEncoding( "UTF-8" ); } try { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; MultipartFile multipartFile = multipartRequest.getFile(conf.get("fieldName").toString()); // FileItemIterator iterator = upload.getItemIterator(request); // // while (iterator.hasNext()) { // fileStream = iterator.next(); // // if (!fileStream.isFormField()) // break; // fileStream = null; // } if (multipartFile == null) { return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA); } String savePath = (String) conf.get("savePath"); String originFileName = multipartFile.getOriginalFilename(); String suffix = FileType.getSuffixByFilename(originFileName); originFileName = originFileName.substring(0, originFileName.length() - suffix.length()); savePath = savePath + suffix; long maxSize = ((Long) conf.get("maxSize")).longValue(); if (!validType(suffix, (String[]) conf.get("allowFiles"))) { return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE); } savePath = PathFormat.parse(savePath, originFileName); String physicalPath = (String) conf.get("rootPath") + savePath; InputStream is = multipartFile.getInputStream(); State storageState = StorageManager.saveFileByInputStream(is, physicalPath, maxSize); is.close(); if (storageState.isSuccess()) { storageState.putInfo("url", PathFormat.format(savePath)); storageState.putInfo("type", suffix); storageState.putInfo("original", originFileName + suffix); } return storageState; } catch (IOException e) { } return new BaseState(false, AppInfo.IO_ERROR); } private static boolean validType(String type, String[] allowTypes) { List<String> list = Arrays.asList(allowTypes); return list.contains(type); }
到这里,UEditor能够上传文件了,可能还有一点小坑就是文件保存的路径和返回给前端的路径不太相符,这个大家debug一下,在config.json里面可以修改文件的上传保存路径和返回url前缀等配置,源码在手,有什么错都能自己改一下。另外因为我项目有用spring security,所以response头的X-Frame-Options默认是DENY,这样会时UEditor上传图片的坑爹iframe显示不出图片。这里我试过在Controller那里setHeader,结果前端说X-Frame-Options有两个值,真是日了狗。所以干脆把spring security这个功能关了,大家知道怎么在controller改header值告诉我一声。
http.headers().frameOptions().disable()