Java SpringBoot实现UeditorPlus 集成秀米编辑器图片转存的功能

1,398 阅读2分钟

概述

最近自己做的一个内容管理平台,客户需要集成秀米编辑器,查看了秀米官方文档,仅支持ueditor内核的编辑器才行,这边不得不吐槽一下百度这款开源的产品BUG真是太多了。随便一搜CSDN都是踩坑日记,各种修改js,最后可能还是有各种隐藏的坑在里面。

UeditorPlus是Ueditor一个重构的版本,之前的应该也不维护了,BUG实在太多了。

下面的文章是基于vue + UeditorPlus集成秀米编辑器为例来说一下如何用java 实现图片的转储功能。

官方文档

vue-ueditor-wrap Vue UEditor插件

UEditorPlus 使用文档

1. 集成UeditorPlus

前端接入基于vue插件接入非常简单, (1) 安装UEditor插件

npm i vue-ueditor-wrap

(2) 解压 UEditorPlus 到静态资源目录,配置

image.png

<script>
  import VueUeditorWrap from "vue-ueditor-wrap";
  import SingleUpload from '@/components/Upload/singleUpload'
  import {getNewsById} from '@/api/getNews'


  const defaultNews = {
    id:'',
    title: '',
    coverImg: '',
    content: ''
  };

  export default {
    name: 'newsDetail',
    components: { VueUeditorWrap, SingleUpload },
    data() {
      return {
        newsParam: Object.assign({}, defaultNews),
        content: 'Welcome to Your Vue.js App',
        editorConfig: {
          // 相对路径
          UEDITOR_HOME_URL: '/static/UEditorPlus/',
          serverUrl: "http://1.13.22.158:8080/ueditor/cos",
          toolbars: [[
            'insertvideo',
            'xiumi-dialog'
          ]],
          catchRemoteImageEnable: false, //设置是否抓取远程图片
          paths: {
            ZeroClipboard: "/static/UEditorPlus/ZeroClipboard"
          },
          // 编辑器不自动被内容撑高
          autoHeightEnabled: false,
          // 初始容器高度// 初始容器宽度
          initialFrameHeight: 400,
          initialFrameWidth: '100%'
        }
      };
    },
    created(){
      getNewsById(this.$route.query.id).then(response=>{
        this.newsParam=response.data;
      });
    },
    methods: {
      addXiumiDialog(editorId) {
        window.UE.registerUI(
          'xiumi-dialog',
          (editor, uiName) => {
            // 创建 “秀米弹窗”
            const dialog = new window.UE.ui.Dialog({
              // 注意:这是 xiumi-ue-dialog-v5.html 文件的访问链接,这个页面会通过 iframe 的方式嵌入到弹窗里
              iframeUrl: '/static/UEditorPlus/xiumi-ue-dialog-v5.html',
              editor,
              name: uiName,
              title: '秀米图文消息助手',
              cssRules: 'width: ' + (window.innerWidth - 60) + 'px; height: ' + (window.innerHeight - 60) + 'px;',
            });

            // 添加自定义按钮用于唤起“秀米弹窗”
            const btn = new window.UE.ui.Button({
              name: 'xiumi-connect',
              title: '秀米',
              cssRules: `background-image: url('//dl.xiumi.us/connect/ue/xiumi-connect-icon.png') !important; background-size: contain;`,
              onclick() {
                dialog.render();
                dialog.open();
              },
            });

            return btn;
          },
          2 /* 指定添加到工具栏上的那个位置,默认时追加到最后 */,
          editorId /* 指定这个UI是哪个编辑器实例上的,默认是页面上所有的编辑器都会添加这个按钮 */
        );
      }
    }
  }
</script>

2. 集成秀米编辑器

官网推荐的before-init钩子函数进行秀米编辑器的集成。参考上面的代码

methods: {
  addXiumiDialog(editorId) {
    window.UE.registerUI(
      'xiumi-dialog',
      (editor, uiName) => {
        // 创建 “秀米弹窗”
        const dialog = new window.UE.ui.Dialog({
          // 注意:这是 xiumi-ue-dialog-v5.html 文件的访问链接,这个页面会通过 iframe 的方式嵌入到弹窗里
          iframeUrl: '/static/UEditorPlus/xiumi-ue-dialog-v5.html',
          editor,
          name: uiName,
          title: '秀米图文消息助手',
          cssRules: 'width: ' + (window.innerWidth - 60) + 'px; height: ' + (window.innerHeight - 60) + 'px;',
        });

        // 添加自定义按钮用于唤起“秀米弹窗”
        const btn = new window.UE.ui.Button({
          name: 'xiumi-connect',
          title: '秀米',
          cssRules: `background-image: url('//dl.xiumi.us/connect/ue/xiumi-connect-icon.png') !important; background-size: contain;`,
          onclick() {
            dialog.render();
            dialog.open();
          },
        });

        return btn;
      },
      2 /* 指定添加到工具栏上的那个位置,默认时追加到最后 */,
      editorId /* 指定这个UI是哪个编辑器实例上的,默认是页面上所有的编辑器都会添加这个按钮 */
    );
  }
}

