SpringBoot+Thymeleaf整合UEditor

1.下载UEditor

UEditor - 下载,将最新版本1.4.3.3的完整源码和Jsp版本UTF-8版本下载下来并解压。
下载UEditor

2.配置pom.xml

项目中配置UEditor的源码需要的jar包

<dependency>
	<groupId>org.json</groupId>
	<artifactId>json</artifactId>
	<version>20180813</version>
</dependency>
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.4</version>
</dependency>
<dependency>
	<groupId>commons-codec</groupId>
	<artifactId>commons-codec</artifactId>
	<version>1.11</version>
</dependency>

3.导入UEditor源码及资源文件

3.1导入源码文件

将解压的完整源码包下的jsp->src目录下的源码拷贝到项目对应包目录下
导入UEditor源码

3.2导入资源文件

将解压的utf8-jsp版本目录下的除jsp目录和index.html文件,其余文件全部导入到resources/static目录下新建的ueditors文件夹中(注:带有s的ueditors文件夹,后续会有说明)。
将目录下的index.html文件拷贝到templates目录下的ueditor文件夹下,根目录下jsp目录中的config.json拷贝到resources根路径下。
UEditor静态资源路径
修改index.html资源引用路径

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>完整demo</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <script type="text/javascript" charset="utf-8" th:src="@{/ueditors/ueditor.config.js}"></script>
    <script type="text/javascript" charset="utf-8" th:src="@{/ueditors/ueditor.all.js}"> </script>
    <!--建议手动加在语言,避免在ie下有时因为加载语言失败导致编辑器加载失败-->
    <!--这里加载的语言文件会覆盖你在配置项目里添加的语言类型,比如你在配置项目里配置的是英文,这里加载的中文,那最后就是中文-->
    <script type="text/javascript" charset="utf-8" th:src="@{/ueditors/lang/zh-cn/zh-cn.js}"></script>

    <style type="text/css">
        div{
            width:100%;
        }
    </style>
</head>

4.自定义Controller访问index.html页面

package com.solang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/ueditor")
public class UEditorController {

    @RequestMapping("/index")
    public String showUeditorPage() {
        return "ueditor/index";
    }
	
}	

5.运行项目并访问路径

由于application.properties配置了项目访问路径前缀

server.servlet.context-path=/ue

访问http://localhost:8080/ue/ueditor/index,跳转到如下界面说明源码已拷贝成功
显示完整demo
此时点击多图上传,发现上传图片功能不能用
多图上传不能正常使用

6.编写加载后端配置项的代码

依据utf8-jsp版本目录下jsp文件夹里的controller.jsp,编写加载后端配置项的代码。

①application.properties文件配置UEditor上传图片视频等存放路径。

# UEditor上传路径地址
web.upload-path=E:/upload/

注:E:后面跟一个/

②在自定义Controller中继续编写代码

package com.solang.controller;

import com.solang.ueditor.ActionEnter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Controller
@RequestMapping("/ueditor")
public class UEditorController {

    @Value("${web.upload-path}")
    private String uploadPath;

    @RequestMapping("/index")
    private String showUeditorPage(){
        return "ueditor/index";
    }

