公司招聘网站排行榜专业从事网站开发公司
news/
2025/9/23 23:52:54/
文章来源:
公司招聘网站排行榜,专业从事网站开发公司,安卓优化大师官方版本下载,如室室内设计官网前言 今天参考的开源组件Graceful Response——Spring Boot接口优雅响应处理器。 具体用法可以参考github以及官方文档。 基本使用
引入Graceful Response组件
项目中直接引入如下maven依赖#xff0c;即可使用其相关功能。 dependencygroupIdcom.feiniaoji…前言 今天参考的开源组件Graceful Response——Spring Boot接口优雅响应处理器。 具体用法可以参考github以及官方文档。 基本使用
引入Graceful Response组件
项目中直接引入如下maven依赖即可使用其相关功能。 dependencygroupIdcom.feiniaojin/groupIdartifactIdgraceful-response/artifactIdversion{latest.version}/version/dependency开始使用
配置文件可不配置直接全部默认配置。
graceful-response:response-style: 1 # 配置响应格式类型0 or 1后续介绍print-exception-in-global-advice: true # 在全局异常处理器中打印异常默认不打印一切之前需在主启动类添加该注解开启功能EnableGracefulResponse。后续介绍 Controller直接返回我们查询的对象即可Graceful Response会帮我们封装响应格式响应格式可配置
Controller
RestController
public class HelloController {Resourceprivate UserMapper userMapper;GetMapping(/userList)public ListUser userList() {return userMapper.selectList(null);}
}调用接口 默认成功/失败状态码和提示消息也都是可以配置的是不是感觉非常的神奇一切皆可配 其他具体用法见官网。
废话不多说接下来我们直接步入主题探究下自定义starter组件核心步骤。
自定义starter组件核心步骤
首先明确一下自定义starter组件的三个核心步骤 自定义注解结合Spring AOP实现注解逻辑实现starter组件自动装配以及可配置 接下来看开源组件都是怎么做的吧~
看看源码目录结构麻雀虽小但五脏俱全 0. 注解使用 以ExceptionMapper注解为例介绍一下相关功能及实现原理。 Graceful Response引入ExceptionMapper注解通过该注解将异常和错误码关联起来这样Service方法就不需要再维护Response的响应码了直接抛出业务异常由Graceful Response进行异常和响应码的关联。 ExceptionMapper的用法如下
自定义业务类异常
/*** NotFoundException的定义使用ExceptionMapper注解修饰* code:代表接口的异常码* msg:代表接口的异常提示*/
ExceptionMapper(code 1404, msg 找不到对象)
public class NotFoundException extends RuntimeException {}Service接口定义
public interface QueryService {UserInfoView queryOne(Query query);
}Service接口实现
Service
public class QueryServiceImpl implements QueryService {Resourceprivate UserInfoMapper mapper;public UserInfoView queryOne(Query query) {UserInfo userInfo mapper.findOne(query.getId());if (Objects.isNull(userInfo)) {// 这里直接抛自定义异常throw new NotFoundException();}// ……后续业务操作}
}当Service层的queryOne方法抛出NotFoundException时Graceful Response会进行异常捕获并将NotFoundException对应的异常码和异常信息封装到统一的响应对象中最终接口返回以下JSON默认响应格式
{status: {code: 1404,msg: 找不到对象},payload: {}
}使用起来十分方便接下来我们看下具体实现原理。
1. 自定义注解
首先看下注解定义
/*** 异常映射注解.*/
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
Inherited
public interface ExceptionMapper {/*** 异常对应的错误码.** return 异常对应的错误码*/String code() default ERROR;/*** 异常信息.** return 异常对应的提示信息*/String msg() default Poor network quality!;/*** 异常信息是否支持替换* 仅当msgReplaceableture且异常实例的message不为空时才能替换*/boolean msgReplaceable() default false;
}2. 结合Spring AOP实现注解逻辑核心
配置类 配置类GracefulResponseProperties跟可配置项相关所有配置项都映射为该类 ConfigurationProperties(prefix graceful-response) // 配置前缀
public class GracefulResponseProperties {/*** 在全局异常处理器中打印异常默认不打印*/private boolean printExceptionInGlobalAdvice false;/*** 默认的Response实现类名称配置了responseClassFullName则responseStyle不生效*/private String responseClassFullName;/*** responseStyle的风格responseClassFullName为空时才会生效* responseStylenull或者responseStyle0,Response风格为 DefaultResponseImplStyle0* responseStyle1,Response风格为 DefaultResponseImplStyle1*/private Integer responseStyle;/*** 默认的成功返回码 默认0*/private String defaultSuccessCode DefaultConstants.DEFAULT_SUCCESS_CODE;/*** 默认的成功提示 默认OK*/private String defaultSuccessMsg DefaultConstants.DEFAULT_SUCCESS_MSG;/*** 默认的失败码 默认1*/private String defaultErrorCode DefaultConstants.DEFAULT_ERROR_CODE;/*** 默认的失败提示 默认error*/private String defaultErrorMsg DefaultConstants.DEFAULT_ERROR_MSG;/*** Validate异常码不提供的话默认DefaultConstants.DEFAULT_ERROR_CODE*/private String defaultValidateErrorCode DefaultConstants.DEFAULT_ERROR_CODE;/*** 例外包路径*/private ListString excludePackages;/*** 不使用ExceptionMapper和ExceptionAliasFor修饰的原生异常* 是否使用异常信息Throwable类的detailMessage进行返回* originExceptionUsingDetailMessagefalse则msgdefaultErrorMsg*/private Boolean originExceptionUsingDetailMessage false;// getter / setter
}
设置响应状态 ResponseStatusFactory响应状态工厂仅定义code和msg默认实现成功默认响应、失败默认响应以及自定义code、msg响应状态 默认实现类
// 响应状态
public interface ResponseStatus {void setCode(String code);String getCode();void setMsg(String msg);String getMsg();
}// 默认响应状态
public class DefaultResponseStatus implements ResponseStatus {private String code;private String msg;public DefaultResponseStatus() {}public DefaultResponseStatus(String code, String msg) {this.code code;this.msg msg;}Overridepublic void setCode(String code) {this.code code;}Overridepublic String getCode() {return code;}Overridepublic void setMsg(String msg) {this.msg msg;}Overridepublic String getMsg() {return msg;}
}
// 核心实现类
public class DefaultResponseStatusFactoryImpl implements ResponseStatusFactory {Resourceprivate GracefulResponseProperties properties;// 默认成功响应转态Overridepublic ResponseStatus defaultSuccess() {DefaultResponseStatus defaultResponseStatus new DefaultResponseStatus();defaultResponseStatus.setCode(properties.getDefaultSuccessCode());defaultResponseStatus.setMsg(properties.getDefaultSuccessMsg());return defaultResponseStatus;}// 默认失败响应转态Overridepublic ResponseStatus defaultError() {DefaultResponseStatus defaultResponseStatus new DefaultResponseStatus();defaultResponseStatus.setCode(properties.getDefaultErrorCode());defaultResponseStatus.setMsg(properties.getDefaultErrorMsg());return defaultResponseStatus;}// 自定code、msg状态Overridepublic ResponseStatus newInstance(String code, String msg) {return new DefaultResponseStatus(code, msg);}
}设置响应格式 ResponseFactory根据配置项设置响应格式 默认实现类
public class DefaultResponseFactory implements ResponseFactory {private final Logger logger LoggerFactory.getLogger(DefaultResponseFactory.class);private static final Integer RESPONSE_STYLE_0 0;private static final Integer RESPONSE_STYLE_1 1;Resourceprivate ResponseStatusFactory responseStatusFactory;Resourceprivate GracefulResponseProperties properties;Overridepublic Response newEmptyInstance() {try {String responseClassFullName properties.getResponseClassFullName();// 配置了Response的全限定名即实现Response接口用配置的进行返回if (StringUtils.hasLength(responseClassFullName)) {Object newInstance Class.forName(responseClassFullName).getConstructor().newInstance();return (Response) newInstance;} else {// 没有配Response的全限定名则创建DefaultResponsereturn generateDefaultResponse();}} catch (Exception e) {throw new RuntimeException(e);}}// 响应格式判断private Response generateDefaultResponse() {Integer responseStyle properties.getResponseStyle();// 未配置或者配置0if (Objects.isNull(responseStyle) || RESPONSE_STYLE_0.equals(responseStyle)) {return new DefaultResponseImplStyle0();} else if (RESPONSE_STYLE_1.equals(responseStyle)) {return new DefaultResponseImplStyle1();} else {logger.error(不支持的Response style类型,responseStyle{}, responseStyle);throw new IllegalArgumentException(不支持的Response style类型);}}Overridepublic Response newInstance(ResponseStatus responseStatus) {Response bean this.newEmptyInstance();bean.setStatus(responseStatus);return bean;}Overridepublic Response newSuccessInstance() {Response emptyInstance this.newEmptyInstance();emptyInstance.setStatus(responseStatusFactory.defaultSuccess());return emptyInstance;}Overridepublic Response newSuccessInstance(Object payload) {Response bean this.newSuccessInstance();bean.setPayload(payload);return bean;}Overridepublic Response newFailInstance() {Response bean this.newEmptyInstance();bean.setStatus(responseStatusFactory.defaultError());return bean;}}对应配置文件中两种响应格式 默认响应格式
public interface Response {void setStatus(ResponseStatus statusLine);ResponseStatus getStatus();void setPayload(Object payload);Object getPayload();
}默认格式实现类
{status: {code: ,msg: },payload: {}
}public class DefaultResponseImplStyle0 implements Response {private ResponseStatus status;private Object payload Collections.emptyMap();public DefaultResponseImplStyle0() {}public DefaultResponseImplStyle0(Object payload) {this.payload payload;}Overridepublic void setStatus(ResponseStatus responseStatus) {this.status responseStatus;}Overridepublic ResponseStatus getStatus() {return status;}Overridepublic void setPayload(Object obj) {this.payload obj;}Overridepublic Object getPayload() {return payload;}
}style设置为1响应格式
{code: 1404,msg: 找不到对象data: {}
}另一种响应实现类
public class DefaultResponseImplStyle1 implements Response {private String code;private String msg;private Object data Collections.emptyMap();Overridepublic void setStatus(ResponseStatus statusLine) {this.code statusLine.getCode();this.msg statusLine.getMsg();}OverrideJsonIgnorepublic ResponseStatus getStatus() {return null;}Overridepublic void setPayload(Object payload) {this.data payload;}// 这里直接把 payload 忽略了因此这种响应格式中没有payload字段OverrideJsonIgnorepublic Object getPayload() {return null;}public String getCode() {return code;}public void setCode(String code) {this.code code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg msg;}public Object getData() {return data;}public void setData(Object data) {this.data data;}
}核心处理逻辑类
核心处理逻辑类全局异常处理
/*** 全局异常处理.*/
ControllerAdvice
Order(200)
public class GlobalExceptionAdvice implements ApplicationContextAware {private final Logger logger LoggerFactory.getLogger(GlobalExceptionAdvice.class);Resourceprivate ResponseStatusFactory responseStatusFactory;Resourceprivate ResponseFactory responseFactory;private ExceptionAliasRegister exceptionAliasRegister;// 配置类Resourceprivate GracefulResponseProperties properties;/*** 异常处理逻辑. 【统一捕获所有异常】** param throwable 业务逻辑抛出的异常* return 统一返回包装后的结果*/ExceptionHandler({Throwable.class})ResponseBody public Response exceptionHandler(Throwable throwable) {// 配置项是否打印异常信息默认falseif (properties.isPrintExceptionInGlobalAdvice()) {logger.error(Graceful Response:GlobalExceptionAdvice捕获到异常,message[{}], throwable.getMessage(), throwable);}ResponseStatus statusLine;if (throwable instanceof GracefulResponseException) {statusLine fromGracefulResponseExceptionInstance((GracefulResponseException) throwable);} else {// 校验异常转自定义异常statusLine fromExceptionInstance(throwable);}// 设置完code、msg之后直接返回return responseFactory.newInstance(statusLine);}private ResponseStatus fromGracefulResponseExceptionInstance(GracefulResponseException exception) {String code exception.getCode();if (code null) {code properties.getDefaultErrorCode();}return responseStatusFactory.newInstance(code,exception.getMsg());}private ResponseStatus fromExceptionInstance(Throwable throwable) {Class? extends Throwable clazz throwable.getClass();// 【直接获取抛出异常上的注解】ExceptionMapper exceptionMapper clazz.getAnnotation(ExceptionMapper.class);// 1.有ExceptionMapper注解直接设置结果的状态if (exceptionMapper ! null) {boolean msgReplaceable exceptionMapper.msgReplaceable();//异常提示可替换抛出来的异常有自定义的异常信息if (msgReplaceable) {String throwableMessage throwable.getMessage();if (throwableMessage ! null) {return responseStatusFactory.newInstance(exceptionMapper.code(), throwableMessage);}}return responseStatusFactory.newInstance(exceptionMapper.code(),exceptionMapper.msg());}// 2.有ExceptionAliasFor异常别名注解获取已注册的别名信息if (exceptionAliasRegister ! null) {ExceptionAliasFor exceptionAliasFor exceptionAliasRegister.getExceptionAliasFor(clazz);if (exceptionAliasFor ! null) {return responseStatusFactory.newInstance(exceptionAliasFor.code(),exceptionAliasFor.msg());}}ResponseStatus defaultError responseStatusFactory.defaultError();// 3. 原生异常 originExceptionUsingDetailMessagetrue// 如果有自定义的异常信息原生异常将直接使用异常信息进行返回不再返回默认错误提示if (properties.getOriginExceptionUsingDetailMessage()) {String throwableMessage throwable.getMessage();if (throwableMessage ! null) {defaultError.setMsg(throwableMessage);}}return defaultError;}Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.exceptionAliasRegister applicationContext.getBean(ExceptionAliasRegister.class);}
}非空返回值封装处理类ResponseBodyAdvice
ResponseBodyAdvice泛型T为响应data类型直接Object即可
ControllerAdvice
Order(value 1000)
public class NotVoidResponseBodyAdvice implements ResponseBodyAdviceObject {private final Logger logger LoggerFactory.getLogger(NotVoidResponseBodyAdvice.class);Resourceprivate ResponseFactory responseFactory;Resourceprivate GracefulResponseProperties properties;/*** 路径过滤器*/private static final AntPathMatcher ANT_PATH_MATCHER new AntPathMatcher();/*** 只处理不返回void的并且MappingJackson2HttpMessageConverter支持的类型.** param methodParameter 方法参数* param clazz 处理器* return 是否支持*/Overridepublic boolean supports(MethodParameter methodParameter,Class? extends HttpMessageConverter? clazz) {Method method methodParameter.getMethod();// method为空、返回值为void、非JSON直接跳过if (Objects.isNull(method)|| method.getReturnType().equals(Void.TYPE)|| !MappingJackson2HttpMessageConverter.class.isAssignableFrom(clazz)) {logger.debug(Graceful Response:method为空、返回值为void、非JSON跳过);return false;}// 有ExcludeFromGracefulResponse注解修饰的也跳过if (method.isAnnotationPresent(ExcludeFromGracefulResponse.class)) {if (logger.isDebugEnabled()) {logger.debug(Graceful Response:方法被ExcludeFromGracefulResponse注解修饰跳过:methodName{}, method.getName());}return false;}// 配置了例外包路径则该路径下的controller都不再处理ListString excludePackages properties.getExcludePackages();if (!CollectionUtils.isEmpty(excludePackages)) {// 获取请求所在类的的包名String packageName method.getDeclaringClass().getPackage().getName();if (excludePackages.stream().anyMatch(item - ANT_PATH_MATCHER.match(item, packageName))) {logger.debug(Graceful Response:匹配到excludePackages例外配置跳过:packageName{},, packageName);return false;}}logger.debug(Graceful Response:非空返回值需要进行封装);return true;}// 满足上述条件封装返回对象只要是非Void返回值不做任何配置都会封装返回结果Overridepublic Object beforeBodyWrite(Object body,MethodParameter methodParameter,MediaType mediaType,Class? extends HttpMessageConverter? clazz,ServerHttpRequest serverHttpRequest,ServerHttpResponse serverHttpResponse) {if (body null) {return responseFactory.newSuccessInstance();} else if (body instanceof Response) {return body;} else {// 设置data数据return responseFactory.newSuccessInstance(body);}}}…
3. 实现starter组件自动装配以及可配置
全局自动装配类
该类可以将我们自定义的所有类全部加载到Spring容器中。
/*** 全局返回值处理的自动配置.*/
Configuration
// 将外部配置文件中的属性注入到配置类中将配置类加载到Spring容器中
EnableConfigurationProperties(GracefulResponseProperties.class)
public class AutoConfig {Bean// 这个注解很是重要ConditionalOnMissingBean(value GlobalExceptionAdvice.class)public GlobalExceptionAdvice globalExceptionAdvice() {return new GlobalExceptionAdvice();}BeanConditionalOnMissingBean(value ValidationExceptionAdvice.class)public ValidationExceptionAdvice validationExceptionAdvice() {return new ValidationExceptionAdvice();}BeanConditionalOnMissingBean(NotVoidResponseBodyAdvice.class)public NotVoidResponseBodyAdvice notVoidResponseBodyAdvice() {return new NotVoidResponseBodyAdvice();}BeanConditionalOnMissingBean(VoidResponseBodyAdvice.class)public VoidResponseBodyAdvice voidResponseBodyAdvice() {return new VoidResponseBodyAdvice();}BeanConditionalOnMissingBean(value {ResponseFactory.class})public ResponseFactory responseBeanFactory() {return new DefaultResponseFactory();}BeanConditionalOnMissingBean(value {ResponseStatusFactory.class})public ResponseStatusFactory responseStatusFactory() {return new DefaultResponseStatusFactoryImpl();}Beanpublic ExceptionAliasRegister exceptionAliasRegister() {return new ExceptionAliasRegister();}Beanpublic Init init(){return new Init();}
}注解启动全局结果处理入口
通过元注解 Import(AutoConfig.class) 实际上将 AutoConfig 这个配置类引入到标注了 EnableGracefulResponse 注解的类中。 引入该组件只有在某个类上添加了 EnableGracefulResponse 注解时AutoConfig 中定义的相关 Bean 才会被注册到 Spring 容器中。可以方便地启用特定功能或配置。 Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
Import(AutoConfig.class)
public interface EnableGracefulResponse {
}SpringBoot主启动类添加该注解开启功能 另一种方式META-INF/spring.factories 如果想引入该组件就直接开启所有功能可以不用上述全局启动注解 直接在组件项目的 resources 中创建 META-INF 目录并在此目录下创建一个 spring.factories 文件将starter组件的自动配置类的类路径写在文件上即可。
resourcesMETA-INFspring.factories// 直接将自动装配类全限定名放入该文件即可
com.feiniaojin.gracefulresponse.AutoConfigSpring Boot项目启动时会扫描外部引入的Jar中的META-INF/spring.factories文件将文件中配置的类信息装配到Spring容器中【用的是Java的SPI机制还没研究后续再说吧】 这样只要引入该组件组件功能也就集成进来了。【这种不够灵活视情况用哪种方式】建议能用全局启动注解就用全局启动注解
配置智能提示
组件中记得添加该依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdversion${spring.boot.version}/versionoptionaltrue/optional/dependency组件中添加上述依赖可以用于处理配置类ConfigurationProperties 注解标注的类以及生成相关的元数据。
IDE 支持 提供更好的集成开发环境IDE支持。通过生成的配置元数据IDE 可以在配置文件中提供智能提示我们可以更方便地编辑配置。 引入该组件在修改配置类可以有智能提示 如下 该文章只介绍了该组件部分功能有兴趣可以自行研究呀~
最后看一下组件的目录结构学习一下 小结
自定义starter组件的三个核心步骤
自定义注解注解结合AOP实现逻辑自动装配和可配置配置类、自动装配类以及全局启动注解/spring.factories文件
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/914282.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!