导入SpringbootWEb依赖

  <!--web项目驱动-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot-start-version}</version>
</dependency> <!--redis缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

定义一个Controller,指定RESTFUL接口映射

@RestController
@SwaggerScanClass
public class TestController { @Autowired
private RedisTemplate redisTemplate; @Value("${mp.event.aeskey:4b57e89bac82a797}")
private String aesKey; private Map<String, Long> mockUrlTimeOut = new ConcurrentHashMap<>(); /**
* Description: 使用 Spring Framework 的事件发布机制发布应用程序事件。
*/
@Autowired
private ApplicationEventPublisher applicationEventPublisher; @PostMapping("/addMockInfo")
@ApiOperation("添加Mock信息")
public Resp addMockInfo(@RequestParam("url") String url, @RequestBody Object body) {
String redisSaveKey = AES.encrypt(url, aesKey);
Object returnBody = redisTemplate.opsForValue().get(redisSaveKey);
if (returnBody != null) {
redisTemplate.opsForValue().setIfAbsent(redisSaveKey, body, 48, TimeUnit.HOURS);
return Resp.Ok("url 响应报文更新成功" + url);
}
applicationEventPublisher.publishEvent(new AddMockInfoEvent(this, Clock.systemDefaultZone(), url, body));
return Resp.Ok("url添加Mock成功" + url);
} @PostMapping("/addMockInfoTimeOut")
@ApiOperation("添加Mock信息Url的阻塞时间")
public Resp addMockInfoTimeOut(@RequestParam("url") String url, @RequestParam("timeOut") Long timeOut) {
Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(url, timeOut, 48, TimeUnit.HOURS);
mockUrlTimeOut.put(url, timeOut);
return aBoolean ? Resp.Ok("url添加Mock成功" + timeOut) : Resp.error("添加Mock信息Url的阻塞时间失败");
} @ApiOperation("Mock动态回调Request")
public Resp addMockInfoByRequest() {
ServletRequestAttributes httpRequest = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = httpRequest.getRequest();
String requestURI = request.getRequestURI();
String redisSaveKey = AES.encrypt(requestURI, aesKey);
Object returnBody = redisTemplate.opsForValue().get(redisSaveKey);
if (returnBody == null) {
return Resp.error("Mock动态回调Request 没找到报文");
}
Long timeOut = mockUrlTimeOut.get(requestURI);
if (timeOut == null || timeOut == 0) {
Object redisSaveTimeOut = redisTemplate.opsForValue().get(requestURI);
if (redisSaveTimeOut != null) {
timeOut = (Long) redisSaveTimeOut;
mockUrlTimeOut.put(requestURI, timeOut);
}
}
try {
if (timeOut == null || timeOut == 0) {
return Resp.Ok(returnBody);
}
Thread.sleep(timeOut);
} catch (InterruptedException e) {
e.printStackTrace();
} return Resp.Ok(returnBody); } }

定义一个事件 AddMockInfoEvent

/**
* @description: 扩展来创建调用的自定义事件:extends ApplicationEvent
* @author: GuoTong
* @createTime: 2023-06-06 20:03
* @since JDK 1.8 OR 11
**/
public class AddMockInfoEvent extends ApplicationEvent { /**
* Description: Mock使用的地址
*/
private String url; /**
* Description: Mock使用的地址的响应报文
*/
private Object context; public AddMockInfoEvent(Object source) {
super(source);
} public AddMockInfoEvent(Object source, Clock clock) {
super(source, clock);
} public AddMockInfoEvent(Object source, String url, Object context) {
super(source);
this.url = url;
this.context = context;
} public AddMockInfoEvent(Object source, Clock clock, String url, Object context) {
super(source, clock);
this.url = url;
this.context = context;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public Object getContext() {
return context;
} public void setContext(Object context) {
this.context = context;
}
}

监听事件的发生:调用了添加动态URL的Mock接口时发生

import com.baomidou.mybatisplus.core.toolkit.AES;
import com.gton.controller.TestController;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.UrlPathHelper; import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit; /**
* @description: 使用@EventListener注解;启用注解驱动的配置时,不需要其他配置。我们的方法可以监听多个事件,
* @author: GuoTong
* @createTime: 2023-06-06 20:05
* @since JDK 1.8 OR 11
**/
@Component
@SuppressWarnings("unchecked")
public class SystemDIYEventPushListener { @Autowired
private RedisTemplate redisTemplate; /**
* Description: Controller AA
*/
@Autowired
@Lazy
private TestController testController; @Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping; @Value("${mp.event.aeskey:4b57e89bac82a797}")
private String aesKey; private String mockUrls = "MockUrls"; /**
* Description: 启用注解驱动监听事件,AddMockInfoEvent
*
* @param event
* @author: GuoTong
* @date: 2023-06-06 20:10:52
* @return:void
*/
@EventListener
public void handleUserRemovedEvent(AddMockInfoEvent event) {
String url = event.getUrl();
String redisSaveKeyUrl = AES.encrypt(url, aesKey);
Object context = event.getContext();
redisTemplate.opsForValue().setIfAbsent(redisSaveKeyUrl, context, 48, TimeUnit.HOURS);
// 获取所有的Mock的URL
Set<String> mockUrlsVar = redisTemplate.opsForSet().members(mockUrls);
if (CollectionUtils.isEmpty(mockUrlsVar)) {
// 准备好加入动态就接口的URL的容器
mockUrlsVar = new HashSet<>();
} else {
// 动态添加接口调用| 找出注册的,
RequestMappingInfo build = RequestMappingInfo.paths(mockUrlsVar.stream().toArray(String[]::new)).build();
// 准备注销原始接口
requestMappingHandlerMapping.unregisterMapping(build);
}
try {
// 加入新的URL
mockUrlsVar.add(url);
// 往redis里面注册URL
redisTemplate.opsForSet().add(mockUrls, url);
// 设置过期时间
redisTemplate.expire(mockUrls, 48, TimeUnit.HOURS);
// 动态添加接口调用
RequestMappingInfo requestMappingInfo =
RequestMappingInfo.
paths(mockUrlsVar.stream().toArray(String[]::new))
.build();
// 指定接口回调的方法
Method addMockInfoByGetMethod = TestController.class.getDeclaredMethod("addMockInfoByRequest");
// 注册新的接口
requestMappingHandlerMapping.
registerMapping(requestMappingInfo,
testController,
addMockInfoByGetMethod);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} } }

测试

响应

试验新的Mock挡板是否动态添加成功

添加延时响应

查看效果

利用SpringBoot项目做一个Mock挡板;基于事件发布动态自定义URL和响应报文的更多相关文章

  1. 利用jquery+iframe做一个ajax上传效果

    以下是自学it网--中级班上课笔记 网址:www.zixue.it html页面 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict ...

  2. SpringBoot项目打成一个war包

    springboot 带有内置Tomcat 服务器,可以直接将项目打包成jar运行,运行命令为: java -jar demo.jar 但是如果在需要把项目达成war包该怎么办呢?下面是将spring ...

  3. 给你的SpringBoot项目定制一个牛年专属banner吧

    新春快乐,牛年大吉! 新的一年是牛年,在SpringBoot项目里自定义了一个牛年相关的banner,看起来可真不错. 上面是自己制作的一个banner,相关的ASCII字符在文末. SpringBo ...

  4. c#利用三层架构做一个简单的登录窗体

