commit
90c71c40e1
295 changed files with 16902 additions and 0 deletions
@ -0,0 +1,8 @@ |
|||||
|
.idea/ |
||||
|
logs/ |
||||
|
target/ |
||||
|
gyoa-java.iml |
||||
|
*.http |
||||
|
*.env.json |
||||
|
*.json |
||||
|
/src/test/ |
@ -0,0 +1,223 @@ |
|||||
|
<?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> |
||||
|
|
||||
|
<groupId>com.qs</groupId> |
||||
|
<artifactId>questionnaire</artifactId> |
||||
|
<version>1.0.0RELEASE</version> |
||||
|
|
||||
|
<parent> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-parent</artifactId> |
||||
|
<version>2.6.4</version> |
||||
|
</parent> |
||||
|
|
||||
|
<properties> |
||||
|
<spring-boot.version>2.6.4</spring-boot.version> |
||||
|
<maven.compiler.source>8</maven.compiler.source> |
||||
|
<maven.compiler.target>8</maven.compiler.target> |
||||
|
<xxlJob.version>2.3.0</xxlJob.version> |
||||
|
<hutool.version>5.7.19</hutool.version> |
||||
|
<jwt.version>3.10.3</jwt.version> |
||||
|
<httpclient.version>4.5.7</httpclient.version> |
||||
|
<commons-httpclient.version>3.1</commons-httpclient.version> |
||||
|
<fastjson.version>1.2.49</fastjson.version> |
||||
|
<mybatis-plus.version>3.4.1</mybatis-plus.version> |
||||
|
<skipTests>true</skipTests> |
||||
|
<wx.java.version>4.2.0</wx.java.version> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>cn.hutool</groupId> |
||||
|
<artifactId>hutool-all</artifactId> |
||||
|
<version>${hutool.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter</artifactId> |
||||
|
<exclusions> |
||||
|
<exclusion> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-logging</artifactId> |
||||
|
</exclusion> |
||||
|
</exclusions> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||
|
<exclusions> |
||||
|
<exclusion> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-tomcat</artifactId> |
||||
|
</exclusion> |
||||
|
</exclusions> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-undertow</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-data-redis</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-security</artifactId> |
||||
|
<exclusions> |
||||
|
<exclusion> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-logging</artifactId> |
||||
|
</exclusion> |
||||
|
</exclusions> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-aop</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-validation</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.auth0</groupId> |
||||
|
<artifactId>java-jwt</artifactId> |
||||
|
<version>${jwt.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-log4j2</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.alibaba</groupId> |
||||
|
<artifactId>fastjson</artifactId> |
||||
|
<version>${fastjson.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.github.pagehelper</groupId> |
||||
|
<artifactId>pagehelper-spring-boot-starter</artifactId> |
||||
|
<version>1.4.1</version> |
||||
|
<exclusions> |
||||
|
<exclusion> |
||||
|
<groupId>org.mybatis</groupId> |
||||
|
<artifactId>mybatis-spring</artifactId> |
||||
|
</exclusion> |
||||
|
<exclusion> |
||||
|
<groupId>org.mybatis</groupId> |
||||
|
<artifactId>mybatis</artifactId> |
||||
|
</exclusion> |
||||
|
<exclusion> |
||||
|
<groupId>com.github.jsqlparser</groupId> |
||||
|
<artifactId>jsqlparser</artifactId> |
||||
|
</exclusion> |
||||
|
</exclusions> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.baomidou</groupId> |
||||
|
<artifactId>mybatis-plus-boot-starter</artifactId> |
||||
|
<version>${mybatis-plus.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>mysql</groupId> |
||||
|
<artifactId>mysql-connector-java</artifactId> |
||||
|
<version>8.0.15</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.projectlombok</groupId> |
||||
|
<artifactId>lombok</artifactId> |
||||
|
<version>1.18.12</version> |
||||
|
<scope>compile</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.apache.commons</groupId> |
||||
|
<artifactId>commons-lang3</artifactId> |
||||
|
<version>3.12.0</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.github.binarywang</groupId> |
||||
|
<artifactId>weixin-java-mp</artifactId> |
||||
|
<version>${wx.java.version}</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>junit</groupId> |
||||
|
<artifactId>junit</artifactId> |
||||
|
<version>RELEASE</version> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.github.shalousun</groupId> |
||||
|
<artifactId>smart-doc</artifactId> |
||||
|
<version>2.4.0</version> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
</dependencies> |
||||
|
|
||||
|
<build> |
||||
|
<finalName>serve</finalName> |
||||
|
<plugins> |
||||
|
<plugin> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
|
<version>${spring-boot.version}</version> |
||||
|
</plugin> |
||||
|
</plugins> |
||||
|
<!-- <resources>--> |
||||
|
<!-- <resource>--> |
||||
|
<!-- <directory>src/main/resources</directory>--> |
||||
|
<!-- <excludes>--> |
||||
|
<!-- <exclude>*.yml</exclude>--> |
||||
|
<!-- </excludes>--> |
||||
|
<!-- </resource>--> |
||||
|
<!-- </resources>--> |
||||
|
</build> |
||||
|
<repositories> |
||||
|
<repository> |
||||
|
<id>public</id> |
||||
|
<name>aliyun nexus</name> |
||||
|
<url>https://maven.aliyun.com/repository/public/</url> |
||||
|
<releases> |
||||
|
<enabled>true</enabled> |
||||
|
</releases> |
||||
|
</repository> |
||||
|
</repositories> |
||||
|
|
||||
|
<pluginRepositories> |
||||
|
<pluginRepository> |
||||
|
<id>public</id> |
||||
|
<name>aliyun nexus</name> |
||||
|
<url>https://maven.aliyun.com/repository/public/</url> |
||||
|
<releases> |
||||
|
<enabled>true</enabled> |
||||
|
</releases> |
||||
|
<snapshots> |
||||
|
<enabled>false</enabled> |
||||
|
</snapshots> |
||||
|
</pluginRepository> |
||||
|
</pluginRepositories> |
||||
|
</project> |
@ -0,0 +1,51 @@ |
|||||
|
package com.qs.serve; |
||||
|
|
||||
|
import com.qs.serve.common.config.DevEnvironmentConfig; |
||||
|
import org.springframework.boot.CommandLineRunner; |
||||
|
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
import org.springframework.boot.builder.SpringApplicationBuilder; |
||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
||||
|
import org.springframework.cache.annotation.EnableCaching; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.scheduling.annotation.EnableAsync; |
||||
|
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import javax.servlet.ServletContext; |
||||
|
import javax.servlet.ServletException; |
||||
|
import java.util.TimeZone; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
@EnableAsync |
||||
|
@EnableScheduling |
||||
|
@EnableTransactionManagement |
||||
|
@EnableCaching |
||||
|
@SpringBootApplication |
||||
|
public class Application extends SpringBootServletInitializer { |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
DevEnvironmentConfig.openDevEnv(true); |
||||
|
SpringApplication.run(Application.class,args); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onStartup(ServletContext servletContext) throws ServletException { |
||||
|
super.onStartup(servletContext); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { |
||||
|
return builder.sources(Application.class); |
||||
|
} |
||||
|
|
||||
|
@PostConstruct |
||||
|
void started() { |
||||
|
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import org.springframework.boot.web.servlet.ServletContextInitializer; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
import javax.servlet.ServletContext; |
||||
|
import javax.servlet.ServletException; |
||||
|
import javax.servlet.SessionTrackingMode; |
||||
|
import java.util.Collections; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 禁用jsessionid |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/11 |
||||
|
*/ |
||||
|
@Configuration |
||||
|
public class CustomServletContextInitializer implements ServletContextInitializer { |
||||
|
|
||||
|
@Override |
||||
|
public void onStartup(ServletContext servletContext) throws ServletException { |
||||
|
servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE)); |
||||
|
} |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/11 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class DevEnvironmentConfig { |
||||
|
|
||||
|
private static Boolean devEnv = null; |
||||
|
public static void openDevEnv(Boolean open){ |
||||
|
if(devEnv==null){devEnv = open;} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static boolean isDev(){ |
||||
|
if(devEnv==null){ |
||||
|
return false; |
||||
|
} |
||||
|
return devEnv; |
||||
|
} |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
|
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* @Author: YenHex |
||||
|
* @Date: 2021/3/3 |
||||
|
* @Version: 1.0 |
||||
|
**/ |
||||
|
@Getter |
||||
|
public class JwtConfig { |
||||
|
|
||||
|
/** |
||||
|
* 单位分钟 |
||||
|
*/ |
||||
|
private final Integer expire = 60; |
||||
|
|
||||
|
private final String iss = "KP_ISS"; |
||||
|
|
||||
|
private final String secret = "QiShenAa18n9VUcCxaSeSqLtFvsSCaRoVPKtBLaYxB0"; |
||||
|
|
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.annotation.DbType; |
||||
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; |
||||
|
import com.qs.serve.common.framework.mybatis.handler.SysMetaHandler; |
||||
|
import com.qs.serve.common.framework.mybatis.handler.SysTenantHandler; |
||||
|
import org.mybatis.spring.annotation.MapperScan; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@MapperScan("com.qs.serve.modules.*.mapper") |
||||
|
@Configuration(proxyBeanMethods = false) |
||||
|
public class MyBatisConfig { |
||||
|
|
||||
|
@Bean |
||||
|
public MybatisPlusInterceptor mybatisPlusInterceptor() { |
||||
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); |
||||
|
// 翻页拦截器
|
||||
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); |
||||
|
// 多租户、乐观锁等配置拦截
|
||||
|
interceptor.addInnerInterceptor(buildTenantHandler()); |
||||
|
// 添加防止全表更新与删除拦截器
|
||||
|
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); |
||||
|
return interceptor; |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public MetaObjectHandler sysMetaHandler(){ |
||||
|
return new SysMetaHandler(); |
||||
|
} |
||||
|
|
||||
|
public TenantLineInnerInterceptor buildTenantHandler(){ |
||||
|
String[] ignoreTable = new String[]{ |
||||
|
"sys_user", |
||||
|
"sys_user_tenant", |
||||
|
"sys_permit", |
||||
|
"sys_tenant", |
||||
|
"wx_app", |
||||
|
"sys_menu", |
||||
|
"sys_menu_permit" |
||||
|
}; |
||||
|
SysTenantHandler sysTenantHandler = new SysTenantHandler(ignoreTable); |
||||
|
return new TenantLineInnerInterceptor(sysTenantHandler); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
|
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
|
import org.springframework.cache.CacheManager; |
||||
|
import org.springframework.cache.annotation.CachingConfigurerSupport; |
||||
|
import org.springframework.cache.annotation.EnableCaching; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.data.redis.cache.RedisCacheConfiguration; |
||||
|
import org.springframework.data.redis.cache.RedisCacheManager; |
||||
|
import org.springframework.data.redis.cache.RedisCacheWriter; |
||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory; |
||||
|
import org.springframework.data.redis.core.RedisTemplate; |
||||
|
import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
||||
|
import org.springframework.data.redis.serializer.*; |
||||
|
import org.springframework.data.redis.serializer.RedisSerializationContext; |
||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer; |
||||
|
|
||||
|
import java.time.Duration; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
@EnableCaching |
||||
|
@Configuration(proxyBeanMethods = false) |
||||
|
public class RedisConfig extends CachingConfigurerSupport{ |
||||
|
|
||||
|
private static final StringRedisSerializer STRING_SERIALIZER = new StringRedisSerializer(); |
||||
|
private static final GenericJackson2JsonRedisSerializer JACKSON__SERIALIZER = new GenericJackson2JsonRedisSerializer(); |
||||
|
|
||||
|
@Bean |
||||
|
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { |
||||
|
//设置缓存过期时间
|
||||
|
RedisCacheConfiguration redisCacheCfg=RedisCacheConfiguration.defaultCacheConfig() |
||||
|
.entryTtl(Duration.ofHours(1)) |
||||
|
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(STRING_SERIALIZER)) |
||||
|
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(JACKSON__SERIALIZER)); |
||||
|
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)) |
||||
|
.cacheDefaults(redisCacheCfg) |
||||
|
.build(); |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory){ |
||||
|
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); |
||||
|
container.setConnectionFactory(connectionFactory); |
||||
|
return container; |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
@ConditionalOnMissingBean(name = "redisTemplate") |
||||
|
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){ |
||||
|
// 配置redisTemplate
|
||||
|
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); |
||||
|
redisTemplate.setConnectionFactory(factory); |
||||
|
// key序列化
|
||||
|
redisTemplate.setKeySerializer(STRING_SERIALIZER); |
||||
|
// value序列化
|
||||
|
redisTemplate.setValueSerializer(JACKSON__SERIALIZER); |
||||
|
// Hash key序列化
|
||||
|
redisTemplate.setHashKeySerializer(STRING_SERIALIZER); |
||||
|
// Hash value序列化
|
||||
|
redisTemplate.setHashValueSerializer(JACKSON__SERIALIZER); |
||||
|
redisTemplate.afterPropertiesSet(); |
||||
|
return redisTemplate; |
||||
|
} |
||||
|
} |
@ -0,0 +1,64 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import com.qs.serve.common.config.properties.PermitProperties; |
||||
|
import com.qs.serve.common.framework.security.filter.SecurityRequestFilter; |
||||
|
import com.qs.serve.common.framework.security.handler.SecurityAccessDeniedHandler; |
||||
|
import com.qs.serve.common.framework.security.handler.SecurityLogoutHandler; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.http.HttpMethod; |
||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; |
||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
||||
|
import org.springframework.security.config.http.SessionCreationPolicy; |
||||
|
import org.springframework.security.core.userdetails.UserDetailsService; |
||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2021/6/13 |
||||
|
*/ |
||||
|
@Configuration |
||||
|
@AllArgsConstructor |
||||
|
@EnableGlobalMethodSecurity(prePostEnabled=true) |
||||
|
public class SecurityConfig extends WebSecurityConfigurerAdapter { |
||||
|
|
||||
|
private final SecurityRequestFilter securityRequestFilter; |
||||
|
private final UserDetailsService userService; |
||||
|
private final PermitProperties permitProperties; |
||||
|
|
||||
|
@Override |
||||
|
protected void configure(HttpSecurity http) throws Exception { |
||||
|
List<String> permitUrls = new ArrayList<>(); |
||||
|
if(permitProperties.getPermits()!=null){ permitUrls.addAll(permitProperties.getPermits()); } |
||||
|
if(permitProperties.getTenants()!=null){ permitUrls.addAll(permitProperties.getTenants()); } |
||||
|
permitUrls = permitUrls.stream().distinct().collect(Collectors.toList()); |
||||
|
String[] permit_urls = new String[permitUrls.size()]; |
||||
|
permitUrls.toArray(permit_urls); |
||||
|
http.csrf().disable(); |
||||
|
http.authorizeRequests() |
||||
|
.antMatchers(HttpMethod.OPTIONS.toString()).permitAll() |
||||
|
.antMatchers(permit_urls).permitAll() |
||||
|
//.antMatchers().permitAll() //测试用
|
||||
|
.anyRequest().authenticated(); |
||||
|
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER); |
||||
|
http.logout() |
||||
|
.logoutUrl("/portal/logout") |
||||
|
.addLogoutHandler(new SecurityLogoutHandler()) |
||||
|
.invalidateHttpSession(true); |
||||
|
http.headers().cacheControl(); |
||||
|
http.addFilterBefore(securityRequestFilter, UsernamePasswordAuthenticationFilter.class); |
||||
|
http.exceptionHandling().accessDeniedHandler(new SecurityAccessDeniedHandler()); |
||||
|
//http.formLogin().failureHandler(new SecurityAuthenticationFailureHandler());
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public UserDetailsService userDetailsService() { |
||||
|
return userService; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import com.qs.serve.common.framework.interceptor.ApiAuthInterceptor; |
||||
|
import com.qs.serve.common.framework.interceptor.LimitSubmitInterceptor; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.cors.CorsConfiguration; |
||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
||||
|
import org.springframework.web.filter.CorsFilter; |
||||
|
import org.springframework.web.multipart.MultipartResolver; |
||||
|
import org.springframework.web.multipart.commons.CommonsMultipartResolver; |
||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
@AllArgsConstructor |
||||
|
@Configuration(proxyBeanMethods = false) |
||||
|
public class SpringMvcConfig implements WebMvcConfigurer { |
||||
|
|
||||
|
private final LimitSubmitInterceptor limitSubmitInterceptor; |
||||
|
private final ApiAuthInterceptor apiAuthInterceptor; |
||||
|
|
||||
|
@Override |
||||
|
public void addInterceptors(InterceptorRegistry registry) { |
||||
|
//注册LimitSubmitInterceptor拦截器
|
||||
|
registry.addInterceptor(apiAuthInterceptor) |
||||
|
.addPathPatterns("/api/**") |
||||
|
.excludePathPatterns("/api/wx/login/*","/api/dev/**"); |
||||
|
registry.addInterceptor(limitSubmitInterceptor) |
||||
|
.addPathPatterns("/**"); |
||||
|
} |
||||
|
|
||||
|
/*@Override |
||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) { |
||||
|
registry.addResourceHandler("/static/**") |
||||
|
.addResourceLocations("classpath:/static/"); |
||||
|
}*/ |
||||
|
|
||||
|
@Bean |
||||
|
public CorsFilter corsFilter() { |
||||
|
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); |
||||
|
final CorsConfiguration corsConfiguration = new CorsConfiguration(); |
||||
|
/*是否允许请求带有验证信息*/ |
||||
|
corsConfiguration.setAllowCredentials(true); |
||||
|
/*允许访问的客户端域名*/ |
||||
|
corsConfiguration.addAllowedOrigin("*"); |
||||
|
/*允许服务端访问的客户端请求头*/ |
||||
|
corsConfiguration.addAllowedHeader("*"); |
||||
|
/*允许访问的方法名,GET POST等*/ |
||||
|
corsConfiguration.addAllowedMethod("*"); |
||||
|
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); |
||||
|
return new CorsFilter(urlBasedCorsConfigurationSource); |
||||
|
} |
||||
|
|
||||
|
//@Bean
|
||||
|
public MultipartResolver multipartResolver(){ |
||||
|
CommonsMultipartResolver resolver = new CommonsMultipartResolver(); |
||||
|
resolver.setMaxInMemorySize(5120); |
||||
|
resolver.setMaxInMemorySize(300 * 1024 * 1024); |
||||
|
resolver.setDefaultEncoding("UTF-8"); |
||||
|
return resolver; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import com.qs.serve.common.util.ThreadsUtils; |
||||
|
import org.apache.commons.lang3.concurrent.BasicThreadFactory; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
||||
|
|
||||
|
import java.util.concurrent.ScheduledExecutorService; |
||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor; |
||||
|
import java.util.concurrent.ThreadPoolExecutor; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 线程池配置 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
@Configuration |
||||
|
public class ThreadPoolConfig { |
||||
|
|
||||
|
/** 核心线程池大小 */ |
||||
|
private final int corePoolSize = 50; |
||||
|
|
||||
|
|
||||
|
@Bean(name = "threadPoolTaskExecutor") |
||||
|
public ThreadPoolTaskExecutor threadPoolTaskExecutor() { |
||||
|
// 最大可创建的线程数
|
||||
|
int maxPoolSize = 200; |
||||
|
// 队列最大长度
|
||||
|
int queueCapacity = 1000; |
||||
|
// 线程池维护线程所允许的空闲时间
|
||||
|
int keepAliveSeconds = 300; |
||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
||||
|
executor.setMaxPoolSize(maxPoolSize); |
||||
|
executor.setCorePoolSize(corePoolSize); |
||||
|
executor.setQueueCapacity(queueCapacity); |
||||
|
executor.setKeepAliveSeconds(keepAliveSeconds); |
||||
|
// 线程池对拒绝任务(无线程可用)的处理策略
|
||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
||||
|
return executor; |
||||
|
} |
||||
|
|
||||
|
/** 执行周期性或定时任务 */ |
||||
|
@Bean(name = "scheduledExecutorService") |
||||
|
protected ScheduledExecutorService scheduledExecutorService() { |
||||
|
return new ScheduledThreadPoolExecutor(corePoolSize, |
||||
|
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) { |
||||
|
@Override |
||||
|
protected void afterExecute(Runnable r, Throwable t) { |
||||
|
super.afterExecute(r, t); |
||||
|
ThreadsUtils.printException(r, t); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
package com.qs.serve.common.config.properties; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @Author: YenHex |
||||
|
* @Date: 2021/3/3 |
||||
|
* @Version: 1.0 |
||||
|
**/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "project.ignore-url") |
||||
|
public class PermitProperties { |
||||
|
|
||||
|
/** |
||||
|
* 可通过路径(适用于回调场景、无拦截场景等) |
||||
|
*/ |
||||
|
private List<String> permits = new ArrayList<>(); |
||||
|
|
||||
|
/** |
||||
|
* 默认租户拦截(适用于无需登录接口,但有租户拦截) |
||||
|
*/ |
||||
|
private List<String> tenants = new ArrayList<>(); |
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.qs.serve.common.config.properties; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/7 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "spring.redis") |
||||
|
public class RedisProperties { |
||||
|
|
||||
|
private String host; |
||||
|
|
||||
|
private Integer port; |
||||
|
|
||||
|
private String password; |
||||
|
|
||||
|
private Integer database; |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
package com.qs.serve.common.config.properties; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/14 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "project.upload") |
||||
|
public class UploadProperties { |
||||
|
|
||||
|
private String tempPath; |
||||
|
|
||||
|
private String proxyUrl; |
||||
|
|
||||
|
private String logicalPath; |
||||
|
|
||||
|
} |
@ -0,0 +1,210 @@ |
|||||
|
package com.qs.serve.common.framework.aop; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.qs.serve.common.framework.manager.AsyncFactory; |
||||
|
import com.qs.serve.common.framework.manager.AsyncManager; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.common.model.annotation.SysLog; |
||||
|
import com.qs.serve.common.model.consts.GySysConst; |
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
import com.qs.serve.common.util.ServletUtils; |
||||
|
import com.qs.serve.modules.sys.entity.SysOperationLog; |
||||
|
import com.qs.serve.modules.sys.entity.SysUser; |
||||
|
import com.qs.serve.modules.sys.service.SysUserService; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.aspectj.lang.JoinPoint; |
||||
|
import org.aspectj.lang.Signature; |
||||
|
import org.aspectj.lang.annotation.*; |
||||
|
import org.aspectj.lang.reflect.MethodSignature; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.HttpMethod; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.validation.BindingResult; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
import org.springframework.web.servlet.HandlerMapping; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.lang.reflect.Method; |
||||
|
import java.util.Collection; |
||||
|
import java.util.Iterator; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* 操作日志织入 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/8 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Aspect |
||||
|
@Component |
||||
|
public class SysLogAspect { |
||||
|
|
||||
|
@Autowired |
||||
|
private SysUserService sysUserService; |
||||
|
|
||||
|
ThreadLocal<Long> startTimeIndex = new ThreadLocal<>(); |
||||
|
|
||||
|
@Pointcut("@annotation(com.qs.serve.common.model.annotation.SysLog)") |
||||
|
public void logPointCut() {} |
||||
|
|
||||
|
@Before("@annotation(com.qs.serve.common.model.annotation.SysLog)") |
||||
|
public void doBefore() { |
||||
|
startTimeIndex.set(System.currentTimeMillis()); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理完请求后执行 |
||||
|
* @param joinPoint 切点 |
||||
|
*/ |
||||
|
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") |
||||
|
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) { |
||||
|
handleLog(joinPoint, null, jsonResult); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 拦截异常操作 |
||||
|
* @param joinPoint 切点 |
||||
|
* @param e 异常 |
||||
|
*/ |
||||
|
@AfterThrowing(value = "logPointCut()", throwing = "e") |
||||
|
public void doAfterThrowing(JoinPoint joinPoint, Exception e) { |
||||
|
handleLog(joinPoint, e, null); |
||||
|
} |
||||
|
|
||||
|
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) { |
||||
|
try { |
||||
|
// 获得注解
|
||||
|
SysLog controllerLog = getAnnotationLog(joinPoint); |
||||
|
if (controllerLog == null) { |
||||
|
return; |
||||
|
} |
||||
|
HttpServletRequest request = ServletUtils.getRequest(); |
||||
|
// 获取当前的用户
|
||||
|
LoginUser loginUser = AuthContextUtils.getLoginUser(false); |
||||
|
SysOperationLog operLog = new SysOperationLog(); |
||||
|
operLog.setReqIp(ServletUtils.getIp(request)); |
||||
|
operLog.setReqMethod(request.getMethod()); |
||||
|
operLog.setJsonResult(JSON.toJSONString(jsonResult)); |
||||
|
operLog.setReqUrl(request.getRequestURI()); |
||||
|
operLog.setUserAgent(request.getHeader(GySysConst.USER_AGENT_PROP)); |
||||
|
if (loginUser != null) { |
||||
|
operLog.setUserId(loginUser.getUserId()); |
||||
|
operLog.setUserType(loginUser.getTypeFlag().getCode()); |
||||
|
SysUser sysUser = sysUserService.getById(loginUser.getUserId()); |
||||
|
if(sysUser!=null){ |
||||
|
operLog.setCreatorName(sysUser.getName()); |
||||
|
} |
||||
|
} |
||||
|
if (e != null) { |
||||
|
operLog.setErrMsg(StringUtils.substring(e.getMessage(), 0, 2500)); |
||||
|
} |
||||
|
//耗时
|
||||
|
Long startTime = startTimeIndex.get(); |
||||
|
if(startTime!=null){ |
||||
|
operLog.setElapsedTime(System.currentTimeMillis()-startTime); |
||||
|
}else { |
||||
|
operLog.setElapsedTime(0L); |
||||
|
} |
||||
|
String className = joinPoint.getTarget().getClass().getName(); |
||||
|
String methodName = joinPoint.getSignature().getName(); |
||||
|
operLog.setCodeMethod(className + "." + methodName + "()"); |
||||
|
// 处理设置注解上的参数
|
||||
|
getControllerMethodDescription(joinPoint, controllerLog, operLog); |
||||
|
operLog.setTenantId(AuthContextUtils.getTenant()); |
||||
|
// 保存数据库
|
||||
|
AsyncManager.me().execute(AsyncFactory.saveOperationLog(operLog)); |
||||
|
} catch (Exception exp) { |
||||
|
// 记录本地异常日志
|
||||
|
log.error("==前置通知异常==\n异常信息:{}", exp.getMessage()); |
||||
|
exp.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取注解中对方法的描述信息 |
||||
|
* @param sysLog 日志 |
||||
|
* @param operationLog 操作日志 |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
public void getControllerMethodDescription(JoinPoint joinPoint, SysLog sysLog, SysOperationLog operationLog) throws Exception { |
||||
|
operationLog.setBizType(sysLog.biz().getValue()); |
||||
|
operationLog.setInterType(sysLog.inter().name()); |
||||
|
operationLog.setTitle(sysLog.title()); |
||||
|
operationLog.setModule(sysLog.module().getVale()); |
||||
|
operationLog.setOptDesc(sysLog.desc()); |
||||
|
if (sysLog.saveReqParam()) { |
||||
|
setRequestValue(joinPoint, operationLog); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取请求的参数,放到log中 |
||||
|
* @param operationLog 操作日志 |
||||
|
* @throws Exception 异常 |
||||
|
*/ |
||||
|
private void setRequestValue(JoinPoint joinPoint, SysOperationLog operationLog) throws Exception { |
||||
|
String requestMethod = operationLog.getReqMethod(); |
||||
|
if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { |
||||
|
String params = argsArrayToString(joinPoint.getArgs()); |
||||
|
operationLog.setReqParam(StringUtils.substring(params, 0, 2500)); |
||||
|
} else { |
||||
|
Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); |
||||
|
operationLog.setReqParam(StringUtils.substring(paramsMap.toString(), 0, 2500)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** 是否存在注解,如果存在就获取 */ |
||||
|
private SysLog getAnnotationLog(JoinPoint joinPoint){ |
||||
|
Signature signature = joinPoint.getSignature(); |
||||
|
MethodSignature methodSignature = (MethodSignature) signature; |
||||
|
Method method = methodSignature.getMethod(); |
||||
|
if (method != null) { |
||||
|
return method.getAnnotation(SysLog.class); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 参数拼装 |
||||
|
*/ |
||||
|
private String argsArrayToString(Object[] paramsArray) { |
||||
|
String params = ""; |
||||
|
if (paramsArray != null && paramsArray.length > 0) { |
||||
|
for (int i = 0; i < paramsArray.length; i++) { |
||||
|
if (paramsArray[i]!=null && !isFilterObject(paramsArray[i])) { |
||||
|
Object jsonObj = JSON.toJSON(paramsArray[i]); |
||||
|
params += jsonObj.toString() + " "; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return params.trim(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否需要过滤的对象。 |
||||
|
* @param o 对象信息。 |
||||
|
* @return 如果是需要过滤的对象,则返回true;否则返回false。 |
||||
|
*/ |
||||
|
@SuppressWarnings("rawtypes") |
||||
|
public boolean isFilterObject(final Object o) { |
||||
|
Class<?> clazz = o.getClass(); |
||||
|
if (clazz.isArray()) { |
||||
|
return clazz.getComponentType().isAssignableFrom(MultipartFile.class); |
||||
|
} else if (Collection.class.isAssignableFrom(clazz)) { |
||||
|
Collection collection = (Collection) o; |
||||
|
for (Iterator iter = collection.iterator(); iter.hasNext(); ) { |
||||
|
return iter.next() instanceof MultipartFile; |
||||
|
} |
||||
|
} else if (Map.class.isAssignableFrom(clazz)) { |
||||
|
Map map = (Map) o; |
||||
|
for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) { |
||||
|
Map.Entry entry = (Map.Entry) iter.next(); |
||||
|
return entry.getValue() instanceof MultipartFile; |
||||
|
} |
||||
|
} |
||||
|
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse |
||||
|
|| o instanceof BindingResult; |
||||
|
} |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
package com.qs.serve.common.framework.exception; |
||||
|
|
||||
|
/** |
||||
|
* @author JcYen |
||||
|
* @date 2020/6/11 |
||||
|
* @version 1.0 |
||||
|
*/ |
||||
|
public abstract class BaseException extends RuntimeException { |
||||
|
|
||||
|
public BaseException(String message){ |
||||
|
super(message); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 错误代码 |
||||
|
* @return |
||||
|
*/ |
||||
|
public abstract int getCode(); |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.qs.serve.common.framework.exception; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
/** |
||||
|
* @author JcYen |
||||
|
* @Date 2020/6/11 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
public class BusinessException extends BaseException implements Serializable { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private Integer status; |
||||
|
|
||||
|
public BusinessException(String message,Integer status) { |
||||
|
super(message); |
||||
|
this.status = status; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getCode() { |
||||
|
return status; |
||||
|
} |
||||
|
} |
@ -0,0 +1,118 @@ |
|||||
|
package com.qs.serve.common.framework.exception; |
||||
|
|
||||
|
import com.qs.serve.common.config.DevEnvironmentConfig; |
||||
|
import com.qs.serve.common.model.dto.R; |
||||
|
import com.qs.serve.common.model.enums.HttpCode; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.dao.DuplicateKeyException; |
||||
|
import org.springframework.http.converter.HttpMessageNotWritableException; |
||||
|
import org.springframework.security.access.AccessDeniedException; |
||||
|
import org.springframework.security.authentication.BadCredentialsException; |
||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.validation.BindException; |
||||
|
import org.springframework.web.HttpRequestMethodNotSupportedException; |
||||
|
import org.springframework.web.bind.MethodArgumentNotValidException; |
||||
|
import org.springframework.web.bind.annotation.ControllerAdvice; |
||||
|
import org.springframework.web.bind.annotation.ExceptionHandler; |
||||
|
import org.springframework.web.bind.annotation.ResponseBody; |
||||
|
|
||||
|
import java.sql.SQLIntegrityConstraintViolationException; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @Author JcYen |
||||
|
* @Date 2019/6/7 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
@ControllerAdvice |
||||
|
public class UnifiedExceptionHandler { |
||||
|
|
||||
|
|
||||
|
@ExceptionHandler(value = BusinessException.class) |
||||
|
@ResponseBody |
||||
|
public R handleBindException(BusinessException e) { |
||||
|
return new R(e.getCode(),e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler(value = NullPointerException.class) |
||||
|
@ResponseBody |
||||
|
public R handleBindException(NullPointerException e) { |
||||
|
e.printStackTrace(); |
||||
|
return R.error("数据不存在或被移除"); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
AccessDeniedException.class |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handleAccessException(AccessDeniedException e) { |
||||
|
HttpCode hc = HttpCode.FORBIDDEN_403; |
||||
|
return new R(hc.getCode(),hc.getMsg()); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
UsernameNotFoundException.class, |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handlePrintMsgException(UsernameNotFoundException e) { |
||||
|
return R.error(); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
BadCredentialsException.class, |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handlePrintMsgException(Exception e) { |
||||
|
log.warn(e.getMessage()); |
||||
|
HttpCode hc = HttpCode.LOGIN_ERR_1; |
||||
|
return new R(hc.getCode(),hc.getMsg()); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
BindException.class, |
||||
|
MethodArgumentNotValidException.class, |
||||
|
HttpRequestMethodNotSupportedException.class |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handleDevPrintMsgException(Exception e) { |
||||
|
log.warn("参数校验异常:{}",e.getMessage()); |
||||
|
if(DevEnvironmentConfig.isDev()){return R.error(e.getMessage());} |
||||
|
return R.error(); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
DuplicateKeyException.class, |
||||
|
SQLIntegrityConstraintViolationException.class, |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handleSqlIntegrityException(Exception e) { |
||||
|
String msg = e.getMessage(); |
||||
|
e.printStackTrace(); |
||||
|
String[] tmps = msg.split("\\n"); |
||||
|
String msg2 = tmps.length>1?tmps[1]:null; |
||||
|
return new R(500,"数据库拦截"+(msg2==null?"":" : "+msg2)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 强制运行写入成功 |
||||
|
* @param e |
||||
|
* @return |
||||
|
*/ |
||||
|
@ExceptionHandler(value = HttpMessageNotWritableException.class) |
||||
|
@ResponseBody |
||||
|
public R handleMsgException(HttpMessageNotWritableException e) { |
||||
|
return R.ok(); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler(value = Exception.class) |
||||
|
@ResponseBody |
||||
|
public R handleException(Exception e) { |
||||
|
log.error("Servlet异常\n异常类型:{}\n异常信息:{}\n异常体:",e.getClass().getSimpleName(),e.getMessage(),e); |
||||
|
if(DevEnvironmentConfig.isDev()){return R.error(e.getMessage());} |
||||
|
return R.error(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,60 @@ |
|||||
|
package com.qs.serve.common.framework.interceptor; |
||||
|
|
||||
|
import com.qs.serve.common.framework.redis.RedisService; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUserDTO; |
||||
|
import com.qs.serve.common.model.consts.GySysConst; |
||||
|
import com.qs.serve.common.model.consts.RedisCacheKeys; |
||||
|
import com.qs.serve.common.util.JsonUtil; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
||||
|
import org.springframework.security.core.context.SecurityContextHolder; |
||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; |
||||
|
import org.springframework.web.servlet.HandlerInterceptor; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* API接口身份拦截器 |
||||
|
* @author YenHex |
||||
|
*/ |
||||
|
@Configuration(proxyBeanMethods = false) |
||||
|
public class ApiAuthInterceptor implements HandlerInterceptor { |
||||
|
|
||||
|
|
||||
|
@Resource private RedisService redisService; |
||||
|
|
||||
|
@Override |
||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { |
||||
|
String token = request.getHeader(GySysConst.APP_TOKEN_PROP); |
||||
|
String loginUserJson = redisService.getString(RedisCacheKeys.LOGIN_KEY_WX+token); |
||||
|
if(loginUserJson!=null){ |
||||
|
LoginUser loginUser = Objects.requireNonNull(JsonUtil.jsonToPojo(loginUserJson, LoginUserDTO.class)).loginUser(); |
||||
|
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); |
||||
|
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); |
||||
|
SecurityContextHolder.getContext().setAuthentication(authentication); |
||||
|
return true; |
||||
|
} |
||||
|
try { |
||||
|
response.setHeader("Access-Control-Allow-Origin", "*"); |
||||
|
response.setHeader("Access-Control-Allow-Credentials", "true"); |
||||
|
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"); |
||||
|
response.setHeader("Access-Control-Max-Age", "86400"); |
||||
|
response.setHeader("Access-Control-Allow-Headers", "*"); |
||||
|
response.setStatus(200); |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
response.setContentType("application/json;charset=UTF-8"); |
||||
|
response.getWriter().print("{\"status\":401,\"msg\":\"用户信息无效或过期了\"}"); |
||||
|
response.getWriter().flush(); |
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
package com.qs.serve.common.framework.interceptor; |
||||
|
|
||||
|
import com.qs.serve.common.framework.redis.RedisService; |
||||
|
import com.qs.serve.common.model.HttpResponsePrintUtil; |
||||
|
import com.qs.serve.common.model.annotation.LimitSubmit; |
||||
|
import com.qs.serve.common.util.StringUtils; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.method.HandlerMethod; |
||||
|
import org.springframework.web.servlet.HandlerInterceptor; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.lang.reflect.Method; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* 防止重复提交拦截器 |
||||
|
* @author YenHex |
||||
|
*/ |
||||
|
@Configuration(proxyBeanMethods = false) |
||||
|
public class LimitSubmitInterceptor implements HandlerInterceptor { |
||||
|
|
||||
|
public final String REPEAT_Limit_KEY = "repeatLimitKey"; |
||||
|
|
||||
|
@Resource |
||||
|
public RedisService redisService; |
||||
|
|
||||
|
@Override |
||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
||||
|
if (handler instanceof HandlerMethod) { |
||||
|
HandlerMethod handlerMethod = (HandlerMethod) handler; |
||||
|
Method method = handlerMethod.getMethod(); |
||||
|
LimitSubmit annotation = method.getAnnotation(LimitSubmit.class); |
||||
|
if (annotation != null) { |
||||
|
if (this.LimitSubmit(request, annotation)) { |
||||
|
if(StringUtils.isNotEmpty(annotation.message())){ |
||||
|
HttpResponsePrintUtil.print(response,406,annotation.message()); |
||||
|
}else { |
||||
|
HttpResponsePrintUtil.print(response,406,"系统处理中,请勿频繁操作"); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证是否重复提交由子类实现具体的防重复提交的规则 |
||||
|
* @param request 请求对象 |
||||
|
* @param annotation 防复注解 |
||||
|
* @return |
||||
|
*/ |
||||
|
public boolean LimitSubmit(HttpServletRequest request, LimitSubmit annotation) throws Exception { |
||||
|
String key = REPEAT_Limit_KEY+"_"+request.getRequestURI()+"_"+request.getRemoteHost(); |
||||
|
Object cache = redisService.get(key); |
||||
|
if(cache!=null){return true;} |
||||
|
redisService.set(key,"true",annotation.interval(), TimeUnit.MILLISECONDS); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
package com.qs.serve.common.framework.interceptor; |
||||
|
|
||||
|
import java.lang.reflect.Method; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import javax.servlet.http.HttpSession; |
||||
|
|
||||
|
import com.qs.serve.common.model.HttpResponsePrintUtil; |
||||
|
import com.qs.serve.common.model.annotation.RepeatSubmit; |
||||
|
import com.qs.serve.common.util.JsonUtil; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.method.HandlerMethod; |
||||
|
import org.springframework.web.servlet.HandlerInterceptor; |
||||
|
|
||||
|
/** |
||||
|
* 防止重复提交拦截器 |
||||
|
* @author YenHex |
||||
|
*/ |
||||
|
@Configuration(proxyBeanMethods = false) |
||||
|
public class RepeatSubmitInterceptor implements HandlerInterceptor { |
||||
|
|
||||
|
public final String REPEAT_PARAMS = "repeatParams"; |
||||
|
public final String REPEAT_TIME = "repeatTime"; |
||||
|
public final String SESSION_REPEAT_KEY = "repeatData"; |
||||
|
|
||||
|
@Override |
||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
||||
|
if (handler instanceof HandlerMethod) { |
||||
|
HandlerMethod handlerMethod = (HandlerMethod) handler; |
||||
|
Method method = handlerMethod.getMethod(); |
||||
|
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); |
||||
|
if (annotation != null) { |
||||
|
if (this.isRepeatSubmit(request, annotation)) { |
||||
|
HttpResponsePrintUtil.print(response,406,"系统正常处理,请勿重复提交"); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证是否重复提交由子类实现具体的防重复提交的规则 |
||||
|
* @param request 请求对象 |
||||
|
* @param annotation 防复注解 |
||||
|
* @return |
||||
|
*/ |
||||
|
public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation) throws Exception { |
||||
|
// 本次参数及系统时间
|
||||
|
String nowParams = JsonUtil.objectToJson(request.getParameterMap()); |
||||
|
Map<String, Object> nowDataMap = new HashMap<String, Object>(); |
||||
|
nowDataMap.put(REPEAT_PARAMS, nowParams); |
||||
|
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); |
||||
|
// 请求地址(作为存放session的key值)
|
||||
|
String url = request.getRequestURI(); |
||||
|
HttpSession session = request.getSession(); |
||||
|
Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY); |
||||
|
if (sessionObj != null) { |
||||
|
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj; |
||||
|
if (sessionMap.containsKey(url)) { |
||||
|
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url); |
||||
|
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval())) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
Map<String, Object> sessionMap = new HashMap<>(); |
||||
|
sessionMap.put(url, nowDataMap); |
||||
|
session.setAttribute(SESSION_REPEAT_KEY, sessionMap); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断参数是否相同 |
||||
|
*/ |
||||
|
private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap) { |
||||
|
String nowParams = (String) nowMap.get(REPEAT_PARAMS); |
||||
|
String preParams = (String) preMap.get(REPEAT_PARAMS); |
||||
|
return nowParams.equals(preParams); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断两次间隔时间 |
||||
|
*/ |
||||
|
private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval) { |
||||
|
long time1 = (Long) nowMap.get(REPEAT_TIME); |
||||
|
long time2 = (Long) preMap.get(REPEAT_TIME); |
||||
|
if ((time1 - time2) < interval) { |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
package com.qs.serve.common.framework.manager; |
||||
|
|
||||
|
|
||||
|
import com.qs.serve.common.config.DevEnvironmentConfig; |
||||
|
import com.qs.serve.common.util.JsonUtil; |
||||
|
import com.qs.serve.common.util.SpringUtils; |
||||
|
import com.qs.serve.modules.sys.entity.SysOperationLog; |
||||
|
import com.qs.serve.modules.sys.mapper.SysOperationLogMapper; |
||||
|
|
||||
|
import java.util.TimerTask; |
||||
|
|
||||
|
/** |
||||
|
* 异步工厂 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
public class AsyncFactory { |
||||
|
|
||||
|
/** |
||||
|
* 操作日志记录 |
||||
|
* @param operationLog |
||||
|
* @return |
||||
|
*/ |
||||
|
public static TimerTask saveOperationLog(final SysOperationLog operationLog) { |
||||
|
return new TimerTask() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
if(DevEnvironmentConfig.isDev()){ |
||||
|
System.out.println(JsonUtil.objectToJson(operationLog)); |
||||
|
} |
||||
|
SpringUtils.getBean(SysOperationLogMapper.class).saveLog(operationLog); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,52 @@ |
|||||
|
package com.qs.serve.common.framework.manager; |
||||
|
|
||||
|
import com.qs.serve.common.util.SpringUtils; |
||||
|
import com.qs.serve.common.util.ThreadsUtils; |
||||
|
|
||||
|
import java.util.TimerTask; |
||||
|
import java.util.concurrent.ScheduledExecutorService; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 异步任务管理器 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
public class AsyncManager { |
||||
|
/** |
||||
|
* 操作延迟10毫秒 |
||||
|
*/ |
||||
|
private final int OPERATE_DELAY_TIME = 10; |
||||
|
|
||||
|
/** |
||||
|
* 异步操作任务调度线程池 |
||||
|
*/ |
||||
|
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); |
||||
|
|
||||
|
/** |
||||
|
* 单例模式 |
||||
|
*/ |
||||
|
private AsyncManager() { |
||||
|
} |
||||
|
|
||||
|
private static AsyncManager me = new AsyncManager(); |
||||
|
|
||||
|
public static AsyncManager me() { |
||||
|
return me; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执行任务 |
||||
|
* @param task 任务 |
||||
|
*/ |
||||
|
public void execute(TimerTask task) { |
||||
|
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); |
||||
|
} |
||||
|
|
||||
|
/** 停止任务线程池 */ |
||||
|
public void shutdown() { |
||||
|
ThreadsUtils.shutdownAndAwaitTermination(executor); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,161 @@ |
|||||
|
package com.qs.serve.common.framework.mvc; |
||||
|
|
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
import com.qs.serve.common.util.DateUtils; |
||||
|
import com.qs.serve.common.util.ServletUtils; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.core.annotation.Order; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import javax.servlet.*; |
||||
|
import javax.servlet.annotation.WebFilter; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletRequestWrapper; |
||||
|
import java.io.BufferedReader; |
||||
|
import java.io.ByteArrayInputStream; |
||||
|
import java.io.IOException; |
||||
|
import java.io.InputStreamReader; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
|
||||
|
/** |
||||
|
* HttpServletRequest 过滤器 |
||||
|
* 解决: request.getInputStream()只能读取一次的问题 |
||||
|
* 目标: 流可重复读 |
||||
|
* @Author YenHex |
||||
|
* @Date 2021/4/9 |
||||
|
* @Version: 1.0 |
||||
|
**/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
@WebFilter(filterName = "HttpServletRequestFilter", urlPatterns = "/") |
||||
|
@Order(10000) |
||||
|
public class HttpServletRequestFilter implements Filter{ |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public void init(FilterConfig filterConfig) throws ServletException { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { |
||||
|
RequestWrapper requestWrapper = null; |
||||
|
if(servletRequest instanceof HttpServletRequest) { |
||||
|
//过滤文件URL
|
||||
|
String url = ((HttpServletRequest) servletRequest).getRequestURI(); |
||||
|
if(!url.contains("import")&&!url.contains("upload")){ |
||||
|
requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest); |
||||
|
} |
||||
|
} |
||||
|
long startTime = System.currentTimeMillis(); |
||||
|
if(null == requestWrapper) { |
||||
|
filterChain.doFilter(servletRequest, servletResponse); |
||||
|
} else { |
||||
|
filterChain.doFilter(requestWrapper, servletResponse); |
||||
|
} |
||||
|
long endTime = System.currentTimeMillis(); |
||||
|
double diffTime = DateUtils.diffTime(startTime,endTime); |
||||
|
assert servletRequest instanceof HttpServletRequest; |
||||
|
HttpServletRequest request = (HttpServletRequest)servletRequest; |
||||
|
String tenant = request.getHeader("tenant-id"); |
||||
|
String url = request.getRequestURL().toString(); |
||||
|
String method = request.getMethod(); |
||||
|
String queryStr = request.getQueryString(); |
||||
|
String reqBody = ""; |
||||
|
if (ServletUtils.isJsonRequest(request)) { |
||||
|
reqBody = requestWrapper.getBody(); |
||||
|
} |
||||
|
StringBuffer buffer = new StringBuffer("["+method+"] "+url + " IP: "+ServletUtils.getIp(request)); |
||||
|
buffer.append("\n校区编号: "+tenant); |
||||
|
try { |
||||
|
LoginUser loginUser = AuthContextUtils.getLoginUser(false); |
||||
|
if(loginUser!=null){ |
||||
|
buffer.append("\n用户类型: "+ loginUser.getTypeFlag().getName()+" 用户ID: "+loginUser.getUserId()); |
||||
|
} |
||||
|
} catch (Exception e) {} |
||||
|
if(!StringUtils.isEmpty(queryStr)){ |
||||
|
buffer.append("\n参数: "+queryStr); |
||||
|
} |
||||
|
if(!StringUtils.isEmpty(reqBody)){ |
||||
|
buffer.append("\n请求体: "+reqBody); |
||||
|
} |
||||
|
buffer.append("\n耗时: "+diffTime+"秒"); |
||||
|
/*if(diffTime>4){ log.warn("访问速度:{}秒,接口:{},参数:{},请求体:{}",diffTime,"["+method+"] "+url,queryStr,reqBody);}*/ |
||||
|
System.out.println(buffer); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void destroy() { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/*** |
||||
|
* HttpServletRequest 包装器 |
||||
|
* 解决: request.getInputStream()只能读取一次的问题 |
||||
|
* 目标: 流可重复读 |
||||
|
*/ |
||||
|
public class RequestWrapper extends HttpServletRequestWrapper { |
||||
|
|
||||
|
/** |
||||
|
* 请求体 |
||||
|
*/ |
||||
|
private String mBody; |
||||
|
|
||||
|
public RequestWrapper(HttpServletRequest request) { |
||||
|
super(request); |
||||
|
mBody = getBody(request); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取请求体 |
||||
|
* @param request 请求 |
||||
|
* @return 请求体 |
||||
|
*/ |
||||
|
private String getBody(HttpServletRequest request) { |
||||
|
return ServletUtils.getBodyString(request); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取请求体 |
||||
|
* @return 请求体 |
||||
|
*/ |
||||
|
public String getBody() { |
||||
|
return mBody; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public BufferedReader getReader() throws IOException { |
||||
|
return new BufferedReader(new InputStreamReader(getInputStream())); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ServletInputStream getInputStream() throws IOException { |
||||
|
// 创建字节数组输入流
|
||||
|
final ByteArrayInputStream bais = new ByteArrayInputStream(mBody.getBytes(StandardCharsets.UTF_8)); |
||||
|
|
||||
|
return new ServletInputStream() { |
||||
|
@Override |
||||
|
public boolean isFinished() { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isReady() { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setReadListener(ReadListener readListener) { |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int read() throws IOException { |
||||
|
return bais.read(); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.handler; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; |
||||
|
import com.qs.serve.common.util.NanoIdUtils; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/4/11 |
||||
|
*/ |
||||
|
public class IdGeneratorHandler extends DefaultIdentifierGenerator { |
||||
|
|
||||
|
@Override |
||||
|
public String nextUUID(Object entity) { |
||||
|
return NanoIdUtils.randomNanoId(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.handler; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.ibatis.reflection.MetaObject; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
/** |
||||
|
* 自动注入列数据 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class SysMetaHandler implements MetaObjectHandler { |
||||
|
|
||||
|
@Override |
||||
|
public void insertFill(MetaObject metaObject) { |
||||
|
LoginUser loginUser = AuthContextUtils.getLoginUser(false); |
||||
|
if(loginUser!=null){ |
||||
|
this.strictInsertFill(metaObject, "createBy", () -> loginUser.getUserId(), String.class); |
||||
|
} |
||||
|
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void updateFill(MetaObject metaObject) { |
||||
|
LoginUser loginUser = AuthContextUtils.getLoginUser(false); |
||||
|
if(loginUser!=null){ |
||||
|
this.strictUpdateFill(metaObject, "updateBy", () -> loginUser.getUserId(), String.class); |
||||
|
} |
||||
|
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); |
||||
|
} |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.handler; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; |
||||
|
import com.qs.serve.common.model.consts.GySysConst; |
||||
|
import com.qs.serve.common.model.enums.HttpCode; |
||||
|
import com.qs.serve.common.util.Assert; |
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
import net.sf.jsqlparser.expression.Expression; |
||||
|
import net.sf.jsqlparser.expression.StringValue; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
/** |
||||
|
* @Author YenHex |
||||
|
* @Date 2021/5/7 |
||||
|
* @Version: 1.0 |
||||
|
**/ |
||||
|
public class SysTenantHandler implements TenantLineHandler { |
||||
|
|
||||
|
public SysTenantHandler(String[] ignoreTables){ |
||||
|
this.IGNORE_TABLES = Arrays.asList(ignoreTables); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
final private java.util.List<String> IGNORE_TABLES; |
||||
|
|
||||
|
@Override |
||||
|
public Expression getTenantId() { |
||||
|
String tenant = AuthContextUtils.getTenant(); |
||||
|
if(tenant==null){ |
||||
|
Assert.throwEx(HttpCode.LOGIN_ERR_4001); |
||||
|
} |
||||
|
return new StringValue(tenant); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getTenantIdColumn() { |
||||
|
return GySysConst.TENANT_COLUMN; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否忽略该表,默认全忽略,匹配到的不忽略 |
||||
|
* @param tableName |
||||
|
* @return |
||||
|
*/ |
||||
|
@Override |
||||
|
public boolean ignoreTable(String tableName) { |
||||
|
for (String tb : this.IGNORE_TABLES) { |
||||
|
if(tableName.equalsIgnoreCase(tb)){ |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.handler.meta; |
||||
|
|
||||
|
import cn.hutool.json.JSONUtil; |
||||
|
import org.apache.ibatis.type.BaseTypeHandler; |
||||
|
import org.apache.ibatis.type.JdbcType; |
||||
|
import org.apache.ibatis.type.MappedJdbcTypes; |
||||
|
import org.apache.ibatis.type.MappedTypes; |
||||
|
|
||||
|
import java.sql.CallableStatement; |
||||
|
import java.sql.PreparedStatement; |
||||
|
import java.sql.ResultSet; |
||||
|
import java.sql.SQLException; |
||||
|
|
||||
|
/** |
||||
|
* 存储到数据库, 将String数组转换成字符串; |
||||
|
* 从数据库获取数据, 将字符串转为LONG数组. |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@MappedTypes({String[].class}) |
||||
|
@MappedJdbcTypes({JdbcType.VARCHAR}) |
||||
|
public class JsonStringTypeHandler extends BaseTypeHandler<String[]> { |
||||
|
|
||||
|
private static String[] l = new String[]{}; |
||||
|
|
||||
|
@Override |
||||
|
public void setNonNullParameter(PreparedStatement ps, int i, |
||||
|
String[] parameter, JdbcType jdbcType) throws SQLException { |
||||
|
ps.setString(i, JSONUtil.toJsonStr(parameter)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String[] getNullableResult(ResultSet rs, String columnName) |
||||
|
throws SQLException { |
||||
|
return JSONUtil.parseArray(rs.getString(columnName)).toArray(l); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String[] getNullableResult(ResultSet rs, int columnIndex) |
||||
|
throws SQLException { |
||||
|
return JSONUtil.parseArray(rs.getString(columnIndex)).toArray(l); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String[] getNullableResult(CallableStatement cs, int columnIndex) |
||||
|
throws SQLException { |
||||
|
return JSONUtil.parseArray(cs.getString(columnIndex)).toArray(l); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,74 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.handler.meta; |
||||
|
|
||||
|
import com.qs.serve.common.util.StringUtils; |
||||
|
import org.apache.ibatis.type.BaseTypeHandler; |
||||
|
import org.apache.ibatis.type.JdbcType; |
||||
|
import org.apache.ibatis.type.MappedJdbcTypes; |
||||
|
import org.apache.ibatis.type.MappedTypes; |
||||
|
|
||||
|
import java.sql.CallableStatement; |
||||
|
import java.sql.PreparedStatement; |
||||
|
import java.sql.ResultSet; |
||||
|
import java.sql.SQLException; |
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
/** |
||||
|
* 存储到数据库, 将String数组转换成字符串; |
||||
|
* 从数据库获取数据, 将字符串转为LONG数组. |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@MappedTypes({String[].class}) |
||||
|
@MappedJdbcTypes({JdbcType.VARCHAR}) |
||||
|
public class SplitStringTypeHandler extends BaseTypeHandler<String[]> { |
||||
|
|
||||
|
private static String[] l = new String[]{}; |
||||
|
|
||||
|
@Override |
||||
|
public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException { |
||||
|
if(parameter!=null&¶meter.length>1){ |
||||
|
StringBuffer buffer = new StringBuffer(); |
||||
|
for (int i1 = 0; i1 < parameter.length; i1++) { |
||||
|
buffer.append(parameter[i1]); |
||||
|
if(i1+1<parameter.length){ |
||||
|
buffer.append(","); |
||||
|
} |
||||
|
} |
||||
|
ps.setString(i, buffer.toString()); |
||||
|
}else if (parameter!=null&¶meter.length==1){ |
||||
|
ps.setString(i, parameter[0]); |
||||
|
}else { |
||||
|
ps.setString(i, ""); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String[] getNullableResult(ResultSet rs, String columnName) throws SQLException { |
||||
|
String valueString = rs.getString(columnName); |
||||
|
return initValues(valueString); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException { |
||||
|
String valueString = rs.getString(columnIndex); |
||||
|
return initValues(valueString); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { |
||||
|
String valueString = cs.getString(columnIndex); |
||||
|
return initValues(valueString); |
||||
|
} |
||||
|
|
||||
|
private String[] initValues(String valueString){ |
||||
|
if(StringUtils.isNotEmpty(valueString)){ |
||||
|
String[] vals = valueString.split(","); |
||||
|
return Arrays.stream(vals) |
||||
|
.filter(val -> val != null && val.trim().length() > 0) |
||||
|
.toArray(String[]::new); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,115 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.join; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.qs.serve.common.framework.mybatis.join.annotations.BindEntity; |
||||
|
import com.qs.serve.common.framework.mybatis.join.enums.JoinType; |
||||
|
import com.qs.serve.common.framework.mybatis.join.model.JoinFieldData; |
||||
|
import com.qs.serve.common.util.CollectionUtil; |
||||
|
import com.qs.serve.common.util.SpringUtils; |
||||
|
import com.qs.serve.common.util.WordUtil; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import java.lang.annotation.Annotation; |
||||
|
import java.lang.reflect.Field; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/24 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class JoinUtil { |
||||
|
|
||||
|
private static Map<String, List<JoinFieldData>> CACHE_MAP = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
private static List<JoinFieldData> getJoinFields(List<?> list) { |
||||
|
if(CollectionUtil.isEmpty(list)){ |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
String className = list.get(0).getClass().getName(); |
||||
|
List<JoinFieldData> joinFieldDataList = new ArrayList<>(); |
||||
|
Class<?> clazz = null; |
||||
|
try { |
||||
|
clazz = Class.forName(className); |
||||
|
} catch (ClassNotFoundException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
if(clazz==null){return null;} |
||||
|
Field[] fields = clazz.getDeclaredFields(); |
||||
|
Field fieldJoinVal = null; |
||||
|
Field fieldSetVal = null; |
||||
|
BindEntity bindEntity = null; |
||||
|
for (Field field : fields) { |
||||
|
for (Annotation annotation : field.getAnnotations()) { |
||||
|
if(annotation instanceof BindEntity){ |
||||
|
fieldSetVal = field; |
||||
|
bindEntity = (BindEntity) annotation; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if(fieldSetVal!=null){ |
||||
|
for (Field field :fields){ |
||||
|
if(field.getName().equals(bindEntity.joinField())){ |
||||
|
fieldJoinVal = field; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if(bindEntity!=null&&fieldJoinVal!=null){ |
||||
|
JoinFieldData fieldData = new JoinFieldData(); |
||||
|
fieldData.setFieldJoinVal(fieldJoinVal); |
||||
|
fieldData.setBindEntity(bindEntity); |
||||
|
fieldData.setFieldSetVal(fieldSetVal); |
||||
|
joinFieldDataList.add(fieldData); |
||||
|
} |
||||
|
CACHE_MAP.put(className,joinFieldDataList); |
||||
|
return joinFieldDataList; |
||||
|
} |
||||
|
|
||||
|
public static void relate(List<?> list) { |
||||
|
List<JoinFieldData> joinFieldData = getJoinFields(list); |
||||
|
HashMap<String,Object> tempCache = new HashMap<>(list.size()+1); |
||||
|
for (JoinFieldData fieldData : joinFieldData) { |
||||
|
for (Object object : list) { |
||||
|
try { |
||||
|
Field fieldJoinVal = fieldData.getFieldJoinVal(); |
||||
|
Field fieldSetVal = fieldData.getFieldSetVal(); |
||||
|
BindEntity bindEntity = fieldData.getBindEntity(); |
||||
|
fieldSetVal.setAccessible(true); |
||||
|
fieldJoinVal.setAccessible(true); |
||||
|
IService<?> iService = SpringUtils.getBean(bindEntity.service()); |
||||
|
Object identity = fieldJoinVal.get(object); |
||||
|
if(identity==null){ |
||||
|
continue; |
||||
|
} |
||||
|
Object result = tempCache.get(identity.toString()); |
||||
|
if(result!=null){ |
||||
|
fieldSetVal.set(object,result); |
||||
|
continue; |
||||
|
} |
||||
|
if(bindEntity.joinType()== JoinType.List){ |
||||
|
QueryWrapper wrapper = new QueryWrapper<>(); |
||||
|
wrapper.eq(WordUtil.toLine(bindEntity.joinField()),identity); |
||||
|
result = iService.list(wrapper); |
||||
|
}else { |
||||
|
QueryWrapper wrapper = new QueryWrapper(); |
||||
|
wrapper.eq(WordUtil.toLine(bindEntity.selfField()),identity); |
||||
|
result = iService.getOne(wrapper,false); |
||||
|
} |
||||
|
fieldSetVal.set(object,result); |
||||
|
tempCache.put(identity.toString(),result); |
||||
|
} catch (IllegalAccessException e) { |
||||
|
log.warn("join 工具失败:",e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
tempCache = null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.join.annotations; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
import com.qs.serve.common.framework.mybatis.join.enums.JoinType; |
||||
|
|
||||
|
import java.lang.annotation.ElementType; |
||||
|
import java.lang.annotation.Retention; |
||||
|
import java.lang.annotation.RetentionPolicy; |
||||
|
import java.lang.annotation.Target; |
||||
|
|
||||
|
/** |
||||
|
* 实现left join |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/24 |
||||
|
*/ |
||||
|
@Target({ElementType.FIELD}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
public @interface BindEntity { |
||||
|
|
||||
|
Class<? extends IService> service(); |
||||
|
|
||||
|
/** |
||||
|
* 关联的表 |
||||
|
* @return |
||||
|
*/ |
||||
|
String joinField() default ""; |
||||
|
|
||||
|
/** |
||||
|
* 主表 |
||||
|
* @return |
||||
|
*/ |
||||
|
String selfField() default "id"; |
||||
|
|
||||
|
JoinType joinType() default JoinType.Object; |
||||
|
|
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.join.enums; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/24 |
||||
|
*/ |
||||
|
public enum JoinType { |
||||
|
|
||||
|
/** |
||||
|
* 返回类型 |
||||
|
*/ |
||||
|
Object,List |
||||
|
|
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.join.model; |
||||
|
|
||||
|
import com.qs.serve.common.framework.mybatis.join.annotations.BindEntity; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.lang.reflect.Field; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/24 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class JoinFieldData { |
||||
|
Field fieldJoinVal; |
||||
|
Field fieldSetVal; |
||||
|
BindEntity bindEntity; |
||||
|
} |
@ -0,0 +1,159 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.query; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.annotation.TableField; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
|
import com.qs.serve.common.framework.mybatis.query.model.QueryFieldData; |
||||
|
import com.qs.serve.common.framework.mybatis.query.model.QueryFieldDataValue; |
||||
|
import com.qs.serve.common.framework.mybatis.query.model.QueryType; |
||||
|
import com.qs.serve.common.framework.mybatis.query.annotations.QueryWrap; |
||||
|
import com.qs.serve.common.util.WordUtil; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.util.CollectionUtils; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import java.lang.annotation.Annotation; |
||||
|
import java.lang.reflect.Field; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
|
||||
|
/** |
||||
|
* @author JcYen |
||||
|
* @Date 2017/10/28 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class AnnotationQueryStorage { |
||||
|
|
||||
|
private static final Map<String, List<QueryFieldData>> BEAN_QUERY_FIELD = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
protected static List<QueryFieldData> getQueryFieldList(String className){ |
||||
|
List<QueryFieldData> queryFieldList = BEAN_QUERY_FIELD.get(className); |
||||
|
if(queryFieldList==null){ |
||||
|
Class<?> clazz = null; |
||||
|
try { |
||||
|
clazz = Class.forName(className); |
||||
|
} catch (ClassNotFoundException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
queryFieldList = new ArrayList<>(); |
||||
|
if(clazz==null){return queryFieldList;} |
||||
|
Field[] fields = clazz.getDeclaredFields(); |
||||
|
for (Field field : fields) { |
||||
|
Annotation[] annotations = field.getAnnotations(); |
||||
|
boolean isExist = false; |
||||
|
boolean isIgnore = false; |
||||
|
for (Annotation annotation : annotations) { |
||||
|
if(annotation instanceof QueryWrap){ |
||||
|
QueryWrap queryWrap = (QueryWrap)annotation; |
||||
|
QueryFieldData queryField= handleQueryField(queryWrap.type(),field); |
||||
|
if(queryField!=null){ |
||||
|
isExist = true; |
||||
|
queryFieldList.add(queryField); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if(annotation instanceof TableField){ |
||||
|
TableField tableField = (TableField) annotation; |
||||
|
isIgnore = tableField.exist(); |
||||
|
} |
||||
|
} |
||||
|
//不存在,添加默认
|
||||
|
if( !isExist && !isIgnore ){ |
||||
|
QueryFieldData queryField = new QueryFieldData(); |
||||
|
//系统默认使用格式。示例: userInfo -> user_info
|
||||
|
queryField.setColumnName(WordUtil.toLine(field.getName())); |
||||
|
queryField.setField(field); |
||||
|
queryField.setFieldName(field.getName()); |
||||
|
queryField.setType(QueryType.NONE); |
||||
|
queryFieldList.add(queryField); |
||||
|
} |
||||
|
} |
||||
|
BEAN_QUERY_FIELD.put(className,queryFieldList); |
||||
|
if(queryFieldList.size()==0){ |
||||
|
log.warn("无匹配的注解字段,类名:"+className); |
||||
|
} |
||||
|
} |
||||
|
return queryFieldList; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理查询列 |
||||
|
* @param queryType |
||||
|
* @param field |
||||
|
* @return |
||||
|
*/ |
||||
|
private static QueryFieldData handleQueryField(QueryType queryType, Field field){ |
||||
|
String columnName = null; |
||||
|
if(queryType!=null){ |
||||
|
QueryFieldData queryField = new QueryFieldData(); |
||||
|
if(StringUtils.isEmpty(columnName)){ |
||||
|
columnName = WordUtil.toLine(field.getName()); |
||||
|
} |
||||
|
queryField.setFieldName(field.getName()); |
||||
|
queryField.setColumnName(columnName); |
||||
|
queryField.setField(field); |
||||
|
queryField.setType(queryType); |
||||
|
return queryField; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 加载查询对象生成配置值 |
||||
|
* @param query |
||||
|
* @return |
||||
|
*/ |
||||
|
protected static List<QueryFieldDataValue> loadQueryFieldDataValues(Object query){ |
||||
|
String className = query.getClass().getName(); |
||||
|
List<QueryFieldData> dataList = AnnotationQueryStorage.getQueryFieldList(className); |
||||
|
if(!CollectionUtils.isEmpty(dataList)){ |
||||
|
List<QueryFieldDataValue> valueList = new ArrayList<>(); |
||||
|
for (QueryFieldData fieldData : dataList) { |
||||
|
Field field = fieldData.getField(); |
||||
|
field.setAccessible(true); |
||||
|
Object value = null; |
||||
|
try { |
||||
|
value = field.get(query); |
||||
|
} catch (IllegalAccessException e) { |
||||
|
log.warn("查询类字段参数异常。查询类:{},字段:{}",className,field.getName()); |
||||
|
} |
||||
|
if(value!=null){ |
||||
|
QueryFieldDataValue dataValue = new QueryFieldDataValue(fieldData); |
||||
|
//通过列条件,重新赋值(赋值查询条件和格式)
|
||||
|
dataValue.setValue(value); |
||||
|
valueList.add(dataValue); |
||||
|
} |
||||
|
} |
||||
|
return valueList; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 初始化封装包参数 |
||||
|
* @param fieldValues |
||||
|
* @param queryWrapper |
||||
|
* @param <T> |
||||
|
* @return 判断是否排序 |
||||
|
*/ |
||||
|
protected static <T> void initWrap(List<QueryFieldDataValue> fieldValues, QueryWrapper<T> queryWrapper){ |
||||
|
for (QueryFieldDataValue fieldValue : fieldValues) { |
||||
|
QueryType queryType = fieldValue.getType(); |
||||
|
Object value = fieldValue.getValue(); |
||||
|
String column = fieldValue.getColumnName(); |
||||
|
if(queryType.equals(QueryType.EQ)){ queryWrapper.eq(column,value); } |
||||
|
if(queryType.equals(QueryType.GE)){ queryWrapper.ge(column,value); } |
||||
|
if(queryType.equals(QueryType.GT)){ queryWrapper.gt(column,value); } |
||||
|
if(queryType.equals(QueryType.In)){ queryWrapper.in(column,value); } |
||||
|
if(queryType.equals(QueryType.LE)){ queryWrapper.le(column,value); } |
||||
|
if(queryType.equals(QueryType.Like)){ queryWrapper.like(column,value); } |
||||
|
if(queryType.equals(QueryType.LT)){ queryWrapper.lt(column,value); } |
||||
|
if(queryType.equals(QueryType.NE)){ queryWrapper.ne(column,value); } |
||||
|
if(queryType.equals(QueryType.RightLike)){ queryWrapper.likeRight(column,value); } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.query.annotations; |
||||
|
|
||||
|
import com.qs.serve.common.framework.mybatis.query.model.QueryType; |
||||
|
|
||||
|
import java.lang.annotation.ElementType; |
||||
|
import java.lang.annotation.Retention; |
||||
|
import java.lang.annotation.RetentionPolicy; |
||||
|
import java.lang.annotation.Target; |
||||
|
|
||||
|
/** |
||||
|
* @author JcYen |
||||
|
* @date 2020/5/26 |
||||
|
* SQL In条件注解 |
||||
|
*/ |
||||
|
@Target({ElementType.FIELD}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
public @interface QueryWrap { |
||||
|
|
||||
|
/** |
||||
|
* 列名(默认为空字符串) |
||||
|
* 空字符串,采用字段转列策略 示例: userInfo -> user_info |
||||
|
* 非空时,采用列的值 |
||||
|
*/ |
||||
|
String value() default ""; |
||||
|
|
||||
|
/** |
||||
|
* 查询类型(默认采用值相对) |
||||
|
*/ |
||||
|
QueryType type() default QueryType.EQ; |
||||
|
|
||||
|
} |
||||
|
|
@ -0,0 +1,23 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.query.model; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
import java.lang.reflect.Field; |
||||
|
|
||||
|
/** |
||||
|
* 存储DTO |
||||
|
* @author JcYen |
||||
|
* @Date 2017/10/28 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
public class QueryFieldData { |
||||
|
|
||||
|
private Field field; |
||||
|
private QueryType type; |
||||
|
private String columnName; |
||||
|
private String fieldName; |
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.query.model; |
||||
|
|
||||
|
import com.qs.serve.common.util.CopierUtil; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
/** |
||||
|
* 存储DTO |
||||
|
* @author JcYen |
||||
|
* @Date 2017/10/28 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
public class QueryFieldDataValue{ |
||||
|
|
||||
|
public QueryFieldDataValue(QueryFieldData data){ |
||||
|
CopierUtil.copy(data,this); |
||||
|
} |
||||
|
|
||||
|
private QueryType type; |
||||
|
private String columnName; |
||||
|
private String fieldName; |
||||
|
private Object value; |
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
package com.qs.serve.common.framework.mybatis.query.model; |
||||
|
|
||||
|
/** |
||||
|
* @author JcYen |
||||
|
*/ |
||||
|
public enum QueryType { |
||||
|
|
||||
|
/** |
||||
|
* 无 |
||||
|
*/ |
||||
|
NONE, |
||||
|
|
||||
|
/** |
||||
|
* 通用的equals(Integer,Long,String) |
||||
|
*/ |
||||
|
EQ, |
||||
|
NE, |
||||
|
|
||||
|
/** |
||||
|
* 比较修饰符,修饰日期,数值类型(Integer,Long,Double,BigDecimal) |
||||
|
*/ |
||||
|
LT, |
||||
|
LE, |
||||
|
GT, |
||||
|
GE, |
||||
|
|
||||
|
/** |
||||
|
* 修饰List<Long> |
||||
|
*/ |
||||
|
In, |
||||
|
NotIn, |
||||
|
|
||||
|
/** |
||||
|
* 修饰字符串 |
||||
|
*/ |
||||
|
Like, |
||||
|
RightLike, |
||||
|
NotLike, |
||||
|
|
||||
|
} |
@ -0,0 +1,309 @@ |
|||||
|
package com.qs.serve.common.framework.redis; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import org.springframework.data.redis.core.*; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import java.io.Serializable; |
||||
|
import java.util.*; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* @author JcYen |
||||
|
* @since 2022/3/4 |
||||
|
*/ |
||||
|
@Service |
||||
|
@AllArgsConstructor |
||||
|
public class RedisService { |
||||
|
|
||||
|
private RedisTemplate redisTemplate; |
||||
|
|
||||
|
private StringRedisTemplate stringRedisTemplate; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 写入缓存 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param value |
||||
|
* @return |
||||
|
*/ |
||||
|
public boolean set(final String key, Object value) { |
||||
|
boolean result = false; |
||||
|
try { |
||||
|
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
||||
|
operations.set(key, value); |
||||
|
result = true; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 写入缓存设置时效时间 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param value |
||||
|
* @return |
||||
|
*/ |
||||
|
public boolean set(final String key, Object value, int expireTime) { |
||||
|
return set(key, value, expireTime,TimeUnit.SECONDS); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 写入缓存设置时效时间 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param value |
||||
|
* @return |
||||
|
*/ |
||||
|
public boolean set(final String key, Object value, int expireTime,TimeUnit unit) { |
||||
|
boolean result = false; |
||||
|
try { |
||||
|
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
||||
|
operations.set(key, value); |
||||
|
redisTemplate.expire(key, expireTime, unit); |
||||
|
result = true; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 批量删除对应的value |
||||
|
* |
||||
|
* @param keys |
||||
|
*/ |
||||
|
public void remove(final String... keys) { |
||||
|
for (String key : keys) { |
||||
|
remove(key); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 批量删除key |
||||
|
* |
||||
|
* @param pattern |
||||
|
*/ |
||||
|
public void removePattern(final String pattern) { |
||||
|
Set<Serializable> keys = redisTemplate.keys(pattern); |
||||
|
if (keys.size() > 0) |
||||
|
redisTemplate.delete(keys); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除对应的value |
||||
|
* |
||||
|
* @param key |
||||
|
*/ |
||||
|
public void remove(final String key) { |
||||
|
if (exists(key)) { |
||||
|
redisTemplate.delete(key); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断缓存中是否有对应的value |
||||
|
* |
||||
|
* @param text |
||||
|
* @return |
||||
|
*/ |
||||
|
public Set<String> list(final String text) { |
||||
|
Set<String> keySet = redisTemplate.keys("*" + text + "*"); |
||||
|
for (String key : keySet) { |
||||
|
System.out.println(key); |
||||
|
} |
||||
|
return keySet; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取所有数据 |
||||
|
* |
||||
|
* @return |
||||
|
*/ |
||||
|
public Set<String> list() { |
||||
|
Set<String> keySet = redisTemplate.keys("*" + "#" +"*"); |
||||
|
for (String key : keySet) { |
||||
|
System.out.println(key); |
||||
|
} |
||||
|
return keySet; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 判断缓存中是否有对应的value |
||||
|
* |
||||
|
* @param text |
||||
|
* @return |
||||
|
*/ |
||||
|
public void removeForLike(final String text) { |
||||
|
Set<String> keySet = redisTemplate.keys("*" + text + "*"); |
||||
|
Iterator<String> it = keySet.iterator(); |
||||
|
while(it.hasNext()){ |
||||
|
redisTemplate.delete(it.next()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public Map<String, Object> cleanRedis() { |
||||
|
Map<String, Object> map = new HashMap<>(); |
||||
|
try { |
||||
|
// 获取所有key
|
||||
|
Set<String> keys = redisTemplate.keys("*"); |
||||
|
assert keys != null; |
||||
|
// 迭代
|
||||
|
Iterator<String> it1 = keys.iterator(); |
||||
|
while (it1.hasNext()) { |
||||
|
// 循环删除
|
||||
|
stringRedisTemplate.delete(it1.next()); |
||||
|
} |
||||
|
map.put("code", 1); |
||||
|
map.put("msg", "清理全局缓存成功"); |
||||
|
return map; |
||||
|
} catch (Exception e) { |
||||
|
map.put("code", -1); |
||||
|
map.put("msg", "清理全局缓存失败"); |
||||
|
return map; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 判断缓存中是否有对应的value |
||||
|
* |
||||
|
* @param key |
||||
|
* @return |
||||
|
*/ |
||||
|
public boolean exists(final String key) { |
||||
|
return redisTemplate.hasKey(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 读取缓存 |
||||
|
* |
||||
|
* @param key |
||||
|
* @return |
||||
|
*/ |
||||
|
public Object get(final String key) { |
||||
|
Object result = null; |
||||
|
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
||||
|
result = operations.get(key); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public String getString(final String key) { |
||||
|
Object result = null; |
||||
|
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); |
||||
|
result = operations.get(key); |
||||
|
if(result!=null){ |
||||
|
return result.toString(); |
||||
|
|
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public Integer getInteger(final String key) { |
||||
|
String result = getString(key); |
||||
|
if(result!=null){ |
||||
|
return Integer.parseInt(result); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 哈希 添加 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param hashKey |
||||
|
* @param value |
||||
|
*/ |
||||
|
public void hmSet(String key, Object hashKey, Object value) { |
||||
|
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); |
||||
|
hash.put(key, hashKey, value); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 哈希获取数据 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param hashKey |
||||
|
* @return |
||||
|
*/ |
||||
|
public Object hmGet(String key, Object hashKey) { |
||||
|
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); |
||||
|
return hash.get(key, hashKey); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 列表添加 |
||||
|
* |
||||
|
* @param k |
||||
|
* @param v |
||||
|
*/ |
||||
|
public void lPush(String k, Object v) { |
||||
|
ListOperations<String, Object> list = redisTemplate.opsForList(); |
||||
|
list.rightPush(k, v); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 列表获取 |
||||
|
* |
||||
|
* @param k |
||||
|
* @param l |
||||
|
* @param l1 |
||||
|
* @return |
||||
|
*/ |
||||
|
public List<Object> lRange(String k, long l, long l1) { |
||||
|
ListOperations<String, Object> list = redisTemplate.opsForList(); |
||||
|
return list.range(k, l, l1); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 集合添加 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param value |
||||
|
*/ |
||||
|
public void add(String key, Object value) { |
||||
|
SetOperations<String, Object> set = redisTemplate.opsForSet(); |
||||
|
set.add(key, value); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 集合获取 |
||||
|
* |
||||
|
* @param key |
||||
|
* @return |
||||
|
*/ |
||||
|
public Set<Object> setMembers(String key) { |
||||
|
SetOperations<String, Object> set = redisTemplate.opsForSet(); |
||||
|
return set.members(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 有序集合添加 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param value |
||||
|
* @param scoure |
||||
|
*/ |
||||
|
public void zAdd(String key, Object value, double scoure) { |
||||
|
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet(); |
||||
|
zset.add(key, value, scoure); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 有序集合获取 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param scoure |
||||
|
* @param scoure1 |
||||
|
* @return |
||||
|
*/ |
||||
|
public Set<Object> rangeByScore(String key, double scoure, double scoure1) { |
||||
|
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet(); |
||||
|
return zset.rangeByScore(key, scoure, scoure1); |
||||
|
} |
||||
|
} |
@ -0,0 +1,192 @@ |
|||||
|
package com.qs.serve.common.framework.security.filter; |
||||
|
|
||||
|
import com.qs.serve.common.config.DevEnvironmentConfig; |
||||
|
import com.qs.serve.common.config.properties.PermitProperties; |
||||
|
import com.qs.serve.common.framework.redis.RedisService; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUserType; |
||||
|
import com.qs.serve.common.model.HttpResponsePrintUtil; |
||||
|
import com.qs.serve.common.model.consts.GySysConst; |
||||
|
import com.qs.serve.common.model.consts.RedisCacheKeys; |
||||
|
import com.qs.serve.common.util.JwtUtils; |
||||
|
import com.qs.serve.common.framework.security.util.SecurityPermitUtil; |
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
import com.qs.serve.modules.sys.service.SysUserService; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
||||
|
import org.springframework.security.core.context.SecurityContextHolder; |
||||
|
import org.springframework.security.core.userdetails.UserDetails; |
||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
import org.springframework.web.filter.OncePerRequestFilter; |
||||
|
|
||||
|
import javax.servlet.FilterChain; |
||||
|
import javax.servlet.ServletException; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* 判断token情况 |
||||
|
* @Author JcYen |
||||
|
* @Date 2022/03/01 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
public class SecurityRequestFilter extends OncePerRequestFilter { |
||||
|
|
||||
|
@Value("${server.servlet.context-path}") |
||||
|
public String contextPath; |
||||
|
|
||||
|
@Autowired |
||||
|
private SysUserService sysUserService; |
||||
|
|
||||
|
@Autowired |
||||
|
private PermitProperties permitProperties; |
||||
|
|
||||
|
@Autowired |
||||
|
private RedisService redisService; |
||||
|
|
||||
|
@Override |
||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { |
||||
|
//移除前缀
|
||||
|
String url = request.getRequestURI(); |
||||
|
if(!StringUtils.isEmpty(contextPath)&&!contextPath.equals("/")){ |
||||
|
url = url.replace(contextPath,""); |
||||
|
} |
||||
|
//分析拦截类型
|
||||
|
boolean ignorePermit = false; |
||||
|
for(String reg : permitProperties.getPermits()){ |
||||
|
if(SecurityPermitUtil.verify(reg,url)){ |
||||
|
ignorePermit=true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
//分析拦截类型
|
||||
|
boolean ignoreTenant = false; |
||||
|
for(String reg : permitProperties.getTenants()){ |
||||
|
if(SecurityPermitUtil.verify(reg,url)){ |
||||
|
ignoreTenant = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
response.setHeader("Access-Control-Allow-Origin", "*"); |
||||
|
//登录拦截
|
||||
|
if ("OPTIONS".equals(request.getMethod())) { |
||||
|
HttpResponsePrintUtil.print(response,200,"success"); |
||||
|
return; |
||||
|
} |
||||
|
if(!ignoreTenant){ |
||||
|
boolean hasTenant = handleTenant(request,response); |
||||
|
if(!hasTenant){ |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
if(ignorePermit){ |
||||
|
//try to doSecurityAuthor
|
||||
|
tryDoSecurityAuthor(request, response, chain); |
||||
|
chain.doFilter(request,response); |
||||
|
}else { |
||||
|
doSecurityAuthor(request, response, chain); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 尝试执行登录 |
||||
|
* @param request |
||||
|
* @param response |
||||
|
* @param chain |
||||
|
* @throws IOException |
||||
|
* @throws ServletException |
||||
|
*/ |
||||
|
private void tryDoSecurityAuthor(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { |
||||
|
String tenant = request.getHeader(GySysConst.TENANT_PROP); |
||||
|
String token = request.getHeader(GySysConst.AUTHORIZATION_PROP); |
||||
|
if(tenant!=null&&token!=null&&JwtUtils.verify(token)){ |
||||
|
String userId = JwtUtils.getUserId(token); |
||||
|
String userType = JwtUtils.getUserType(token); |
||||
|
AuthContextUtils.setTenant(tenant); |
||||
|
if(SecurityContextHolder.getContext().getAuthentication()==null){ |
||||
|
UserDetails userDetails = null; |
||||
|
if(userType.equals(LoginUserType.SYS_USER.getCode()) |
||||
|
||userType.equals(LoginUserType.SYS_SUP_USER.getCode())){ |
||||
|
//后台管理员登录
|
||||
|
userDetails = sysUserService.getLoginUserById(userId); |
||||
|
} |
||||
|
if(userDetails!=null){ |
||||
|
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); |
||||
|
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); |
||||
|
SecurityContextHolder.getContext().setAuthentication(authentication); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 执行登录 |
||||
|
* @param request |
||||
|
* @param response |
||||
|
* @param chain |
||||
|
* @throws IOException |
||||
|
* @throws ServletException |
||||
|
*/ |
||||
|
private void doSecurityAuthor(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { |
||||
|
String token = request.getHeader(GySysConst.AUTHORIZATION_PROP); |
||||
|
if(!JwtUtils.verify(token)){ |
||||
|
HttpResponsePrintUtil.print2(response,401,"身份凭证无效或过期"); |
||||
|
}else{ |
||||
|
String userId = JwtUtils.getUserId(token); |
||||
|
String userType = JwtUtils.getUserType(token); |
||||
|
String client = JwtUtils.getClient(token); |
||||
|
String redisKey = com.qs.serve.common.util.StringUtils.format(RedisCacheKeys.LOGIN_KEY_APP,client,userId); |
||||
|
String cacheToken = redisService.getString(redisKey); |
||||
|
if(!DevEnvironmentConfig.isDev()&&!token.equals(cacheToken)){ |
||||
|
redisService.remove(redisKey); |
||||
|
HttpResponsePrintUtil.print2(response,401,"异地登录,已被系统登出"); |
||||
|
//return解决:security.access.AccessDeniedException
|
||||
|
return; |
||||
|
} |
||||
|
if(SecurityContextHolder.getContext().getAuthentication()==null){ |
||||
|
UserDetails userDetails = null; |
||||
|
if(userType.equals(LoginUserType.SYS_USER.getCode()) |
||||
|
||userType.equals(LoginUserType.SYS_SUP_USER.getCode())){ |
||||
|
//后台管理员登录
|
||||
|
userDetails = sysUserService.getLoginUserById(userId); |
||||
|
} |
||||
|
if(userDetails==null){ |
||||
|
HttpResponsePrintUtil.print2(response,401,"登录信息无效,请重新登录"); |
||||
|
//return解决:security.access.AccessDeniedException
|
||||
|
return; |
||||
|
}else { |
||||
|
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); |
||||
|
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); |
||||
|
SecurityContextHolder.getContext().setAuthentication(authentication); |
||||
|
} |
||||
|
} |
||||
|
chain.doFilter(request, response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 多租户模式下使用 |
||||
|
* @param request |
||||
|
* @param response |
||||
|
* @throws IOException |
||||
|
* @throws ServletException |
||||
|
*/ |
||||
|
private boolean handleTenant(HttpServletRequest request, HttpServletResponse response) throws IOException{ |
||||
|
String tenant = request.getHeader(GySysConst.TENANT_PROP); |
||||
|
if (tenant != null) { |
||||
|
AuthContextUtils.setTenant(tenant); |
||||
|
return true; |
||||
|
}else{ |
||||
|
HttpResponsePrintUtil.print2(response,4001,"校区信息错误"); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package com.qs.serve.common.framework.security.handler; |
||||
|
|
||||
|
import com.qs.serve.common.model.HttpResponsePrintUtil; |
||||
|
import org.springframework.security.access.AccessDeniedException; |
||||
|
import org.springframework.security.web.access.AccessDeniedHandler; |
||||
|
|
||||
|
import javax.servlet.ServletException; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/3 |
||||
|
*/ |
||||
|
public class SecurityAccessDeniedHandler implements AccessDeniedHandler { |
||||
|
|
||||
|
@Override |
||||
|
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { |
||||
|
HttpResponsePrintUtil.print(response,403,"权限不足"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package com.qs.serve.common.framework.security.handler; |
||||
|
|
||||
|
import com.qs.serve.common.model.HttpResponsePrintUtil; |
||||
|
import org.springframework.security.core.AuthenticationException; |
||||
|
import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
||||
|
|
||||
|
import javax.servlet.ServletException; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/3 |
||||
|
*/ |
||||
|
public class SecurityAuthenticationFailureHandler implements AuthenticationFailureHandler { |
||||
|
|
||||
|
@Override |
||||
|
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException { |
||||
|
HttpResponsePrintUtil.print(response,401,"登录信息已过期或失效"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
package com.qs.serve.common.framework.security.handler; |
||||
|
|
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.common.model.HttpResponsePrintUtil; |
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
import com.qs.serve.common.util.SpringUtils; |
||||
|
import com.qs.serve.modules.sys.mapper.SysUserMapper; |
||||
|
import org.springframework.security.core.Authentication; |
||||
|
import org.springframework.security.web.authentication.logout.LogoutHandler; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2021/12/22 |
||||
|
*/ |
||||
|
public class SecurityLogoutHandler implements LogoutHandler { |
||||
|
|
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { |
||||
|
SysUserMapper sysUserMapper = SpringUtils.getBean(SysUserMapper.class); |
||||
|
LoginUser loginUser = AuthContextUtils.getLoginUser(false); |
||||
|
if(loginUser!=null){ |
||||
|
sysUserMapper.updateYmTokenInt(loginUser.getUserId(),"#","#"); |
||||
|
} |
||||
|
try { |
||||
|
HttpResponsePrintUtil.print(response,200,"退出登录成功"); |
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
package com.qs.serve.common.framework.security.model; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import org.springframework.security.core.GrantedAuthority; |
||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority; |
||||
|
import org.springframework.security.core.userdetails.UserDetails; |
||||
|
|
||||
|
import java.util.Collection; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
/** |
||||
|
* 用户登录信息 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@Data |
||||
|
@AllArgsConstructor |
||||
|
public class LoginUser implements UserDetails { |
||||
|
|
||||
|
private String userId; |
||||
|
|
||||
|
private String nick; |
||||
|
|
||||
|
private String password; |
||||
|
|
||||
|
private String loginIp; |
||||
|
|
||||
|
/** 用户类型 */ |
||||
|
private LoginUserType typeFlag; |
||||
|
|
||||
|
private List<String> authorList; |
||||
|
private List<String> authorIds; |
||||
|
|
||||
|
private String tenant; |
||||
|
|
||||
|
@Override |
||||
|
public Collection<? extends GrantedAuthority> getAuthorities() { |
||||
|
if(authorList!=null&&authorList.size()>0){ |
||||
|
return authorList |
||||
|
.stream() |
||||
|
.filter(n->n.length()>0) |
||||
|
.map(auth->new SimpleGrantedAuthority("ROLE_"+auth)) |
||||
|
.collect(Collectors.toList()); |
||||
|
} |
||||
|
return Collections.singletonList(new SimpleGrantedAuthority("NOT_ROLE")); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getPassword() { |
||||
|
return password; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getUsername() { |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isAccountNonExpired() { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isAccountNonLocked() { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isCredentialsNonExpired() { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isEnabled() { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public LoginUserDTO loginUserDTO(){ |
||||
|
return new LoginUserDTO(userId,nick,password,loginIp,typeFlag.getCode(),authorList,authorIds,tenant); |
||||
|
} |
||||
|
|
||||
|
public boolean verifyRole(String permitCode){ |
||||
|
return authorList.contains(permitCode); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 是否拥有招生超管权限 |
||||
|
* @return |
||||
|
*/ |
||||
|
public boolean hasRegSuperRole(){ |
||||
|
return verifyRole("edu:reg:admin"); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
package com.qs.serve.common.framework.security.model; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 用户登录信息 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class LoginUserDTO { |
||||
|
|
||||
|
private String userId; |
||||
|
|
||||
|
private String nick; |
||||
|
|
||||
|
private String password; |
||||
|
|
||||
|
private String loginIp; |
||||
|
|
||||
|
private String typeFlagCode; |
||||
|
|
||||
|
private List<String> authorList; |
||||
|
private List<String> authorIds; |
||||
|
private String tenant; |
||||
|
|
||||
|
public LoginUser loginUser(){ |
||||
|
return new LoginUser(userId,nick,password,loginIp,LoginUserType.getByCode(typeFlagCode),authorList,authorIds,tenant); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
package com.qs.serve.common.framework.security.model; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/7 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum LoginUserType { |
||||
|
|
||||
|
/** |
||||
|
* 人员分类 |
||||
|
*/ |
||||
|
APP_USER("00","微信用户"), |
||||
|
SYS_USER("01","系统人员"), |
||||
|
SYS_SUP_USER("02","超级管理员") |
||||
|
; |
||||
|
|
||||
|
private String code; |
||||
|
private String name; |
||||
|
|
||||
|
public static LoginUserType getByCode(String code){ |
||||
|
for (LoginUserType value : LoginUserType.values()) { |
||||
|
if(value.getCode().equals(code)){ |
||||
|
return value; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package com.qs.serve.common.framework.security.service; |
||||
|
|
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.modules.sys.entity.SysUser; |
||||
|
import com.qs.serve.modules.sys.service.SysUserService; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import org.springframework.security.core.userdetails.UserDetails; |
||||
|
import org.springframework.security.core.userdetails.UserDetailsService; |
||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@Service |
||||
|
@AllArgsConstructor |
||||
|
public class SysUserDetailsServiceImpl implements UserDetailsService { |
||||
|
|
||||
|
private final SysUserService sysUserService; |
||||
|
|
||||
|
@Override |
||||
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { |
||||
|
return sysUserService.getLoginUserByAccount(username); |
||||
|
} |
||||
|
|
||||
|
public LoginUser buildLoginUser(SysUser sysUser){ |
||||
|
return sysUserService.buildLoginUser(sysUser); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package com.qs.serve.common.framework.security.util; |
||||
|
|
||||
|
/** |
||||
|
* @Author JcYen |
||||
|
* @Date 2021/9/24 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
public class SecurityPermitUtil { |
||||
|
|
||||
|
public static boolean verify(String reg, String input){ |
||||
|
if ("/*".equals(reg)) return true; |
||||
|
String[] reg_split = reg.split("\\*"); |
||||
|
int index = 0, reg_len = reg_split.length; |
||||
|
boolean b = reg.charAt(reg.length() - 1) == '*' ? true : false; |
||||
|
while (input.length() > 0) { |
||||
|
if (index == reg_len) { |
||||
|
if (b) return true; |
||||
|
else return false; |
||||
|
} |
||||
|
String r = reg_split[index++]; |
||||
|
int indexOf = input.indexOf(r); |
||||
|
if (indexOf != 0) return false; |
||||
|
input = input.substring(indexOf + r.length()); |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
package com.qs.serve.common.model; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/30 |
||||
|
*/ |
||||
|
public class HttpResponsePrintUtil { |
||||
|
|
||||
|
public static void print(HttpServletResponse response,Integer code ,String msg) throws IOException,SecurityException{ |
||||
|
response.setHeader("Access-Control-Allow-Origin", "*"); |
||||
|
response.setHeader("Access-Control-Allow-Credentials", "true"); |
||||
|
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"); |
||||
|
response.setHeader("Access-Control-Max-Age", "86400"); |
||||
|
response.setHeader("Access-Control-Allow-Headers", "*"); |
||||
|
response.setStatus(200); |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
response.setContentType("application/json;charset=UTF-8"); |
||||
|
response.getWriter().print("{\"status\":"+code+",\"msg\":\""+msg+"\"}"); |
||||
|
response.getWriter().flush(); |
||||
|
} |
||||
|
|
||||
|
public static void print2(HttpServletResponse response,Integer code ,String msg)throws IOException,SecurityException{ |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
response.setContentType("application/json;charset=UTF-8"); |
||||
|
response.getWriter().print("{\"status\":"+code+",\"msg\":\""+msg+"\"}"); |
||||
|
response.getWriter().flush(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.qs.serve.common.model.annotation; |
||||
|
|
||||
|
import java.lang.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* 防止表单重复提交 |
||||
|
* @author YenHex |
||||
|
* @since 2022-03-01 |
||||
|
*/ |
||||
|
@Target({ElementType.METHOD}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
@Documented |
||||
|
public @interface LimitSubmit { |
||||
|
|
||||
|
/** |
||||
|
* 间隔时间(ms),在世界间隔内超过执行次数,视为被限制 |
||||
|
*/ |
||||
|
int interval() default 1000; |
||||
|
|
||||
|
/** |
||||
|
* 提示消息 |
||||
|
*/ |
||||
|
String message() default ""; |
||||
|
|
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
package com.qs.serve.common.model.annotation; |
||||
|
|
||||
|
/** |
||||
|
* 防止表单重复提交 |
||||
|
* @author YenHex |
||||
|
* @since 2022-03-01 |
||||
|
*/ |
||||
|
public @interface RepeatSubmit { |
||||
|
|
||||
|
/** |
||||
|
* 间隔时间(ms),小于此时间视为重复提交 |
||||
|
*/ |
||||
|
int interval() default 5000; |
||||
|
|
||||
|
/** |
||||
|
* 提示消息 |
||||
|
*/ |
||||
|
String message() default "不允许重复提交,请稍后再试"; |
||||
|
|
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package com.qs.serve.common.model.annotation; |
||||
|
|
||||
|
import com.qs.serve.common.model.enums.BizType; |
||||
|
import com.qs.serve.common.model.enums.InterType; |
||||
|
import com.qs.serve.common.model.enums.SystemModule; |
||||
|
|
||||
|
import java.lang.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* 记录用户登录操作 |
||||
|
* @author YenHex |
||||
|
* @since 2022-03-01 |
||||
|
*/ |
||||
|
@Target({ElementType.METHOD}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
@Documented |
||||
|
public @interface SysLog { |
||||
|
|
||||
|
SystemModule module() default SystemModule.SYSTEM; |
||||
|
|
||||
|
/** 业务标题 */ |
||||
|
String title() default ""; |
||||
|
|
||||
|
/** 操作描述 */ |
||||
|
String desc() default ""; |
||||
|
|
||||
|
/** 操作类型 */ |
||||
|
BizType biz() default BizType.OTHER; |
||||
|
|
||||
|
/** 接口类型 */ |
||||
|
InterType inter() default InterType.ADMIN; |
||||
|
|
||||
|
boolean saveReqParam() default true; |
||||
|
|
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
public class DateConst { |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* 系统字段 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
public class GySysConst { |
||||
|
|
||||
|
/** 后台身份验证 */ |
||||
|
public static final String AUTHORIZATION_PROP = "Authorization"; |
||||
|
|
||||
|
/** API身份验证 */ |
||||
|
public static final String APP_TOKEN_PROP = "token"; |
||||
|
|
||||
|
/** 请求头参数 */ |
||||
|
public static final String USER_AGENT_PROP = "User-Agent"; |
||||
|
|
||||
|
public static final String TENANT_PROP = "tenant-id"; |
||||
|
|
||||
|
/** 系统租户数据库列 */ |
||||
|
public static final String TENANT_COLUMN = "tenant_id"; |
||||
|
|
||||
|
/** 第三方应用id。如:公众号 */ |
||||
|
public static final String APP_ID_PROP = "appid"; |
||||
|
|
||||
|
/** 通用参数 */ |
||||
|
public static final int STATUS_YES_1 = 1; |
||||
|
public static final int STATUS_NO_1 = 0; |
||||
|
|
||||
|
public static final String LANG_ZH_CN = "zh_CN"; |
||||
|
|
||||
|
|
||||
|
public static final String ROLE_ADMIN_OPT_LOG = "sys:operationLog:admin"; |
||||
|
public static final String ROLE_ADMIN_REG = "edu:reg:admin"; |
||||
|
|
||||
|
public static final String DEFAULT_PASSWORD = "12345678"; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/10 |
||||
|
*/ |
||||
|
public class OssConst { |
||||
|
|
||||
|
/** |
||||
|
* 访问类型 |
||||
|
*/ |
||||
|
public static final String ACCESS_OWNER = "own"; |
||||
|
public static final String ACCESS_DEPT = "dept"; |
||||
|
|
||||
|
/** |
||||
|
* 文件夹前缀 |
||||
|
*/ |
||||
|
public static final String OWNER_DIR = "owner/"; |
||||
|
public static final String DEPT_DIR = "dept/"; |
||||
|
public static final String SPLIT = "/"; |
||||
|
|
||||
|
/** |
||||
|
* Tag |
||||
|
*/ |
||||
|
public static final String TAG_CREATOR = "creator"; |
||||
|
public static final String TAG_CREATE_BY = "create_by"; |
||||
|
|
||||
|
public static final String FILE_TYPE_DIR = "文件夹"; |
||||
|
|
||||
|
public static final String DIR_TYPE_UNKNOWN = "未知"; |
||||
|
|
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
public class RedisCacheKeys { |
||||
|
|
||||
|
/** 权限列表 */ |
||||
|
public final static String PERMIT_ALL_LIST = "expire_permit_list"; |
||||
|
|
||||
|
/** 租户列表 */ |
||||
|
public final static String Tenant_ALL_LIST = "expire_tenant_list"; |
||||
|
|
||||
|
/** 管理员登录key */ |
||||
|
public final static String LOGIN_KEY_ADMIN = "login_admin_:"; |
||||
|
|
||||
|
/** 家长登录key */ |
||||
|
public final static String LOGIN_KEY_WX = "login_wx_:"; |
||||
|
|
||||
|
/** 用户登录APP {}客户端 {}用户ID */ |
||||
|
public final static String LOGIN_KEY_APP = "login_app_{}:{}:"; |
||||
|
|
||||
|
/** 手机号验证吗 */ |
||||
|
public final static String PHONE_KEY = "phone_code_:"; |
||||
|
|
||||
|
/** 工号标识 */ |
||||
|
public final static String SYS_USER_CODE_KEY = "sys_user_code_:"; |
||||
|
|
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
public class RedisListenerKeys { |
||||
|
|
||||
|
public final static String EXPIRED_TYPE = "__keyevent@*__:expired"; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,46 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import com.qs.serve.common.util.PageUtil; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Getter |
||||
|
@Setter |
||||
|
public class PageVo<T>{ |
||||
|
|
||||
|
/** |
||||
|
* 页幅 |
||||
|
*/ |
||||
|
private Integer pageSize; |
||||
|
|
||||
|
/** |
||||
|
* 页眉 |
||||
|
*/ |
||||
|
private Integer pageNum; |
||||
|
|
||||
|
/** |
||||
|
* 总数据数 |
||||
|
*/ |
||||
|
private Long total; |
||||
|
|
||||
|
/** |
||||
|
* 总页数 |
||||
|
*/ |
||||
|
private Long totalPage; |
||||
|
|
||||
|
/** |
||||
|
* 数据列表 |
||||
|
*/ |
||||
|
private List<T> list; |
||||
|
|
||||
|
public void initPageByTotal(long total){ |
||||
|
this.total = total; |
||||
|
this.pageNum = PageUtil.getPageNum(); |
||||
|
this.pageSize = PageUtil.getPageSize(); |
||||
|
if(pageSize==null||pageSize==0){ return; } |
||||
|
this.totalPage = total%pageSize==0?total/pageSize:(total/pageSize+1); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,173 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
|
import com.github.pagehelper.PageInfo; |
||||
|
import com.qs.serve.common.util.PageUtil; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 统一返回封装 |
||||
|
* 1.替代旧版的ViewResult |
||||
|
* 2.支持SmartDoc |
||||
|
* @author JcYen |
||||
|
* @date 2021/4/22 |
||||
|
* @version 2.0 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
public class R<T> implements Serializable { |
||||
|
|
||||
|
public R(int status, String msg) { |
||||
|
this.status = status; |
||||
|
this.msg = msg; |
||||
|
} |
||||
|
|
||||
|
public R(int status, String msg, T data) { |
||||
|
this.status = status; |
||||
|
this.msg = msg; |
||||
|
this.data = data; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 状态码 |
||||
|
*/ |
||||
|
private Integer status; |
||||
|
|
||||
|
/** |
||||
|
* 信息 |
||||
|
*/ |
||||
|
private String msg; |
||||
|
|
||||
|
/** |
||||
|
* 数据 |
||||
|
*/ |
||||
|
private T data; |
||||
|
|
||||
|
public static final int SUCCESS_STATUS = 200; |
||||
|
public static final int LOGOUT_STATUS = 401; |
||||
|
public static final int FORBIDDEN_STATUS = 403; |
||||
|
public static final int NOT_FOUND_STATUS = 434; |
||||
|
public static final int FAILED_STATUS = 500; |
||||
|
|
||||
|
public static final String SUCCESS_TIPS = "操作成功"; |
||||
|
public static final String FAILED_TIPS = "操作失败"; |
||||
|
public static final String FAILED_TIPS_2 = "业务操作失败"; |
||||
|
public static final String LOGOUT_TIPS = "登录无效"; |
||||
|
public static final String FORBIDDEN_TIPS = "无权限访问"; |
||||
|
public static final String NOT_FOUND_TIPS = "数据不存在或被移除"; |
||||
|
|
||||
|
public static R ok() { |
||||
|
return new R(SUCCESS_STATUS,SUCCESS_TIPS,null); |
||||
|
} |
||||
|
|
||||
|
public static R ok(String msg) { |
||||
|
return new R<>(SUCCESS_STATUS,msg,null); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<TYPE> ok(TYPE data) { |
||||
|
return new R<>(SUCCESS_STATUS,SUCCESS_TIPS,data); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<TYPE> ok(TYPE data,String message) { |
||||
|
return new R<>(SUCCESS_STATUS,message,data); |
||||
|
} |
||||
|
|
||||
|
public static R isTrue(Boolean bool){ |
||||
|
if(bool==null|| !bool){ |
||||
|
return error(); |
||||
|
} |
||||
|
return ok(); |
||||
|
} |
||||
|
|
||||
|
public static R isTrue(Boolean bool, String message){ |
||||
|
if(bool==null|| !bool){ |
||||
|
return error(message); |
||||
|
} |
||||
|
return ok(null,message); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static <TYPE> R<TYPE> isNotNull(TYPE object){ |
||||
|
if(object==null){ |
||||
|
return error(); |
||||
|
} |
||||
|
return ok(object,SUCCESS_TIPS); |
||||
|
} |
||||
|
|
||||
|
public static R<?> isOk(Boolean rs){ |
||||
|
if(rs==null){ |
||||
|
return error(); |
||||
|
} |
||||
|
return ok(); |
||||
|
} |
||||
|
|
||||
|
public static R<?> isOk(Boolean rs,String errMsg){ |
||||
|
if(rs==null){ |
||||
|
return error(errMsg); |
||||
|
} |
||||
|
return ok(); |
||||
|
} |
||||
|
|
||||
|
public static R error(String message) { |
||||
|
return new R<>(FAILED_STATUS,message,null); |
||||
|
} |
||||
|
|
||||
|
public static R error() { |
||||
|
return new R<>(FAILED_STATUS,FAILED_TIPS,null); |
||||
|
} |
||||
|
|
||||
|
public static R error2() { |
||||
|
return new R<>(FAILED_STATUS,FAILED_TIPS_2,null); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<PageVo<TYPE>> byMbpList(IPage<TYPE> page){ |
||||
|
PageVo<TYPE> pageVo = new PageVo<>(); |
||||
|
pageVo.initPageByTotal(page.getTotal()); |
||||
|
pageVo.setList(page.getRecords()); |
||||
|
return R.ok(pageVo); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<PageVo<TYPE>> byMbpList(IPage<?> page,List<TYPE> data){ |
||||
|
PageVo<TYPE> pageVo = new PageVo<>(); |
||||
|
pageVo.initPageByTotal(page.getTotal()); |
||||
|
pageVo.setList(data); |
||||
|
return R.ok(pageVo); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<PageVo<TYPE>> byPageHelperList(List<TYPE> data){ |
||||
|
PageVo<TYPE> pageVo = new PageVo<>(); |
||||
|
PageInfo<TYPE> pageInfo = new PageInfo<>(data); |
||||
|
pageVo.setPageSize(pageInfo.getPageSize()); |
||||
|
pageVo.setPageNum(pageInfo.getPageNum()); |
||||
|
pageVo.setTotal(pageInfo.getTotal()); |
||||
|
pageVo.setList(data); |
||||
|
pageVo.setTotalPage(new Long(pageInfo.getPages())); |
||||
|
return R.ok(pageVo); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<PageVo<TYPE>> byEmptyList(){ |
||||
|
PageVo<TYPE> pageVo = new PageVo<>(); |
||||
|
pageVo.setPageSize(PageUtil.getPageSize()); |
||||
|
pageVo.setPageNum(PageUtil.getPageNum()); |
||||
|
pageVo.setTotal(0L); |
||||
|
pageVo.setList(null); |
||||
|
pageVo.setTotalPage(0L); |
||||
|
return R.ok(pageVo); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE,R_TYPE> R<PageVo<R_TYPE>> byPageHelperList(List<TYPE> sources,List<R_TYPE> details){ |
||||
|
PageVo<R_TYPE> pageVo = new PageVo<>(); |
||||
|
PageInfo<TYPE> pageInfo = new PageInfo<>(sources); |
||||
|
pageVo.setPageSize(pageInfo.getPageSize()); |
||||
|
pageVo.setPageNum(pageInfo.getPageNum()); |
||||
|
pageVo.setTotal(pageInfo.getTotal()); |
||||
|
pageVo.setList(details); |
||||
|
pageVo.setTotalPage(new Long(pageInfo.getPages())); |
||||
|
return R.ok(pageVo); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
@AllArgsConstructor |
||||
|
public class SimpleKeyValue<T> { |
||||
|
|
||||
|
/** 键 */ |
||||
|
private String label; |
||||
|
|
||||
|
/** 值 */ |
||||
|
private T value; |
||||
|
|
||||
|
/** 说明 */ |
||||
|
private String remark; |
||||
|
|
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 树节点 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class TreeNode { |
||||
|
protected String id; |
||||
|
protected String parentId; |
||||
|
private Integer sort; |
||||
|
protected List<TreeNode> children = new ArrayList<>(); |
||||
|
|
||||
|
public void addChildren(TreeNode treeNode) { |
||||
|
children.add(treeNode); |
||||
|
} |
||||
|
|
||||
|
public List<TreeNode> getChildren() { |
||||
|
if(children.size()<=0){ |
||||
|
return null; |
||||
|
} |
||||
|
return children; |
||||
|
} |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/8 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum BizType { |
||||
|
|
||||
|
/** 其它 */ |
||||
|
OTHER("其它"), |
||||
|
|
||||
|
/** 新增 */ |
||||
|
INSERT("新增"), |
||||
|
|
||||
|
/** 修改 */ |
||||
|
UPDATE("修改"), |
||||
|
|
||||
|
/** 删除 */ |
||||
|
DELETE("删除"), |
||||
|
|
||||
|
/** 授权 */ |
||||
|
GRANT("授权"), |
||||
|
|
||||
|
/** 强退 */ |
||||
|
FORCE("强退"), |
||||
|
|
||||
|
/** 清空数据 */ |
||||
|
CLEAN("清空"), |
||||
|
|
||||
|
/** 登录 */ |
||||
|
LOGIN("登录"), |
||||
|
|
||||
|
LOGOUT("登出"), |
||||
|
|
||||
|
UPLOAD("上传"), |
||||
|
|
||||
|
DOWNLOAD("下载"), |
||||
|
|
||||
|
QUERY("查询"), |
||||
|
|
||||
|
RESET("重置"); |
||||
|
|
||||
|
String value; |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/10 |
||||
|
*/ |
||||
|
@AllArgsConstructor |
||||
|
public enum ExcelFilePath { |
||||
|
|
||||
|
/** 地址 */ |
||||
|
EDU_REG_ARCHIVE_IN("1000",""); |
||||
|
|
||||
|
String code; |
||||
|
|
||||
|
String path; |
||||
|
|
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* 请求状态码 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/28 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum HttpCode { |
||||
|
|
||||
|
/** 基本参数 */ |
||||
|
SUCCESS(200,"操作成功"), |
||||
|
ERROR(500,"操作失败"), |
||||
|
DEV_ERR(500,"部分功能开发中..."), |
||||
|
WX_ERR(500,"微信服务调用异常"), |
||||
|
|
||||
|
LOGIN_ERR(401,"登录信息已过期或失效"), |
||||
|
LOGIN_ERR_2(500,"该账号已被停用,请联系系统管理员"), |
||||
|
LOGIN_ERR_1(500,"账号或登录密码不正确"), |
||||
|
LOGIN_ERR_4001(4001,"校区信息错误"), |
||||
|
LOGIN_ERR_4002(4002,"应用信息错误"), |
||||
|
|
||||
|
|
||||
|
/** 资源权限相关 */ |
||||
|
FORBIDDEN_403(403,"权限不足,无法访问"), |
||||
|
FORBIDDEN_403_1(403,"账套未注册,无权访问"), |
||||
|
FORBIDDEN_403_2(403,"客户端未注册,无权访问"), |
||||
|
FORBIDDEN_403_3(403,"IP地址未注册,无权访问"), |
||||
|
FORBIDDEN_403_4(403,"无招生超管权限,无权访问"), |
||||
|
FORBIDDEN_404(404,"资源不存在或被移除"), |
||||
|
FORBIDDEN_406(406,"系统正常处理,请勿重复提交"), |
||||
|
|
||||
|
|
||||
|
ERROR_EDU_SCHOOL_YEAR(5031,"当前学年信息错误,请重新设置当前学年"), |
||||
|
; |
||||
|
|
||||
|
Integer code; |
||||
|
String msg; |
||||
|
|
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/8 |
||||
|
*/ |
||||
|
public enum InterType { |
||||
|
|
||||
|
/** |
||||
|
* 前台接口 |
||||
|
*/ |
||||
|
API, |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 后台接口 |
||||
|
*/ |
||||
|
ADMIN |
||||
|
|
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* minio策略配置 |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/10 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum PolicyType { |
||||
|
|
||||
|
/** |
||||
|
* 只读 |
||||
|
*/ |
||||
|
READ("read-only"), |
||||
|
|
||||
|
/** |
||||
|
* 只写 |
||||
|
*/ |
||||
|
WRITE("write-only"), |
||||
|
|
||||
|
/** |
||||
|
* 读写 |
||||
|
*/ |
||||
|
READ_WRITE("read-write"); |
||||
|
|
||||
|
/** |
||||
|
* 类型 |
||||
|
*/ |
||||
|
private final String type; |
||||
|
|
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/7/25 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum SystemModule { |
||||
|
|
||||
|
QUESTION("qms","问卷"), |
||||
|
SYSTEM("sys","系统"), |
||||
|
UMS("ums","手机用户"); |
||||
|
|
||||
|
String code; |
||||
|
|
||||
|
String vale; |
||||
|
|
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
package com.qs.serve.common.model.group; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/16 |
||||
|
*/ |
||||
|
public interface EditGroup { |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
package com.qs.serve.common.model.group; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/16 |
||||
|
*/ |
||||
|
public interface SaveGroup { |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
package com.qs.serve.common.model.group; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/16 |
||||
|
*/ |
||||
|
public interface SearchGroup { |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package com.qs.serve.common.service; |
||||
|
|
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/7/4 |
||||
|
*/ |
||||
|
public abstract class RedisBaseListenerImpl implements RedisServiceListener{ |
||||
|
|
||||
|
@Override |
||||
|
public String getKey(String pk) { |
||||
|
return getPrefix()+pk+"_"+ AuthContextUtils.getTenant(); |
||||
|
} |
||||
|
|
||||
|
public String getPk(String key){ |
||||
|
return key.replace(getPrefix(),"") |
||||
|
.replace("_"+AuthContextUtils.getTenant(),""); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void doJob(String key) { |
||||
|
String[] vals = key.split("_"); |
||||
|
AuthContextUtils.setTenant(vals[vals.length-1]); |
||||
|
} |
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
package com.qs.serve.common.service; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/7/4 |
||||
|
*/ |
||||
|
public interface RedisServiceListener { |
||||
|
|
||||
|
/** |
||||
|
* 业务前缀 |
||||
|
* @return |
||||
|
*/ |
||||
|
String getPrefix(); |
||||
|
|
||||
|
/** |
||||
|
* 获取完整的key |
||||
|
* @param pk |
||||
|
* @return |
||||
|
*/ |
||||
|
String getKey(String pk); |
||||
|
|
||||
|
/** |
||||
|
* 同步最近时间段任务,添加redis实现监听 |
||||
|
*/ |
||||
|
void syncTask(); |
||||
|
|
||||
|
/** |
||||
|
* 监听过期得key |
||||
|
* @param key |
||||
|
*/ |
||||
|
void doJob(String key); |
||||
|
|
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
|
||||
|
import com.qs.serve.common.framework.exception.BusinessException; |
||||
|
import com.qs.serve.common.model.enums.HttpCode; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
/** |
||||
|
* 抛出异常工具类 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/25 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class Assert { |
||||
|
|
||||
|
public static void throwEx(Integer code,String msg){ |
||||
|
throw new BusinessException(msg, code); |
||||
|
} |
||||
|
|
||||
|
public static void throwEx(HttpCode httpCode){ |
||||
|
throw new BusinessException(httpCode.getMsg(),httpCode.getCode()); |
||||
|
} |
||||
|
|
||||
|
public static void throwEx(String msg){ |
||||
|
throw new BusinessException(msg,500); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUserType; |
||||
|
import com.qs.serve.common.model.consts.GySysConst; |
||||
|
import com.qs.serve.common.model.enums.HttpCode; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import org.springframework.security.core.Authentication; |
||||
|
import org.springframework.security.core.context.SecurityContext; |
||||
|
import org.springframework.security.core.context.SecurityContextHolder; |
||||
|
import org.springframework.security.core.userdetails.UserDetails; |
||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
||||
|
|
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class AuthContextUtils { |
||||
|
|
||||
|
private final static ThreadLocal<String> THREAD_TENANT = new ThreadLocal<>(); |
||||
|
|
||||
|
public static String getAppId(){ |
||||
|
return getAppId(true); |
||||
|
} |
||||
|
|
||||
|
public static String getAppId(boolean throwEx){ |
||||
|
String appId = ServletUtils.getHeader(GySysConst.APP_ID_PROP); |
||||
|
if(throwEx&&StringUtils.isEmpty(appId)){ |
||||
|
Assert.throwEx(HttpCode.LOGIN_ERR_4002); |
||||
|
} |
||||
|
return appId; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取用户登录信息 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static LoginUser getLoginUser(){ |
||||
|
return getLoginUser(true); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取微信用户ID |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getAppUserId(){ |
||||
|
LoginUser loginUser = getLoginUser(); |
||||
|
if(loginUser.getTypeFlag().equals(LoginUserType.APP_USER)){ |
||||
|
return loginUser.getUserId(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 系统用户ID |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getSysUserId(){ |
||||
|
LoginUser loginUser = getLoginUser(); |
||||
|
if(loginUser.getTypeFlag().equals(LoginUserType.SYS_SUP_USER) |
||||
|
||loginUser.getTypeFlag().equals(LoginUserType.SYS_USER)){ |
||||
|
return loginUser.getUserId(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否超级管理员 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static boolean isSupAdmin(){ |
||||
|
return Objects.requireNonNull(getLoginUser(false)) |
||||
|
.getTypeFlag().equals(LoginUserType.SYS_SUP_USER); |
||||
|
} |
||||
|
|
||||
|
public static void setTenant(String value){THREAD_TENANT.set(value);} |
||||
|
|
||||
|
public static String getTenant(){return THREAD_TENANT.get();} |
||||
|
|
||||
|
public static void removeTenant(){THREAD_TENANT.remove();} |
||||
|
|
||||
|
public static LoginUser getLoginUser(boolean throwEx){ |
||||
|
UserDetails details = getUserDetail(throwEx); |
||||
|
if(details instanceof LoginUser){ |
||||
|
return (LoginUser) details; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private static UserDetails getUserDetail(boolean throwEx){ |
||||
|
SecurityContext ctx = SecurityContextHolder.getContext(); |
||||
|
Authentication auth = ctx.getAuthentication(); |
||||
|
if (auth != null) { |
||||
|
Object authPri = auth.getPrincipal(); |
||||
|
if (authPri instanceof UserDetails) { |
||||
|
UserDetails details = (UserDetails) authPri; |
||||
|
return details; |
||||
|
} |
||||
|
} |
||||
|
if(throwEx){ |
||||
|
throw new UsernameNotFoundException("未登录或被登出"); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/25 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class CollectionUtil extends cn.hutool.core.collection.CollectionUtil{ |
||||
|
|
||||
|
/** |
||||
|
* 去除list中的重复数据 |
||||
|
*/ |
||||
|
public static <T> List<T> removeRepeat(List<T> list) { |
||||
|
if (isEmpty(list)) { |
||||
|
return list; |
||||
|
} |
||||
|
List<T> result = new ArrayList<T>(); |
||||
|
for (T e : list) { |
||||
|
if (!result.contains(e)) { |
||||
|
result.add(e); |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static boolean hasNull(Object... objects){ |
||||
|
for (int i = 0; i < objects.length; i++) { |
||||
|
if(objects[i]==null){return true;} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public static boolean hasNotNull(Object... objects){ |
||||
|
for (int i = 0; i < objects.length; i++) { |
||||
|
if(objects[i]!=null){return true;} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将集合转换为String数组 |
||||
|
*/ |
||||
|
public static <T> String[] toArray(List<T> list) { |
||||
|
if (isEmpty(list)) { |
||||
|
return null; |
||||
|
} |
||||
|
String[] result = new String[list.size()]; |
||||
|
for (int i = 0; i < list.size(); i++) { |
||||
|
result[i] = String.valueOf(list.get(i)); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将list拆分成多给指定的大小的list |
||||
|
*/ |
||||
|
public static <T> List<List<T>> createList(List<T> target, int size) { |
||||
|
List<List<T>> listArr = new ArrayList<>(); |
||||
|
//获取被拆分的数组个数
|
||||
|
int arrSize = target.size()%size==0?target.size()/size:target.size()/size+1; |
||||
|
for(int i=0;i<arrSize;i++) { |
||||
|
List<T> sub = new ArrayList<T>(); |
||||
|
//把指定索引数据放入到list中
|
||||
|
for(int j=i*size;j<=size*(i+1)-1;j++) { |
||||
|
if(j<=target.size()-1) { |
||||
|
sub.add(target.get(j)); |
||||
|
} |
||||
|
} |
||||
|
listArr.add(sub); |
||||
|
} |
||||
|
return listArr; |
||||
|
} |
||||
|
|
||||
|
public static <T> boolean isNotEmpty(T[] arr){ |
||||
|
return arr!=null && arr.length>0; |
||||
|
} |
||||
|
|
||||
|
public static <T> T selectFirst(List<T> list){ |
||||
|
if(isNotEmpty(list)){ |
||||
|
return list.get(0); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,95 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import org.springframework.cglib.beans.BeanCopier; |
||||
|
|
||||
|
import java.io.*; |
||||
|
import java.util.Collection; |
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
|
||||
|
/** |
||||
|
* 取代BeanUtils.CP |
||||
|
* @Author JcYen |
||||
|
* @Date 2019/6/3 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class CopierUtil { |
||||
|
|
||||
|
private static final Map<String, BeanCopier> BEAN_COPIERS = new ConcurrentHashMap<String, BeanCopier>(); |
||||
|
|
||||
|
private static String genKey(Class<?> source, Class<?> target) { |
||||
|
return source.getName() + target.getName(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* target字段值,会被source字段值覆盖(包括null) |
||||
|
* @param source |
||||
|
* @param target |
||||
|
*/ |
||||
|
public static <T> T copy(Object source, T target) { |
||||
|
String key = genKey(source.getClass(), target.getClass()); |
||||
|
BeanCopier copier; |
||||
|
if (!BEAN_COPIERS.containsKey(key)) { |
||||
|
copier = BeanCopier.create(source.getClass(), target.getClass(), false); |
||||
|
BEAN_COPIERS.put(key, copier); |
||||
|
} else { |
||||
|
copier = BEAN_COPIERS.get(key); |
||||
|
} |
||||
|
copier.copy(source, target, null); |
||||
|
return target; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 采用对象的序列化完成对象的深克隆 |
||||
|
* @param obj 待克隆的对象 |
||||
|
* @return |
||||
|
*/ |
||||
|
@SuppressWarnings("unchecked") |
||||
|
public static <T extends Serializable> T cloneObject(T obj) { |
||||
|
T cloneObj = null; |
||||
|
try { |
||||
|
// 写入字节流
|
||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream(); |
||||
|
ObjectOutputStream obs = new ObjectOutputStream(out); |
||||
|
obs.writeObject(obj); |
||||
|
obs.close(); |
||||
|
|
||||
|
// 分配内存,写入原始对象,生成新对象
|
||||
|
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray()); |
||||
|
ObjectInputStream ois = new ObjectInputStream(ios); |
||||
|
// 返回生成的新对象
|
||||
|
cloneObj = (T) ois.readObject(); |
||||
|
ois.close(); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return cloneObj; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 利用序列化完成集合的深克隆 |
||||
|
* |
||||
|
* @param collection 待克隆的集合 |
||||
|
* @return |
||||
|
* @throws ClassNotFoundException |
||||
|
* @throws IOException |
||||
|
*/ |
||||
|
@SuppressWarnings("unchecked") |
||||
|
public static <T> Collection<T> cloneCollection(Collection<T> collection) throws ClassNotFoundException, IOException{ |
||||
|
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); |
||||
|
ObjectOutputStream out = new ObjectOutputStream(byteOut); |
||||
|
out.writeObject(collection); |
||||
|
out.close(); |
||||
|
|
||||
|
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); |
||||
|
ObjectInputStream in = new ObjectInputStream(byteIn); |
||||
|
Collection<T> dest = (Collection<T>) in.readObject(); |
||||
|
in.close(); |
||||
|
|
||||
|
return dest; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.qs.serve.common.util.model.DateFormatString; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
import java.text.ParseException; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.time.LocalDate; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.ZoneId; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.time.temporal.ChronoUnit; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class DateUtils { |
||||
|
|
||||
|
public static String getString(DateFormatString format){ |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format.getValue()); |
||||
|
return LocalDateTime.now().format(formatter); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取设置后得时间 |
||||
|
* @param time |
||||
|
* @param unit |
||||
|
* @param num |
||||
|
* @return |
||||
|
*/ |
||||
|
public static LocalDateTime beSetTime(LocalDateTime time, ChronoUnit unit,int num){ |
||||
|
if(num>0){ |
||||
|
return time.plus(num,unit); |
||||
|
}else { |
||||
|
return time.minus(-num,unit); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static LocalDate beSetDate(LocalDate time,int days){ |
||||
|
return time.plusDays(days); |
||||
|
} |
||||
|
|
||||
|
public static Date toDate(String str,String format){ |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format); |
||||
|
try { |
||||
|
return sdf.parse(str); |
||||
|
} catch (ParseException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static Date toDate(LocalDateTime time){ |
||||
|
return Date.from( time.atZone( ZoneId.systemDefault()).toInstant()); |
||||
|
} |
||||
|
|
||||
|
public static double diffTime(long beganTime, long endTime) { |
||||
|
return (double)(endTime - beganTime) / 1000.0D; |
||||
|
} |
||||
|
|
||||
|
public static String format(LocalDateTime localDateTime, DateFormatString format){ |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format.getValue()); |
||||
|
return localDateTime.format(formatter); |
||||
|
} |
||||
|
|
||||
|
public static String datePath(){ |
||||
|
return format(LocalDate.now(),DateFormatString.DATE); |
||||
|
} |
||||
|
|
||||
|
public static String format(LocalDate localDate, DateFormatString format){ |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format.getValue()); |
||||
|
return localDate.format(formatter); |
||||
|
} |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
System.out.println(DateUtils.beSetTime(LocalDateTime.now(), ChronoUnit.DAYS,-2)); |
||||
|
// Get the LocalDateTime instance
|
||||
|
LocalDateTime ldt |
||||
|
= LocalDateTime |
||||
|
.parse("2019-12-31T19:15:30"); |
||||
|
|
||||
|
// Get the String representation of this LocalDateTime
|
||||
|
System.out.println("Original LocalDateTime: " |
||||
|
+ ldt.toString()); |
||||
|
|
||||
|
// subtract 200 DAYS to LocalDateTime
|
||||
|
LocalDateTime value |
||||
|
= ldt.minus(200, ChronoUnit.DAYS); |
||||
|
|
||||
|
// print result
|
||||
|
System.out.println("LocalDateTime after subtracting DAYS: " |
||||
|
+ value); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import cn.hutool.core.lang.Snowflake; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.Random; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/3 |
||||
|
*/ |
||||
|
public class IdUtil extends cn.hutool.core.util.IdUtil { |
||||
|
|
||||
|
private static final long BASE_DIFF_MILLIS = 1648013774104L; |
||||
|
|
||||
|
private static final Snowflake snowflake = getSnowflake(1,1); |
||||
|
|
||||
|
public static String timeStampId() { |
||||
|
long millis = System.currentTimeMillis(); |
||||
|
String prefix = String.format("%013d", millis-BASE_DIFF_MILLIS); |
||||
|
Random random = new Random(); |
||||
|
int end2 = random.nextInt(999); |
||||
|
return prefix + String.format("%03d", end2); |
||||
|
} |
||||
|
|
||||
|
public static Long timeStampLong() { |
||||
|
return System.currentTimeMillis()-BASE_DIFF_MILLIS; |
||||
|
} |
||||
|
|
||||
|
public static String dateTimeStampId() { |
||||
|
LocalDateTime localDateTime = LocalDateTime.now(); |
||||
|
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); |
||||
|
String localTime = df.format(localDateTime); |
||||
|
Random random = new Random(); |
||||
|
int end2 = random.nextInt(999); |
||||
|
return localTime + String.format("%03d", end2); |
||||
|
} |
||||
|
|
||||
|
public static String genCode(int len) { |
||||
|
int max = new Double(Math.pow(10, len)).intValue() - 1; |
||||
|
Random random = new Random(); |
||||
|
int end2 = random.nextInt(max); |
||||
|
return String.format("%0"+len+"d", end2); |
||||
|
} |
||||
|
|
||||
|
public static long getSnowFlakeId(){ |
||||
|
return snowflake.nextId(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,99 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.fasterxml.jackson.annotation.JsonInclude; |
||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
|
import com.fasterxml.jackson.databind.JavaType; |
||||
|
import com.fasterxml.jackson.databind.MapperFeature; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Jackson json序列化和反序列化工具类 |
||||
|
* @Author JcYen |
||||
|
* @Date 2019/6/3 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class JsonUtil { |
||||
|
|
||||
|
/** |
||||
|
* jackson对象 |
||||
|
*/ |
||||
|
static final ObjectMapper MAPPER = new ObjectMapper(); |
||||
|
|
||||
|
static { |
||||
|
MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); |
||||
|
MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将对象转换成json字符串。 |
||||
|
*/ |
||||
|
public static String objectToJson(Object data) { |
||||
|
try { |
||||
|
String string = MAPPER.writeValueAsString(data); |
||||
|
return string; |
||||
|
} catch (JsonProcessingException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 将json结果集转化为对象 |
||||
|
* |
||||
|
* @param jsonData json数据 |
||||
|
* @param beanType 对象中的object类型 |
||||
|
*/ |
||||
|
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) { |
||||
|
try { |
||||
|
T t = MAPPER.readValue(jsonData, beanType); |
||||
|
return t; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将json数据转换成pojo对象list |
||||
|
*/ |
||||
|
public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) { |
||||
|
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); |
||||
|
try { |
||||
|
List<T> list = MAPPER.readValue(jsonData, javaType); |
||||
|
return list; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static Map<String, Object> jsonToMap(String jsonStr){ |
||||
|
Map<String, Object> json = JSONObject.parseObject(jsonStr, Map.class); |
||||
|
return json; |
||||
|
} |
||||
|
|
||||
|
public static Map<String,Object> objectToMap(Object object){ |
||||
|
Map<String,Object> map = JSONObject.parseObject(JSON.toJSONString(object)); |
||||
|
return map; |
||||
|
} |
||||
|
|
||||
|
public static <T> List<Map<String,Object>> listToMap(List<T> objects){ |
||||
|
List<Map<String,Object>> result = new ArrayList<>(); |
||||
|
for (T object : objects) { |
||||
|
Map<String,Object> map = objectToMap(object); |
||||
|
result.add(map); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,82 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.auth0.jwt.JWT; |
||||
|
import com.auth0.jwt.JWTVerifier; |
||||
|
import com.auth0.jwt.algorithms.Algorithm; |
||||
|
import com.qs.serve.common.config.JwtConfig; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUserType; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.security.authentication.BadCredentialsException; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.temporal.ChronoUnit; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class JwtUtils { |
||||
|
|
||||
|
private final static String USER_ID_CLAIM = "UID"; |
||||
|
private final static String USER_TYPE_CLAIM = "TYPE"; |
||||
|
private final static String USER_CLIENT_CLAIM = "CLIENT"; |
||||
|
|
||||
|
private final static JwtConfig jwtConfig = new JwtConfig(); |
||||
|
|
||||
|
public static String generateToken(String userId, LoginUserType userType,String client) { |
||||
|
LocalDateTime dateTime = LocalDateTime.now(); |
||||
|
LocalDateTime exTime = DateUtils.beSetTime(dateTime, ChronoUnit.DAYS,jwtConfig.getExpire()); |
||||
|
Algorithm algorithm = Algorithm.HMAC256(jwtConfig.getSecret()); |
||||
|
return JWT.create() |
||||
|
.withIssuer(jwtConfig.getIss()) |
||||
|
.withIssuedAt(DateUtils.toDate(dateTime)) |
||||
|
.withExpiresAt(DateUtils.toDate(exTime)) |
||||
|
.withClaim(USER_TYPE_CLAIM,userType.getCode()) |
||||
|
.withClaim(USER_ID_CLAIM,userId) |
||||
|
.withClaim(USER_CLIENT_CLAIM,client) |
||||
|
.sign(algorithm); |
||||
|
} |
||||
|
|
||||
|
public static boolean verify(String token) { |
||||
|
try{ |
||||
|
Algorithm algorithm = Algorithm.HMAC256(jwtConfig.getSecret()); |
||||
|
JWTVerifier verifier = JWT.require(algorithm) |
||||
|
.withIssuer(jwtConfig.getIss()) |
||||
|
.build(); |
||||
|
verifier.verify(token); |
||||
|
return true; |
||||
|
} catch (Exception ex){ |
||||
|
log.debug("令牌验证异常:{}",ex.getMessage()); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static String getUserId(String token) { |
||||
|
try{ |
||||
|
return JWT.decode(token).getClaim(USER_ID_CLAIM).asString(); |
||||
|
}catch (Exception ex){ |
||||
|
log.debug("方法:getUserId() 令牌验证异常:{}",ex.getMessage()); |
||||
|
throw new BadCredentialsException("调用凭证无效"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static String getUserType(String token) { |
||||
|
try{ |
||||
|
return JWT.decode(token).getClaim(USER_TYPE_CLAIM).asString(); |
||||
|
}catch (Exception ex){ |
||||
|
log.debug("方法:getUserId() 令牌验证异常:{}",ex.getMessage()); |
||||
|
throw new BadCredentialsException("调用凭证无效"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static String getClient(String token) { |
||||
|
try{ |
||||
|
return JWT.decode(token).getClaim(USER_CLIENT_CLAIM).asString(); |
||||
|
}catch (Exception ex){ |
||||
|
log.debug("方法:getUserId() 令牌验证异常:{}",ex.getMessage()); |
||||
|
throw new BadCredentialsException("调用凭证无效"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,84 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.qs.serve.common.model.enums.PolicyType; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/10 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class MinioUtil { |
||||
|
|
||||
|
public static String getPolicy(String bucketName, PolicyType policyType) { |
||||
|
StringBuilder builder = new StringBuilder(); |
||||
|
builder.append("{\n"); |
||||
|
builder.append(" \"Statement\": [\n"); |
||||
|
builder.append(" {\n"); |
||||
|
builder.append(" \"Action\": [\n"); |
||||
|
if (policyType == PolicyType.WRITE) { |
||||
|
builder.append(" \"s3:GetBucketLocation\",\n"); |
||||
|
builder.append(" \"s3:ListBucketMultipartUploads\"\n"); |
||||
|
} else if (policyType == PolicyType.READ_WRITE) { |
||||
|
builder.append(" \"s3:GetBucketLocation\",\n"); |
||||
|
builder.append(" \"s3:ListBucket\",\n"); |
||||
|
builder.append(" \"s3:ListBucketMultipartUploads\"\n"); |
||||
|
} else { |
||||
|
builder.append(" \"s3:GetBucketLocation\"\n"); |
||||
|
} |
||||
|
builder.append(" ],\n"); |
||||
|
builder.append(" \"Effect\": \"Allow\",\n"); |
||||
|
builder.append(" \"Principal\": \"*\",\n"); |
||||
|
builder.append(" \"Resource\": \"arn:aws:s3:::"); |
||||
|
builder.append(bucketName); |
||||
|
builder.append("\"\n"); |
||||
|
builder.append(" },\n"); |
||||
|
if (PolicyType.READ.equals(policyType)) { |
||||
|
builder.append(" {\n"); |
||||
|
builder.append(" \"Action\": [\n"); |
||||
|
builder.append(" \"s3:ListBucket\"\n"); |
||||
|
builder.append(" ],\n"); |
||||
|
builder.append(" \"Effect\": \"Deny\",\n"); |
||||
|
builder.append(" \"Principal\": \"*\",\n"); |
||||
|
builder.append(" \"Resource\": \"arn:aws:s3:::"); |
||||
|
builder.append(bucketName); |
||||
|
builder.append("\"\n"); |
||||
|
builder.append(" },\n"); |
||||
|
} |
||||
|
builder.append(" {\n"); |
||||
|
builder.append(" \"Action\": "); |
||||
|
switch (policyType) { |
||||
|
case WRITE: |
||||
|
builder.append("[\n"); |
||||
|
builder.append(" \"s3:AbortMultipartUpload\",\n"); |
||||
|
builder.append(" \"s3:DeleteObject\",\n"); |
||||
|
builder.append(" \"s3:ListMultipartUploadParts\",\n"); |
||||
|
builder.append(" \"s3:PutObject\"\n"); |
||||
|
builder.append(" ],\n"); |
||||
|
break; |
||||
|
case READ_WRITE: |
||||
|
builder.append("[\n"); |
||||
|
builder.append(" \"s3:AbortMultipartUpload\",\n"); |
||||
|
builder.append(" \"s3:DeleteObject\",\n"); |
||||
|
builder.append(" \"s3:GetObject\",\n"); |
||||
|
builder.append(" \"s3:ListMultipartUploadParts\",\n"); |
||||
|
builder.append(" \"s3:PutObject\"\n"); |
||||
|
builder.append(" ],\n"); |
||||
|
break; |
||||
|
default: |
||||
|
builder.append("\"s3:GetObject\",\n"); |
||||
|
break; |
||||
|
} |
||||
|
builder.append(" \"Effect\": \"Allow\",\n"); |
||||
|
builder.append(" \"Principal\": \"*\",\n"); |
||||
|
builder.append(" \"Resource\": \"arn:aws:s3:::"); |
||||
|
builder.append(bucketName); |
||||
|
builder.append("/*\"\n"); |
||||
|
builder.append(" }\n"); |
||||
|
builder.append(" ],\n"); |
||||
|
builder.append(" \"Version\": \"2012-10-17\"\n"); |
||||
|
builder.append("}\n"); |
||||
|
return builder.toString(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,60 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import java.security.SecureRandom; |
||||
|
import java.util.Random; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/4/11 |
||||
|
*/ |
||||
|
public final class NanoIdUtils { |
||||
|
public static final SecureRandom DEFAULT_NUMBER_GENERATOR = new SecureRandom(); |
||||
|
public static final char[] DEFAULT_ALPHABET = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); |
||||
|
public static final int DEFAULT_SIZE = 21; |
||||
|
|
||||
|
private NanoIdUtils() { |
||||
|
} |
||||
|
|
||||
|
public static String randomNanoId() { |
||||
|
return randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, 21); |
||||
|
} |
||||
|
|
||||
|
public static String randomNanoId(Random random, char[] alphabet, int size) { |
||||
|
if (random == null) { |
||||
|
throw new IllegalArgumentException("random cannot be null."); |
||||
|
} else if (alphabet == null) { |
||||
|
throw new IllegalArgumentException("alphabet cannot be null."); |
||||
|
} else if (alphabet.length != 0 && alphabet.length < 256) { |
||||
|
if (size <= 0) { |
||||
|
throw new IllegalArgumentException("size must be greater than zero."); |
||||
|
} else { |
||||
|
int mask = (2 << (int)Math.floor(Math.log((double)(alphabet.length - 1)) / Math.log(2.0D))) - 1; |
||||
|
int step = (int)Math.ceil(1.6D * (double)mask * (double)size / (double)alphabet.length); |
||||
|
StringBuilder idBuilder = new StringBuilder(); |
||||
|
|
||||
|
while(true) { |
||||
|
byte[] bytes = new byte[step]; |
||||
|
random.nextBytes(bytes); |
||||
|
|
||||
|
for(int i = 0; i < step; ++i) { |
||||
|
int alphabetIndex = bytes[i] & mask; |
||||
|
if (alphabetIndex < alphabet.length) { |
||||
|
idBuilder.append(alphabet[alphabetIndex]); |
||||
|
if (idBuilder.length() == size) { |
||||
|
return idBuilder.toString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
throw new IllegalArgumentException("alphabet must contain between 1 and 255 symbols."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
for (int i = 0; i < 1000; i++) { |
||||
|
System.out.println(randomNanoId()); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,169 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.metadata.OrderItem; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
import com.github.pagehelper.PageHelper; |
||||
|
import com.qs.serve.common.framework.exception.BusinessException; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 翻页工具类 |
||||
|
* @Author YenHex |
||||
|
* @Date 2021/6/9 |
||||
|
* @Version: 1.0 |
||||
|
**/ |
||||
|
@UtilityClass |
||||
|
public class PageUtil { |
||||
|
|
||||
|
private static final String PAGE_NUM = "pageNum"; |
||||
|
private static final String PAGE_SIZE = "pageSize"; |
||||
|
|
||||
|
private static final String ORDER_TYPE = "orderType"; |
||||
|
private static final String ORDER_PROP = "orderProp"; |
||||
|
|
||||
|
private static final String ORDER_TYPE_ASC = "ASC"; |
||||
|
private static final String ORDER_TYPE_DESC = "DESC"; |
||||
|
|
||||
|
private static final int MAX_PAGE_SIZE = 66; |
||||
|
|
||||
|
public static <T> Page<T> getMbpPage(){ |
||||
|
Integer pageNum = getPageNum(); |
||||
|
Integer pageSize = getPageSize(); |
||||
|
String orderProp = getOrderProp(); |
||||
|
String orderType = getOrderType(); |
||||
|
if ( pageNum ==null || pageNum<1 || pageSize==null || pageSize<1) { |
||||
|
throw new BusinessException("翻页参数异常",500); |
||||
|
} |
||||
|
Page<T> page = new Page<>(); |
||||
|
page.setCurrent(pageNum); |
||||
|
page.setSize(pageSize); |
||||
|
if(StringUtils.hasText(orderProp)){ |
||||
|
OrderItem orderItem = new OrderItem(); |
||||
|
orderItem.setColumn(orderProp); |
||||
|
orderItem.setAsc(orderType.equals(ORDER_TYPE_ASC)); |
||||
|
List<OrderItem> orderItems = new ArrayList<>(); |
||||
|
orderItems.add(orderItem); |
||||
|
page.setOrders(orderItems); |
||||
|
} |
||||
|
return page; |
||||
|
} |
||||
|
|
||||
|
public static Integer getPageNum(){ |
||||
|
Integer pageNum=null; |
||||
|
String pageNumStr = ServletUtils.getParameter(PAGE_NUM); |
||||
|
if(StringUtils.hasText(pageNumStr)){ |
||||
|
pageNum = Integer.parseInt(pageNumStr); |
||||
|
} |
||||
|
return pageNum; |
||||
|
} |
||||
|
|
||||
|
public static Integer getPageSize(){ |
||||
|
String pageSizeStr = ServletUtils.getParameter(PAGE_SIZE); |
||||
|
Integer pageSize = null; |
||||
|
if(StringUtils.hasText(pageSizeStr)){ |
||||
|
pageSize = Integer.parseInt(pageSizeStr); |
||||
|
} |
||||
|
if(pageSize!=null && pageSize > MAX_PAGE_SIZE){ |
||||
|
throw new BusinessException("超出数据额度",500); |
||||
|
} |
||||
|
return pageSize; |
||||
|
} |
||||
|
|
||||
|
public static String getOrderProp(){ |
||||
|
String orderProp = ServletUtils.getParameter(ORDER_PROP); |
||||
|
if(StringUtils.hasText(orderProp)){ |
||||
|
orderProp = orderProp.trim(); |
||||
|
if(orderProp.contains(".")){ |
||||
|
String[] strings = orderProp.split("\\."); |
||||
|
return strings[0]+"."+strings[1]; |
||||
|
} |
||||
|
return WordUtil.toLine(orderProp); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static String getOrderType(){ |
||||
|
String orderType = ServletUtils.getParameter(ORDER_TYPE); |
||||
|
if(StringUtils.hasText(orderType)){ |
||||
|
if(orderType.equalsIgnoreCase(ORDER_TYPE_DESC)){ |
||||
|
return ORDER_TYPE_DESC; |
||||
|
} |
||||
|
} |
||||
|
return ORDER_TYPE_ASC; |
||||
|
} |
||||
|
|
||||
|
public static Integer getStartRow(){ |
||||
|
Integer pageNum = getPageNum(); |
||||
|
Integer pageSize = getPageSize(); |
||||
|
if (pageNum==null || pageSize==null) { |
||||
|
throw new BusinessException("翻页参数异常",500); |
||||
|
} |
||||
|
return (pageNum-1)*pageSize; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 启动翻页(翻页失败,会抛出异常) |
||||
|
* @return 是否使用翻页 |
||||
|
*/ |
||||
|
public static boolean startPage(){ |
||||
|
return startPage(true); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @param throwEx 是否抛异常 |
||||
|
* @return 是否使用翻页 |
||||
|
*/ |
||||
|
public static boolean startPage(boolean throwEx){ |
||||
|
return startPage(null,null,throwEx); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执行翻页 |
||||
|
* @param object POJO |
||||
|
* @return 是否使用翻页 |
||||
|
*/ |
||||
|
public static <T> boolean startPage(T object){ |
||||
|
return startPage(object,null,true); |
||||
|
} |
||||
|
|
||||
|
public static <T> boolean startPage(String prefix){ |
||||
|
return startPage(null,prefix,true); |
||||
|
} |
||||
|
/** |
||||
|
* |
||||
|
* @param throwEx 是否抛异常 |
||||
|
* @return 是否使用翻页 |
||||
|
*/ |
||||
|
public static <T> boolean startPage(T object,String prefix,boolean throwEx){ |
||||
|
Integer pageNum = getPageNum(); |
||||
|
Integer pageSize = getPageSize(); |
||||
|
String orderProp = getOrderProp(); |
||||
|
String orderType = getOrderType(); |
||||
|
if (pageNum!=null && pageNum>0 && pageSize!=null && pageSize>0) { |
||||
|
if(!StringUtils.isEmpty(orderProp)){ |
||||
|
if(prefix==null && object!=null){ |
||||
|
prefix = WordUtil.toLine(object.getClass().getSimpleName()); |
||||
|
} |
||||
|
if(prefix!=null){ |
||||
|
PageHelper.startPage(pageNum, pageSize).setOrderBy(prefix+"."+orderProp+" "+orderType); |
||||
|
}else { |
||||
|
PageHelper.startPage(pageNum, pageSize).setOrderBy(orderProp+" "+orderType); |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
PageHelper.startPage(pageNum, pageSize); |
||||
|
return true; |
||||
|
}else{ |
||||
|
if(throwEx){ |
||||
|
throw new BusinessException("翻页参数异常",500); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,129 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import org.springframework.http.MediaType; |
||||
|
import org.springframework.web.context.request.RequestAttributes; |
||||
|
import org.springframework.web.context.request.RequestContextHolder; |
||||
|
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
|
||||
|
import javax.servlet.ServletRequest; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.servlet.http.HttpSession; |
||||
|
import java.io.BufferedReader; |
||||
|
import java.io.IOException; |
||||
|
import java.io.InputStream; |
||||
|
import java.io.InputStreamReader; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
|
||||
|
/** |
||||
|
* Servlet容器工具类 |
||||
|
* @author YenHex |
||||
|
* @date 2021/6/9 |
||||
|
**/ |
||||
|
@UtilityClass |
||||
|
public class ServletUtils { |
||||
|
/** |
||||
|
* 获取String参数 |
||||
|
*/ |
||||
|
public static String getParameter(String name) { |
||||
|
return getRequest().getParameter(name); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取String参数 |
||||
|
*/ |
||||
|
public static String getHeader(String name) { |
||||
|
return getRequest().getHeader(name); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取IP |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getIp(HttpServletRequest request) { |
||||
|
if(request==null){ |
||||
|
request = getRequest(); |
||||
|
} |
||||
|
String ip = request.getHeader("x-forwarded-for"); |
||||
|
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
|
ip = request.getHeader("Proxy-Client-IP"); |
||||
|
} |
||||
|
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
|
ip = request.getHeader("WL-Proxy-Client-IP"); |
||||
|
} |
||||
|
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
|
ip = request.getRemoteAddr(); |
||||
|
} |
||||
|
return ip; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断本次请求的数据类型是否为json |
||||
|
* @param request request |
||||
|
* @return true: 是 JSON 数据; false: 非 json 数据 |
||||
|
*/ |
||||
|
public static boolean isJsonRequest(HttpServletRequest request) { |
||||
|
if (request.getContentType() != null) { |
||||
|
return request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE) || |
||||
|
request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取请求Body |
||||
|
* @param request |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getBodyString(ServletRequest request) { |
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
InputStream inputStream = null; |
||||
|
BufferedReader reader = null; |
||||
|
try { |
||||
|
inputStream = request.getInputStream(); |
||||
|
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); |
||||
|
String line = ""; |
||||
|
while ((line = reader.readLine()) != null) { |
||||
|
sb.append(line); |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
} finally { |
||||
|
if (inputStream != null) { |
||||
|
try { |
||||
|
inputStream.close(); |
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
if (reader != null) { |
||||
|
try { |
||||
|
reader.close(); |
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return sb.toString(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取request |
||||
|
*/ |
||||
|
public static HttpServletRequest getRequest() { |
||||
|
return getRequestAttributes().getRequest(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取session |
||||
|
*/ |
||||
|
public static HttpSession getSession() { |
||||
|
return getRequest().getSession(); |
||||
|
} |
||||
|
|
||||
|
private static ServletRequestAttributes getRequestAttributes() { |
||||
|
RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); |
||||
|
return (ServletRequestAttributes) attributes; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.qs.serve.modules.wx.common.model.WxSmsProp; |
||||
|
import com.qs.serve.modules.wx.entity.dto.SmsBaseDto; |
||||
|
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; |
||||
|
|
||||
|
import java.lang.annotation.Annotation; |
||||
|
import java.lang.reflect.Field; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/16 |
||||
|
*/ |
||||
|
public class SmsReflectUtil { |
||||
|
|
||||
|
/** |
||||
|
* 反射获取WX_SMS配置 |
||||
|
* @param baseDto |
||||
|
* @param <T> |
||||
|
* @return |
||||
|
*/ |
||||
|
public static<T extends SmsBaseDto> List<WxMpTemplateData> getTemplateDataList(T baseDto){ |
||||
|
List<WxMpTemplateData> dataList = new ArrayList<>(); |
||||
|
for (Field field : baseDto.getClass().getDeclaredFields()) { |
||||
|
WxSmsProp wxSmsProp = null; |
||||
|
for (Annotation annotation : field.getAnnotations()) { |
||||
|
if(annotation instanceof WxSmsProp){ |
||||
|
wxSmsProp = (WxSmsProp)annotation; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
try { |
||||
|
field.setAccessible(true); |
||||
|
Object fieldObject = field.get(baseDto); |
||||
|
String value = ""; |
||||
|
if(fieldObject!=null){ |
||||
|
value = fieldObject.toString(); |
||||
|
} |
||||
|
WxMpTemplateData templateData = new WxMpTemplateData(wxSmsProp.keyword(),value); |
||||
|
dataList.add(templateData); |
||||
|
} catch (IllegalAccessException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
return dataList; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,148 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import cn.hutool.core.collection.CollectionUtil; |
||||
|
import org.springframework.aop.framework.AopContext; |
||||
|
import org.springframework.beans.BeansException; |
||||
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
||||
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; |
||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
||||
|
import org.springframework.context.ApplicationContext; |
||||
|
import org.springframework.context.ApplicationContextAware; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
/** |
||||
|
* spring工具类 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/28 |
||||
|
*/ |
||||
|
@Component |
||||
|
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware |
||||
|
{ |
||||
|
/** Spring应用上下文环境 */ |
||||
|
private static ConfigurableListableBeanFactory beanFactory; |
||||
|
|
||||
|
private static ApplicationContext applicationContext; |
||||
|
|
||||
|
@Override |
||||
|
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException |
||||
|
{ |
||||
|
SpringUtils.beanFactory = beanFactory; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException |
||||
|
{ |
||||
|
SpringUtils.applicationContext = applicationContext; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取对象 |
||||
|
* |
||||
|
* @param name |
||||
|
* @return Object 一个以所给名字注册的bean的实例 |
||||
|
* @throws BeansException |
||||
|
* |
||||
|
*/ |
||||
|
@SuppressWarnings("unchecked") |
||||
|
public static <T> T getBean(String name) throws BeansException |
||||
|
{ |
||||
|
return (T) beanFactory.getBean(name); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取类型为requiredType的对象 |
||||
|
* |
||||
|
* @param clz |
||||
|
* @return |
||||
|
* @throws BeansException |
||||
|
* |
||||
|
*/ |
||||
|
public static <T> T getBean(Class<T> clz) throws BeansException |
||||
|
{ |
||||
|
T result = (T) beanFactory.getBean(clz); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true |
||||
|
* |
||||
|
* @param name |
||||
|
* @return boolean |
||||
|
*/ |
||||
|
public static boolean containsBean(String name) |
||||
|
{ |
||||
|
return beanFactory.containsBean(name); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) |
||||
|
* |
||||
|
* @param name |
||||
|
* @return boolean |
||||
|
* @throws NoSuchBeanDefinitionException |
||||
|
* |
||||
|
*/ |
||||
|
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException |
||||
|
{ |
||||
|
return beanFactory.isSingleton(name); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param name |
||||
|
* @return Class 注册对象的类型 |
||||
|
* @throws NoSuchBeanDefinitionException |
||||
|
* |
||||
|
*/ |
||||
|
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException |
||||
|
{ |
||||
|
return beanFactory.getType(name); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 如果给定的bean名字在bean定义中有别名,则返回这些别名 |
||||
|
* |
||||
|
* @param name |
||||
|
* @return |
||||
|
* @throws NoSuchBeanDefinitionException |
||||
|
* |
||||
|
*/ |
||||
|
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException |
||||
|
{ |
||||
|
return beanFactory.getAliases(name); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取aop代理对象 |
||||
|
* |
||||
|
* @param invoker |
||||
|
* @return |
||||
|
*/ |
||||
|
@SuppressWarnings("unchecked") |
||||
|
public static <T> T getAopProxy(T invoker) |
||||
|
{ |
||||
|
return (T) AopContext.currentProxy(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取当前的环境配置,无配置返回null |
||||
|
* |
||||
|
* @return 当前的环境配置 |
||||
|
*/ |
||||
|
public static String[] getActiveProfiles() |
||||
|
{ |
||||
|
return applicationContext.getEnvironment().getActiveProfiles(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取当前的环境配置,当有多个环境配置时,只获取第一个 |
||||
|
* |
||||
|
* @return 当前的环境配置 |
||||
|
*/ |
||||
|
public static String getActiveProfile() |
||||
|
{ |
||||
|
final String[] activeProfiles = getActiveProfiles(); |
||||
|
return CollectionUtil.isNotEmpty(Arrays.asList(activeProfiles)) ? activeProfiles[0] : null; |
||||
|
} |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/28 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class StringUtils extends org.springframework.util.StringUtils { |
||||
|
|
||||
|
/** 非空 */ |
||||
|
public static boolean isNotEmpty(String str){ |
||||
|
return !isEmpty(str); |
||||
|
} |
||||
|
|
||||
|
/** 含有空对象 */ |
||||
|
public static boolean hasEmpty(Object... strings){ |
||||
|
for (Object str : strings) { |
||||
|
if(isEmpty(str)){return true;} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 格式化 |
||||
|
* @param exp 含{}的表达式 |
||||
|
* @param params 参数(注意跳过空值) |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String format(String exp,String... params){ |
||||
|
StringBuilder builder = new StringBuilder(exp); |
||||
|
int idx_p = 0; |
||||
|
while (hasText(builder,"{}")){ |
||||
|
int idx = builder.indexOf("{}"); |
||||
|
if(idx_p<params.length&¶ms[idx_p]!=null){ |
||||
|
builder.replace(idx,idx+2,params[idx_p]); |
||||
|
idx_p++; |
||||
|
}else { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
return builder.toString(); |
||||
|
} |
||||
|
|
||||
|
private static boolean hasText(StringBuilder a,String text){ |
||||
|
return a.toString().contains(text); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,75 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import java.util.concurrent.*; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 线程相关 |
||||
|
* @author YenHex |
||||
|
* @since 2022-03-01 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@UtilityClass |
||||
|
public class ThreadsUtils { |
||||
|
|
||||
|
/** |
||||
|
* sleep等待,单位为毫秒 |
||||
|
*/ |
||||
|
public static void sleep(long milliseconds) { |
||||
|
try { |
||||
|
Thread.sleep(milliseconds); |
||||
|
} catch (InterruptedException e) { |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 停止线程池 |
||||
|
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. |
||||
|
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. |
||||
|
* 如果仍人超時,則強制退出. |
||||
|
* 另对在shutdown时线程本身被调用中断做了处理. |
||||
|
*/ |
||||
|
public static void shutdownAndAwaitTermination(ExecutorService pool) { |
||||
|
if (pool != null && !pool.isShutdown()) { |
||||
|
pool.shutdown(); |
||||
|
try { |
||||
|
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { |
||||
|
pool.shutdownNow(); |
||||
|
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { |
||||
|
log.info("Pool did not terminate"); |
||||
|
} |
||||
|
} |
||||
|
} catch (InterruptedException ie) { |
||||
|
pool.shutdownNow(); |
||||
|
Thread.currentThread().interrupt(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 打印线程异常信息 |
||||
|
*/ |
||||
|
public static void printException(Runnable r, Throwable t) { |
||||
|
if (t == null && r instanceof Future<?>) { |
||||
|
try { |
||||
|
Future<?> future = (Future<?>) r; |
||||
|
if (future.isDone()) { |
||||
|
future.get(); |
||||
|
} |
||||
|
} catch (CancellationException ce) { |
||||
|
t = ce; |
||||
|
} catch (ExecutionException ee) { |
||||
|
t = ee.getCause(); |
||||
|
} catch (InterruptedException ie) { |
||||
|
Thread.currentThread().interrupt(); |
||||
|
} |
||||
|
} |
||||
|
if (t != null) { |
||||
|
log.error(t.getMessage(), t); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,46 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
|
||||
|
import com.qs.serve.common.util.model.DesUtils; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/25 |
||||
|
*/ |
||||
|
public class TokenUtil { |
||||
|
|
||||
|
private static final String secretKey = "N2aD7vLTJjeo71vCHwbqYsSF9rZPUh"; |
||||
|
|
||||
|
/** |
||||
|
* 加密 |
||||
|
* @param userId |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String desEncrypt(String userId){ |
||||
|
String formatStr = userId+"-N2aD7vLTJjeo71vCHwbqYsSF9rZPUh"; |
||||
|
DesUtils des = new DesUtils(secretKey); |
||||
|
try { |
||||
|
return des.encrypt(formatStr); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 解密 |
||||
|
* @param encryptText |
||||
|
* @return clientId |
||||
|
*/ |
||||
|
public static String desDecrypt(String encryptText){ |
||||
|
DesUtils des = new DesUtils(secretKey); |
||||
|
try { |
||||
|
String formatStr = des.decrypt(encryptText); |
||||
|
return formatStr.split("-")[0]; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,74 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.qs.serve.common.model.dto.TreeNode; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class TreeUtil { |
||||
|
|
||||
|
public static final String DEFAULT_PID_STRING = "0"; |
||||
|
|
||||
|
/** |
||||
|
* 两层循环实现建树 |
||||
|
* @param treeNodes 传入的树节点列表 |
||||
|
* @param rootPid |
||||
|
* @return |
||||
|
* sorted(Comparator.comparingInt(DemoEntity::getSort)) |
||||
|
*/ |
||||
|
public <T extends TreeNode> List<T> build(List<T> treeNodes, String rootPid) { |
||||
|
List<T> trees = new ArrayList<>(); |
||||
|
for (T treeNode : treeNodes) { |
||||
|
if (rootPid.equals(treeNode.getParentId())) { |
||||
|
trees.add(treeNode); |
||||
|
} |
||||
|
for (T it : treeNodes) { |
||||
|
if (it.getParentId().equals(treeNode.getId())) { |
||||
|
treeNode.addChildren(it); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return trees; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 使用递归方法建树 |
||||
|
* |
||||
|
* @param treeNodes |
||||
|
* @return |
||||
|
*/ |
||||
|
public <T extends TreeNode> List<T> buildByRecursive(List<T> treeNodes, Object root) { |
||||
|
List<T> trees = new ArrayList<T>(); |
||||
|
for (T treeNode : treeNodes) { |
||||
|
if (root.equals(treeNode.getParentId())) { |
||||
|
trees.add(findChildren(treeNode, treeNodes)); |
||||
|
} |
||||
|
} |
||||
|
return trees; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 递归查找子节点 |
||||
|
* |
||||
|
* @param treeNodes |
||||
|
* @return |
||||
|
*/ |
||||
|
public <T extends TreeNode> T findChildren(T treeNode, List<T> treeNodes) { |
||||
|
for (T it : treeNodes) { |
||||
|
if (treeNode.getId().equals(it.getParentId())) { |
||||
|
if (treeNode.getChildren() == null) { |
||||
|
treeNode.setChildren(new ArrayList<>()); |
||||
|
} |
||||
|
treeNode.addChildren(findChildren(it, treeNodes)); |
||||
|
} |
||||
|
} |
||||
|
return treeNode; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import cn.hutool.core.io.FileUtil; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
import org.springframework.web.multipart.MultipartHttpServletRequest; |
||||
|
import org.springframework.web.util.WebUtils; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import java.io.File; |
||||
|
import java.io.IOException; |
||||
|
import java.time.LocalDate; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/14 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class UploadUtil { |
||||
|
|
||||
|
/** |
||||
|
* 返回相对地址 |
||||
|
* @param uploadPath 物理路径 |
||||
|
* @param fileName2 文件名 |
||||
|
* @param request |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String put(String uploadPath,final String fileName2,HttpServletRequest request){ |
||||
|
String contentType = request.getContentType(); |
||||
|
MultipartFile file = null; |
||||
|
if (contentType != null && contentType.toLowerCase().startsWith("multipart")) { |
||||
|
MultipartHttpServletRequest multipartHttpServletRequest = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); |
||||
|
file = multipartHttpServletRequest.getFile("file"); |
||||
|
} |
||||
|
if (file==null||file.isEmpty()) { |
||||
|
Assert.throwEx("请选择文件"); |
||||
|
} |
||||
|
String fileOrgName = file.getOriginalFilename(); |
||||
|
String mimeType = fileOrgName.substring(fileOrgName.lastIndexOf(".")); |
||||
|
String fileName = fileName2 + mimeType ; |
||||
|
String prefix = LocalDate.now().toString().replace("-","")+"/"; |
||||
|
try { |
||||
|
FileUtil.createTempFile(new File(uploadPath+prefix)); |
||||
|
File dest = new File(uploadPath + prefix + fileName); |
||||
|
file.transferTo(dest); |
||||
|
return prefix + fileName; |
||||
|
} catch (IOException e) { |
||||
|
log.error(e.toString(), e); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
|
import com.qs.serve.common.framework.mybatis.query.AnnotationQueryStorage; |
||||
|
import com.qs.serve.common.framework.mybatis.query.model.QueryFieldDataValue; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 生成SQL条件包装对象 |
||||
|
* @author YenHex |
||||
|
* @date 2022/2/28 |
||||
|
**/ |
||||
|
@UtilityClass |
||||
|
@Slf4j |
||||
|
public class WarpUtil extends AnnotationQueryStorage { |
||||
|
|
||||
|
private static final String ORDER_PROP_NAME = "prop"; |
||||
|
private static final String ORDER_TYPE_NAME = "order"; |
||||
|
private static final String ORDER_DESC = "desc"; |
||||
|
private static final String CREATE_TIME = "create_time"; |
||||
|
|
||||
|
private static final String START_TIME = "startTime"; |
||||
|
private static final String END_TIME = "endTime"; |
||||
|
|
||||
|
public static <T> QueryWrapper<T> build(T query){ |
||||
|
return build(query,false); |
||||
|
} |
||||
|
|
||||
|
public static <T> QueryWrapper<T> build(T query,Boolean orderAble){ |
||||
|
QueryWrapper<T> queryWrapper = new QueryWrapper<>(); |
||||
|
List<QueryFieldDataValue> dataValues = loadQueryFieldDataValues(query); |
||||
|
assert dataValues != null; |
||||
|
initWrap(dataValues,queryWrapper); |
||||
|
initBetweenTime(queryWrapper); |
||||
|
if(orderAble){ |
||||
|
String columnsString = ServletUtils.getParameter(ORDER_PROP_NAME); |
||||
|
String orderType = ServletUtils.getParameter(ORDER_TYPE_NAME); |
||||
|
if(StringUtils.isNotEmpty(columnsString)){ |
||||
|
String[] columns = columnsString.split(","); |
||||
|
if(orderType.equals(ORDER_DESC)){ |
||||
|
queryWrapper.orderByDesc(columns); |
||||
|
}else { |
||||
|
queryWrapper.orderByAsc(columns); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return queryWrapper; |
||||
|
} |
||||
|
|
||||
|
public static void initBetweenTime(QueryWrapper<?> queryWrapper){ |
||||
|
String startTime = ServletUtils.getParameter(START_TIME); |
||||
|
String endTime = ServletUtils.getParameter(END_TIME); |
||||
|
if(!StringUtils.hasEmpty(startTime,endTime)){ |
||||
|
queryWrapper.ge(CREATE_TIME,startTime); |
||||
|
queryWrapper.le(CREATE_TIME,endTime); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
package com.qs.serve.common.util; |
||||
|
|
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
/** |
||||
|
* 单词间转换工具类 |
||||
|
* @author JcYen |
||||
|
* @Date 2020/5/27 |
||||
|
* @Version 1.0 |
||||
|
*/ |
||||
|
@UtilityClass |
||||
|
public class WordUtil { |
||||
|
|
||||
|
public static String lowerFirst(String className){ |
||||
|
return lowerFirst(className,null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 类名首字母小写 |
||||
|
* @param className 类名 |
||||
|
* @param rmPrefix 移除的前缀,不区分大小写 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String lowerFirst(String className,String rmPrefix){ |
||||
|
if(className==null){throw new RuntimeException("className is null");} |
||||
|
if(rmPrefix!=null){ |
||||
|
String prefix = className.substring(0,rmPrefix.length()); |
||||
|
if(prefix.toLowerCase().equals(rmPrefix.toLowerCase())){ |
||||
|
className = className.substring(rmPrefix.length()); |
||||
|
} |
||||
|
} |
||||
|
char[]chars = className.toCharArray(); |
||||
|
chars[0] += 32; |
||||
|
return String.valueOf(chars); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数据库表名 转 类名 : ums_user_log ->> UmsUserLog |
||||
|
* 1.首字母转小写 |
||||
|
* 2.下横线后的字母大写,去掉"_"下横线, |
||||
|
* @param tableName |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String tableToClass(String tableName) { |
||||
|
if(StringUtils.isEmpty(tableName)){return null;} |
||||
|
char[] chars = tableName.toCharArray(); |
||||
|
for (int i = 0; i < chars.length; i++) { |
||||
|
if(Character.isLowerCase(chars[i])&&i==0){ |
||||
|
chars[i] = Character.toUpperCase(chars[i]); |
||||
|
} |
||||
|
if(chars[i] == '_' && i+1<chars.length){ |
||||
|
chars[i+1] = Character.toUpperCase(chars[i+1]); |
||||
|
} |
||||
|
} |
||||
|
return String.valueOf(chars).replace("_",""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数据库列 转 字段名 : ums_user_log ->> umsUserLog |
||||
|
* 1.首字母转小写 |
||||
|
* 2.下横线后的字母大写,去掉"_"下横线, |
||||
|
* @param columnName |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String columnToField(String columnName) { |
||||
|
if(StringUtils.isEmpty(columnName)){return null;} |
||||
|
char[] chars = columnName.toCharArray(); |
||||
|
for (int i = 0; i < chars.length; i++) { |
||||
|
if(chars[i] == '_' && i+1<chars.length){ |
||||
|
chars[i+1] = Character.toUpperCase(chars[i+1]); |
||||
|
} |
||||
|
} |
||||
|
return String.valueOf(chars).replace("_",""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字段名 转 数据库列 : umsUserLog / UmsUserLog ->> ums_user_log |
||||
|
* 1.首字母转小写 |
||||
|
* 2.字符非首个字母,添加"_"下横线,并大写字母转小写 |
||||
|
* @param fieldName |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String toLine(String fieldName) { |
||||
|
if(StringUtils.isEmpty(fieldName)){return null;} |
||||
|
columnToField(fieldName); |
||||
|
char[] chars = fieldName.toCharArray(); |
||||
|
int countUpper = 0; |
||||
|
for (int i = 0; i < chars.length; i++) { |
||||
|
if(Character.isUpperCase(chars[i])&&i!=0){ |
||||
|
countUpper ++ ; |
||||
|
} |
||||
|
} |
||||
|
char[] newChars = new char[chars.length+countUpper]; |
||||
|
//偏移量
|
||||
|
int offset = 0; |
||||
|
for (int i = 0; i < chars.length; i++) { |
||||
|
if(Character.isUpperCase(chars[i])){ |
||||
|
if(i!=0){ |
||||
|
newChars[i+offset] = '_'; |
||||
|
offset++; |
||||
|
} |
||||
|
} |
||||
|
newChars[i+offset] = Character.toLowerCase(chars[i]); |
||||
|
} |
||||
|
return String.valueOf(newChars); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
package com.qs.serve.common.util.model; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/17 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum DateFormatString { |
||||
|
|
||||
|
DATE_TIME("yyyy-MM-dd HH:mm:ss"), |
||||
|
DATE_TIME_NUM("yyyyMMddHHmmss"), |
||||
|
DATE_TIME_CN("yyyy年MM月dd日 HH时mm分ss秒"), |
||||
|
|
||||
|
DATE("yyyy-MM-dd"), |
||||
|
DATE_NUM("yyyyMMdd"), |
||||
|
DATE_CN("yyyy年MM月dd日"); |
||||
|
|
||||
|
private String value; |
||||
|
|
||||
|
} |
@ -0,0 +1,125 @@ |
|||||
|
package com.qs.serve.common.util.model; |
||||
|
|
||||
|
import javax.crypto.Cipher; |
||||
|
import java.security.Key; |
||||
|
|
||||
|
/** |
||||
|
* 使用DES算法对字符串进行加密解密 (加密解密的操作步骤正好相反, 参考 {@link #encrypt(String)}, {@link #decrypt(String)}) |
||||
|
*/ |
||||
|
public class DesUtils { |
||||
|
private static String defaultSecretKey = "default_secret_key"; //默认密钥
|
||||
|
private Cipher encryptCipher = null; //加密器
|
||||
|
private Cipher decryptCipher = null; //解密器
|
||||
|
|
||||
|
public DesUtils() throws Exception { |
||||
|
this(defaultSecretKey); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param secretKey 加密解密使用的密钥 |
||||
|
*/ |
||||
|
public DesUtils(String secretKey) { |
||||
|
Key key; |
||||
|
try { |
||||
|
key = getKey(secretKey.getBytes()); |
||||
|
encryptCipher = Cipher.getInstance("DES"); |
||||
|
encryptCipher.init(Cipher.ENCRYPT_MODE, key); |
||||
|
decryptCipher = Cipher.getInstance("DES"); |
||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, key); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 加密 (逻辑: 1. 将要加密的字符串转换为字节数组(byte array)<br/> |
||||
|
* 2. 将第一步的字节数组作为输入使用加密器(Cipher)的doFinal方法进行加密, 返回字节数组<br/> |
||||
|
* 3. 把加密后的字节数组转换成十六进制的字符串)<br/> |
||||
|
* @param strIn 要加密的字符串 |
||||
|
* @return 返回加密后的十六进制字符串 |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
public String encrypt(String strIn) throws Exception { |
||||
|
return byteArr2HexStr(encrypt(strIn.getBytes())); |
||||
|
} |
||||
|
|
||||
|
public byte[] encrypt(byte[] arrB) throws Exception { |
||||
|
return encryptCipher.doFinal(arrB); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 解密 (逻辑: 1. 把加密后的十六进制字符串转换成字节数组(byte array)<br/> |
||||
|
* 2. 将第一步的字节数组作为输入使用加密器(Cipher)的doFinal方法进行解密, 返回字节数组(byte array)<br/> |
||||
|
* 3. 把解密后的字节数组转换成字符串)<br/> |
||||
|
* @param strIn |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
public String decrypt(String strIn) throws Exception { |
||||
|
return new String(decrypt(hexStr2ByteArr(strIn))); |
||||
|
} |
||||
|
|
||||
|
public byte[] decrypt(byte[] arrB) throws Exception { |
||||
|
return decryptCipher.doFinal(arrB); |
||||
|
} |
||||
|
|
||||
|
public static String byteArr2HexStr(byte[] arrB) throws Exception { |
||||
|
int iLen = arrB.length; |
||||
|
// 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍
|
||||
|
StringBuffer sb = new StringBuffer(iLen * 2); |
||||
|
for (int i = 0; i < iLen; i++) { |
||||
|
int intTmp = arrB[i]; |
||||
|
// 把负数转换为正数
|
||||
|
while (intTmp < 0) { |
||||
|
intTmp = intTmp + 256; |
||||
|
} |
||||
|
// 小于0F的数需要在前面补0
|
||||
|
if (intTmp < 16) { |
||||
|
sb.append("0"); |
||||
|
} |
||||
|
sb.append(Integer.toString(intTmp, 16)); |
||||
|
} |
||||
|
return sb.toString(); |
||||
|
} |
||||
|
|
||||
|
public static byte[] hexStr2ByteArr(String strIn) throws Exception { |
||||
|
byte[] arrB = strIn.getBytes(); |
||||
|
int iLen = arrB.length; |
||||
|
// 两个字符表示一个字节,所以字节数组长度是字符串长度除以2
|
||||
|
byte[] arrOut = new byte[iLen / 2]; |
||||
|
for (int i = 0; i < iLen; i = i + 2) { |
||||
|
String strTmp = new String(arrB, i, 2); |
||||
|
arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16); |
||||
|
} |
||||
|
return arrOut; |
||||
|
} |
||||
|
|
||||
|
private Key getKey(byte[] arrBTmp) throws Exception { |
||||
|
// 创建一个空的8位字节数组(默认值为0)
|
||||
|
byte[] arrB = new byte[8]; |
||||
|
// 将原始字节数组转换为8位
|
||||
|
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) { |
||||
|
arrB[i] = arrBTmp[i]; |
||||
|
} |
||||
|
// 生成密钥
|
||||
|
Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES"); |
||||
|
return key; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 用法实例 |
||||
|
*/ |
||||
|
public static void main(String[] args) { |
||||
|
try { |
||||
|
String test = "liwc"; |
||||
|
DesUtils des = new DesUtils("leemenz"); //自定义密钥
|
||||
|
System.out.println("加密前的字符:" + test); |
||||
|
System.out.println("加密后的字符:" + des.encrypt(test)); |
||||
|
System.out.println("解密后的字符:" + des.decrypt(des.encrypt(test))); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,138 @@ |
|||||
|
package com.qs.serve.controller; |
||||
|
|
||||
|
import cn.hutool.crypto.SecureUtil; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.qs.serve.common.framework.redis.RedisService; |
||||
|
import com.qs.serve.common.model.annotation.LimitSubmit; |
||||
|
import com.qs.serve.common.model.annotation.SysLog; |
||||
|
import com.qs.serve.common.model.consts.RedisCacheKeys; |
||||
|
import com.qs.serve.common.model.dto.R; |
||||
|
import com.qs.serve.common.model.enums.BizType; |
||||
|
import com.qs.serve.common.util.IdUtil; |
||||
|
import com.qs.serve.modules.sys.entity.SysTenant; |
||||
|
import com.qs.serve.modules.sys.entity.SysUser; |
||||
|
import com.qs.serve.modules.sys.entity.dto.SysLoginByPhoneParam; |
||||
|
import com.qs.serve.modules.sys.entity.dto.SysLoginParam; |
||||
|
import com.qs.serve.modules.sys.entity.dto.SysResetPwdByPhoneParam; |
||||
|
import com.qs.serve.modules.sys.mapper.SysNoticeUserMapper; |
||||
|
import com.qs.serve.modules.sys.service.SysTenantService; |
||||
|
import com.qs.serve.modules.sys.service.SysUserLoginService; |
||||
|
import com.qs.serve.modules.sys.service.SysUserService; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import javax.validation.Valid; |
||||
|
import java.util.List; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* 门户:后台接口 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/2 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@AllArgsConstructor |
||||
|
@RestController |
||||
|
@RequestMapping("portal") |
||||
|
public class AdminPortalController { |
||||
|
|
||||
|
private SysTenantService sysTenantService; |
||||
|
private SysUserLoginService sysUserLoginService; |
||||
|
private RedisService redisService; |
||||
|
private SysUserService sysUserService; |
||||
|
|
||||
|
/** |
||||
|
* 获取所有租户 |
||||
|
* @return |
||||
|
*/ |
||||
|
@GetMapping("/listTenant") |
||||
|
public R<List<SysTenant>> getList(){ |
||||
|
List<SysTenant> list = sysTenantService.list2(); |
||||
|
return R.ok(list); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 登录接口 |
||||
|
* @return |
||||
|
*/ |
||||
|
@LimitSubmit |
||||
|
@SysLog(title = "人员",desc = "后台登录",biz = BizType.LOGIN,saveReqParam = false) |
||||
|
@PostMapping("/login") |
||||
|
public R<?> login(@RequestBody @Valid SysLoginParam param){ |
||||
|
return R.ok(sysUserLoginService.login(param)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 手机登陆 |
||||
|
* @return |
||||
|
*/ |
||||
|
@LimitSubmit |
||||
|
@SysLog(title = "人员",desc = "手机登陆",biz = BizType.LOGIN,saveReqParam = false) |
||||
|
@PostMapping("/phoneLogin") |
||||
|
public R<?> phoneLogin(@RequestBody @Valid SysLoginByPhoneParam param){ |
||||
|
return R.ok(sysUserLoginService.login(param)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 登出接口 |
||||
|
* @return |
||||
|
*/ |
||||
|
@SysLog(title = "人员",desc = "退出登录",biz = BizType.LOGOUT,saveReqParam = false) |
||||
|
@GetMapping("/logout") |
||||
|
public R<?> login(){ |
||||
|
return R.ok(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取用户手机验证码 |
||||
|
*/ |
||||
|
@LimitSubmit(interval = 10000,message = "请10秒后尝试") |
||||
|
@SysLog(title = "人员",desc = "获取用户手机验证码",biz = BizType.OTHER) |
||||
|
@GetMapping("/userPhoneCode/{phone}") |
||||
|
public R<?> phoneCode(@PathVariable("phone") String phone){ |
||||
|
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>(); |
||||
|
wrapper.eq(SysUser::getAccount,phone); |
||||
|
int count = sysUserService.count(wrapper); |
||||
|
if(count<1){ |
||||
|
return R.error("无效手机号,请重新输入"); |
||||
|
} |
||||
|
String key = RedisCacheKeys.PHONE_KEY+phone; |
||||
|
String code = redisService.getString(key); |
||||
|
if(code==null){ |
||||
|
code = IdUtil.genCode(6); |
||||
|
} |
||||
|
redisService.set(key,code,1, TimeUnit.MINUTES); |
||||
|
//TODO send msg
|
||||
|
return R.ok(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 重置手机用户密码 |
||||
|
*/ |
||||
|
@LimitSubmit(interval = 10000,message = "请10秒后尝试") |
||||
|
@SysLog(title = "人员",desc = "重置手机用户密码",biz = BizType.RESET) |
||||
|
@PostMapping("/resetPwdByPhone") |
||||
|
public R<?> phoneCode(@RequestBody @Valid SysResetPwdByPhoneParam param){ |
||||
|
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>(); |
||||
|
wrapper.eq(SysUser::getAccount,param.getPhone()); |
||||
|
List<SysUser> userList = sysUserService.list(wrapper); |
||||
|
if(userList.size()<1){ |
||||
|
return R.error("无效手机号,请重新输入"); |
||||
|
} |
||||
|
String key = RedisCacheKeys.PHONE_KEY+param.getPhone(); |
||||
|
String code = redisService.getString(key); |
||||
|
if(!param.getCode().equals(code)){ |
||||
|
return R.error("验证码无效或过期"); |
||||
|
} |
||||
|
SysUser sysUser = new SysUser(); |
||||
|
sysUser.setId(userList.get(0).getId()); |
||||
|
sysUser.setPassword(SecureUtil.md5(param.getNewPwd())); |
||||
|
sysUserService.updateById(sysUser); |
||||
|
return R.ok(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package com.qs.serve.controller; |
||||
|
|
||||
|
import com.qs.serve.common.model.dto.R; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.PathVariable; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
|
||||
|
/** |
||||
|
* 门户:API通用接口 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/14 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@AllArgsConstructor |
||||
|
@RestController |
||||
|
@RequestMapping("/api/common") |
||||
|
public class CommonApi { |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,103 @@ |
|||||
|
package com.qs.serve.controller; |
||||
|
|
||||
|
import com.qs.serve.common.config.properties.UploadProperties; |
||||
|
import com.qs.serve.common.model.annotation.SysLog; |
||||
|
import com.qs.serve.common.model.dto.R; |
||||
|
import com.qs.serve.common.model.enums.BizType; |
||||
|
import com.qs.serve.common.util.*; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
import org.springframework.web.multipart.MultipartHttpServletRequest; |
||||
|
import org.springframework.web.util.WebUtils; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import java.io.File; |
||||
|
import java.io.IOException; |
||||
|
import java.time.LocalDate; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 门户:后台通用接口 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/14 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@AllArgsConstructor |
||||
|
@RestController |
||||
|
@RequestMapping("/common") |
||||
|
public class CommonController { |
||||
|
|
||||
|
private UploadProperties uploadProperties; |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 单图上传 |
||||
|
* @apiNote file不能为空 |
||||
|
* @param request |
||||
|
* @return |
||||
|
*/ |
||||
|
@SysLog(title = "文件",biz = BizType.UPLOAD) |
||||
|
@PostMapping("/upload") |
||||
|
public R upload(HttpServletRequest request) { |
||||
|
String relativePath = UploadUtil.put(uploadProperties.getLogicalPath(),IdUtil.timeStampId(),request); |
||||
|
if(relativePath!=null){ |
||||
|
return R.ok(uploadProperties.getProxyUrl()+relativePath,"上传成功"); |
||||
|
} |
||||
|
return R.error("上传失败"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证token |
||||
|
* @param token |
||||
|
* @return |
||||
|
*/ |
||||
|
@PostMapping("/validToken") |
||||
|
public R validToken(String token) { |
||||
|
return R.isOk(JwtUtils.verify(token),"无效token"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 多图上传 |
||||
|
* @apiNote files不能为空 |
||||
|
* @param request |
||||
|
* @return |
||||
|
*/ |
||||
|
@SysLog(title = "文件",biz = BizType.UPLOAD) |
||||
|
@PostMapping( "/uploadMulti") |
||||
|
public R<?> multiUpload(HttpServletRequest request) { |
||||
|
String contentType = request.getContentType(); |
||||
|
List<MultipartFile> files = null; |
||||
|
if (contentType != null && contentType.toLowerCase().startsWith("multipart")) { |
||||
|
MultipartHttpServletRequest multipartHttpServletRequest = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); |
||||
|
files = multipartHttpServletRequest.getFiles("files"); |
||||
|
} |
||||
|
if (files==null||files.isEmpty()) { |
||||
|
return R.error("请选择文件"); |
||||
|
} |
||||
|
List<String> list = new ArrayList<>(); |
||||
|
for (int i = 0; i < files.size(); i++) { |
||||
|
MultipartFile file = files.get(i); |
||||
|
if (file.isEmpty()) { |
||||
|
return R.error("上传第" + (i++) + "个文件失败"); |
||||
|
} |
||||
|
String fileOrgName = file.getOriginalFilename(); |
||||
|
String mimeType = fileOrgName.substring(fileOrgName.lastIndexOf(".")); |
||||
|
String filePath = LocalDate.now().toString().replace("-","")+"/"+ IdUtil.timeStampId()+mimeType; |
||||
|
String uploadPath = uploadProperties.getLogicalPath(); |
||||
|
File dest = new File(uploadPath + filePath); |
||||
|
try { |
||||
|
file.transferTo(dest); |
||||
|
list.add(uploadProperties.getProxyUrl()+filePath); |
||||
|
} catch (IOException e) { |
||||
|
log.error(e.toString(), e); |
||||
|
return R.error("上传第" + (i++) + "个文件失败"); |
||||
|
} |
||||
|
} |
||||
|
return R.ok(list); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,129 @@ |
|||||
|
package com.qs.serve.controller; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import me.chanjar.weixin.mp.api.WxMpMessageRouter; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.PathVariable; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import me.chanjar.weixin.mp.api.WxMpService; |
||||
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; |
||||
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; |
||||
|
|
||||
|
/** |
||||
|
* 门户:微信公众号回调 |
||||
|
* @author YenHex |
||||
|
* @since 2022-03-07 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@AllArgsConstructor |
||||
|
//@RestController
|
||||
|
//@RequestMapping("/api/wx/mp/portal/{appid}")
|
||||
|
public class WxMpPortalApi { |
||||
|
|
||||
|
private final WxMpService wxService; |
||||
|
private final WxMpMessageRouter messageRouter; |
||||
|
|
||||
|
/** |
||||
|
* 校验身份 |
||||
|
* @param appid |
||||
|
* @param signature |
||||
|
* @param timestamp |
||||
|
* @param nonce |
||||
|
* @param echostr |
||||
|
* @return |
||||
|
*/ |
||||
|
@GetMapping(produces = "text/plain;charset=utf-8") |
||||
|
public String authGet(@PathVariable String appid, |
||||
|
@RequestParam(name = "signature", required = false) String signature, |
||||
|
@RequestParam(name = "timestamp", required = false) String timestamp, |
||||
|
@RequestParam(name = "nonce", required = false) String nonce, |
||||
|
@RequestParam(name = "echostr", required = false) String echostr) { |
||||
|
|
||||
|
log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, |
||||
|
timestamp, nonce, echostr); |
||||
|
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { |
||||
|
throw new IllegalArgumentException("请求参数非法,请核实!"); |
||||
|
} |
||||
|
if (!this.wxService.switchover(appid)) { |
||||
|
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid)); |
||||
|
} |
||||
|
if (wxService.checkSignature(timestamp, nonce, signature)) { |
||||
|
return echostr; |
||||
|
} |
||||
|
return "非法请求"; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 身份校验2 |
||||
|
* @param appid |
||||
|
* @param requestBody |
||||
|
* @param signature |
||||
|
* @param timestamp |
||||
|
* @param nonce |
||||
|
* @param openid |
||||
|
* @param encType |
||||
|
* @param msgSignature |
||||
|
* @return |
||||
|
*/ |
||||
|
@PostMapping(produces = "application/xml; charset=UTF-8") |
||||
|
public String post(@PathVariable String appid, |
||||
|
@RequestBody String requestBody, |
||||
|
@RequestParam("signature") String signature, |
||||
|
@RequestParam("timestamp") String timestamp, |
||||
|
@RequestParam("nonce") String nonce, |
||||
|
@RequestParam("openid") String openid, |
||||
|
@RequestParam(name = "encrypt_type", required = false) String encType, |
||||
|
@RequestParam(name = "msg_signature", required = false) String msgSignature) { |
||||
|
log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}]," |
||||
|
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", |
||||
|
openid, signature, encType, msgSignature, timestamp, nonce, requestBody); |
||||
|
if (!this.wxService.switchover(appid)) { |
||||
|
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid)); |
||||
|
} |
||||
|
|
||||
|
if (!wxService.checkSignature(timestamp, nonce, signature)) { |
||||
|
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); |
||||
|
} |
||||
|
String out = null; |
||||
|
if (encType == null) { |
||||
|
// 明文传输的消息
|
||||
|
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); |
||||
|
WxMpXmlOutMessage outMessage = this.route(inMessage); |
||||
|
if (outMessage == null) { |
||||
|
return ""; |
||||
|
} |
||||
|
out = outMessage.toXml(); |
||||
|
} else if ("aes".equalsIgnoreCase(encType)) { |
||||
|
// aes加密的消息
|
||||
|
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(), |
||||
|
timestamp, nonce, msgSignature); |
||||
|
log.debug("\n消息解密后内容为:\n{} ", inMessage.toString()); |
||||
|
WxMpXmlOutMessage outMessage = this.route(inMessage); |
||||
|
if (outMessage == null) { |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage()); |
||||
|
} |
||||
|
|
||||
|
log.debug("\n组装回复信息:{}", out); |
||||
|
return out; |
||||
|
} |
||||
|
|
||||
|
private WxMpXmlOutMessage route(WxMpXmlMessage message) { |
||||
|
try { |
||||
|
return this.messageRouter.route(message); |
||||
|
} catch (Exception e) { |
||||
|
log.error("路由消息时出现异常!", e); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
package com.qs.serve.controller; |
||||
|
|
||||
|
import com.qs.serve.common.framework.redis.RedisService; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUser; |
||||
|
import com.qs.serve.common.framework.security.model.LoginUserType; |
||||
|
import com.qs.serve.common.model.annotation.SysLog; |
||||
|
import com.qs.serve.common.model.consts.RedisCacheKeys; |
||||
|
import com.qs.serve.common.model.dto.R; |
||||
|
import com.qs.serve.common.model.enums.BizType; |
||||
|
import com.qs.serve.common.model.enums.HttpCode; |
||||
|
import com.qs.serve.common.model.enums.InterType; |
||||
|
import com.qs.serve.common.util.*; |
||||
|
import com.qs.serve.modules.ums.entity.UmsUser; |
||||
|
import com.qs.serve.modules.ums.service.UmsUserService; |
||||
|
import com.qs.serve.modules.wx.entity.WxUser; |
||||
|
import com.qs.serve.modules.wx.entity.dto.WxLoginUser; |
||||
|
import com.qs.serve.modules.wx.service.WxUserService; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import javax.validation.Valid; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* 门户:微信登录 |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/7 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@AllArgsConstructor |
||||
|
@RestController |
||||
|
@RequestMapping("/api/wx/login") |
||||
|
public class WxSvcLoginApi { |
||||
|
|
||||
|
private final WxUserService wxUserService; |
||||
|
|
||||
|
private final RedisService redisService; |
||||
|
|
||||
|
private final UmsUserService umsUserService; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 公众号登录 |
||||
|
* @param wxLoginUser |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
@SysLog(title = "公众号登录",biz = BizType.LOGIN,inter = InterType.API) |
||||
|
@PostMapping("/mp") |
||||
|
public R<?> login(@RequestBody @Valid WxLoginUser wxLoginUser, HttpServletRequest request){ |
||||
|
Map<String,Object> objectMap = new HashMap<>(); |
||||
|
WxUser wxUser = null; |
||||
|
try { |
||||
|
wxUser = wxUserService.login(wxLoginUser); |
||||
|
} catch (Exception e) { |
||||
|
log.warn(e.getMessage()); |
||||
|
} |
||||
|
if(wxUser==null){ |
||||
|
Assert.throwEx(HttpCode.WX_ERR); |
||||
|
} |
||||
|
String token = IdUtil.fastSimpleUUID(); |
||||
|
String key = RedisCacheKeys.LOGIN_KEY_WX + token; |
||||
|
String wxUserId = wxUser.getId(); |
||||
|
UmsUser umsUser = umsUserService.getByWxUserId(wxUserId,wxUser); |
||||
|
LoginUser loginUser = new LoginUser(umsUser.getId()+"",umsUser.getName(),"", |
||||
|
ServletUtils.getIp(request), LoginUserType.SYS_USER,new ArrayList<>(),null,AuthContextUtils.getTenant()); |
||||
|
redisService.set(key, JsonUtil.objectToJson(loginUser.loginUserDTO()),2, TimeUnit.DAYS); |
||||
|
objectMap.put("token",token); |
||||
|
return R.ok(objectMap); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 公众号测试登录 |
||||
|
*/ |
||||
|
@PostMapping("/mptest") |
||||
|
public R<?> login(HttpServletRequest request){ |
||||
|
Map<String,Object> objectMap = new HashMap<>(); |
||||
|
String token = TokenUtil.desEncrypt("1"); |
||||
|
String key = RedisCacheKeys.LOGIN_KEY_WX + token; |
||||
|
LoginUser loginUser = new LoginUser("1","微信测试用户","", |
||||
|
ServletUtils.getIp(request), LoginUserType.APP_USER,new ArrayList<>(),null,AuthContextUtils.getTenant()); |
||||
|
redisService.set(key, JsonUtil.objectToJson(loginUser.loginUserDTO()),2, TimeUnit.DAYS); |
||||
|
objectMap.put("token",token); |
||||
|
return R.ok(objectMap); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue