• springboot整合ueditor(不修改前端源码)


    springboot整合ueditor

    这篇文章记录下如何在springboot工程中使用ueditor,没有做前后端分离,ueditor的前端页面也在后端的springboot工程中。使用修改ueditor后端源码码的方式进行整合

    一、分析

    1.1 使用ueditor为什么需要后端工程的配合

    ueditor是一个可以嵌入在前端页面上的富文本编辑器,但它的配置信息和上传图片,上传附件等这些功能的实现需要后端工程的支持,即前端向后端请求配置信息,上传图片。

    ueditor官方提供了jsp版的后台代码。这个示例工程可以直接在tomcat中部署进行测试,就是把ueditor前端页面和jsp后端都部署在tomcat中,这种方式官网有详细示例,可以用来熟悉ueditor使用时的前后端交互过程。

    1.2 ueditor的jsp版后端代码部分详解

    首先给出一个ueditor发给后端的获取配置信息的请求的url示例:

    http://localhost:8080/ueditor-demo/jsp/controller.jsp?action=config&&noCache=1589691598506
    

    在官网下载ueditor的源码,其中有一个jsp文件夹,这里边放的就是jsp后端代码

    lib目录中是其依赖的jar包,src中是工程源码,config.json是对ueditor进行配置的配置文件,controller.jsp是前端请求的入口。

    controller.jsp中的主要内容如下:

    	request.setCharacterEncoding( "utf-8" );
    	response.setHeader("Content-Type" , "text/html");
    	
    	String rootPath = application.getRealPath( "/" );
    	
    	out.write( new ActionEnter( request, rootPath ).exec() );
    

    可以看到所有请求的处理都是通过ActionEnter这个类中的exec方法处理的。从src目录中找到这个文件。

    梳理下这个文件中的主要操作:

    (1) 构造方法中实例化了配置文件管理对象ConfigManager,通过这个对象来读取配置文件

    
    	public ActionEnter ( HttpServletRequest request, String rootPath ) {
    		
    		this.request = request;
    		this.rootPath = rootPath;
    		this.actionType = request.getParameter( "action" );
    		this.contextPath = request.getContextPath();
    		this.configManager = ConfigManager.getInstance( this.rootPath, this.contextPath, request.getRequestURI() );
    		
    	}
    

    (2) exec方法调用了本类中的invoke方法,在invoke方法中根据前端请求参数action来判断到底是进行什么操作,这个action在构造方法中通过request获取,如上边的示例url中action=config

    (3) invoke方法的内容如下

    public String invoke() {
    		
    		if ( actionType == null || !ActionMap.mapping.containsKey( actionType ) ) {
    			return new BaseState( false, AppInfo.INVALID_ACTION ).toJSONString();
    		}
    		
    		if ( this.configManager == null || !this.configManager.valid() ) {
    			return new BaseState( false, AppInfo.CONFIG_ERROR ).toJSONString();
    		}
    		
    		State state = null;
    		//1.把前台传递的action转换为actionCode
    		int actionCode = ActionMap.getType( this.actionType );
    		
    		Map<String, Object> conf = null;
    		//2.根据actionCode进行对应的操作:获取配置,上传图片等
    		switch ( actionCode ) {
    		
    			case ActionMap.CONFIG:
    				return this.configManager.getAllConfig().toString();
    				
    			case ActionMap.UPLOAD_IMAGE:
    			case ActionMap.UPLOAD_SCRAWL:
    			case ActionMap.UPLOAD_VIDEO:
    			case ActionMap.UPLOAD_FILE:
    				conf = this.configManager.getConfig( actionCode );
    				state = new Uploader( request, conf ).doExec();
    				break;
    				
    			case ActionMap.CATCH_IMAGE:
    				conf = configManager.getConfig( actionCode );
    				String[] list = this.request.getParameterValues( (String)conf.get( "fieldName" ) );
    				state = new ImageHunter( conf ).capture( list );
    				break;
    				
    			case ActionMap.LIST_IMAGE:
    			case ActionMap.LIST_FILE:
    				conf = configManager.getConfig( actionCode );
    				int start = this.getStartIndex();
    				state = new FileManager( conf ).listFile( start );
    				break;
    				
    		}
    		
    		return state.toJSONString();
    		
    	}
    

    1.3 总结

    在springboot工程中整合ueditor后端部分,我们可以直接拷贝官方提供的jsp后端的src目录中的源码,然后自己建一个Controll来处理来自ueditor的请求,并把所有的请求向jsp中那样使用ActionEnter类的exec方法处理。

    二、整合ueditor到springboot

    2.1 复制官方提供的源码,导入需要的依赖

    把官方提供的jsp文件中的src目录复制到我们自己的工程中,根据根据jsp文件中lib目录下的jar包导入对应的依赖到我们的工程中。

    lib目录中的jar包:


    对应的导入如下的maven依赖

     <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.6</version>
            </dependency>
    
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.3</version>
            </dependency>
    
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.json</groupId>
                <artifactId>json</artifactId>
                <version>20180813</version>
            </dependency>
    
    

    2.2创建一个Controller来处理ueditor的请求

    @RestController
    @RequestMapping("/ueditor")
    public class UEditorController {
    
        @RequestMapping("/config")
        public String config(HttpServletRequest request, HttpServletResponse response){
            String userDir = System.getProperty("user.dir");
            return new ActionEnter(request, userDir).exec();
        }
    }
    
    

    这里的参数userDir我指定的是springboot工程打成jar包运行时这个jar包所在的目录,jsp示例中指定的是应用的根路径,这个可根据实际情况调整。

    2.4 前端页面构建

    在resources目录下新建static文件夹,因为放在这个目录下的内容工程启动时可以被直接访问,所以我们把官方提供的示例直接复制到这个目录下


    这样在浏览器中直接访问index.html就可以访问到该页面,修改ueditor.config.js中的serverUrl指向我们定义的这个controller

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

    2.5 配置文件读取位置的调整

    现在启动工程已经可以访问到ueditor页面了,但现在因为在后端代码读取配置文件的路径下并没有配置文件,所以前台页面会提示后端配置错误,接下来我们研究下后端代码如何读取配置文件。

    前边提到在ActionEnter的构造方法中创建了ConfigManager对象,通过ConfigManager来读取配置文件

    ConfigManager的构造方法调用了initEnv方法,这个方法的代码如下

    	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() );
    		
    		try{
    			JSONObject jsonConfig = new JSONObject( configContent );
    			this.jsonConfig = jsonConfig;
    		} catch ( Exception e ) {
    			this.jsonConfig = null;
    		}
    		
    	}
    

    可以看到给readFile方法传入了一个路径返回了configContent,所以是这个readFile方法在读取配置文件,

    private String readFile ( String path ) throws IOException {
    		
    		StringBuilder builder = new StringBuilder();
    		
    		try {
    			
    			InputStreamReader reader = new InputStreamReader( new FileInputStream( path ), "UTF-8" );
    			BufferedReader bfReader = new BufferedReader( reader );
    			
    			String tmpContent = null;
    			
    			while ( ( tmpContent = bfReader.readLine() ) != null ) {
    				builder.append( tmpContent );
    			}
    			
    			bfReader.close();
    			
    		} catch ( UnsupportedEncodingException e ) {
    			// 忽略
    		}
    		
    		return this.filter( builder.toString() );
    		
    	}
    

    可以看到在这个方法中通过InputStreamReader在读取配置文件。所以我们可以把自己的配置文件放在resources目录下,通过类加载器返回输入流传给InputStreamReader,这样就可以读取到自己的配置文件

    private String readFile () throws IOException {
    		
    		//更改读取后端配置文件的位置
    		InputStream resourceAsStream = ConfigManager.class.getClassLoader().getResourceAsStream("config.json");
    		StringBuilder builder = new StringBuilder();
    		...省略其他
    

    然后这个readFile方法就可以修改为不带参数的

    2.6 上传图片未找到数据异常的处理

    经过上边的处理后编辑器页面已经可以使用了,但如果上传图片会报未找到数据的异常,这是因为上传图片的请求被springmvc的MultipartResolver拦截到了并封装成了MultipartFile对象,所以请求中没有文件数据,这个MultipartResolver是springboot自动配置的StandardServletMultipartResolver。所以解决的办法是排除掉

    springboot自动配置MultipartResolver,重写一个自己的MultipartResolver并在其中放行ueditor的上传请求。

    (1) 排除springboot自动配置MultipartResolver

    在application.yml中进行如下配置

    spring:
      autoconfigure:
        #排除springboot对MultipartResolver的自动配置,使用自己的配置,在其中放行来自ueditor的上传请求
        exclude: org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
    

    (2) 创建一个自定义的MultipartResolver,继承StandardServletMultipartResolver

    public class MyCommonsMultipartResolver extends StandardServletMultipartResolver {
    
        //springmvc对上传文件请求的处理,使其过滤掉ueditor的上传请求
        @Override
        public boolean isMultipart(HttpServletRequest request) {
            String requestURI = request.getRequestURI();
            if(requestURI.contains("/ueditor")){
                return false;
            }
            return super.isMultipart(request);
        }
    }
    
    

    (3) 把这个自定义类配置到spring容器中

       @Bean(name = "multipartResolver")
        public MultipartResolver multipartResolver(){
            return new MyCommonsMultipartResolver();
        }
    

    这样图片上传功能就可以了,图片的保存路径是在创建ActionEnter时的第二个参数指定的路径,再加上config.json中指定的imagePathFormat,可以通过修改配置文件中的这个参数来改变图片的保存路径。

    2.7 图片回显问题

    上一步只是完成了图片的上传,但图片在编辑器中的回显依然存在问题,报找不到图片的错误,这是因为后端图片上传成功后给前端返回了一个url,前端会访问这个url获取图片。追踪源码会发现在BinaryUploader#save方法中

    if (storageState.isSuccess()) {
    				storageState.putInfo("url", PathFormat.format(savePath));
    				storageState.putInfo("type", suffix);
    				storageState.putInfo("original", originFileName + suffix);
    			}
    

    这个savePath就是上面config.json中的imagePathFormat再加上文件的保存名称而前端拿到这个url后,会直接请求这个地址:http://localhost:8080/url,比如按我的配置文件,这个url是/ueditor/upload/image/20200517/1589695937922096997.png

    因为现在工程中不存在这样一个接口,所以获取不到图片。

    这里给出一种解决方案,在工程中增加一个获取图片的接口,然后在这里把这个url指向获取图片的接口(文件名拼接在url上),这样前端就可以拿到上传的图片进行回显。

    当然也可以修改ueditor的前端回显图片部分直接指向获取图片的接口,这样这里的url就可以只放一个参数名

    三、总结

    这篇文章记录了在springboot工程中如何整合ueditor,并没有进行前后端分离,导入了ueditor的jsp后端源码并进行了修改,没有修改ueditor的前端源码。

  • 相关阅读:
    单词 统计
    第十周学习记录
    梦断代码阅读笔记03
    梦断代码阅读笔记02
    梦断代码阅读笔记01
    用户模板和用户场景
    第九周学习记录
    分享好友-分享朋友圈
    生命周期函数-页面刷新
    底部导航的设置
  • 原文地址:https://www.cnblogs.com/chengxuxiaoyuan/p/12905226.html
Copyright © 2020-2023  润新知