假设现在有一个需求:一个前端请求抵达Java后端后,经过6次接口调用,横跨3个类,在6个接口中,在调用第4个接口时,可能会产生多条消息,这些消息最终需要返回给前端。那么,如何将消息返回给Controller层的接口?最简单的方式可能是将在全部6个接口中封装一个对象,作为参数层层传递。但弊端也有2点:
- 使得接口之间耦合太深,为了实现这一个小小的需求,给6个接口都加上一个消息入参,一旦需求有变,需要修改这6个接口;
- 使得接口职责不再纯粹,接口应该是根据实际的需求,完成某项职责,如将文件存储到本地。
在不考虑引入外部工具,仅依靠Java自身的特性,使用单例模式,代码如下:
package com.**.**.**;
import java.util.HashMap;
/**
* @author mason
* @version 1.0
* @description: 文件上传返回消息处理类
* @date 2022/6/21 13:36
*/
public class FileHandleMsg {
// 单例的文件处理类实例
private static final FileHandleMsg fileHandleMsg = new FileHandleMsg();
// 存储文件处理消息的MAP
private HashMap<Long, String> msgMap = new HashMap<>();
/***
* @description 构造方法私有,禁止外部创建新实例
* @return
* @author mason
* @date 2022/6/21 14:33
*/
private FileHandleMsg(){}
/***
* @description 对外暴露的获取类实例的方法
* @return com.sw.collect.vos.FileHandleMsg
* @author mason
* @date 2022/6/21 14:34
*/
public static FileHandleMsg getInstance() {
return fileHandleMsg;
}
/***
* @description 添加文件处理返回消息
* 以任务id作为key,若之前已存在该任务的消息,则将新消息追加到原有消息后面
* @param taskId 任务id
* @param msg 消息
* @return void
* @author mason
* @date 2022/6/21 14:34
*/
public void addMsg(Long taskId, String msg) {
if (msgMap.containsKey(taskId)) {
StringBuilder sb = new StringBuilder(msgMap.get(taskId));
sb.append(msg);
msgMap.replace(taskId, sb.toString());
} else {
msgMap.put(taskId, msg);
}
}
/***
* @description 获取文件处理消息,获取到消息后,从map中移除此消息
* @param taskId 任务id
* @param defaultMsg 默认消息,若该任务没有异常消息,则返回此默认消息
* @return java.lang.String
* @author mason
* @date 2022/6/21 14:36
*/
public String getMsg (Long taskId, String defaultMsg) {
String msg = defaultMsg;
if (msgMap.containsKey(taskId)) {
msg = msgMap.get(taskId);
msgMap.remove(taskId);
}
return msg;
}
}
在保存消息的地方,按如下方式调用:
// 以taskId作为key存储在FileHandleMsg的Map中
FileHandleMsg.getInstance().addMsg(taskId, "文件存储异常");
在Controller层,按如下方式调用。理论上Map存储的数据大小只受限于int的最大值,但如果不及时清理Map中的数据,还是会造成Map过大的情况,因此设定了在取得消息之后,随机从Map中删除该条记录。
return FileHandleMsg.getInstance().getMsg(taskId, "采集任务创建成功");