UEditor 富文本编辑器-后端实现文件上传功能

一、背景

前端使用 UEditor 富文本编辑器,前后端分离情况下,需要后端提供一个接口实现文件上传功能
本文根据文章:vue+Ueditor集成 [前后端分离项目][图片、文件上传][富文本编辑] 的思路,对项目进行对应修改,配合前端实现 UEditor 上传功能

二、实现步骤

  1. 源码
    在git仓库:https://github.com/coderliguoqing/UeditorSpringboot 下载源码
  2. 复制文件
  • 复制配置文件:/ueditor-demo/src/main/resources/config.json 到项目的resources 文件下
  • 复制实现类文件夹:/ueditor-demo/src/main/java/cn/com/lee/common/ueditor 到项目的工具类文件下
  • 删除多余启动类文件:/util/SpringUtil.java
  1. 修改代码
    3.1 引入maven依赖
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20201115</version>
</dependency>

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

3.2 新建接口,给前端调用

/**
 * UEditor 富文本编辑器-后端文件上传功能
 *
 * @param request request
 * @return java.lang.String
 * @author linc
 * @date 2021/2/25 下午5:10
 */
@ResponseBody
@RequestMapping(value = "/ueditor/upload")
public String ueditorUpload(HttpServletRequest request) throws UnsupportedEncodingException {
    request.setCharacterEncoding("utf-8");
	String rootPath = request.getSession().getServletContext().getRealPath("/");
    return new ActionEnter(request, rootPath).exec();
}

3.3 在测试环境出现【配置文件初始化失败】的提示,本地正常

需要修改 /util/ueditor/ConfigManager.java 文件中 initEnv 方法,读取配置部分的代码

package com.fb.crm.util.ueditor;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.core.io.ClassPathResource;

import com.fb.crm.util.ueditor.define.ActionMap;

