如何優雅地實現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}
這樣就基本上滿足我們的需求了