commit
e8d399ac19
436 changed files with 31446 additions and 0 deletions
@ -0,0 +1,9 @@ |
|||||
|
.idea/ |
||||
|
logs/ |
||||
|
target/ |
||||
|
gyoa-java.iml |
||||
|
*.http |
||||
|
*.env.json |
||||
|
*.json |
||||
|
/src/test/ |
||||
|
questionnaire.iml |
@ -0,0 +1,241 @@ |
|||||
|
<?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>company-svc</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.5.2</mybatis-plus.version> |
||||
|
<skipTests>true</skipTests> |
||||
|
<wx.java.version>4.2.0</wx.java.version> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.fasterxml.jackson.datatype</groupId> |
||||
|
<artifactId>jackson-datatype-jsr310</artifactId> |
||||
|
<version>2.13.0</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<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.4</version> |
||||
|
<exclusions> |
||||
|
<exclusion> |
||||
|
<groupId>org.mybatis</groupId> |
||||
|
<artifactId>mybatis-spring</artifactId> |
||||
|
</exclusion> |
||||
|
<exclusion> |
||||
|
<groupId>org.mybatis</groupId> |
||||
|
<artifactId>mybatis</artifactId> |
||||
|
</exclusion> |
||||
|
</exclusions> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>com.baomidou</groupId> |
||||
|
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> |
||||
|
<version>${mybatis-plus.version}</version> |
||||
|
</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>com.microsoft.sqlserver</groupId> |
||||
|
<artifactId>mssql-jdbc</artifactId> |
||||
|
<version>8.4.1.jre8</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>com.github.binarywang</groupId> |
||||
|
<artifactId>weixin-java-cp</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.aliyun.oss</groupId> |
||||
|
<artifactId>aliyun-sdk-oss</artifactId> |
||||
|
<version>3.16.1</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.cloud</groupId> |
||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId> |
||||
|
<version>3.1.5</version> |
||||
|
</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> |
||||
|
</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,69 @@ |
|||||
|
package com.qs.serve; |
||||
|
|
||||
|
import com.qs.serve.common.config.DevEnvironmentConfig; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
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.core.env.Environment; |
||||
|
import org.springframework.scheduling.annotation.EnableAsync; |
||||
|
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
|
import org.springframework.stereotype.Indexed; |
||||
|
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 |
||||
|
*/ |
||||
|
@Indexed |
||||
|
@EnableAsync |
||||
|
@EnableScheduling |
||||
|
@EnableTransactionManagement |
||||
|
@EnableCaching |
||||
|
@SpringBootApplication |
||||
|
public class Application extends SpringBootServletInitializer { |
||||
|
|
||||
|
@Value("${project.dev}") |
||||
|
String dev; |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
long start = System.currentTimeMillis(); |
||||
|
SpringApplication.run(Application.class,args); |
||||
|
long end = System.currentTimeMillis(); |
||||
|
double diff = (end-start)/1000.0; |
||||
|
System.out.println("启动时间:"+diff |
||||
|
+"\n ____ _ _ __ _ _ \n" + |
||||
|
" / ___| | |_ __ _ _ __ | |_ _ _ _ __ ___ _ _ ___ ___ ___ ___ ___ / _| _ _ | || |\n" + |
||||
|
" \\___ \\ | __|/ _` || '__|| __| | | | || '_ \\ / __|| | | | / __|/ __|/ _ \\/ __|/ __|| |_ | | | || || |\n" + |
||||
|
" ___) || |_| (_| || | | |_ | |_| || |_) | \\__ \\| |_| || (__| (__| __/\\__ \\\\__ \\| _|| |_| || ||_|\n" + |
||||
|
" |____/ \\__|\\__,_||_| \\__| \\__,_|| .__/ |___/ \\__,_| \\___|\\___|\\___||___/|___/|_| \\__,_||_|(_)\n" + |
||||
|
" |_| \n"); |
||||
|
} |
||||
|
|
||||
|
@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")); |
||||
|
DevEnvironmentConfig.openDevEnv(dev.equals("true")); |
||||
|
} |
||||
|
|
||||
|
} |
@ -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,33 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import com.qs.serve.common.util.Assert; |
||||
|
import lombok.experimental.UtilityClass; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/11 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@UtilityClass |
||||
|
public class DevEnvironmentConfig { |
||||
|
|
||||
|
private static Boolean devEnv = null; |
||||
|
public static void openDevEnv(Boolean open){ |
||||
|
log.warn("环境变量:devEnv=>>> "+open); |
||||
|
devEnv = open; |
||||
|
} |
||||
|
|
||||
|
public static Boolean isDev(){ |
||||
|
if(devEnv==null){ |
||||
|
Assert.throwEx("资源加载中..."); |
||||
|
} |
||||
|
return devEnv; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 开启账套 |
||||
|
*/ |
||||
|
public final static boolean OPEN_TENANT_BOOK = true; |
||||
|
|
||||
|
} |
@ -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 = 7; |
||||
|
|
||||
|
private final String iss = "KP_ISS"; |
||||
|
|
||||
|
private final String secret = "QiShenAa18n9VUcCxaSeSqLtFvsSCaRoVPKtBLaYxB0123456"; |
||||
|
|
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
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", |
||||
|
"sys_request_log", |
||||
|
"bir_budget_target" |
||||
|
}; |
||||
|
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,73 @@ |
|||||
|
package com.qs.serve.common.config; |
||||
|
|
||||
|
import com.qs.serve.common.config.properties.ProjectProperties; |
||||
|
import com.qs.serve.common.framework.interceptor.LimitSubmitInterceptor; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
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.ResourceHandlerRegistry; |
||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@AllArgsConstructor |
||||
|
@Configuration(proxyBeanMethods = false) |
||||
|
public class SpringMvcConfig implements WebMvcConfigurer { |
||||
|
|
||||
|
private final LimitSubmitInterceptor limitSubmitInterceptor; |
||||
|
//private final ApiAuthInterceptor apiAuthInterceptor;
|
||||
|
|
||||
|
private final ProjectProperties projectProperties; |
||||
|
|
||||
|
@Override |
||||
|
public void addInterceptors(InterceptorRegistry registry) { |
||||
|
registry.addInterceptor(limitSubmitInterceptor) |
||||
|
.addPathPatterns("/**"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) { |
||||
|
log.warn("PcWebLocal==>{}",projectProperties.getPcWebLocal()); |
||||
|
registry.addResourceHandler("/web/**") |
||||
|
.addResourceLocations("file:"+projectProperties.getPcWebLocal()); |
||||
|
registry.addResourceHandler("/static/**") |
||||
|
.addResourceLocations("file:"+projectProperties.getPcWebLocal()+"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,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 |
||||
|
* @Date: 2021/3/3 |
||||
|
* @Version: 1.0 |
||||
|
**/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "aliyun.oss") |
||||
|
public class AliYunOssProperties { |
||||
|
|
||||
|
private String bucket; |
||||
|
private String accessKeyId; |
||||
|
private String accessKeySecret; |
||||
|
private String endpoint; |
||||
|
private String prefix; |
||||
|
|
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package com.qs.serve.common.config.properties; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2024/3/27 |
||||
|
*/ |
||||
|
public class AuthUrlConst { |
||||
|
|
||||
|
public final static String[] AUTH_ALLOW_URL = new String[]{ |
||||
|
"bir/" |
||||
|
}; |
||||
|
|
||||
|
} |
@ -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,36 @@ |
|||||
|
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 2023/9/7 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "project.apis") |
||||
|
public class ProjectApisProperties { |
||||
|
|
||||
|
/** 支付接口 */ |
||||
|
private String costToPay; |
||||
|
|
||||
|
/** 同步核销的支付状态 */ |
||||
|
private String checkPayStatus; |
||||
|
|
||||
|
/** 调度系统-发货单 */ |
||||
|
private String diaoduPlanOrder; |
||||
|
|
||||
|
/** 嘉士利接口,spu转换sku */ |
||||
|
private String spuToSku; |
||||
|
|
||||
|
/** |
||||
|
* 原是生成销路通apt的中间表,替换伟成的接口直接生成 |
||||
|
*/ |
||||
|
private String policySyncCate; |
||||
|
|
||||
|
private String policySyncInv; |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
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 |
||||
|
* @Date: 2021/3/3 |
||||
|
* @Version: 1.0 |
||||
|
**/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "project") |
||||
|
public class ProjectProperties { |
||||
|
|
||||
|
private String closeAuth; |
||||
|
|
||||
|
private String birService; |
||||
|
|
||||
|
private String birServiceUrl; |
||||
|
|
||||
|
private String hostUrl; |
||||
|
|
||||
|
private String webUrl; |
||||
|
|
||||
|
private String pcWebLocal; |
||||
|
|
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
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 2024/6/18 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@Setter |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.qisheng") |
||||
|
public class QiShengDsProperties { |
||||
|
|
||||
|
private String url; |
||||
|
private String username; |
||||
|
private String password; |
||||
|
|
||||
|
} |
@ -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,28 @@ |
|||||
|
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.seeyon") |
||||
|
public class SeeYonProperties { |
||||
|
|
||||
|
private Boolean enable; |
||||
|
|
||||
|
private String url; |
||||
|
|
||||
|
private String extApi; |
||||
|
|
||||
|
} |
@ -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,4 @@ |
|||||
|
package com.qs.serve.common.framework.annotations; |
||||
|
|
||||
|
public @interface TagField { |
||||
|
} |
@ -0,0 +1,215 @@ |
|||||
|
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(); |
||||
|
//忽略GET
|
||||
|
if(request.getMethod().equals("GET")){ |
||||
|
return; |
||||
|
} |
||||
|
// 获取当前的用户
|
||||
|
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,148 @@ |
|||||
|
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.HttpMessageNotReadableException; |
||||
|
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.BeanPropertyBindingResult; |
||||
|
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 javax.servlet.http.HttpServletRequest; |
||||
|
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,HttpServletRequest request) { |
||||
|
log.warn("自定义异常触发【{},{}】,请求地址:{}",e.getCode(),e.getMessage(),request.getRequestURI()); |
||||
|
return new R(e.getCode(),e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler(value = NullPointerException.class) |
||||
|
@ResponseBody |
||||
|
public R handleBindException(NullPointerException e,HttpServletRequest request) { |
||||
|
e.printStackTrace(); |
||||
|
log.error("空指针【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
||||
|
return R.error("数据不存在或被移除"); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
AccessDeniedException.class |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handleAccessException(AccessDeniedException e,HttpServletRequest request) { |
||||
|
HttpCode hc = HttpCode.FORBIDDEN_403; |
||||
|
log.error("访问拦截【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
||||
|
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, |
||||
|
HttpRequestMethodNotSupportedException.class |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handleDevPrintMsgException(Exception e,HttpServletRequest request) { |
||||
|
log.error("参数校验异常:{}",e.getMessage()); |
||||
|
if(DevEnvironmentConfig.isDev()){ |
||||
|
return R.error(e.getMessage()); |
||||
|
} |
||||
|
return R.error(); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
MethodArgumentNotValidException.class, |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e,HttpServletRequest request) { |
||||
|
log.error("参数校验异常【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
||||
|
return R.error(e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@ExceptionHandler(value = DuplicateKeyException.class) |
||||
|
@ResponseBody |
||||
|
public R handleDuplicateKeyException(DuplicateKeyException e,HttpServletRequest request) { |
||||
|
log.error("限制重复数据【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
||||
|
e.printStackTrace(); |
||||
|
return R.error("限制重复数据,请联系管理员"); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler(value = HttpMessageNotReadableException.class) |
||||
|
@ResponseBody |
||||
|
public R handleHttpMessageNotReadableException(HttpMessageNotReadableException e,HttpServletRequest request) { |
||||
|
log.error("请求参数无法解析【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
||||
|
return R.error("请求参数无法解析"); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({ |
||||
|
SQLIntegrityConstraintViolationException.class, |
||||
|
}) |
||||
|
@ResponseBody |
||||
|
public R handleSqlIntegrityException(Exception e,HttpServletRequest request) { |
||||
|
log.warn("数据库拦截【{}】,请求地址:{}",e.getMessage(),request.getRequestURI()); |
||||
|
e.printStackTrace(); |
||||
|
return new R(500,"数据库拦截,请联系管理员"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 强制运行写入成功 |
||||
|
* @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,HttpServletRequest request) { |
||||
|
log.error("Servlet异常\n请求地址:{},异常类型:{}\n异常信息:{}\n异常体:",request.getRequestURI(),e.getClass().getSimpleName(),e.getMessage(),e); |
||||
|
e.printStackTrace(); |
||||
|
if(DevEnvironmentConfig.isDev()){return R.error(e.getMessage());} |
||||
|
return R.error(); |
||||
|
} |
||||
|
|
||||
|
} |
@ -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,31 @@ |
|||||
|
package com.qs.serve.common.framework.interceptor; |
||||
|
|
||||
|
import com.alibaba.fastjson.serializer.JSONSerializer; |
||||
|
import com.alibaba.fastjson.serializer.ObjectSerializer; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.lang.reflect.Type; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2024/7/18 |
||||
|
*/ |
||||
|
public class LocalDateTimeFormatSerializer implements ObjectSerializer { |
||||
|
|
||||
|
@Override |
||||
|
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { |
||||
|
if (object == null) { |
||||
|
serializer.out.writeNull(); |
||||
|
return; |
||||
|
} |
||||
|
LocalDateTime date = (LocalDateTime) object; |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
||||
|
String timeString = formatter.format(date); |
||||
|
serializer.write(timeString); |
||||
|
} |
||||
|
|
||||
|
} |
@ -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,35 @@ |
|||||
|
package com.qs.serve.common.framework.manager; |
||||
|
|
||||
|
|
||||
|
import com.qs.serve.common.util.SpringUtils; |
||||
|
import com.qs.serve.modules.sys.entity.SysOperationLog; |
||||
|
import com.qs.serve.modules.sys.mapper.SysOperationLogMapper; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import java.util.TimerTask; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 异步工厂 |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class AsyncFactory { |
||||
|
|
||||
|
/** |
||||
|
* 操作日志记录 |
||||
|
* @param operationLog |
||||
|
* @return |
||||
|
*/ |
||||
|
public static TimerTask saveOperationLog(final SysOperationLog operationLog) { |
||||
|
return new TimerTask() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
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,187 @@ |
|||||
|
package com.qs.serve.common.framework.mvc; |
||||
|
|
||||
|
import com.qs.serve.common.config.DevEnvironmentConfig; |
||||
|
import com.qs.serve.common.framework.redis.RedisService; |
||||
|
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.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.core.annotation.Order; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
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; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
|
||||
|
/** |
||||
|
* 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{ |
||||
|
|
||||
|
@Resource |
||||
|
RedisService redisService; |
||||
|
|
||||
|
@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 supplierId = request.getHeader("supplierId"); |
||||
|
String url = request.getRequestURL().toString(); |
||||
|
String method = request.getMethod(); |
||||
|
String queryStr = request.getQueryString(); |
||||
|
String reqBody = ""; |
||||
|
if (ServletUtils.isJsonRequest(request)&&requestWrapper!=null) { |
||||
|
reqBody = requestWrapper.getBody(); |
||||
|
} |
||||
|
StringBuffer buffer = new StringBuffer("\n["+method+"] "+url); |
||||
|
if(supplierId!=null){ |
||||
|
buffer.append(" 供应商ID: "+supplierId); |
||||
|
} |
||||
|
if(!StringUtils.isEmpty(queryStr)){ |
||||
|
buffer.append("\n参数: "+queryStr); |
||||
|
} |
||||
|
if(DevEnvironmentConfig.isDev() &&!StringUtils.isEmpty(reqBody)){ |
||||
|
buffer.append("\n请求体: "+reqBody); |
||||
|
} |
||||
|
if(diffTime>0.6D){ |
||||
|
buffer.append("\n耗时: "+diffTime+"秒"); |
||||
|
} |
||||
|
try { |
||||
|
LoginUser loginUser = AuthContextUtils.getLoginUser(false); |
||||
|
if(loginUser!=null){ |
||||
|
buffer.append("\n用户: "+loginUser.getNick()); |
||||
|
buffer.append(" IP:["+ServletUtils.getIp(request)+"]"); |
||||
|
buffer.append(" 时间:["+ LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)+"]"); |
||||
|
} |
||||
|
} catch (Exception e) {} |
||||
|
if(diffTime< 1D){ |
||||
|
log.info(buffer.toString()); |
||||
|
}else if (diffTime< 20D){ |
||||
|
log.warn(buffer.toString()); |
||||
|
}else { |
||||
|
log.error(buffer.toString()); |
||||
|
} |
||||
|
String themeKey = AuthContextUtils.getLockTheme(); |
||||
|
if(StringUtils.hasText(themeKey)){ |
||||
|
log.warn("释放资源key:{}",themeKey); |
||||
|
redisService.remove(themeKey); |
||||
|
} |
||||
|
//释放资源 防止线程池重复利用出现脏数据
|
||||
|
AuthContextUtils.removeThreadLocal(); |
||||
|
} |
||||
|
|
||||
|
@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,395 @@ |
|||||
|
package com.qs.serve.common.framework.redis; |
||||
|
|
||||
|
import com.qs.serve.common.util.Assert; |
||||
|
import com.qs.serve.common.util.AuthContextUtils; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Primary; |
||||
|
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.core.*; |
||||
|
import org.springframework.data.redis.serializer.RedisSerializationContext; |
||||
|
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 { |
||||
|
|
||||
|
@Bean |
||||
|
@Primary |
||||
|
public RedisCacheManager selfCacheManager(RedisTemplate<String, Object> redisTemplate) { |
||||
|
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory()); |
||||
|
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() |
||||
|
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer())); |
||||
|
return new TtlRedisCacheManager(redisCacheWriter, redisCacheConfiguration); |
||||
|
} |
||||
|
|
||||
|
private RedisTemplate redisTemplate; |
||||
|
|
||||
|
private StringRedisTemplate stringRedisTemplate; |
||||
|
|
||||
|
/** |
||||
|
* 加锁 |
||||
|
* @param theme |
||||
|
* @param id |
||||
|
* @return 是否在锁 |
||||
|
*/ |
||||
|
public void throwResLock(String theme,String id){ |
||||
|
String key = "LOCK_RES:"+theme+":"+id; |
||||
|
String value = this.getString(key); |
||||
|
System.out.println("throwResLock:"+value); |
||||
|
String newVal = "lock"; |
||||
|
if(newVal.equals(value)){ |
||||
|
Assert.throwEx("服务正在处理,请稍后再试"); |
||||
|
} |
||||
|
this.set(key,newVal,10,TimeUnit.MINUTES); |
||||
|
String value2 = this.getString(key); |
||||
|
if(!newVal.equals(value2)){ |
||||
|
Assert.throwEx("锁失效"); |
||||
|
} |
||||
|
AuthContextUtils.setLockTheme(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 释放锁 |
||||
|
* @param theme |
||||
|
* @param id |
||||
|
* @return 是否在锁 |
||||
|
*/ |
||||
|
public void removeResLock(String theme,String id){ |
||||
|
String key = "LOCK_RES:"+theme+":"+id; |
||||
|
this.remove(key); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 写入缓存 |
||||
|
* |
||||
|
* @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; |
||||
|
} |
||||
|
|
||||
|
public Long getLong(final String key) { |
||||
|
String result = getString(key); |
||||
|
if(result!=null){ |
||||
|
return Long.parseLong(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); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 移除业务锁 |
||||
|
* @param code |
||||
|
* @param targetId |
||||
|
*/ |
||||
|
public void removeLock(String code,String targetId){ |
||||
|
String key = "lock_commit:"+code+":"+targetId; |
||||
|
this.remove(key); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 锁 |
||||
|
* @param code |
||||
|
* @param targetId |
||||
|
* @return true--新建锁成功,false反之 |
||||
|
*/ |
||||
|
public boolean tryToLock(String code,String targetId){ |
||||
|
String key = "lock_commit:"+code+":"+targetId; |
||||
|
Integer existState = getInteger(key); |
||||
|
if(existState==null){ |
||||
|
this.set(key,1,20,TimeUnit.SECONDS); |
||||
|
return true; |
||||
|
}else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package com.qs.serve.common.framework.redis; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.data.redis.cache.RedisCache; |
||||
|
import org.springframework.data.redis.cache.RedisCacheConfiguration; |
||||
|
import org.springframework.data.redis.cache.RedisCacheManager; |
||||
|
import org.springframework.data.redis.cache.RedisCacheWriter; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import java.time.Duration; |
||||
|
|
||||
|
@Slf4j |
||||
|
public class TtlRedisCacheManager extends RedisCacheManager { |
||||
|
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { |
||||
|
super(cacheWriter, defaultCacheConfiguration); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { |
||||
|
log.debug("TtlRedisCacheManager keyName:{}",name); |
||||
|
String[] cells = StringUtils.delimitedListToStringArray(name, "="); |
||||
|
name = cells[0]; |
||||
|
if (cells.length > 1) { |
||||
|
long ttl = Long.parseLong(cells[1]); |
||||
|
// 根据传参设置缓存失效时间,默认单位是秒
|
||||
|
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); |
||||
|
} |
||||
|
return super.createRedisCache(name, cacheConfig); |
||||
|
} |
||||
|
} |
@ -0,0 +1,205 @@ |
|||||
|
package com.qs.serve.common.framework.security.filter; |
||||
|
|
||||
|
import com.qs.serve.common.config.DevEnvironmentConfig; |
||||
|
import com.qs.serve.common.config.properties.AuthUrlConst; |
||||
|
import com.qs.serve.common.config.properties.PermitProperties; |
||||
|
import com.qs.serve.common.config.properties.ProjectProperties; |
||||
|
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.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.JsonUtil; |
||||
|
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; |
||||
|
import java.util.Objects; |
||||
|
|
||||
|
/** |
||||
|
* 判断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; |
||||
|
|
||||
|
@Autowired |
||||
|
private ProjectProperties projectProperties; |
||||
|
|
||||
|
@Override |
||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { |
||||
|
|
||||
|
String supplierId = request.getHeader(GySysConst.SUPPLIER_PROP); |
||||
|
AuthContextUtils.setSupplierId(supplierId); |
||||
|
//移除前缀
|
||||
|
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(projectProperties.getCloseAuth()!=null && projectProperties.getCloseAuth().equals("true")){ |
||||
|
for (String allowUrl : AuthUrlConst.AUTH_ALLOW_URL) { |
||||
|
if(url.contains(allowUrl)){ |
||||
|
doSecurityAuthor(false,request, response, chain); |
||||
|
} |
||||
|
} |
||||
|
}else { |
||||
|
if(ignorePermit){ |
||||
|
//try to doSecurityAuthor
|
||||
|
tryDoSecurityAuthor(request, response, chain); |
||||
|
chain.doFilter(request,response); |
||||
|
}else { |
||||
|
doSecurityAuthor(true,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); |
||||
|
AuthContextUtils.setTenant(tenant); |
||||
|
if(SecurityContextHolder.getContext().getAuthentication()==null){ |
||||
|
UserDetails 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(boolean checkRedis,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); |
||||
|
if(checkRedis){ |
||||
|
String redisKey = com.qs.serve.common.util.StringUtils.format(RedisCacheKeys.LOGIN_KEY_APP,client,userId); |
||||
|
String cacheToken = redisService.getString(redisKey); |
||||
|
if(cacheToken==null){ |
||||
|
//redisService.remove(redisKey);
|
||||
|
HttpResponsePrintUtil.print2(response,401,"已被系统登出"); |
||||
|
//return解决:security.access.AccessDeniedException
|
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
if(SecurityContextHolder.getContext().getAuthentication()==null){ |
||||
|
UserDetails 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{ |
||||
|
log.error("商户信息错误,请求地址:{}",request.getRequestURI()); |
||||
|
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,18 @@ |
|||||
|
package com.qs.serve.common.model; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/7/31 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class AmountDTO { |
||||
|
|
||||
|
private String id; |
||||
|
|
||||
|
private BigDecimal amount; |
||||
|
|
||||
|
} |
@ -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,20 @@ |
|||||
|
package com.qs.serve.common.model.annotation; |
||||
|
|
||||
|
import java.lang.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/4/25 |
||||
|
*/ |
||||
|
@Target({ElementType.FIELD}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
@Documented |
||||
|
public @interface BusinessDifference { |
||||
|
|
||||
|
/** |
||||
|
* 字段备注 |
||||
|
* @return |
||||
|
*/ |
||||
|
String value() default ""; |
||||
|
|
||||
|
} |
@ -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,19 @@ |
|||||
|
package com.qs.serve.common.model.chart; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/6/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class BiCommonCounter { |
||||
|
|
||||
|
/** |
||||
|
* 横轴下标的ID |
||||
|
*/ |
||||
|
private String label; |
||||
|
|
||||
|
private Long counts; |
||||
|
|
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
package com.qs.serve.common.model.chart; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/6/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class BiMonthCounter { |
||||
|
|
||||
|
private String months; |
||||
|
private Long counts; |
||||
|
|
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
package com.qs.serve.common.model.chart; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/6/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class ChartAxisColumn { |
||||
|
|
||||
|
/** 列Id */ |
||||
|
String columnId; |
||||
|
|
||||
|
/** 列名 */ |
||||
|
String columnName; |
||||
|
|
||||
|
/** 系列坐标值合计 */ |
||||
|
Double total; |
||||
|
|
||||
|
public static List<ChartAxisColumn> buildMonthsOfYear(){ |
||||
|
List<ChartAxisColumn> axisColumnList = new ArrayList<>(); |
||||
|
for (long i = 1; i < 13; i++) { |
||||
|
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
||||
|
if(i>9){ |
||||
|
axisColumn.setColumnId(i+""); |
||||
|
}else { |
||||
|
axisColumn.setColumnId("0"+i); |
||||
|
} |
||||
|
axisColumn.setColumnName(i+"月"); |
||||
|
axisColumnList.add(axisColumn); |
||||
|
} |
||||
|
return axisColumnList; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,148 @@ |
|||||
|
package com.qs.serve.common.model.chart; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/6/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class ChartDataVo { |
||||
|
|
||||
|
/** |
||||
|
* 列(饼状图的主要参数) |
||||
|
*/ |
||||
|
List<ChartAxisColumn> axisColumnList; |
||||
|
|
||||
|
/** |
||||
|
* 系列 |
||||
|
*/ |
||||
|
List<ChartSeriesItem> seriesItemList; |
||||
|
|
||||
|
/** |
||||
|
* 分组 |
||||
|
*/ |
||||
|
List<ChartGroupItem> groupItemList; |
||||
|
|
||||
|
|
||||
|
public void initAxisColumnTotal(){ |
||||
|
for (int i = 0; i < axisColumnList.size(); i++) { |
||||
|
ChartAxisColumn axisColumn = axisColumnList.get(i); |
||||
|
BigDecimal total = BigDecimal.ZERO; |
||||
|
if(seriesItemList!=null&&seriesItemList.size()>0){ |
||||
|
for (ChartSeriesItem seriesItem : seriesItemList) { |
||||
|
double value = seriesItem.getValues().get(i); |
||||
|
total = total.add(new BigDecimal(value+"")); |
||||
|
} |
||||
|
} |
||||
|
axisColumn.setTotal(total.doubleValue()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static ChartDataVo buildStateChartData(List<BiCommonCounter> stateCounterList, Map<String,String> stateMap){ |
||||
|
ChartDataVo chartDataVo = new ChartDataVo(); |
||||
|
List<ChartAxisColumn> axisColumnList = new ArrayList<>(); |
||||
|
List<ChartSeriesItem> seriesItemList = new ArrayList<>(); |
||||
|
List<ChartGroupItem> groupItemList = new ArrayList<>(); |
||||
|
ChartGroupItem groupItem = new ChartGroupItem(); |
||||
|
groupItem.setGroupId(100L); |
||||
|
groupItem.setGroupName("默认"); |
||||
|
groupItemList.add(groupItem); |
||||
|
for (String stateNum : stateMap.keySet()) { |
||||
|
String label = stateMap.get(stateNum); |
||||
|
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
||||
|
axisColumn.setColumnId(stateNum); |
||||
|
axisColumn.setColumnName(label); |
||||
|
axisColumnList.add(axisColumn); |
||||
|
} |
||||
|
List<Double> values = new ArrayList<>(); |
||||
|
for (ChartAxisColumn chartAxisColumn : axisColumnList) { |
||||
|
Double currVal = 0.0; |
||||
|
for (BiCommonCounter counter : stateCounterList) { |
||||
|
if(chartAxisColumn.getColumnId().equals(counter.getLabel())){ |
||||
|
currVal = counter.getCounts().doubleValue(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
values.add(currVal); |
||||
|
} |
||||
|
ChartSeriesItem seriesItem = new ChartSeriesItem(); |
||||
|
seriesItem.setGroupId(groupItem.getGroupId()); |
||||
|
seriesItem.setGroupName(groupItem.getGroupName()); |
||||
|
seriesItem.setValues(values); |
||||
|
seriesItemList.add(seriesItem); |
||||
|
//更新total
|
||||
|
chartDataVo.setAxisColumnList(axisColumnList); |
||||
|
chartDataVo.setGroupItemList(groupItemList); |
||||
|
chartDataVo.setSeriesItemList(seriesItemList); |
||||
|
chartDataVo.initAxisColumnTotal(); |
||||
|
return chartDataVo; |
||||
|
} |
||||
|
|
||||
|
public void tes(){ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public void buildStateMap(Map<String,String> stateMap){ |
||||
|
init(); |
||||
|
for (String stateNum : stateMap.keySet()) { |
||||
|
String label = stateMap.get(stateNum); |
||||
|
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
||||
|
axisColumn.setColumnId(stateNum); |
||||
|
axisColumn.setColumnName(label); |
||||
|
this.axisColumnList.add(axisColumn); |
||||
|
} |
||||
|
} |
||||
|
public void buildStateMapOfMonths(){ |
||||
|
init(); |
||||
|
this.axisColumnList = ChartAxisColumn.buildMonthsOfYear(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 先调用buildStateMap |
||||
|
* @param groupId |
||||
|
* @param groupName |
||||
|
* @param stateCounterList |
||||
|
*/ |
||||
|
public void addData(Long groupId,String groupName,List<BiCommonCounter> stateCounterList){ |
||||
|
ChartGroupItem groupItem = new ChartGroupItem(); |
||||
|
groupItem.setGroupId(groupId); |
||||
|
groupItem.setGroupName(groupName); |
||||
|
groupItemList.add(groupItem); |
||||
|
List<Double> values = new ArrayList<>(); |
||||
|
for (ChartAxisColumn chartAxisColumn : axisColumnList) { |
||||
|
Double currVal = 0.0; |
||||
|
for (BiCommonCounter counter : stateCounterList) { |
||||
|
if(chartAxisColumn.getColumnId().equals(counter.getLabel())){ |
||||
|
currVal = counter.getCounts().doubleValue(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
values.add(currVal); |
||||
|
} |
||||
|
ChartSeriesItem seriesItem = new ChartSeriesItem(); |
||||
|
seriesItem.setGroupId(groupItem.getGroupId()); |
||||
|
seriesItem.setGroupName(groupItem.getGroupName()); |
||||
|
seriesItem.setValues(values); |
||||
|
seriesItemList.add(seriesItem); |
||||
|
this.initAxisColumnTotal(); |
||||
|
} |
||||
|
|
||||
|
private void init(){ |
||||
|
if(axisColumnList==null){ |
||||
|
axisColumnList = new ArrayList<>(); |
||||
|
} |
||||
|
if(seriesItemList==null){ |
||||
|
seriesItemList = new ArrayList<>(); |
||||
|
} |
||||
|
if(groupItemList==null){ |
||||
|
groupItemList = new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package com.qs.serve.common.model.chart; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/6/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class ChartGroupItem { |
||||
|
|
||||
|
/** 组id */ |
||||
|
private Long groupId; |
||||
|
|
||||
|
/** 组名 */ |
||||
|
private String groupName; |
||||
|
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package com.qs.serve.common.model.chart; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/6/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class ChartSeriesItem { |
||||
|
|
||||
|
|
||||
|
/** 组id */ |
||||
|
Long groupId; |
||||
|
|
||||
|
/** 组名 */ |
||||
|
String groupName; |
||||
|
|
||||
|
/** |
||||
|
* 值列表(列对应axisColumns) |
||||
|
*/ |
||||
|
List<Double> values; |
||||
|
|
||||
|
} |
@ -0,0 +1,75 @@ |
|||||
|
package com.qs.serve.common.model.chart; |
||||
|
|
||||
|
import com.qs.serve.common.util.JsonUtil; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Random; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/2/17 |
||||
|
*/ |
||||
|
public class PrintChart { |
||||
|
|
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
|
||||
|
//eg. 统计最近5年入学人数,并区分男女数量
|
||||
|
ChartDataVo chartDataVo = new ChartDataVo(); |
||||
|
|
||||
|
List<ChartAxisColumn> axisColumnList = new ArrayList<>(); |
||||
|
List<ChartSeriesItem> seriesItemList = new ArrayList<>(); |
||||
|
List<ChartGroupItem> groupItemList = new ArrayList<>(); |
||||
|
|
||||
|
ChartGroupItem groupItem = new ChartGroupItem(); |
||||
|
groupItem.setGroupId(100L); |
||||
|
groupItem.setGroupName("男学生"); |
||||
|
groupItemList.add(groupItem); |
||||
|
|
||||
|
ChartGroupItem groupItem2 = new ChartGroupItem(); |
||||
|
groupItem2.setGroupId(200L); |
||||
|
groupItem2.setGroupName("女学生"); |
||||
|
groupItemList.add(groupItem2); |
||||
|
|
||||
|
for (long i = 1; i <= 5; i++) { |
||||
|
ChartAxisColumn axisColumn = new ChartAxisColumn(); |
||||
|
axisColumn.setColumnId(i+""); |
||||
|
axisColumn.setColumnName("202"+i+"年"); |
||||
|
axisColumnList.add(axisColumn); |
||||
|
} |
||||
|
|
||||
|
Random random = new Random(); |
||||
|
for (ChartGroupItem chartGroupItem : groupItemList) { |
||||
|
ChartSeriesItem seriesItem = new ChartSeriesItem(); |
||||
|
seriesItem.setGroupId(chartGroupItem.getGroupId()); |
||||
|
seriesItem.setGroupName(chartGroupItem.getGroupName()); |
||||
|
List<Double> values = new ArrayList<>(); |
||||
|
for (int i = 0; i < axisColumnList.size(); i++) { |
||||
|
double result = random.nextInt(1000)+3000; |
||||
|
values.add(result); |
||||
|
} |
||||
|
seriesItem.setValues(values); |
||||
|
seriesItemList.add(seriesItem); |
||||
|
} |
||||
|
//更新total
|
||||
|
for (int i = 0; i < axisColumnList.size(); i++) { |
||||
|
ChartAxisColumn axisColumn = axisColumnList.get(i); |
||||
|
BigDecimal total = BigDecimal.ZERO; |
||||
|
for (ChartSeriesItem seriesItem : seriesItemList) { |
||||
|
double value = seriesItem.getValues().get(i); |
||||
|
total = total.add(new BigDecimal(value+"")); |
||||
|
} |
||||
|
axisColumn.setTotal(total.doubleValue()); |
||||
|
} |
||||
|
chartDataVo.setAxisColumnList(axisColumnList); |
||||
|
chartDataVo.setGroupItemList(groupItemList); |
||||
|
chartDataVo.setSeriesItemList(seriesItemList); |
||||
|
String v = JsonUtil.objectToJson(chartDataVo); |
||||
|
System.out.println(v); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/9/19 |
||||
|
*/ |
||||
|
public interface ApplyTypeConst { |
||||
|
|
||||
|
String CostBill = "CostBill"; |
||||
|
String CheckCost = "CheckCost"; |
||||
|
String ReleasePolicy = "ReleasePolicy"; |
||||
|
|
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/1/30 |
||||
|
*/ |
||||
|
public interface BudgetLogRollbackFlag { |
||||
|
|
||||
|
/** 正常(标记为最新记录) */ |
||||
|
Integer State_0 = 0; |
||||
|
|
||||
|
/** 回退 */ |
||||
|
Integer State_1 = 1; |
||||
|
|
||||
|
/** 回退已处理 */ |
||||
|
Integer State_2 = 2; |
||||
|
|
||||
|
/** 删除已处理 */ |
||||
|
Integer State_3 = 3; |
||||
|
|
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2024/3/20 |
||||
|
*/ |
||||
|
public interface DSName { |
||||
|
|
||||
|
String QiSheng = "qisheng"; |
||||
|
|
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/2/24 |
||||
|
*/ |
||||
|
public class DateConst { |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
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 SUPPLIER_PROP = "supplierId"; |
||||
|
|
||||
|
/** 系统租户数据库列 */ |
||||
|
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,33 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/3/1 |
||||
|
*/ |
||||
|
public class RedisCacheKeys { |
||||
|
|
||||
|
public final static String SUPPLIER_RELATE_TREE = "supplier_relate_tree"; |
||||
|
|
||||
|
/** 租户列表 */ |
||||
|
public final static String Tenant_ALL_LIST = "expire_tenant_list"; |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** 用户登录APP {}客户端 {}用户ID */ |
||||
|
public final static String LOGIN_KEY_APP = "login_app_{}:{}:"; |
||||
|
|
||||
|
/** 微信用户ID */ |
||||
|
public final static String WX_KEY_USER = "wx_usr_id:{}:"; |
||||
|
|
||||
|
/** 手机号验证吗 */ |
||||
|
public final static String PHONE_KEY = "phone_code_:"; |
||||
|
|
||||
|
/** |
||||
|
* 0-无需操作 |
||||
|
* 1-未处理 |
||||
|
* 2-同步中 |
||||
|
* 3-同步完成,但未更新表 |
||||
|
*/ |
||||
|
public final static String HIS_UPDATE = "update_his_flag:"; |
||||
|
|
||||
|
} |
@ -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,12 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/2/15 |
||||
|
*/ |
||||
|
public interface ResultFlag { |
||||
|
|
||||
|
int OK = 1; |
||||
|
int NOT = 0; |
||||
|
|
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
package com.qs.serve.common.model.consts; |
||||
|
|
||||
|
/** |
||||
|
* 系统配置 |
||||
|
* @author YenHex |
||||
|
* @since 2022/11/12 |
||||
|
*/ |
||||
|
public interface SysConfigKey { |
||||
|
|
||||
|
/** 费用超支 */ |
||||
|
String TbsBudgetOverspend = "TbsBudgetOverspend"; |
||||
|
|
||||
|
/** 活动预计核销日期 */ |
||||
|
String ActivityPreCheckDays = "ActivityPreCheckDays"; |
||||
|
|
||||
|
String DateCheckApplyExcelYear = "DateCheckApplyExcelYear"; |
||||
|
|
||||
|
String PolicyDelayDays = "PolicyDelayDays"; |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2024/6/11 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class CommonIdsParam { |
||||
|
|
||||
|
private List<String> ids; |
||||
|
|
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.time.LocalDate; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/6/5 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class DateSplitDTO { |
||||
|
|
||||
|
Integer days; |
||||
|
|
||||
|
LocalDate startDate; |
||||
|
|
||||
|
LocalDate endDate; |
||||
|
|
||||
|
Integer yearMonth; |
||||
|
|
||||
|
Integer sort; |
||||
|
|
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/4/25 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class DiffFieldVal { |
||||
|
|
||||
|
String field; |
||||
|
String comment; |
||||
|
String orgValue; |
||||
|
String newValue; |
||||
|
|
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import com.qs.serve.common.util.PageUtil; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/5/17 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class HeaderOption { |
||||
|
|
||||
|
private String name; |
||||
|
// private String width;
|
||||
|
// private String prefix;
|
||||
|
// private String suffix;
|
||||
|
private Boolean isSum; |
||||
|
private Integer decimalLength; |
||||
|
private String align; |
||||
|
private List<HeaderOption> children; |
||||
|
|
||||
|
public HeaderOption(String name){ |
||||
|
this.name = name; |
||||
|
} |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
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); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE,R_TYPE> PageVo<R_TYPE> initNewList(PageVo<TYPE> oldVo,List<R_TYPE> list){ |
||||
|
PageVo<R_TYPE> newVo = new PageVo<>(); |
||||
|
newVo.setPageNum(oldVo.getPageNum()); |
||||
|
newVo.setPageSize(oldVo.getPageSize()); |
||||
|
newVo.setTotal(oldVo.getTotal()); |
||||
|
newVo.setTotalPage(oldVo.getTotalPage()); |
||||
|
newVo.setList(list); |
||||
|
return newVo; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,223 @@ |
|||||
|
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 IMPORT_ERROR = 201; |
||||
|
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 errorImport(Object data) { |
||||
|
return new R<>(IMPORT_ERROR,"导入异常",data); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<TYPE> error(String message,TYPE data) { |
||||
|
return new R<>(FAILED_STATUS,FAILED_TIPS,data); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
public static R error() { |
||||
|
return new R<>(FAILED_STATUS,FAILED_TIPS,null); |
||||
|
} |
||||
|
public static R errorNotFound() { |
||||
|
return new R<>(FAILED_STATUS,NOT_FOUND_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){ |
||||
|
return R.ok(buildPageHelperList(data)); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> PageVo<TYPE> buildPageHelperList(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 pageVo; |
||||
|
} |
||||
|
|
||||
|
public static <TYPE,R_TYPE> PageVo<R_TYPE> buildPageHelperList(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 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); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<PageVo<TYPE>> byPageList(Integer pageNum,Integer pageSize,Long total,List<TYPE> data){ |
||||
|
PageVo<TYPE> pageVo = new PageVo<>(); |
||||
|
pageVo.setPageSize(pageSize); |
||||
|
pageVo.setPageNum(pageNum); |
||||
|
pageVo.setTotal(total); |
||||
|
pageVo.setList(data); |
||||
|
pageVo.setTotalPage(total%pageSize==0?total/pageSize:total/pageSize+1); |
||||
|
return R.ok(pageVo); |
||||
|
} |
||||
|
|
||||
|
public static <TYPE> R<PageVo<TYPE>> byPageList(Long total,List<TYPE> data){ |
||||
|
Integer pageNum = PageUtil.getPageNum(); |
||||
|
Integer pageSize = PageUtil.getPageSize(); |
||||
|
PageVo<TYPE> pageVo = new PageVo<>(); |
||||
|
pageVo.setPageSize(pageSize); |
||||
|
pageVo.setPageNum(pageNum); |
||||
|
pageVo.setTotal(total); |
||||
|
pageVo.setList(data); |
||||
|
pageVo.setTotalPage(total%pageSize==0?total/pageSize:total/pageSize+1); |
||||
|
return R.ok(pageVo); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import com.qs.serve.common.util.PageUtil; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/5/17 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class RowParam { |
||||
|
|
||||
|
private Integer startIndex; |
||||
|
private Integer size; |
||||
|
|
||||
|
public RowParam(Integer startIndex, Integer size) { |
||||
|
this.startIndex = startIndex; |
||||
|
this.size = size; |
||||
|
} |
||||
|
|
||||
|
public RowParam(boolean pageable) { |
||||
|
this.size = PageUtil.getPageSize(); |
||||
|
this.startIndex = (PageUtil.getPageNum()-1)*size; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2024/8/29 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class SimpleCountValue { |
||||
|
|
||||
|
String id; |
||||
|
|
||||
|
Long count; |
||||
|
|
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
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; |
||||
|
|
||||
|
public SimpleKeyValue(String label,T value){ |
||||
|
this.label = label; |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/4/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
@AllArgsConstructor |
||||
|
public class TargetDTO { |
||||
|
String targetId; |
||||
|
String targetCode; |
||||
|
String targetName; |
||||
|
|
||||
|
public TargetDTO(String targetId, String targetCode, String targetName) { |
||||
|
this.targetId = targetId; |
||||
|
this.targetCode = targetCode; |
||||
|
this.targetName = targetName; |
||||
|
} |
||||
|
|
||||
|
//拜访相关业务
|
||||
|
String localX; |
||||
|
String localY; |
||||
|
String address; |
||||
|
String mapAddress; |
||||
|
|
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
package com.qs.serve.common.model.dto; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import org.springframework.format.annotation.DateTimeFormat; |
||||
|
|
||||
|
import java.time.LocalDate; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/4/7 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class TargetObjectDTO { |
||||
|
|
||||
|
String targetType; |
||||
|
String targetId; |
||||
|
|
||||
|
String targetCode; |
||||
|
String targetName; |
||||
|
|
||||
|
} |
@ -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==null||children.size()<=0){ |
||||
|
return null; |
||||
|
} |
||||
|
return children; |
||||
|
} |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
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("查询"), |
||||
|
|
||||
|
LEAVE("离职"), |
||||
|
EXPORT("导出"), |
||||
|
SUBMIT("提交"), |
||||
|
|
||||
|
RESET("重置"); |
||||
|
|
||||
|
String value; |
||||
|
} |
@ -0,0 +1,91 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Getter; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Arrays; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/1/30 |
||||
|
*/ |
||||
|
@Getter |
||||
|
@AllArgsConstructor |
||||
|
public enum BudgetLogOptFlag { |
||||
|
|
||||
|
/** 0-预算新增 */ |
||||
|
State_0(0,true), |
||||
|
|
||||
|
/** 1-费用申请(费用申请,预算调减) */ |
||||
|
State_1(1,false), |
||||
|
|
||||
|
/** 2-预算调增 */ |
||||
|
State_2(2,true), |
||||
|
|
||||
|
/** 3-预算调减 */ |
||||
|
State_3(3,false), |
||||
|
|
||||
|
/** 4-费用释放(预算调增) */ |
||||
|
State_4(4,true), |
||||
|
|
||||
|
/** 5-费用申请调增(费用申请,预算调增) */ |
||||
|
State_5(5,true), |
||||
|
|
||||
|
/** 6-费用申请调减(费用申请,预算调减) */ |
||||
|
State_6(6,false), |
||||
|
|
||||
|
/** 已取消 7-销售区域迁移调增 */ |
||||
|
State_7(7,false), |
||||
|
|
||||
|
/** 已取消 8-销售区域迁移调减 */ |
||||
|
State_8(8,false), |
||||
|
|
||||
|
/** 已取消 9-行政区域迁移调增 */ |
||||
|
State_9(9,false), |
||||
|
|
||||
|
/** 已取消 10-行政区域迁移调减 */ |
||||
|
State_10(10,false), |
||||
|
|
||||
|
/** 11-政策申请 */ |
||||
|
State_11(11,false), |
||||
|
|
||||
|
/** 12-政策申请调增(政策申请,预算调增) */ |
||||
|
State_12(12,true), |
||||
|
|
||||
|
/** 13-政策因费用申请调增(政策申请,预算转移) */ |
||||
|
State_13(13,true), |
||||
|
|
||||
|
/** 14-政策申请释放(被拒绝后,政策释放) */ |
||||
|
State_14(14,true), |
||||
|
|
||||
|
/** 15-费用申请释放(被拒绝后,预算增加) */ |
||||
|
State_15(15,true), |
||||
|
|
||||
|
/** 16-政策释放(释放操作,预算增加) */ |
||||
|
State_16(16,true); |
||||
|
|
||||
|
/** |
||||
|
* 编码 |
||||
|
*/ |
||||
|
private Integer code; |
||||
|
|
||||
|
/** |
||||
|
* 是否取反,添加预算 |
||||
|
*/ |
||||
|
private boolean addBudget; |
||||
|
|
||||
|
private final static List<Integer> finalBudgetOptFlag = Arrays.asList(0, 2, 3); |
||||
|
|
||||
|
public final static List<Integer> finalCostOptFlag = Arrays.asList(1,4,5,6); |
||||
|
|
||||
|
public final static List<Integer> finalPolicyOptFlag = Arrays.asList(11,12,13,14,15); |
||||
|
|
||||
|
/** |
||||
|
* 预算规划,状态0,2,3,新增、调增、调减 |
||||
|
*/ |
||||
|
public static List<Integer> getFinalBudgetOptFlag(){ |
||||
|
return finalBudgetOptFlag; |
||||
|
} |
||||
|
} |
@ -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,40 @@ |
|||||
|
package com.qs.serve.common.model.enums; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2023/9/13 |
||||
|
*/ |
||||
|
public class MonthValues { |
||||
|
|
||||
|
public static final int[] Q1 = {1,2,3}; |
||||
|
public static final int[] Q2 = {4,5,6}; |
||||
|
public static final int[] Q3 = {7,8,9}; |
||||
|
public static final int[] Q4 = {10,11,12}; |
||||
|
|
||||
|
|
||||
|
|
||||
|
public static int[] getQArr(Integer val){ |
||||
|
for (int i = 0; i < Q1.length; i++) { |
||||
|
if(val==Q1[i]){ |
||||
|
return Q1; |
||||
|
} |
||||
|
} |
||||
|
for (int i = 0; i < Q2.length; i++) { |
||||
|
if(val==Q2[i]){ |
||||
|
return Q2; |
||||
|
} |
||||
|
} |
||||
|
for (int i = 0; i < Q3.length; i++) { |
||||
|
if(val==Q3[i]){ |
||||
|
return Q3; |
||||
|
} |
||||
|
} |
||||
|
for (int i = 0; i < Q4.length; i++) { |
||||
|
if(val==Q4[i]){ |
||||
|
return Q4; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -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,34 @@ |
|||||
|
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","问卷"), |
||||
|
BAZ("baz","拜访"), |
||||
|
Policy("tzc","政策"), |
||||
|
Payment("pay","支付"), |
||||
|
Budget("budget","预算"), |
||||
|
Verification("verification","核算"), |
||||
|
BIZ("biz","业务"), |
||||
|
BASE("bms","基础档案"), |
||||
|
GOODS("goods","商品"), |
||||
|
SYSTEM("sys","系统"), |
||||
|
UMS("ums","手机用户"), |
||||
|
DATA("data","数据"), |
||||
|
Excel("excel","excel数据"), |
||||
|
Tag("tag","标签"), |
||||
|
SALE("sale","销售"); |
||||
|
|
||||
|
String code; |
||||
|
|
||||
|
String vale; |
||||
|
|
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
package com.qs.serve.common.model.group; |
||||
|
|
||||
|
/** |
||||
|
* @author YenHex |
||||
|
* @since 2022/5/16 |
||||
|
*/ |
||||
|
public interface EditGroup { |
||||
|
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue