First of all, I won't talk about the most basic usage, just the file uploaded.
First of all, the file upload has changed a lot, so let's talk about its usage slowly.
1. The file structure of the Java version in the jsp directory is as follows:
As you can see from this, there is a controller.jsp, a config.json, and a bunch of jar files, which are not consistent with previous versions.
2. Reference to the jar package for the Maven project
If you don't use jar packages, it's easy to copy files directly, but maven's way, this jar doesn't exist on the Internet. Thankfully, Maven provides system-based dependencies:
The location of maven's jar package is as follows:
- < dependency>
- < groupId> com.baidu.ueditor </groupId >
- < artifactId> ueditor </artifactId >
- < version> 1.1.1 </version >
- < scope> system </scope >
- < systemPath> ${basedir}/ src/main/webapp /WEB-INF/lib/ ueditor-1.1.1.jar </systemPath >
- </ dependency>
Other jar s are easy to find.
3. Read controller.jsp file
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- import="com.baidu.ueditor.ActionEnter"
- pageEncoding="UTF-8"%>
- <%@ page trimDirectiveWhitespaces="true" %>
- <%
- request.setCharacterEncoding( "utf-8" );
- response.setHeader("Content-Type" , "text/html");
- String rootPath = application.getRealPath( "/" );
- out.write( new ActionEnter( request, rootPath ).exec() );
- %>
From the code point of view, rootPath is actually the root path of the project, constructs the ActionEnter, and calls the exec function.
Let's look at the code for ActionEnter:
Let's look at this function slowly: First, we call the request.getContextPath() and request.getRequestURI() functions in the constructor.
- package com.baidu.ueditor;
- import com.baidu.ueditor.define.ActionMap;
- import com.baidu.ueditor.define.BaseState;
- import com.baidu.ueditor.define.State;
- import com.baidu.ueditor.hunter.FileManager;
- import com.baidu.ueditor.hunter.ImageHunter;
- import com.baidu.ueditor.upload.Uploader;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- import org.json.JSONObject;
- public class ActionEnter
- {
- private HttpServletRequest request = null;
- private String rootPath = null;
- private String contextPath = null;
- private String actionType = null;
- private ConfigManager configManager = null;
- public ActionEnter(HttpServletRequest request, String rootPath)
- {
- this.request = request;
- this.rootPath = rootPath;
- //Assignment of action.
- this.actionType = request.getParameter("action");
- this.contextPath = request.getContextPath();
- //Build configManager class
- this.configManager = ConfigManager.getInstance(this.rootPath, this.contextPath, request.getRequestURI());
- }
- public String exec()
- {
- //This is in the form of jsonp, which is generally non-cross-domain.
- String callbackName = this.request.getParameter("callback");
- if (callbackName != null)
- {
- if (!validCallbackName(callbackName)) {
- return new BaseState(false, 401).toJSONString();
- }
- return callbackName + "(" + invoke() + ");";
- }
- return invoke();
- }
- public String invoke()
- {
- //Judging whether action is legal or not, if it returns to an illegal state
- if ((this.actionType == null) || (!ActionMap.mapping.containsKey(this.actionType))) {
- return new BaseState(false, 101).toJSONString();
- }
- //If configManager is not found, an error is also reported
- if ((this.configManager == null) || (!this.configManager.valid())) {
- return new BaseState(false, 102).toJSONString();
- }
- State state = null;
- //Get actionCode
- int actionCode = ActionMap.getType(this.actionType);
- Map conf = null;
- switch (actionCode)
- {
- case 0:
- return this.configManager.getAllConfig().toString();
- case 1:
- case 2:
- case 3:
- case 4:
- //Processing uploaded files
- conf = this.configManager.getConfig(actionCode);
- state = new Uploader(this.request, conf).doExec();
- break;
- case 5:
- conf = this.configManager.getConfig(actionCode);
- String[] list = this.request.getParameterValues((String)conf.get("fieldName"));
- //Processing online editing
- state = new ImageHunter(conf).capture(list);
- break;
- case 6:
- case 7:
- conf = this.configManager.getConfig(actionCode);
- int start = getStartIndex();
- //Processing file list
- state = new FileManager(conf).listFile(start);
- }
- return state.toJSONString();
- }
- public int getStartIndex()
- {
- String start = this.request.getParameter("start");
- try
- {
- return Integer.parseInt(start); } catch (Exception e) {
- }
- return 0;
- }
- public boolean validCallbackName(String name)
- {
- if (name.matches("^[a-zA-Z_]+[\\w0-9_]*$")) {
- return true;
- }
- return false;
- }
- }
Assuming our project's contextPath is: test, the return values of the following two functions are as follows:
request.getContextPath /test
request.getRequestURI /test/resources/ueditor/jsp/controller.jsp
Let's first look at the ConfigManager class.
- package com.baidu.ueditor;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.UnsupportedEncodingException;
- import java.util.HashMap;
- import java.util.Map;
- import org.json.JSONArray;
- import org.json.JSONObject;
- public final class ConfigManager
- {
- private final String rootPath;
- private final String originalPath;
- private final String contextPath;
- private static final String configFileName = "config.json";
- private String parentPath = null;
- private JSONObject jsonConfig = null;
- private static final String SCRAWL_FILE_NAME = "scrawl";
- private static final String REMOTE_FILE_NAME = "remote";
- private ConfigManager(String rootPath, String contextPath, String uri)
- throws FileNotFoundException, IOException
- {
- rootPath = rootPath.replace("\\", "/");
- this.rootPath = rootPath;
- this.contextPath = contextPath;
- //This place should pay special attention to the fact that originalPath is actually the path of controller.jsp
- if (contextPath.length() > 0)
- this.originalPath = (this.rootPath + uri.substring(contextPath.length()));
- else {
- this.originalPath = (this.rootPath + uri);
- }
- initEnv();
- }
- public static ConfigManager getInstance(String rootPath, String contextPath, String uri)
- {
- try
- {
- return new ConfigManager(rootPath, contextPath, uri); } catch (Exception e) {
- }
- return null;
- }
- public boolean valid()
- {
- return this.jsonConfig != null;
- }
- public JSONObject getAllConfig()
- {
- return this.jsonConfig;
- }
- public Map<String, Object> getConfig(int type)
- {
- Map conf = new HashMap();
- String savePath = null;
- //Resolve config.json configuration files according to different code s
- switch (type)
- {
- case 4:
- conf.put("isBase64", "false");
- conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("fileMaxSize")));
- conf.put("allowFiles", getArray("fileAllowFiles"));
- conf.put("fieldName", this.jsonConfig.getString("fileFieldName"));
- savePath = this.jsonConfig.getString("filePathFormat");
- break;
- case 1:
- conf.put("isBase64", "false");
- conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("imageMaxSize")));
- conf.put("allowFiles", getArray("imageAllowFiles"));
- conf.put("fieldName", this.jsonConfig.getString("imageFieldName"));
- savePath = this.jsonConfig.getString("imagePathFormat");
- break;
- case 3:
- conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("videoMaxSize")));
- conf.put("allowFiles", getArray("videoAllowFiles"));
- conf.put("fieldName", this.jsonConfig.getString("videoFieldName"));
- savePath = this.jsonConfig.getString("videoPathFormat");
- break;
- case 2:
- conf.put("filename", "scrawl");
- conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("scrawlMaxSize")));
- conf.put("fieldName", this.jsonConfig.getString("scrawlFieldName"));
- conf.put("isBase64", "true");
- savePath = this.jsonConfig.getString("scrawlPathFormat");
- break;
- case 5:
- conf.put("filename", "remote");
- conf.put("filter", getArray("catcherLocalDomain"));
- conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("catcherMaxSize")));
- conf.put("allowFiles", getArray("catcherAllowFiles"));
- conf.put("fieldName", this.jsonConfig.getString("catcherFieldName") + "[]");
- savePath = this.jsonConfig.getString("catcherPathFormat");
- break;
- case 7:
- conf.put("allowFiles", getArray("imageManagerAllowFiles"));
- conf.put("dir", this.jsonConfig.getString("imageManagerListPath"));
- conf.put("count", Integer.valueOf(this.jsonConfig.getInt("imageManagerListSize")));
- break;
- case 6:
- conf.put("allowFiles", getArray("fileManagerAllowFiles"));
- conf.put("dir", this.jsonConfig.getString("fileManagerListPath"));
- conf.put("count", Integer.valueOf(this.jsonConfig.getInt("fileManagerListSize")));
- }
- conf.put("savePath", savePath);
- conf.put("rootPath", this.rootPath);
- return conf;
- }
- //Load config.json configuration file
- 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 = readFile(getConfigPath());
- try
- {
- JSONObject jsonConfig = new JSONObject(configContent);
- this.jsonConfig = jsonConfig;
- } catch (Exception e) {
- this.jsonConfig = null;
- }
- }
- private String getConfigPath()
- {
- return this.parentPath + File.separator + "config.json";
- }
- private String[] getArray(String key)
- {
- JSONArray jsonArray = this.jsonConfig.getJSONArray(key);
- String[] result = new String[jsonArray.length()];
- int i = 0; for (int len = jsonArray.length(); i < len; i++) {
- result[i] = jsonArray.getString(i);
- }
- return result;
- }
- //Read the contents of config.json
- 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 localUnsupportedEncodingException)
- {
- }
- return filter(builder.toString());
- }
- private String filter(String input)
- {
- return input.replaceAll("/\\*[\\s\\S]*?\\*/", "");
- }
- }
Let's look at the Uploader function again. It's actually very simple:
- package com.baidu.ueditor.upload;
- import com.baidu.ueditor.define.State;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- public class Uploader
- {
- private HttpServletRequest request = null;
- private Map<String, Object> conf = null;
- public Uploader(HttpServletRequest request, Map<String, Object> conf) {
- this.request = request;
- this.conf = conf;
- }
- public final State doExec() {
- String filedName = (String)this.conf.get("fieldName");
- State state = null;
- if ("true".equals(this.conf.get("isBase64")))
- state = Base64Uploader.save(this.request.getParameter(filedName),
- this.conf);
- else {
- state = BinaryUploader.save(this.request, this.conf);
- }
- return state;
- }
- }
This is easy to understand, so let's move on to the BinaryUploader class:
- package com.baidu.ueditor.upload;
- import com.baidu.ueditor.PathFormat;
- import com.baidu.ueditor.define.BaseState;
- import com.baidu.ueditor.define.FileType;
- import com.baidu.ueditor.define.State;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- import org.apache.commons.fileupload.FileItemIterator;
- import org.apache.commons.fileupload.FileItemStream;
- import org.apache.commons.fileupload.FileUploadException;
- import org.apache.commons.fileupload.disk.DiskFileItemFactory;
- import org.apache.commons.fileupload.servlet.ServletFileUpload;
- public class BinaryUploader
- {
- //Use fileupload to process file uploads
- public static final State save(HttpServletRequest request, Map<String, Object> conf)
- {
- FileItemStream fileStream = null;
- boolean isAjaxUpload = request.getHeader("X_Requested_With") != null;
- if (!ServletFileUpload.isMultipartContent(request)) {
- return new BaseState(false, 5);
- }
- ServletFileUpload upload = new ServletFileUpload(
- new DiskFileItemFactory());
- if (isAjaxUpload) {
- upload.setHeaderEncoding("UTF-8");
- }
- try
- {
- FileItemIterator iterator = upload.getItemIterator(request);
- while (iterator.hasNext()) {
- fileStream = iterator.next();
- if (!fileStream.isFormField())
- break;
- fileStream = null;
- }
- if (fileStream == null) {
- return new BaseState(false, 7);
- }
- String savePath = (String)conf.get("savePath");
- String originFileName = fileStream.getName();
- 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, 8);
- }
- savePath = PathFormat.parse(savePath, originFileName);
- String physicalPath = (String)conf.get("rootPath") + savePath;
- //Call storage classes to handle file storage
- InputStream is = fileStream.openStream();
- 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 (FileUploadException e) {
- return new BaseState(false, 6);
- } catch (IOException localIOException) {
- }
- return new BaseState(false, 4);
- }
- private static boolean validType(String type, String[] allowTypes) {
- List list = Arrays.asList(allowTypes);
- return list.contains(type);
- }
- }
Storage Manager, we don't look at it, just do some things about file storage, let's analyze the problem of this implementation.
Finally, I'll summarize the benefits of this code and give some suggestions to the authors.
- From this point of view, it is impossible to place pictures in external paths, because this implementation determines that they can only be placed under project paths. The biggest problem is that it is possible to accidentally re-offline and lose all the content.
- From the implementation point of view, a large number of static calls, basically unable to re-develop, can not flexibly inherit it to deal with personalized things, such as if stored in fastDFS, this need to change the code inside, can not be extended by way of.
- Configuration item conversion in config.json is renamed. This place requires the reader to remember two variable names, for example, imagePathFormat becomes savePath, which seems to be quite understandable, but this is obviously not a good way. If there is a logic in it, it's better to explain it explicitly. Not hard-coded
- The source code is not open and can not be extended and modified. It is recommended that the author develop this jar into github and maintain it in the community.