马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
1.同一数据返回格式
欺压登录案例中, 我们共做了两部分⼯作
1. 通过Session来判断⽤户是否登录
2. 对后端返回数据进⾏封装, 告知前端处理处罚的结果(设置status401等)
回想我们在给前端返回时举行了一个同一的数据包装- @Data
- public class Result<T> {
- private int status;//1. 200成功 2. -1未登录 3. -2 异常
- private String errorMsg;//错误信息
- private T data;
- /**
- * 登录成功
- * @param data
- * @param <T>
- * @return
- */
- public static <T> Result success(T data) {
- Result result = new Result();
- result.setStatus(ResultStatus.SUCCESS.getCode());
- result.setErrorMsg("");
- result.setData(data);
- return result;
- }
- /**
- * 未登录
- * @return
- */
- public static Result unLogin() {
- Result result = new Result();
- result.setErrorMsg("未登录,请登录后访问");
- result.setStatus(ResultStatus.UNLOGIN.getCode());
- return result;
- }
- /**
- * 登录失败
- * @param data
- * @param <T>
- * @return
- */
- public static <T> Result fail(String msg) {
- Result result = new Result();
- result.setErrorMsg(msg);
- result.setStatus(ResultStatus.FAIL.getCode());
- result.setData("");
- return result;
- }
- }
复制代码 假如能将返回的数据全部都包装为Result那么代码就更加结实了(方便后续的添加修改)
参考拦截器,我们肯定不会对原来的方法返回结果直接一个一个修改。
SpringBoot也对此功能举行了支持
使用方法:
统⼀的数据返回格式使⽤ @ControllerAdvice 和 ResponseBodyAdvice 的⽅式实现 - @ControllerAdvice
- public class ResponseAdvice implements ResponseBodyAdvice {
- @Override
- public boolean supports(MethodParameter returnType, Class converterType) {
- return true;
- }
-
- @Override
- public Object beforeBodyWrite(Object body, MethodParameter returnType,
- MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest
- request, ServerHttpResponse response) {
- return Result.success(body);
- }
- }
复制代码
@ControllerAdvice注解已经包罗五大注解,会交给Spring举行管理
这个类有两个方法:supports(),beforeBodyWrite()
supports():判断是否要执⾏beforeBodyWrite⽅法. true为执⾏, false不执⾏
可以通过参数获取类及方法誊写逻辑:- @Override
- public boolean supports(MethodParameter returnType, Class converterType) {
- //获取执行方法的类
- Class<?> declaringClass = returnType.getMethod().getDeclaringClass();
- //获取执行的方法
- Method method = returnType.getMethod();
- //判断是否执行beforeBodyWrite方法 true--执行 false--不执行
- return true;
- }
复制代码 beforeBodyWrite(): 对response⽅法进⾏详细操纵处理处罚
在这里是将返回数据包装后返回给前端
但是这里假如直接对String举行包装返回会出现错误:
写一个测试类:- @RestController
- @RequestMapping("/test")
- public class TestController {
- @RequestMapping("/t1")
- public String t1() {
- return "t1";
- }
- @RequestMapping("/t2")
- public Integer t2() {
- return 2;
- }
- @RequestMapping("/t3")
- public Boolean t3() {
- return true;
- }
- }
复制代码
而其他范例不会出现这种环境。出现这种环境是在源码阶段的范例不匹配(这里不举行穷究)
解决方法是将返回的Result转换成Spring范例。- private static ObjectMapper mapper = new ObjectMapper();
- if(body instanceof String) {
- //将result类型转化为String类型 否则在源码阶段会出现类型不匹配
- return mapper.writeValueAsString(Result.success(body));
- }
复制代码 假如返回的范例就是Result则不消转换,直接返回- //如果body是Result类型就直接返回
- if(body instanceof Result) {
- return body;
- }
复制代码 最终代码:- /** * 同一结果返回 */@Slf4j@ControllerAdvicepublic class ResponseAdvice implements ResponseBodyAdvice { private static ObjectMapper mapper = new ObjectMapper();
- @Override
- public boolean supports(MethodParameter returnType, Class converterType) {
- //获取执行方法的类
- Class<?> declaringClass = returnType.getMethod().getDeclaringClass();
- //获取执行的方法
- Method method = returnType.getMethod();
- //判断是否执行beforeBodyWrite方法 true--执行 false--不执行
- return true;
- } @SneakyThrows @Override public Object beforeBodyWrite(Object body, MethodParameter returnType , MediaType selectedContentType, Class selectedConverterType , ServerHttpRequest request, ServerHttpResponse response) { //判断body是否是String范例 if(body instanceof String) { //将result范例转化为String范例 否则在源码阶段会出现范例不匹配 return mapper.writeValueAsString(Result.success(body)); }
- //如果body是Result类型就直接返回
- if(body instanceof Result) {
- return body;
- } return Result.success(body); }}
复制代码 2.同一非常处理处罚
在上一步同一结果返回时,假如范例不匹配,并没有爆出非常(最外层显示200),这是我们不能吸取的。
我们固然可以对每一块代码举行trycacth围绕,但同样面对冗余的环境。
解决方法是:同一非常处理处罚
统⼀非常处理处罚使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的
@ControllerAdvice 控制器关照类(标识作用), @ExceptionHandler 是非常处理处罚器,两个团结表⽰当出现非常的时间执⾏某个关照,也就是执⾏某个⽅法变乱
记得加: @ResponseBody- /**
- * 统一异常处理
- */
- //接⼝返回为数据时, 需要加 @ResponseBody 注解
- @ControllerAdvice
- @ResponseBody
- public class ErrorAdvice {
- @ExceptionHandler
- public Object handler(Exception e) {
- return Result.fail(e.getMessage());
- }
- }
复制代码 假如代码出现Exception非常(包罗Exception的⼦类), 就返回⼀个 Result的对象, Result 对象的设置参考 Result.fail(e.getMessage())- public static <T> Result fail(String msg) {
- Result result = new Result();
- result.setErrorMsg(msg);
- result.setStatus(ResultStatus.FAIL.getCode());
- result.setData("");
- return result;
- }
复制代码 固然,只能爆Exception这么宽泛的非常就没有意义了
我们可以针对差别的非常, 返回差别的结果- @ExceptionHandler
- public Object handler(Exception e) {
- return Result.fail(e.getMessage());
- }
- //空指针异常
- @ExceptionHandler
- public Object handler(NullPointerException e) {
- return Result.fail(e.getMessage());
- }
- //算数异常
- @ExceptionHandler
- public Object handler(ArithmeticException e) {
- return Result.fail(e.getMessage());
- }
复制代码 如今我们在测试类中添加两个非常观察一下:- @RequestMapping("/t1")
- public String t1() {
- String s = "1";
- char a = s.charAt(2);
- return "t1";
- }
- @RequestMapping("/t2")
- public Integer t2() {
- int s = 10/0;
- return 2;
- }
复制代码
它会抛出隔断最近的非常
针对差别的非常, 返回差别的结果尚有一种写法:- //算数异常
- @ExceptionHandler(ArithmeticException.class)
- public Object handler1(Exception e) {
- return Result.fail(e.getMessage());
- }
- @ExceptionHandler(NullPointerException.class)
- public Object handler2(Exception e) {
- return Result.fail(e.getMessage());
- }
- @ExceptionHandler(Exception.class)
- public Object handler3(Exception e) {
- return Result.fail(e.getMessage());
- }
复制代码 将非常加在注解中
|