美文网首页
UEditor java 后端代码重构

UEditor java 后端代码重构

作者: 秋元_92a3 | 来源:发表于2020-04-18 13:51 被阅读0次

1、需求

使用百度的富文本编辑器,发送附件上传功能不太好使,点击附件上传的时候,报错【后端配置项没有正确加载,上传功能不能正常使用】,通过检查,发现是前端发送加载配置的请求,不能得到正确的配置请求结果导致的。官方提供的后端程序的版本也是比较老的,使用的还是jsp技术,因此,对ueditor的后端程序进行重构,来修复ueditor的上传附件功能。

2、接口分析

重构的话,实际上就是重写这些接口,重写之前,需要捋清楚,都有哪些接口,奉上前端程序的请求源码:

setTimeout(function(){
  try{
        me.options.imageUrl && me.setOpt('serverUrl', me.options.imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2'));

        var configUrl = me.getActionUrl('config'),
            isJsonp = utils.isCrossDomainUrl(configUrl);

        /* 发出ajax请求 */
        me._serverConfigLoaded = false;

        configUrl && UE.ajax.request(configUrl,{
            'method': 'GET',
            'dataType': isJsonp ? 'jsonp':'',
            'onsuccess':function(r){
                try {
                    var config = isJsonp ? r:eval("("+r.responseText+")");
                    utils.extend(me.options, config);
                    me.fireEvent('serverConfigLoaded');
                    me._serverConfigLoaded = true;
                } catch (e) {
                    showErrorMsg(me.getLang('loadconfigFormatError'));
                }
            },
            'onerror':function(){
                showErrorMsg(me.getLang('loadconfigHttpError'));
            }
        });
    } catch(e){
        showErrorMsg(me.getLang('loadconfigError'));
    }
});

在上面获取serverUrl的配置文件所在的是ueditor.config.js,配置的内容如下:

服务器统一请求接口路径
serverUrl: "/cms/UEditor/action"

完成上面的配置,页面初始化的时候,就会请求上面配置的服务端地址了,与在服务端定义好对应的controller。

@Controller
@RequestMapping("/cms/UEditor")
public class UEditorController extends BaseController {

    /**
     * ueditor资源路径
     */
    @Resource
    private IUEditorService iuEditorService;
    /**
     * ueditor action
     * 调用地址:    /cms/UEditor/action
     */
    @RequestMapping(value = "/action")
    @ResponseBody
    public String action(UEditorModel uEditorModel) {
        final String action = uEditorModel.getAction();
        if (UEditorAction.CONFIG.getActionCode().equals(action)) {
            return iuEditorService.loadConfig();
        } else if (UEditorAction.UPLOAD_FILE.getActionCode().equals(action)) {
            return iuEditorService.saveFile(uEditorModel.getUpfile());
        }
        return null;
    }
}

当前的方法的返回值是String类型,看源码之后,发现,其返回值实际上是json对象转的字符串,所以这个controller的方法中,需要对请求参数进行判断,根据参数返回不通的对象转的json,参数类型与返回的对象类型的对应关系,当时不是我猜的,我是根据源码找的;这里奉上参数类型与返回对象类型对应关系的源码,这个源码出自ueditor的jsp版本的服务端源码。

public String invoke() {
        if (this.actionType != null && ActionMap.mapping.containsKey(this.actionType)) {
            if (this.configManager != null && this.configManager.valid()) {
                State state = null;
                int actionCode = ActionMap.getType(this.actionType);
                Map<String, Object> conf = null;
                switch(actionCode) {
                case 0:
                    return this.configManager.getAllConfig().toString();
                case 1:
                case 2:
                case 3:
                case 4:
                    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"));
                    state = (new ImageHunter(conf)).capture(list);
                    break;
                case 6:
                case 7:
                    conf = this.configManager.getConfig(actionCode);
                    int start = this.getStartIndex();
                    state = (new FileManager(conf)).listFile(start);
                }

                return state.toJSONString();
            } else {
                return (new BaseState(false, 102)).toJSONString();
            }
        } else {
            return (new BaseState(false, 101)).toJSONString();
        }
    }
public final class ActionMap {
    public static final Map<String, Integer> mapping = new HashMap<String, Integer>() {
        {
            this.put("config", 0);
            this.put("uploadimage", 1);
            this.put("uploadscrawl", 2);
            this.put("uploadvideo", 3);
            this.put("uploadfile", 4);
            this.put("catchimage", 5);
            this.put("listfile", 6);
            this.put("listimage", 7);
        }
    };
    public static final int CONFIG = 0;
    public static final int UPLOAD_IMAGE = 1;
    public static final int UPLOAD_SCRAWL = 2;
    public static final int UPLOAD_VIDEO = 3;
    public static final int UPLOAD_FILE = 4;
    public static final int CATCH_IMAGE = 5;
    public static final int LIST_FILE = 6;
    public static final int LIST_IMAGE = 7;

    public ActionMap() {
    }

    public static int getType(String key) {
        return (Integer)mapping.get(key);
    }
}

通过上面的源码,知道他是判读了下参数,当传入的参数是config的时候,直接返回后端配置文件内容(config.json),否则的话,返回一个叫State生产的对象或其子类。
找到给接口的其中一个实现,如下:

public class MultiState implements State {
    private boolean state = false;
    private String info = null;
    private Map<String, Long> intMap = new HashMap();
    private Map<String, String> infoMap = new HashMap();
    private List<String> stateList = new ArrayList();

    public MultiState(boolean state) {
        this.state = state;
    }

    public MultiState(boolean state, String info) {
        this.state = state;
        this.info = info;
    }

    public MultiState(boolean state, int infoKey) {
        this.state = state;
        this.info = AppInfo.getStateInfo(infoKey);
    }

    public boolean isSuccess() {
        return this.state;
    }

    public void addState(State state) {
        this.stateList.add(state.toJSONString());
    }

    public void putInfo(String name, String val) {
        this.infoMap.put(name, val);
    }

    public String toJSONString() {
        String stateVal = this.isSuccess() ? AppInfo.getStateInfo(0) : this.info;
        StringBuilder builder = new StringBuilder();
        builder.append("{\"state\": \"" + stateVal + "\"");
        Iterator iterator = this.intMap.keySet().iterator();

        while(iterator.hasNext()) {
            stateVal = (String)iterator.next();
            builder.append(",\"" + stateVal + "\": " + this.intMap.get(stateVal));
        }

        iterator = this.infoMap.keySet().iterator();

        while(iterator.hasNext()) {
            stateVal = (String)iterator.next();
            builder.append(",\"" + stateVal + "\": \"" + (String)this.infoMap.get(stateVal) + "\"");
        }

        builder.append(", list: [");
        iterator = this.stateList.iterator();

        while(iterator.hasNext()) {
            builder.append((String)iterator.next() + ",");
        }

        if (this.stateList.size() > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }

        builder.append(" ]}");
        return Encoder.toUnicode(builder.toString());
    }

    public void putInfo(String name, long val) {
        this.intMap.put(name, val);
    }
}

发现这个对象内并没有清楚的定义各种属性,而是通过定义HashMap来实现对其属性数据的存储,那么,要搞清楚state内部的元素,就只有跟踪用过它地方,进行反推了。
下面截取源码中往这个对象中进行塞值的地方,然后将其聚合,形成我要返回对象中包含的属性。

state.putInfo("url", PathFormat.format(savePath));
state.putInfo("type", suffix);
state.putInfo("original", "");
state.putInfo("size", (long)data.length);
state.putInfo("title", file.getName());
private boolean state = false;

通过对上面属性的聚合,最终完成重构后端接口上传file时,点击上传按钮的请求的返回结果对象的字符串的拼接;
同时需要说明一点,源码中,处理上传文件的方式是将文件保存到服务器本地,而我这里是将文件传输给oss进行存储。下面是我的处理文件上传的接口的逻辑程序:

  @Override
    public String saveFile(MultipartFile upFile) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 上传Byte数组。
        byte[] content;
        try {
            content = upFile.getBytes();
            ossClient.putObject(bucketName, objectName + File.separator + upFile.getOriginalFilename(), new ByteArrayInputStream(content));
            // 关闭OSSClient。
            final String url = String.format("https://%s.%s/%s%s%s", bucketName, endpoint, objectName, File.separator, upFile.getOriginalFilename());
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("url", url);
            jsonObject.put("size", upFile.getSize());
            jsonObject.put("title", upFile.getName());
            jsonObject.put("type", upFile.getContentType());
            jsonObject.put("original", upFile.getOriginalFilename());
            jsonObject.put("state", "SUCCESS");
            return jsonObject.toJSONString();
        } catch (IOException e) {
            log.error("OSS upload file occur IO exception ~!", e);
        } finally {
            ossClient.shutdown();
        }
        return null;
    }

