自定義spring mvc的json視圖

場景

咱們團隊如今面臨着多端數據接口對接的問題,爲了解決這個問題咱們定義了接口對接的規範,
前端(安卓,Ios,web前端)和後端進行了數據的格式規範的討論,肯定了json的數據格式:前端

{
    "code":"200",
    "data":{"":""},
    "message":"處理成功"
}
{
    "code":"300",
    "data":{"":""},
    "message":"沒有此用戶"
}

code表明請求處理狀態:200爲正常處理,300爲業務異常處理,500就係統異常處理。
data表明後臺返回的數據。
message後臺的提示語,正常或者成功的時候會返回錯誤緣由。web

問題來了

讓每個人對每個json視圖的返回值都要進行包裝的話,豈不很麻煩,
這個時候AOP就登場了,咱們能夠利用aop的思想在請求返回json以後還未response到客戶端時爲其包裝上一層。spring

實現步驟

啓用aop

<!-- base-package 若是多個,用「,」分隔 -->
    <context:component-scan base-package="com.we,cn.isuyang">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    <!-- 打開aop 註解 -->
   <aop:aspectj-autoproxy />

建立切面

/**
 * json返回切面
 * <p>
 * 用於處理json返回結果
 *
 * @author   ZhuangJunxiang(529272571@qq.com)
 * @Date     2017年4月28日      
 */
@Component
@Aspect
@Order(2)
public class JsonReturnAspect {
        
    /**
     * 設置分頁默認值
     * <p>
     * 若是分頁沒有設置值,則默認從系統的配置文件裏讀取
     *
     * @param pjp 切點
    */
    @Around(value = "@annotation(org.springframework.web.bind.annotation.ResponseBody)")
    @Order(1)
    public Object warp(final ProceedingJoinPoint pjp) throws Throwable {
        Object list = pjp.proceed();
        if (isReturnVoid(pjp)) {
            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getResponse();
            if (isNeedWrap(pjp)) {
                response.getWriter().write(JsonUtil.toJson(success("操做成功")));
            }
            return list;
        }
        return data(list);
    }
    /**
     * 是否須要包裹
     *
     * @param pjp 切點
     * 
     * @return true表示不須要
    */
    private boolean isNeedWrap(final ProceedingJoinPoint pjp) {
        Method method = AspectUtil.getMethod(pjp);
        return !method.isAnnotationPresent(Void.class);
    }
    /**
     * 是否返回空
     *
     * @param pjp
     * @return true:返回類型爲void,false:返回類型不是void
    */
    private boolean isReturnVoid(ProceedingJoinPoint pjp) {
        Method method = AspectUtil.getMethod(pjp);
        Class<?> returnType = method.getReturnType();
        return "void".equals(returnType.getName());
    }  

    /**
     * 構建成功後的返回對象
     * <p>
     * 消息爲空時,不提示,不爲空則進行提示
     * 
     * @param message 成功消息
     * @return json對象
     */
    public static Map<String, Object> success(final String message) {
        Map<String, Object> map = MapUtil.map();
        map.put("code", StatusCode.SUCCESS.key());
        map.put("message", message);
        map.put("data","");
        return map;
    }        
    /**
     * 構建成功後的返回對象
     * <p>
     * 消息爲空時,不提示,不爲空則進行提示
     * 
     * @param message 成功消息
     * @return json對象
     */
    public static Map<String, Object> data(final Object data) {
        Map<String, Object> map = MapUtil.map();
        map.put("code", StatusCode.SUCCESS.key());
        map.put("message", message);
        map.put("data",data);
        return map;
    }        
}

分析一下

@Component 這個註解表示將這個對象交給spring容器進行實例化express

@Aspect 表示這是一個切面類json

@Around(value = "@annotation(org.springframework.web.bind.annotation.ResponseBody)")後端

表示凡是方法上帶有@ResponseBody註解的都是這個切面中切點,換句話說都會被攔截。app

注意:
warp方法中的ProceedingJoinPoint參數只有環繞通知纔可使用JoinPoint的子類ProceedingJoinPoint,
各鏈接點類型能夠調用代理的方法,並獲取、改變返回值。不然就是用JoinPoint。函數

狀況一:假設conroller類中的函數不須要任何返回值

好比:我對一個實體對象進行更新我只須要把更新結果返回去就OK了,不須要填充數據
返回的數據格式:
{
"code":"200",
"data":"",
"message":"處理成功"
}
實現思路:
在切面處理類的處理函數中獲取到這個函數的返回值類型若是是void就返回指定格式的數據。
上面的isReturnVoid()就是作這樣的一個判斷。.net

你只須要將函數的返回值爲void便可:插件

@RequestMapping
@ResponseBody
public void add(long matchId, Model model) {
    slxSignupViewService.setAddInfo(matchId, model);
}

狀況二:假設conroller類中的函數的返回值不須要包裹呢

好比:
某些前端插件以及第三方對接(支付)的返回值是規定好的,
以及下載文件,咱們這些就是多餘了,
實現思路:
自定一個@Void的註解:

/**
 * 空註解
 * <p>
 * 用於標識將controller層中的返回值原模原樣的out出去
 * 
 * @author   WangSen(wangsenhehe@126.com)
 * @Date     2017年8月17日      
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Void {

}

在controller層的方法上添加這個註解

/**
   * 支付完成
   */
@Void
@ResponseBody
@RequestMapping
public void payFinish() throws IOException {
        alipayViewService.payFinish();
}

在這個切面處理類上判斷這個函數是否包含這個註解若是包含
就不做處理,原模原樣的返回出去。
JsonReturnAspect類中的isNeedWrap()方法就是處理這個需求。

參考資料

http://blog.csdn.net/zx13525079024/article/details/51884234

相關文章
相關標籤/搜索