后台管理框架+文件上传首次提交
commit
b71b0b2fc9
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*.{adoc,bat,groovy,html,java,js,jsp,kt,kts,md,properties,py,rb,sh,sql,svg,txt,xml,xsd}]
|
||||
charset = utf-8
|
||||
|
||||
[*.{groovy,java,kt,kts,xml,xsd}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
continuation_indent_size = 8
|
@ -0,0 +1 @@
|
||||
java-baseline=8
|
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Hccake
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -0,0 +1,5 @@
|
||||
# ballcat-boot
|
||||
|
||||
此项目是 Ballcat 单体应用的模板项目。
|
||||
|
||||
用户可以基于此模板项目进行业务的定制开发。
|
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ad-distribute-admin</artifactId>
|
||||
<groupId>com.baiye</groupId>
|
||||
<version>1.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>admin-core</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!--mybatis plus-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 脱敏工具 -->
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>common-desensitize</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>common-model</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<!-- 基于 spring authorization server 的授权服务器 -->
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>security-oauth2-authorization-server</artifactId>
|
||||
<scope>compile</scope>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>security-oauth2-resource-server</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>system-controller</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,42 @@
|
||||
package com.hccake.ballcat.admin.upms.config.mybatis;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.hccake.ballcat.common.core.constant.GlobalConstants;
|
||||
import com.hccake.ballcat.common.security.userdetails.User;
|
||||
import com.hccake.ballcat.common.security.util.SecurityUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author Hccake 2019/7/26 14:41
|
||||
*/
|
||||
@Slf4j
|
||||
public class FillMetaObjectHandle implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
// 逻辑删除标识
|
||||
this.strictInsertFill(metaObject, "deleted", Long.class, GlobalConstants.NOT_DELETED_FLAG);
|
||||
// 创建时间
|
||||
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
|
||||
// 创建人
|
||||
User user = SecurityUtils.getUser();
|
||||
if (user != null) {
|
||||
this.strictInsertFill(metaObject, "createBy", Long.class, user.getUserId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
// 修改时间
|
||||
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
|
||||
// 修改人
|
||||
User user = SecurityUtils.getUser();
|
||||
if (user != null) {
|
||||
this.strictUpdateFill(metaObject, "updateBy", Long.class, user.getUserId());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
// package com.hccake.ballcat.admin.upms.log;
|
||||
//
|
||||
// import com.hccake.ballcat.common.log.access.handler.AccessLogHandler;
|
||||
// import com.hccake.ballcat.common.log.operation.handler.OperationLogHandler;
|
||||
// import com.hccake.ballcat.log.handler.CustomAccessLogHandler;
|
||||
// import com.hccake.ballcat.log.handler.CustomOperationLogHandler;
|
||||
// import com.hccake.ballcat.log.model.entity.AccessLog;
|
||||
// import com.hccake.ballcat.log.model.entity.OperationLog;
|
||||
// import com.hccake.ballcat.log.service.AccessLogService;
|
||||
// import com.hccake.ballcat.log.service.LoginLogService;
|
||||
// import com.hccake.ballcat.log.service.OperationLogService;
|
||||
// import com.hccake.ballcat.log.thread.AccessLogSaveThread;
|
||||
// import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
// import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
// import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
// import org.springframework.context.annotation.Bean;
|
||||
// import org.springframework.context.annotation.Configuration;
|
||||
// import
|
||||
// org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
|
||||
// import
|
||||
// org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
|
||||
//
|
||||
/// **
|
||||
// * @author hccake
|
||||
// */
|
||||
// @Configuration(proxyBeanMethods = false)
|
||||
// @ConditionalOnClass(LoginLogService.class)
|
||||
// public class LogConfiguration {
|
||||
//
|
||||
// /**
|
||||
// * 访问日志保存
|
||||
// * @param accessLogService 访问日志Service
|
||||
// * @return CustomAccessLogHandler
|
||||
// */
|
||||
// @Bean
|
||||
// @ConditionalOnBean(AccessLogService.class)
|
||||
// @ConditionalOnMissingBean(AccessLogHandler.class)
|
||||
// public AccessLogHandler<AccessLog> customAccessLogHandler(AccessLogService
|
||||
// accessLogService) {
|
||||
// return new CustomAccessLogHandler(new AccessLogSaveThread(accessLogService));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 操作日志处理器
|
||||
// * @param operationLogService 操作日志Service
|
||||
// * @return CustomOperationLogHandler
|
||||
// */
|
||||
// @Bean
|
||||
// @ConditionalOnBean(OperationLogService.class)
|
||||
// @ConditionalOnMissingBean(OperationLogHandler.class)
|
||||
// public OperationLogHandler<OperationLog> customOperationLogHandler(OperationLogService
|
||||
// operationLogService) {
|
||||
// return new CustomOperationLogHandler(operationLogService);
|
||||
// }
|
||||
//
|
||||
// @ConditionalOnClass(OAuth2AuthorizationServerConfigurer.class)
|
||||
// @ConditionalOnBean(LoginLogService.class)
|
||||
// @ConditionalOnMissingBean(LoginLogHandler.class)
|
||||
// @Configuration(proxyBeanMethods = false)
|
||||
// static class SpringAuthorizationServerLoginLogConfiguration {
|
||||
//
|
||||
// /**
|
||||
// * Spring Authorization Server 的登录日志处理,监听登录事件记录登录登出
|
||||
// * @param loginLogService 操作日志Service
|
||||
// * @param authorizationServerSettings 授权服务器设置
|
||||
// * @return SpringAuthorizationServerLoginLogHandler
|
||||
// */
|
||||
// @Bean
|
||||
// public LoginLogHandler springAuthorizationServerLoginLogHandler(LoginLogService
|
||||
// loginLogService,
|
||||
// AuthorizationServerSettings authorizationServerSettings) {
|
||||
// return new SpringAuthorizationServerLoginLogHandler(loginLogService,
|
||||
// authorizationServerSettings);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
@ -0,0 +1,8 @@
|
||||
package com.hccake.ballcat.admin.upms.log;
|
||||
|
||||
/**
|
||||
* @author hccake
|
||||
*/
|
||||
public interface LoginLogHandler {
|
||||
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
// package com.hccake.ballcat.admin.upms.log;
|
||||
//
|
||||
// import com.hccake.ballcat.common.core.util.WebUtils;
|
||||
//// import com.hccake.ballcat.common.log.operation.enums.LogStatusEnum;
|
||||
// import com.hccake.ballcat.common.security.util.SecurityUtils;
|
||||
//// import com.hccake.ballcat.log.enums.LoginEventTypeEnum;
|
||||
//// import com.hccake.ballcat.log.model.entity.LoginLog;
|
||||
//// import com.hccake.ballcat.log.service.LoginLogService;
|
||||
// import lombok.RequiredArgsConstructor;
|
||||
// import
|
||||
// org.ballcat.springsecurity.oauth2.server.authorization.authentication.OAuth2TokenRevocationAuthenticationToken;
|
||||
// import org.springframework.context.event.EventListener;
|
||||
// import org.springframework.security.authentication.ProviderNotFoundException;
|
||||
// import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
// import
|
||||
// org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
|
||||
// import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
||||
// import org.springframework.security.authentication.event.LogoutSuccessEvent;
|
||||
// import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
// import
|
||||
// org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
||||
// import
|
||||
// org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
||||
// import
|
||||
// org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
|
||||
//
|
||||
// import javax.servlet.http.HttpServletRequest;
|
||||
//
|
||||
//// import static com.hccake.ballcat.log.handler.LoginLogUtils.prodLoginLog;
|
||||
//
|
||||
/// **
|
||||
// * spring 授权服务器的登录日志处理器
|
||||
// *
|
||||
// * @author hccake
|
||||
// */
|
||||
// @RequiredArgsConstructor
|
||||
// public class SpringAuthorizationServerLoginLogHandler implements LoginLogHandler {
|
||||
//
|
||||
//// private final LoginLogService loginLogService;
|
||||
//
|
||||
// private final AuthorizationServerSettings authorizationServerSettings;
|
||||
//
|
||||
// /**
|
||||
// * 登录成功事件监听 记录用户登录日志
|
||||
// * @param event 登录成功 event
|
||||
// */
|
||||
// @EventListener(AuthenticationSuccessEvent.class)
|
||||
// public void onAuthenticationSuccessEvent(AuthenticationSuccessEvent event) {
|
||||
// Object source = event.getSource();
|
||||
// String username = null;
|
||||
//
|
||||
// String tokenEndpoint = authorizationServerSettings.getTokenEndpoint();
|
||||
// HttpServletRequest request = WebUtils.getRequest();
|
||||
// boolean isOauth2LoginRequest = request.getRequestURI().equals(tokenEndpoint);
|
||||
//
|
||||
// // Oauth2登录 和表单登录 处理分开
|
||||
// if (isOauth2LoginRequest && source instanceof OAuth2AccessTokenAuthenticationToken) {
|
||||
// username = SecurityUtils.getAuthentication().getName();
|
||||
// }
|
||||
// else if (!isOauth2LoginRequest && source instanceof
|
||||
// UsernamePasswordAuthenticationToken) {
|
||||
// username = ((UsernamePasswordAuthenticationToken) source).getName();
|
||||
// }
|
||||
//
|
||||
//// if (username != null) {
|
||||
//// LoginLog loginLog = prodLoginLog(username).setMsg("登录成功")
|
||||
//// .setStatus(LogStatusEnum.SUCCESS.getValue())
|
||||
//// .setEventType(LoginEventTypeEnum.LOGIN.getValue());
|
||||
//// loginLogService.save(loginLog);
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 监听鉴权失败事件,记录登录失败日志
|
||||
// * @param event the event
|
||||
// */
|
||||
// @EventListener(AbstractAuthenticationFailureEvent.class)
|
||||
// public void onAuthenticationFailureEvent(AbstractAuthenticationFailureEvent event) {
|
||||
// if (event.getException().getClass().isAssignableFrom(ProviderNotFoundException.class))
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Object source = event.getSource();
|
||||
// String username = null;
|
||||
//
|
||||
// String tokenEndpoint = authorizationServerSettings.getTokenEndpoint();
|
||||
// HttpServletRequest request = WebUtils.getRequest();
|
||||
// boolean isOauth2LoginRequest = request.getRequestURI().equals(tokenEndpoint);
|
||||
//
|
||||
// // Oauth2登录 和表单登录 处理分开
|
||||
// if (isOauth2LoginRequest && source instanceof
|
||||
// OAuth2AuthorizationGrantAuthenticationToken) {
|
||||
// username = ((OAuth2AuthorizationGrantAuthenticationToken) source).getName();
|
||||
// }
|
||||
// else if (!isOauth2LoginRequest && source instanceof
|
||||
// UsernamePasswordAuthenticationToken) {
|
||||
// username = ((UsernamePasswordAuthenticationToken) source).getName();
|
||||
// }
|
||||
//
|
||||
//// if (username != null) {
|
||||
//// LoginLog loginLog = prodLoginLog(username).setMsg(event.getException().getMessage())
|
||||
//// .setEventType(LoginEventTypeEnum.LOGIN.getValue())
|
||||
//// .setStatus(LogStatusEnum.FAIL.getValue());
|
||||
//// loginLogService.save(loginLog);
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 登出成功事件监听
|
||||
// * @param event the event
|
||||
// */
|
||||
// @EventListener(LogoutSuccessEvent.class)
|
||||
// public void onLogoutSuccessEvent(LogoutSuccessEvent event) {
|
||||
// Object source = event.getSource();
|
||||
// String username = null;
|
||||
//
|
||||
// String tokenRevocationEndpoint =
|
||||
// authorizationServerSettings.getTokenRevocationEndpoint();
|
||||
// HttpServletRequest request = WebUtils.getRequest();
|
||||
// boolean isOauth2Login = request.getRequestURI().equals(tokenRevocationEndpoint);
|
||||
//
|
||||
// // Oauth2撤销令牌 和表单登出 处理分开
|
||||
// if (isOauth2Login && source instanceof OAuth2TokenRevocationAuthenticationToken) {
|
||||
// OAuth2Authorization authorization = ((OAuth2TokenRevocationAuthenticationToken)
|
||||
// source).getAuthorization();
|
||||
// username = authorization.getPrincipalName();
|
||||
// }
|
||||
// else if (!isOauth2Login && source instanceof UsernamePasswordAuthenticationToken) {
|
||||
// username = ((UsernamePasswordAuthenticationToken) source).getName();
|
||||
// }
|
||||
//
|
||||
//// if (username != null) {
|
||||
//// LoginLog loginLog = prodLoginLog(username).setMsg("登出成功")
|
||||
//// .setEventType(LoginEventTypeEnum.LOGOUT.getValue());
|
||||
//// loginLogService.save(loginLog);
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// }
|
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.hccake.ballcat.admin.upms.UpmsAutoConfiguration
|
@ -0,0 +1 @@
|
||||
com.hccake.ballcat.admin.upms.UpmsAutoConfiguration
|
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ad-distribute-admin</artifactId>
|
||||
<groupId>com.baiye</groupId>
|
||||
<version>1.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>admin-websocket</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>admin-core</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>ad-distribute-starter-websocket</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,34 @@
|
||||
package com.hccake.ballcat.admin.websocket;
|
||||
|
||||
import com.hccake.ballcat.admin.websocket.component.UserAttributeHandshakeInterceptor;
|
||||
import com.hccake.ballcat.admin.websocket.component.UserSessionKeyGenerator;
|
||||
import com.hccake.ballcat.common.websocket.session.SessionKeyGenerator;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||
|
||||
/**
|
||||
* @author Hccake 2021/1/5
|
||||
* @version 1.0
|
||||
*/
|
||||
@Import({ SystemWebsocketEventListenerConfiguration.class })
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class AdminWebSocketAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(UserAttributeHandshakeInterceptor.class)
|
||||
public HandshakeInterceptor authenticationHandshakeInterceptor() {
|
||||
return new UserAttributeHandshakeInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SessionKeyGenerator.class)
|
||||
public SessionKeyGenerator userSessionKeyGenerator() {
|
||||
return new UserSessionKeyGenerator();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// package com.hccake.ballcat.admin.websocket;
|
||||
//
|
||||
// import com.hccake.ballcat.admin.websocket.listener.NotifyWebsocketEventListener;
|
||||
// import com.hccake.ballcat.common.websocket.distribute.MessageDistributor;
|
||||
// import com.hccake.ballcat.notify.handler.NotifyInfoDelegateHandler;
|
||||
// import com.hccake.ballcat.notify.model.domain.NotifyInfo;
|
||||
// import com.hccake.ballcat.notify.service.UserAnnouncementService;
|
||||
// import lombok.RequiredArgsConstructor;
|
||||
// import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
// import org.springframework.context.annotation.Bean;
|
||||
// import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
// @RequiredArgsConstructor
|
||||
// @ConditionalOnClass({ NotifyWebsocketEventListener.class, UserAnnouncementService.class
|
||||
// })
|
||||
// @Configuration(proxyBeanMethods = false)
|
||||
// public class NotifyWebsocketEventListenerConfiguration {
|
||||
//
|
||||
// private final MessageDistributor messageDistributor;
|
||||
//
|
||||
// @Bean
|
||||
// public NotifyWebsocketEventListener notifyWebsocketEventListener(
|
||||
// NotifyInfoDelegateHandler<? super NotifyInfo> notifyInfoDelegateHandler) {
|
||||
// return new NotifyWebsocketEventListener(messageDistributor, notifyInfoDelegateHandler);
|
||||
// }
|
||||
//
|
||||
// }
|
@ -0,0 +1,25 @@
|
||||
package com.hccake.ballcat.admin.websocket;
|
||||
|
||||
import com.hccake.ballcat.admin.websocket.listener.SystemWebsocketEventListener;
|
||||
import com.hccake.ballcat.common.websocket.distribute.MessageDistributor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Hccake
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnClass(SystemWebsocketEventListener.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class SystemWebsocketEventListenerConfiguration {
|
||||
|
||||
private final MessageDistributor messageDistributor;
|
||||
|
||||
@Bean
|
||||
public SystemWebsocketEventListener systemWebsocketEventListener() {
|
||||
return new SystemWebsocketEventListener(messageDistributor);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.hccake.ballcat.admin.websocket.component;
|
||||
|
||||
import com.hccake.ballcat.admin.websocket.constant.AdminWebSocketConstants;
|
||||
import com.hccake.ballcat.common.security.userdetails.User;
|
||||
import com.hccake.ballcat.common.security.util.SecurityUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* WebSocket 握手拦截器 在握手时记录下当前 session 对应的用户Id和token信息
|
||||
*
|
||||
* @author Hccake 2021/1/4
|
||||
* @version 1.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class UserAttributeHandshakeInterceptor implements HandshakeInterceptor {
|
||||
|
||||
/**
|
||||
* Invoked before the handshake is processed.
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
* @param wsHandler the target WebSocket handler
|
||||
* @param attributes the attributes from the HTTP handshake to associate with the
|
||||
* WebSocket session; the provided attributes are copied, the original map is not
|
||||
* used.
|
||||
* @return whether to proceed with the handshake ({@code true}) or abort
|
||||
* ({@code false})
|
||||
*/
|
||||
@Override
|
||||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Map<String, Object> attributes) {
|
||||
String accessToken = null;
|
||||
// 获得 accessToken
|
||||
if (request instanceof ServletServerHttpRequest) {
|
||||
ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request;
|
||||
accessToken = serverRequest.getServletRequest().getParameter(AdminWebSocketConstants.TOKEN_ATTR_NAME);
|
||||
}
|
||||
// 由于 WebSocket 握手是由 http 升级的,携带 token 已经被 Security 拦截验证了,所以可以直接获取到用户
|
||||
User user = SecurityUtils.getUser();
|
||||
attributes.put(AdminWebSocketConstants.TOKEN_ATTR_NAME, accessToken);
|
||||
attributes.put(AdminWebSocketConstants.USER_KEY_ATTR_NAME, user.getUserId());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after the handshake is done. The response status and headers indicate the
|
||||
* results of the handshake, i.e. whether it was successful or not.
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
* @param wsHandler the target WebSocket handler
|
||||
* @param exception an exception raised during the handshake, or {@code null} if none
|
||||
*/
|
||||
@Override
|
||||
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Exception exception) {
|
||||
// doNothing
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.hccake.ballcat.admin.websocket.constant;
|
||||
|
||||
/**
|
||||
* @author Hccake 2021/1/5
|
||||
* @version 1.0
|
||||
*/
|
||||
public final class AdminWebSocketConstants {
|
||||
|
||||
private AdminWebSocketConstants() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储在 WebSocketSession Attribute 中的 token 属性名
|
||||
*/
|
||||
public static final String TOKEN_ATTR_NAME = "access_token";
|
||||
|
||||
/**
|
||||
* 存储在 WebSocketSession Attribute 中的 用户唯一标识 属性名
|
||||
*/
|
||||
public static final String USER_KEY_ATTR_NAME = "userId";
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
// package com.hccake.ballcat.admin.websocket.listener;
|
||||
//
|
||||
// import com.hccake.ballcat.common.util.JsonUtils;
|
||||
// import com.hccake.ballcat.common.websocket.distribute.MessageDO;
|
||||
// import com.hccake.ballcat.common.websocket.distribute.MessageDistributor;
|
||||
// import com.hccake.ballcat.notify.event.AnnouncementCloseEvent;
|
||||
// import com.hccake.ballcat.notify.event.StationNotifyPushEvent;
|
||||
// import com.hccake.ballcat.notify.handler.NotifyInfoDelegateHandler;
|
||||
// import com.hccake.ballcat.notify.model.domain.NotifyInfo;
|
||||
// import com.hccake.ballcat.admin.websocket.message.AnnouncementCloseMessage;
|
||||
// import com.hccake.ballcat.system.model.entity.SysUser;
|
||||
// import lombok.RequiredArgsConstructor;
|
||||
// import lombok.extern.slf4j.Slf4j;
|
||||
// import org.springframework.context.event.EventListener;
|
||||
// import org.springframework.scheduling.annotation.Async;
|
||||
//
|
||||
// import java.util.List;
|
||||
//
|
||||
/// **
|
||||
// * @author Hccake 2021/1/5
|
||||
// * @version 1.0
|
||||
// */
|
||||
// @Slf4j
|
||||
// @RequiredArgsConstructor
|
||||
// public class NotifyWebsocketEventListener {
|
||||
//
|
||||
// private final MessageDistributor messageDistributor;
|
||||
//
|
||||
// private final NotifyInfoDelegateHandler<? super NotifyInfo> notifyInfoDelegateHandler;
|
||||
//
|
||||
// /**
|
||||
// * 公告关闭事件监听
|
||||
// * @param event the AnnouncementCloseEvent
|
||||
// */
|
||||
// @Async
|
||||
// @EventListener(AnnouncementCloseEvent.class)
|
||||
// public void onAnnouncementCloseEvent(AnnouncementCloseEvent event) {
|
||||
// // 构建公告关闭的消息体
|
||||
// AnnouncementCloseMessage message = new AnnouncementCloseMessage();
|
||||
// message.setId(event.getId());
|
||||
// String msg = JsonUtils.toJson(message);
|
||||
//
|
||||
// // 广播公告关闭信息
|
||||
// MessageDO messageDO = new MessageDO().setMessageText(msg).setNeedBroadcast(true);
|
||||
// messageDistributor.distribute(messageDO);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 站内通知推送事件
|
||||
// * @param event the StationNotifyPushEvent
|
||||
// */
|
||||
// @Async
|
||||
// @EventListener(StationNotifyPushEvent.class)
|
||||
// public void onAnnouncementPublishEvent(StationNotifyPushEvent event) {
|
||||
// NotifyInfo notifyInfo = event.getNotifyInfo();
|
||||
// List<SysUser> userList = event.getUserList();
|
||||
// notifyInfoDelegateHandler.handle(userList, notifyInfo);
|
||||
// }
|
||||
//
|
||||
// }
|
@ -0,0 +1,34 @@
|
||||
package com.hccake.ballcat.admin.websocket.listener;
|
||||
|
||||
import com.hccake.ballcat.common.util.JsonUtils;
|
||||
import com.hccake.ballcat.common.websocket.distribute.MessageDO;
|
||||
import com.hccake.ballcat.common.websocket.distribute.MessageDistributor;
|
||||
import com.hccake.ballcat.system.event.DictChangeEvent;
|
||||
import com.hccake.ballcat.admin.websocket.message.DictChangeMessage;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SystemWebsocketEventListener {
|
||||
|
||||
private final MessageDistributor messageDistributor;
|
||||
|
||||
/**
|
||||
* 字典修改事件监听
|
||||
* @param event the `DictChangeEvent`
|
||||
*/
|
||||
@Async
|
||||
@EventListener(DictChangeEvent.class)
|
||||
public void onDictChangeEvent(DictChangeEvent event) {
|
||||
// 构建字典修改的消息体
|
||||
DictChangeMessage dictChangeMessage = new DictChangeMessage();
|
||||
dictChangeMessage.setDictCode(event.getDictCode());
|
||||
String msg = JsonUtils.toJson(dictChangeMessage);
|
||||
|
||||
// 广播修改信息
|
||||
MessageDO messageDO = new MessageDO().setMessageText(msg).setNeedBroadcast(true);
|
||||
messageDistributor.distribute(messageDO);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.hccake.ballcat.admin.websocket.message;
|
||||
|
||||
import com.hccake.ballcat.common.websocket.message.JsonWebSocketMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Hccake 2021/1/7
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AnnouncementCloseMessage extends JsonWebSocketMessage {
|
||||
|
||||
public AnnouncementCloseMessage() {
|
||||
super("announcement-close");
|
||||
}
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.hccake.ballcat.admin.websocket.message;
|
||||
|
||||
import com.hccake.ballcat.common.websocket.message.JsonWebSocketMessage;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 字典修改消息
|
||||
*
|
||||
* @author Hccake 2021/1/5
|
||||
* @version 1.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DictChangeMessage extends JsonWebSocketMessage {
|
||||
|
||||
public DictChangeMessage() {
|
||||
super("dict-change");
|
||||
}
|
||||
|
||||
/**
|
||||
* 改动的字典标识
|
||||
*/
|
||||
private String dictCode;
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
com.hccake.ballcat.admin.websocket.AdminWebSocketAutoConfiguration
|
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ad-distribute</artifactId>
|
||||
<groupId>com.baiye</groupId>
|
||||
<version>1.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ad-distribute-admin</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>admin-core</module>
|
||||
<module>admin-websocket</module>
|
||||
</modules>
|
||||
<!-- 不生成target文件 -->
|
||||
<build>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>clean</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ad-distribute-common</artifactId>
|
||||
<groupId>com.baiye</groupId>
|
||||
<version>1.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!--hutool-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-poi</artifactId>
|
||||
</dependency>
|
||||
<!--json模块-->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>common-model</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baiye</groupId>
|
||||
<artifactId>common-util</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>jakarta.el</artifactId>
|
||||
<version>3.0.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- slf4j日志 -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<!-- web相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,26 @@
|
||||
package com.hccake.ballcat.common.core.compose;
|
||||
|
||||
/**
|
||||
* 上下文组件, 在接入对应的上下文时(如: spring 的 bean) 便于在 开始和结束时执行对应的方法
|
||||
* <p>
|
||||
* 默认自动接入spring
|
||||
* </p>
|
||||
* <p>
|
||||
* 一般用于线程类实例达成接入到对应的上下文环境时自动开启和结束线程
|
||||
* </p>
|
||||
*
|
||||
* @author lingting 2022/10/15 17:55
|
||||
*/
|
||||
public interface ContextComponent {
|
||||
|
||||
/**
|
||||
* 上下文准备好之后调用, 内部做一些线程的初始化以及线程启动
|
||||
*/
|
||||
void onApplicationStart();
|
||||
|
||||
/**
|
||||
* 在上下文销毁前调用, 内部做线程停止和数据缓存相关
|
||||
*/
|
||||
void onApplicationStop();
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.hccake.ballcat.common.core.constant;
|
||||
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/10/31 11:55
|
||||
*/
|
||||
public final class HeaderConstants {
|
||||
|
||||
private HeaderConstants() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求时间戳
|
||||
*/
|
||||
public static final String REQ_TIME = "reqTime";
|
||||
|
||||
/**
|
||||
* 请求sign
|
||||
*/
|
||||
public static final String SIGN = "sign";
|
||||
|
||||
/**
|
||||
* SECRET_ID
|
||||
*/
|
||||
public static final String SECRET_ID = "secretId";
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.hccake.ballcat.common.core.constant.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Boolean 类型常量
|
||||
*
|
||||
* @author Hccake 2020/4/6 21:52
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum BooleanEnum {
|
||||
|
||||
/**
|
||||
* 是
|
||||
*/
|
||||
TRUE(true, 1),
|
||||
/**
|
||||
* 否
|
||||
*/
|
||||
FALSE(false, 0);
|
||||
|
||||
private final Boolean booleanValue;
|
||||
|
||||
private final Integer intValue;
|
||||
|
||||
public Boolean booleanValue() {
|
||||
return booleanValue;
|
||||
}
|
||||
|
||||
public Integer intValue() {
|
||||
return intValue;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.hccake.ballcat.common.core.constant.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 当数据以存在时的导入动作
|
||||
*
|
||||
* @author Hccake
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ImportModeEnum {
|
||||
|
||||
/**
|
||||
* 跳过已存在的数据
|
||||
*/
|
||||
SKIP_EXISTING,
|
||||
|
||||
/**
|
||||
* 覆盖已存在的数据
|
||||
*/
|
||||
OVERWRITE_EXISTING;
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.hccake.ballcat.common.core.exception;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import com.hccake.ballcat.common.model.result.ResultCode;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 通用业务异常
|
||||
*
|
||||
* @author Hccake
|
||||
*/
|
||||
@Getter
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
private final String message;
|
||||
|
||||
private final int code;
|
||||
|
||||
public BusinessException(ResultCode resultCode) {
|
||||
super(resultCode.getMessage());
|
||||
this.code = resultCode.getCode();
|
||||
this.message = resultCode.getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于需要format返回结果的异常
|
||||
*/
|
||||
public BusinessException(ResultCode resultCode, Object... args) {
|
||||
this(resultCode.getCode(), CharSequenceUtil.format(resultCode.getMessage(), args));
|
||||
}
|
||||
|
||||
public BusinessException(ResultCode resultCode, Throwable e) {
|
||||
super(resultCode.getMessage(), e);
|
||||
this.code = resultCode.getCode();
|
||||
this.message = resultCode.getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于需要format返回结果的异常
|
||||
*/
|
||||
public BusinessException(ResultCode resultCode, Throwable e, Object... args) {
|
||||
this(resultCode.getCode(), CharSequenceUtil.format(resultCode.getMessage(), args), e);
|
||||
}
|
||||
|
||||
public BusinessException(int code, String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BusinessException(int code, String message, Throwable e) {
|
||||
super(message, e);
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.hccake.ballcat.common.core.exception;
|
||||
|
||||
import com.hccake.ballcat.common.model.result.SystemResultCode;
|
||||
|
||||
/**
|
||||
* sql防注入校验异常
|
||||
*
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/10/19 16:52
|
||||
*/
|
||||
public class SqlCheckedException extends BusinessException {
|
||||
|
||||
public SqlCheckedException(SystemResultCode systemResultMsg) {
|
||||
super(systemResultMsg);
|
||||
}
|
||||
|
||||
public SqlCheckedException(SystemResultCode systemResultMsg, Throwable e) {
|
||||
super(systemResultMsg, e);
|
||||
}
|
||||
|
||||
public SqlCheckedException(int code, String msg) {
|
||||
super(code, msg);
|
||||
}
|
||||
|
||||
public SqlCheckedException(int code, String msg, Throwable e) {
|
||||
super(code, msg, e);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.hccake.ballcat.common.core.https;
|
||||
|
||||
import com.hccake.ballcat.common.core.constant.HttpsConstants;
|
||||
import com.hccake.ballcat.common.util.ArrayUtils;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* 用于兼容 android 使用
|
||||
*
|
||||
* @author lingting
|
||||
*/
|
||||
public class CompatibleSSLFactory extends SSLSocketFactory {
|
||||
|
||||
private final String[] protocols;
|
||||
|
||||
private final SSLSocketFactory factory;
|
||||
|
||||
public CompatibleSSLFactory(String... protocols) throws NoSuchAlgorithmException, KeyManagementException {
|
||||
this(HttpsConstants.TLS, HttpsConstants.KEY_MANAGERS, HttpsConstants.TRUST_MANAGERS, new SecureRandom(),
|
||||
protocols);
|
||||
}
|
||||
|
||||
public CompatibleSSLFactory(String protocol, KeyManager[] keyManagers, TrustManager[] trustManagers,
|
||||
SecureRandom secureRandom, String... protocols) throws NoSuchAlgorithmException, KeyManagementException {
|
||||
this.protocols = protocols;
|
||||
final SSLContext context = SSLContext.getInstance(protocol);
|
||||
context.init(keyManagers, trustManagers, secureRandom);
|
||||
this.factory = context.getSocketFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return factory.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return factory.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
return enabledProtocols(factory.createSocket());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket socket, InputStream inputStream, boolean b) throws IOException {
|
||||
return enabledProtocols(factory.createSocket(socket, inputStream, b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
|
||||
return enabledProtocols(factory.createSocket(socket, s, i, b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String s, int i) throws IOException {
|
||||
return enabledProtocols(factory.createSocket(s, i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException {
|
||||
return enabledProtocols(factory.createSocket(s, i, inetAddress, i1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
|
||||
return enabledProtocols(factory.createSocket(inetAddress, i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
|
||||
return enabledProtocols(factory.createSocket(inetAddress, i, inetAddress1, i1));
|
||||
}
|
||||
|
||||
private Socket enabledProtocols(Socket socket) {
|
||||
if (!ArrayUtils.isEmpty(protocols) && socket instanceof SSLSocket) {
|
||||
((SSLSocket) socket).setEnabledProtocols(protocols);
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.hccake.ballcat.common.core.https;
|
||||
|
||||
/**
|
||||
* @author lingting 2023/2/1 14:29
|
||||
*/
|
||||
public class SSLSocketFactoryInitException extends RuntimeException {
|
||||
|
||||
public SSLSocketFactoryInitException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.hccake.ballcat.common.core.jackson;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 自定义java8新增时间类型的序列化
|
||||
*
|
||||
* @see com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||
* @author Hccake
|
||||
*/
|
||||
public class CustomJavaTimeModule extends SimpleModule {
|
||||
|
||||
public CustomJavaTimeModule() {
|
||||
super(PackageVersion.VERSION);
|
||||
|
||||
this.addSerializer(LocalDateTime.class,
|
||||
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
|
||||
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
|
||||
this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
|
||||
this.addSerializer(Instant.class, InstantSerializer.INSTANCE);
|
||||
|
||||
this.addDeserializer(LocalDateTime.class,
|
||||
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
|
||||
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
|
||||
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
|
||||
this.addDeserializer(Instant.class, InstantDeserializer.INSTANT);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.hccake.ballcat.common.core.jackson;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* jackson NULL值序列化为 ""
|
||||
*
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/10/17 22:19
|
||||
*/
|
||||
public class NullStringJsonSerializer extends JsonSerializer<Object> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException {
|
||||
jsonGenerator.writeString("");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.hccake.ballcat.common.core.lock;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author lingting 2023-04-22 10:55
|
||||
*/
|
||||
@Getter
|
||||
public class JavaReentrantLock {
|
||||
|
||||
/**
|
||||
* 锁
|
||||
*/
|
||||
protected final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* 激活与休眠线程
|
||||
*/
|
||||
protected final Condition defaultCondition = lock.newCondition();
|
||||
|
||||
public Condition newCondition() {
|
||||
return getLock().newCondition();
|
||||
}
|
||||
|
||||
public void lock() {
|
||||
getLock().lock();
|
||||
}
|
||||
|
||||
public void lockInterruptibly() throws InterruptedException {
|
||||
getLock().lockInterruptibly();
|
||||
}
|
||||
|
||||
public void runLock(Runnable runnable) throws InterruptedException {
|
||||
ReentrantLock reentrantLock = getLock();
|
||||
reentrantLock.lock();
|
||||
try {
|
||||
runnable.run();
|
||||
}
|
||||
finally {
|
||||
reentrantLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void runLockInterruptibly(Runnable runnable) throws InterruptedException {
|
||||
ReentrantLock reentrantLock = getLock();
|
||||
reentrantLock.lockInterruptibly();
|
||||
try {
|
||||
runnable.run();
|
||||
}
|
||||
finally {
|
||||
reentrantLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void unlock() {
|
||||
getLock().unlock();
|
||||
}
|
||||
|
||||
public void signal() {
|
||||
getDefaultCondition().signal();
|
||||
}
|
||||
|
||||
public void signalAll() {
|
||||
getDefaultCondition().signalAll();
|
||||
}
|
||||
|
||||
public void await() throws InterruptedException {
|
||||
getDefaultCondition().await();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否被唤醒
|
||||
*/
|
||||
public boolean await(long time, TimeUnit timeUnit) throws InterruptedException {
|
||||
return getDefaultCondition().await(time, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author lingting 2023-04-22 11:35
|
||||
*/
|
||||
public interface Runnable {
|
||||
|
||||
void run() throws InterruptedException;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
package com.hccake.ballcat.common.core.markdown;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.hccake.ballcat.common.util.json.JacksonJsonToolAdapter;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 生成 markdown 文本
|
||||
*
|
||||
* @author lingting 2020/6/10 22:43
|
||||
*/
|
||||
public class MarkdownBuilder {
|
||||
|
||||
public static final String TITLE_PREFIX = "#";
|
||||
|
||||
public static final String QUOTE_PREFIX = "> ";
|
||||
|
||||
public static final String CODE_PREFIX = "``` ";
|
||||
|
||||
public static final String CODE_SUFFIX = "```";
|
||||
|
||||
public static final String BOLD_PREFIX = "**";
|
||||
|
||||
public static final String ITALIC_PREFIX = "*";
|
||||
|
||||
public static final String UNORDERED_LIST_PREFIX = "- ";
|
||||
|
||||
public static final String ORDER_LIST_PREFIX = ". ";
|
||||
|
||||
/**
|
||||
* 存放内容
|
||||
*/
|
||||
private final List<String> content = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 当前操作行文本
|
||||
*/
|
||||
private StringBuilder lineTextBuilder;
|
||||
|
||||
public MarkdownBuilder() {
|
||||
this.lineTextBuilder = new StringBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加自定义内容
|
||||
* @param content 自定义内容
|
||||
*/
|
||||
public MarkdownBuilder append(Object content) {
|
||||
lineTextBuilder.append(toString(content));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 有序列表 自动生成 索引
|
||||
* @param content 文本
|
||||
*/
|
||||
public MarkdownBuilder orderList(Object content) {
|
||||
// 获取最后一个字符串
|
||||
String tmp = "";
|
||||
if (!this.content.isEmpty()) {
|
||||
tmp = this.content.get(this.content.size() - 1);
|
||||
}
|
||||
// 索引
|
||||
int index = 1;
|
||||
|
||||
// 校验 是否 为有序列表行的正则
|
||||
String isOrderListPattern = "^\\d\\. .*";
|
||||
if (Pattern.matches(isOrderListPattern, tmp)) {
|
||||
// 如果是数字开头
|
||||
index = Convert.toInt(tmp.substring(0, tmp.indexOf(ORDER_LIST_PREFIX) - 1));
|
||||
}
|
||||
return orderList(index, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 有序列表
|
||||
* @param index 索引
|
||||
* @param content 文本
|
||||
*/
|
||||
public MarkdownBuilder orderList(int index, Object content) {
|
||||
lineBreak();
|
||||
lineTextBuilder.append(index).append(ORDER_LIST_PREFIX).append(toString(content));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无序列表 - item1 - item2
|
||||
*/
|
||||
public MarkdownBuilder unorderedList(Object content) {
|
||||
// 换行
|
||||
lineBreak();
|
||||
lineTextBuilder.append(UNORDERED_LIST_PREFIX).append(toString(content));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片
|
||||
* @param url 图片链接
|
||||
*/
|
||||
public MarkdownBuilder pic(String url) {
|
||||
return pic("", url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片
|
||||
* @param title 图片标题
|
||||
* @param url 图片路径
|
||||
*/
|
||||
public MarkdownBuilder pic(Object title, String url) {
|
||||
lineTextBuilder.append("![").append(title).append("](").append(url).append(")");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 链接
|
||||
* @param title 标题
|
||||
* @param url http 路径
|
||||
*/
|
||||
public MarkdownBuilder link(Object title, String url) {
|
||||
lineTextBuilder.append("[").append(title).append("](").append(url).append(")");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 斜体
|
||||
*/
|
||||
public MarkdownBuilder italic(Object content) {
|
||||
lineTextBuilder.append(ITALIC_PREFIX).append(toString(content)).append(ITALIC_PREFIX);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加粗
|
||||
*/
|
||||
public MarkdownBuilder bold(Object content) {
|
||||
lineTextBuilder.append(BOLD_PREFIX).append(toString(content)).append(BOLD_PREFIX);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 引用 > 文本
|
||||
* @param content 文本
|
||||
*/
|
||||
public MarkdownBuilder quote(Object... content) {
|
||||
lineBreak();
|
||||
lineTextBuilder.append(QUOTE_PREFIX);
|
||||
for (Object o : content) {
|
||||
lineTextBuilder.append(toString(o));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加引用后, 换行, 写入下一行引用
|
||||
*/
|
||||
public MarkdownBuilder quoteBreak(Object... content) {
|
||||
// 当前行引用内容
|
||||
quote(content);
|
||||
// 空引用行
|
||||
return quote();
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码
|
||||
*/
|
||||
public MarkdownBuilder code(String type, Object... code) {
|
||||
lineBreak();
|
||||
lineTextBuilder.append(CODE_PREFIX).append(type);
|
||||
lineBreak();
|
||||
for (Object o : code) {
|
||||
lineTextBuilder.append(toString(o));
|
||||
}
|
||||
lineBreak();
|
||||
lineTextBuilder.append(CODE_SUFFIX);
|
||||
return lineBreak();
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码
|
||||
*/
|
||||
public MarkdownBuilder json(Object obj) {
|
||||
String json;
|
||||
if (obj instanceof String) {
|
||||
json = (String) obj;
|
||||
}
|
||||
else {
|
||||
json = multiJson(obj);
|
||||
}
|
||||
return code("json", json);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private String multiJson(Object obj) {
|
||||
ObjectMapper mapper = JacksonJsonToolAdapter.getMapper().copy().enable(SerializationFeature.INDENT_OUTPUT);
|
||||
return mapper.writeValueAsString(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制换行
|
||||
*/
|
||||
public MarkdownBuilder forceLineBreak() {
|
||||
content.add(lineTextBuilder.toString());
|
||||
lineTextBuilder = new StringBuilder();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 换行 当已编辑文本长度不为0时换行
|
||||
*/
|
||||
public MarkdownBuilder lineBreak() {
|
||||
if (lineTextBuilder.length() != 0) {
|
||||
return forceLineBreak();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 i 级标题
|
||||
*
|
||||
* @author lingting 2020-06-10 22:55:39
|
||||
*/
|
||||
private MarkdownBuilder title(int i, Object content) {
|
||||
// 如果当前操作行已有字符,需要换行
|
||||
lineBreak();
|
||||
for (int j = 0; j < i; j++) {
|
||||
lineTextBuilder.append(TITLE_PREFIX);
|
||||
}
|
||||
this.content.add(lineTextBuilder.append(" ").append(toString(content)).toString());
|
||||
lineTextBuilder = new StringBuilder();
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder title1(Object text) {
|
||||
return title(1, text);
|
||||
}
|
||||
|
||||
public MarkdownBuilder title2(Object text) {
|
||||
return title(2, text);
|
||||
}
|
||||
|
||||
public MarkdownBuilder title3(Object text) {
|
||||
return title(3, text);
|
||||
}
|
||||
|
||||
public MarkdownBuilder title4(Object text) {
|
||||
return title(4, text);
|
||||
}
|
||||
|
||||
public MarkdownBuilder title5(Object text) {
|
||||
return title(5, text);
|
||||
}
|
||||
|
||||
String toString(Object o) {
|
||||
if (o == null) {
|
||||
return "";
|
||||
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构筑 Markdown 文本
|
||||
*/
|
||||
public String build() {
|
||||
lineBreak();
|
||||
StringBuilder res = new StringBuilder();
|
||||
content.forEach(line -> res.append(line).append(" \n"));
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.hccake.ballcat.common.core.request.wrapper;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 修改parameterMap
|
||||
*
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/10/17 21:57
|
||||
*/
|
||||
public class ModifyParamMapRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private final Map<String, String[]> parameterMap;
|
||||
|
||||
public ModifyParamMapRequestWrapper(HttpServletRequest request, Map<String, String[]> parameterMap) {
|
||||
super(request);
|
||||
this.parameterMap = parameterMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String[]> getParameterMap() {
|
||||
return this.parameterMap;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.hccake.ballcat.common.core.spring;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* @author lingting 2022/10/22 15:11
|
||||
*/
|
||||
public interface BallcatBeanPostProcessor extends BeanPostProcessor, Ordered {
|
||||
|
||||
/**
|
||||
* 判断是否处理该bean
|
||||
* @param bean bean实例
|
||||
* @param beanName bean名称
|
||||
* @param isBefore true表示当前为初始化之前是否处理判断, false 表示当前为初始化之后是否处理判断
|
||||
* @return boolean true 表示要处理该bean
|
||||
*/
|
||||
boolean isProcess(Object bean, String beanName, boolean isBefore);
|
||||
|
||||
/**
|
||||
* 初始化之前处理
|
||||
* @param bean bean
|
||||
* @param beanName bean名称
|
||||
* @return java.lang.Object
|
||||
*/
|
||||
default Object postProcessBefore(Object bean, String beanName) {
|
||||
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化之后处理
|
||||
* @param bean bean
|
||||
* @param beanName bean名称
|
||||
* @return java.lang.Object
|
||||
*/
|
||||
default Object postProcessAfter(Object bean, String beanName) {
|
||||
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getOrder() {
|
||||
// 默认优先级
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (isProcess(bean, beanName, true)) {
|
||||
return postProcessBefore(bean, beanName);
|
||||
}
|
||||
|
||||
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (isProcess(bean, beanName, false)) {
|
||||
return postProcessAfter(bean, beanName);
|
||||
}
|
||||
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.hccake.ballcat.common.core.spring.compose;
|
||||
|
||||
import com.hccake.ballcat.common.core.compose.ContextComponent;
|
||||
import com.hccake.ballcat.common.core.spring.BallcatBeanPostProcessor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author lingting 2022/10/22 15:10
|
||||
*/
|
||||
@Component
|
||||
public class ContextComposeBeanPostProcessor implements BallcatBeanPostProcessor {
|
||||
|
||||
@Override
|
||||
public boolean isProcess(Object bean, String beanName, boolean isBefore) {
|
||||
return bean != null && ContextComponent.class.isAssignableFrom(bean.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfter(Object bean, String beanName) {
|
||||
((ContextComponent) bean).onApplicationStart();
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.hccake.ballcat.common.core.spring.compose;
|
||||
|
||||
import com.hccake.ballcat.common.core.compose.ContextComponent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author lingting 2022/10/22 17:45
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SpringContextClosed implements ApplicationListener<ContextClosedEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
log.debug("spring context closed");
|
||||
ApplicationContext applicationContext = event.getApplicationContext();
|
||||
|
||||
// 上下文容器停止
|
||||
contextComponentStop(applicationContext);
|
||||
}
|
||||
|
||||
private static void contextComponentStop(ApplicationContext applicationContext) {
|
||||
Map<String, ContextComponent> contextComponentMap = applicationContext.getBeansOfType(ContextComponent.class);
|
||||
|
||||
for (Map.Entry<String, ContextComponent> entry : contextComponentMap.entrySet()) {
|
||||
entry.getValue().onApplicationStop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.hccake.ballcat.common.core.thread;
|
||||
|
||||
import com.hccake.ballcat.common.core.lock.JavaReentrantLock;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author lingting 2023-04-22 10:39
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings("java:S1066")
|
||||
public abstract class AbstractDynamicTimer<T> extends AbstractThreadContextComponent {
|
||||
|
||||
private final JavaReentrantLock lock = new JavaReentrantLock();
|
||||
|
||||
protected final PriorityBlockingQueue<T> queue = new PriorityBlockingQueue<>(defaultCapacity(), comparator());
|
||||
|
||||
public abstract Comparator<T> comparator();
|
||||
|
||||
/**
|
||||
* 默认大小
|
||||
*/
|
||||
protected int defaultCapacity() {
|
||||
return 11;
|
||||
}
|
||||
|
||||
/**
|
||||
* 还有多久要处理该对象
|
||||
* @param t 对象
|
||||
* @return 具体处理该对象还要多久, 单位: 毫秒
|
||||
*/
|
||||
protected abstract long sleepTime(T t);
|
||||
|
||||
public void put(T t) {
|
||||
if (t == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
lock.runLockInterruptibly(() -> {
|
||||
queue.add(t);
|
||||
lock.signalAll();
|
||||
});
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
interrupt();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("{} put error, param: {}", this.getClass().toString(), t, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
init();
|
||||
while (isRun()) {
|
||||
try {
|
||||
T t = pool();
|
||||
lock.runLockInterruptibly(() -> {
|
||||
if (t == null) {
|
||||
lock.await(24, TimeUnit.HOURS);
|
||||
return;
|
||||
}
|
||||
|
||||
long sleepTime = sleepTime(t);
|
||||
// 需要休眠
|
||||
if (sleepTime > 0) {
|
||||
// 如果是被唤醒
|
||||
if (lock.await(sleepTime, TimeUnit.MILLISECONDS)) {
|
||||
put(t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
process(t);
|
||||
});
|
||||
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
interrupt();
|
||||
shutdown();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("类: {}; 线程: {}; 运行异常! ", getSimpleName(), getId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected T pool() {
|
||||
return queue.poll();
|
||||
}
|
||||
|
||||
protected abstract void process(T t);
|
||||
|
||||
protected void shutdown() {
|
||||
log.warn("类: {}; 线程: {}; 被中断! 剩余数据: {}", getSimpleName(), getId(), queue.size());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.hccake.ballcat.common.core.thread;
|
||||
|
||||
import com.hccake.ballcat.common.core.compose.ContextComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author lingting 2023-04-22 10:40
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class AbstractThreadContextComponent extends Thread implements ContextComponent {
|
||||
|
||||
protected void init() {
|
||||
|
||||
}
|
||||
|
||||
public boolean isRun() {
|
||||
return !isInterrupted() && isAlive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationStart() {
|
||||
setName(getClass().getSimpleName());
|
||||
if (!isAlive()) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationStop() {
|
||||
log.warn("{} 线程: {}; 开始关闭!", getClass().getSimpleName(), getId());
|
||||
interrupt();
|
||||
}
|
||||
|
||||
public String getSimpleName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void run();
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package com.hccake.ballcat.common.core.thread;
|
||||
|
||||
import com.hccake.ballcat.common.core.compose.ContextComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author lingting 2022/6/27 20:26
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class AbstractTimer extends Thread implements ContextComponent {
|
||||
|
||||
/**
|
||||
* 获取超时时间, 单位: 毫秒
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return TimeUnit.SECONDS.toMillis(30);
|
||||
}
|
||||
|
||||
public boolean isRun() {
|
||||
return !isInterrupted();
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行前执行初始化
|
||||
*/
|
||||
protected void init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
*/
|
||||
protected abstract void process();
|
||||
|
||||
/**
|
||||
* 线程被中断触发.
|
||||
*/
|
||||
protected void shutdown() {
|
||||
}
|
||||
|
||||
protected void error(Exception e) {
|
||||
log.error("{} 类 线程: {} 出现异常!", getClass().getSimpleName(), getId(), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
init();
|
||||
while (isRun()) {
|
||||
try {
|
||||
process();
|
||||
|
||||
// 已经停止运行, 结束
|
||||
if (!isRun()) {
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.sleep(getTimeout());
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
interrupt();
|
||||
shutdown();
|
||||
}
|
||||
catch (Exception e) {
|
||||
error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationStart() {
|
||||
setName(getClass().getSimpleName());
|
||||
if (!isAlive()) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationStop() {
|
||||
log.warn("{} 线程: {}; 开始关闭!", getClass().getSimpleName(), getId());
|
||||
interrupt();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.hccake.ballcat.common.core.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* WebUtils
|
||||
*
|
||||
* @author Hccake
|
||||
*/
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class WebUtils extends org.springframework.web.util.WebUtils {
|
||||
|
||||
/**
|
||||
* 获取 ServletRequestAttributes
|
||||
* @return {ServletRequestAttributes}
|
||||
*/
|
||||
public ServletRequestAttributes getServletRequestAttributes() {
|
||||
return (ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 HttpServletRequest
|
||||
* @return {HttpServletRequest}
|
||||
*/
|
||||
public HttpServletRequest getRequest() {
|
||||
return getServletRequestAttributes().getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 HttpServletResponse
|
||||
* @return {HttpServletResponse}
|
||||
*/
|
||||
public HttpServletResponse getResponse() {
|
||||
return getServletRequestAttributes().getResponse();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.hccake.ballcat.common.core.validation;
|
||||
|
||||
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
|
||||
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 将消息中空的花括号替换为校验注解的默认值
|
||||
* <p>
|
||||
* 扩展自原有的 {@link ResourceBundleMessageInterpolator} 消息处理器
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
public class EmptyCurlyToDefaultMessageInterpolator extends ResourceBundleMessageInterpolator {
|
||||
|
||||
private static final String EMPTY_CURLY_BRACES = "{}";
|
||||
|
||||
public EmptyCurlyToDefaultMessageInterpolator() {
|
||||
}
|
||||
|
||||
public EmptyCurlyToDefaultMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {
|
||||
super(userResourceBundleLocator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String interpolate(String message, Context context, Locale locale) {
|
||||
|
||||
// 如果包含花括号占位符
|
||||
if (message.contains(EMPTY_CURLY_BRACES)) {
|
||||
// 获取注解类型
|
||||
Class<? extends Annotation> annotationType = context.getConstraintDescriptor()
|
||||
.getAnnotation()
|
||||
.annotationType();
|
||||
|
||||
Method messageMethod;
|
||||
try {
|
||||
messageMethod = annotationType.getDeclaredMethod("message");
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
return super.interpolate(message, context, locale);
|
||||
}
|
||||
|
||||
// 找到对应 message 的默认值,将 {} 替换为默认值
|
||||
if (messageMethod.getDefaultValue() != null) {
|
||||
Object defaultValue = messageMethod.getDefaultValue();
|
||||
if (defaultValue instanceof String) {
|
||||
String defaultMessage = (String) defaultValue;
|
||||
message = message.replace(EMPTY_CURLY_BRACES, defaultMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.interpolate(message, context, locale);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.hccake.ballcat.common.core.validation.constraints;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.validator.EnumValueValidatorOfClass;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* @author housl
|
||||
* @version 1.0
|
||||
*/
|
||||
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(OneOfClasses.List.class)
|
||||
@Documented
|
||||
@Constraint(validatedBy = { EnumValueValidatorOfClass.class })
|
||||
public @interface OneOfClasses {
|
||||
|
||||
String message() default "value must match one of the values in the list: {value}";
|
||||
|
||||
Class<?>[] value();
|
||||
|
||||
/**
|
||||
* 允许值为 null, 默认不允许
|
||||
*/
|
||||
boolean allowNull() default false;
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@interface List {
|
||||
|
||||
OneOfClasses[] value();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.hccake.ballcat.common.core.validation.constraints;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.validator.EnumValueValidatorOfInt;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* @author housl
|
||||
* @version 1.0
|
||||
*/
|
||||
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(OneOfInts.List.class)
|
||||
@Documented
|
||||
@Constraint(validatedBy = { EnumValueValidatorOfInt.class })
|
||||
public @interface OneOfInts {
|
||||
|
||||
String message() default "value must match one of the values in the list: {value}";
|
||||
|
||||
int[] value();
|
||||
|
||||
/**
|
||||
* 允许值为 null, 默认不允许
|
||||
*/
|
||||
boolean allowNull() default false;
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@interface List {
|
||||
|
||||
OneOfInts[] value();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.hccake.ballcat.common.core.validation.constraints;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.validator.EnumValueValidatorOfString;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* @author housl
|
||||
* @version 1.0
|
||||
*/
|
||||
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(OneOfStrings.List.class)
|
||||
@Documented
|
||||
@Constraint(validatedBy = { EnumValueValidatorOfString.class })
|
||||
public @interface OneOfStrings {
|
||||
|
||||
String message() default "value must match one of the values in the list: {value}";
|
||||
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* 允许值为 null, 默认不允许
|
||||
*/
|
||||
boolean allowNull() default false;
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@interface List {
|
||||
|
||||
OneOfStrings[] value();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.hccake.ballcat.common.core.validation.constraints;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.validator.ValueOfEnumValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* @author housl
|
||||
* @version 1.0
|
||||
*/
|
||||
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(ValueOfEnum.List.class)
|
||||
@Documented
|
||||
@Constraint(validatedBy = { ValueOfEnumValidator.class })
|
||||
public @interface ValueOfEnum {
|
||||
|
||||
String message() default "value is not in enum {enumClass}";
|
||||
|
||||
Class<?>[] enumClass();
|
||||
|
||||
String method() default "valueOf";
|
||||
|
||||
/**
|
||||
* 允许值为 null, 默认不允许
|
||||
*/
|
||||
boolean allowNull() default false;
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@interface List {
|
||||
|
||||
ValueOfEnum[] value();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.hccake.ballcat.common.core.validation.validator;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.constraints.OneOfClasses;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* @author hccake
|
||||
* @version 1.0 枚举值 Validator
|
||||
*/
|
||||
public class EnumValueValidatorOfClass implements ConstraintValidator<OneOfClasses, Class<?>> {
|
||||
|
||||
private Class<?>[] classList;
|
||||
|
||||
private boolean allowNull;
|
||||
|
||||
@Override
|
||||
public void initialize(OneOfClasses constraintAnnotation) {
|
||||
classList = constraintAnnotation.value();
|
||||
allowNull = constraintAnnotation.allowNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Class value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return allowNull;
|
||||
}
|
||||
for (Class<?> clazz : classList) {
|
||||
if (clazz.isAssignableFrom(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.hccake.ballcat.common.core.validation.validator;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.constraints.OneOfInts;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* @author housl
|
||||
* @version 1.0 枚举值 Validator
|
||||
*/
|
||||
public class EnumValueValidatorOfInt implements ConstraintValidator<OneOfInts, Integer> {
|
||||
|
||||
private int[] ints;
|
||||
|
||||
private boolean allowNull;
|
||||
|
||||
@Override
|
||||
public void initialize(OneOfInts constraintAnnotation) {
|
||||
ints = constraintAnnotation.value();
|
||||
allowNull = constraintAnnotation.allowNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Integer value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return allowNull;
|
||||
}
|
||||
for (int anInt : ints) {
|
||||
if (anInt == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.hccake.ballcat.common.core.validation.validator;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.constraints.OneOfStrings;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* @author housl
|
||||
* @version 1.0 枚举值 Validator
|
||||
*/
|
||||
public class EnumValueValidatorOfString implements ConstraintValidator<OneOfStrings, String> {
|
||||
|
||||
private String[] stringList;
|
||||
|
||||
private boolean allowNull;
|
||||
|
||||
@Override
|
||||
public void initialize(OneOfStrings constraintAnnotation) {
|
||||
stringList = constraintAnnotation.value();
|
||||
allowNull = constraintAnnotation.allowNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return allowNull;
|
||||
}
|
||||
for (String strValue : stringList) {
|
||||
if (strValue.equals(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.hccake.ballcat.common.core.validation.validator;
|
||||
|
||||
import com.hccake.ballcat.common.core.validation.constraints.ValueOfEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
|
||||
import javax.validation.ConstraintDefinitionException;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* @author housl
|
||||
* @version 1.0 枚举类 Validator
|
||||
*/
|
||||
@Slf4j
|
||||
public class ValueOfEnumValidator implements ConstraintValidator<ValueOfEnum, Object> {
|
||||
|
||||
private Class<?>[] targetEnum;
|
||||
|
||||
private String checkMethod;
|
||||
|
||||
private boolean allowNull;
|
||||
|
||||
@Override
|
||||
public void initialize(ValueOfEnum constraintAnnotation) {
|
||||
targetEnum = constraintAnnotation.enumClass();
|
||||
checkMethod = constraintAnnotation.method();
|
||||
allowNull = constraintAnnotation.allowNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return allowNull;
|
||||
}
|
||||
for (Class<?> eClass : targetEnum) {
|
||||
// 包装类和原始类型的处理
|
||||
Class<?> clazz = ClassUtils.isPrimitiveWrapper(value.getClass())
|
||||
? ClassUtils.wrapperToPrimitive(value.getClass()) : value.getClass();
|
||||
|
||||
try {
|
||||
Object enumInstance = MethodUtils.invokeStaticMethod(eClass, checkMethod, new Object[] { value },
|
||||
new Class[] { clazz });
|
||||
return enumInstance != null;
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new ConstraintDefinitionException(ex);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
log.warn("check enum error: ", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ad-distribute-common</artifactId>
|
||||
<groupId>com.baiye</groupId>
|
||||
<version>1.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-desensitize</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,100 @@
|
||||
package com.hccake.ballcat.common.desensitize;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.hccake.ballcat.common.desensitize.enums.RegexDesensitizationTypeEnum;
|
||||
import com.hccake.ballcat.common.desensitize.enums.SlideDesensitizationTypeEnum;
|
||||
import com.hccake.ballcat.common.desensitize.functions.DesensitizeFunction;
|
||||
import com.hccake.ballcat.common.desensitize.handler.RegexDesensitizationHandler;
|
||||
import com.hccake.ballcat.common.desensitize.handler.SimpleDesensitizationHandler;
|
||||
import com.hccake.ballcat.common.desensitize.handler.SlideDesensitizationHandler;
|
||||
import com.hccake.ballcat.common.desensitize.json.annotation.JsonRegexDesensitize;
|
||||
import com.hccake.ballcat.common.desensitize.json.annotation.JsonSimpleDesensitize;
|
||||
import com.hccake.ballcat.common.desensitize.json.annotation.JsonSlideDesensitize;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 注解处理方法 脱敏注解->处理逻辑
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public final class AnnotationHandlerHolder {
|
||||
|
||||
private static final AnnotationHandlerHolder INSTANCE = new AnnotationHandlerHolder();
|
||||
|
||||
/**
|
||||
* 注解类型 处理函数映射
|
||||
*/
|
||||
private final Map<Class<? extends Annotation>, DesensitizeFunction> annotationHandlers;
|
||||
|
||||
private AnnotationHandlerHolder() {
|
||||
annotationHandlers = new ConcurrentHashMap<>();
|
||||
|
||||
annotationHandlers.put(JsonSimpleDesensitize.class, (annotation, value) -> {
|
||||
// Simple 类型处理
|
||||
JsonSimpleDesensitize an = (JsonSimpleDesensitize) annotation;
|
||||
Class<? extends SimpleDesensitizationHandler> handlerClass = an.handler();
|
||||
SimpleDesensitizationHandler desensitizationHandler = DesensitizationHandlerHolder
|
||||
.getSimpleHandler(handlerClass);
|
||||
Assert.notNull(desensitizationHandler, "SimpleDesensitizationHandler can not be Null");
|
||||
return desensitizationHandler.handle(value);
|
||||
});
|
||||
|
||||
annotationHandlers.put(JsonRegexDesensitize.class, (annotation, value) -> {
|
||||
// 正则类型脱敏处理
|
||||
JsonRegexDesensitize an = (JsonRegexDesensitize) annotation;
|
||||
RegexDesensitizationTypeEnum type = an.type();
|
||||
RegexDesensitizationHandler regexDesensitizationHandler = DesensitizationHandlerHolder
|
||||
.getRegexDesensitizationHandler();
|
||||
return RegexDesensitizationTypeEnum.CUSTOM.equals(type)
|
||||
? regexDesensitizationHandler.handle(value, an.regex(), an.replacement())
|
||||
: regexDesensitizationHandler.handle(value, type);
|
||||
});
|
||||
|
||||
annotationHandlers.put(JsonSlideDesensitize.class, (annotation, value) -> {
|
||||
// 滑动类型脱敏处理
|
||||
JsonSlideDesensitize an = (JsonSlideDesensitize) annotation;
|
||||
SlideDesensitizationTypeEnum type = an.type();
|
||||
SlideDesensitizationHandler slideDesensitizationHandler = DesensitizationHandlerHolder
|
||||
.getSlideDesensitizationHandler();
|
||||
return SlideDesensitizationTypeEnum.CUSTOM.equals(type) ? slideDesensitizationHandler.handle(value,
|
||||
an.leftPlainTextLen(), an.rightPlainTextLen(), an.maskString())
|
||||
: slideDesensitizationHandler.handle(value, type);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到注解类型处理函数
|
||||
* @param annotationType {@code annotationType} 注解类型
|
||||
* @return {@link DesensitizeFunction}脱敏处理函数|null
|
||||
*/
|
||||
public static DesensitizeFunction getHandleFunction(Class<? extends Annotation> annotationType) {
|
||||
return INSTANCE.annotationHandlers.get(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加注解处理函数
|
||||
* @param annotationType {@code annotationType}指定注解类型
|
||||
* @param desensitizeFunction {@link DesensitizeFunction}指定脱敏处理函数
|
||||
* @return 上一个key 对应的脱敏处理函数 | null
|
||||
*/
|
||||
public static DesensitizeFunction addHandleFunction(Class<? extends Annotation> annotationType,
|
||||
DesensitizeFunction desensitizeFunction) {
|
||||
Assert.notNull(annotationType, "annotation cannot be null");
|
||||
Assert.notNull(desensitizeFunction, "desensitization function cannot be null");
|
||||
// 加入注解处理映射
|
||||
return INSTANCE.annotationHandlers.put(annotationType, desensitizeFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前支持的注解处理类
|
||||
* @return {@code 注解处理类列表}
|
||||
*/
|
||||
public static Set<Class<? extends Annotation>> getAnnotationClasses() {
|
||||
return INSTANCE.annotationHandlers.keySet();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.hccake.ballcat.common.desensitize.functions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* 脱敏函数
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DesensitizeFunction {
|
||||
|
||||
/**
|
||||
* 脱敏函数
|
||||
* @param annotation 当前脱敏注解
|
||||
* @param value 原始值
|
||||
* @return 脱敏处理后的值
|
||||
*/
|
||||
String desensitize(Annotation annotation, String value);
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.hccake.ballcat.common.desensitize.handler;
|
||||
|
||||
/**
|
||||
* 脱敏处理器
|
||||
*
|
||||
* @author Hccake 2021/1/22
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface DesensitizationHandler {
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hccake.ballcat.common.desensitize.json;
|
||||
|
||||
/**
|
||||
* 脱敏工具类 定义开启脱敏规则
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public interface DesensitizeStrategy {
|
||||
|
||||
/**
|
||||
* 判断是否忽略字段
|
||||
* @param fieldName {@code 当前字段名称}
|
||||
* @return @{code true 忽略 |false 不忽略}
|
||||
*/
|
||||
boolean ignoreField(String fieldName);
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.hccake.ballcat.common.desensitize.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
||||
/**
|
||||
* Json 脱敏模块
|
||||
*
|
||||
* @author hccake
|
||||
*/
|
||||
public class JsonDesensitizeModule extends SimpleModule {
|
||||
|
||||
public JsonDesensitizeModule(JsonDesensitizeSerializerModifier jsonDesensitizeSerializerModifier) {
|
||||
super();
|
||||
this.setSerializerModifier(jsonDesensitizeSerializerModifier);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.hccake.ballcat.common.desensitize.json;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.hccake.ballcat.common.desensitize.AnnotationHandlerHolder;
|
||||
import com.hccake.ballcat.common.desensitize.functions.DesensitizeFunction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* Jackson脱敏处理序列化器
|
||||
*
|
||||
* @author Hccake 2021/1/22
|
||||
* @version 1.0
|
||||
*/
|
||||
public class JsonDesensitizeSerializer extends JsonSerializer<Object> {
|
||||
|
||||
/**
|
||||
* json 脱敏处理注解
|
||||
*/
|
||||
private final Annotation jsonDesensitizeAnnotation;
|
||||
|
||||
/**
|
||||
* 脱敏注解条件工具类
|
||||
*/
|
||||
private final DesensitizeStrategy desensitizeStrategy;
|
||||
|
||||
public JsonDesensitizeSerializer(Annotation jsonDesensitizeAnnotation, DesensitizeStrategy desensitizeStrategy) {
|
||||
this.jsonDesensitizeAnnotation = jsonDesensitizeAnnotation;
|
||||
this.desensitizeStrategy = desensitizeStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializers)
|
||||
throws IOException {
|
||||
if (value instanceof String) {
|
||||
String str = (String) value;
|
||||
|
||||
String fieldName = jsonGenerator.getOutputContext().getCurrentName();
|
||||
// 未开启脱敏
|
||||
if (desensitizeStrategy != null && desensitizeStrategy.ignoreField(fieldName)) {
|
||||
jsonGenerator.writeString(str);
|
||||
return;
|
||||
}
|
||||
DesensitizeFunction handleFunction = AnnotationHandlerHolder
|
||||
.getHandleFunction(jsonDesensitizeAnnotation.annotationType());
|
||||
if (handleFunction == null) {
|
||||
jsonGenerator.writeString(str);
|
||||
return;
|
||||
}
|
||||
jsonGenerator.writeString(handleFunction.desensitize(jsonDesensitizeAnnotation, str));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.hccake.ballcat.common.desensitize.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.SerializationConfig;
|
||||
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
|
||||
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
|
||||
import com.hccake.ballcat.common.desensitize.AnnotationHandlerHolder;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* json serial modifier
|
||||
*
|
||||
* @author Yakir
|
||||
*/
|
||||
public class JsonDesensitizeSerializerModifier extends BeanSerializerModifier {
|
||||
|
||||
private DesensitizeStrategy desensitizeStrategy;
|
||||
|
||||
public JsonDesensitizeSerializerModifier() {
|
||||
}
|
||||
|
||||
public JsonDesensitizeSerializerModifier(DesensitizeStrategy desensitizeStrategy) {
|
||||
this.desensitizeStrategy = desensitizeStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
|
||||
List<BeanPropertyWriter> beanProperties) {
|
||||
for (BeanPropertyWriter beanProperty : beanProperties) {
|
||||
Annotation annotation = getDesensitizeAnnotation(beanProperty);
|
||||
|
||||
if (annotation != null && beanProperty.getType().isTypeOrSubTypeOf(String.class)) {
|
||||
beanProperty.assignSerializer(new JsonDesensitizeSerializer(annotation, desensitizeStrategy));
|
||||
}
|
||||
}
|
||||
return beanProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到脱敏注解
|
||||
* @param beanProperty BeanPropertyWriter
|
||||
* @return 返回第一个获取的脱敏注解
|
||||
*/
|
||||
private Annotation getDesensitizeAnnotation(BeanPropertyWriter beanProperty) {
|
||||
for (Class<? extends Annotation> annotationClass : AnnotationHandlerHolder.getAnnotationClasses()) {
|
||||
Annotation annotation = beanProperty.getAnnotation(annotationClass);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
com.hccake.ballcat.common.desensitize.handler.SixAsteriskDesensitizationHandler
|
@ -0,0 +1 @@
|
||||
com.hccake.common.core.test.desensite.TestDesensitizationHandler
|
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ad-distribute-common</artifactId>
|
||||
<groupId>com.baiye</groupId>
|
||||
<version>1.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>common-i18n</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
<!-- slf4j日志 -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue