天天看點

SpringMVC利用注解 規範http接口傳回值SpringMVC利用注解 規範http接口傳回值

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類型傳回值

SpringMVC利用注解 規範http接口傳回值SpringMVC利用注解 規範http接口傳回值

void類型傳回值

SpringMVC利用注解 規範http接口傳回值SpringMVC利用注解 規範http接口傳回值

自定義異常傳回值

SpringMVC利用注解 規範http接口傳回值SpringMVC利用注解 規範http接口傳回值

其他異常傳回值

SpringMVC利用注解 規範http接口傳回值SpringMVC利用注解 規範http接口傳回值