3、实现效果

对上上面工作进行简单总结:
1、前端配置文件修改配置serverURL到我新写的服务地址;
2、在服务接口中,设置请求参数,当请求参数是config的时候,服务config.json配置文件,将内容以字符串的方式返回;如果是文件类型的,则将文件存储到oss上,并根据state属性,组装返回对象,将其转化成json字符串返回。

处理之前的效果:


处理之后的效果


image.png
image.png

image.png

相关文章

  • UEditor java 后端代码重构

    1、需求 使用百度的富文本编辑器,发送附件上传功能不太好使,点击附件上传的时候,报错【后端配置项没有正确加载,上传...

  • 代码重构 - 后端部分代码

    前一篇主要写了一下前端部分的重构,这一篇则主要关注后端部分。 在前一篇后面说到了一个很实用的套路(模式),其类图如...

  • 待看书籍-02-26

    《Effective Java》 《Java编程思想》 《重构:改善既有代码质量》

  • WebSocket 心跳 登陆 实例代码!

    · JS-前端代码. · JAVA-后端代码.

  • 个人技术文章系列汇总(csdn)

    Java基础 Effective Java读书笔记 java 几种加载驱动的方法 《重构改善既有代码的设计》代码的...

  • Java代码重构

    1、什么是重构? 在不改变代码接口的情况下,对代码作出修改,以改进程序的内部结构。本质上说,重构就是在代码写好之后...

  • 2. UEditor Java后端配置

    背景UEditor 1.4.0 版本对之前的配置方式进行了简化,具体请参见:后端请求规范,为了适应这次升级,JAV...

  • Java学习书

    《Java编程思想》 《大话设计模式》 《重构 改善既有代码的设计》,《effective java》 《深入理解...

  • 重构 - 异常处理

    公司早期后端服务(nodejs),异常返回体如下: 现在重构成 java,用的是 spring boot 。但是在...

  • 第十一周周报:05-07~05-13

    工作: 本周工作:1>分账代码重构完毕,发布测试服务器测试;2>太易保APP,后端项目准备开发:思考APP和后端如...

网友评论

      本文标题:UEditor java 后端代码重构

      本文链接:https://www.haomeiwen.com/subject/fljvmhtx.html