SpringMVC利用注解 规范http接口返回值
一般在项目构建时,会选择定义基础接口返回值规范实体,并直接规定返回实体,但在控制器上对实体的进行的实例化会产生多余代码,为了减少这一部门的冗余代码,部分项目会采用注解的方式或者直接全局使用切面来处理返回值。以下我将介绍一下我的处理方案。
实现代码:
注解代码:
import java.lang.annotation.*;
/**
* 如果该注解的方法出现异常,则会反馈标准的异常结果【ResponseMsg.java】给前端或者服务调用方
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyResponse {
}
返回值实体用于测试,具体的web应用,可以具体使用项目的规范,以下只是测试时使用的实体规范,具体应用时可以根据具体需要来拼装数据
import lombok.Data;
/**
* 接口默认返回参数
* lombok.Data 可以改成直接写入封装方法
*/
@Data
public class ResponseMsg {
/**
* 代码
*/
private int code;
/**
* 消息
*/
private String msg;
/**
* 是否成功
*/
private boolean success;
/**
* 数据
*/
private Object data;
}
自定义异常,用于测试,同理可根据具体项目需求改变
import lombok.Data;
@Data
public class MyException extends RuntimeException{
private int code;
/**
* 构造
*/
public MyException(int code, String msg) {
super(msg);
this.code = code;
}
}
关键代码,返回值切面,JSON,Slf4j类根据具体项目依赖处理,此处为了减少代码增加了这个类。
实际就是利用切面获取返回值并拼装,处理Object及void类型,并通过捕捉切点的异常封装返回值。
建议将切面位置提前,保证其他切面的异常不影响返回值的规范。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import self.aop.anno.MyResponse;
import self.aop.model.ResponseMsg;
import self.exception.MyException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 使用AOP拦截出现异常的Controller的方法,并反馈标准的异常描述
*
* @Slf4j可以去掉,换成手动的log
*/
@Order(1)
@Aspect
@Component
@Slf4j
public class ResponseAspect {
private static final String VOID = "void";
private static final int ERR_CODE = 500;
@Around(value = "@annotation(catchErr)")
public Object doAudit(ProceedingJoinPoint point, MyResponse catchErr) throws Throwable {
Object returnVal;
ResponseMsg resultMsg;
try {
returnVal = point.proceed();
} catch (MyException ex) {
resultMsg = new ResponseMsg();
resultMsg.setCode(ex.getCode());
resultMsg.setMsg(ex.getMessage());
resultMsg.setSuccess(false);
writeResultMessage2Writer(point, resultMsg);
log.info("{}", ex);
return resultMsg;
} catch (Exception ex) {
resultMsg = new ResponseMsg();
resultMsg.setCode(ERR_CODE);
resultMsg.setMsg(ex.getMessage());
resultMsg.setSuccess(false);
writeResultMessage2Writer(point, resultMsg);
log.error("{}", ex);
return resultMsg;
}
resultMsg = new ResponseMsg();
resultMsg.setCode(200);
resultMsg.setMsg("成功");
resultMsg.setSuccess(true);
Class returnType = ((MethodSignature) point.getSignature()).getReturnType();
if (StringUtils.equals(returnType.getName(), VOID)) {
writeResultMessage2Writer(point, resultMsg);
}
resultMsg.setData(returnVal);
return resultMsg;
}
/**
* 返回void情况下单独做response处理防止无法输出
* @param point 切点
* @param resultMsg 消息实体
* @throws IOException io异常
*/
private void writeResultMessage2Writer(ProceedingJoinPoint point, ResponseMsg resultMsg) throws IOException {
Class returnType = ((MethodSignature) point.getSignature()).getReturnType();
if (!StringUtils.equals(returnType.getName(), VOID)) {
return;
}
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
response.setCharacterEncoding("UTF-8");
response.setHeader("content-type", "application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(resultMsg, SerializerFeature.PrettyFormat));
}
}
以下是测试使用的web控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import self.aop.anno.MyResponse;
import self.exception.MyException;
/**
* 返回值规范测试控制器
*/
@Controller
@RequestMapping("response/msg")
public class ResponseMsgController {
@PostMapping("/object")
@MyResponse
@ResponseBody
public Object objectFunction(){
return "data";
}
@PostMapping("/void")
@MyResponse
@ResponseBody
public void voidFunction(){}
@PostMapping("/my/exception")
@MyResponse
@ResponseBody
public void myExceptionFunction(){
throw new MyException(501,"手动抛自定义异常");
}
@PostMapping("/exception")
@MyResponse
@ResponseBody
public void exceptionFunction(){
throw new RuntimeException("手动抛其他异常");
}
}
Object类型返回值
void类型返回值
自定义异常返回值
其他异常返回值