    @RequestMapping(value="/config")
    public void config(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("application/json");
        String rootPath = uploadPath;
        try {
            String exec = new ActionEnter(request, rootPath).exec();
            PrintWriter writer = response.getWriter();
            writer.write(exec);
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

注:此处rootPath是做成可配置的,因为查看UEditor的源码,发现上传图片视频等其实是上传到rootPath目录下的,不用像其它博客写的那样单独定义一个上传的参数。

③加载config.json文件,修改ConfigManage类的getConfigPath()方法

private String getConfigPath () {
		//return this.parentPath + File.separator + ConfigManager.configFileName;
		try {
			//获取classpath下的config.json路径
			return this.getClass().getClassLoader().getResource("config.json").toURI().getPath();
		} catch (URISyntaxException e) {
			return null;
		}
	}

此处需要先转为URI再getPath(),否则如果路径带空格或者带中文则无法读取到文件。

7.配置ueditor.config.js

   /**
    * 编辑器资源文件根路径。它所表示的含义是:以编辑器实例化页面为当前路径,指向编辑器资源文件(即dialog等文件夹)的路径。
    * 鉴于很多同学在使用编辑器的时候出现的种种路径问题,此处强烈建议大家使用"相对于网站根目录的相对路径"进行配置。
    * "相对于网站根目录的相对路径"也就是以斜杠开头的形如"/myProject/ueditor/"这样的路径。
    * 如果站点中有多个不在同一层级的页面需要实例化编辑器,且引用了同一UEditor的时候,此处的URL可能不适用于每个页面的编辑器。
    * 因此,UEditor提供了针对不同页面的编辑器可单独配置的根路径,具体来说,在需要实例化编辑器的页面最顶部写上如下代码即可。当然,需要令此处的URL等于对应的配置。
    * window.UEDITOR_HOME_URL = "/xxxx/xxxx/";
    */
   var URL = window.UEDITOR_HOME_URL || getUEBasePath();

   /**
    * 配置项主体。注意,此处所有涉及到路径的配置别遗漏URL变量。
    */
   window.UEDITOR_CONFIG = {

       //为编辑器实例添加一个路径,这个不能被注释
       UEDITOR_HOME_URL: URL

      // 服务器统一请求接口路径
       , serverUrl: URL + "jsp/controller.jsp"

根据提示推荐使用相对于网站根目录的相对路径的形式,本博客也会使用这种形式。

此处有必要先说明下URL的取值问题以及UEDITOR_HOME_URL和serverUrl的作用。

如果window.UEDITOR_HOME_URL未在页面上定义或者取值为空,那么URL的值取的是getUEBasePath()方法,而这个方法返回的是UEditor的静态资源存放的地址,例如本博客中URL获取的地址就是:http://localhost:8080/ue/ueditors/

UEDITOR_HOME_URL地址其实就是UEditor静态资源文件存放的地址,如果存放静态资源文件的文件夹不是ueditors而是aaa,那么地址就是http://localhost:8080/ue/aaa/。综上所述,其实这个地址可以不用改

serverUrl是服务器统一请求接口路径,其实就是Controller里写的加载config.json配置项的请求接口路径,要改的也是这个serverUrl地址。

修改index.html页面,在引入ueditor.config.js之前配置要获取的项目路径

<!DOCTYPE>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>完整demo</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <script type="text/javascript">
        var ctxPath= "[[${#httpServletRequest.getContextPath()}]]";
        window.CTX = ctxPath;
    </script>
    <script type="text/javascript" charset="utf-8" th:src="@{/ueditors/ueditor.config.js}"></script>
    <script type="text/javascript" charset="utf-8" th:src="@{/ueditors/ueditor.all.js}"> </script>
    <!--建议手动加在语言,避免在ie下有时因为加载语言失败导致编辑器加载失败-->
    <!--这里加载的语言文件会覆盖你在配置项目里添加的语言类型,比如你在配置项目里配置的是英文,这里加载的中文,那最后就是中文-->
    <script type="text/javascript" charset="utf-8" th:src="@{/ueditors/lang/zh-cn/zh-cn.js}"></script>

    <style type="text/css">
        div{
            width:100%;
        }
    </style>
</head>

修改ueditor.config.js中serverUrl的值为加载后台config.json配置项的接口路径

// 服务器统一请求接口路径
, serverUrl: window.CTX + "/ueditor/config"

8.访问查看后端配置项

运行项目,访问路径http://localhost:8080/ue/ueditor/config?action=config,如下图所示则表示可读取到config.json文件。
访问config.json
此时点击多图上传,上传出现未找到上传数据
未找到上传数据
debug发现BinaryUploader类无法获取到字节流,原因是因为SpringMVC框架对含字节流的request进行了处理,此处传的是处理过的request,故获取不到字节流。此时采用SpringMVC框架的解析器MultipartResolver。修改BinaryUploader源码如下:

package com.solang.ueditor.upload;

import com.solang.ueditor.PathFormat;
import com.solang.ueditor.define.AppInfo;
import com.solang.ueditor.define.BaseState;
import com.solang.ueditor.define.FileType;
import com.solang.ueditor.define.State;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class BinaryUploader {

	public static final State save(HttpServletRequest request,
			Map<String, Object> conf) {
		if (!ServletFileUpload.isMultipartContent(request)) {
			return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT);
		}
		try {
			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
			MultipartFile multipartFile = multipartRequest.getFile(conf.get("fieldName").toString());
			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);
	}
	
}

此处physicalPath即为上传的物理路径,是上传到rootPath目录下的。

9.修改config.json上传路径

由于UEditor上传的路径比较深,修改config.json的上传路径,将带有PathFormat后缀的参数值去掉/ueditor/jsp/upload前缀
修改config.json上传保存路径
此时运行项目,上传图片发现图片上传成功,上传路径
图片上传路径
但是编辑器图片不显示
上传图片不显示
因为把图片存在E盘upload文件夹下了,而spring并没有对E盘upload目录进行映射。此时我们加入路径映射。打开application.properties文件,添加如下代码

spring.mvc.static-path-pattern=/**
spring.resources.static-locations=file:${web.upload-path},classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/

此时运行项目,发现图片还是不能正常显示,如果没有定义项目名那么能正常显示。由于项目定义了项目名,所以config.json需要定义项目名访问前缀,即UrlPrefix结尾的参数对应的值。本博客定义为/ue
定义文件路径访问前缀
此时想到如果项目名变化的话(毕竟SpringBoot改项目名很方便),这样固定写法很不好,所以将此配置到后台代码中。

修改ConfigManager源码的initEnv方法,顺便把SpringBoot打成jar包运行,在jar包里无法以ClassLoader.getResource().getPath()获得的路径读取文件的问题解决,需要使用Class类的getResourceAsStream()来读取。

private void initEnv () throws FileNotFoundException, IOException {
		File file = new File( this.originalPath );
		if ( !file.isAbsolute() ) {
			file = new File( file.getAbsolutePath() );
		}
		
		this.parentPath = file.getParent();
		
		//String configContent = this.readFile( this.getConfigPath() );
		String configContent = this.filter(IOUtils.toString(this.getClass().getClassLoader().getResourceAsStream("config.json"), "utf-8"));

		try{
			JSONObject jsonConfig = new JSONObject( configContent );
			/* 图片访问路径前缀 */
			jsonConfig.put("imageUrlPrefix", contextPath);
			/* 图片访问路径前缀 */
			jsonConfig.put("scrawlUrlPrefix", contextPath);
			/* 图片访问路径前缀 */
			jsonConfig.put("snapscreenUrlPrefix", contextPath);
			/* 图片访问路径前缀 */
			jsonConfig.put("catcherUrlPrefix", contextPath);
			/* 视频访问路径前缀 */
			jsonConfig.put("videoUrlPrefix", contextPath);
			/* 文件访问路径前缀 */
			jsonConfig.put("fileUrlPrefix", contextPath);
			/* 图片访问路径前缀 */
			jsonConfig.put("imageManagerUrlPrefix", contextPath);
			/* 文件访问路径前缀 */
			jsonConfig.put("fileManagerUrlPrefix", contextPath);
			this.jsonConfig = jsonConfig;
		} catch ( Exception e ) {
			this.jsonConfig = null;
		}
		
	}

此时代码里设置的路径前缀会覆盖config.json里对应参数配置的值。

运行项目,上传图片发现图片上传成功并能在编辑器显示。
上传成功并显示成功

10.在线管理

此时点击在线管理(附件中的在线附件也是同样的问题),发现图片路径显示有问题
在线管理显示问题
修改FileManager的getPath方法,将rootPath路径E:/upload/替换为/

private String getPath ( File file ) {
	// String path = file.getAbsolutePath();
	// return path.replace( this.rootPath, "/" );
	String path = PathFormat.format(file.getAbsolutePath());
	return path.replace(this.rootPath, "/" );	
}

此时在线管理也能正常显示图片了
在线管理显示正常

至于UEditor的静态资源存放路径使用ueditors而不是ueditor,是因为使用ueditor文件夹在谷歌浏览器上多图上传和附件上传按钮不能点击,其它浏览器能正常点击,不清楚具体原因,文件夹名改下就好了。

11.自定义上传接口

参见UEditor官方文档,可自定义上传接口。
如何自定义请求地址
后端请求规范

本文参考:
SpringBoot整合UEditor教程
很详细的SpringBoot整合UEditor教程
UEditor多图上传在线管理,附件在线附件显示路径问题

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章