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的前端源碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM