Browse Source

init

master
Yen 10 months ago
commit
e8d399ac19
  1. 9
      .gitignore
  2. 241
      pom.xml
  3. 69
      src/main/java/com/qs/serve/Application.java
  4. 24
      src/main/java/com/qs/serve/common/config/CustomServletContextInitializer.java
  5. 33
      src/main/java/com/qs/serve/common/config/DevEnvironmentConfig.java
  6. 23
      src/main/java/com/qs/serve/common/config/JwtConfig.java
  7. 56
      src/main/java/com/qs/serve/common/config/MyBatisConfig.java
  8. 70
      src/main/java/com/qs/serve/common/config/RedisConfig.java
  9. 64
      src/main/java/com/qs/serve/common/config/SecurityConfig.java
  10. 73
      src/main/java/com/qs/serve/common/config/SpringMvcConfig.java
  11. 56
      src/main/java/com/qs/serve/common/config/ThreadPoolConfig.java
  12. 25
      src/main/java/com/qs/serve/common/config/properties/AliYunOssProperties.java
  13. 13
      src/main/java/com/qs/serve/common/config/properties/AuthUrlConst.java
  14. 32
      src/main/java/com/qs/serve/common/config/properties/PermitProperties.java
  15. 36
      src/main/java/com/qs/serve/common/config/properties/ProjectApisProperties.java
  16. 31
      src/main/java/com/qs/serve/common/config/properties/ProjectProperties.java
  17. 22
      src/main/java/com/qs/serve/common/config/properties/QiShengDsProperties.java
  18. 25
      src/main/java/com/qs/serve/common/config/properties/RedisProperties.java
  19. 28
      src/main/java/com/qs/serve/common/config/properties/SeeYonProperties.java
  20. 24
      src/main/java/com/qs/serve/common/config/properties/UploadProperties.java
  21. 4
      src/main/java/com/qs/serve/common/framework/annotations/TagField.java
  22. 215
      src/main/java/com/qs/serve/common/framework/aop/SysLogAspect.java
  23. 21
      src/main/java/com/qs/serve/common/framework/exception/BaseException.java
  24. 25
      src/main/java/com/qs/serve/common/framework/exception/BusinessException.java
  25. 148
      src/main/java/com/qs/serve/common/framework/exception/UnifiedExceptionHandler.java
  26. 66
      src/main/java/com/qs/serve/common/framework/interceptor/LimitSubmitInterceptor.java
  27. 31
      src/main/java/com/qs/serve/common/framework/interceptor/LocalDateTimeFormatSerializer.java
  28. 98
      src/main/java/com/qs/serve/common/framework/interceptor/RepeatSubmitInterceptor.java
  29. 35
      src/main/java/com/qs/serve/common/framework/manager/AsyncFactory.java
  30. 52
      src/main/java/com/qs/serve/common/framework/manager/AsyncManager.java
  31. 187
      src/main/java/com/qs/serve/common/framework/mvc/HttpServletRequestFilter.java
  32. 17
      src/main/java/com/qs/serve/common/framework/mybatis/handler/IdGeneratorHandler.java
  33. 36
      src/main/java/com/qs/serve/common/framework/mybatis/handler/SysMetaHandler.java
  34. 58
      src/main/java/com/qs/serve/common/framework/mybatis/handler/SysTenantHandler.java
  35. 50
      src/main/java/com/qs/serve/common/framework/mybatis/handler/meta/JsonStringTypeHandler.java
  36. 74
      src/main/java/com/qs/serve/common/framework/mybatis/handler/meta/SplitStringTypeHandler.java
  37. 115
      src/main/java/com/qs/serve/common/framework/mybatis/join/JoinUtil.java
  38. 36
      src/main/java/com/qs/serve/common/framework/mybatis/join/annotations/BindEntity.java
  39. 14
      src/main/java/com/qs/serve/common/framework/mybatis/join/enums/JoinType.java
  40. 17
      src/main/java/com/qs/serve/common/framework/mybatis/join/model/JoinFieldData.java
  41. 159
      src/main/java/com/qs/serve/common/framework/mybatis/query/AnnotationQueryStorage.java
  42. 32
      src/main/java/com/qs/serve/common/framework/mybatis/query/annotations/QueryWrap.java
  43. 23
      src/main/java/com/qs/serve/common/framework/mybatis/query/model/QueryFieldData.java
  44. 25
      src/main/java/com/qs/serve/common/framework/mybatis/query/model/QueryFieldDataValue.java
  45. 40
      src/main/java/com/qs/serve/common/framework/mybatis/query/model/QueryType.java
  46. 395
      src/main/java/com/qs/serve/common/framework/redis/RedisService.java
  47. 30
      src/main/java/com/qs/serve/common/framework/redis/TtlRedisCacheManager.java
  48. 205
      src/main/java/com/qs/serve/common/framework/security/filter/SecurityRequestFilter.java
  49. 22
      src/main/java/com/qs/serve/common/framework/security/handler/SecurityAccessDeniedHandler.java
  50. 22
      src/main/java/com/qs/serve/common/framework/security/handler/SecurityAuthenticationFailureHandler.java
  51. 36
      src/main/java/com/qs/serve/common/framework/security/handler/SecurityLogoutHandler.java
  52. 97
      src/main/java/com/qs/serve/common/framework/security/model/LoginUser.java
  53. 37
      src/main/java/com/qs/serve/common/framework/security/model/LoginUserDTO.java
  54. 34
      src/main/java/com/qs/serve/common/framework/security/model/LoginUserType.java
  55. 31
      src/main/java/com/qs/serve/common/framework/security/service/SysUserDetailsServiceImpl.java
  56. 28
      src/main/java/com/qs/serve/common/framework/security/util/SecurityPermitUtil.java
  57. 18
      src/main/java/com/qs/serve/common/model/AmountDTO.java
  58. 34
      src/main/java/com/qs/serve/common/model/HttpResponsePrintUtil.java
  59. 20
      src/main/java/com/qs/serve/common/model/annotation/BusinessDifference.java
  60. 25
      src/main/java/com/qs/serve/common/model/annotation/LimitSubmit.java
  61. 20
      src/main/java/com/qs/serve/common/model/annotation/RepeatSubmit.java
  62. 35
      src/main/java/com/qs/serve/common/model/annotation/SysLog.java
  63. 19
      src/main/java/com/qs/serve/common/model/chart/BiCommonCounter.java
  64. 15
      src/main/java/com/qs/serve/common/model/chart/BiMonthCounter.java
  65. 39
      src/main/java/com/qs/serve/common/model/chart/ChartAxisColumn.java
  66. 148
      src/main/java/com/qs/serve/common/model/chart/ChartDataVo.java
  67. 18
      src/main/java/com/qs/serve/common/model/chart/ChartGroupItem.java
  68. 26
      src/main/java/com/qs/serve/common/model/chart/ChartSeriesItem.java
  69. 75
      src/main/java/com/qs/serve/common/model/chart/PrintChart.java
  70. 13
      src/main/java/com/qs/serve/common/model/consts/ApplyTypeConst.java
  71. 21
      src/main/java/com/qs/serve/common/model/consts/BudgetLogRollbackFlag.java
  72. 11
      src/main/java/com/qs/serve/common/model/consts/DSName.java
  73. 10
      src/main/java/com/qs/serve/common/model/consts/DateConst.java
  74. 41
      src/main/java/com/qs/serve/common/model/consts/GySysConst.java
  75. 32
      src/main/java/com/qs/serve/common/model/consts/OssConst.java
  76. 33
      src/main/java/com/qs/serve/common/model/consts/RedisCacheKeys.java
  77. 12
      src/main/java/com/qs/serve/common/model/consts/RedisListenerKeys.java
  78. 12
      src/main/java/com/qs/serve/common/model/consts/ResultFlag.java
  79. 19
      src/main/java/com/qs/serve/common/model/consts/SysConfigKey.java
  80. 16
      src/main/java/com/qs/serve/common/model/dto/CommonIdsParam.java
  81. 29
      src/main/java/com/qs/serve/common/model/dto/DateSplitDTO.java
  82. 17
      src/main/java/com/qs/serve/common/model/dto/DiffFieldVal.java
  83. 27
      src/main/java/com/qs/serve/common/model/dto/HeaderOption.java
  84. 56
      src/main/java/com/qs/serve/common/model/dto/PageVo.java
  85. 223
      src/main/java/com/qs/serve/common/model/dto/R.java
  86. 26
      src/main/java/com/qs/serve/common/model/dto/RowParam.java
  87. 16
      src/main/java/com/qs/serve/common/model/dto/SimpleCountValue.java
  88. 28
      src/main/java/com/qs/serve/common/model/dto/SimpleKeyValue.java
  89. 29
      src/main/java/com/qs/serve/common/model/dto/TargetDTO.java
  90. 23
      src/main/java/com/qs/serve/common/model/dto/TargetObjectDTO.java
  91. 30
      src/main/java/com/qs/serve/common/model/dto/TreeNode.java
  92. 53
      src/main/java/com/qs/serve/common/model/enums/BizType.java
  93. 91
      src/main/java/com/qs/serve/common/model/enums/BudgetLogOptFlag.java
  94. 19
      src/main/java/com/qs/serve/common/model/enums/ExcelFilePath.java
  95. 44
      src/main/java/com/qs/serve/common/model/enums/HttpCode.java
  96. 21
      src/main/java/com/qs/serve/common/model/enums/InterType.java
  97. 40
      src/main/java/com/qs/serve/common/model/enums/MonthValues.java
  98. 35
      src/main/java/com/qs/serve/common/model/enums/PolicyType.java
  99. 34
      src/main/java/com/qs/serve/common/model/enums/SystemModule.java
  100. 8
      src/main/java/com/qs/serve/common/model/group/EditGroup.java

