SpringBoot+FastJson 优雅的过滤 Response Body

Spring 源码系列

1、Spring 学习之扩展点总结之后置处理器(一)
2、Spring 学习之扩展点总结之后置处理器(二)
3、Spring 学习之扩展点总结之自定义事件(三)
4、Spring 学习之扩展点总结之内置事件(四)
5、Spring 学习之扩展点总结之@Import(五)
6、Spring 学习之AOP总结之基础介绍(六)
7、Spring 学习之AOP总结之实现代理(七)
8、SpringBoot 学习之自动配置基本原理(八)
9、SpringBoot 学习之启动原理(九)
10、ElasticSearch学习随笔之SpringBoot Starter 操作
11、图数据库 Neo4j 学习之SpringBoot整合
12、SpringBoot 学习之常用 Filter / Advice 总结
13、SpringBoot+FastJson 优雅的过滤 Response Body

文章目录

  • Spring 源码系列
  • 前言
  • 一、思路简介
  • 二、FastJsonHttpMessageConverter 是什么?
  • 三、@*** 注解编写
    • 3.1 @ResponseJSON 注解
    • 3.2 @Ignore 注解
  • 四、JSONHttpMessageConverter 消息体处理实现
    • 4.1 JSONHttpMessageConverter 类及依赖
    • 4.2 writeInternal() 处理消息体
    • 4.3 toJSONString() 对象转换 JSON
    • 4.4 getSerializeFilter() 序列化Filter实现
    • 4.5 setApplicationContext() 设置上下文
  • 五、HandlerHolder 获取请求处理器 Handler 实现
  • 六、EntityClassPropertyFilter 序列化对象属性过滤器
  • 七、AppConfig 配置类让转换器生效
  • 八、测试结果
    • 8.1 测试接口
    • 8.2 请求测试
  • 八、小结

前言

还是那个问题,前两天在开发一个需求时遇到这么一个问题,就是对接口的返回体【Response Body】做一些处理,,猛然间居然还是手足无措,最后决定使用 ResponseBodyAdvice 通知来实现,所以总结了一下开发中常用的 Filter 和 Advice,也欢迎 码友 们指点一二,我也会在空闲时第一时间补充进去,博文见 《SpringBoot 学习之常用 Filter / Advice 总结》。
不过发现即便使用 Filter 或者 Advice 可以实现,但是不够优雅…
目前企业开发项目中基本上都是用 JSON 格式作为 API 响应体,我负责的项目亦是,并且使用的是 alibaba 的 fastjson,然后有前面大佬的杰作加上我的虚心学习之后,决定用 FastJson 扩展点【FastJsonHttpMessageConverter】来实现。

提示:只要按照思路简介的几步完成即可实现优雅的过滤消息体功能!

一、思路简介

在 Spring Boot 中,默认使用 Jackson 库来将返回体转换为 JSON 格式的数据。 Jackson 是一个流行的 JSON 处理库,Spring 框架中集成了它作为默认的 JSON 序列化和反序列化工具。
不过在我们的应用中也使用到了 FastJson 来对响应体或对象实体与 JSON 进行转换,既然使用到了了 FastJson,那我们就可以通过 FastJson 扩展来在转换 JSON 的过程中实现字段过滤,这样我觉得就优雅了许多。
FastJson 中有一个 FastJsonHttpMessageConverter 是 FastJson 中提供的消息【转换器】,我们就通过继承FastJsonHttpMessageConverter 并重写转换功能来实现返回体字段过滤。
具体有如下几点:

  1. 编写 @ResponseJSON@Ignore 注解,我们通过注解来配置每个接口返回的字段。
  2. 自定义转换器【JSONHttpMessageConverter】继承 FastJsonHttpMessageConverter 并且实现 ApplicationContextAware 接口(主要用于获取上下文)。
  3. 自定义HandlerHolder 类实现接口 HandlerInterceptor,主要用于获取到我们自己开发的请求处理器 Handler请求处理器)。
  4. 自定义 EntityClassPropertyFilter 过滤器实现 FastJson 提供的 PropertyPreFilter 过滤器并且 重写 apply(*) 方法 ,通过实现这个方法,可以自定义过滤规则,在序列化对象时,Fastjson 将会根据实现了 PropertyPreFilter 接口的对象的 apply 方法来判断哪些属性需要被序列化,哪些属性需要被过滤掉。
  5. 自定义 AppConfig 配置类让返回体转换器生效。

