概述
应用范围和场景
和统一异常处理不同,有些时候Controller处理可能需要做后续处理,例如关键字拦截,例如数据脱敏等,使用切面的方式比较复杂,如果Controller里需要后续处理的接口使用的都是@ResponseBody注解,那么实现ResponseBodyAdvice接口将是非常便利的处理方法,当然使用拦截器、HandlerMethodReturnValueHandler接口实现也是几种方法,这里仅示例更简单的ResponseBodyAdvice接口使用实现。
应用示例
我们想对所有接口返回的json数据替换掉一些关键字,例如域名信息等,仅需多写一个@ControllerAdvice注解并实现了ResponseBodyAdvice的类即可。如下:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.endcy.common.entity.CommonResult;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.util.List;
import java.util.Map;
/**
* @ClassName: ResponseBodyReturnAdvice
* @Author: ss
* @Description: 参数返回拦截
* @Date: 2021/5/8 17:06
*/
@ControllerAdvice
public class ResponseBodyReturnAdvice implements ResponseBodyAdvice<Object> {
private static Logger logger = LoggerFactory.getLogger(ResponseBodyReturnAdvice.class.getName());
@Value("${upload.host}")
private String uploadHost;
@Value("${upload.replace.host:http://abc.net,http://abcd.net}")
private String uploadReplaceHost;
private static final String HOST_SPLIT_STR = ",";
/**
* @throws null
* @description 是否执行beforeBodyWrite
* @author ss
* @updateTime 2021/5/8 17:53
*/
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
/**
* @throws null
* @description 返回值资源域名替换
* @author ss
* @updateTime 2021/5/8 18:24
*/
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (!(o instanceof CommonResult || o instanceof List || o instanceof Map)) {
logger.info("return type does not be exchange");
return o;
}
if (true) { //test
return o;
}
String returnJsonStr = JSON.toJSONStringWithDateFormat(o, "yyyy-MM-dd HH:mm:ss");
logger.info("TestResponseBodyAdvice==>beforeBodyWrite:{}", returnJsonStr);
//不需要替换
if (StringUtils.isEmpty(uploadReplaceHost)) {
return o;
}
String[] replaceHostList = uploadReplaceHost.split(HOST_SPLIT_STR);
uploadHost = "http://abcd.net";
//开始轮训替换字符串
boolean hasReplace = false;
for (String str : replaceHostList) {
if (!str.equals(uploadHost) && returnJsonStr.contains(str)) {
returnJsonStr = returnJsonStr.replaceAll(str, uploadHost);
logger.info("ResponseBodyReturnAdvice has replaced 【{}】 to 【{}】", str, uploadHost);
hasReplace = true;
}
}
if (hasReplace) {
o = JSON.parseObject(returnJsonStr, o.getClass(), Feature.OrderedField);
}
logger.info("TestResponseBodyAdvice==>methodParameter:{}", methodParameter);
return o;
}
}
这样,任何使用了ResponseBody注解的接口返回参数都将经过beforeBodyWrite方法处理,实现出参的拦截替换。
存在的问题
这么做并不能保证完整的需求业务,因为使用该方法会导致返回的数据存在一定的差异性,所以该方法和拦截器/切面作用类似,因为使用了序列化和反序列化操作,返回数据结果的差异性并不仅仅体现在关键字(域名)替换上,还存在如下问题:
* 1、序列换转对象后顺序乱了,如List不能保证之前的顺序性;
* 2、时间格式只能统一,不能long时间戳和Date共存,或者转换后时间格式和之前不一致;
* 3、不能处理拦截返回文件数据中的url值如导出接口。
最后
以上就是甜蜜冬天为你收集整理的SpringMVC中Controller返回的后续自定义处理的全部内容,希望文章能够帮你解决SpringMVC中Controller返回的后续自定义处理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复