9
.gitignore

@ -0,0 +1,9 @@
.idea/
logs/
target/
gyoa-java.iml
*.http
*.env.json
*.json
/src/test/
questionnaire.iml

241
pom.xml

@ -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>

69
src/main/java/com/qs/serve/Application.java

@ -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"));
}
}

24
src/main/java/com/qs/serve/common/config/CustomServletContextInitializer.java

@ -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));
}
}

33
src/main/java/com/qs/serve/common/config/DevEnvironmentConfig.java

@ -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;
}

23
src/main/java/com/qs/serve/common/config/JwtConfig.java

@ -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";
}

56
src/main/java/com/qs/serve/common/config/MyBatisConfig.java

@ -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);
}
}

70
src/main/java/com/qs/serve/common/config/RedisConfig.java

@ -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;
}
}

64
src/main/java/com/qs/serve/common/config/SecurityConfig.java

@ -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;
}
}

73
src/main/java/com/qs/serve/common/config/SpringMvcConfig.java

@ -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;
}
}

56
src/main/java/com/qs/serve/common/config/ThreadPoolConfig.java

@ -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);
}
};
}
}

25
src/main/java/com/qs/serve/common/config/properties/AliYunOssProperties.java

@ -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;
}

13
src/main/java/com/qs/serve/common/config/properties/AuthUrlConst.java