/**
 * 配置管理器
 *
 * @author hancong03@baidu.com
 */
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;
    // 涂鸦上传filename定义
    private final static String SCRAWL_FILE_NAME = "scrawl";
    // 远程图片抓取filename定义
    private final static String REMOTE_FILE_NAME = "remote";

    /*
     * 通过一个给定的路径构建一个配置管理器, 该管理器要求地址路径所在目录下必须存在config.properties文件
     */
    private ConfigManager(String rootPath, String contextPath, String uri) throws FileNotFoundException, IOException {

        rootPath = rootPath.replace("\\", "/");

        this.rootPath = rootPath;
        this.contextPath = contextPath;
        this.originalPath = "src/main/resources/config.json";

        this.initEnv();

    }

    /**
     * 配置管理器构造工厂
     *
     * @param rootPath    服务器根路径
     * @param contextPath 服务器所在项目路径
     * @param uri         当前访问的uri
     * @return 配置管理器实例或者null
     */
    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) throws JSONException {

        Map<String, Object> conf = new HashMap<String, Object>();
        String savePath = null;
        String localSavePathPrefix = null;

        switch (type) {

            case ActionMap.UPLOAD_FILE:
                conf.put("isBase64", "false");
                conf.put("maxSize", this.jsonConfig.getLong("fileMaxSize"));
                conf.put("allowFiles", this.getArray("fileAllowFiles"));
                conf.put("fieldName", this.jsonConfig.getString("fileFieldName"));
                savePath = this.jsonConfig.getString("filePathFormat");
                break;

            case ActionMap.UPLOAD_IMAGE:
                conf.put("isBase64", "false");
                conf.put("maxSize", this.jsonConfig.getLong("imageMaxSize"));
                conf.put("allowFiles", this.getArray("imageAllowFiles"));
                conf.put("fieldName", this.jsonConfig.getString("imageFieldName"));
                savePath = this.jsonConfig.getString("imagePathFormat");
                localSavePathPrefix = this.jsonConfig.getString("localSavePathPrefix");
                break;

            case ActionMap.UPLOAD_VIDEO:
                conf.put("maxSize", this.jsonConfig.getLong("videoMaxSize"));
                conf.put("allowFiles", this.getArray("videoAllowFiles"));
                conf.put("fieldName", this.jsonConfig.getString("videoFieldName"));
                savePath = this.jsonConfig.getString("videoPathFormat");
                localSavePathPrefix = this.jsonConfig.getString("localSavePathPrefix");
                break;

            case ActionMap.UPLOAD_SCRAWL:
                conf.put("filename", ConfigManager.SCRAWL_FILE_NAME);
                conf.put("maxSize", this.jsonConfig.getLong("scrawlMaxSize"));
                conf.put("fieldName", this.jsonConfig.getString("scrawlFieldName"));
                conf.put("isBase64", "true");
                savePath = this.jsonConfig.getString("scrawlPathFormat");
                break;

            case ActionMap.CATCH_IMAGE:
                conf.put("filename", ConfigManager.REMOTE_FILE_NAME);
                conf.put("filter", this.getArray("catcherLocalDomain"));
                conf.put("maxSize", this.jsonConfig.getLong("catcherMaxSize"));
                conf.put("allowFiles", this.getArray("catcherAllowFiles"));
                conf.put("fieldName", this.jsonConfig.getString("catcherFieldName") + "[]");
                savePath = this.jsonConfig.getString("catcherPathFormat");
                localSavePathPrefix = this.jsonConfig.getString("localSavePathPrefix");
                break;

            case ActionMap.LIST_IMAGE:
                conf.put("allowFiles", this.getArray("imageManagerAllowFiles"));
                conf.put("dir", this.jsonConfig.getString("imageManagerListPath"));
                conf.put("count", this.jsonConfig.getInt("imageManagerListSize"));
                break;

            case ActionMap.LIST_FILE:
                conf.put("allowFiles", this.getArray("fileManagerAllowFiles"));
                conf.put("dir", this.jsonConfig.getString("fileManagerListPath"));
                conf.put("count", this.jsonConfig.getInt("fileManagerListSize"));
                break;

        }

        conf.put("savePath", savePath);
        conf.put("localSavePathPrefix", localSavePathPrefix);
        conf.put("rootPath", this.rootPath);

        return conf;

    }

    private void initEnv() throws FileNotFoundException, IOException {
        ClassPathResource resource = new ClassPathResource("config.json");
        String configContent = readFileByInputStream(resource.getInputStream());
        try {
            JSONObject jsonConfig = new JSONObject(configContent);
            this.jsonConfig = jsonConfig;
        } catch (Exception e) {
            this.jsonConfig = null;
        }

    }

    private String getConfigPath() {
        return this.parentPath + File.separator + ConfigManager.configFileName;
    }

    private String[] getArray(String key) throws JSONException {

        JSONArray jsonArray = this.jsonConfig.getJSONArray(key);
        String[] result = new String[jsonArray.length()];

        for (int i = 0, len = jsonArray.length(); i < len; i++) {
            result[i] = jsonArray.getString(i);
        }

        return result;

    }

    private String readFileByInputStream(InputStream inputStream) throws IOException {

        StringBuilder builder = new StringBuilder();

        try {

            InputStreamReader reader = new InputStreamReader(inputStream, "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());

    }

    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());

    }

    // 过滤输入字符串, 剔除多行注释以及替换掉反斜杠
    private String filter(String input) {

        return input.replaceAll("/\\*[\\s\\S]*?\\*/", "");

    }

}

3.4 修改 /ueditor/upload/StorageManager.java 源代码中 TODO 的部分,实现上传到七牛云的功能

package com.fb.crm.util.ueditor.upload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.fb.crm.component.QiniuComponent;
import org.apache.commons.io.FileUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import com.fb.crm.util.ueditor.define.AppInfo;
import com.fb.crm.util.ueditor.define.BaseState;
import com.fb.crm.util.ueditor.define.State;

@Component
@ConfigurationProperties(prefix = "nginx")
public class StorageManager {

    @Resource
    private QiniuComponent qiniuComponent;

    /**
     * 维护一个本类的静态变量
     */
    private static StorageManager storageManager;

    /**
     * 初始化的时候,将本类中的sysConfigManager赋值给静态的本类变量
     */
    @PostConstruct
    public void init() {
        storageManager = this;
        storageManager.qiniuComponent = this.qiniuComponent;
    }

    public static final int BUFFER_SIZE = 8192;

    private static String fileurl;

    public static String getFileurl() {
        return fileurl;
    }

    public static void setFileurl(String fileurl) {
        StorageManager.fileurl = fileurl;
    }