image.png

3. java后端接口转存

参考官方文档: 后端部署说明

我这边是提供一个后端接口,将秀米图片文件或者视频链接文件上传到自己的minio服务器上。具体代码如下:

package com.xx.news.platform.modules.admin.controller;

import com.xx.news.platform.modules.admin.dto.Ueditor;
import com.xx.news.platform.modules.admin.service.MinioService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@RequestMapping("/ueditor")
@Controller
@CrossOrigin
public class UeditorController {

    @Resource
    private MinioService minioService;

    @RequestMapping(value = "/cos")
    @ResponseBody
    public Object server(String action, String callback, MultipartFile upfile, HttpServletResponse response) {
        Object result = null;
        switch (action) {
            case Ueditor.ACTION_CONFIG:
                String result1 = "";
                if (callback != null) {
                    result1 = callback + "(" + Ueditor.UEDITOR_CONFIG + ")";
                } else {
                    result1 = Ueditor.UEDITOR_CONFIG;
                }
                try {
                    response.getWriter().write(result1);//返回的十回调函数
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            case Ueditor.ACTION_UPLOADFILE:
            case Ueditor.ACTION_UPLOADVIDEO:
            case Ueditor.ACTION_UPLOADIMAGE:
                String url = minioService.upload(upfile);
                Ueditor ueditor = new Ueditor();
                ueditor.setUrl(url);
                ueditor.setState(Ueditor.ACTION_SUCCESS);
                ueditor.setTitle(upfile.getOriginalFilename());
                result = ueditor;
                break;
            default:
        }
        return result;
    }
}
package com.xx.news.platform.modules.admin.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.xx.news.platform.modules.admin.service.MinioService;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;


@Slf4j
@Service
public class MinioServiceImpl implements MinioService {
    @Value("${minio.endpoint}")
    private String ENDPOINT;
    @Value("${minio.bucketName}")
    private String BUCKET_NAME;
    @Value("${minio.accessKey}")
    private String ACCESS_KEY;
    @Value("${minio.secretKey}")
    private String SECRET_KEY;

    @Value("${minio.tempPath}")
    private String tempPath;

    @Override
    public String upload(String imgUrl) {

        try {
            //创建一个MinIO的Java客户端
            MinioClient minioClient =MinioClient.builder()
                    .endpoint(ENDPOINT)
                    .credentials(ACCESS_KEY,SECRET_KEY)
                    .build();

            File imgFile = HttpUtil.downloadFileFromUrl(imgUrl, tempPath);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            // 设置存储对象名称
            String objectName = sdf.format(new Date()) + "/" + imgFile.getName();

            // 使用putObject上传一个文件到存储桶中
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(BUCKET_NAME)
                    .object(objectName)
                    .stream(FileUtil.getInputStream(imgFile), imgFile.length(), -1).build();
            minioClient.putObject(putObjectArgs);
            String minioURL = ENDPOINT + "/" + BUCKET_NAME + "/" + objectName;
            log.info("文件上传成功, minioURL:{}!", minioURL);
            return minioURL;
        } catch (Exception e) {
            log.info("上传到minio文件出现异常",  e);
        }
        return null;
    }

    @Override
    public String upload(MultipartFile file) {
        try {
            //创建一个MinIO的Java客户端
            MinioClient minioClient =MinioClient.builder()
                    .endpoint(ENDPOINT)
                    .credentials(ACCESS_KEY,SECRET_KEY)
                    .build();


            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            // 设置存储对象名称
            String objectName = sdf.format(new Date()) + "/" + file.getOriginalFilename();

            // 使用putObject上传一个文件到存储桶中
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(BUCKET_NAME)
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1).build();
            minioClient.putObject(putObjectArgs);
            String minioURL = ENDPOINT + "/" + BUCKET_NAME + "/" + objectName;
            log.info("文件上传成功, minioURL:{}!", minioURL);
            return minioURL;
        } catch (Exception e) {
            log.info("上传到minio文件出现异常",  e);
        }
        return null;
    }
}

image.png

最后

目前这个内容管理平台已经放在git上面了,如果有帮助欢迎大家关注和点赞。有什么不正确的也欢迎大家指正。

前端地址:xx-web

后端项目地址:xx-admin 后台管理系统