@ -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/"
};
}

32
src/main/java/com/qs/serve/common/config/properties/PermitProperties.java

@ -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<>();
}

36
src/main/java/com/qs/serve/common/config/properties/ProjectApisProperties.java

@ -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;
}

31
src/main/java/com/qs/serve/common/config/properties/ProjectProperties.java

@ -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;
}

22
src/main/java/com/qs/serve/common/config/properties/QiShengDsProperties.java

@ -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;
}

25
src/main/java/com/qs/serve/common/config/properties/RedisProperties.java

@ -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;
}

28
src/main/java/com/qs/serve/common/config/properties/SeeYonProperties.java

@ -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;
}

24
src/main/java/com/qs/serve/common/config/properties/UploadProperties.java

@ -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;
}

4
src/main/java/com/qs/serve/common/framework/annotations/TagField.java

@ -0,0 +1,4 @@
package com.qs.serve.common.framework.annotations;
public @interface TagField {
}

215
src/main/java/com/qs/serve/common/framework/aop/SysLogAspect.java

@ -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;
}
}

21
src/main/java/com/qs/serve/common/framework/exception/BaseException.java

@ -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();
}

25
src/main/java/com/qs/serve/common/framework/exception/BusinessException.java

@ -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;
}
}

148
src/main/java/com/qs/serve/common/framework/exception/UnifiedExceptionHandler.java

@ -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();
}
}

66
src/main/java/com/qs/serve/common/framework/interceptor/LimitSubmitInterceptor.java

@ -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;
}
}

31
src/main/java/com/qs/serve/common/framework/interceptor/LocalDateTimeFormatSerializer.java

@ -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);
}
}

98
src/main/java/com/qs/serve/common/framework/interceptor/RepeatSubmitInterceptor.java

@ -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;
}
}

35
src/main/java/com/qs/serve/common/framework/manager/AsyncFactory.java

@ -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);
}
};
}
}

52
src/main/java/com/qs/serve/common/framework/manager/AsyncManager.java

@ -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);
}
}

187
src/main/java/com/qs/serve/common/framework/mvc/HttpServletRequestFilter.java

@ -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();
}
};
}
}
}

17
src/main/java/com/qs/serve/common/framework/mybatis/handler/IdGeneratorHandler.java

@ -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();
}
}

36
src/main/java/com/qs/serve/common/framework/mybatis/handler/SysMetaHandler.java

