Hello,早上好,我是楼下小黑哥~ 最近偶然间在看到 Spring 官方文档的时候,新学到一个注解 展示具体重构代码之前,我们先来看下原先对外 API 接口是如何开发的。 这个 API 接口主要是用来与我们 APP 交互,这个过程我们统一定义一个交互协议,APP 端与后台 API 接口统一都使用 JSON 格式。 另外后台 API 接口对 APP 返回时,统一一些错误码,APP 端需要根据相应错误码,在页面弹出一些提示。 下面展示一个查询用户信息返回的接口数据: { "code": "000000", "msg": "success", "result": { "id": "1", "name": "test" } }
前端 APP 获取这个返回信息,首先判断接口返回 重构之前下面我们来看下,重构之前的,后台 API 层的如何编码。 /** * V1 版本 * * @return */ @RequestMapping("testv1") public APIResult testv1() { try { User user = new User(); user.setId("1"); user.setName("test"); return APIResult.success(user); } catch (APPException e) { log.error("内部异常", e); return APIResult.error(e.getCode(), e.getMsg()); } catch (Exception e) { log.error("系统异常", e); return APIResult.error(RetCodeEnum.FAILED); } } 上面的代码其实很简单,内部统一封装了一个工具类 @Data public class APIResult<T> implements Serializable { private static final long serialVersionUID = 4747774542107711845L; private String code; private String msg; private T result; public static <T> APIResult success(T result) { APIResult apiResult = new APIResult(); apiResult.setResult(result); apiResult.setCode("000000"); apiResult.setMsg("success"); return apiResult; } public static APIResult error(String code, String msg) { APIResult apiResult = new APIResult(); apiResult.setCode(code); apiResult.setMsg(msg); return apiResult; } public static APIResult error(RetCodeEnum codeEnum) { APIResult apiResult = new APIResult(); apiResult.setCode(codeEnum.getCode()); apiResult.setMsg(codeEnum.getMsg()); return apiResult; } 除了这个以外,还定义一个异常对象 上面的代码很简单,但是呢可以说比较繁琐,重复代码也比较多,每个接口都需要使用 第二呢,接口对象只能返回 重构之后下面我们开始重构上面的代码,主要目的是去除重复的那一坨 这次重构我们需要使用Spring 注解
改写返回信息首先我们需要实现 @ControllerAdvice public class CustomResponseAdvice implements ResponseBodyAdvice { /** * 是否需要处理返回结果 * @param methodParameter * @param aClass * @return */ @Override public boolean supports(MethodParameter methodParameter, Class aClass) { System.out.println("In supports() method of " + getClass().getSimpleName()); return true; } /** * 处理返回结果 * @param body * @param methodParameter * @param mediaType * @param aClass * @param serverHttpRequest * @param serverHttpResponse * @return */ @Override public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { System.out.println("In beforeBodyWrite() method of " + getClass().getSimpleName()); if (body instanceof APIResult) { return body; } return APIResult.success(body); } } 实现上面的接口,我们就可以在 上面代码中,只是简单使用 另外,这里判断一下 body 是否 这么做一来兼容之前的老接口,这是因为默认情况下,我们自己实现的 如果不做判断,以前的老接返回就会被包装了两层 除此之外,如果大家担心这个修改对以前的老接口有影响的话,可以使用下面的方式,只对指定的方法生效。 首先自定义一个注解,比如说: @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CustomResponse { } 然后将其标注在需要改动的方法中,然后我们在 /** * 是否需要处理返回结果 * * @param methodParameter * @param aClass * @return */ @Override public boolean supports(MethodParameter methodParameter, Class aClass) { System.out.println("In supports() method of " + getClass().getSimpleName()); Method method = methodParameter.getMethod(); return method.isAnnotationPresent(CustomResponse.class); } 全局异常处理上面的代码重构之后,将重复代码抽取了出来,整体的代码就剩下我们的业务逻辑,这样就变得非常简洁优雅。 不过,上面的重构的代码,还是存在问题,主要是异常的处理。 如果上面的业务代码抛出了异常,那么接口将会返回堆栈错误信息,而不是我们定义的错误信息。所以下面我们这个,再次优化一下。 这次我们主要需要使用 @Slf4j @ControllerAdvice public class CustomExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public APIResult handleException(Exception e) { log.error("系统异常", e); return APIResult.error(RetCodeEnum.FAILED); } @ExceptionHandler(APPException.class) @ResponseBody public APIResult handleAPPException(APPException e) { log.error("内部异常", e); return APIResult.error(e.getCode(), e.getMsg()); } } 使用这个 总结我们可以使用 另外,针对业务代码的中,我们可以使用 不过这里需要一点,我们实现的 |
|