源码已提交到码云仓库,欢迎点击查看!!!

二、FastJsonHttpMessageConverter 是什么?

FastJsonHttpMessageConverter 是 FastJson 中提供的消息转换器,在 Spring Boot 中可以用来将对象转换为 JSON 格式的数据,用于处理接口返回体的数据,具体作用如下:

  1. JSON 转换,FastJsonHttpMessageConverter 实现了 Spring 框架中的 HttpMessageConverter 接口,能够将 JAVA 对象转换成 JSON 格式数据,以便通过 HTTP 返回给客户端。
  2. FastJson 配置,该转换器对 FastJson 进行配置,比如设置序列化特性、日期格式化等。
  3. 可以替代 Spring Boot 默认的 Jackson 转换器。

三、@*** 注解编写

按照思路简介 第 1 步,编写注解类,直接上代码。

3.1 @ResponseJSON 注解

package com.selftest.web.annotation;import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseJSON {Ignore[] ignore() default {};boolean enable() default true;}

3.2 @Ignore 注解

package com.selftest.web.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Ignore {Class<?> declaringClass();String[] propNames();boolean inverse() default false;}

四、JSONHttpMessageConverter 消息体处理实现

按照思路简介第 2 步,编写 JSONHttpMessageConverter 类,代码中都有注释,直接上代码。
这个类是实现响应体的主要部分,主要是实现消息体转换和配置,代码比较多,分开一段一段看。

4.1 JSONHttpMessageConverter 类及依赖

package com.selftest.web.http;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.selftest.web.RequestHandlerHolder;
import com.selftest.web.annotation.Ignore;
import com.selftest.web.annotation.ResponseJSON;
import com.selftest.web.filter.EntityClassPropertyFilter;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.CollectionUtils;
import org.springframework.web.method.HandlerMethod;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;/*** JSON 数据转换,实现返回体字段过滤*/
public class JSONHttpMessageConverter extends FastJsonHttpMessageConverter implements ApplicationContextAware {/*** 应用上下文*/private ApplicationContext ctx;/*** 请求处理器 Handler 持有者 */@Resourceprivate RequestHandlerHolder requestHandlerHolder;private FastJsonConfig fastJsonConfig = new FastJsonConfig();此处代码下面依次呈现3.2 writeInternal() 方法3.3 toJSONString() 方法3.4 getSerializeFilter() 方法3.5 setApplicationContext() 方法
}

4.2 writeInternal() 处理消息体

	/*** 返回体处理* @param obj the object to write to the output message* @param outputMessage the HTTP output message to write to* @throws IOException* @throws HttpMessageNotWritableException*/@Overrideprotected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {//获取到返回流OutputStream out = outputMessage.getBody();String jsonString = toJSONString(obj);out.write(jsonString.getBytes(StandardCharsets.UTF_8));}

4.3 toJSONString() 对象转换 JSON

/*** 将对象转换为JSON字符串* @return*/private String toJSONString(Object obj){//获取到处理请求的 Handlerif(Objects.isNull(requestHandlerHolder)){return JSON.toJSONString(obj);}Object handler = requestHandlerHolder.getHandler();//如果 handler 为空或者 handler 不为空但是返回类型不是 entity 的if(Objects.isNull(handler)|| (Objects.nonNull(requestHandlerHolder.getHandlerMethod().getReturnType())&& requestHandlerHolder.getHandlerMethod().getReturnType().isAssignableFrom(ResponseEntity.class))){return JSON.toJSONString(obj);}//如果是处理方法,则获取到返回类型 ReturnType、annotationResponseJSON annotation = null;if (handler instanceof HandlerMethod) {HandlerMethod method = (HandlerMethod) handler;MethodParameter returnType = method.getReturnType();annotation = returnType.getMethodAnnotation(ResponseJSON.class);if (Objects.isNull(annotation)) {annotation = method.getMethodAnnotation(ResponseJSON.class);}}if(Objects.isNull(annotation) || (Objects.nonNull(annotation) && !annotation.enable())){return Objects.nonNull(obj) ? JSON.toJSONString(obj) : null;}// 获取到真正实现返回体过滤的序列化 filterSerializeFilter filter = getSerializeFilter(annotation);// 封装自定义 filter, 传入上面的 filter 和 自定义注解EntityClassPropertyFilter propertyFilter = new EntityClassPropertyFilter(filter, annotation);return JSON.toJSONString(obj, propertyFilter, this.fastJsonConfig.getSerializerFeatures());}

4.4 getSerializeFilter() 序列化Filter实现

/*** 获取序列化 filter* @param annotation* @return*/private SerializeFilter getSerializeFilter(ResponseJSON annotation) {if(Objects.nonNull(annotation)){Ignore[] ignoreFields = annotation.ignore();if(ignoreFields.length == 0){return null;}Map<Class<?>, Map<Boolean, Set<String>>> ignoreMap = new HashMap<>();for (Ignore ignore : ignoreFields) {Class<?> declaringClass = ignore.declaringClass();Map<Boolean, Set<String>> propNameMap = ignoreMap.get(declaringClass);if(Objects.isNull(propNameMap)) {propNameMap = new HashMap<>();ignoreMap.put(declaringClass, propNameMap);}boolean inverse = ignore.inverse();Set<String> propNameSet = propNameMap.get(inverse);if(CollectionUtils.isEmpty(propNameSet)){propNameSet = new HashSet<>();propNameMap.put(inverse, propNameSet);}for (String propName : ignore.propNames()) {propNameSet.add(propName);}}// 返回 属性预处理 Filter 实例,真正实现返回体字段过滤return (PropertyPreFilter) (jsonSerializer, object, name) -> {for (Map.Entry<Class<?>, Map<Boolean, Set<String>>> ignoreEntry : ignoreMap.entrySet()) {if (ignoreEntry.getKey().isAssignableFrom(object.getClass())) {Set<String> ignorePropNames = ignoreEntry.getValue().get(false);if (Objects.nonNull(ignorePropNames) && ignorePropNames.contains(name)) {return false;}ignorePropNames = ignoreEntry.getValue().get(true);if (Objects.nonNull(ignorePropNames) && !ignorePropNames.contains(name)) {return false;}}}return true;};}return null;}

4.5 setApplicationContext() 设置上下文

 /*** 获取应用上下文* @param applicationContext the ApplicationContext object to be used by this object* @throws BeansException*/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.ctx = applicationContext;}

五、HandlerHolder 获取请求处理器 Handler 实现

按照思路简介 第 3 步,编写 HandlerHolder 类,代码中都有注释,直接上代码。
这个类主要是为了能在处理消息体处理的时候能获取到 Handler,因为我们的消息体处理是通过 Handler 方法上的 @ResponseJSON@Ignore 注解配置来实现的。

package com.selftest.web.interceptor;import com.selftest.web.RequestHandlerHolder;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;/*** 请求处理拦截器,主要获取 Handler* 通过 ThreadLocal 获取*/
public class HandlerHolder implements HandlerInterceptor, RequestHandlerHolder {/*** 通过 ThreadLocal 来暂存和获取 Handler*/private final ThreadLocal<Object> HANDLERS = new ThreadLocal<>();/*** 在请求是获取到 Handler 并存入 ThreadLocal* @param request current HTTP request* @param response current HTTP response* @param handler chosen handler to execute, for type and/or instance evaluation* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HANDLERS.set(handler);return true;}/*** 从 ThreadLocal 获取 Handler* @return* @param <T>*/@Overridepublic <T> T getHandler(){return (T) HANDLERS.get();}/*** 获取 Handler 的方法* @return*/@Overridepublic Method getHandlerMethod() {Object handler = getHandler();if (handler instanceof HandlerMethod) {return ((HandlerMethod) handler).getMethod();} else if (handler instanceof Method) {return (Method) handler;}return null;}
}

接口 RequestHandlerHolder 实现:

package com.selftest.web;import java.lang.reflect.Method;public interface RequestHandlerHolder {<T> T getHandler();Method getHandlerMethod();
}

六、EntityClassPropertyFilter 序列化对象属性过滤器

按照思路简介 第 4 步,编写 EntityClassPropertyFilter 类,代码中都有注释,直接上代码。

package com.selftest.web.filter;import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.selftest.web.annotation.ResponseJSON;import java.util.Objects;/*** 实现对象属性序列化 filter*/
public class EntityClassPropertyFilter implements PropertyPreFilter {private SerializeFilter filter;private ResponseJSON annotation;/*** 实例化* @param filter* @param annotation*/public EntityClassPropertyFilter(SerializeFilter filter, ResponseJSON annotation) {this.filter = filter;this.annotation = annotation;}/*** 自定义过滤规则, 判断哪些属性需要被序列化,哪些属性需要被过滤掉* @param jsonSerializer* @param object* @param name* @return*/@Overridepublic boolean apply(JSONSerializer jsonSerializer, Object object, String name) {Class<?> elementType = object.getClass();if (Objects.nonNull(elementType)) {while (!elementType.equals(Object.class)) {if (Objects.nonNull(filter) && filter instanceof PropertyPreFilter) {// 这里调用的是 JSONHttpMessageConverter 中 getSerializeFilter() 提供的 SerializeFilterif (!((PropertyPreFilter)filter).apply(jsonSerializer, object, name)) {return false;}}elementType = elementType.getSuperclass();}}return true;}
}

七、AppConfig 配置类让转换器生效

按照思路简介 第 5 步,编写 HandlerHolder 类,代码中都有注释,直接上代码。

package com.selftest.config;import com.selftest.web.http.JSONHttpMessageConverter;
import com.selftest.web.interceptor.HandlerHolder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 配置类*/
@Configuration
public class AppConfig implements WebMvcConfigurer {/*** 实例化请求 handler* @return*/@Bean(name = "requestHandlerHolder")public HandlerHolder requestHandlerHolder(){return new HandlerHolder();}/*** 返回体消息过滤 Bean* @return*/@Beanpublic JSONHttpMessageConverter jsonHttpMessageConverter(){return new JSONHttpMessageConverter();}/*** 注册请求拦截器* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(requestHandlerHolder());}
}

八、测试结果

8.1 测试接口

	@ResponseJSON(ignore = {@Ignore(declaringClass = User.class, propNames = {"age"})})@GetMapping("users")public User getUser(){User user = new User();user.setId(1);user.setName("phen");user.setAge(30);return user;}

8.2 请求测试

成功过滤字段

八、小结

在 Spring Boot 中,默认使用 Jackson 库来将返回体转换为 JSON 格式的数据。 Jackson 是一个流行的 JSON 处理库,Spring 框架中集成了它作为默认的 JSON 序列化和反序列化工具。
那在 FastJson 中提供的 FastJsonHttpMessageConverter 消息转换器,我们则可以通过对此转换器的重写来实现对请求体字段的过滤,在 FastJsonHttpMessageConverter 中的 getSerializeFilter() 方法返回了 PropertyPreFilter 实体则真正的实现了返回体字段的过滤,在 自定义类 JSONHttpMessageConverter 中的 toJSONString() 方法中我们可以看到这几句代码:

SerializeFilter filter = getSerializeFilter(annotation);
EntityClassPropertyFilter propertyFilter = new EntityClassPropertyFilter(filter, annotation);
return JSON.toJSONString(obj, propertyFilter, this.fastJsonConfig.getSerializerFeatures()) 

第二个参数 propertyFilter 则是我们自己定义的 Filter,并且实现了 FastJson 提供的序列化过滤器 PropertyPreFilterEntityClassPropertyFilter 重写了 apply() 并且回调了 getSerializeFilter() 获取到的 filter,通过 JSON.toJSONString() 并且传入三个参数,第一个参数是我们自己实现的请求处理器返回的实体对象 User,第二个参数则是我们自己实现的序列化 Filter,第三个参数就是 FastJson 的默认的 SerializerFeature。

到这里,Spring Boot + FastJson 优雅的实现消息体字段的过滤就基本完成了,可以通过 debug 方式来看一下具体请求过滤是如何执行的,调用逻辑是什么。


江湖必有大佬藏,如有指点可别藏!
本文示例亲自手敲代码并且执行通过。
如有问题,还请指教。 评论区告诉我!!!一起学习一起进步!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/228021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手把手教你Linux查找Java的安装目录并设置环境变量以及Linux下执行javac未找到命令的保姆级教学

查找Java的安装目录 输入 java -version&#xff0c;查看是否成功安装Java 输入 which java&#xff0c;查看Java的执行路径 输入 ls -lrt /usr/bin/java 输入 ls -lrt /etc/alternatives/java&#xff0c;/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-0.el7_7.x86_64 就是J…

自动化测试(终章)webdriver的常用api(2)以及新的开始

目录 多层框架/窗口定位 多层框架的定位 frame是什么&#xff1f; 多层窗口定位 层级定位 使用 XPath 进行层级定位&#xff1a; 使用 CSS 选择器进行层级定位&#xff1a; 下拉框处理 alert、confirm、prompt 的处理 Alert 弹窗&#xff1a; Confirm 弹窗&#xff…

IDEA安装插件搜索不到插件的解决方法

解决idea安装所需插件&#xff0c;插件搜索不到的问题 1.通过设置代理和去掉使用安装链接的方式来解决的 File–>Settings–>Appearance & Behavior–>System Settings—>HTTP Proxy(修改为图片所示) 2.在系统设置中将更新选项中的“use secure connection”…

Xml与Json格式在线转换器

具体请前往&#xff1a;在线Json转Form表单参数工具

C语言之函数式宏

目录 函数和数据类型 函数式宏 函数和函数式宏 函数式宏和对象式宏 不带参数的函数式宏 函数式宏和逗号运算符 函数式宏和函数类似并且比函数更加灵活&#xff0c;下面我们就来学习函数式宏的相关内容。 函数和数据类型 我们来编写一个程序&#xff0c;它能计算出所读取…

Jetpack Compose开发一个Android WiFi导航应用

在以前的一篇文章构建一个WIFI室内定位系统_wifi定位系统-CSDN博客中&#xff0c;我介绍了如何用Android来测量WiFi信号&#xff0c;上传到服务器进行分析后&#xff0c;生成室内不同地方的WiFi指纹&#xff0c;从而帮助进行室内导航。当时我是用的HTML5的技术来快速开发一个An…

QQ邮箱发送工具类的实现

我们在日常开发中&#xff0c;需要实现一个对邮箱的发送&#xff0c;今天就实现邮箱的发送工具类&#xff0c;只需要一些注册邮箱之后的配置即可&#xff0c;我这边使用的是qq邮箱 0.加上依赖 <!--邮箱--><dependency><groupId>org.springframework.boot&l…

基于vue开发 - 编写登录页面样式

vue创建项目&#xff0c;使用可视化界面安装插件-CSDN博客 使用vue UI安装路由插件-CSDN博客 基于vue开发-创建登录页-CSDN博客 在src/views文件夹中创建登录页面login.vue&#xff0c;在router/index.js文件中加入登录页的路由&#xff0c;然后在浏览器中输入登录页的路径就…

FL Studio终身永久2024中文版下载安装详细操作图文步骤教程

FL Studio2024版是一款在国内非常受欢迎的多功能音频处理软件&#xff0c;我们可以通过这款软件来对多种不同格式的音频文件来进行编辑处理。而且FL Studio 2024版还为用户们准备了超多的音乐乐器伴奏&#xff0c;我们可以直接一键调取自己需要的音调。 FL Studio 2024版不仅拥…

算法设计基础——综合

算法设计基础中最基础的几种算法&#xff1a;分治法、减治法、贪心法、动态规划法、回溯法基本都掌握后&#xff0c;我们现在可以对这些算法做整体的比较&#xff0c;本次实验使用蛮力法、动态规划法、回溯法来求解0/1背包问题&#xff0c;来比较各个算法的优劣。 1. 蛮力法 …

代码随想录27期|Python|Day16|二叉树|104.二叉树的最大深度|111.二叉树的最小深度|222.完全二叉树的节点个数

二叉树专题&#xff0c;重点掌握后续的递归和中间节点的处理。 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 本题在前一章已经解决了层序遍历的解法&#xff0c;现在来聊一下递归法。 首先需要明确两个概念&#xff1a;深度和高度。&#xff08;注意&…

抠图软件哪个好用?什么软件可以抠图换背景?

抠图软件哪个好用&#xff1f;在图片处理中&#xff0c;抠图换背景是一项常见的操作。很多新手可能会对此感到困惑&#xff0c;不知道应该使用什么软件来进行抠图换景。实际上&#xff0c;现在市面上有很多图片处理软件都具备抠图换背景的功能&#xff0c;每款软件都有其优缺点…

LVS负载均衡群集部署 DR模式

目录 DR模式直接路由 LVS-DR工作原理 LVS-DR 数据包流向分析 DR 模式的特点 DR模式 LVS负载均衡群集部署 DR模式直接路由 Direct Routing&#xff0c;简称DR模式&#xff0c;采用半开放式的网络结构&#xff0c;与TUN模式的结构类似&#xff0c;但各节点并不是分散在各地…

c语言链表的基本操作

在C语言中&#xff0c;链表是一种常见的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。链表的基本操作包括创建、插入、删除和遍历等。 下面是一个简单的链表节点结构体定义&#xff1a; struct Node { int da…

Python实现员工管理系统(Django页面版 ) 六

本篇博客主要实现用户账号管理&#xff0c;这与之前的账号管理不同&#xff0c;之前的账号管理你可以理解为公司在外面买的一些手机号然后需要发放给员工做内部使用&#xff0c;而本篇博客的用户账号管理主要是为了后续的登录网页实现&#xff0c;那么我们开始今天的项目实现吧…

2. 套圈(分治)

题目 Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded. In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it c…

搭建消息时光机:深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用【RabbitMQ实战 二】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 搭建消息时光机&#xff1a;深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用 引言前言第一&#xff1a;开启插件支持第二&#xff1a;springboot整合第三&#xff1a;效果展示交换机属…

locust 压测 websocket

* 安装 python 3.8 https://www.python.org/ py --version * 安装 locust pip install locust2.5.1 -i http://pypi.douban.com/simple/ pip install locust2.5.1 -i https://pypi.mirrors.ustc.edu.cn/simple/ locust -V 备注&#xff1a;-i 是切换下载源 * 安装依赖 pip ins…

Electron框架:构建跨平台桌面应用的终极解决方案

文章目录 一、Electron框架简介二、Electron框架的优势1. 开发效率高2. 跨平台性能好3. 易于维护4. 强大的原生能力 三、如何使用Electron框架快速开发跨平台桌面应用1. 安装Electron2. 创建项目文件夹3. 编写主进程代码4. 编写界面代码5. 运行应用 《Electron入门与实战》编辑…

《软件方法》2023版1.1利润=需求-设计1.2 ABCD工作流

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 第1章 建模和UML 牵着你走进傍晚的风里&#xff0c;看见万家灯火下面平凡的秘密。 《情歌唱晚》&#xff1b;词&#xff1a;黄群&#xff0c;曲&#xff1a;黄群&#xff0c;唱&#…