Commit c2be2a42 authored by 向怀芳's avatar 向怀芳 🎱

初始化项目

parent e8e6917a
Pipeline #233 canceled with stages
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>cloud-auth</artifactId>
<packaging>jar</packaging>
<name>cloud-auth</name>
<description>认证授权中心,基于 spring security oAuth2</description>
<dependencies>
<!--upms api、model 模块-->
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-upms-api</artifactId>
</dependency>
<!--缓存操作-->
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-data</artifactId>
</dependency>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--JDBC相关-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--freemarker-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--spring security 、oauth、jwt依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<!--web 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除tomcat依赖-->
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-log</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.sh.stc.sict.cloud.auth;
import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
/**
* @author F_xh
*/
@SpringCloudApplication
@EnableSictFeignClients
public class SictAuthApplication {
public static void main(String[] args) {
SpringApplication.run(SictAuthApplication.class, args);
}
}
package cn.sh.stc.sict.cloud.auth.config;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.data.cache.MyRedisTokenStore;
import cn.sh.stc.sict.cloud.common.security.component.SictWebResponseExceptionTranslator;
import cn.sh.stc.sict.cloud.common.security.service.SictClientDetailsService;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @Description 认证服务器配置
* @Author
* @Date
*/
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final DataSource dataSource;
private final SictUserDetailsService sictUserDetailsService;
private final AuthenticationManager authenticationManagerBean;
private final RedisConnectionFactory redisConnectionFactory;
@Override
@SneakyThrows
public void configure(ClientDetailsServiceConfigurer clients) {
SictClientDetailsService clientDetailsService = new SictClientDetailsService(dataSource);
clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.allowFormAuthenticationForClients()
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancer())
.userDetailsService(sictUserDetailsService)
.authenticationManager(authenticationManagerBean)
.reuseRefreshTokens(false)
.exceptionTranslator(new SictWebResponseExceptionTranslator());
}
@Bean
public MyRedisTokenStore tokenStore() {
MyRedisTokenStore tokenStore = new MyRedisTokenStore(redisConnectionFactory);
tokenStore.setPrefix(SecurityConstants.SICT_PREFIX + SecurityConstants.OAUTH_PREFIX);
tokenStore.setAuthenticationKeyGenerator(new DefaultAuthenticationKeyGenerator() {
@Override
public String extractKey(OAuth2Authentication authentication) {
return super.extractKey(authentication);
}
});
return tokenStore;
}
/**
* token增强,客户端模式不增强。
*
* @return TokenEnhancer
*/
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
if (SecurityConstants.CLIENT_CREDENTIALS
.equals(authentication.getOAuth2Request().getGrantType())) {
return accessToken;
}
final Map<String, Object> additionalInfo = new HashMap<>(8);
SictUser user = (SictUser) authentication.getUserAuthentication().getPrincipal();
additionalInfo.put("user_id", user.getId());
additionalInfo.put("license", SecurityConstants.SICT_LICENSE);
additionalInfo.put("code", Constant.BYTE_YES);
// additionalInfo.put("user_info", "");
// additionalInfo.put("patient_info", "");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
};
}
}
package cn.sh.stc.sict.cloud.auth.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.sh.stc.sict.cloud.common.security.handler.MobileLoginSuccessHandler;
import cn.sh.stc.sict.cloud.common.security.mobile.MobileSecurityConfigurer;
import cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
/**
* @Description 认证相关配置
* @Author
* @Date
*/
@Primary
@Order(90)
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private SictUserDetailsService userDetailsService;
@Lazy
@Autowired
private AuthorizationServerTokenServices defaultAuthorizationServerTokenServices;
@Override
@SneakyThrows
protected void configure(HttpSecurity http) {
http
.formLogin()
.loginPage("/token/login")
.loginProcessingUrl("/token/form")
.and()
.authorizeRequests()
.antMatchers(
"/token/**",
"/test/**",
"/actuator/**",
"/mobile/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable()
.apply(mobileSecurityConfigurer());
}
/**
* 不拦截静态资源
*
* @param web
*/
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/css/**");
}
@Bean
@Override
@SneakyThrows
public AuthenticationManager authenticationManagerBean() {
return super.authenticationManagerBean();
}
@Bean
public AuthenticationSuccessHandler mobileLoginSuccessHandler() {
return MobileLoginSuccessHandler.builder()
.objectMapper(objectMapper)
.clientDetailsService(clientDetailsService)
.passwordEncoder(passwordEncoder())
.defaultAuthorizationServerTokenServices(defaultAuthorizationServerTokenServices).build();
}
@Bean
public MobileSecurityConfigurer mobileSecurityConfigurer() {
MobileSecurityConfigurer mobileSecurityConfigurer = new MobileSecurityConfigurer();
mobileSecurityConfigurer.setMobileLoginSuccessHandler(mobileLoginSuccessHandler());
mobileSecurityConfigurer.setUserDetailsService(userDetailsService);
return mobileSecurityConfigurer;
}
/**
* https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-storage-updated
* Encoded password does not look like BCrypt
*
* @return PasswordEncoder
*/
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
package cn.sh.stc.sict.cloud.auth.endpoint;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.PaginationConstants;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.security.annotation.Inner;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import lombok.AllArgsConstructor;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @Description 删除token端点
* @Author
* @Date
*/
@RestController
@AllArgsConstructor
@RequestMapping("/token")
public class SictTokenEndpoint {
private static final String SICT_OAUTH_ACCESS = SecurityConstants.SICT_PREFIX + SecurityConstants.OAUTH_PREFIX + "auth_to_access:";
private static final String SICT_ACCESS = SecurityConstants.SICT_PREFIX + SecurityConstants.OAUTH_PREFIX + "access:";
private final TokenStore tokenStore;
private final RedisTemplate redisTemplate;
private final CacheManager cacheManager;
/**
* 认证页面
*
* @return ModelAndView
*/
@GetMapping("/login")
public ModelAndView require() {
return new ModelAndView("ftl/login");
}
/**
* 退出token
*
* @param authHeader Authorization
*/
@DeleteMapping("/logout")
public R logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
if (StrUtil.isBlank(authHeader)) {
return R.builder()
.code(Constant.BYTE_NO)
.data(Boolean.FALSE)
.msg("退出失败,token 为空").build();
}
String tokenValue = authHeader.replaceAll("(?i)Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
return R.builder()
.code(Constant.BYTE_NO)
.data(Boolean.FALSE)
.msg("退出失败,token 无效").build();
}
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
SictUser user = (SictUser) cacheManager.getCache(RedisCacheConstant.USER_DETAILS).get(auth2Authentication.getName()).get();
cacheManager.getCache(RedisCacheConstant.USER_DETAILS)
.evict(auth2Authentication.getName());
tokenStore.removeAccessToken(accessToken);
return new R<>(Boolean.TRUE);
}
/**
* 令牌管理调用
*
* @param token token
* @return
*/
@Inner
@DeleteMapping("/{token}")
public R<Boolean> delToken(@PathVariable("token") String token) {
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
tokenStore.removeAccessToken(oAuth2AccessToken);
return new R<>();
}
/**
* 查询token
*
* @param params 分页参数
* @return
*/
@Inner
@PostMapping("/page")
public R<Page> tokenList(@RequestBody Map<String, Object> params) {
//根据分页参数获取对应数据
String key = String.format("%s", SICT_OAUTH_ACCESS);
List<String> pages = findKeysForPage(key, MapUtil.getInt(params, PaginationConstants.CURRENT)
, MapUtil.getInt(params, PaginationConstants.SIZE));
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
Page result = new Page(MapUtil.getInt(params, PaginationConstants.CURRENT), MapUtil.getInt(params, PaginationConstants.SIZE));
result.setRecords(redisTemplate.opsForValue().multiGet(pages));
result.setTotal(Long.valueOf(redisTemplate.keys(key).size()));
return new R<>(result);
}
private List<String> findKeysForPage(String patternKey, int pageNum, int pageSize) {
ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
List<String> result = new ArrayList<>();
int tmpIndex = 0;
int startIndex = (pageNum - 1) * pageSize;
int end = pageNum * pageSize;
assert cursor != null;
while (cursor.hasNext()) {
if (tmpIndex >= startIndex && tmpIndex < end) {
result.add(cursor.next().toString());
tmpIndex++;
continue;
}
if (tmpIndex >= end) {
break;
}
tmpIndex++;
cursor.next();
}
return result;
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationFailureEvenHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationFailureEvenHandler extends AbstractAuthenticationFailureEvenHandler {
/**
* 处理登录失败方法
* <p>
*
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
*/
@Override
public void handle(AuthenticationException authenticationException, Authentication authentication) {
log.info("用户:{} 登录失败,异常:{}", authentication.getPrincipal(), authenticationException.getLocalizedMessage());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationSuccessEventHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationSuccessEventHandler extends AbstractAuthenticationSuccessEventHandler {
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
*
* @param authentication 登录对象
*/
@Override
public void handle(Authentication authentication) {
log.info("用户:{} 登录成功", authentication.getPrincipal());
}
}
server:
port: 10254
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 172.26.140.130:8848
discovery:
namespace: 8e95da30-3e0e-4622-8818-9a9cb4cc6641
config:
namespace: 8e95da30-3e0e-4622-8818-9a9cb4cc6641
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
\ No newline at end of file
server:
port: 10254
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 173.18.1.63:8848
discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
server:
port: 10254
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: 173eb3a0-1782-4b36-9681-0a229b2483e5
config:
namespace: 173eb3a0-1782-4b36-9681-0a229b2483e5
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
}
.form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-margin-top {
margin-top: 50px;
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
margin-bottom: 10px;
}
.form-signin .checkbox {
font-weight: normal;
}
.form-signin .form-control {
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
footer{
text-align: center;
position:absolute;
bottom:0;
width:100%;
height:100px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<title>微服务统一认证</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/signin.css" rel="stylesheet">
</head>
<body>
<div class="container form-margin-top">
<form class="form-signin" action="/token/form" method="post">
<h2 class="form-signin-heading" align="center">统一认证系统</h2>
<input type="text" name="username" class="form-control form-margin-top" placeholder="账号" required autofocus>
<input type="password" name="password" class="form-control" placeholder="密码" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">sign in</button>
</form>
</div>
<footer>
<p>support by: F_xh</p>
<p>email: <a href="mailto:F_xh518@163.com">F_xh518@163.com</a>.</p>
</footer>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<!--
小技巧: 在根pom里面设置统一存放路径,统一管理方便维护
<properties>
<log-path>/Users/shenye</log-path>
</properties>
1. 其他模块加日志输出,直接copy本文件放在resources 目录即可
2. 注意修改 <property name="${log-path}/log.path" value=""/> 的value模块
-->
<configuration debug="false" scan="false">
<property name="log.path" value="logs/${project.artifactId}"/>
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- Console log output -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- Log file debug output -->
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/debug.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
</encoder>
</appender>
<!-- Log file error output -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<logger name="org.activiti.engine.impl.db" level="DEBUG">
<appender-ref ref="debug"/>
</logger>
<!--nacos 心跳 INFO 屏蔽-->
<logger name="com.alibaba.nacos" level="OFF">
<appender-ref ref="error"/>
</logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="DEBUG">
<appender-ref ref="console"/>
<appender-ref ref="debug"/>
</root>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>2.1.3.RELEASE</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-common-bom</artifactId>
<packaging>pom</packaging>
<version>${sict.version}</version>
<description>公共版本控制</description>
<properties>
<sict.version>1.0.0</sict.version>
<jackson.modules>2.9.6</jackson.modules>
<mybatis-plus.version>3.3.2</mybatis-plus.version>
<mysql.connector.version>8.0.15</mysql.connector.version>
<swagger.core.version>1.5.22</swagger.core.version>
<swagger.version>2.9.2</swagger.version>
<hutool.version>5.5.1</hutool.version>
<poi.version>4.1.0</poi.version>
<pinyin4j.version>2.5.1</pinyin4j.version>
<ttl.version>2.10.1</ttl.version>
<kaptcha.version>0.0.9</kaptcha.version>
<minio.version>6.0.8</minio.version>
<orika.version>1.4.6</orika.version>
<commons.lang3.version>3.9</commons.lang3.version>
<security.oauth.version>2.3.4.RELEASE</security.oauth.version>
<javaformat.plugin.version>0.0.23</javaformat.plugin.version>
<cloud.plugin.version>1.0.0</cloud.plugin.version>
<mbp.dynamic.version>3.1.1</mbp.dynamic.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-upms-api</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${mbp.dynamic.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-minio</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-core</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-auth-api</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-dynamic-gateway</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-gateway</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-security</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-data</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-swagger</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-log</artifactId>
<version>${sict.version}</version>
</dependency>
<!-- 实体映射工具 -->
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>${orika.version}</version>
</dependency>
<!--验证码-->
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!--TTL-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>${ttl.version}</version>
</dependency>
<!-- 拼音 -->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>${pinyin4j.version}</version>
</dependency>
<!--jackson模块-->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-modules-java8</artifactId>
<version>${jackson.modules}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- minio -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
<!--mybatis plus extension,包含了mybatis plus core-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
<!--swagger 最新依赖内置版本-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${swagger.core.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.core.version}</version>
</dependency>
<!--swagger 依赖-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<!--稳定版本,替代spring security bom内置-->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${security.oauth.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!--避免和parent bom坐标不一致 -->
<!-- <plugin>-->
<!-- <groupId>cn.sh.stc.sict.plugin</groupId>-->
<!-- <artifactId>spring-cloud-maven-plugin</artifactId>-->
<!-- <version>${cloud.plugin.version}</version>-->
<!-- <executions>-->
<!-- <execution>-->
<!-- <phase>package</phase>-->
<!-- <goals>-->
<!-- <goal>info</goal>-->
<!-- </goals>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- </plugin>-->
<!--代码格式插件,默认使用spring 规则-->
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
<version>${javaformat.plugin.version}</version>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>aliyun-plugin</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-common</artifactId>
<groupId>cn.sh.stc.sict</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-common-core</artifactId>
<description>核心基础模块</description>
<packaging>jar</packaging>
<dependencies>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- 实体映射工具 -->
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
</dependency>
<!--server-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--feign 依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--hibernate-validator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--jackson模块-->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!--TTL-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<!-- 拼音 -->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!--缓存依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.sh.stc.sict.cloud.common.core.config;
import cn.hutool.core.date.DatePattern;
import cn.sh.stc.sict.cloud.common.core.jackson.MyJavaTimeModule;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
/**
* JacksonConfig
*
* @author F_xh
* @date: 2018/10/22
*/
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> {
builder.locale(Locale.CHINA);
builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
builder.modules(new MyJavaTimeModule());
builder.featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
};
}
}
package cn.sh.stc.sict.cloud.common.core.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
/**
* @Description 国际化配置
* @Author
* @Date
*/
@Configuration
public class MessageSourceConfig {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource
= new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:i18n/messages");
return messageSource;
}
}
package cn.sh.stc.sict.cloud.common.core.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @Description RestTemplate
* @Author
* @Date
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
package cn.sh.stc.sict.cloud.common.core.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class UnionChainProperties {
@Value("${union.chain.url:#{null}}")
private String url;
}
package cn.sh.stc.sict.cloud.common.core.config;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
/**
* @ClassName ValidatorConfig
* @Description 校验模式:快速失败返回(任意一个参数校验失败后立即返回,不进行后续参数的校验)
* @Author Y
* @Date 2019-12-26 20:38
*/
@Configuration
public class ValidatorConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(true)
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
}
package cn.sh.stc.sict.cloud.common.core.constant;
/**
* 健康链常量
*/
public class ChainConstant {
/**
* biz
*/
/**
* type
*/
}
package cn.sh.stc.sict.cloud.common.core.constant;
/**
* @Author: 向怀芳
* @Date: 2018/8/22 17:23
* @Description:
*/
public class Constant {
public static final String DEFAULT_PASSWORD = "123456";
/**
* 标识:是
*/
public static final Byte BYTE_YES = 1;
/**
* 标识:否
*/
public static final Byte BYTE_NO = 0;
/**
* 标识:是
*/
public static final Integer INT_YES = 1;
/**
* 标识:否
*/
public static final Integer INT_NO = 0;
/**
* 标识:是
*/
public static final String STRING_YES = "1";
/**
* 标识:否
*/
public static final String STRING_NO = "0";
/**
* 树的根节点
*/
public static final Long ROOT_NODE = 0L;
/**
* 默认头像
*/
public static final String DEFAULT_AVATAR_IMG = "/default-avatar.png";
/**
* 日志类型标识:正常
*/
public static final String LOG_TYPE_NORMAL = "1";
/**
* 日志类型标识:异常
*/
public static final String LOG_TYPE_EXCEPTION = "9";
}
package cn.sh.stc.sict.cloud.common.core.constant;
/**
* @Description 分页相关的参数
* @Author
* @Date
*/
public interface PaginationConstants {
/**
* 当前页
*/
String CURRENT="current";
/**
* 每页大小
*/
String SIZE="size";
}
package cn.sh.stc.sict.cloud.common.core.constant;
/**
* @Description
* @Author
* @Date
*/
public class RedisCacheConstant {
/**
* 用户角色与终端类型的分隔符
*/
public static final String USER_ROLE_SEPARATOR = "@";
/**
* 微信用户信息明细
*/
public static final String WX_USER_DETAILS = "wx_user_details";
/**
* 基础用户信息明细 base
*/
public static final String BASE_USER_DETAILS = "base_user_details";
/**
* 基础学生信息
*/
public static final String CURRENT_STUDENT = "current_student";
/**
* 基础用户信息明细
*/
public static final String USER_DETAILS = "user_details";
/**
* 当前登录用户的角色信息
*/
public static final String TOKEN_ROLES = "token_roles";
/**
* 当前登录用户的详细信息
*/
public static final String TOKEN_CURRENT = "token_current";
/**
* 微信应用缓存
*/
public static final String WECHAT_OFFICALS = "wechat_officals";
/**
* 冷知识点赞数量
*/
public static final String CLD_TRIVIA_NUM = "cld_trivia_num";
/**
* 积分
*/
public static final String CREDIT = "credit";
public static final String CREDIT_NEXT_LEVEL_BY_SCORE = "credit:score:next";
public static final String CREDIT_LEVEL_BY_SCORE = "credit:score:current";
/**
* 未付款订单
*/
public static final String PAY_ORDER_NOT_PAID = "order_info:not_paid";
/**
* temp 微信支付开关
*/
public static final String WECHAT_APPLE_PAY_SWITCH = "order_info:wechat_apple_pay_switch";
/**
* 是否需要弹窗
*/
public static final String WECHAT_POP_UP = "pop-up:kindergarten";
/**
* 用户短信验证码
*/
public static final String SICT_PHONE_CODE_KEY = "SICT_PHONE_CODE_KEY";
/**
* 路由存放
*/
public static final String ROUTE_KEY = "gateway_route_key";
/**
* 验证码前缀
*/
public static final String DEFAULT_CODE_KEY = "SICT_DEFAULT_CODE_KEY_";
}
package cn.sh.stc.sict.cloud.common.core.constant;
/**
* @Description
* @Author
* @Date
*/
public interface SecurityConstants {
/**
* 刷新
*/
String REFRESH_TOKEN = "refresh_token";
/**
* 验证码有效期
*/
int CODE_TIME = 60;
/**
* 验证码长度
*/
String CODE_SIZE = "4";
/**
* 角色前缀
*/
String ROLE = "ROLE_";
/**
* 前缀
*/
String SICT_PREFIX = "sict_";
/**
* oauth 相关前缀
*/
String OAUTH_PREFIX = "oauth:";
/**
* 项目的license
*/
String SICT_LICENSE = "made by SICT";
/**
* 内部
*/
String FROM_IN = "Y";
/**
* 标志
*/
String FROM = "from";
/**
* OAUTH URL
*/
String OAUTH_TOKEN_URL = "/oauth/token";
/**
* 手机号登录URL
*/
String SMS_TOKEN_URL = "/mobile/token/sms";
/**
* 社交登录URL
*/
String SOCIAL_TOKEN_URL = "/mobile/token/social";
/**
* 自定义登录URL
*/
String MOBILE_TOKEN_URL = "/mobile/token/**";
/**
* oauth 客户端信息
*/
String CLIENT_DETAILS_KEY = "sict_oauth:client:details";
/**
* 微信获取OPENID
*/
String WX_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
/**
* {bcrypt} 加密的特征码
*/
String BCRYPT = "{bcrypt}";
/**
* sys_oauth_client_details 表的字段,不包括client_id、client_secret
*/
String CLIENT_FIELDS = "client_id, CONCAT('{noop}',client_secret) as client_secret, resource_ids, scope, "
+ "authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, "
+ "refresh_token_validity, additional_information, autoapprove";
/**
* JdbcClientDetailsService 查询语句
*/
String BASE_FIND_STATEMENT = "select " + CLIENT_FIELDS
+ " from sys_oauth_client_details";
/**
* 默认的查询语句
*/
String DEFAULT_FIND_STATEMENT = BASE_FIND_STATEMENT + " order by client_id";
/**
* 按条件client_id 查询
*/
String DEFAULT_SELECT_STATEMENT = BASE_FIND_STATEMENT + " where client_id = ?";
/**
* 资源服务器默认bean名称
*/
String RESOURCE_SERVER_CONFIGURER = "resourceServerConfigurerAdapter";
/**
* 客户端模式
*/
String CLIENT_CREDENTIALS = "client_credentials";
/**
* 用户ID字段
*/
String DETAILS_USER_ID = "id";
/**
* 用户名字段
*/
String DETAILS_USERNAME = "username";
/**
* uuid
*/
String DETAILS_NAME = "name";
/**
* openid
*/
String DETAILS_OPENID = "openid";
/**
* openid
*/
String DETAILS_APPID = "appid";
/**
* 租户ID 字段
*/
String DETAILS_TENANT_ID = "tenant_id";
/**
* 协议字段
*/
String DETAILS_LICENSE = "license";
/**
*
*/
String DEFAULT_GATEWAY_PREFIX = "";
/**
* 正式环境 active
*/
String ACTIVE_PROD = "prd";
/**
* uat环境 uat
*/
String ACTIVE_UAT = "uat";
/**
* test 环境使用内网连接数据库
*/
String ACTIVE_DEV = "dev";
/**
* test 环境使用内网连接数据库
*/
String ACTIVE_TEST = "test";
/**
* 激活字段 兼容外围系统接入
*/
String ACTIVE = "active";
/**
* 用户基本信息
*/
String DETAILS_USER = "user_info";
/**
* 授权码模式code key 前缀
*/
String OAUTH_CODE_PREFIX = "oauth:code:";
/**
* token 相关前缀
*/
String TOKEN_PREFIX = "token:";
}
package cn.sh.stc.sict.cloud.common.core.constant;
/**
* @Description
* @Author
* @Date
*/
public interface ServiceNameConstants {
/**
* 认证中心
*/
String UPMS_SERVICE = "cloud-upms-biz";
}
package cn.sh.stc.sict.cloud.common.core.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author F_xh
* 业务类异常枚举字典
* 同类枚举放在相邻位置,并做好备注
*/
@Getter
@AllArgsConstructor
public enum BizCodeConstant {
/* */
TEMP(0,"");
private Integer code;
private String description;
}
package cn.sh.stc.sict.cloud.common.core.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @Description 社交登录类型
* @Author
* @Date
*/
@Getter
@AllArgsConstructor
public enum LoginTypeEnum {
/**
* 账号密码登录
*/
PWD("pwd", "账号密码登录"),
/**
* 验证码登录
*/
SMS("sms", "验证码登录"),
/**
* H5登录
*/
H5("h5", "H5登录"),
/**
* QQ登录
*/
QQ("qq", "QQ登录"),
/**
* 微信登录
*/
WECHAT("wx", "微信登录");
/**
* 类型
*/
private final String type;
/**
* 描述
*/
private final String description;
}
package cn.sh.stc.sict.cloud.common.core.exception;
import cn.sh.stc.sict.cloud.common.core.constant.enums.BizCodeConstant;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @Description 200 业务异常处理
* @Author
* @Date
*/
@NoArgsConstructor
public class BusinessException extends Exception {
private static final long serialVersionUID = 1L;
@Getter
@Setter
private int code = 0;
public BusinessException(String message) {
super(message);
}
public BusinessException(int code, String message){
super(message);
this.code = code;
}
public BusinessException(BizCodeConstant biz){
super(biz.getDescription());
this.code = biz.getCode();
}
public BusinessException(Throwable cause) {
super(cause);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package cn.sh.stc.sict.cloud.common.core.exception;
import lombok.NoArgsConstructor;
/**
* @author F_xh
* @date
*/
@NoArgsConstructor
public class CheckedException extends RuntimeException {
private static final long serialVersionUID = 1L;
public CheckedException(String message) {
super(message);
}
public CheckedException(Throwable cause) {
super(cause);
}
public CheckedException(String message, Throwable cause) {
super(message, cause);
}
public CheckedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package cn.sh.stc.sict.cloud.common.core.exception;
import lombok.NoArgsConstructor;
/**
* @Description 403 授权拒绝
* @Author
* @Date
*/
@NoArgsConstructor
public class SictDeniedException extends RuntimeException {
private static final long serialVersionUID = 1L;
public SictDeniedException(String message) {
super(message);
}
public SictDeniedException(Throwable cause) {
super(cause);
}
public SictDeniedException(String message, Throwable cause) {
super(message, cause);
}
public SictDeniedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package cn.sh.stc.sict.cloud.common.core.exception;
import lombok.NoArgsConstructor;
/**
* @Description
* @Author
* @Date
*/
@NoArgsConstructor
public class UnloginException extends RuntimeException {
private static final long serialVersionUID = 1L;
public UnloginException(String message) {
super(message);
}
public UnloginException(Throwable cause) {
super(cause);
}
public UnloginException(String message, Throwable cause) {
super(message, cause);
}
public UnloginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package cn.sh.stc.sict.cloud.common.core.exception;
/**
* @Description
* @Author
* @Date
*/
public class ValidateCodeException extends Exception {
private static final long serialVersionUID = -7285211528095468156L;
public ValidateCodeException() {
}
public ValidateCodeException(String msg) {
super(msg);
}
}
package cn.sh.stc.sict.cloud.common.core.jackson;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import java.util.List;
import java.util.Set;
/**
* @author F_xh
* @date 2019/5/27 19:29
*/
public class MyBeanSerializerModifier extends BeanSerializerModifier {
private JsonSerializer _nullArrayJsonSerializer = new MyNullArrayJsonSerializer();
private JsonSerializer _nullJsonSerializer = new MyNullJsonSerializer();
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
List beanProperties) {
//循环所有的beanPropertyWriter
for (int i = 0; i < beanProperties.size(); i++) {
BeanPropertyWriter writer = (BeanPropertyWriter) beanProperties.get(i);
//判断字段的类型,如果是array,list,set则注册nullSerializer
if (isArrayType(writer)) {
//给writer注册一个自己的nullSerializer
writer.assignNullSerializer(this._nullArrayJsonSerializer);
} else {
writer.assignNullSerializer(this._nullJsonSerializer);
}
}
return beanProperties;
}
//判断是什么类型
protected boolean isArrayType(BeanPropertyWriter writer) {
Class clazz = writer.getPropertyType();
return clazz.isArray() || clazz.equals(List.class) || clazz.equals(Set.class);
}
}
package cn.sh.stc.sict.cloud.common.core.jackson;
import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
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.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
/**
* java 8 时间默认序列化
*
* @author L.cm
* @author lishanbu
*/
public class MyJavaTimeModule extends SimpleModule {
public MyJavaTimeModule() {
super(PackageVersion.VERSION);
this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
this.addSerializer(Long.class, ToStringSerializer.instance);
this.addSerializer(Long.TYPE, ToStringSerializer.instance);
this.setSerializerModifier(new MyBeanSerializerModifier());
}
}
package cn.sh.stc.sict.cloud.common.core.jackson;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
* @author F_xh
* @date 2019/5/27 19:28
*/
public class MyNullArrayJsonSerializer extends JsonSerializer {
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
if (value == null) {
jgen.writeStartArray();
jgen.writeEndArray();
}
}
}
package cn.sh.stc.sict.cloud.common.core.jackson;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
* @author F_xh
* @date 2019/5/27 19:28
*/
public class MyNullJsonSerializer extends JsonSerializer {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
jsonGenerator.writeString("");
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import lombok.experimental.UtilityClass;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.web.method.HandlerMethod;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @Description 类工具类
* @Author
* @Date
*/
@UtilityClass
public class ClassUtils extends org.springframework.util.ClassUtils {
private final ParameterNameDiscoverer PARAMETERNAMEDISCOVERER = new DefaultParameterNameDiscoverer();
/**
* 获取方法参数信息
*
* @param constructor 构造器
* @param parameterIndex 参数序号
* @return {MethodParameter}
*/
public MethodParameter getMethodParameter(Constructor<?> constructor, int parameterIndex) {
MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex);
methodParameter.initParameterNameDiscovery(PARAMETERNAMEDISCOVERER);
return methodParameter;
}
/**
* 获取方法参数信息
*
* @param method 方法
* @param parameterIndex 参数序号
* @return {MethodParameter}
*/
public MethodParameter getMethodParameter(Method method, int parameterIndex) {
MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);
methodParameter.initParameterNameDiscovery(PARAMETERNAMEDISCOVERER);
return methodParameter;
}
/**
* 获取Annotation
*
* @param method Method
* @param annotationType 注解类
* @param <A> 泛型标记
* @return {Annotation}
*/
public <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
Class<?> targetClass = method.getDeclaringClass();
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 先找方法,再找方法上的类
A annotation = AnnotatedElementUtils.findMergedAnnotation(specificMethod, annotationType);
;
if (null != annotation) {
return annotation;
}
// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类
return AnnotatedElementUtils.findMergedAnnotation(specificMethod.getDeclaringClass(), annotationType);
}
/**
* 获取Annotation
*
* @param handlerMethod HandlerMethod
* @param annotationType 注解类
* @param <A> 泛型标记
* @return {Annotation}
*/
public <A extends Annotation> A getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType) {
// 先找方法,再找方法上的类
A annotation = handlerMethod.getMethodAnnotation(annotationType);
if (null != annotation) {
return annotation;
}
// 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类
Class<?> beanType = handlerMethod.getBeanType();
return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.util.ObjectUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* @Description 数字类型Util
* @Author
* @Date
*/
public class NumberUtil {
private static final BigDecimal zero = BigDecimal.ZERO;
public static boolean isNotNullOrZero(Double val) {
return !isNullOrZero(val);
}
/**
* 判断 Byte 是否null或0
*
* @param val
* @return
*/
public static boolean isNullOrZero(Double val) {
return null == val || val == 0;
}
/**
* 判断 Byte 是否null或0
*
* @param val
* @return
*/
public static boolean isNullOrZero(Byte val) {
return null == val || val == 0;
}
/**
* @description: 反向判断 Byte 是否null或0
*/
public static boolean isNotNullOrZero(Byte val) {
return !isNullOrZero(val);
}
/**
* 判断 Interger 是否null或0
*
* @param val
* @return
*/
public static boolean isNullOrZero(Integer val) {
return null == val || val == 0;
}
/**
* @description: 反向判断 Integer 是否null或0
*/
public static boolean isNotNullOrZero(Integer val) {
return !isNullOrZero(val);
}
/**
* 判断 Long 数字是否有效
*
* @param val
* @return
*/
public static boolean isNullOrZero(Long val) {
return ObjectUtil.isNull(val) || val == 0;
}
/**
* @description: 反向判断 Long 是否null或0
*/
public static boolean isNotNullOrZero(Long val) {
return !isNullOrZero(val);
}
/**
* @description: 判断bigDecimal函数是不是空或0
*/
public static boolean isNullOrZero(BigDecimal val) {
return null == val || val.compareTo(zero) == 0;
}
/**
* @description: 反向判断bigDecimal函数是不是空或0
*/
public static boolean isNotNullOrZero(BigDecimal val) {
return !isNullOrZero(val);
}
/**
* 把 object 转为 BigDecimal
*
* @param value
* @return
*/
public static BigDecimal getBigDecimal(Object value) {
BigDecimal ret = null;
if (value != null) {
if (value instanceof BigDecimal) {
ret = (BigDecimal) value;
} else if (value instanceof String) {
ret = new BigDecimal((String) value);
} else if (value instanceof BigInteger) {
ret = new BigDecimal((BigInteger) value);
} else if (value instanceof Number) {
ret = new BigDecimal(((Number) value).doubleValue());
} else {
throw new ClassCastException("Not possible to coerce [" + value + "] from class " + value.getClass() + " into a BigDecimal.");
}
}
return ret;
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 响应信息主体
*
* @param <T>
* @author F_xh
*/
@Builder
@ToString
@Accessors(chain = true)
@AllArgsConstructor
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
@Getter
@Setter
private byte code = Constant.BYTE_YES;
@Getter
@Setter
private Integer bizCode = Constant.INT_YES;
@Getter
@Setter
private String msg = "操作成功";
@Getter
@Setter
private T data;
public R() {
super();
}
public R(T data) {
super();
this.data = data;
}
public R(T data, String msg) {
super();
this.data = data;
this.msg = msg;
}
public R success(T data, String msg) {
return R.builder().code(Constant.BYTE_YES).data(data).msg(msg).build();
}
public R success(T data) {
return R.builder().code(Constant.BYTE_YES).data(data).msg("操作成功").build();
}
public R error(String msg) {
return this.error(null, msg);
}
public R error(T data, String msg) {
return R.builder().code(Constant.BYTE_NO).data(data).msg("操作失败:" + msg).build();
}
public R(Throwable e) {
super();
this.msg = e.getMessage();
this.code = Constant.BYTE_NO;
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @description: xxx短信验证发送工具类
* @author: template from A-LI-Cloud
* @create: 2019/5/9 15:16
*/
@Slf4j
@Component
@RefreshScope
public class SmsSendUtil {
@Autowired
private StringRedisTemplate redisService;
@Value("${ali.signName:test}")
private String signName;
private String regionId = "";
@Value("${ali.accesskeyId:ak}")
private String accesskeyId;
@Value("${ali.accessKeySecret:sk}")
private String accessKeySecret;
/**
* 身份验证验证码
*/
@Value("${ali.templateCode:SMS_165540176}")
private String templateCode6;
/**
* 登录确认验证码
*/
@Value("${ali.templateCode:SMS_165540175}")
private String templateCode5;
/**
* 登录异常验证码
*/
@Value("${ali.templateCode:SMS_165540174}")
private String templateCode4;
/**
* 用户注册验证码
*/
@Value("${ali.templateCode:SMS_165540173}")
private String templateCode3;
/**
* 修改密码验证码
*/
@Value("${ali.templateCode:SMS_165540172}")
private String templateCode2;
/**
* 信息变更验证码
*/
@Value("${ali.templateCode:SMS_165540171}")
private String templateCode1;
/**
* cache前缀
*/
private final static String VERIFICATION_PRE = "SMS:";
/**
* 过期时间/s
*/
private final static Long EXPIRE_TIME_SECOND = 7200L;
public String getActive() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
String[] activeProfiles = context.getEnvironment().getActiveProfiles();
return activeProfiles.length > 0 ? activeProfiles[0] : "";
}
/**
* 发送短信验证码
* type: 1-登录验证码 2-注册验证码
* @param phoneNumber 手机号
* @return
*/
public String sendSMS(String phoneNumber, Integer type) {
if (!Validator.isMobile(phoneNumber)) {
return "手机号不合法";
}
String active = getActive();
log.error("sms active = {}", active);
if (StrUtil.equalsIgnoreCase(active, SecurityConstants.ACTIVE_DEV)) {
return sendUatSMS(phoneNumber, type);
}
return this.sendProdSMS(phoneNumber, type);
}
private String sendUatSMS(String phoneNumber, Integer type) {
String key = VERIFICATION_PRE + type + phoneNumber;
String code = RandomStringUtils.random(6, false, true);
redisService.opsForValue().set(key, code, EXPIRE_TIME_SECOND, TimeUnit.SECONDS);
log.info("手机号码为:{}的用户收到验证码:{}", phoneNumber, code);
return "dev环境发送成功:" + code;
}
private String sendProdSMS(String phoneNumber, Integer type) {
String templateCode = templateCode6;
if (type != null) {
Map<Integer, String> templateCodeMap = new ConcurrentHashMap<>();
templateCodeMap.put(1, templateCode1);
templateCodeMap.put(2, templateCode2);
templateCodeMap.put(3, templateCode3);
templateCodeMap.put(4, templateCode4);
templateCodeMap.put(5, templateCode5);
templateCodeMap.put(6, templateCode6);
if (StringUtils.isNotEmpty(templateCodeMap.get(type))) {
templateCode = templateCodeMap.get(type);
}
}
// 检查是否重复发送
String key = VERIFICATION_PRE + type + phoneNumber;
// if (StrUtil.isNotBlank(redisService.opsForValue().get(key))) {
// return "发送成功";
// }
/**
* 002.使用线程安全的集合,防止在并发条件下的污染问题
*/
Map hashMap = new ConcurrentHashMap();
hashMap.put("code", RandomStringUtils.random(6, false, true));
// DefaultProfile profile = DefaultProfile.getProfile(regionId, accesskeyId, accessKeySecret);
// IAcsClient client = new DefaultAcsClient(profile);
// CommonRequest request = new CommonRequest();
// request.setMethod(MethodType.POST);
// request.setDomain("dysmsapi.aliyuncs.com");
// request.setVersion("2017-05-25");
// request.setAction("SendSms");
// request.putQueryParameter("RegionId", regionId);
// request.putQueryParameter("SignName", signName);
// request.putQueryParameter("TemplateCode", templateCode);
// request.putQueryParameter("PhoneNumbers", phoneNumber);
// request.putQueryParameter("TemplateParam", JSONUtil.toJsonStr(hashMap));
// try {
// CommonResponse commonResponse = client.getCommonResponse(request);
// JSONObject jsonObject = JSONUtil.parseObj(commonResponse.getData());
// if (commonResponse.getHttpStatus() == 200 && jsonObject.get("Message").equals("OK")) {
// redisService.opsForValue().set(key, hashMap.get("code").toString(), EXPIRE_TIME_SECOND, TimeUnit.SECONDS);
// log.info("手机号码为:{}的用户收到验证码:{}", phoneNumber, hashMap.get("code"));
// hashMap.clear();
// return "发送成功";
// }
// if (jsonObject.get("Message").toString().equals("触发分钟级流控Permits:1")
// || jsonObject.get("Message").toString().equals("触发小时级流控Permits:5")) {
// return "发送短信过于频繁,请您稍后再试";
// }
// } catch (Exception e) {
// log.error(e.getMessage(), e);
// }
return "发送短信过于频繁,请您稍后再试";
}
/**
* 校验验证码
*
* @param phone
* @param code
*/
public Boolean checkCode(String phone, Integer type, String code) {
String key = VERIFICATION_PRE + type + phone;
// String redisCode = redisService.opsForValue().get(key);
// if (StringUtils.isNotEmpty(redisCode) && redisCode.equals(code)) {
// redisService.delete(key);
// return true;
// }
return false;
}
}
\ No newline at end of file
package cn.sh.stc.sict.cloud.common.core.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
/**
* @Description Spring 工具类
* @Author
* @Date
*/
@Slf4j
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
if (log.isDebugEnabled()) {
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
/**
* 发布事件
*
* @param event
*/
public static void publishEvent(ApplicationEvent event) {
if (applicationContext == null) {
return;
}
applicationContext.publishEvent(event);
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() {
SpringContextHolder.clearHolder();
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Locale;
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
// 传入线程中
public static <T> T getBean(String beanName) {
return (T) context.getBean(beanName);
}
// 国际化使用
public static String getMessage(String key) {
return context.getMessage(key, null, Locale.getDefault());
}
/// 获取当前环境
public static String getActiveProfile() {
if(context.getEnvironment().getActiveProfiles().length>0){
return context.getEnvironment().getActiveProfiles()[0];
}
return "";
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.sh.stc.sict.cloud.common.core.exception.CheckedException;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* @Description Miscellaneous utilities for web applications.
* @Author
* @Date
*/
@Slf4j
@UtilityClass
public class WebUtils extends org.springframework.web.util.WebUtils {
private final String BASIC_ = "Basic ";
private final String UNKNOWN = "unknown";
/**
* 判断是否ajax请求
* spring ajax 返回含有 ResponseBody 或者 RestController注解
*
* @param handlerMethod HandlerMethod
* @return 是否ajax请求
*/
public boolean isBody(HandlerMethod handlerMethod) {
ResponseBody responseBody = ClassUtils.getAnnotation(handlerMethod, ResponseBody.class);
return responseBody != null;
}
/**
* 读取cookie
*
* @param name cookie name
* @return cookie value
*/
public String getCookieVal(String name) {
HttpServletRequest request = WebUtils.getRequest();
Assert.notNull(request, "request from RequestContextHolder is null");
return getCookieVal(request, name);
}
/**
* 读取cookie
*
* @param request HttpServletRequest
* @param name cookie name
* @return cookie value
*/
public String getCookieVal(HttpServletRequest request, String name) {
Cookie cookie = getCookie(request, name);
return cookie != null ? cookie.getValue() : null;
}
/**
* 清除 某个指定的cookie
*
* @param response HttpServletResponse
* @param key cookie key
*/
public void removeCookie(HttpServletResponse response, String key) {
setCookie(response, key, null, 0);
}
/**
* 设置cookie
*
* @param response HttpServletResponse
* @param name cookie name
* @param value cookie value
* @param maxAgeInSeconds maxage
*/
public void setCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
Cookie cookie = new Cookie(name, value);
cookie.setPath("/");
cookie.setMaxAge(maxAgeInSeconds);
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
/**
* 获取 HttpServletRequest
*
* @return {HttpServletRequest}
*/
public HttpServletRequest getRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
/**
* 获取 HttpServletResponse
*
* @return {HttpServletResponse}
*/
public HttpServletResponse getResponse() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
/**
* 返回json
*
* @param response HttpServletResponse
* @param result 结果对象
*/
public void renderJson(HttpServletResponse response, Object result) {
renderJson(response, result, MediaType.APPLICATION_JSON_UTF8_VALUE);
}
/**
* 返回json
*
* @param response HttpServletResponse
* @param result 结果对象
* @param contentType contentType
*/
public void renderJson(HttpServletResponse response, Object result, String contentType) {
response.setCharacterEncoding("UTF-8");
response.setContentType(contentType);
try (PrintWriter out = response.getWriter()) {
out.append(JSONUtil.toJsonStr(result));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
/**
* 获取ip
*
* @return {String}
*/
public String getIP() {
return getIP(WebUtils.getRequest());
}
public String getSession(){
return WebUtils.getSessionId(WebUtils.getRequest());
}
/**
* 获取ip
*
* @param request HttpServletRequest
* @return {String}
*/
public String getIP(HttpServletRequest request) {
Assert.notNull(request, "HttpServletRequest is null");
String ip = request.getHeader("X-Requested-For");
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return StringUtils.isBlank(ip) ? null : ip.split(",")[0];
}
/**
* 从request 获取CLIENT_ID
*
* @return
*/
@SneakyThrows
public String[] getClientId(ServerHttpRequest request) {
String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (header == null || !header.startsWith(BASIC_)) {
throw new CheckedException("请求头中client信息为空");
}
byte[] base64Token = header.substring(6).getBytes("UTF-8");
byte[] decoded;
try {
decoded = Base64.decode(base64Token);
} catch (IllegalArgumentException e) {
throw new CheckedException(
"Failed to decode basic authentication token");
}
String token = new String(decoded, StandardCharsets.UTF_8);
int delim = token.indexOf(":");
if (delim == -1) {
throw new CheckedException("Invalid basic authentication token");
}
return new String[]{token.substring(0, delim), token.substring(delim + 1)};
}
/**
*
* @param request HttpServletRequest
* tip: 不可使用WebUtils.getRequest()获取
* @param allowSuffix 文件后缀名 多个以","逗号分隔
* @return
*/
public MultipartFile getRequestFile(@NonNull HttpServletRequest request, @NonNull String allowSuffix){
String errorMsg = StrUtil.EMPTY;
String[] suffixs = allowSuffix.split(",");
Set<String> suffixSet = new HashSet<String>(Arrays.asList(suffixs));
Map<String, MultipartFile> fileMap = ((MultipartHttpServletRequest) request).getFileMap();
MultipartFile file = null;
for (Map.Entry<String, MultipartFile> fileEntity : fileMap.entrySet()) {
file = fileEntity.getValue();
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
if(suffixSet.contains(suffix)){
break;
}
errorMsg = "文件类型不支持";
}
Assert.isTrue(StrUtil.isBlank(errorMsg), errorMsg);
Objects.requireNonNull(file,"excel导入 ---------->>>>>>> 未检测到上传文件");
return file;
}
/**
* 导出excel
* @param list 数据
* @param writer
* @param name 文件名
*/
@SneakyThrows
public void exportExcel(@NonNull List list,@NonNull ExcelWriter writer, String name) {
writer.setOnlyAlias(true);
HttpServletResponse response = WebUtils.getResponse();
//response为HttpServletResponse对象
response.setContentType("application/vnd.ms-excel;charset=utf-8");
//codes.xls是弹出下载对话框的文件名,不能为中文,中文需自行编码
response.setHeader("Content-Disposition", "attachment;filename=data.xlsx");
ServletOutputStream out = response.getOutputStream();
try {
writer.write(list);
writer.flush(out);
} catch (Exception e) {
log.error("下载[{}]excel异常 =====>>>>> {}", name, e.getMessage());
} finally {
// 关闭writer,释放内存
writer.close();
//关闭输出Servlet流
IoUtil.close(out);
}
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.sh.stc.sict.cloud.common.core.util.SpringContextUtil,\
cn.sh.stc.sict.cloud.common.core.config.JacksonConfig,\
cn.sh.stc.sict.cloud.common.core.config.MessageSourceConfig,\
cn.sh.stc.sict.cloud.common.core.config.RestTemplateConfig,\
cn.sh.stc.sict.cloud.common.core.util.SpringContextHolder,\
cn.sh.stc.sict.cloud.common.core.config.UnionChainProperties,\
cn.sh.stc.sict.cloud.common.core.util.SmsSendUtil
\ No newline at end of file
index.title=Index
index.search=Search
index.search.placeholder=Block Number/Transaction Hash
index.hyperledger.explorer.title=Open Hyperledger Explorer
index.breadcrumb.blockchain=Blockchain
index.breadcrumb.generic=Generic
index.breadcrumb.tx=Transaction
index.breadcrumb.history=History
index.breadcrumb.block=Block
index.blocks.title=Block Info
index.blocks.desc=Total blocks
index.blocks.name=Blocks
index.network.title=Network Info
index.network.peers=Peers
index.network.peers.desc=Peer Nodes
index.network.org=Organizations
index.network.channel=Channel
index.chaincode=Chaincode
index.chaincode.name=Name
index.table.title=Block List
index.table.blockhash=Block Hash
index.table.datahash=Data Hash
index.table.txcount=Transactions
index.loadmore=Load more...
index.loadmore.title=Load previous 5 items.
index.view.title=Click to view all transactions
index.loading=Loading...
copyright=@Copyright
back=Back
tx.title=Transactions
tx.time=Time
tx.committer=Comitter
tx.reads=Reads
tx.reads.items=Read Items
tx.reads.others=Others
tx.writes=Writes
tx.writes.items=Write Items
tx.writes.delete=Delete
tx.view.history=Click to view history
tx.view=View
tx.view.details=Click to view details
block.block.height=Block Number
block.table.title=Transactions
block.table.id=ID
block.table.time=Time
block.view.title=Click to view transaction details
history.title=History
history.table=Transactions
history.table.id=ID
history.table.time=Time
history.table.delete=Delete
\ No newline at end of file
index.title=Index
index.search=Search
index.search.placeholder=Block Number/Transaction Hash
index.hyperledger.explorer.title=Open Hyperledger Explorer
index.breadcrumb.blockchain=Blockchain
index.breadcrumb.generic=Generic
index.breadcrumb.tx=Transaction
index.breadcrumb.history=History
index.breadcrumb.block=Block
index.blocks.title=Block Info
index.blocks.desc=Total blocks
index.blocks.name=Blocks
index.network.title=Network Info
index.network.peers=Peers
index.network.peers.desc=Peer Nodes
index.network.org=Organizations
index.network.channel=Channel
index.chaincode=Chaincode
index.chaincode.name=Name
index.table.title=Block List
index.table.blockhash=Block Hash
index.table.datahash=Data Hash
index.table.txcount=Transactions
index.loadmore=Load more...
index.loadmore.title=Load previous 5 items.
index.view.title=Click to view all transactions
index.loading=Loading...
copyright=@Copyright
back=Back
tx.title=Transactions
tx.time=Time
tx.committer=Comitter
tx.reads=Reads
tx.reads.items=Read Items
tx.reads.others=Others
tx.writes=Writes
tx.writes.items=Write Items
tx.writes.delete=Delete
tx.view.history=Click to view history
tx.view=View
tx.view.details=Click to view details
block.block.height=Block Number
block.table.title=Transactions
block.table.id=ID
block.table.time=Time
block.view.title=Click to view transaction details
history.title=History
history.table=Transactions
history.table.id=ID
history.table.time=Time
history.table.delete=Delete
\ No newline at end of file
index.title=\u9996\u9875
index.search=\u641C\u7D22
index.search.placeholder=\u533A\u5757\u9AD8\u5EA6/\u4EA4\u6613Hash
index.hyperledger.explorer.title=\u6253\u5F00\u8D85\u7EA7\u8D26\u672C\u6D4F\u89C8\u5668
index.breadcrumb.blockchain=\u533A\u5757\u94FE
index.breadcrumb.generic=\u6982\u8FF0
index.breadcrumb.tx=\u4EA4\u6613
index.breadcrumb.history=\u5386\u53F2\u8BB0\u5F55
index.breadcrumb.block=\u533A\u5757
index.blocks.title=\u533A\u5757\u4FE1\u606F
index.blocks.desc=\u603B\u533A\u5757
index.blocks.name=\u533A\u5757
index.network.title=\u7F51\u7EDC\u4FE1\u606F
index.network.peers=\u8282\u70B9
index.network.peers.desc=Peer\u8282\u70B9
index.network.org=\u7EC4\u7EC7
index.network.channel=\u901A\u9053
index.chaincode=\u667A\u80FD\u5408\u7EA6
index.chaincode.name=\u540D\u79F0
index.table.title=\u533A\u5757\u5217\u8868
index.table.blockhash=\u533A\u5757\u54C8\u5E0C
index.table.datahash=\u6570\u636E\u54C8\u5E0C
index.table.txcount=\u4EA4\u6613\u6570\u91CF
index.loadmore=\u52A0\u8F7D\u66F4\u591A
index.loadmore.title=\u52A0\u8F7D\u524D5\u4E2A\u533A\u5757
index.view.title=\u70B9\u51FB\u67E5\u770B\u6240\u6709\u4EA4\u6613
index.loading=\u52A0\u8F7D\u4E2D...
copyright=@\u7248\u6743\u6240\u6709
back=\u8FD4\u56DE\u9996\u9875
tx.title=\u4EA4\u6613
tx.time=\u65F6\u95F4
tx.committer=\u63D0\u4EA4\u8005
tx.reads=\u4EA4\u6613\u8BFB\u53D6\u96C6
tx.reads.items=\u8BFB\u53D6\u8D26\u672C
tx.reads.others=\u5176\u5B83
tx.writes=\u4EA4\u6613\u5199\u5165\u96C6
tx.writes.items=\u5199\u5165\u8D26\u672C
tx.writes.delete=\u5220\u9664
tx.view.history=\u70B9\u51FB\u67E5\u8BE2\u5386\u53F2\u8BB0\u5F55
tx.view=\u67E5\u770B
tx.view.details=\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5
block.block.height=\u9AD8\u5EA6
block.table.title=\u4EA4\u6613\u8BE6\u60C5
block.table.id=\u4EA4\u6613ID
block.table.time=\u4EA4\u6613\u65F6\u95F4
block.view.title=\u70B9\u51FB\u67E5\u770B\u4EA4\u6613\u8BE6\u60C5
history.title=\u5386\u53F2\u8BB0\u5F55
history.table=\u5199\u5165\u4EA4\u6613
history.table.id=\u4EA4\u6613ID
history.table.time=\u4EA4\u6613\u65F6\u95F4
history.table.delete=\u5220\u9664
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="false">
<springProperty scop="context" name="spring.application.name" source="spring.application.name" defaultValue=""/>
<property name="log.path" value="logs/${spring.application.name}" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- Console log output -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- Log file debug output -->
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/debug.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>5MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!-- Log file error output -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>5MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
<logger name="org.activiti.engine.impl.db" level="DEBUG">
<appender-ref ref="debug" />
</logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="error" />
</root>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-common</artifactId>
<groupId>cn.sh.stc.sict</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-common-data</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-core</artifactId>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-security</artifactId>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-swagger</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--mybatis plus extension,包含了mybatis plus core-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
</dependency>
<!--缓存依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
package cn.sh.stc.sict.cloud.common.data.cache;
import cn.hutool.core.util.StrUtil;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* {@link RedisCacheWriter} implementation capable of reading/writing binary data from/to Redis in {@literal standalone}
* and {@literal cluster} environments. Works upon a given {@link RedisConnectionFactory} to obtain the actual
* {@link RedisConnection}. <br />
* {@link DefaultRedisCacheWriter} can be used in
* {@link RedisCacheWriter#lockingRedisCacheWriter(RedisConnectionFactory) locking} or
* {@link RedisCacheWriter#nonLockingRedisCacheWriter(RedisConnectionFactory) non-locking} mode. While
* {@literal non-locking} aims for maximum performance it may result in overlapping, non atomic, command execution for
* operations spanning multiple Redis interactions like {@code putIfAbsent}. The {@literal locking} counterpart prevents
* command overlap by setting an explicit lock key and checking against presence of this key which leads to additional
* requests and potential command wait times.
*
* @author Christoph Strobl
* @since 2.0
*/
class DefaultRedisCacheWriter implements RedisCacheWriter {
private final RedisConnectionFactory connectionFactory;
private final Duration sleepTime;
private static final String TOKEN_NAME = "token";
/**
* @param connectionFactory must not be {@literal null}.
*/
DefaultRedisCacheWriter(RedisConnectionFactory connectionFactory) {
this(connectionFactory, Duration.ZERO);
}
/**
* @param connectionFactory must not be {@literal null}.
* @param sleepTime sleep time between lock request attempts. Must not be {@literal null}. Use {@link Duration#ZERO}
* to disable locking.
*/
private DefaultRedisCacheWriter(RedisConnectionFactory connectionFactory, Duration sleepTime) {
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
Assert.notNull(sleepTime, "SleepTime must not be null!");
this.connectionFactory = connectionFactory;
this.sleepTime = sleepTime;
}
@Override
public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
execute(name, connection -> {
if (shouldExpireWithin(name, ttl)) {
connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), SetOption.upsert());
} else {
connection.set(key, value);
}
return "OK";
});
}
@Override
public byte[] get(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
return execute(name, connection -> connection.get(key));
}
@Override
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
return execute(name, connection -> {
if (isLockingCacheWriter()) {
doLock(name, connection);
}
try {
if (connection.setNX(key, value)) {
if (shouldExpireWithin(name, ttl)) {
connection.pExpire(key, ttl.toMillis());
}
return null;
}
return connection.get(key);
} finally {
if (isLockingCacheWriter()) {
doUnlock(name, connection);
}
}
});
}
@Override
public void remove(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
execute(name, connection -> connection.del(key));
}
@Override
public void clean(String name, byte[] pattern) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(pattern, "Pattern must not be null!");
execute(name, connection -> {
boolean wasLocked = false;
try {
if (isLockingCacheWriter()) {
doLock(name, connection);
wasLocked = true;
}
byte[][] keys = Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet())
.toArray(new byte[0][]);
if (keys.length > 0) {
connection.del(keys);
}
} finally {
if (wasLocked && isLockingCacheWriter()) {
doUnlock(name, connection);
}
}
return "OK";
});
}
/**
* Explicitly set a write lock on a cache.
*
* @param name the name of the cache to lock.
*/
void lock(String name) {
execute(name, connection -> doLock(name, connection));
}
/**
* Explicitly remove a write lock from a cache.
*
* @param name the name of the cache to unlock.
*/
void unlock(String name) {
executeLockFree(connection -> doUnlock(name, connection));
}
private Boolean doLock(String name, RedisConnection connection) {
return connection.setNX(createCacheLockKey(name), new byte[0]);
}
private Long doUnlock(String name, RedisConnection connection) {
return connection.del(createCacheLockKey(name));
}
boolean doCheckLock(String name, RedisConnection connection) {
return connection.exists(createCacheLockKey(name));
}
/**
* @return {@literal true} if {@link RedisCacheWriter} uses locks.
*/
private boolean isLockingCacheWriter() {
return !sleepTime.isZero() && !sleepTime.isNegative();
}
private <T> T execute(String name, Function<RedisConnection, T> callback) {
RedisConnection connection = connectionFactory.getConnection();
try {
checkAndPotentiallyWaitUntilUnlocked(name, connection);
return callback.apply(connection);
} finally {
connection.close();
}
}
private void executeLockFree(Consumer<RedisConnection> callback) {
RedisConnection connection = connectionFactory.getConnection();
try {
callback.accept(connection);
} finally {
connection.close();
}
}
private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {
if (!isLockingCacheWriter()) {
return;
}
try {
while (doCheckLock(name, connection)) {
Thread.sleep(sleepTime.toMillis());
}
} catch (InterruptedException ex) {
// Re-interrupt current thread, to allow other participants to react.
Thread.currentThread().interrupt();
throw new PessimisticLockingFailureException(String.format("Interrupted while waiting to unlock cache %s", name),
ex);
}
}
private static boolean shouldExpireWithin(String name, @Nullable Duration ttl) {
return StrUtil.isNotBlank(name) && name.contains(TOKEN_NAME) && ttl != null && !ttl.isZero() && !ttl.isNegative();
}
private static byte[] createCacheLockKey(String name) {
return (name + "~lock").getBytes(StandardCharsets.UTF_8);
}
}
package cn.sh.stc.sict.cloud.common.data.cache;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.lang.Nullable;
import java.time.Duration;
import java.util.Map;
/**
* @Description redis cache 扩展cache name自动化配置
*
* <p>
* cachename = xx#ttl
*
* @Author
* @Date
*/
@Slf4j
public class RedisAutoCacheManager extends RedisCacheManager {
private static final String SPLIT_FLAG = "#";
private static final int CACHE_LENGTH = 2;
RedisAutoCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration,
Map<String, RedisCacheConfiguration> initialCacheConfigurations, boolean allowInFlightCacheCreation) {
super(cacheWriter, defaultCacheConfiguration, initialCacheConfigurations, allowInFlightCacheCreation);
}
@Override
protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
if (StrUtil.isBlank(name) || !name.contains(SPLIT_FLAG)) {
return super.createRedisCache(name, cacheConfig);
}
String[] cacheArray = name.split(SPLIT_FLAG);
if (cacheArray.length < CACHE_LENGTH) {
return super.createRedisCache(name, cacheConfig);
}
if (cacheConfig != null) {
long cacheAge = Long.parseLong(cacheArray[1]);
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(cacheAge));
}
return super.createRedisCache(name, cacheConfig);
}
@Override
public Cache getCache(String name) {
return super.getCache(name);
}
}
package cn.sh.stc.sict.cloud.common.data.cache;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.lang.Nullable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @Description 扩展redis-cache支持注解cacheName添加超时时间
*
* @Author
* @Date
*/
@Configuration
@AutoConfigureAfter({RedisAutoConfiguration.class})
@ConditionalOnBean({RedisConnectionFactory.class})
@ConditionalOnMissingBean({CacheManager.class})
@EnableConfigurationProperties(CacheProperties.class)
public class RedisCacheAutoConfiguration {
private final CacheProperties cacheProperties;
private final CacheManagerCustomizers customizerInvoker;
@Nullable
private final RedisCacheConfiguration redisCacheConfiguration;
RedisCacheAutoConfiguration(CacheProperties cacheProperties,
CacheManagerCustomizers customizerInvoker,
ObjectProvider<RedisCacheConfiguration> redisCacheConfiguration) {
this.cacheProperties = cacheProperties;
this.customizerInvoker = customizerInvoker;
this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
}
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory, ResourceLoader resourceLoader) {
DefaultRedisCacheWriter redisCacheWriter = new DefaultRedisCacheWriter(connectionFactory);
RedisCacheConfiguration cacheConfiguration = this.determineConfiguration(resourceLoader.getClassLoader());
List<String> cacheNames = this.cacheProperties.getCacheNames();
Map<String, RedisCacheConfiguration> initialCaches = new LinkedHashMap<>();
if (!cacheNames.isEmpty()) {
Map<String, RedisCacheConfiguration> cacheConfigMap = new LinkedHashMap<>(cacheNames.size());
cacheNames.forEach(it -> cacheConfigMap.put(it, cacheConfiguration));
initialCaches.putAll(cacheConfigMap);
}
RedisAutoCacheManager cacheManager = new RedisAutoCacheManager(redisCacheWriter, cacheConfiguration,
initialCaches, true);
cacheManager.setTransactionAware(false);
return this.customizerInvoker.customize(cacheManager);
}
private RedisCacheConfiguration determineConfiguration(ClassLoader classLoader) {
if (this.redisCacheConfiguration != null) {
return this.redisCacheConfiguration;
} else {
CacheProperties.Redis redisProperties = this.cacheProperties.getRedis();
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixKeysWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
}
package cn.sh.stc.sict.cloud.common.data.cache;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @Description CacheManagerCustomizers配置
*
* @Author
* @Date
*/
@Configuration
@ConditionalOnMissingBean(CacheManagerCustomizers.class)
public class RedisCacheManagerConfig {
@Bean
public CacheManagerCustomizers cacheManagerCustomizers(
ObjectProvider<List<CacheManagerCustomizer<?>>> customizers) {
return new CacheManagerCustomizers(customizers.getIfAvailable());
}
}
package cn.sh.stc.sict.cloud.common.data.cache;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @Description RedisTemplate 配置
* @Author
* @Date
*/
@EnableCaching
@Configuration
@AllArgsConstructor
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisTemplateConfig {
private final RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new
Jackson2JsonRedisSerializer(Object.class);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
package cn.sh.stc.sict.cloud.common.data.datascope;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* @Description 数据权限查询参数
* @Author
* @Date
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class DataScope extends HashMap {
/**
* 限制范围的字段名称
*/
private String scopeName = "deptId";
/**
* 具体的数据范围
*/
private List<Integer> deptIds = new ArrayList<>();
/**
* 是否只查询本部门
*/
private Boolean isOnly = false;
}
package cn.sh.stc.sict.cloud.common.data.datascope;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.exception.CheckedException;
import cn.sh.stc.sict.cloud.common.data.enums.DataScopeTypeEnum;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.security.core.GrantedAuthority;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Description mybatis 数据权限拦截器
* @Author
* @Date
*/
@Slf4j
@AllArgsConstructor
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DataScopeInterceptor extends AbstractSqlParserHandler implements Interceptor {
private final DataSource dataSource;
@Override
@SneakyThrows
public Object intercept(Invocation invocation) {
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
this.sqlParser(metaObject);
// 先判断是不是SELECT操作
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
String originalSql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
//查找参数中包含DataScope类型的参数
DataScope dataScope = findDataScopeObject(parameterObject);
if (dataScope == null) {
return invocation.proceed();
}
String scopeName = dataScope.getScopeName();
List<Integer> deptIds = dataScope.getDeptIds();
// 优先获取赋值数据
if (CollUtil.isEmpty(deptIds)) {
SictUser user = SecurityUtils.getUser();
if (user == null) {
throw new CheckedException("auto datascope, set up security details true");
}
List<String> roleIdList = user.getAuthorities()
.stream().map(GrantedAuthority::getAuthority)
.filter(authority -> authority.startsWith(SecurityConstants.ROLE))
.map(authority -> authority.split("_")[1])
.collect(Collectors.toList());
Entity query = Db.use(dataSource)
.query("SELECT * FROM sys_role where role_id IN (" + CollUtil.join(roleIdList, ",") + ")")
.stream().min(Comparator.comparingInt(o -> o.getInt("ds_type"))).get();
Integer dsType = query.getInt("ds_type");
// 查询全部
if (DataScopeTypeEnum.ALL.getType() == dsType) {
return invocation.proceed();
}
// 自定义
if (DataScopeTypeEnum.CUSTOM.getType() == dsType) {
String dsScope = query.getStr("ds_scope");
deptIds.addAll(Arrays.stream(dsScope.split(","))
.map(Integer::parseInt).collect(Collectors.toList()));
}
/*
// 查询本级及其下级
if (DataScopeTypeEnum.OWN_CHILD_LEVEL.getType() == dsType) {
List<Integer> deptIdList = Db.use(dataSource)
.findBy("sys_dept_relation", "ancestor", user.getDeptId())
.stream().map(entity -> entity.getInt("descendant"))
.collect(Collectors.toList());
deptIds.addAll(deptIdList);
}
// 只查询本级
if (DataScopeTypeEnum.OWN_LEVEL.getType() == dsType) {
deptIds.add(user.getDeptId());
}*/
}
String join = CollectionUtil.join(deptIds, ",");
originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")";
metaObject.setValue("delegate.boundSql.sql", originalSql);
return invocation.proceed();
}
/**
* 生成拦截对象的代理
*
* @param target 目标对象
* @return 代理对象
*/
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}
/**
* mybatis配置的属性
*
* @param properties mybatis配置的属性
*/
@Override
public void setProperties(Properties properties) {
}
/**
* 查找参数是否包括DataScope对象
*
* @param parameterObj 参数列表
* @return DataScope
*/
private DataScope findDataScopeObject(Object parameterObj) {
if (parameterObj instanceof DataScope) {
return (DataScope) parameterObj;
} else if (parameterObj instanceof Map) {
for (Object val : ((Map<?, ?>) parameterObj).values()) {
if (val instanceof DataScope) {
return (DataScope) val;
}
}
}
return null;
}
}
package cn.sh.stc.sict.cloud.common.data.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import java.io.Serializable;
import java.util.Date;
/**
* @author admin
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("chain_event_info")
public class EventInfo extends Model<EventInfo> {
@ApiModelProperty(hidden = true)
@TableId("`key`")
protected String key;
private String hospId;
private String doctorId;
private String patientId;
@ApiModelProperty(example = "2020-09-10 08:29:31")
@TableField("`time`")
private Date time;
/**
* 操作类型:
*/
private String type;
/**
* 业务类型:知情同意书
*/
private String biz;
/**
* 具体数据
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Object data;
/**
* 入链状态:0-失败 1-成功
*/
private Byte status;
/**
* 主键值
*/
@Override
protected Serializable pkVal(){
return this.key;
}
@Override
public String toString() {
return "EventInfo{" +
"key='" + key + '\'' +
", hospId='" + hospId + '\'' +
", doctorId='" + doctorId + '\'' +
", patientId='" + patientId + '\'' +
", time=" + time +
", type='" + type + '\'' +
", biz='" + biz + '\'' +
", data='" + data + '\'' +
'}';
}
}
package cn.sh.stc.sict.cloud.common.data.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @Description 数据权限类型
* @Author
* @Date
*/
@Getter
@AllArgsConstructor
public enum DataScopeTypeEnum {
/**
* 查询全部数据
*/
ALL(0, "全部"),
/**
* 自定义
*/
CUSTOM(1, "自定义"),
/**
* 本级及子级
*/
OWN_CHILD_LEVEL(2, "本级及子级"),
/**
* 本级
*/
OWN_LEVEL(3, "本级");
/**
* 类型
*/
private final int type;
/**
* 描述
*/
private final String description;
}
package cn.sh.stc.sict.cloud.common.data.mybatis;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @ClassName MyMetaObjectHandler
* @Description 自定义公共字段填充处理器
* @Author Y
* @Date 2020-01-06 18:21
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入操作自动填充
*
* @author:
* @param:
* @return:
* @date:
*/
@Override
public void insertFill(MetaObject metaObject) {
Object createUserName = getFieldValByName("createUserName", metaObject);
Object createUserId = getFieldValByName("createUserId", metaObject);
Object createTime = getFieldValByName("createTime", metaObject);
Object isDeteled = getFieldValByName("isDeleted", metaObject);
Object isUse = getFieldValByName("isUse", metaObject);
SictUser user = SecurityUtils.getUser();
Date currentDate = DateUtil.date();
if (createUserName == null) {
String name = ObjectUtil.isNull(user) ? "未获取" : StrUtil.isBlank(user.getName()) ? user.getUsername() : user.getName();
setFieldValByName("createUserName", name, metaObject);
}
if (createUserId == null) {
Long userId = ObjectUtil.isNull(user) ? null : user.getId();
setFieldValByName("createUserId", userId, metaObject);
}
if (createTime == null) {
setFieldValByName("createTime", currentDate, metaObject);
}
if (isDeteled == null) {
setFieldValByName("isDeleted", Constant.BYTE_NO, metaObject);
}
if (isUse == null) {
setFieldValByName("isUse", Constant.BYTE_YES, metaObject);
}
}
/**
* 修改操作自动填充
*
* @author:
* @param:
* @return:
* @date:
*/
@Override
public void updateFill(MetaObject metaObject) {
Object updateUserName = getFieldValByName("updateUserName", metaObject);
Object updateUserId = getFieldValByName("updateUserId", metaObject);
Object updateTime = getFieldValByName("updateTime", metaObject);
SictUser user = SecurityUtils.getUser();
DateTime currentDate = DateUtil.date();
if (updateUserName == null) {
String name = ObjectUtil.isNull(user) ? "未获取" : StrUtil.isBlank(user.getName()) ? user.getUsername() : user.getName();
setFieldValByName("updateUserName", name, metaObject);
}
if (updateUserId == null) {
Long userId = ObjectUtil.isNull(user) ? null : user.getId();
setFieldValByName("updateUserId", userId, metaObject);
}
if (updateTime == null) {
setFieldValByName("updateTime", currentDate, metaObject);
}
}
}
package cn.sh.stc.sict.cloud.common.data.mybatis;
import cn.sh.stc.sict.cloud.common.data.datascope.DataScopeInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
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 javax.sql.DataSource;
/**
* @Description
* @Author
* @Date
*/
@Configuration
@ConditionalOnClass(MybatisPlusConfig.class)
@MapperScan(basePackages = {"cn.sh.stc.sict.**.dao", "com.smarthealth.themestore.*.dao"})
public class MybatisPlusConfig {
/**
* 分页插件
*
* @return PaginationInterceptor
*/
@Bean
@ConditionalOnMissingBean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
// paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
/**
* 数据权限插件
*
* @param dataSource 数据源
* @return DataScopeInterceptor
*/
@Bean
@ConditionalOnMissingBean
public DataScopeInterceptor dataScopeInterceptor(DataSource dataSource) {
return new DataScopeInterceptor(dataSource);
}
}
package cn.sh.stc.sict.cloud.common.data.util;
import lombok.experimental.UtilityClass;
/**
* @Description 系统参数配置获取类
* @Author
* @Date
*/
@UtilityClass
public class ConfigUtils {
}
package cn.sh.stc.sict.cloud.common.data.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
public class HySearchWrapperUtil {
public static void setWrapper(LambdaQueryWrapper wrapper, String param) {
StringBuilder sb = new StringBuilder();
if (StrUtil.isNotBlank(param) && JSONUtil.isJsonObj(param)) {
sb.append("where 1 = 1");
JSONObject json = JSONUtil.parseObj(param);
json.forEach((k, v) -> {
sb.append(" and ");
sb.append(k);
sb.append(" like '%");
sb.append(v);
sb.append("%'");
});
wrapper.last(sb.toString());
}
}
}
package cn.sh.stc.sict.cloud.common.data.util;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.data.dto.EventInfo;
import lombok.experimental.UtilityClass;
/**
* 联盟链工具类
* @author admin
*/
@UtilityClass
public class UnionChainUtil {
/**
* 存储一般事件
*
* @param event
*/
public String saveEvent(String url, EventInfo event) {
String body = HttpRequest.post(url)
.body(JSONUtil.toJsonStr(event))
.execute()
.body();
System.out.println(body);
return body;
}
}
package cn.sh.stc.sict.cloud.common.data.util;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import org.springframework.data.redis.core.RedisTemplate;
/**
* @Description 验证码校验工具类
* @Author
* @Date
*/
public class ValidateCodeUtil {
/**
* 从redis取出验证码并验证
*/
public static boolean validateCode(RedisTemplate redisTemplate, String code, String phone) {
String key = RedisCacheConstant.SICT_PHONE_CODE_KEY + phone;
if (!redisTemplate.hasKey(key)) {
return false;
}
Object codeObj = redisTemplate.opsForValue().get(key);
if (codeObj == null) {
return false;
}
String savedCode = codeObj.toString();
if (StrUtil.isBlank(savedCode)) {
redisTemplate.delete(key);
return false;
}
if (!StrUtil.equals(savedCode, code)) {
return false;
}
return true;
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.sh.stc.sict.cloud.common.data.cache.RedisTemplateConfig,\
cn.sh.stc.sict.cloud.common.data.cache.RedisCacheManagerConfig,\
cn.sh.stc.sict.cloud.common.data.cache.RedisCacheAutoConfiguration,\
cn.sh.stc.sict.cloud.common.data.mybatis.MyMetaObjectHandler,\
cn.sh.stc.sict.cloud.common.data.mybatis.MybatisPlusConfig
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-common</artifactId>
<groupId>cn.sh.stc.sict</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-common-dynamic-gateway</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
This diff is collapsed.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.sh.stc.sict.cloud.common.gateway.GatewayAutoConfiguration
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment