自己写个方法,实现ResponseBodyAdvice接口,如
import cn.linkengine.pre.service.config.mvc.annotation.ResponseBabyMessage;
import cn.linkengine.pre.service.config.mvc.annotation.SimpleResponseBody;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author: yuhh
* @create: 2019-01-07 15:17
**/
@ControllerAdvice
public class SimpleResponseBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return !returnType.getMethod().getReturnType().isAssignableFrom(JsonVo.class) && (returnType.hasMethodAnnotation(SimpleResponseBody.class) || AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), SimpleResponseBody.class));
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return JsonVo.buildSuccess(body);
}
}
@ControllerAdvice:可以对控制器的进行全局配置
supports(MethodParameter returnType, Class converterType):判断是否需要进行处理,返回true则会进行拦截并统一返回格式
//如果本次请求的返回值是否是JsonVo,不是的话才需要拦截
!returnType.getMethod().getReturnType().isAssignableFrom(JsonVo.class)
//本次请求的方法上是否有SimpleResponseBody注解,有的话才需要拦截
&& (returnType.hasMethodAnnotation(SimpleResponseBody.class) ||
// 本次请求的方法上是否有注解包含SimpleResponseBody注解,有的话才需要拦截
AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), SimpleResponseBody.class));
beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response):对返回值进行统一处理
以下是我用到的注解:
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.annotation.*;
/**
* @Auther: yuhh
* @Date: 2019/1/7 15:14
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ResponseBody
public @interface SimpleResponseBody {
}
import org.springframework.stereotype.Controller;
import java.lang.annotation.*;
/**
* @Auther: yuhh
* @Date: 2019/1/7 15:12
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@SimpleResponseBody
public @interface SimpleRestController {
}
然后在controller上标注SimpleRestController 注解,如
import cn.linkengine.pre.service.config.mvc.annotation.SimpleRestController;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Auther: yuhh
* @Date: 2018/7/6 17:01
*/
@SimpleRestController
@RequestMapping("/dictionaryController")
@Api(description = "数据字典api")
public class DictionaryController {
}
注意:SimpleRestController注解中因为标注了SimpleResponseBody注解,而SimpleResponseBody注解中又标注了ResponseBody注解,因此SimpleRestController注解是和RestController注解一样,无法返回jsp页面,或者html页面
这样会有一个问题,那就是无法controller中的方法无法返回String类型的返回值,不然会报类型转换失败的异常,我想了个旁门左道去解决该问题
新建一个注解
import java.lang.annotation.*;
/**
* 设置需要返回的String值
* @Auther: yuhh
* @Date: 2019/1/9 15:01
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBabyMessage {
String message() default "";
}
然后修改ResponseBodyAdvice 的beforeBodyWrite方法
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 判断该方法上是否有ResponseBabyMessage注解
if (returnType.hasMethodAnnotation(ResponseBabyMessage.class)){
String message = returnType.getMethodAnnotation(ResponseBabyMessage.class).message();
}
return JsonVo.buildSuccessMessage(message);
}
return JsonVo.buildSuccess(body);
}
但这样又会出现一个问题,那就是这个系统中该方法都只能有一个返回值,无法在方法里动态的修改返回值,我又想了个旁门左道去解决该问题
import cn.linkengine.pre.service.config.mvc.annotation.ResponseBabyMessage;
import java.lang.reflect.Method;
/**
* @author: yuhh
* @create: 2019-01-09 15:23
**/
public class ChangeResponseBabyMessage {
private static ThreadLocal<String> messageThreadLocal = new ThreadLocal<>();
/**
* 如果满足该类中有指定方法且方法上有ResponseBabyMessage注解,则改变其方法上的ResponseBabyMessage的message值
* 因为注解是单例,所以用了迂回的方式,声明一个线程变量
* @param: cls:指定类
* @param: methodName:指定方法名
* @param: message:需要改变的message值
* @return: void
* @author: yuhh
* @date: 2019/1/10 11:10
*/
public static void changeMeaage(Class cls, String methodName, String message){
//如果满足该类中有指定方法且方法上有ResponseBabyMessage注解,则改变其方法上的ResponseBabyMessage的message值
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods){
if (m.getName().equals(methodName) && m.isAnnotationPresent(ResponseBabyMessage.class)){
messageThreadLocal.set(message);
break;
}
}
// 因为注解是单例,所以不满足需求,故废弃之
// Method[] methods = cls.getDeclaredMethods();
// ResponseBabyMessage responseBabyMessage = null;
// for (Method m : methods){
// if (m.getName().equals(methodName) && m.isAnnotationPresent(ResponseBabyMessage.class)){
// responseBabyMessage = m.getDeclaredAnnotation(ResponseBabyMessage.class);
// break;
// }
// }
// try {
// //获取 responseBabyMessage 这个代理实例所持有的 InvocationHandler
// InvocationHandler h = Proxy.getInvocationHandler(responseBabyMessage);
// // 获取 AnnotationInvocationHandler 的 memberValues 字段
// Field hField = h.getClass().getDeclaredField("memberValues");
// // 因为这个字段事 private final 修饰,所以要打开权限
// hField.setAccessible(true);
// // 获取 memberValues
// LinkedHashMap memberValues = (LinkedHashMap) hField.get(h);
// // 修改 message 属性值
// memberValues.put("message", message);
// } catch (Exception e) {
// e.printStackTrace();
// }
}
/**
* 获取线程变量message的值
* @param:
* @return: java.lang.String
* @author: yuhh
* @date: 2019/1/10 13:58
*/
public static String getMessage(){
return messageThreadLocal.get();
}
/**
* 清除线程变量message的值
* @param:
* @return: void
* @author: yuhh
* @date: 2019/1/10 13:59
*/
public static void cleanMessage(){
messageThreadLocal.remove();
}
}
同时修改ResponseBodyAdvice 的beforeBodyWrite方法
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 判断该方法上是否有ResponseBabyMessage注解
if (returnType.hasMethodAnnotation(ResponseBabyMessage.class)){
// 先取线程变量的值
String message = ChangeResponseBabyMessage.getMessage();
// 如果线程变量的值不为空,则说明message已经被修改了
if (!StringUtils.isEmpty(message)){
// 取完值后移除线程变量的值
ChangeResponseBabyMessage.cleanMessage();
} else {
// 如果线程变量的值为空,则去注解上的message默认值
message = returnType.getMethodAnnotation(ResponseBabyMessage.class).message();
}
return JsonVo.buildSuccessMessage(message);
}
return JsonVo.buildSuccess(body);
}
放个例子上来
import cn.linkengine.pre.service.business.camera.domain.entity.PsCameraParkingLotConfig;
import cn.linkengine.pre.service.business.camera.park.service.ParkingLotConfigService;
import cn.linkengine.pre.service.config.mvc.ChangeResponseBabyMessage;
import cn.linkengine.pre.service.config.mvc.annotation.ResponseBabyMessage;
import cn.linkengine.pre.service.config.mvc.annotation.SimpleRestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author: yuhh
* @create: 2018-10-16 14:18
**/
@SimpleRestController
@RequestMapping("parkingLotConfigController")
@Api(description = "停车场接口配置api")
public class ParkingLotConfigController {
@Autowired
private ParkingLotConfigService parkingLotConfigService;
@PostMapping(value = "saveParkInterface")
@ApiOperation(value = "保存停车场接口", notes = "保存停车场接口")
@ResponseBabyMessage(message = "保存成功")
public void saveParkInterface(PsCameraParkingLotConfig psCameraParkingLotConfig, String userId){
psCameraParkingLotConfig.setUpdateUserId(userId);
if (parkingLotConfigService.canSaveByParkingLotIdAndInterfaceCode(psCameraParkingLotConfig)){
if (psCameraParkingLotConfig.getId() == null){
psCameraParkingLotConfig.setCreateUserId(userId);
parkingLotConfigService.singSave(psCameraParkingLotConfig);
} else {
parkingLotConfigService.update(psCameraParkingLotConfig);
}
} else {
ChangeResponseBabyMessage.changeMeaage(this.getClass(), "saveParkInterface", "该停车场已经配置了该接口,无需再次配置");
}
}
}