@ -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);
}
}

58
src/main/java/com/qs/serve/common/framework/mybatis/handler/SysTenantHandler.java

@ -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;
}
}

50
src/main/java/com/qs/serve/common/framework/mybatis/handler/meta/JsonStringTypeHandler.java

@ -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);
}
}

74
src/main/java/com/qs/serve/common/framework/mybatis/handler/meta/SplitStringTypeHandler.java

@ -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&&parameter.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&&parameter.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;
}
}

115
src/main/java/com/qs/serve/common/framework/mybatis/join/JoinUtil.java

@ -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;
}
}

36
src/main/java/com/qs/serve/common/framework/mybatis/join/annotations/BindEntity.java

@ -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;
}

14
src/main/java/com/qs/serve/common/framework/mybatis/join/enums/JoinType.java

@ -0,0 +1,14 @@
package com.qs.serve.common.framework.mybatis.join.enums;
/**
* @author YenHex
* @since 2022/5/24
*/
public enum JoinType {
/**
* 返回类型
*/
Object,List
}

17
src/main/java/com/qs/serve/common/framework/mybatis/join/model/JoinFieldData.java

@ -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;
}

159
src/main/java/com/qs/serve/common/framework/mybatis/query/AnnotationQueryStorage.java

@ -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); }
}
}
}

32
src/main/java/com/qs/serve/common/framework/mybatis/query/annotations/QueryWrap.java

@ -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;
}

23
src/main/java/com/qs/serve/common/framework/mybatis/query/model/QueryFieldData.java

@ -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;
}

25
src/main/java/com/qs/serve/common/framework/mybatis/query/model/QueryFieldDataValue.java

@ -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;
}

40
src/main/java/com/qs/serve/common/framework/mybatis/query/model/QueryType.java

@ -0,0 +1,40 @@
package com.qs.serve.common.framework.mybatis.query.model;
/**
* @author JcYen
*/
public enum QueryType {
/**
*
*/
NONE,
/**
* 通用的equalsIntegerLongString
*/
EQ,
NE,
/**
* 比较修饰符修饰日期数值类型Integer,Long,Double,BigDecimal)
*/
LT,
LE,
GT,
GE,
/**
* 修饰List<Long>
*/
In,
NotIn,
/**
* 修饰字符串
*/
Like,
RightLike,
NotLike,
}

395
src/main/java/com/qs/serve/common/framework/redis/RedisService.java

@ -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;
}
}
}

30
src/main/java/com/qs/serve/common/framework/redis/TtlRedisCacheManager.java

@ -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);
}
}

205
src/main/java/com/qs/serve/common/framework/security/filter/SecurityRequestFilter.java

@ -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;
}
}
}

22
src/main/java/com/qs/serve/common/framework/security/handler/SecurityAccessDeniedHandler.java

@ -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,"权限不足");
}
}

22
src/main/java/com/qs/serve/common/framework/security/handler/SecurityAuthenticationFailureHandler.java

@ -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,"登录信息已过期或失效");
}
}

36
src/main/java/com/qs/serve/common/framework/security/handler/SecurityLogoutHandler.java

@ -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();
}
}
}

97
src/main/java/com/qs/serve/common/framework/security/model/LoginUser.java

@ -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");
}
}

37
src/main/java/com/qs/serve/common/framework/security/model/LoginUserDTO.java

@ -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);
}
}

34
src/main/java/com/qs/serve/common/framework/security/model/LoginUserType.java

@ -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;
}
}

31
src/main/java/com/qs/serve/common/framework/security/service/SysUserDetailsServiceImpl.java

@ -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);
}
}

28
src/main/java/com/qs/serve/common/framework/security/util/SecurityPermitUtil.java

@ -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;
}
}

18
src/main/java/com/qs/serve/common/model/AmountDTO.java

@ -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;
}

34
src/main/java/com/qs/serve/common/model/HttpResponsePrintUtil.java

@ -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();
}
}

20
src/main/java/com/qs/serve/common/model/annotation/BusinessDifference.java

@ -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 "";
}

25
src/main/java/com/qs/serve/common/model/annotation/LimitSubmit.java

@ -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 "";
}

20
src/main/java/com/qs/serve/common/model/annotation/RepeatSubmit.java

@ -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 "不允许重复提交,请稍后再试";
}

35
src/main/java/com/qs/serve/common/model/annotation/SysLog.java

@ -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;
}

19
src/main/java/com/qs/serve/common/model/chart/BiCommonCounter.java

@ -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;
}

