mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Merge branch 'master' of https://github.com/zhangdaiscott/jeecg-boot
This commit is contained in:
@ -1,7 +1,10 @@
|
||||
package org.jeecg.config.init;
|
||||
|
||||
import io.undertow.server.DefaultByteBufferPool;
|
||||
import io.undertow.server.handlers.BlockingHandler;
|
||||
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
|
||||
import org.jeecg.modules.monitor.actuator.undertow.CustomUndertowMetricsHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -12,7 +15,14 @@ import org.springframework.context.annotation.Configuration;
|
||||
* 解决启动提示: WARN io.undertow.websockets.jsr:68 - UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
|
||||
*/
|
||||
@Configuration
|
||||
public class UndertowConfiguration implements WebServerFactoryCustomizer<UndertowServletWebServerFactory>{
|
||||
public class UndertowConfiguration implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
|
||||
|
||||
/**
|
||||
* 自定义undertow监控指标工具类
|
||||
* for [QQYUN-11902]tomcat 替换undertow 这里的功能还没修改
|
||||
*/
|
||||
@Autowired
|
||||
private CustomUndertowMetricsHandler customUndertowMetricsHandler;
|
||||
|
||||
@Override
|
||||
public void customize(UndertowServletWebServerFactory factory) {
|
||||
@ -24,6 +34,9 @@ public class UndertowConfiguration implements WebServerFactoryCustomizer<Underto
|
||||
webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 8192));
|
||||
|
||||
deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
|
||||
|
||||
// 添加自定义 监控 handler
|
||||
deploymentInfo.addInitialHandlerChainWrapper(next -> new BlockingHandler(customUndertowMetricsHandler.wrap(next)));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package org.jeecg.modules.monitor.actuator.undertow;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.undertow.server.HttpHandler;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.server.session.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* 自定义undertow监控指标工具类
|
||||
* for [QQYUN-11902]tomcat 替换undertow 这里的功能还没修改
|
||||
* @author chenrui
|
||||
* @date 2025/4/8 19:06
|
||||
*/
|
||||
@Component("jeecgCustomUndertowMetricsHandler")
|
||||
public class CustomUndertowMetricsHandler {
|
||||
|
||||
// 用于统计已创建的 session 数量
|
||||
private final LongAdder sessionsCreated = new LongAdder();
|
||||
|
||||
// 用于统计已销毁的 session 数量
|
||||
private final LongAdder sessionsExpired = new LongAdder();
|
||||
|
||||
// 当前活跃的 session 数量
|
||||
private final AtomicInteger activeSessions = new AtomicInteger();
|
||||
|
||||
// 历史最大活跃 session 数
|
||||
private final AtomicInteger maxActiveSessions = new AtomicInteger();
|
||||
|
||||
// Undertow 内存 session 管理器(用于创建与管理 session)
|
||||
private final InMemorySessionManager sessionManager = new InMemorySessionManager("undertow-session-manager");
|
||||
|
||||
// 使用 Cookie 存储 session ID
|
||||
private final SessionConfig sessionConfig = new SessionCookieConfig();
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param meterRegistry
|
||||
* @author chenrui
|
||||
* @date 2025/4/8 19:07
|
||||
*/
|
||||
public CustomUndertowMetricsHandler(MeterRegistry meterRegistry) {
|
||||
// 注册 Micrometer 指标
|
||||
meterRegistry.gauge("undertow.sessions.created", sessionsCreated, LongAdder::longValue);
|
||||
meterRegistry.gauge("undertow.sessions.expired", sessionsExpired, LongAdder::longValue);
|
||||
meterRegistry.gauge("undertow.sessions.active.current", activeSessions, AtomicInteger::get);
|
||||
meterRegistry.gauge("undertow.sessions.active.max", maxActiveSessions, AtomicInteger::get);
|
||||
|
||||
// 添加 session 生命周期监听器,统计 session 创建与销毁
|
||||
sessionManager.registerSessionListener(new SessionListener() {
|
||||
@Override
|
||||
public void sessionCreated(Session session, HttpServerExchange exchange) {
|
||||
sessionsCreated.increment();
|
||||
int now = activeSessions.incrementAndGet();
|
||||
maxActiveSessions.getAndUpdate(max -> Math.max(max, now));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionDestroyed(Session session, HttpServerExchange exchange, SessionDestroyedReason reason) {
|
||||
sessionsExpired.increment();
|
||||
activeSessions.decrementAndGet();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 包装 Undertow 的 HttpHandler,实现 session 自动创建逻辑
|
||||
* @param next
|
||||
* @return
|
||||
* @author chenrui
|
||||
* @date 2025/4/8 19:07
|
||||
*/
|
||||
public HttpHandler wrap(HttpHandler next) {
|
||||
return exchange -> {
|
||||
// 获取当前 session,如果不存在则创建
|
||||
Session session = sessionManager.getSession(exchange, sessionConfig);
|
||||
if (session == null) {
|
||||
sessionManager.createSession(exchange, sessionConfig);
|
||||
}
|
||||
|
||||
// 执行下一个 Handler
|
||||
next.handleRequest(exchange);
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,177 @@
|
||||
package org.jeecg.modules.system.test;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.modules.redis.client.JeecgRedisClient;
|
||||
import org.jeecg.common.util.RedisUtil;
|
||||
import org.jeecg.config.JeecgBaseConfig;
|
||||
import org.jeecg.modules.base.service.BaseCommonService;
|
||||
import org.jeecg.modules.system.controller.SysUserController;
|
||||
import org.jeecg.modules.system.entity.SysUser;
|
||||
import org.jeecg.modules.system.service.*;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
|
||||
/**
|
||||
* 系统用户单元测试
|
||||
*/
|
||||
@WebMvcTest(SysUserController.class)
|
||||
public class SysUserApiTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private ISysUserService sysUserService;
|
||||
|
||||
@MockBean
|
||||
private ISysDepartService sysDepartService;
|
||||
|
||||
@MockBean
|
||||
private ISysUserRoleService sysUserRoleService;
|
||||
|
||||
@MockBean
|
||||
private ISysUserDepartService sysUserDepartService;
|
||||
|
||||
@MockBean
|
||||
private ISysDepartRoleUserService departRoleUserService;
|
||||
|
||||
@MockBean
|
||||
private ISysDepartRoleService departRoleService;
|
||||
|
||||
@MockBean
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Value("${jeecg.path.upload}")
|
||||
private String upLoadPath;
|
||||
|
||||
@MockBean
|
||||
private BaseCommonService baseCommonService;
|
||||
|
||||
@MockBean
|
||||
private ISysUserAgentService sysUserAgentService;
|
||||
|
||||
@MockBean
|
||||
private ISysPositionService sysPositionService;
|
||||
|
||||
@MockBean
|
||||
private ISysUserTenantService userTenantService;
|
||||
|
||||
@MockBean
|
||||
private JeecgRedisClient jeecgRedisClient;
|
||||
|
||||
@MockBean
|
||||
private JeecgBaseConfig jeecgBaseConfig;
|
||||
/**
|
||||
* 测试地址:实际使用时替换成你自己的地址
|
||||
*/
|
||||
private final String BASE_URL = "/sys/user/";
|
||||
|
||||
/**
|
||||
* 测试用例:查询记录
|
||||
*/
|
||||
@Test
|
||||
public void testQuery() throws Exception{
|
||||
// 请求地址
|
||||
String url = BASE_URL + "list";
|
||||
|
||||
Page<SysUser> sysUserPage = new Page<>();
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUsername("admin");
|
||||
List<SysUser> users = new ArrayList<>();
|
||||
users.add(sysUser);
|
||||
sysUserPage.setRecords(users);
|
||||
sysUserPage.setCurrent(1);
|
||||
sysUserPage.setSize(10);
|
||||
sysUserPage.setTotal(1);
|
||||
|
||||
given(this.sysUserService.queryPageList(any(), any(), any(), any())).willReturn(Result.OK(sysUserPage));
|
||||
|
||||
String result = mockMvc.perform(get(url)).andReturn().getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSON.parseObject(result);
|
||||
Assertions.assertEquals("admin", jsonObject.getJSONObject("result").getJSONArray("records").getJSONObject(0).getString("username"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试用例:新增
|
||||
*/
|
||||
@Test
|
||||
public void testAdd() throws Exception {
|
||||
// 请求地址
|
||||
String url = BASE_URL + "add" ;
|
||||
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("username", "wangwuTest");
|
||||
params.put("password", "123456");
|
||||
params.put("confirmpassword","123456");
|
||||
params.put("realname", "单元测试");
|
||||
params.put("activitiSync", "1");
|
||||
params.put("userIdentity","1");
|
||||
params.put("workNo","0025");
|
||||
|
||||
String result = mockMvc.perform(post(url).contentType(MediaType.APPLICATION_JSON_VALUE).content(params.toJSONString()))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSON.parseObject(result);
|
||||
Assertions.assertTrue(jsonObject.getBoolean("success"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试用例:修改
|
||||
*/
|
||||
@Test
|
||||
public void testEdit() throws Exception {
|
||||
// 数据Id
|
||||
String dataId = "1331795062924374018";
|
||||
// 请求地址
|
||||
String url = BASE_URL + "edit";
|
||||
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("username", "wangwuTest");
|
||||
params.put("realname", "单元测试1111");
|
||||
params.put("activitiSync", "1");
|
||||
params.put("userIdentity","1");
|
||||
params.put("workNo","0025");
|
||||
params.put("id",dataId);
|
||||
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUsername("admin");
|
||||
|
||||
given(this.sysUserService.getById(any())).willReturn(sysUser);
|
||||
|
||||
String result = mockMvc.perform(put(url).contentType(MediaType.APPLICATION_JSON_VALUE).content(params.toJSONString()))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSON.parseObject(result);
|
||||
Assertions.assertTrue(jsonObject.getBoolean("success"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试用例:删除
|
||||
*/
|
||||
@Test
|
||||
public void testDelete() throws Exception {
|
||||
// 数据Id
|
||||
String dataId = "1331795062924374018";
|
||||
// 请求地址
|
||||
String url = BASE_URL + "delete" + "?id=" + dataId;
|
||||
String result = mockMvc.perform(delete(url)).andReturn().getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSON.parseObject(result);
|
||||
Assertions.assertTrue(jsonObject.getBoolean("success"));
|
||||
}
|
||||
}
|
||||
@ -359,7 +359,7 @@
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework</groupId>
|
||||
<artifactId>weixin4j</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<version>2.0.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user