如何优雅地实现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}

这样就基本上满足我们的需求了

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