15
src/main/java/com/qs/serve/common/model/chart/BiMonthCounter.java

@ -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;
}

39
src/main/java/com/qs/serve/common/model/chart/ChartAxisColumn.java

@ -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;
}
}

148
src/main/java/com/qs/serve/common/model/chart/ChartDataVo.java

@ -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<>();
}
}
}

18
src/main/java/com/qs/serve/common/model/chart/ChartGroupItem.java

@ -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;
}

26
src/main/java/com/qs/serve/common/model/chart/ChartSeriesItem.java

@ -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;
}

75
src/main/java/com/qs/serve/common/model/chart/PrintChart.java

@ -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);
}
}

13
src/main/java/com/qs/serve/common/model/consts/ApplyTypeConst.java

@ -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";
}

21
src/main/java/com/qs/serve/common/model/consts/BudgetLogRollbackFlag.java

@ -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;
}

11
src/main/java/com/qs/serve/common/model/consts/DSName.java

@ -0,0 +1,11 @@
package com.qs.serve.common.model.consts;
/**
* @author YenHex
* @since 2024/3/20
*/
public interface DSName {
String QiSheng = "qisheng";
}

10
src/main/java/com/qs/serve/common/model/consts/DateConst.java

@ -0,0 +1,10 @@
package com.qs.serve.common.model.consts;
/**
* @author YenHex
* @since 2022/2/24
*/
public class DateConst {
}

41
src/main/java/com/qs/serve/common/model/consts/GySysConst.java

@ -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";
}

32
src/main/java/com/qs/serve/common/model/consts/OssConst.java

@ -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 = "未知";
}

33
src/main/java/com/qs/serve/common/model/consts/RedisCacheKeys.java

@ -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:";
}

12
src/main/java/com/qs/serve/common/model/consts/RedisListenerKeys.java

@ -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";
}

12
src/main/java/com/qs/serve/common/model/consts/ResultFlag.java

@ -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;
}

19
src/main/java/com/qs/serve/common/model/consts/SysConfigKey.java

@ -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";
}

16
src/main/java/com/qs/serve/common/model/dto/CommonIdsParam.java

@ -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;
}

29
src/main/java/com/qs/serve/common/model/dto/DateSplitDTO.java

@ -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;
}

17
src/main/java/com/qs/serve/common/model/dto/DiffFieldVal.java

@ -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;
}

27
src/main/java/com/qs/serve/common/model/dto/HeaderOption.java

@ -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;
}
}

56
src/main/java/com/qs/serve/common/model/dto/PageVo.java

@ -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;
}
}

223
src/main/java/com/qs/serve/common/model/dto/R.java

@ -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);
}
}

26
src/main/java/com/qs/serve/common/model/dto/RowParam.java

@ -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;
}
}

16
src/main/java/com/qs/serve/common/model/dto/SimpleCountValue.java

@ -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;
}

28
src/main/java/com/qs/serve/common/model/dto/SimpleKeyValue.java

@ -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;
}
}

29
src/main/java/com/qs/serve/common/model/dto/TargetDTO.java

@ -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;
}

23
src/main/java/com/qs/serve/common/model/dto/TargetObjectDTO.java

@ -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;
}

30
src/main/java/com/qs/serve/common/model/dto/TreeNode.java

@ -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;
}
}

53
src/main/java/com/qs/serve/common/model/enums/BizType.java

@ -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;
}

91
src/main/java/com/qs/serve/common/model/enums/BudgetLogOptFlag.java

@ -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);
/**
* 预算规划状态023新增调增调减
*/
public static List<Integer> getFinalBudgetOptFlag(){
return finalBudgetOptFlag;
}
}

19
src/main/java/com/qs/serve/common/model/enums/ExcelFilePath.java

@ -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;
}

44
src/main/java/com/qs/serve/common/model/enums/HttpCode.java

@ -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;
}

21
src/main/java/com/qs/serve/common/model/enums/InterType.java

@ -0,0 +1,21 @@
package com.qs.serve.common.model.enums;
/**
* @author YenHex
* @since 2022/3/8
*/
public enum InterType {
/**
* 前台接口
*/
API,
/**
* 后台接口
*/
ADMIN
}

40
src/main/java/com/qs/serve/common/model/enums/MonthValues.java

@ -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;
}
}

35
src/main/java/com/qs/serve/common/model/enums/PolicyType.java

@ -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;
}

34
src/main/java/com/qs/serve/common/model/enums/SystemModule.java

@ -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;
}

8
src/main/java/com/qs/serve/common/model/group/EditGroup.java

@ -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…
Cancel
Save