如何優雅地實現Controller返回數據格式的統一

如何優雅地實現Controller返回數據格式的統一

在controller裏面,我們可以這樣實現返回格式的統一

@ResponseBody
    @RequestMapping(value = "saveReferenceInfo", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public JSONObject saveReferenceInfo(@RequestBody List<AfcApplicantVo> voList, String sessionKey){
        try{
            applicantService.saveReferenceInfo(voList);
        }catch (HandleException e){
            e.printStackTrace();
            return Success(ResultType.error, e.getMessage(), null);
        }catch (Exception e){
            e.printStackTrace();
            return Success(ResultType.error, "系統錯誤", null);
        }
        return Success(ResultType.success, "操作成功", null);
    }

但是這樣實現容易出現以下問題

  • 返回格式容易不統一
  • 每次都要硬編碼對返回數據進行處理,容易出錯
  • 代碼看起來會很混亂

那麼有沒有辦法來做統一的數據返回呢?

定義統一的數據返回
@ControllerAdvice(basePackages = "org.zj.test.test")
public class TestResponseBodyAdvice<T> implements ResponseBodyAdvice<T> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public T beforeBodyWrite(T t, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        Result<T> tResult = new Result<>();
        tResult.setCode(200);
        tResult.setMessage("操作成功");
        tResult.setData(t);
        return (T) tResult;
    }
}

這裏我們定義一個ControllerAdvice來對Controller的返回結果進行處理
請求過來的時候,會路由到方法上進行執行。這裏會先執行定義的supports方法,對返回值進行判斷。如果返回值爲true並且在往Response中寫入json之前纔會執行beforeBodyWrite方法。這裏沒有特殊要求,我就直接讓supports方法返回true了

我們看一下我們的測試代碼

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/t")
    public Student ttt() throws TestException {
        Result<Student> studentResult = new Result<>();
        studentResult.setCode(1);
        studentResult.setMessage("成功");
        Student student = new Student();
        student.setName("李四");
        student.setPassword("ffff");
        return student;
    }
}

調用接口就能看見他已經起作用了

{“code”:200,“message”:“操作成功”,“data”:{“name”:“李四”,“password”:“ffff”}}

定義統一的異常返回

先定義我們的異常類

public class TestException extends Exception {
    public TestException(String message) {
        super(message);
    }
}

然後定義我們的異常攔截

@ControllerAdvice
public class ResultHandler  {
    @ResponseBody
    @ExceptionHandler(TestException.class)
    public <T>Result<T> handle(HttpServletRequest request,TestException exception){
        Result<T> objectResult = new Result<>();
        objectResult.setMessage(exception.getMessage());
        objectResult.setCode(400000);
        return objectResult;
    }
}

注意,這裏我們加了異常處理的返回和通用的結果返回,必須要配置下通用結果返回的Supports方法的返回值,不然就會出現這種情況

{“code”:200,“message”:“操作成功”,“data”:{“code”:400000,“message”:“我故意的”,“data”:null}}

遇到異常後,這裏先處理了異常結果的返回,然後又經過了響應處理。
我們可以在響應處理的Supports方法裏面進行處理,判斷結果是否處理過,處理過就不處理了
只需要改一下這裏

 @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return methodParameter.getParameterType()!=Result.class;
    }

這裏直接判斷返回值是否是我定義的那個類,是的話就不處理了

然後就是測試代碼

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/t")
    public Student ttt() throws TestException {
        Result<Student> studentResult = new Result<>();
        studentResult.setCode(1);
        studentResult.setMessage("成功");
        throw new TestException("我故意的");
    }
}

這裏我直接手動在Controller方法中拋出了一個異常

{“code”:400000,“message”:“我故意的”,“data”:null}

這樣就基本上滿足我們的需求了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章