    就个人而言,三层架构有点难理解,不知道该如何下手,各层与各层之间怎么调用 最近一直在研究三层架构,经过网上学习与多方打听写一下自己的心得.有不足之处,可以评论和私聊探讨 言归正传: 三层架构(3-ti ...

  5. 【构建之法教学项目】一个简单的基于C#的电子商务系统演练场景的代码示例

    电子商务平台,是一个历史悠久而又充满挑战的行业,他和社交一起成为中国互联网市场的两极.电子商务系统是一个非常复杂的系统,他实现了人与物.人与人的链接,同时也需要大量的技术来支撑,实现系统的高可用.这些 ...

  6. 利用random模块做一个抢红包功能

    我们都知道random模块是一个生成随机数的模块,用它来做抢红包的功能很合适. 抢红包,抢到的金额是随机的,但怎么让每个人抢到的随机金额公平合理呢 比如:我想发一个100元的红包让10个人抢,我可以把 ...

  7. 利用python+tkinter做一个简单的智能电视遥控器

    要通过python实现遥控器功能分两步: 第一步:开发图形化界面,以暴风TV的遥控器按钮为例 第二步:使PC端给电视发送相应指令(此步骤需要打开电视的adb开关) 现在就开始第一步操作实现遥控器功能, ...

  8. python小练习,利用dict,做一个简单的登录。

    '''利用字典实现登录'''users=[{'username':'jerry','pwd':'123456'},{'username':'tom','pwd':'1'}] def login(use ...

  9. 利用ssm框架做一个客户管理系统

    1. 需求分析 (1)初始化查询条件下拉列表 (2)展示客户列表,并且可以根据查询条件过滤查询结果,并且实现分页处理. (3)修改客户信息: 1)点击客户列表中的“修改”按钮弹出客户信息修改对话框,并 ...

  10. 利用shell脚本做一个用户登录系统

    效果图如下: #!/bin/bash# while truedocat << EOF//======================\\\\| 用户登录系统 |-------------- ...

随机推荐

  1. 驱动开发:摘除InlineHook内核钩子

    在笔者上一篇文章<驱动开发:内核层InlineHook挂钩函数>中介绍了通过替换函数头部代码的方式实现Hook挂钩,对于ARK工具来说实现扫描与摘除InlineHook钩子也是最基本的功能 ...

  2. 大数据实战手册-开发篇之RDD:计算 transform->action

    2.2 RDD:计算 transform->action 2.2.1 aggregate x = sc.parallelize([2,3,4], 2)[Task不能跨分片,task数为2] ne ...

  3. WPF入门教程系列二十九 ——DataGrid使用示例MVVM模式(7)

    WPF入门教程系列目录 WPF入门教程系列二--Application介绍 WPF入门教程系列三--Application介绍(续) WPF入门教程系列四--Dispatcher介绍 WPF入门教程系 ...

  4. Solon Web 也支持响应式开发了?!

    "solon.web.flux" 是 solon v2.3.6 新推出的生态插件,为 solon web 提供响应式接口支持 (io.projectreactor) .为什么叫这个 ...

  5. asp.net程序通过Microsoft Azure令牌授予流获取UserInfo终结点实现单点登录--隐式授予流(OIDC协议)

    1. Microsoft Azure令牌授予流 令牌授予流种类如下: 本章节采用: 隐式授予流: 2. 隐式授予流的实现 流程:重定向到authorize--->拿到access_token-- ...

  6. PostMan如何联调SignalR WebSockets

    我们在调试SignalR的时候,往往要写多一个客户端对接联调.其实,在过去的几个版本中,Postman 已经能够使用 WebSocket 连接连接到 SignalR 中心并发送和接收消息. 设置请求 ...

  7. spingmvc配置AOP 之 非注解方式

    spingmvc配置AOP有两种方式,一种是利用注解的方式配置,另一种是XML配置实现. 应用注解的方式配置: 先在maven中引入AOP用到的依赖 <dependency> <gr ...

  8. python笔记:第四章使用字典

    1.1 概述 说白了就是键值对的映射关系 不会丢失数据本身关联的结构,但不关注数据的顺序 是一种可变类型 格式:dic = {键:值, 键:值} 键的类型:字典的键可以是任何不可变的类型,如浮点数,字 ...

  9. 【Redis】字符串sds

    sds,即 Simple Dynamic Strings,是Redis中存储绝大部分字符串所采用的数据结构. typedef char *sds; 一.类型 sds的类型包括SDS_TYPE_5, S ...

  10. 【阅读笔记】低照度图像增强-《An Integrated Neighborhood Dependent...

    本文介绍的是一种比较实用的低照度图像增强算法,选自2004年Tao的一篇论文,名称是<An Integrated Neighborhood Dependent Approach for Nonl ...