    public static int getBufferSize() {
        return BUFFER_SIZE;
    }

    public StorageManager() {
    }

    public static State saveBinaryFile(byte[] data, String path) {
        File file = new File(path);

        State state = valid(file);

        if (!state.isSuccess()) {
            return state;
        }

        try {
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream(file));
            bos.write(data);
            bos.flush();
            bos.close();
        } catch (IOException ioe) {
            return new BaseState(false, AppInfo.IO_ERROR);
        }

        state = new BaseState(true, file.getAbsolutePath());
        state.putInfo("size", data.length);
        state.putInfo("title", file.getName());
        return state;
    }

    public static State saveFileByInputStream(HttpServletRequest request, InputStream is, String path, String picName,
                                              long maxSize) {

        State state = null;
        File tmpFile = getTmpFile();
        byte[] dataBuf = new byte[2048];

        try {
            //转成字节流
            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            int rc = 0;
            while ((rc = is.read(dataBuf, 0, 100)) > 0) {
                swapStream.write(dataBuf, 0, rc);
            }

            dataBuf = swapStream.toByteArray();
            swapStream.flush();
            swapStream.close();

            if (tmpFile.length() > maxSize) {
                tmpFile.delete();
                return new BaseState(false, AppInfo.MAX_SIZE);
            }

            // 此处调用文件上传服务,并获取返回结果返回
            String uploadUrl = storageManager.qiniuComponent.uploadBytes(dataBuf, picName);

            boolean success = true;
            //如果上传成功
            if (success) {
                state = new BaseState(true);
                state.putInfo("size", tmpFile.length());
                //文件名填入此处
                state.putInfo("title", uploadUrl.replace(storageManager.qiniuComponent.getBucketHost() + "/", ""));
                //所属group填入此处
                state.putInfo("group", "");
                //文件访问的url填入此处
                state.putInfo("url", uploadUrl);
                tmpFile.delete();
            } else {
                state = new BaseState(false, 4);
                tmpFile.delete();
            }

            return state;

        } catch (IOException e) {
        }
        return new BaseState(false, AppInfo.IO_ERROR);
    }

    public static State saveFileByInputStream(InputStream is, String path, String picName) {
        State state = null;

        File tmpFile = getTmpFile();

        byte[] dataBuf = new byte[2048];
        BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);

        try {
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);

            int count = 0;
            while ((count = bis.read(dataBuf)) != -1) {
                bos.write(dataBuf, 0, count);
            }
            bos.flush();
            bos.close();

            //state = saveTmpFile(tmpFile, path);
            //重新将文件转成文件流的方式
//       InputStream in = new FileInputStream(tmpFile);
//       UploadUtils uploadUtils = new UploadUtils();
//       boolean success = uploadUtils.uploadFile(in, path, picName);
            boolean success = true;

            //如果上传成功
            if (success) {
                state = new BaseState(true);
                state.putInfo("size", tmpFile.length());
                state.putInfo("title", tmpFile.getName());
                tmpFile.delete();
            } else {
                state = new BaseState(false, 4);
                tmpFile.delete();
            }

            return state;
        } catch (IOException e) {
        }
        return new BaseState(false, AppInfo.IO_ERROR);
    }

    private static File getTmpFile() {
        File tmpDir = FileUtils.getTempDirectory();
        String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
        return new File(tmpDir, tmpFileName);
    }

    private static State saveTmpFile(File tmpFile, String path) {
        State state = null;
        File targetFile = new File(path);

        if (targetFile.canWrite()) {
            return new BaseState(false, AppInfo.PERMISSION_DENIED);
        }
        try {
            FileUtils.moveFile(tmpFile, targetFile);
        } catch (IOException e) {
            return new BaseState(false, AppInfo.IO_ERROR);
        }

        state = new BaseState(true);
        state.putInfo("size", targetFile.length());
        state.putInfo("title", targetFile.getName());

        return state;
    }

    private static State valid(File file) {
        File parentPath = file.getParentFile();

        if ((!parentPath.exists()) && (!parentPath.mkdirs())) {
            return new BaseState(false, AppInfo.FAILED_CREATE_FILE);
        }

        if (!parentPath.canWrite()) {
            return new BaseState(false, AppInfo.PERMISSION_DENIED);
        }

        return new BaseState(true);
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值