spring项目自定义全局响应处理器统一处理响应结果的实现步骤
作者:Java高手马保国
本文详细描述了如何通过@ControllerAdvice和ResponseBodyAdvice在SpringMVC项目中创建自定义响应处理器,以及如何使用Wrapper类包装和标准化返回结果,感兴趣的朋友跟随小编一起看看吧
实现方式
使用@ControllerAdvice注解和实现ResponseBodyAdvice接口自定义全局响应处理器
实现步骤
自定义统一返回类
定义统一返回类,包装返回结果
@Data @JsonInclude(JsonInclude.Include.NON_NULL)//过滤null,提高性能 @ApiModel(value = "返回类") public class Wrapper<T> implements Serializable { /** * 成功码 */ public static final int SUCCESS_CODE = 200; /** * 成功信息 */ public static final String SUCCESS_MESSAGE = "操作成功"; /** * 错误码 */ public static final int ERROR_CODE = 500; /** * 错误信息 */ public static final String ERROR_MESSAGE = "内部异常"; /** * 编号 */ @ApiModelProperty("编号") private int code; /** * 信息 */ @ApiModelProperty("信息") private String message; /** * 结果数据 */ @ApiModelProperty("结果数据") private T result; /** 为什么使用this替代new类名 * 代码简洁:使用 this 可以使得代码更加简洁,因为你不需要每次都重复使用类的名称。 * 明确性:通过使用 this,你清楚地表明你正在调用当前类的另一个构造函数或方法,而不是其他类的构造函数或方法。 * 减少重复:在多构造函数的类中,如果每个构造函数都需要设置相同的属性,那么使用 this 可以避免重复代码。 * 提高可读性:当一个构造函数调用了另一个构造函数时,使用 this 可以让读者更容易理解正在发生的事情,尤其是当构造函数的参数不同,但都包含某些共同参数时。 */ //默认构造函数,它直接调用第二个构造函数,并传递 SUCCESS_CODE 和 SUCCESS_MESSAGE 作为参数。 Wrapper() { this(SUCCESS_CODE, SUCCESS_MESSAGE); } //不需要返回数据 带有两个参数的构造函数,它调用第三个构造函数,并传递相同的参数。 Wrapper(int code, String message) { this(code, message, null); } //需要返回数据 Wrapper(int code, String message, T result) { super(); this.code(code).message(message).result(result); } private Wrapper<T> code(int code) { this.setCode(code); return this; } private Wrapper<T> message(String message) { this.setMessage(message); return this; } public Wrapper<T> result(T result) { this.setResult(result); return this; } @JsonIgnore public boolean success() { return Wrapper.SUCCESS_CODE == this.code; } @JsonIgnore public boolean error() { return !success(); } }
定义 统一返回包装类
public class WrapMapper { /** * 在 `WrapMapper` 类中,私有构造函数的设计是为了防止外部实例化这个类。这是一个常见的做法,有以下几个原因: * 1. **单一职责原则**:`WrapMapper` 类被设计为一个工具类,只提供一系列静态方法,用于创建和处理 `Wrapper` 对象。它不包含任何实例变量,因此它没有必要被实例化。 * 2. **减少依赖**:如果 `WrapMapper` 类可以被实例化,那么任何使用这个类的代码都需要导入这个类的引用。通过将构造函数设为私有,你可以限制它的使用,只允许通过静态方法来使用这个类。 * 3. **提高效率**:工具类通常不需要创建多个实例,因为它们不依赖于外部状态,而且它们的操作通常可以通过静态方法完成。因此,设计为不可实例化可以提高效率。 * 4. **清晰意图**:通过将构造函数设为私有,明确地表明这个类不应该被实例化,这有助于其他开发者理解这个类的用途和设计意图。 * 总之,将 `WrapMapper` 类的构造函数设为私有是为了遵循单一职责原则,减少依赖,提高效率,并提高代码的可读性和可维护性。这样的设计有助于确保 `WrapMapper` 类只作为工具类被使用,而不被误用或滥用。 */ private WrapMapper() { } public static <E> Wrapper<E> wrap(int code) { return wrap(code, null); } public static <E> Wrapper<E> wrap(int code, String message) { return wrap(code, message, null); } public static <E> Wrapper<E> wrap(int code, String message, E o) { return new Wrapper<>(code, message, o); } public static <E> Wrapper<E> wrap(Exception e) { return new Wrapper<>(Wrapper.ERROR_CODE, e.getMessage()); } public static <E> E unWrap(Wrapper<E> wrapper) { return wrapper.getResult(); } public static <E> Wrapper<E> error() { return wrap(Wrapper.ERROR_CODE, Wrapper.ERROR_MESSAGE); } public static <E> Wrapper<E> error(int code,String message) { return wrap(code, message); } public static <E> Wrapper<E> error(String message) { return wrap(Wrapper.ERROR_CODE, StringUtils.isBlank(message) ? Wrapper.ERROR_MESSAGE : message); } public static <E> Wrapper<E> ok() { return new Wrapper<>(); } public static <E> Wrapper<E> ok(E o) { return new Wrapper<>(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, o); } }
定义启用全局响应注解
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface EnableResponseHandler { }
定义忽略全局响应注解
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface IgnoreResponseHandler { }
定义全局响应处理器
//@Component标记的类,Spring 容器会自动扫描这个类,并将它作为一个 bean 创建和注册到 Spring 容器中。 //可以被其他类通过 @Autowired 注解自动装配,你不需要显式地定义 bean 的依赖关系,Spring 容器会自动处理。 @Component @ControllerAdvice//全局控制器增强 public class GlobalResponseHandler implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { if (methodParameter.getMethod().isAnnotationPresent(IgnoreResponseHandler.class)) { return false; } //只有EnableResponseHandler注解标识的类才会去调用beforeBodyWrite方法 if (methodParameter.getMethod().isAnnotationPresent(EnableResponseHandler.class)) { return true; } if (methodParameter.getDeclaringClass().isAnnotationPresent(EnableResponseHandler.class)) { return true; } return false; } /** *beforeBodyWrite方法在 Spring MVC 将返回的对象写入 HTTP 响应之前被调用,它提供了一个机会来增强或修改响应体。 * 作用 * 1.增强响应:在返回对象被写入响应之前,允许你对响应进行增强或修改。 * 自定义格式化:如果你需要对返回的对象进行特殊的格式化,比如添加额外的头信息,或者修改对象的属性,beforeBodyWrite 提供了这种能力。 * 全局应用:你可以定义多个 ResponseBodyAdvice 实现类,并将它们应用于整个应用程序,或者针对特定的 Controller 或请求类型进行过滤。 */ @Nullable @Override public Object beforeBodyWrite(@Nullable Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { //如果返回的不是自己定义的包装类 if (o instanceof Wrapper) { return o; } //使用WrapMapper包装后返回 return WrapMapper.ok(o); } }
到此这篇关于spring项目自定义全局响应处理器,统一处理响应结果的文章就介绍到这了,更多相关spring自定义全局响应处理器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!