首页IT科技java后端常用技术(Java后端通用接口设计)

java后端常用技术(Java后端通用接口设计)

时间2025-06-17 16:09:01分类IT科技浏览4346
导读:1、接口的响应要明确表示接口的处理结果 为了将接口设计得更合理,我们需要考虑如下两个原则:...

1            、接口的响应要明确表示接口的处理结果

为了将接口设计得更合理            ,我们需要考虑如下两个原则:

对外隐藏内部实现            。即服务A调用服务B                  ,如果服务B异常      ,但是我们不要直接把服务B的状态码                  、错误描述直接暴露给用户;

设计接口结构时      ,明确每个字段的含义                  ,以及客户端的处理方式                  。

比如下面这个是我们设计的接口的响应:

@Data public class APIResponse<T> { private boolean success; private T data; private int code; private String message; }

接口的设计逻辑:

如果出现非 200 的 HTTP 响应状态码            ,就代表请求没有到服务      ,可能是网络出问题      、网络超时                  ,或者网络配置的问题      。这时            ,肯定无法拿到服务端的响应体,客户端可以给予友好提示                  ,比如让用户重试                  ,不需要继续解析响应结构体      。

如果 HTTP 响应码是 200,解析响应体查看 success            ,为 false 代表下单请求处理失败                  ,可能是因为服务参数验证错误      ,也可能是因为服务操作失败                  。这时            ,根据服务定义的错误码表和 code                  ,做不同处理            。比如友好提示      ,或是让用户重新填写相关信息      ,其中友好提示的文字内容可以从 message 中获取      。

success 为 true 的情况下                  ,才需要继续解析响应体中的 data 结构体                  。data 结构体代表了业务数据            。

1.1      、通过ResponseBodyAdvice完成自动包装响应体

为了代码会更简洁            ,我们的业务逻辑中可以通过ResponseBodyAdvice完成响应体的包装。

@RestControllerAdvice @Slf4j public class APIResponseAdvice implements ResponseBodyAdvice<Object> { //自动处理APIException      ,包装为APIResponse @ExceptionHandler(APIException.class) public APIResponse handleApiException(HttpServletRequest request, APIException ex) { log.error("process url {} failed", request.getRequestURL().toString(), ex); APIResponse apiResponse = new APIResponse(); apiResponse.setSuccess(false); apiResponse.setCode(ex.getErrorCode()); apiResponse.setMessage(ex.getErrorMessage()); return apiResponse; } //仅当方法或类没有标记@NoAPIResponse才自动包装 @Override public boolean supports(MethodParameter returnType, Class converterType) { return returnType.getParameterType() != APIResponse.class && AnnotationUtils.findAnnotation(returnType.getMethod(), NoAPIResponse.class) == null && AnnotationUtils.findAnnotation(returnType.getDeclaringClass(), NoAPIResponse.class) == null; } //自动包装外层APIResposne响应 @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { APIResponse apiResponse = new APIResponse(); apiResponse.setSuccess(true); apiResponse.setMessage("OK"); apiResponse.setCode(2000); apiResponse.setData(body); return apiResponse; } }

实现了 @NoAPIResponse 自定义注解                  。如果某些 @RestController 的接口不希望实现自动包装的话                  ,可以标记这个注解:

@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface NoAPIResponse { }

在 ResponseBodyAdvice 的 support 方法中            ,我们排除了标记有这个注解的方法或类的自动响应体包装                  。比如,对于刚才我们实现的测试客户端 client 方法不需要包装为 APIResponse                  ,就可以标记上这个注解:

@GetMapping("client") @NoAPIResponse public String client(@RequestParam(value = "error", defaultValue = "0") int error){ }

这样我们在代码中                  ,就统一了响应体的处理,不用担心有些程序员别出心裁自己搞一套。

2                  、要考虑接口变迁的版本控制策略

接口不可能一成不变            ,需要根据业务需求不断增加内部逻辑            。如果做大的功能调整或重构                  ,涉及参数定义的变化或是参数废弃      ,导致接口无法向前兼容            ,这时接口就需要有版本的概念                  。在考虑接口版本策略设计时                  ,我们需要注意的是      ,最好一开始就明确版本策略      ,并考虑在整个服务端统一版本策略      。

第一                  ,版本策略最好一开始就考虑            。 第二            ,版本实现方式要统一                  。

为了实现上面的目的      ,我们可以通过注解的方式为接口增加基于 URL 的版本号:首先                  ,创建一个注解来定义接口的版本      。@APIVersion 自定义注解可以应用于方法或 Controller 上:

@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface APIVersion { String[] value(); }

然后            ,定义一个 APIVersionHandlerMapping 类继承 RequestMappingHandlerMapping      。

public class APIVersionHandlerMapping extends RequestMappingHandlerMapping { @Override protected boolean isHandler(Class<?> beanType) { return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class); } @Override protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) { Class<?> controllerClass = method.getDeclaringClass(); //类上的APIVersion注解 APIVersion apiVersion = AnnotationUtils.findAnnotation(controllerClass, APIVersion.class); //方法上的APIVersion注解 APIVersion methodAnnotation = AnnotationUtils.findAnnotation(method, APIVersion.class); //以方法上的注解优先 if (methodAnnotation != null) { apiVersion = methodAnnotation; } String[] urlPatterns = apiVersion == null ? new String[0] : apiVersion.value(); PatternsRequestCondition apiPattern = new PatternsRequestCondition(urlPatterns); PatternsRequestCondition oldPattern = mapping.getPatternsCondition(); PatternsRequestCondition updatedFinalPattern = apiPattern.combine(oldPattern); //重新构建RequestMappingInfo mapping = new RequestMappingInfo(mapping.getName(), updatedFinalPattern, mapping.getMethodsCondition(), mapping.getParamsCondition(), mapping.getHeadersCondition(), mapping.getConsumesCondition(), mapping.getProducesCondition(), mapping.getCustomCondition()); super.registerHandlerMethod(handler, method, mapping); } }

RequestMappingHandlerMapping 的作用,是根据类或方法上的 @RequestMapping 来生成 RequestMappingInfo 的实例                  。我们覆盖 registerHandlerMethod 方法的实现                  ,从 @APIVersion 自定义注解中读取版本信息                  ,拼接上原有的            、不带版本号的 URL Pattern,构成新的 RequestMappingInfo            ,来通过注解的方式为接口增加基于 URL 的版本号            。

最后                  ,要通过实现 WebMvcRegistrations 接口      ,来生效自定义的 APIVersionHandlerMapping

@SpringBootApplication public class CommonMistakesApplication implements WebMvcRegistrations { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return new APIVersionHandlerMapping(); } }

这样            ,就实现了在 Controller 上或接口方法上通过注解                  ,来实现以统一的 Pattern 进行版本号控制      ,使用时:

@GetMapping(value = "/api/user") @APIVersion("v4") public int right4() { return 4; }

访问url为 http://localhost:8080/v4/api/user

使用框架来明确 API 版本的指定策略      ,不仅实现了标准化                  ,更实现了强制的 API 版本控制      。假如我们的接口强制要求必须要有版本号            ,可以改动APIVersionHandlerMapping代码      ,在获取不到@APIVersion注解时                  ,就给予报错提示                  。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
自动改写文章的免费软件(文段改写软件-文档自动检查错别字自动改写语法软件) 微信小程序如何查询核酸检测结果(使用微信小程序制作核酸检测点查询工具)