Browse Source

代码初始化

tags/v1.0.0
wanghaoran 1 year ago
commit
c9ceeec1ea
100 changed files with 7110 additions and 0 deletions
  1. +33
    -0
      .gitignore
  2. +3
    -0
      README.md
  3. +108
    -0
      pom.xml
  4. +20
    -0
      tuoheng-common/pom.xml
  5. +133
    -0
      tuoheng-common/tuoheng-common-core/pom.xml
  6. +123
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/advice/CustomExceptionHandler.java
  7. +38
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/annotation/LockAction.java
  8. +36
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/annotation/Log.java
  9. +8
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseController.java
  10. +58
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseEntity.java
  11. +19
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseQuery.java
  12. +210
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseServiceImpl.java
  13. +23
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/ExceptionInterface.java
  14. +109
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/IBaseService.java
  15. +27
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/ValidatorConfig.java
  16. +85
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/common/CommonConfig.java
  17. +43
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/DefaultClientHttpRequestInterceptor.java
  18. +32
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/HeadClientHttpRequestInterceptor.java
  19. +64
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/RestProperties.java
  20. +177
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/RestTemplateConfig.java
  21. +113
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/redisson/RedissonDistributedLockAspectConfiguration.java
  22. +86
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/xxl/XxlJobConfig.java
  23. +16
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/constant/SecurityHeadConstant.java
  24. +183
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/entity/UserEntity.java
  25. +20
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/LockType.java
  26. +68
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/LogType.java
  27. +23
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/OperType.java
  28. +27
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/PhotographyEnum.java
  29. +110
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/ServiceExceptionEnum.java
  30. +97
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/SysExceptionEnum.java
  31. +23
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/exception/ExceptionInterface.java
  32. +59
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/exception/ServiceException.java
  33. +26
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/interceptor/FeignRequestInterceptor.java
  34. +21
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/model/dto/LoginUser.java
  35. +322
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/CommonUtils.java
  36. +237
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/DateUtils.java
  37. +64
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/EncryptUtil.java
  38. +163
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ExceptionUtil.java
  39. +180
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/HttpUtils.java
  40. +296
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/IpUtils.java
  41. +132
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/JacksonUtil.java
  42. +99
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/JsonResult.java
  43. +15
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/LogUtil.java
  44. +70
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/SecurityUserUtils.java
  45. +188
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ServletUtils.java
  46. +386
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/StringUtils.java
  47. +34
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ThreadLocalUtil.java
  48. +74
    -0
      tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ValidatorUtils.java
  49. +53
    -0
      tuoheng-common/tuoheng-common-security/pom.xml
  50. +25
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/annotation/EnableCustomConfig.java
  51. +21
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/annotation/EnableTHFeignClients.java
  52. +19
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/config/OAuth2FeignConfig.java
  53. +77
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/config/ResourceServerConfig.java
  54. +33
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/constant/SecurityConstant.java
  55. +27
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/entity/SecurityUser.java
  56. +26
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/interceptor/OAuth2FeignRequestInterceptor.java
  57. +62
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/CustomUserAuthenticationConverter.java
  58. +34
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/OAuthAccessDeniedHandler.java
  59. +41
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/OAuthAuthExceptionEntryPoint.java
  60. +23
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/SecurityImportBeanDefinitionRegistrar.java
  61. +99
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/utils/JsonResult.java
  62. +78
    -0
      tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/utils/SecurityUtils.java
  63. +18
    -0
      tuoheng-feign/pom.xml
  64. +4
    -0
      tuoheng-feign/tuoheng-api-feign/README.md
  65. +43
    -0
      tuoheng-feign/tuoheng-api-feign/pom.xml
  66. +15
    -0
      tuoheng-feign/tuoheng-api-feign/src/main/java/com/tuoheng/api/feign/feign/ApiClient.java
  67. +21
    -0
      tuoheng-feign/tuoheng-api-feign/src/main/java/com/tuoheng/api/feign/feign/fallback/ApiClientFallback.java
  68. +3
    -0
      tuoheng-feign/tuoheng-api-feign/src/main/resources/META-INF/spring.factories
  69. +20
    -0
      tuoheng-service/pom.xml
  70. +213
    -0
      tuoheng-service/tuoheng-admin/pom.xml
  71. +22
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/THAdminApplication.java
  72. +42
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/AdminMvcConfig.java
  73. +80
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/AliyuncsVodConfig.java
  74. +70
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/CommonConfig.java
  75. +29
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/RestTemplateConfig.java
  76. +86
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/XxlJobConfig.java
  77. +223
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/AbstractLikeSqlConverter.java
  78. +61
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/DruidConfig.java
  79. +75
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/MapLikeSqlConverter.java
  80. +33
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/MybatisPlusConfig.java
  81. +151
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/MybatisPlusInterceptor.java
  82. +26
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/ObjectLikeSqlConverter.java
  83. +26
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/constant/OidcUrlConstant.java
  84. +35
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/constant/UserConstant.java
  85. +63
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/controller/AliyunOssController.java
  86. +47
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/controller/AliyuncsVodController.java
  87. +11
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/ClientRoleDto.java
  88. +16
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/ResetPwdDto.java
  89. +21
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/UpdatePwdDto.java
  90. +46
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/UpdateUserInfoDto.java
  91. +51
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/entity/Role.java
  92. +218
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/entity/User.java
  93. +37
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/entity/UserRole.java
  94. +65
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/interceptor/UserInterceptor.java
  95. +16
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/mapper/UserMapper.java
  96. +37
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/mapper/UserRoleMapper.java
  97. +47
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/query/UserQuery.java
  98. +16
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/request/OidcCreateUserRequest.java
  99. +24
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/request/OidcUpdateUserRequest.java
  100. +0
    -0
      tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/IAliyunOssService.java

+ 33
- 0
.gitignore View File

@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

+ 3
- 0
README.md View File

@@ -0,0 +1,3 @@
# tuoheng_freeway

拓恒高速公路巡检管理平台

+ 108
- 0
pom.xml View File

@@ -0,0 +1,108 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>tuoheng-common</module>
<module>tuoheng-service</module>
<module>tuoheng-feign</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng_freeway</artifactId>
<version>1.0.0</version>
<name>tuoheng_freeway</name>
<description>tuoheng_freeway</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
<tuoheng.version>1.0.0</tuoheng.version>
<fastjson.version>1.2.76</fastjson.version>
<poi.version>3.17</poi.version>
<commons.io.version>2.5</commons.io.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<!-- 核心模块依赖 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-common-core</artifactId>
<version>${tuoheng.version}</version>
</dependency>
<!-- 安全认证依赖 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-common-security</artifactId>
<version>${tuoheng.version}</version>
</dependency>
<!-- 系统服务API接口层模块依赖 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-system-feign</artifactId>
<version>${tuoheng.version}</version>
</dependency>
<!-- freeway api fegin 接口模块依赖 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-api-feign</artifactId>
<version>${tuoheng.version}</version>
</dependency>
<!-- SpringCloud依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- JSON 解析器和生成器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- IO常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>


</project>

+ 20
- 0
tuoheng-common/pom.xml View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tuoheng_freeway</artifactId>
<groupId>com.tuoheng</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-common</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<modules>
<module>tuoheng-common-core</module>
<module>tuoheng-common-security</module>
</modules>

</project>

+ 133
- 0
tuoheng-common/tuoheng-common-core/pom.xml View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tuoheng-common</artifactId>
<groupId>com.tuoheng</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-common-core</artifactId>

<!-- 依赖库管理 -->
<dependencies>
<!-- <dependency>-->
<!-- <groupId>org.redisson</groupId>-->
<!-- <artifactId>redisson</artifactId>-->
<!-- <version>3.17.5</version>-->
<!-- </dependency>-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-log</artifactId>
<version>5.8.3</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.3</version>
</dependency>
<!--任务调度-->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version>
</dependency>
<!--引入kafka依赖-->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!--mybatis-plus 起始依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!-- 引入阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.11</version>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<!-- Apache Commons Pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!-- Excel依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
</dependency>

<!-- Java Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>

<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
</dependencies>

</project>

+ 123
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/advice/CustomExceptionHandler.java View File

@@ -0,0 +1,123 @@
package com.tuoheng.common.core.advice;

import com.tuoheng.common.core.enums.SysExceptionEnum;
import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.utils.JsonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
* 自定义异常处理器
*
* @author zhu_zishuang
* @date 2021-03-12
*/
@RestControllerAdvice
public class CustomExceptionHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(CustomExceptionHandler.class);

/**
* 密码校验异常
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public JsonResult<Object> handleAuthenticationException(BindException e) {
BindingResult bindingResult = e.getBindingResult();
String errorMessage = "";
for (FieldError fieldError : bindingResult.getFieldErrors()) {
errorMessage += fieldError.getDefaultMessage() + "!";
}
return JsonResult.error(SysExceptionEnum.PARAMETER_EMPTY_EXCEPTION.getCode(), errorMessage);
}

/**
* 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是ConstraintViolationException
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public JsonResult<Object> handleConstraintViolationException(ConstraintViolationException e) {
String message = e.getConstraintViolations()
.stream()
.map(constraintViolation -> {
return constraintViolation.getPropertyPath().toString() + ": " + constraintViolation.getMessage();
})
.collect(Collectors.joining(","));
LOGGER.error("参数格式错误:{}", message);
return JsonResult.error(SysExceptionEnum.PARAMETER_EMPTY_EXCEPTION.getCode(), SysExceptionEnum.PARAMETER_EMPTY_EXCEPTION.getMsg());
}

/**
* 校验异常处理
* 处理请求参数格式错误 @RequestBody上使用@Valid 实体上使用@NotNull等
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public JsonResult<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
LOGGER.warn("系统参数校验异常,异常信息:{}", e.getMessage());

JsonResult<Object> error = JsonResult.error(SysExceptionEnum.PARAMETER_EMPTY_EXCEPTION.getCode(),
SysExceptionEnum.PARAMETER_EMPTY_EXCEPTION.getMsg());

BindingResult result = e.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
if (!CollectionUtils.isEmpty(fieldErrors)) {
error.setMsg(fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(",")));
} else {
if (!CollectionUtils.isEmpty(result.getAllErrors())) {
ObjectError currError = result.getAllErrors().get(0);
error.setMsg(currError.getObjectName() + currError.getDefaultMessage());
}
}
return error;
}

/**
* 系统业务异常处理
*/
@ExceptionHandler(ServiceException.class)
@ResponseBody
public JsonResult<Object> handleServiceException(ServiceException e) {
// 打印业务异常日志
LOGGER.warn("系统业务逻辑异常,异常状态码 {},异常信息:{}", e.code, e.getMessage());
return JsonResult.error(e.code, e.getMessage());
}

/**
* 系统数据访问异常处理
*/
@ExceptionHandler(DataAccessException.class)
@ResponseBody
public JsonResult<Object> handleDataAccessException(DataAccessException e) {
LOGGER.error("系统数据访问异常,异常信息:{}", e);
return JsonResult.error(SysExceptionEnum.DATAACCESS_EXCEPTION.getCode(), SysExceptionEnum.DATAACCESS_EXCEPTION.getMsg());
}

/**
* 系统异常处理
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public JsonResult<Object> handleException(Exception e) {
System.out.println(e.getSuppressed());
System.out.println(e.getCause().getMessage());
System.out.println(e.getCause().getCause());
LOGGER.error("系统异常,异常信息:{}", e);
return JsonResult.error(SysExceptionEnum.SYS_EXCEPTION.getCode(), SysExceptionEnum.SYS_EXCEPTION.getMsg());
}
}

+ 38
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/annotation/LockAction.java View File

@@ -0,0 +1,38 @@
//package com.tuoheng.common.core.annotation;
//
//import com.tuoheng.common.core.enums.LockType;
//import org.springframework.core.annotation.AliasFor;
//
//import java.lang.annotation.*;
//import java.util.concurrent.TimeUnit;
//
///**
// * @author chenyukun
// */
//@Target({ElementType.METHOD})
//@Retention(RetentionPolicy.RUNTIME)
//@Inherited
//public @interface LockAction {
//
// /** 锁的资源,key。支持spring El表达式*/
// @AliasFor("key")
// String value() default "'default'";
//
// @AliasFor("value")
// String key() default "'default'";
//
// String prefix() default "lock-";
//
// /** 锁类型*/
// LockType lockType() default LockType.REENTRANT_LOCK;
//
//
// /** 获取锁等待时间,默认3秒*/
// long waitTime() default 3000L;
//
// /** 锁自动释放时间,默认30秒*/
// long leaseTime() default 30000L;
//
// /** 时间单位(获取锁等待时间和持锁时间都用此单位)*/
// TimeUnit unit() default TimeUnit.MILLISECONDS;
//}

+ 36
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/annotation/Log.java View File

@@ -0,0 +1,36 @@
package com.tuoheng.common.core.annotation;

import com.tuoheng.common.core.enums.LogType;
import com.tuoheng.common.core.enums.OperType;

import java.lang.annotation.*;

/**
* 自定义操作日志注解
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {

/**
* 模块
*/
String title() default "";

/**
* 日志类型
*/
LogType logType() default LogType.OTHER;

/**
* 操作人类别
*/
OperType operType() default OperType.MANAGE;

/**
* 是否保存请求的参数
*/
boolean isSaveRequestData() default true;

}

+ 8
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseController.java View File

@@ -0,0 +1,8 @@
package com.tuoheng.common.core.common;

/**
* 基类控制器
*/
public class BaseController {

}

+ 58
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseEntity.java View File

@@ -0,0 +1,58 @@
package com.tuoheng.common.core.common;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.util.Date;

/**
* 基类实体对象
*
* @author qiujinyang
* @date 2022/7/1
*/
@Data
public class BaseEntity implements Serializable {

private static final long serialVersionUID = 1L;

/**
* 主键ID
*/
@TableId(value = "id", type = IdType.UUID)
private String id;

/**
* 添加人
*/
private String createUser;

/**
* 创建时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;

/**
* 更新人
*/
private String updateUser;

/**
* 更新时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;

/**
* 有效标识
*/
private Integer mark;

}

+ 19
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseQuery.java View File

@@ -0,0 +1,19 @@
package com.tuoheng.common.core.common;

import lombok.Data;

/**
* 查询对象基类
*/
@Data
public class BaseQuery {
/**
* 页码(默认1)
*/
private Integer page = 1;

/**
* 每页数(默认:20)
*/
private Integer limit = 20;
}

+ 210
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/BaseServiceImpl.java View File

@@ -0,0 +1,210 @@
package com.tuoheng.common.core.common;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tuoheng.common.core.utils.DateUtils;
import com.tuoheng.common.core.utils.JsonResult;
import com.tuoheng.common.core.utils.StringUtils;

import java.io.Serializable;
import java.util.List;

public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements IBaseService<T> {

/**
* 根据查询条件获取数据列表
*
* @param page 分页
* @param query 查询条件
* @return
*/
@Override
public JsonResult getList(Page<T> page, BaseQuery query) {
return null;
}

/**
* 获取数据列表
*
* @param query 查询条件
* @return
*/
@Override
public JsonResult getList(BaseQuery query) {
return null;
}

/**
* 根据实体ID获取实体信息
*
* @param id 记录ID
* @return
*/
@Override
public JsonResult info(String id) {
if (StringUtils.isEmpty(id)) {
return JsonResult.error("记录ID不能为空");
}
Object result = this.getInfo(id);
return JsonResult.success(result, "操作成功");
}

/**
* 根据ID获取记录信息
*
* @param id 记录ID
* @return
*/
@Override
public Object getInfo(Serializable id) {
T entity = this.getById(id);
return entity;
}

/**
* 传入实体对象添加记录
*
* @param entity 实体对象
* @return
*/
@Override
public JsonResult add(T entity) {
// entity.setCreateUser(SecurityUtils.getUserId());
entity.setCreateTime(DateUtils.now());
entity.setMark(1);
boolean result = this.save(entity);
if (!result) {
return JsonResult.error();
}
return JsonResult.success();
}

/**
* 传入实体对象更新记录
*
* @param entity 实体对象
* @return
*/
@Override
public JsonResult update(T entity) {
// entity.setUpdateUser(SecurityUtils.getUserId());
entity.setUpdateTime(DateUtils.now());
boolean result = this.updateById(entity);
if (!result) {
return JsonResult.error();
}
return JsonResult.success();
}

/**
* 根据实体对象添加、编辑记录
*
* @param entity 实体对象
* @return
*/
@Override
public JsonResult edit(T entity) {
if (entity == null) {
return JsonResult.error("实体对象不存在");
}
if (entity.getId() != null && StringUtils.isNotEmpty(entity.getId())) {
// 修改记录
return this.update(entity);
} else {
// 新增记录
return this.add(entity);
}
}

/**
* 删除记录
*
* @param entity 实体对象
* @return
*/
@Override
public JsonResult delete(T entity) {
// entity.setUpdateUser(SecurityUtils.getUserId());
entity.setUpdateTime(DateUtils.now());
entity.setMark(0);
boolean result = this.updateById(entity);
if (!result) {
return JsonResult.error();
}
return JsonResult.success("删除成功");
}

/**
* 根据ID删除记录
*
* @param id 记录ID
* @return
*/
@Override
public JsonResult deleteById(String id) {
// return JsonResult.error("禁止删除,请联系管理员");
if (id == null || StringUtils.isEmpty(id)) {
return JsonResult.error("记录ID不能为空");
}
// 设置Mark=0
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.set("mark", 0);
updateWrapper.eq("id", id);
boolean result = update(updateWrapper);
if (!result) {
return JsonResult.error();
}
return JsonResult.success("删除成功");
}

/**
* 根据ID删除记录
*
* @param ids 记录ID
* @return
*/
@Override
public JsonResult deleteByIds(String[] ids) {
if (StringUtils.isNull(ids)) {
return JsonResult.error("记录ID不能为空");
}
// 设置Mark=0
Integer totalNum = 0;
for (String id : ids) {
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.set("mark", 0);
updateWrapper.eq("id", id);
boolean result = update(updateWrapper);
if (result) {
totalNum++;
}
}
if (totalNum != ids.length) {
return JsonResult.error();
}
return JsonResult.success("删除成功");
}

/**
* 设置状态
*
* @param entity 实体对象
* @return
*/
@Override
public JsonResult setStatus(T entity) {
return this.update(entity);
}

/**
* 导出Excel
*
* @return
*/
@Override
public List<T> exportExcel() {
return null;
}
}

+ 23
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/ExceptionInterface.java View File

@@ -0,0 +1,23 @@
package com.tuoheng.common.core.common;

/**
* 枚举类 封装
*
* @author zhu_zishuang
* @date 2021-03-12
*/
public interface ExceptionInterface {
/**
* 获取错误码
*
* @return
*/
int getCode();

/**
* 获取异常信息
*
* @return
*/
String getMessage();
}

+ 109
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/common/IBaseService.java View File

@@ -0,0 +1,109 @@
package com.tuoheng.common.core.common;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.tuoheng.common.core.utils.JsonResult;

import java.io.Serializable;
import java.util.List;


public interface IBaseService<T> extends IService<T> {

/**
* 根据查询条件获取数据列表
*
* @param page 分页
* @param query 查询条件
* @return
*/
JsonResult getList(Page<T> page, BaseQuery query);

/**
* 获取数据列表
*
* @param query 查询条件
* @return
*/
JsonResult getList(BaseQuery query);

/**
* 根据ID获取记录信息
*
* @param id 记录ID
* @return
*/
JsonResult info(String id);

/**
* 根据ID获取记录信息
*
* @param id 记录ID
* @return
*/
Object getInfo(Serializable id);

/**
* 根据实体对象添加记录
*
* @param entity 实体对象
* @return
*/
JsonResult add(T entity);

/**
* 根据实体对象更新记录
*
* @param entity 实体对象
* @return
*/
JsonResult update(T entity);

/**
* 根据实体对象添加、编辑记录
*
* @param entity 实体对象
* @return
*/
JsonResult edit(T entity);

/**
* 删除记录
*
* @param entity 实体对象
* @return
*/
JsonResult delete(T entity);

/**
* 根据ID删除记录
*
* @param id 记录ID
* @return
*/
JsonResult deleteById(String id);

/**
* 根据ID删除记录
*
* @param ids 记录ID
* @return
*/
JsonResult deleteByIds(String[] ids);

/**
* 设置状态
*
* @param entity 实体对象
* @return
*/
JsonResult setStatus(T entity);

/**
* 导出Excel
*
* @return
*/
List<T> exportExcel();

}

+ 27
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/ValidatorConfig.java View File

@@ -0,0 +1,27 @@
package com.tuoheng.common.core.config;

import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

/**
* 验证配置类
*/
@Configuration
public class ValidatorConfig {

@Bean
public ValidatorFactory validatorFactory() {
return Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory();
}

@Bean
public Validator validator(ValidatorFactory validatorFactory) {
return validatorFactory.getValidator();
}

}

+ 85
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/common/CommonConfig.java View File

@@ -0,0 +1,85 @@
package com.tuoheng.common.core.config.common;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
@Data
public class CommonConfig {

/**
* 图片域名
*/
public static String imageURL;

/**
* OSS域名
*/
public static String ossURL;

/**
* 视频域名
*/
public static String videoURL;

/**
* 高德KEY
*/
public static String gaodeKey;

/**
* 通道地址
*/
public static String channelUrl;

/**
* 图片域名赋值
*
* @param url 域名地址
*/
@Value("${tuoheng.image-url}")
public void setImageURL(String url) {
imageURL = url;
}

/**
* 阿里云OSS域名
*
* @param url 图片地址
*/
@Value("${tuoheng.oss-url:}")
public void setOssURL(String url) {
ossURL = url;
}

/**
* 视频域名赋值
*
* @param url 域名地址
*/
@Value("${tuoheng.video-url:}")
public void setVideoURL(String url) {
videoURL = url;
}

/**
* 高德KEY赋值
*
* @param key 高德KEY
*/
@Value("${tuoheng.gaodeKey:}")
public void setGaodeKey(String key) {
gaodeKey = key;
}

/**
* 通道域名赋值
*
* @param url 通道地址
*/
@Value("${tuoheng.live-channel-domain-url:}")
public void setChannelUrl(String url) {
channelUrl = url;
}
}

+ 43
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/DefaultClientHttpRequestInterceptor.java View File

@@ -0,0 +1,43 @@
package com.tuoheng.common.core.config.http;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
* 默认拦截器
*/
public class DefaultClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultClientHttpRequestInterceptor.class);

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
trackRequest(request,body);
ClientHttpResponse httpResponse = execution.execute(request, body);
trackResponse(httpResponse);
return httpResponse;
}

private void trackResponse(ClientHttpResponse httpResponse)throws IOException {
LOGGER.info("============================response begin==========================================");
LOGGER.info("Status code : {}", httpResponse.getStatusCode());
LOGGER.info("Status text : {}", httpResponse.getStatusText());
LOGGER.info("Headers : {}", httpResponse.getHeaders());
LOGGER.info("=======================response end=================================================");
}

private void trackRequest(HttpRequest request, byte[] body)throws UnsupportedEncodingException {
LOGGER.info("======= request begin ========");
LOGGER.info("uri : {}", request.getURI());
LOGGER.info("method : {}", request.getMethod());
LOGGER.info("headers : {}", request.getHeaders());
LOGGER.info("request body : {}", new String(body, "UTF-8"));
LOGGER.info("======= request end ========");
}
}

+ 32
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/HeadClientHttpRequestInterceptor.java View File

@@ -0,0 +1,32 @@
package com.tuoheng.common.core.config.http;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;

/**
* 默认拦截器
*/
public class HeadClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(HeadClientHttpRequestInterceptor.class);

@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
LOGGER.info("#####head handle########");
HttpHeaders headers = httpRequest.getHeaders();
headers.add("Accept", "application/json");
headers.add("Accept-Encoding", "gzip");
headers.add("Content-Encoding", "UTF-8");
headers.add("Content-Type", "application/json; charset=UTF-8");
ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
HttpHeaders headersResponse = response.getHeaders();
headersResponse.add("Accept", "application/json");
return response;
}
}

+ 64
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/RestProperties.java View File

@@ -0,0 +1,64 @@
package com.tuoheng.common.core.config.http;

import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
@Getter
@Setter
public class RestProperties {

public final static String HTTP = "http";

public final static String HTTPS = "https";

/**
* 连接超时, 默认10秒
*/
@Value("${spring.http.restTemplate.connect.timeout: 10000}")
private Integer connectTimeout;

/**
* 响应超时, 默认2分钟
*/
@Value("${spring.http.restTemplate.read.timeout: 120000}")
private Integer readTimeout;

/**
* 请求超时时间, 默认10秒
*/
@Value("${spring.http.restTemplate.connection.request.timeout: 10000}")
private Integer connectionRequestTimeout;

/**
* 请求失败重试次数, 默认重试3次
*/
@Value("${spring.http.restTemplate.retryCount: 3}")
private Integer retryCount;

/**
* 请求失败重试开关,默认开启
*/
@Value("${spring.http.restTemplate.requestSentRetryEnabled: true}")
private Boolean requestSentRetryEnabled;

/**
* 线程池最大连接数,默认1000
*/
@Value("${spring.http.restTemplate.pool.maxTotal: 1000}")
private Integer maxTotal;

/**
* 线程池主机最大并发数,默认100
*/
@Value("${spring.http.restTemplate.pool.maxPerRoute: 100}")
private Integer maxPerRoute;

/**
* 线程池空闲连接过期时间,默认60秒
*/
@Value("${spring.http.restTemplate.pool.validateAfterInactivity: 60000}")
private Integer validateAfterInactivity;
}

+ 177
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/http/RestTemplateConfig.java View File

@@ -0,0 +1,177 @@
package com.tuoheng.common.core.config.http;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class RestTemplateConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateConfig.class);

@Bean
public RestTemplate restTemplate(RestProperties restProperties) {
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory(restProperties));
// 获取restTemplate中的转换器集合
List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
// 遍历转换器集合,找到对应的StringHttpMessageConverter转换器
for (HttpMessageConverter<?> converter : converterList) {
if(converter.getClass() == StringHttpMessageConverter.class){
converterList.remove(converter);
break;
}
}
// 添加新的StringHttpMessageConverter转换器,并设置字符集为UTF-8
converterList.add(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
// 添加拦截器
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
// interceptors.add(new DefaultClientHttpRequestInterceptor());
interceptors.add(new HeadClientHttpRequestInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}

private ClientHttpRequestFactory clientHttpRequestFactory(RestProperties restProperties) {
// httpClientBuilder配置构架器
HttpClientBuilder httpClientBuilder = HttpClients.custom();
// 设置重试次数,此处注意,如果使用无参构造,重试次数为3。this(3, false);
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(restProperties.getRetryCount(), restProperties.getRequestSentRetryEnabled()));
// 设置保持长连接
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
// 使用连接池
httpClientBuilder.setConnectionManager(poolingConnectionManager(restProperties));
// 获取httpClient
CloseableHttpClient httpClient = httpClientBuilder.build();
// 配置HttpClient的对应工厂HttpComponentsClientHttpRequestFactory
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setConnectTimeout(restProperties.getConnectTimeout());
factory.setReadTimeout(restProperties.getReadTimeout());
factory.setConnectionRequestTimeout(restProperties.getConnectionRequestTimeout());
return factory;
}

private HttpClientConnectionManager poolingConnectionManager(RestProperties restProperties) {
// 注册http和https请求
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register(RestProperties.HTTP, PlainConnectionSocketFactory.getSocketFactory())
.register(RestProperties.HTTPS, createSSLConn())
.build();
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(registry);
// 最大连接数
poolingConnectionManager.setMaxTotal(restProperties.getMaxTotal());
// 每个主机的并发
poolingConnectionManager.setDefaultMaxPerRoute(restProperties.getMaxPerRoute());
// 空闲连接过期时间
poolingConnectionManager.setValidateAfterInactivity(restProperties.getValidateAfterInactivity());
return poolingConnectionManager;
}

private SSLConnectionSocketFactory createSSLConn() {
SSLConnectionSocketFactory sslsf = null;
try
{
SSLContext sslContext = new SSLContextBuilder()
// 不检查证书
.loadTrustMaterial(null, (X509Certificate[] chain, String authType) -> true)
.build();
// 不检查hostname
sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
} catch (GeneralSecurityException e){
LOGGER.error("restTemplate开启SSL校验失败", e);
}
return sslsf;
}


/**
* 自定义的重试策略,需要的时候使用
*/
private void customHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled){
// 请求失败时,进行请求重试
HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException e, int currentRetryCount, HttpContext httpContext) {
if(!requestSentRetryEnabled){
return false;
}
if (currentRetryCount > retryCount){
// 重试超过3次,放弃请求
LOGGER.error("retry has more than 3 time, give up request");
return false;
}
if (e instanceof NoHttpResponseException){
// 服务器没有响应,可能是服务器断开了连接,应该重试
LOGGER.error("receive no response from server, retry");
return true;
}
if (e instanceof SSLHandshakeException){
// SSL握手异常
LOGGER.error("SSL hand shake exception");
return false;
}
if (e instanceof InterruptedIOException){
// 超时
LOGGER.error("InterruptedIOException");
return false;
}
if (e instanceof UnknownHostException){
// 服务器不可达
LOGGER.error("server host unknown");
return false;
}
if (e instanceof ConnectTimeoutException){
// 连接超时
LOGGER.error("Connection Time out");
return false;
}
if (e instanceof SSLException){
LOGGER.error("SSLException");
return false;
}
HttpClientContext context = HttpClientContext.adapt(httpContext);
HttpRequest request = context.getRequest();
if (!(request instanceof HttpEntityEnclosingRequest)){
// 如果请求不是关闭连接的请求
return true;

}
return false;
}
};
}
}

+ 113
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/redisson/RedissonDistributedLockAspectConfiguration.java View File

@@ -0,0 +1,113 @@
//package com.tuoheng.common.core.config.redisson;
//
//import com.tuoheng.common.core.annotation.LockAction;
//import org.aspectj.lang.ProceedingJoinPoint;
//import org.aspectj.lang.annotation.Around;
//import org.aspectj.lang.annotation.Aspect;
//import org.aspectj.lang.annotation.Pointcut;
//import org.aspectj.lang.reflect.MethodSignature;
//import org.redisson.api.RLock;
//import org.redisson.api.RedissonClient;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Qualifier;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
//import org.springframework.expression.EvaluationContext;
//import org.springframework.expression.ExpressionParser;
//import org.springframework.expression.spel.standard.SpelExpressionParser;
//import org.springframework.expression.spel.support.StandardEvaluationContext;
//import org.springframework.util.StringUtils;
//
//import java.lang.reflect.Method;
//import java.util.Locale;
//
///**
// * @author chenyukun
// */
//@Aspect
//@Configuration
//@ConditionalOnProperty(name = "spring.redis.consumer.enable", havingValue = "true")
//public class RedissonDistributedLockAspectConfiguration {
//
// private final Logger logger = LoggerFactory.getLogger(RedissonDistributedLockAspectConfiguration.class);
//
// @Autowired
// @Qualifier("redissonClient")
// private RedissonClient redissonClient;
//
// private final ExpressionParser parser = new SpelExpressionParser();
//
// private final LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
//
// @Pointcut("@annotation(com.tuoheng.common.core.annotation.LockAction)")
// private void lockPoint(){
// }
//
// @Around("lockPoint()")
// public Object around(ProceedingJoinPoint pjp) throws Throwable{
// Method method = ((MethodSignature) pjp.getSignature()).getMethod();
// LockAction lockAction = method.getAnnotation(LockAction.class);
// String key = lockAction.value();
// String prefix = lockAction.prefix();
// Object[] args = pjp.getArgs();
// key = parse(key, method, args);
// if(!StringUtils.hasLength(key) || !StringUtils.hasLength(prefix)){
// logger.error("get key or prefix failed. key is null or prefix is null");
// return null;
// }
// RLock lock = getLock(String.format(Locale.ENGLISH,"%s%s", prefix, key), lockAction);
// if(!lock.tryLock(lockAction.waitTime(), lockAction.leaseTime(), lockAction.unit())) {
// logger.debug("get lock failed [{}]", key);
// return null;
// }
//
// //得到锁,执行方法,释放锁
// logger.debug("get lock success [{}]", key);
// try {
// return pjp.proceed();
// } finally {
// lock.unlock();
// logger.debug("release lock [{}]", key);
// }
// }
//
// /**
// * 解析spring EL表达式
// * @param key 表达式
// * @param method 方法
// * @param args 方法参数
// * @return string
// */
// private String parse(String key, Method method, Object[] args) {
// String[] params = discoverer.getParameterNames(method);
// if(params == null || params.length == 0){
// return null;
// }
// EvaluationContext context = new StandardEvaluationContext();
// for (int i = 0; i < params.length; i ++) {
// context.setVariable(params[i], args[i]);
// }
// return parser.parseExpression(key).getValue(context, String.class);
// }
//
// private RLock getLock(String key, LockAction lockAction) {
// switch (lockAction.lockType()) {
// case REENTRANT_LOCK:
// return redissonClient.getLock(key);
//
// case FAIR_LOCK:
// return redissonClient.getFairLock(key);
//
// case READ_LOCK:
// return redissonClient.getReadWriteLock(key).readLock();
//
// case WRITE_LOCK:
// return redissonClient.getReadWriteLock(key).writeLock();
// default:
// throw new RuntimeException("do not support lock type:" + lockAction.lockType().name());
// }
// }
//}

+ 86
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/config/xxl/XxlJobConfig.java View File

@@ -0,0 +1,86 @@
package com.tuoheng.common.core.config.xxl;

import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@Configuration
@ConditionalOnProperty(name = XxlJobConfig.XXL_ENABLE, havingValue = XxlJobConfig.TRUE)
public class XxlJobConfig {

public static final String XXL_ENABLE = "xxl.enable";

public static final String TRUE = "true";

private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

@Value("${xxl.job.admin.addresses}")
private String adminAddresses;

@Value("${xxl.job.accessToken}")
private String accessToken;

@Value("${xxl.job.executor.appname}")
private String appname;

@Value("${xxl.job.executor.address}")
private String address;

@Value("${xxl.job.executor.ip}")
private String ip;

@Value("${xxl.job.executor.port}")
private int port;

@Value("${xxl.job.executor.logpath}")
private String logPath;

@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;


@Bean
public XxlJobSpringExecutor xxlJobExecutor() throws InterruptedException {
logger.info(">>>>>>>>>>> xxl-job config init.");
Thread.sleep(5000);
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

return xxlJobSpringExecutor;
}

/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
*
* 1、引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器启动变量
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3、获取IP
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/


}

+ 16
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/constant/SecurityHeadConstant.java View File

@@ -0,0 +1,16 @@
package com.tuoheng.common.core.constant;

/**
* @Author: 吴彬
* @CreateTime: 2022-09-19 08:57
* @Description: 服务间请求头身份信息配置常量
* @Version: 1.0
*/
public class SecurityHeadConstant {

/**
* 用户信息加密串
*/
public static final String JSON_TOKEN = "json-token";

}

+ 183
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/entity/UserEntity.java View File

@@ -0,0 +1,183 @@
package com.tuoheng.common.core.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.tuoheng.common.core.common.BaseEntity;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.NotNull;
import java.util.Date;

/**
* <p>
* 后台用户管理表
* </p>
*
* @author 拓恒
* @since 2022-06-21
*/
@Data
@TableName("th_oauth_user")
public class UserEntity extends BaseEntity {


/**
* 用户编号
*/
private String code;

/**
* 真实姓名
*/
private String realname;

/**
* 昵称
*/
private String nickname;

/**
* 性别:1男 2女 3保密
*/
private Integer gender;

/**
* 头像
*/
private String avatar;

/**
* 手机号码
*/
private String mobile;

/**
* 邮箱地址
*/
private String email;

/**
* 出生日期
*/
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date birthday;

/**
* 部门ID
*/
private String deptId;

/**
* 省份编码
*/
private String provinceCode;

/**
* 城市编码
*/
private String cityCode;

/**
* 区县编码
*/
private String districtCode;
/**
* 街道编码
*/
private String streetCode;
/**
* 详细地址
*/
private String address;

/**
* 所属城市
*/
private String cityName;

/**
* 登录用户名
*/
private String username;

/**
* 登录密码
*/
private String password;

/**
* 用户类型:1管理员
*/
private Integer type;

/**
* 驾照类型:1飞行执照 2飞行许可证
*/
private Integer driverType;

/**
* 驾照编号
*/
private String driverCode;

/**
* 盐加密
*/
private String salt;

/**
* 个人简介
*/
private String intro;

/**
* 状态:1正常 2禁用
*/
private Integer status;

/**
* 备注
*/
private String note;

/**
* 显示顺序
*/
private Integer sort;

/**
* 登录次数
*/
private Integer loginNum;

/**
* 最近登录IP
*/
private String loginIp;

/**
* 最近登录时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date loginTime;

/**
* 角色ID
*/
@TableField(exist = false)
private String[] roleIds;

/**
* 城市集合
*/
@TableField(exist = false)
private String[] city;

}

+ 20
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/LockType.java View File

@@ -0,0 +1,20 @@
package com.tuoheng.common.core.enums;

/**
* @author chenyukun
*/

public enum LockType {

/** 可重入锁*/
REENTRANT_LOCK,

/** 公平锁*/
FAIR_LOCK,

/** 读锁*/
READ_LOCK,

/** 写锁*/
WRITE_LOCK;
}

+ 68
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/LogType.java View File

@@ -0,0 +1,68 @@
package com.tuoheng.common.core.enums;

/**
* 日志类型
*/
public enum LogType {

/**
* 其它
*/
OTHER,

/**
* 新增
*/
INSERT,

/**
* 修改
*/
UPDATE,

/**
* 删除
*/
DELETE,

/**
* 授权
*/
GRANT,

/**
* 导出
*/
EXPORT,

/**
* 导入
*/
IMPORT,

/**
* 强退
*/
FORCE,

/**
* 生成代码
*/
GENCODE,

/**
* 清空数据
*/
CLEAN,

/**
* 状态
*/
STATUS,

/**
* 重置密码
*/
RESETPWD,

}

+ 23
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/OperType.java View File

@@ -0,0 +1,23 @@
package com.tuoheng.common.core.enums;

/**
* 操作类型
*/
public enum OperType {

/**
* 其它
*/
OTHER,

/**
* 后台用户
*/
MANAGE,

/**
* 手机端用户
*/
MOBILE

}

+ 27
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/PhotographyEnum.java View File

@@ -0,0 +1,27 @@
package com.tuoheng.common.core.enums;

import lombok.Getter;

/**
* 摄影方式枚举类
*
* @Author xiaoying
* @Date 2022/10/11 17:37
*/
public enum PhotographyEnum {

INSPECTION(1, "普通巡检"),
ORTHOIMAGE(2, "正射影像"),
INCLINEDIMAGE(3, "倾斜摄影");

PhotographyEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}

@Getter
private final int code;

@Getter
private final String msg;
}

+ 110
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/ServiceExceptionEnum.java View File

@@ -0,0 +1,110 @@
package com.tuoheng.common.core.enums;



import com.tuoheng.common.core.exception.ExceptionInterface;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* 业务异常 枚举
*
* @author zhu_zishuang
* @date 2021-03-12
*/
@AllArgsConstructor
public enum ServiceExceptionEnum implements ExceptionInterface {

/**
* 未查询到数据
*/
GET_NO_DATA(10001, "未查到该记录!"),
/**
* 参数为空
*/
PARAMETER_IS_NULL(10002, "参数为空!"),

/**
* 获取用户ID失败
*/
GET_NO_USER_ID(10003, "获取用户ID失败!"),

/**
* websocket连接异常!
*/
WEB_SOCKET_CONNECTION_ERROR(10004, "websocket连接异常!"),

/**
* 文件不能为空!
*/
FILE_IS_EMPTY(10005, "上传文件不能为空!"),

/**
* 上传文件格式错误!
*/
FILE_FORMAT_IS_ERROR(10006, "上传文件格式错误!"),

/**
* 获取租户信息失败!
*/
GET_NO_TENANT(10007, "获取租户信息失败!"),

/**
* 上传文件数据错误,请检查文件!
*/
FILE_DATA_IS_ERROR(10101, "上传文件数据错误,请检查文件!"),

/**
* 上传文件数据错误,请检查文件!
*/
FILE_DATA_TIME_IS_ERROR(10102, "上传文件数据错误,请检查文件!"),

/**
* 上传文件数据错误,请检查文件!
*/
FILE_DATA_LNG_IS_ERROR(10103, "上传文件数据错误,请检查文件!"),

/**
* 上传文件数据错误,请检查文件!
*/
FILE_DATA_LAT_IS_ERROR(10104, "上传文件数据错误,请检查文件!"),

/**
* 读取图片经纬度失败,请手动填写!
*/
IMAGE_LOCATION_IS_ERROR(11001, "读取图片经纬度失败,请手动填写!"),

/**
* 任务不存在!
*/
TASK_DOES_NOT_EXIST(11111, "巡检任务不存在,请先创建巡检任务!"),

/**
* 视频分析中,请稍后再试
*/
VIDEO_ANALYSIS_IN_PROGRESS(11112, "视频分析中,请稍后再试!"),

/**
* 只有飞行完成状态可以操作
*/
TASK_NOT_OPERATION(11113, "只有飞行完成状态可以操作!"),

/**
* 没有这个飞行状态
*/
TASK_NOT_STATUS(11114, "飞行状态出错!"),

/**
* 巡检时间已过期
*/
INSPECTION_TIME_EXPIRE(11115, "巡检时间已过期,无法审核通过!"),
;

@Getter
private final int code;

@Getter
private final String msg;


}

+ 97
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/enums/SysExceptionEnum.java View File

@@ -0,0 +1,97 @@
package com.tuoheng.common.core.enums;

import com.tuoheng.common.core.exception.ExceptionInterface;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* 系统异常 枚举
*
* @author zhu_zishuang
* @date 2021-03-12
*/
@AllArgsConstructor
public enum SysExceptionEnum implements ExceptionInterface {
/* ===========================User====================================== */
/**
* 数据校验异常
*/
PARAMETER_EMPTY_EXCEPTION(10000, "非法参数!"),

/**
* 登录用户名不能为空
*/
ACCOUNT_IS_EMPTY(10001, "登录用户名不能为空!"),

/**
* 用户名不存在
*/
PASSWORD_IS_EMPTY(10002, "登录密码不能为空!"),

/**
* 用户信息不存在
*/
ACCOUNT_NOT_EXIST(10003, "用户信息不存在!"),

/**
* 用户名或密码错误
*/
ACCOUNT_OR_PASSWORD_ERROR(10004, "用户名或密码错误,请重新输入!"),

/**
* token为空,鉴权失败
*/
TOKEN_IS_EMPTY(10005, "token不能为空!"),

/**
* token已失效
*/
TOKEN_EXPIRED_EXCEPTION(10006,"token 已失效!"),

/**
* token 验证异常
*/
JWT_VERIFICATION_EXCEPTION(10007,"token 验证异常!"),

/**
* 无权访问
*/
PERMISSION_NOT(10008, "无访问权限"),

/**
* 系统发生异常
*/
SYS_EXCEPTION(10009, "系统发生异常!"),

/**
* 系统数据访问异常
*/
DATAACCESS_EXCEPTION(100010, "系统数据访问异常!"),

/**
* 创建线程失败异常
*/
INCREMENT_LESS_THAN_ZERO(10011, "递增因子小于0!"),

/**
* 文件导出关闭流异常
*/
EXPORT_EXCEPTION(10012, "文件导出关闭流异常!"),

/**
* 文件读取异常
*/
EXPORT_READ_EXCEPTION(10013, "文件读取异常!"),

/**
* 账号已被禁用
*/
ACCOUNT_IS_DISABLE(123,"您的账号已被禁用,请联系管理员"),
;

@Getter
private final int code;

@Getter
private final String msg;
}

+ 23
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/exception/ExceptionInterface.java View File

@@ -0,0 +1,23 @@
package com.tuoheng.common.core.exception;

/**
* 枚举类 封装
*
* @author zhu_zishuang
* @date 2021-03-12
*/
public interface ExceptionInterface {
/**
* 获取错误码
*
* @return
*/
int getCode();

/**
* 获取异常信息
*
* @return
*/
String getMsg();
}

+ 59
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/exception/ServiceException.java View File

@@ -0,0 +1,59 @@
package com.tuoheng.common.core.exception;

import com.tuoheng.common.core.utils.JsonResult;

/**
* 业务异常类(业务处理时手动抛出异常)
*
* @author zhu_zishuang
* @date 2021-03-12
*/
public class ServiceException extends RuntimeException {

/**
* 异常码
*/
public int code;

/**
* 异常描述,兼容JsonResult
*/
private String msg;


/**
* 构造器
*
* @param exceptionInfo
*/
public ServiceException(ExceptionInterface exceptionInfo) {
super(exceptionInfo.getMsg());
this.msg = exceptionInfo.getMsg();
this.code = exceptionInfo.getCode();
}

/**
* 构造器
*
* @param code
* @param msg
*/
public ServiceException(int code, String msg) {
super(msg);
this.msg = msg;
this.code = code;
}

/**
* 构造器
*
* @param msg
*/
public ServiceException(String msg) {
super(msg);
this.msg = msg;
this.code = JsonResult.ERROR;
}

}


+ 26
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/interceptor/FeignRequestInterceptor.java View File

@@ -0,0 +1,26 @@
//package com.tuoheng.common.core.interceptor;
//
//import com.tuoheng.common.core.constant.SecurityHeadConstant;
//import feign.RequestInterceptor;
//import feign.RequestTemplate;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.web.context.request.RequestContextHolder;
//import org.springframework.web.context.request.ServletRequestAttributes;
//
//import javax.servlet.http.HttpServletRequest;
//
///**
// * @Author: 吴彬
// * @CreateTime: 2022-09-19 08:57
// * @Description: gateway feign请求全局添加用户加密json-token
// * @Version: 1.0
// */
//@Configuration
//public class FeignRequestInterceptor implements RequestInterceptor {
//
// @Override
// public void apply(RequestTemplate requestTemplate) {
// HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// requestTemplate.header(SecurityHeadConstant.JSON_TOKEN, request.getHeader(SecurityHeadConstant.JSON_TOKEN));
// }
//}

+ 21
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/model/dto/LoginUser.java View File

@@ -0,0 +1,21 @@
package com.tuoheng.common.core.model.dto;

import lombok.Data;
import lombok.experimental.Accessors;

/**
* @author chenjiandong
* @description: TODO
* @date 2022/10/27 11:34
*/
@Data
@Accessors(chain = true)
public class LoginUser {

private String username;

private Long userId;

private String thToken;

}

+ 322
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/CommonUtils.java View File

@@ -0,0 +1,322 @@
package com.tuoheng.common.core.utils;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import com.tuoheng.common.core.config.common.CommonConfig;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
* 公共函数类
*/
public class CommonUtils {

private static final Pattern VOD_URL_PATTERN = Pattern.compile("^((https|http|ftp|rtsp|mms|rtmp|artc)://)"
+ "(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?"
+ "(([0-9]{1,3}\\.){3}[0-9]{1,3}"
+ "|"
+ "([0-9a-z_!~*'()-]+\\.)*"
+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\."
+ "[a-z]{2,6})"
+ "(:[0-9]{1,5})?"
+ "((/?)|"
+ "(/[0-9a-z_!~*'(){}.;?:@&=+$,%#-]+)+/?)$");

/**
* 获取到图片域名的地址
*
* @param imageUrl
* @return
*/
public static String getImageURL(String imageUrl) {
return CommonConfig.imageURL + imageUrl;
}

/**
* 正则匹配富文本图片
*
* @param htmlStr 富文本内容
* @return
*/
public static List<String> getImgStr(String htmlStr) {
Pattern p_image = Pattern.compile("<img.*src\\s*=\\s*(.*?)[^>]*?>", Pattern.CASE_INSENSITIVE);
Pattern r_image = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)");
List<String> list = new ArrayList<>();
Matcher m_image = p_image.matcher(htmlStr);
while (m_image.find()) {
// 得到<img />数据
String img = m_image.group();
System.out.println(img);
// 匹配<img>中的src数据
Matcher m = r_image.matcher(img);
while (m.find()) {
list.add(m.group(1));
}
}
return list;
}

/**
* 验证邮箱是否正确
*
* @param email
* @return
*/
public static boolean isEmail(String email) {
boolean flag = false;
try {
String check = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
Pattern regex = Pattern.compile(check);
Matcher matcher = regex.matcher(email);
flag = matcher.matches();
} catch (Exception e) {
flag = false;
}
return flag;
}

/**
* 验证手机号是否正确
*
* @param mobile
* @return
*/
public static boolean isMobile(String mobile) {
boolean flag = false;
try {
Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$");
Matcher m = p.matcher(mobile);
flag = m.matches();
} catch (Exception e) {
flag = false;
}
return flag;
}

/**
* 生成指定位数的随机字符串
*
* @param isNum 是否是纯数字
* @param length 长度
* @return
*/
public static String getRandomStr(boolean isNum, int length) {
String resultStr = "";
String str = isNum ? "1234567890" : "1234567890abcdefghijkmnpqrstuvwxyz";
int len = str.length();
boolean isStop = true;
do {
resultStr = "";
int count = 0;
for (int i = 0; i < length; i++) {
double dblR = Math.random() * len;
int intR = (int) Math.floor(dblR);
char c = str.charAt(intR);
if (('0' <= c) && (c <= '9')) {
count++;
}
resultStr += str.charAt(intR);
}
if (count >= 2) {
isStop = false;
}
} while (isStop);
return resultStr;
}

/**
* 判断是否在数组中
*
* @param s
* @param array
* @return
*/
public static boolean inArray(final String s, final String[] array) {
for (String item : array) {
if (item != null && item.equals(s)) {
return true;
}
}
return false;
}

/**
* 从html中提取纯文本
*
* @param strHtml
* @return
*/
public static String stripHtml(String strHtml) {
String content = strHtml.replaceAll("</?[^>]+>", ""); //剔出<html>的标签
content = content.replaceAll("\\s*|\t|\r|\n", "");//去除字符串中的空格,回车,换行符,制表符
return content;
}

/**
* 去除字符串中的空格、回车、换行符、制表符等
*
* @param str 原始字符串
* @return
*/
public static String replaceSpecialStr(String str) {
String repl = "";
if (str != null) {
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(str);
repl = m.replaceAll("");
}
return repl;
}

/**
* 判断某个元素是否在数组中
*
* @param key 元素
* @param map 数组
* @return
*/
public static boolean inArray(String key, Map<String, String> map) {
boolean flag = false;
for (String k : map.keySet()) {
if (k.equals(key)) {
flag = true;
}
}
return flag;
}

/**
* 对象转Map
*
* @param obj 对象
* @return
* @throws IllegalAccessException
*/
public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {
Map<String, Object> map = new HashMap<>();
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(obj);
map.put(fieldName, value);
}
return map;
}

/**
* 判断是否是JSON格式
*
* @param str JSON字符串
* @return
*/
private boolean isJson(String str) {
try {
JSONObject jsonStr = JSONObject.parseObject(str);
return true;
} catch (Exception e) {
return false;
}
}

/**
* MD5方法
*
* @param source
* @return
*/
public static String md5(byte[] source) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(source);
StringBuffer buf = new StringBuffer();
for (byte b : md.digest()) {
buf.append(String.format("%02x", b & 0xff));
}
return buf.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 密码加密
*
* @param password 密码
* @return
*/
public static String password(String password) {
String md51 = md5(password.getBytes());
String pwd = md5((md51 + "IgtUdEQJyVevaCxQnY").getBytes());
return pwd;
}

/**
* 对数组进行分组
*
* @param list 数据源
* @param size 每组几个
* @param <T>
* @return
*/
public static <T> List<List<T>> split(List<T> list, Integer size) {
if (CollectionUtils.isEmpty(list)) {
return new ArrayList<>();
}
Integer count = list.size() / size;
List<List<T>> arrayList = new ArrayList<>();
for (int i = 0; i < count; i++) {
List<T> temp = list.subList(i * size, (i + 1) * size);
arrayList.add(temp);
}
Integer extra = list.size() % size;
if (extra != 0) {
List<T> temp = list.subList(count * size, count * size + extra);
arrayList.add(temp);
}
return arrayList;
}

/**
* 批量处理方法
*
* @param operater 回调方法,有入参无返回值
* @param sourceList 批量处理list对象
* @param threshold 阀值,比如有5000个对象,阀值设置1000,就是1000执行一次
* @param <T> 对象类型
*/
public static <T> void batchOperate(Consumer<List<T>> operater, List<T> sourceList, Integer threshold) {
int size = sourceList.size();
int fromIndex = 0;
List<T> list = null;
while (size > fromIndex){
list = sourceList.stream().skip(fromIndex).limit(threshold).collect(Collectors.toList());
operater.accept(list);
fromIndex += threshold;
}
}

/**
* 验证URL是否合法
*
* @param str 字符串url
* @return 布尔值
*/
public static boolean isURL(String str){
str = str.toLowerCase();
Matcher matcher = VOD_URL_PATTERN.matcher(str);
return matcher.find();
}

}

+ 237
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/DateUtils.java View File

@@ -0,0 +1,237 @@
package com.tuoheng.common.core.utils;

import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
* 时间工具类
*/
public final class DateUtils extends org.apache.commons.lang3.time.DateUtils {

public static String YYYY = "yyyy";

public static String YYYY_MM = "yyyy-MM";

public static String YYYY_MM_DD = "yyyy-MM-dd";

public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

private static String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};


/**
* 获取当前时间
*
* @return
*/
public static Date now() {
return new Date();
}

/**
* 获取当前日期, 默认格式为yyyy-MM-dd
*
* @return String
*/
public static String getDate() {
return dateTimeNow(YYYY_MM_DD);
}

public static final String getTime() {
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}

public static final String dateTimeNow() {
return dateTimeNow(YYYYMMDDHHMMSS);
}

public static final String dateTimeNow(final String format) {
return parseDateToStr(format, new Date());
}

public static final String dateTime(final Date date) {
return parseDateToStr(YYYY_MM_DD, date);
}

public static final String parseDateToStr(final String format, final Date date) {
return new SimpleDateFormat(format).format(date);
}

public static final Date dateTime(final String format, final String ts) {
try {
return new SimpleDateFormat(format).parse(ts);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}

/**
* 检查字符串是否使时间格式
* @param format 格式
* @param ts 时间字符串
* @return 布尔值
*/
public static boolean checkStrIsDate(final String format, final String ts) {
try {
new SimpleDateFormat(format).parse(ts);
return true;
} catch (ParseException e) {
return false;
}
}

/**
* 日期路径 即年/月/日 如2018/08/08
*/
public static final String datePath() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}

/**
* 日期路径 即年/月/日 如20180808
*/
public static final String dateTime() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}

/**
* 日期型字符串转化为日期 格式
*/
public static Date parseDate(Object str) {
if (str == null) {
return null;
}
try {
return parseDate(str.toString(), parsePatterns);
} catch (ParseException e) {
return null;
}
}

/**
* 获取服务器启动时间
*/
public static Date getServerStartDate() {
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}

/**
* 计算两个时间差
*/
public static String getDatePoor(Date endDate, Date nowDate) {
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
// long sec = diff % nd % nh % nm / ns;
return day + "天" + hour + "小时" + min + "分钟";
}

/**
* 根据时间生成code
*/
public static String generateCode(String prefix){
// 根据当前时间,生成任务编码
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
return prefix + formatter.format(date);
}

/**
* 生成图片编号,P+年月日时分秒+随机三位数
* @return
*/
public static String generateFileCode(){
String Date = DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS);
int randomNum = (int)(Math.random() * 900) + 100;
String fileCode = "P" + Date + randomNum;

return fileCode;
}

/**
* 返回字符串
*
* 给原本的时间originDate加上自定义的时间
* @param originDate 原本的时间
* @param day 要加的天数
* @param hour 要加的小时数
* @param minute 要加的分钟数
* @param second 要加的秒数
* @return 返回加完时间后的时间str_goalDate
*/
public static String addDateTimeToStr(Date originDate, int day, int hour, int minute,int second) {
SimpleDateFormat dateFormate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Calendar cal = Calendar.getInstance();
cal.setTime(originDate);
cal.add(Calendar.DATE, day);// 24小时制,加天
cal.add(Calendar.HOUR, hour);// 24小时制 ,加小时
cal.add(Calendar.MINUTE, minute);// 24小时制,加分钟
cal.add(Calendar.SECOND, second);// 24小时制,加秒

String str_goalDate = dateFormate.format(cal.getTime());
return str_goalDate;
}

/**
* 返回java.util.Date
*
* 给原本的时间originDate加上自定义的时间
* @param originDate 原本的时间
* @param day 要加的天数
* @param hour 要加的小时数
* @param minute 要加的分钟数
* @param second 要加的秒数
* @return 返回加完时间后的时间goalDate
*/
public static Date addDateTimeToDate(Date originDate, int day, int hour, int minute,int second) {
Calendar cal = Calendar.getInstance();
cal.setTime(originDate);
cal.add(Calendar.DATE, day);// 24小时制,加天
cal.add(Calendar.HOUR, hour);// 24小时制 ,加小时
cal.add(Calendar.MINUTE, minute);// 24小时制,加分钟
cal.add(Calendar.SECOND, second);// 24小时制,加秒

Date goalDate = cal.getTime();
return goalDate;
}

public static void main(String[] args) {
// 当前时间
Date date = new Date(System.currentTimeMillis());
System.out.println("当前时间 = " + date);

// 想加2小时5分10秒,且返回字符串
String strDate = addDateTimeToStr(date, 0, 2, 5, 10);
System.out.println("转换后的时间 = " + strDate);

System.out.println("-------------");
System.out.println("当前时间=" + date);
// 想加3小时2分5秒,且返回Date
Date goalDate = addDateTimeToDate(date, 0, 3, 2, 5);
System.out.println("转换后的时间 = " + goalDate);
}

}

+ 64
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/EncryptUtil.java View File

@@ -0,0 +1,64 @@
package com.tuoheng.common.core.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
* 加密工具类
* @Author: rosh
*/
public final class EncryptUtil {

private EncryptUtil() {

}

private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class);

public static String encodeBase64(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}

public static byte[] decodeBase64(String str) {

return Base64.getDecoder().decode(str);
}

public static String encodeUTF8StringBase64(String str) {
return Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));
}

public static String decodeUTF8StringBase64(String str) {
byte[] bytes = Base64.getDecoder().decode(str);
return new String(bytes, StandardCharsets.UTF_8);
}

public static String encodeURL(String url) {
String encoded = null;
try {
encoded = URLEncoder.encode(url, String.valueOf(StandardCharsets.UTF_8));
} catch (UnsupportedEncodingException e) {
logger.warn("URLEncode失败", e);
}
return encoded;
}


public static String decodeURL(String url) {
String decoded = null;
try {
decoded = URLDecoder.decode(url, String.valueOf(StandardCharsets.UTF_8));
} catch (UnsupportedEncodingException e) {
logger.warn("URLDecode失败", e);
}
return decoded;
}

}

+ 163
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ExceptionUtil.java View File

@@ -0,0 +1,163 @@
package com.tuoheng.common.core.utils;

import cn.hutool.core.util.ObjectUtil;
import com.tuoheng.common.core.exception.ExceptionInterface;
import com.tuoheng.common.core.exception.ServiceException;

import java.util.Optional;

/**
* 异常工具
* @author chenyukun
*/
public class ExceptionUtil {

private ExceptionUtil(){}

/**
* 抛服务异常
*
* @param code 异常编码
* @param exceptionMsg 异常信息
*/
public static void throwServiceExcetion(Integer code, String exceptionMsg){
throw new ServiceException(code, exceptionMsg);
}

/**
* 抛服务异常
*
* @param code 异常编码
* @param exceptionMsg 异常信息
* @param logMsg 日志消息
* @param logObj 日志消息占位对象
*/
public static void throwServiceExcetion(Integer code, String exceptionMsg, String logMsg, String ...logObj){
if(StringUtils.isNotEmpty(logObj)){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, logObj));
}
if(StringUtils.isEmpty(logObj)){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x));
}
throw new ServiceException(code, exceptionMsg);
}

/**
* 抛服务异常
*
* @param code 异常编码
* @param exceptionMsg 异常信息
* @param exception 异常
* @param logMsg 日志消息
* @param logObj 日志消息占位对象
*/
public static void throwServiceExcetion(Integer code, String exceptionMsg, Exception exception, String logMsg,
String ...logObj){
if(StringUtils.isNotEmpty(logObj) && exception != null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, logObj, exception));
}
if(StringUtils.isNotEmpty(logObj) && exception == null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, logObj));
}
if(StringUtils.isEmpty(logObj) && exception != null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, exception));
}
if(StringUtils.isEmpty(logObj) && exception == null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x));
}
throw new ServiceException(code, exceptionMsg);
}

/**
* 抛服务异常
*
* @param exceptionInterface 异常接口
*/
public static void throwServiceExcetion(ExceptionInterface exceptionInterface){
throw new ServiceException(exceptionInterface);
}

/**
* 抛服务异常
*
* @param exceptionInterface 异常接口
* @param logMsg 日志消息
* @param logObj 日志对象
*/
public static void throwServiceExcetion(ExceptionInterface exceptionInterface, String logMsg, String ...logObj){
if(StringUtils.isNotEmpty(logObj)){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, logObj));
}
if(StringUtils.isEmpty(logObj)){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x));
}
throw new ServiceException(exceptionInterface);
}

/**
* 抛服务异常
*
* @param exceptionInterface 异常接口
* @param exception 异常
* @param logMsg 日志消息
* @param logObj 日志对象
*/
public static void throwServiceExcetion(ExceptionInterface exceptionInterface, Exception exception, String logMsg,
String ...logObj){
if(StringUtils.isNotEmpty(logObj) && exception != null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, logObj, exception));
}
if(StringUtils.isNotEmpty(logObj) && exception == null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, logObj));
}
if(StringUtils.isEmpty(logObj) && exception != null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x, exception));
}
if(StringUtils.isEmpty(logObj) && exception == null){
Optional.ofNullable(logMsg).ifPresent(x -> LogUtil.LOGGER.error(x));
}
throw new ServiceException(exceptionInterface);
}

/**
* 校验参数是否为空,为空抛异常
*
* @param obj 参数对象
* @param exceptionInterface 异常接口
*/
public static void paramIsNull(Object obj, ExceptionInterface exceptionInterface){
if(ObjectUtil.isEmpty(obj)){
throwServiceExcetion(exceptionInterface);
}
}

/**
* 校验参数是否为空,为空抛异常
*
* @param obj 参数对象
* @param exceptionInterface 异常接口
* @param logMsg 日志消息
* @param logObj 日志对象
*/
public static void paramIsNull(Object obj, ExceptionInterface exceptionInterface, String logMsg, String ...logObj){
if(ObjectUtil.isEmpty(obj)){
throwServiceExcetion(exceptionInterface, logMsg, logObj);
}
}

/**
* 校验参数是否为空,为空抛异常
*
* @param obj 参数对象
* @param exceptionInterface 异常接口
* @param exception 异常
* @param logMsg 日志消息
* @param logObj 日志对象
*/
public static void paramIsNull(Object obj, ExceptionInterface exceptionInterface, Exception exception,
String logMsg, String ...logObj){
if(ObjectUtil.isEmpty(obj)){
throwServiceExcetion(exceptionInterface, exception, logMsg, logObj);
}
}
}

+ 180
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/HttpUtils.java View File

@@ -0,0 +1,180 @@
package com.tuoheng.common.core.utils;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Map;

/**
* 通用http发送方法
*/
public class HttpUtils {

private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
log.info("sendGet - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("recv - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}

/**
* 处理post请求
* @param urlStr 请求url
* @param data 请求体数据
* @param properties 请求头参数
* @return
*/
public static String doSend(String urlStr, JSONObject data, Map<String, String> properties, String method){
try {
log.info("请求url={}", urlStr);
log.info("请求体数据data={}", data.toJSONString());
log.info("请求头参数properties={}", properties);
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

connection.setDoInput(true); // 设置可输入
connection.setDoOutput(true); // 设置该连接是可以输出的
//设置连接超时时间和读取超时时间
connection.setConnectTimeout(15000);
connection.setReadTimeout(60000);
//设置请求方式
connection.setRequestMethod(method);
connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
if(null != properties && !properties.isEmpty()){
for (String key:properties.keySet()){
connection.setRequestProperty(key, properties.get(key));
}
}

PrintWriter pw = new PrintWriter(new BufferedOutputStream(connection.getOutputStream()));
pw.write(data.toJSONString());
pw.flush();
pw.close();

BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
String line = null;
StringBuilder result = new StringBuilder();
while ((line = br.readLine()) != null) { // 读取数据
result.append(line).append("\n");
}
connection.disconnect();
log.info(result.toString());
return result.toString();
} catch (Exception e) {
log.error("post请求失败,{}",e.getMessage());
return "post请求失败!";
}
}

public static String sendSSLPost(String url, String param) {
StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param;
try {
log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
URL console = new URL(urlNameString);
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);

conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String ret = "";
while ((ret = br.readLine()) != null) {
if (ret != null && !ret.trim().equals("")) {
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
}
}
log.info("recv - {}", result);
conn.disconnect();
br.close();
} catch (ConnectException e) {
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
}
return result.toString();
}

private static class TrustAnyTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}

private static class TrustAnyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}

}

+ 296
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/IpUtils.java View File

@@ -0,0 +1,296 @@
package com.tuoheng.common.core.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
* 获取IP方法
*
* @author ruoyi
*/
@Slf4j
public class IpUtils
{
/**
* 获取客户端IP
*
* @param request 请求对象
* @return IP地址
*/
public static String getIpAddr(HttpServletRequest request)
{
if (request == null)
{
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Real-IP");
}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getRemoteAddr();
}

return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
}

/**
* 检查是否为内部IP地址
*
* @param ip IP地址
* @return 结果
*/
public static boolean internalIp(String ip)
{
byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip);
}

/**
* 检查是否为内部IP地址
*
* @param addr byte地址
* @return 结果
*/
private static boolean internalIp(byte[] addr)
{
if (StringUtils.isNull(addr) || addr.length < 2)
{
return true;
}
final byte b0 = addr[0];
final byte b1 = addr[1];
// 10.x.x.x/8
final byte SECTION_1 = 0x0A;
// 172.16.x.x/12
final byte SECTION_2 = (byte) 0xAC;
final byte SECTION_3 = (byte) 0x10;
final byte SECTION_4 = (byte) 0x1F;
// 192.168.x.x/16
final byte SECTION_5 = (byte) 0xC0;
final byte SECTION_6 = (byte) 0xA8;
switch (b0)
{
case SECTION_1:
return true;
case SECTION_2:
if (b1 >= SECTION_3 && b1 <= SECTION_4)
{
return true;
}
case SECTION_5:
switch (b1)
{
case SECTION_6:
return true;
}
default:
return false;
}
}

/**
* 将IPv4地址转换成字节
*
* @param text IPv4地址
* @return byte 字节
*/
public static byte[] textToNumericFormatV4(String text)
{
if (text.length() == 0)
{
return null;
}

byte[] bytes = new byte[4];
String[] elements = text.split("\\.", -1);
try
{
long l;
int i;
switch (elements.length)
{
case 1:
l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L))
{
return null;
}
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 2:
l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L))
{
return null;
}
bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L))
{
return null;
}
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 3:
for (i = 0; i < 2; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L))
{
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L))
{
return null;
}
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 4:
for (i = 0; i < 4; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L))
{
return null;
}
bytes[i] = (byte) (int) (l & 0xFF);
}
break;
default:
return null;
}
}
catch (NumberFormatException e)
{
return null;
}
return bytes;
}

/**
* 获取IP地址
*
* @return 本地IP地址
*/
public static String getHostIp()
{
try
{
return InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException e)
{
}
return "127.0.0.1";
}

/**
* 获取主机名
*
* @return 本地主机名
*/
public static String getHostName()
{
try
{
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e)
{
}
return "未知";
}

/**
* 从多级反向代理中获得第一个非unknown IP地址
*
* @param ip 获得的IP地址
* @return 第一个非unknown IP地址
*/
public static String getMultistageReverseProxyIp(String ip)
{
// 多级反向代理检测
if (ip != null && ip.indexOf(",") > 0)
{
final String[] ips = ip.trim().split(",");
for (String subIp : ips)
{
if (false == isUnknown(subIp))
{
ip = subIp;
break;
}
}
}
return ip;
}

/**
* 检测给定字符串是否为未知,多用于检测HTTP请求相关
*
* @param checkString 被检测的字符串
* @return 是否未知
*/
public static boolean isUnknown(String checkString)
{
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
}

/**
* 根据IP查询地区
*
* @param ip IP地址
* @return
*/
public static String getRealAddressByIP(String ip) {
String address = "XX XX";
// 内网不查询
if (IpUtils.internalIp(ip)) {
return "内网IP";
}
try {
String rspStr = HttpUtils.doSend("http://ip.taobao.com/service/getIpInfo.php?ip=" + ip, new JSONObject(), null, "GET");
if (org.springframework.util.StringUtils.isEmpty(rspStr)) {
log.error("获取地理位置异常 {}", ip);
return address;
}
JSONObject obj = JSONObject.parseObject(rspStr);
JSONObject data = obj.getObject("data", JSONObject.class);
String region = data.getString("region");
String city = data.getString("city");
address = region + " " + city;
}catch (Exception e){
log.info("获取ip地址信息失败。{}",ip);
}
return address;
}
}

+ 132
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/JacksonUtil.java View File

@@ -0,0 +1,132 @@
package com.tuoheng.common.core.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Map;

public class JacksonUtil {

private final static Logger LOGGER = LoggerFactory.getLogger(JacksonUtil.class);

private final static ObjectMapper objectMapper = new ObjectMapper();

private final static SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

private JacksonUtil(){}

static {
//序列化的时候序列对象的所有属性
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
//反序列化的时候如果多了其他属性,不抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//如果是空对象的时候,不抛异常
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//取消时间的转化格式,默认是时间戳,可以取消,同时需要设置要表现的时间格式
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.setDateFormat(dateformat);
}

/**
* 转换为 JSON 字符串
*
* @param obj
* @return
*/
public static <T> String obj2json(T obj) {
if(obj != null){
try {
return obj instanceof String ? (String)obj : objectMapper.writeValueAsString(obj);
} catch (Exception e) {
LOGGER.error("对象转字符串异常: {}", e);
}
}
return null;
}

/**
* 漂亮的转换为 JSON 字符串
*
* @param obj
* @return
*/
public static <T> String obj2StringPretty(T obj) {
if(obj != null){
try {
return obj instanceof String ? (String)obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (Exception e) {
LOGGER.error("对象转字符串异常: {}", e);
}
}
return null;
}

/**
* 转换为 JavaBean
*
* @param str
* @param clazz
* @return
* @throws Exception
*/
public static <T> T json2pojo(String str, Class<T> clazz) {
if(StringUtils.hasLength(str) && clazz != null){
try {
return clazz.equals(String.class)? (T)str : objectMapper.readValue(str,clazz);
} catch (Exception e) {
LOGGER.error("字符串转对象异常: {}", e);
}
}
return null;
}

/**
* 将 Map 转换为 JavaBean
*
* @param map
* @param clazz
* @return
*/
public static <T> T map2pojo(Map map, Class<T> clazz) {
return objectMapper.convertValue(map, clazz);
}

/**
* 将 JSON 对象转换为 JavaBean
*
* @param obj
* @param clazz
* @return
*/
public static <T> T obj2pojo(Object obj, Class<T> clazz) {
return objectMapper.convertValue(obj, clazz);
}

/**
* 将指定节点的 JSON 数据转换为 JavaBean
*
* @param str
* @param treeNode
* @param clazz
* @return
*/
public static <T> T json2pojoByTree(String str, String treeNode, Class<T> clazz) {
if(StringUtils.hasLength(str) && StringUtils.hasLength(str) && clazz == null){
try {
JsonNode jsonNode = objectMapper.readTree(str);
JsonNode data = jsonNode.findPath(treeNode);
return json2pojo(data.toString(), clazz);
} catch (Exception e) {
LOGGER.error("字符串按节点转对象异常: {}", e);
}
}
return null;
}
}

+ 99
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/JsonResult.java View File

@@ -0,0 +1,99 @@
package com.tuoheng.common.core.utils;

import java.io.Serializable;

/**
* JSON回应类
*
* @author 牧羊人
* @date 2019/11/28
*/
public class JsonResult<T> implements Serializable {

private static final long serialVersionUID = 1L;

/**
* 成功
*/
public static final int SUCCESS = 0;

/**
* 失败
*/
public static final int ERROR = -1;

private int code;

private String msg;

private T data;

public static <T> JsonResult<T> success() {
return jsonResult(null, SUCCESS, "操作成功");
}

public static <T> JsonResult<T> success(String msg) {
return jsonResult(null, SUCCESS, msg);
}

public static <T> JsonResult<T> success(T data) {
return jsonResult(data, SUCCESS, "操作成功");
}

public static <T> JsonResult<T> success(T data, String msg) {
return jsonResult(data, SUCCESS, msg);
}

public static <T> JsonResult<T> error() {
return jsonResult(null, ERROR, "操作失败");
}

public static <T> JsonResult<T> error(String msg) {
return jsonResult(null, ERROR, msg);
}

public static <T> JsonResult<T> error(T data) {
return jsonResult(data, ERROR, "操作失败");
}

public static <T> JsonResult<T> error(T data, String msg) {
return jsonResult(data, ERROR, msg);
}

public static <T> JsonResult<T> error(int code, String msg) {
return jsonResult(null, code, msg);
}

private static <T> JsonResult<T> jsonResult(T data, int code, String msg) {
JsonResult<T> result = new JsonResult<>();
result.setCode(code);
result.setData(data);
result.setMsg(msg);
return result;
}

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}

}

+ 15
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/LogUtil.java View File

@@ -0,0 +1,15 @@
package com.tuoheng.common.core.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 日志工具类
* @author chenyukun
*/
public class LogUtil {

private LogUtil(){}

public static final Logger LOGGER = LoggerFactory.getLogger(LogUtil.class);
}

+ 70
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/SecurityUserUtils.java View File

@@ -0,0 +1,70 @@
package com.tuoheng.common.core.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tuoheng.common.core.entity.UserEntity;
import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.model.dto.LoginUser;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

public class SecurityUserUtils {
/**
* 获取认证信息
*
* @return
*/
public static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}

/**
* 获取用户登录信息
*
* @return
*/
public static LoginUser getLoginUser() {
// header中获取用户token
String token = ServletUtils.getRequest().getHeader("th-token");
String oUserJson = ServletUtils.getRequest().getHeader("o-user-json");
String json = EncryptUtil.decodeUTF8StringBase64(oUserJson);
JSONObject jsonObject = JSON.parseObject(json);
String username = jsonObject.getString("username");
Long oidcUserId = jsonObject.getLong("oUserId");
// 这里可以自定义封装自己的用户信息
//UserPo userPo = clientUserMapper.getUserByUserName(username);
LoginUser user = new LoginUser()
.setUsername(username)
.setUserId(oidcUserId)
.setThToken(token);
return user;
}

public static String token() {
// header中获取用户token
String token = ServletUtils.getRequest().getHeader("th-token");
if (StringUtils.isEmpty(token)) {
throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "token不能为空");
}
return token;
}

/**
* 获取username
*
* @return
*/
public static String username() {
// header中获取用户token
String oUserJson = ServletUtils.getRequest().getHeader("o-user-json");
if (StringUtils.isEmpty(oUserJson)) {
throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "oUserJson不能为空");
}
String json = EncryptUtil.decodeUTF8StringBase64(oUserJson);
JSONObject jsonObject = JSON.parseObject(json);
String username = jsonObject.getString("username");
return username;
}

}

+ 188
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ServletUtils.java View File

@@ -0,0 +1,188 @@
package com.tuoheng.common.core.utils;

import cn.hutool.core.convert.Convert;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;

/**
* 客户端工具类
*
* @author ruoyi
*/
public class ServletUtils
{
/**
* 获取String参数
*/
public static String getParameter(String name)
{
return getRequest().getParameter(name);
}

/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue)
{
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}

/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name)
{
return Convert.toInt(getRequest().getParameter(name));
}

/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue)
{
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}

/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name)
{
return Convert.toBool(getRequest().getParameter(name));
}

/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name, Boolean defaultValue)
{
return Convert.toBool(getRequest().getParameter(name), defaultValue);
}

/**
* 获取request
*/
public static HttpServletRequest getRequest()
{
try
{
return getRequestAttributes().getRequest();
}
catch (Exception e)
{
return null;
}
}

/**
* 获取response
*/
public static HttpServletResponse getResponse()
{
try
{
return getRequestAttributes().getResponse();
}
catch (Exception e)
{
return null;
}
}

/**
* 获取session
*/
public static HttpSession getSession()
{
return getRequest().getSession();
}

public static ServletRequestAttributes getRequestAttributes()
{
try
{
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}
catch (Exception e)
{
return null;
}
}


public static Map<String, String> getHeaders(HttpServletRequest request)
{
Map<String, String> map = new LinkedCaseInsensitiveMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if (enumeration != null)
{
while (enumeration.hasMoreElements())
{
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
}
return map;
}

/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
*/
public static void renderString(HttpServletResponse response, String string)
{
try
{
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
}
catch (IOException e)
{
e.printStackTrace();
}
}

/**
* 是否是Ajax异步请求
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request)
{
String accept = request.getHeader("accept");
if (accept != null && accept.contains("application/json"))
{
return true;
}

String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
{
return true;
}

String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
{
return true;
}

String ajax = request.getParameter("__ajax");
return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
}
}

+ 386
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/StringUtils.java View File

@@ -0,0 +1,386 @@
package com.tuoheng.common.core.utils;

import java.util.*;

/**
* 字符串工具类
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {

/**
* 空字符串
*/
private static final String NULLSTR = "";

/**
* 下划线
*/
private static final char SEPARATOR = '_';

/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue) {
return value != null ? value : defaultValue;
}

/**
* * 判断一个Collection是否为空, 包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
public static boolean isEmpty(Collection<?> coll) {
return isNull(coll) || coll.isEmpty();
}

/**
* * 判断一个Collection是否非空,包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Collection<?> coll) {
return !isEmpty(coll);
}

/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* * @return true:为空 false:非空
*/
public static boolean isEmpty(Object[] objects) {
return isNull(objects) || (objects.length == 0);
}

/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Object[] objects) {
return !isEmpty(objects);
}

/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:为空 false:非空
*/
public static boolean isEmpty(Map<?, ?> map) {
return isNull(map) || map.isEmpty();
}

/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}

/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public static boolean isEmpty(String str) {
return isNull(str) || NULLSTR.equals(str.trim());
}

/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true:非空串 false:空串
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}

/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true:为空 false:非空
*/
public static boolean isNull(Object object) {
return object == null;
}

/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true:非空 false:空
*/
public static boolean isNotNull(Object object) {
return !isNull(object);
}

/**
* * 判断一个对象是否是数组类型(Java基本型别的数组)
*
* @param object 对象
* @return true:是数组 false:不是数组
*/
public static boolean isArray(Object object) {
return isNotNull(object) && object.getClass().isArray();
}

/**
* 去空格
*/
public static String trim(String str) {
return (str == null ? "" : str.trim());
}

/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
if (str == null) {
return NULLSTR;
}

if (start < 0) {
start = str.length() + start;
}

if (start < 0) {
start = 0;
}
if (start > str.length()) {
return NULLSTR;
}

return str.substring(start);
}

/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
if (str == null) {
return NULLSTR;
}

if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = str.length() + start;
}

if (end > str.length()) {
end = str.length();
}

if (start > end) {
return NULLSTR;
}

if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}

return str.substring(start, end);
}

/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static final Set<String> str2Set(String str, String sep) {
return new HashSet<String>(str2List(str, sep, true, false));
}

/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str)) {
return list;
}

// 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str)) {
return list;
}
String[] split = str.split(sep);
for (String string : split) {
if (filterBlank && StringUtils.isBlank(string)) {
continue;
}
if (trim) {
string = string.trim();
}
list.add(string);
}

return list;
}

/**
* 下划线转驼峰命名
*/
public static String toUnderScoreCase(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i > 0) {
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else {
preCharIsUpperCase = false;
}

curreCharIsUpperCase = Character.isUpperCase(c);

if (i < (str.length() - 1)) {
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}

if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}

return sb.toString();
}

/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs) {
if (str != null && strs != null) {
for (String s : strs) {
if (str.equalsIgnoreCase(trim(s))) {
return true;
}
}
}
return false;
}

/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty()) {
// 没必要转换
return "";
} else if (!name.contains("_")) {
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels) {
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) {
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}

/**
* 驼峰式命名法 例如:user_name->userName
*/
public static String toCamelCase(String s) {
if (s == null) {
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);

if (c == SEPARATOR) {
upperCase = true;
} else if (upperCase) {
sb.append(Character.toUpperCase(c));
upperCase = false;
} else {
sb.append(c);
}
}
return sb.toString();
}

/**
* 替换字符串中的域名
*/
public static String removeHost(String str, String host) {
if (!StringUtils.isEmpty(str) && str.contains(host)) {
return str.replaceAll(host, "");
}
return str;
}

/**
* 添加字符串中的域名
*/
public static String addHost(String str, String host) {
if (!StringUtils.isEmpty(str) && !str.contains(host)) {
return host + str;
}
return str;
}
}

+ 34
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ThreadLocalUtil.java View File

@@ -0,0 +1,34 @@



package com.tuoheng.common.core.utils;


/**
* @Author xiaoying
* @Date 2022/10/31 11:01
*/


public class ThreadLocalUtil {

private final static ThreadLocal<Object> USER_THREAD_LOCAL = new ThreadLocal<>();

// 存放
public static void set(Object user) {
USER_THREAD_LOCAL.set(user);
}

// 获取
public static Object get() {
return USER_THREAD_LOCAL.get();
}

// 移除
public static void remove() {
USER_THREAD_LOCAL.remove();
}
}




+ 74
- 0
tuoheng-common/tuoheng-common-core/src/main/java/com/tuoheng/common/core/utils/ValidatorUtils.java View File

@@ -0,0 +1,74 @@
package com.tuoheng.common.core.utils;


import com.tuoheng.common.core.exception.ServiceException;
import org.hibernate.validator.HibernateValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
* @author chenyukun
*/
public class ValidatorUtils {

private static final Logger LOGGER = LoggerFactory.getLogger(ValidatorUtils.class);

private static Validator validatorFast = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(true)
.buildValidatorFactory()
.getValidator();

private static Validator validatorAll = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(false)
.buildValidatorFactory()
.getValidator();

/**
* 校验遇到第一个不合法的字段直接返回不合法字段,后续字段不再校验
* @param t t
*/
public static <T> void validateFast(T t) {
Set<ConstraintViolation<T>> validateResult = validatorFast.validate(t);
buildResult(validateResult);
}

/**
* 校验所有字段并返回不合法字段
* @param t t
*/
public static <T> void validateAll(T t) {
Set<ConstraintViolation<T>> validateResult = validatorAll.validate(t);
buildResult(validateResult);
}

/**
* 封装验证结果
* @param validateResult 验证结果
* @param <T>
*/
private static <T> void buildResult(Set<ConstraintViolation<T>> validateResult){
Map<String, String> result = new HashMap<>(validateResult.size());
if(!CollectionUtils.isEmpty(validateResult)) {
Iterator<ConstraintViolation<T>> it = validateResult.iterator();
while(it.hasNext()) {
ConstraintViolation<T> cv = it.next();
result.put(cv.getPropertyPath().toString(), cv.getMessage());
}
LOGGER.error("参数验证未通过,校验结果:{}", JacksonUtil.obj2json(result));
throw new ServiceException(HttpStatus.BAD_REQUEST.value(), JacksonUtil.obj2json(result));
}
LOGGER.info("参数验证通过,校验异常数量:{}", validateResult.size());
}
}

+ 53
- 0
tuoheng-common/tuoheng-common-security/pom.xml View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tuoheng-common</artifactId>
<groupId>com.tuoheng</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-common-security</artifactId>

<!-- 依赖库管理 -->
<dependencies>
<!-- Spring Security Oauth2 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<!-- 此处需要加版本号 -->
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
<!-- 此处需要加版本号 -->
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-plus 起始依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>

</project>

+ 25
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/annotation/EnableCustomConfig.java View File

@@ -0,0 +1,25 @@
package com.tuoheng.common.security.annotation;

import com.tuoheng.common.security.config.OAuth2FeignConfig;
import com.tuoheng.common.security.security.SecurityImportBeanDefinitionRegistrar;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 表示通过aop框架暴露该代理对象,AopContext能够访问
@EnableAspectJAutoProxy(exposeProxy = true)
// 指定要扫描的Mapper类的包的路径
@MapperScan("com.tuoheng.**.**.mapper")
// 开启线程异步执行
@EnableAsync
// 自动加载类
@Import({SecurityImportBeanDefinitionRegistrar.class, OAuth2FeignConfig.class})
public @interface EnableCustomConfig {
}

+ 21
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/annotation/EnableTHFeignClients.java View File

@@ -0,0 +1,21 @@
package com.tuoheng.common.security.annotation;

import org.springframework.cloud.openfeign.EnableFeignClients;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EnableFeignClients
public @interface EnableTHFeignClients {
String[] value() default {};

String[] basePackages() default {"com.tuoheng"};

Class<?>[] basePackageClasses() default {};

Class<?>[] defaultConfiguration() default {};

Class<?>[] clients() default {};
}

+ 19
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/config/OAuth2FeignConfig.java View File

@@ -0,0 +1,19 @@
package com.tuoheng.common.security.config;

import com.tuoheng.common.security.interceptor.OAuth2FeignRequestInterceptor;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* 拦截器配置
*/
@Configuration
public class OAuth2FeignConfig {

@Bean
public RequestInterceptor requestInterceptor() {
return new OAuth2FeignRequestInterceptor();
}

}

+ 77
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/config/ResourceServerConfig.java View File

@@ -0,0 +1,77 @@
package com.tuoheng.common.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

@Configuration
@EnableResourceServer
//@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(3)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

@Autowired
private ResourceServerProperties resourceServerProperties;

@Autowired
private OAuth2ClientProperties oAuth2ClientProperties;

/**
* 重写安全配置类
*
* @param http
* @throws Exception
*/
@Override
public void configure(HttpSecurity http) throws Exception {
// super.configure(http);
http.csrf().disable();
http
.authorizeRequests()
// 设置不登录可以访问
.antMatchers("/oauth/**").permitAll()
// 其他请求认证后放行
.anyRequest().authenticated();
}

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
return restTemplate;
}

// @Bean
// @Primary
// public ResourceServerTokenServices tokenServices() {
// RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
// DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
// UserAuthenticationConverter userTokenConverter = new CustomUserAuthenticationConverter();
// accessTokenConverter.setUserTokenConverter(userTokenConverter);
// remoteTokenServices.setCheckTokenEndpointUrl(resourceServerProperties.getTokenInfoUri());
// remoteTokenServices.setClientId(oAuth2ClientProperties.getClientId());
// remoteTokenServices.setClientSecret(oAuth2ClientProperties.getClientSecret());
// remoteTokenServices.setRestTemplate(restTemplate());
// remoteTokenServices.setAccessTokenConverter(accessTokenConverter);
// return remoteTokenServices;
// }

// @Override
// public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
// resources.tokenServices(tokenServices())
// // 处理未认证
// .authenticationEntryPoint(new OAuthAuthExceptionEntryPoint())
// // 处理未授权
// .accessDeniedHandler(new OAuthAccessDeniedHandler());
// }
}

+ 33
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/constant/SecurityConstant.java View File

@@ -0,0 +1,33 @@
package com.tuoheng.common.security.constant;

/**
* 安全配置常量
*/
public class SecurityConstant {

/**
* 令牌类型
*/
public static final String BEARER_TOKEN_TYPE = "Bearer";

/**
* 授权token url
*/
public static final String AUTH_TOKEN = "/oauth/token";

/**
* 注销token url
*/
public static final String TOKEN_LOGOUT = "/token/logout";

/**
* 用户ID字段
*/
public static final String DETAILS_USER_ID = "id";

/**
* 用户名字段
*/
public static final String DETAILS_USERNAME = "username";

}

+ 27
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/entity/SecurityUser.java View File

@@ -0,0 +1,27 @@
package com.tuoheng.common.security.entity;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

public class SecurityUser extends User {

/**
* 登录用户ID
*/
private Integer userId;

public SecurityUser(Integer userId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.userId = userId;
}

public Integer getUserId() {
return this.userId;
}

public void setUserId(Integer userId) {
this.userId = userId;
}
}

+ 26
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/interceptor/OAuth2FeignRequestInterceptor.java View File

@@ -0,0 +1,26 @@
package com.tuoheng.common.security.interceptor;

import com.tuoheng.common.security.constant.SecurityConstant;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.stereotype.Component;

@Component
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {

@Override
public void apply(RequestTemplate requestTemplate) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails dateils = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header(HttpHeaders.AUTHORIZATION,
String.format("%s %s", SecurityConstant.BEARER_TOKEN_TYPE, dateils.getTokenValue()));
}
}
}

+ 62
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/CustomUserAuthenticationConverter.java View File

@@ -0,0 +1,62 @@
package com.tuoheng.common.security.security;

import com.tuoheng.common.security.constant.SecurityConstant;
import com.tuoheng.common.security.entity.SecurityUser;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

public class CustomUserAuthenticationConverter implements UserAuthenticationConverter {

private static final String N_A = "N/A";

@Override
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
Map<String, Object> authMap = new LinkedHashMap<>();
authMap.put(USERNAME, authentication.getName());
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
authMap.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
}
return authMap;
}

@Override
public Authentication extractAuthentication(Map<String, ?> map) {
if (map.containsKey(USERNAME)) {
Collection<? extends GrantedAuthority> authorities = getAuthorities(map);

// 自定义对象,这里可以根据实际需要进行设置
Integer userId = Integer.valueOf(map.get(SecurityConstant.DETAILS_USER_ID).toString());
String username = map.get(SecurityConstant.DETAILS_USERNAME).toString();
SecurityUser user = new SecurityUser(userId, username, N_A, true, true, true, true, authorities);

return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
}
return null;
}

/**
* 获取权限资源信息
*
* @param map
* @return
*/
private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
Object authorities = map.get(AUTHORITIES);
if (authorities instanceof String) {
return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
}
if (authorities instanceof Collection) {
return AuthorityUtils.commaSeparatedStringToAuthorityList(
StringUtils.collectionToCommaDelimitedString((Collection<?>) authorities));
}
throw new IllegalArgumentException("Authorities must be either a String or a Collection");
}
}

+ 34
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/OAuthAccessDeniedHandler.java View File

@@ -0,0 +1,34 @@
package com.tuoheng.common.security.security;

import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class OAuthAccessDeniedHandler implements AccessDeniedHandler {

@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", 401);
map.put("msg", "权限不足");
map.put("data", accessDeniedException.getMessage());
map.put("success", false);
map.put("path", request.getServletPath());
map.put("timestamp", String.valueOf(new Date().getTime()));
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(mapper.writeValueAsString(map));
}
}

+ 41
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/OAuthAuthExceptionEntryPoint.java View File

@@ -0,0 +1,41 @@
package com.tuoheng.common.security.security;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.tuoheng.common.security.utils.JsonResult;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class OAuthAuthExceptionEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setStatus(HttpStatus.OK.value());
response.setHeader("Content-Type", "application/json;charset=UTF-8");
// httpServletResponse.setContentType("application/json; charset=utf-8");
// httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
Throwable cause = authException.getCause();
try {
if (cause instanceof InvalidTokenException) {
// 无效的token
JsonResult jsonResult = new JsonResult();
response.getWriter().write(JSONObject.toJSONString(jsonResult.error(401, "请先登录"), SerializerFeature.WriteMapNullValue));
} else {
// 访问此资源需要完全的身份验证
JsonResult jsonResult = new JsonResult();
response.getWriter().write(JSONObject.toJSONString(jsonResult.error(401, "访问此资源需要完全的身份验证"), SerializerFeature.WriteMapNullValue));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

+ 23
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/security/SecurityImportBeanDefinitionRegistrar.java View File

@@ -0,0 +1,23 @@
package com.tuoheng.common.security.security;

import com.tuoheng.common.security.config.ResourceServerConfig;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

/**
* 注册自动加载类
*/
public class SecurityImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
Class<ResourceServerConfig> aClass = ResourceServerConfig.class;
String beanName = StringUtils.uncapitalize(aClass.getSimpleName());
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ResourceServerConfig.class);
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
}
}

+ 99
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/utils/JsonResult.java View File

@@ -0,0 +1,99 @@
package com.tuoheng.common.security.utils;

import java.io.Serializable;

/**
* JSON回应类
*
* @author 牧羊人
* @date 2019/11/28
*/
public class JsonResult<T> implements Serializable {

private static final long serialVersionUID = 1L;

/**
* 成功
*/
public static final int SUCCESS = 0;

/**
* 失败
*/
public static final int error = -1;

private int code;

private String msg;

private T data;

public static <T> JsonResult<T> success() {
return jsonResult(null, SUCCESS, "操作成功");
}

public static <T> JsonResult<T> success(String msg) {
return jsonResult(null, SUCCESS, msg);
}

public static <T> JsonResult<T> success(T data) {
return jsonResult(data, SUCCESS, "操作成功");
}

public static <T> JsonResult<T> success(T data, String msg) {
return jsonResult(data, SUCCESS, msg);
}

public static <T> JsonResult<T> error() {
return jsonResult(null, error, "操作失败");
}

public static <T> JsonResult<T> error(String msg) {
return jsonResult(null, error, msg);
}

public static <T> JsonResult<T> error(T data) {
return jsonResult(data, error, "操作失败");
}

public static <T> JsonResult<T> error(T data, String msg) {
return jsonResult(data, error, msg);
}

public static <T> JsonResult<T> error(int code, String msg) {
return jsonResult(null, code, msg);
}

private static <T> JsonResult<T> jsonResult(T data, int code, String msg) {
JsonResult<T> result = new JsonResult<>();
result.setCode(code);
result.setData(data);
result.setMsg(msg);
return result;
}

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}

}

+ 78
- 0
tuoheng-common/tuoheng-common-security/src/main/java/com/tuoheng/common/security/utils/SecurityUtils.java View File

@@ -0,0 +1,78 @@
package com.tuoheng.common.security.utils;

import com.tuoheng.common.security.entity.SecurityUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class SecurityUtils {

/**
* 获取用户ID
*
* @return
*/
public static Integer getUserId() {
return getSecurityUser().getUserId();
}

/**
* 获取用户认证信息
*
* @return
*/
public static SecurityUser getSecurityUser() {
Authentication authentication = getAuthentication();
if (authentication == null) {
return null;
}
return getLoginUser(authentication);
}

/**
* 获取认证信息
*
* @return
*/
public static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}

/**
* 获取用户登录信息
*
* @param authentication
* @return
*/
public static SecurityUser getLoginUser(Authentication authentication) {
Object principal = authentication.getPrincipal();
if (principal instanceof SecurityUser) {
return (SecurityUser) principal;
}
return null;
}

/**
* 生成加密密码
*
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}

/**
* 比对密码是否一直
*
* @param password 原始密码
* @param encodedPassword 加密后的密码
* @return
*/
public static boolean matchesPassword(String password, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(password, encodedPassword);
}

}

+ 18
- 0
tuoheng-feign/pom.xml View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tuoheng_freeway</artifactId>
<groupId>com.tuoheng</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-feign</artifactId>
<packaging>pom</packaging>
<modules>
<module>tuoheng-api-feign</module>
</modules>

</project>

+ 4
- 0
tuoheng-feign/tuoheng-api-feign/README.md View File

@@ -0,0 +1,4 @@
# tuoheng_freeway

## tuoheng-freeway-feign
freeway内部通过feign相互调用

+ 43
- 0
tuoheng-feign/tuoheng-api-feign/pom.xml View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tuoheng-feign</artifactId>
<groupId>com.tuoheng</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-api-feign</artifactId>

<dependencies>
<!-- 核心基类依赖 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--mybatis-plus 起始依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>

</dependencies>

</project>

+ 15
- 0
tuoheng-feign/tuoheng-api-feign/src/main/java/com/tuoheng/api/feign/feign/ApiClient.java View File

@@ -0,0 +1,15 @@
package com.tuoheng.api.feign.feign;

import com.tuoheng.common.core.utils.JsonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(value = "tuoheng-freeway-admin")
public interface ApiClient {
/**
*
* @return
*/
@GetMapping("/test")
JsonResult test();
}

+ 21
- 0
tuoheng-feign/tuoheng-api-feign/src/main/java/com/tuoheng/api/feign/feign/fallback/ApiClientFallback.java View File

@@ -0,0 +1,21 @@
package com.tuoheng.api.feign.feign.fallback;

import com.tuoheng.api.feign.feign.ApiClient;
import com.tuoheng.common.core.utils.JsonResult;
import org.springframework.stereotype.Component;


/**
* @Author xiaoying
* @Date 2022/10/14 14:58
*/
@Component
public class ApiClientFallback implements ApiClient {


@Override
public JsonResult test() {
return JsonResult.success();
}
}


+ 3
- 0
tuoheng-feign/tuoheng-api-feign/src/main/resources/META-INF/spring.factories View File

@@ -0,0 +1,3 @@
#org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
# com.tuoheng.api.feign.feign.fallback.ApiClientFallback


+ 20
- 0
tuoheng-service/pom.xml View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tuoheng_freeway</artifactId>
<groupId>com.tuoheng</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-service</artifactId>
<packaging>pom</packaging>
<modules>
<module>tuoheng-admin</module>
<module>tuoheng-miniprogram</module>
<module>tuoheng-api</module>
</modules>

</project>

+ 213
- 0
tuoheng-service/tuoheng-admin/pom.xml View File

@@ -0,0 +1,213 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tuoheng-service</artifactId>
<groupId>com.tuoheng</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-admin</artifactId>

<!-- 依赖声明管理 -->
<dependencies>
<!-- 核心基类模块 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-common-core</artifactId>
</dependency>
<!-- Feign调用层系统API接口 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-system-feign</artifactId>
</dependency>
<!-- Consul注册中心起始依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MySql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 引入阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mybatis-plus 代码自动生成 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.aliyun</groupId>
<artifactId>vod20170321</artifactId>
<version>2.16.8</version>
</dependency>
<!--阿里云视频点播-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-vod</artifactId>
<version>2.15.11</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-kms</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.aliyun.vod</groupId>
<artifactId>upload</artifactId>
<version>1.4.14</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/aliyun-java-vod-upload-1.4.14.jar</systemPath>
</dependency>

</dependencies>

<!-- 环境变量配置 -->
<profiles>
<!-- 本地开发环境 -->
<profile>
<id>local</id>
<properties>
<package.environment>local</package.environment>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!-- 开发环境 -->
<profile>
<id>dev</id>
<properties>
<package.environment>dev</package.environment>
</properties>
</profile>
<!-- 测试环境 -->
<profile>
<id>test</id>
<properties>
<package.environment>test</package.environment>
</properties>
</profile>
<!-- 生产环境 -->
<profile>
<id>prod</id>
<properties>
<package.environment>prod</package.environment>
</properties>
</profile>
</profiles>

<!-- 环境变量构建 -->
<build>
<finalName>tuoheng_freeway_admin</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>

<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>

<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<targetPath>WEB-INF/classes</targetPath>
<includes>
<include>application-${package.environment}.yml</include>
</includes>
</resource>
</resources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.11.RELEASE</version>
<configuration>
<finalName>${project.build.finalName}</finalName>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>

+ 22
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/THAdminApplication.java View File

@@ -0,0 +1,22 @@
package com.tuoheng.admin;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.tuoheng")
@MapperScan("com.tuoheng.**.**.mapper")
@EnableAsync
public class THAdminApplication {

public static void main(String[] args) {
SpringApplication.run(THAdminApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 微服务【业务服务】启动成功 ლ(´ڡ`ლ)゙");
}

}

+ 42
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/AdminMvcConfig.java View File

@@ -0,0 +1,42 @@

package com.tuoheng.admin.config;

import com.tuoheng.admin.interceptor.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;


/**
* @Author xiaoying
* @Date 2022/10/31 14:06
*/
//web相关配置
@Configuration
public class AdminMvcConfig implements WebMvcConfigurer {

@Bean
public UserInterceptor setBean(){
//System.out.println("注入了handler");
return new UserInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器
registry.addInterceptor(setBean())
//设置拦截的请求
.addPathPatterns("/**")
//排除拦截的请求
.excludePathPatterns(
"/user/login", //登录
"/user/loginout", //退出
"/error" //springBoot异常处理的默认请求

);
}
}

+ 80
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/AliyuncsVodConfig.java View File

@@ -0,0 +1,80 @@
package com.tuoheng.admin.config;

import com.aliyun.teaopenapi.models.Config;
import com.aliyun.vod20170321.Client;
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.context.annotation.Lazy;

/**
* 阿里云点播服务配置类
*
* @author WangHaoran
* @since 2022-03-11
*/
@Configuration
@Slf4j
public class AliyuncsVodConfig {

/**
* 阿里云endpoint
*/
public final static String ENDPOINT = "vod.cn-shanghai.aliyuncs.com";

/**
* 账号
*/
public static String accessKeyId;

/**
* 密码
*/
public static String accessKeySecret;

/**
* 角色ARN
*/
public static String roleArn;

/**
* Bucket名称
*/
public static String bucketName;

@Value("${aliyuncsVod.accessKeyId}")
public void setAccessKeyId(String accessKeyId) {
AliyuncsVodConfig.accessKeyId = accessKeyId;
}

@Value("${aliyuncsVod.accessKeySecret}")
public void setAccessKeySecret(String accessKeySecret) {
AliyuncsVodConfig.accessKeySecret = accessKeySecret;
}

@Value("${aliyuncsVod.roleArn}")
public void setRoleArn(String roleArn) {
AliyuncsVodConfig.roleArn = roleArn;
}

@Value("${aliyuncsVod.bucketName}")
public void setBucketName(String bucketName) {
AliyuncsVodConfig.bucketName = bucketName;
}

@Bean
@Lazy
public Client vodClient() {
try {
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret)
.setEndpoint(ENDPOINT);
return new Client(config);
} catch (Exception e) {
log.error("获取vodClient客户端失败", e);
}
return null;
}
}

+ 70
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/CommonConfig.java View File

@@ -0,0 +1,70 @@
package com.tuoheng.admin.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

@Configuration
@Data
public class CommonConfig {

/**
* 图片域名
*/
public static String imageURL;

/**
* OSS域名
*/
public static String ossURL;

/**
* 视频域名
*/
public static String videoURL;

/**
* oidc地址
*/
public static String oidcUrl;

/**
* 图片域名赋值
*
* @param url 域名地址
*/
@Value("${tuoheng.image-url}")
public void setImageURL(String url) {
imageURL = url;
}

/**
* 阿里云OSS域名
*
* @param url 图片地址
*/
@Value("${tuoheng.oss-url}")
public void setOssURL(String url) {
ossURL = url;
}

/**
* 视频域名赋值
*
* @param url 域名地址
*/
@Value("${tuoheng.video-url}")
public void setVideoURL(String url) {
videoURL = url;
}

/**
* oidc地址赋值
*
* @param url 通道地址
*/
@Value("${tuoheng.oidc-url}")
public void setOidcUrl(String url) {
oidcUrl = url;
}
}

+ 29
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/RestTemplateConfig.java View File

@@ -0,0 +1,29 @@
package com.tuoheng.admin.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
* 第三方配置
* @Author: xiaoying
* @Date: 2022/10/18 9:02
*/
@Configuration
public class RestTemplateConfig {

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}

@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(30000);
factory.setReadTimeout(30000);
return factory;
}
}

+ 86
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/XxlJobConfig.java View File

@@ -0,0 +1,86 @@
package com.tuoheng.admin.config;

import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@Configuration
@ConditionalOnProperty(name = XxlJobConfig.XXL_ENABLE, havingValue = XxlJobConfig.TRUE)
public class XxlJobConfig {

public static final String XXL_ENABLE = "xxl.enable";

public static final String TRUE = "true";

private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

@Value("${xxl.job.admin.addresses}")
private String adminAddresses;

@Value("${xxl.job.accessToken}")
private String accessToken;

@Value("${xxl.job.executor.appname}")
private String appname;

@Value("${xxl.job.executor.address}")
private String address;

@Value("${xxl.job.executor.ip}")
private String ip;

@Value("${xxl.job.executor.port}")
private int port;

@Value("${xxl.job.executor.logpath}")
private String logPath;

@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;


@Bean
public XxlJobSpringExecutor xxlJobExecutor() throws InterruptedException {
logger.info(">>>>>>>>>>> xxl-job config init.");
Thread.sleep(5000);
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

return xxlJobSpringExecutor;
}

/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
*
* 1、引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器启动变量
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3、获取IP
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/


}

+ 223
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/AbstractLikeSqlConverter.java View File

@@ -0,0 +1,223 @@
package com.tuoheng.admin.config.sql;

import com.tuoheng.common.core.utils.LogUtil;
import com.tuoheng.common.core.utils.StringUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;

/**
* 包含like的SQL语句转义模板
* @author chenyukun
*/
public abstract class AbstractLikeSqlConverter<T> {

/**
* SQL语句like使用关键字%
*/
private final static String LIKE_SQL_KEY = "%";

/**
* SQL语句需要转义的关键字
*/
private final static String[] ESCAPE_CHAR = new String[]{LIKE_SQL_KEY, "_", "\\"};

/**
* mybatis-plus中like的SQL语句样式
*/
private final static String MYBATIS_PLUS_LIKE_SQL = " like ?";

/**
* mybatis-plus中参数前缀
*/
private final static String MYBATIS_PLUS_WRAPPER_PREFIX = "ew.paramNameValuePairs.";

/**
* mybatis-plus中参数键
*/
final static String MYBATIS_PLUS_WRAPPER_KEY = "ew";

/**
* mybatis-plus中参数分隔符
*/
final static String MYBATIS_PLUS_WRAPPER_SEPARATOR = ".";

/**
* mybatis-plus中参数分隔符替换器
*/
final static String MYBATIS_PLUS_WRAPPER_SEPARATOR_REGEX = "\\.";

/**
* 已经替换过的标记
*/
final static String REPLACED_LIKE_KEYWORD_MARK = "replaced.keyword";

/**
* 转义特殊字符
*
* @param sql SQL语句
* @param fields 字段列表
* @param parameter 参数对象
*/
public void convert(String sql, Set<String> fields, T parameter) {
for (String field : fields) {
if (this.hasMybatisPlusLikeSql(sql)) {
if (this.hasWrapper(field)) {
// 第一种情况:在业务层进行条件构造产生的模糊查询关键字,使用QueryWrapper,LambdaQueryWrapper
this.transferWrapper(field, parameter);
} else {
// 第二种情况:未使用条件构造器,但是在service层进行了查询关键字与模糊查询符`%`手动拼接
this.transferSelf(field, parameter);
}
} else {
// 第三种情况:在Mapper类的注解SQL中进行了模糊查询的拼接
this.transferSplice(field, parameter);
}
}
}

/**
* 转义条件构造的特殊字符
* 在业务层进行条件构造产生的模糊查询关键字,使用QueryWrapper,LambdaQueryWrapper
*
* @param field 字段名称
* @param parameter 参数对象
*/
public abstract void transferWrapper(String field, T parameter);

/**
* 转义自定义条件拼接的特殊字符
* 未使用条件构造器,但是在service层进行了查询关键字与模糊查询符`%`手动拼接
*
* @param field 字段名称
* @param parameter 参数对象
*/
public abstract void transferSelf(String field, T parameter);

/**
* 转义自定义条件拼接的特殊字符
* 在Mapper类的注解SQL中进行了模糊查询的拼接
*
* @param field 字段名称
* @param parameter 参数对象
*/
public abstract void transferSplice(String field, T parameter);

/**
* 转义通配符
*
* @param before 待转义字符串
* @return 转义后字符串
*/
String escapeChar(String before) {
if (StringUtils.isNotBlank(before)) {
before = before.replaceAll("\\\\", "\\\\\\\\");
before = before.replaceAll("_", "\\\\_");
before = before.replaceAll("%", "\\\\%");
}
return before;
}

/**
* 是否包含需要转义的字符
*
* @param obj 待判断的对象
* @return true/false
*/
boolean hasEscapeChar(Object obj) {
if (!(obj instanceof String)) {
return false;
}
return this.hasEscapeChar((String) obj);
}

/**
* 处理对象like问题
*
* @param field 对象字段
* @param parameter 对象
*/
void resolveObj(String field, Object parameter) {
if (parameter == null || StringUtils.isBlank(field)) {
return;
}
try {
PropertyDescriptor descriptor = new PropertyDescriptor(field, parameter.getClass());
Method readMethod = descriptor.getReadMethod();
Object param = readMethod.invoke(parameter);
if (this.hasEscapeChar(param)) {
Method setMethod = descriptor.getWriteMethod();
setMethod.invoke(parameter, this.escapeChar(param.toString()));
} else if (this.cascade(field)) {
int index = field.indexOf(MYBATIS_PLUS_WRAPPER_SEPARATOR) + 1;
this.resolveObj(field.substring(index), param);
}
} catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
LogUtil.LOGGER.error("反射 {} 的 {} get/set方法出现异常", parameter, field, e);
}

}

/**
* 判断是否是级联属性
*
* @param field 字段名
* @return true/false
*/
boolean cascade(String field) {
if (StringUtils.isBlank(field)) {
return false;
}
return field.contains(MYBATIS_PLUS_WRAPPER_SEPARATOR) && !this.hasWrapper(field);
}

/**
* 是否包含mybatis-plus的包含like的SQL语句格式
*
* @param sql 完整SQL语句
* @return true/false
*/

private boolean hasMybatisPlusLikeSql(String sql) {
if (StringUtils.isBlank(sql)) {
return false;
}
return sql.toLowerCase().contains(MYBATIS_PLUS_LIKE_SQL);
}

/**
* 判断是否使用mybatis-plus条件构造器
*
* @param field 字段
* @return true/false
*/

private boolean hasWrapper(String field) {
if (StringUtils.isBlank(field)) {
return false;
}
return field.contains(MYBATIS_PLUS_WRAPPER_PREFIX);
}

/**
* 判断字符串是否含有需要转义的字符
*
* @param str 待判断的字符串
* @return true/false
*/
private boolean hasEscapeChar(String str) {
if (StringUtils.isBlank(str)) {
return false;
}
for (String s : ESCAPE_CHAR) {
if (str.contains(s)) {
return true;
}
}
return false;
}

}

+ 61
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/DruidConfig.java View File

@@ -0,0 +1,61 @@
//package com.tuoheng.admin.config.sql;
//
//import com.alibaba.druid.pool.DruidDataSource;
//import com.alibaba.druid.support.http.StatViewServlet;
//import com.alibaba.druid.support.http.WebStatFilter;
//import org.springframework.boot.context.properties.ConfigurationProperties;
//import org.springframework.boot.web.servlet.FilterRegistrationBean;
//import org.springframework.boot.web.servlet.ServletRegistrationBean;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//import javax.servlet.Filter;
//import javax.servlet.Servlet;
//import javax.sql.DataSource;
//import java.util.Arrays;
//import java.util.HashMap;
//import java.util.Map;
//
///**
// * Druid连接池配置类
// * @author chenyukun
// */
//@Configuration
//public class DruidConfig {
//
// @ConfigurationProperties(prefix = "spring.datasource")
// @Bean
// public DataSource druid() {
// return new DruidDataSource();
// }
//
// /**
// * 配置Druid的监控 配置一个管理后台的Servlet
// * @return
// */
// @Bean
// public ServletRegistrationBean statViewServlet() {
// ServletRegistrationBean<Servlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
// Map<String, String> initParams = new HashMap<>(4);
// initParams.put("loginUsername", "admin");
// initParams.put("loginPassword", "123456");
// initParams.put("allow", "");
// initParams.put("deny", "192.168.15.21");
// bean.setInitParameters(initParams);
// return bean;
// }
//
// /**
// * 配置一个web监管的filter
// */
// @Bean
// public FilterRegistrationBean webStatFilter() {
// final FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
// bean.setFilter(new WebStatFilter());
// Map<String, String> initParams = new HashMap<>();
// bean.setInitParameters(initParams);
// bean.setUrlPatterns(Arrays.asList("/*"));
// return bean;
// }
//
//}

+ 75
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/MapLikeSqlConverter.java View File

@@ -0,0 +1,75 @@
package com.tuoheng.admin.config.sql;

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import java.util.Map;
import java.util.Objects;

/**
* @author chenyukun
*/
public class MapLikeSqlConverter extends AbstractLikeSqlConverter<Map> {

@Override
public void transferWrapper(String field, Map parameter) {
AbstractWrapper wrapper = (AbstractWrapper) parameter.get(MYBATIS_PLUS_WRAPPER_KEY);
parameter = wrapper.getParamNameValuePairs();
String[] keys = field.split(MYBATIS_PLUS_WRAPPER_SEPARATOR_REGEX);
// ew.paramNameValuePairs.param1,截取字符串之后,获取第三个,即为参数名
String paramName = keys[2];
String mapKey = String.format("%s.%s", REPLACED_LIKE_KEYWORD_MARK, paramName);
if (parameter.containsKey(mapKey) && Objects.equals(parameter.get(mapKey), true)) {
return;
}
if (this.cascade(field)) {
this.resolveCascadeObj(field, parameter);
} else {
Object param = parameter.get(paramName);
if (this.hasEscapeChar(param)) {
String paramStr = param.toString();
parameter.put(keys[2], String.format("%%%s%%", this.escapeChar(paramStr.substring(1, paramStr.length() - 1))));
}
}
parameter.put(mapKey, true);
}

@Override
public void transferSelf(String field, Map parameter) {
if (this.cascade(field)) {
this.resolveCascadeObj(field, parameter);
return;
}
Object param = parameter.get(field);
if (this.hasEscapeChar(param)) {
String paramStr = param.toString();
parameter.put(field, String.format("%%%s%%", this.escapeChar(paramStr.substring(1, paramStr.length() - 1))));
}
}

@Override
public void transferSplice(String field, Map parameter) {
if (this.cascade(field)) {
this.resolveCascadeObj(field, parameter);
return;
}
Object param = parameter.get(field);
if (this.hasEscapeChar(param)) {
parameter.put(field, this.escapeChar(param.toString()));
}
}

/**
* 处理级联属性
*
* @param field 级联字段名
* @param parameter 参数Map对象
*/
private void resolveCascadeObj(String field, Map parameter) {
int index = field.indexOf(MYBATIS_PLUS_WRAPPER_SEPARATOR);
Object param = parameter.get(field.substring(0, index));
if (param == null) {
return;
}
this.resolveObj(field.substring(index + 1), param);
}

}

+ 33
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/MybatisPlusConfig.java View File

@@ -0,0 +1,33 @@
package com.tuoheng.admin.config.sql;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.tuoheng.admin.config.sql.MybatisPlusInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
* 分页插件配置类
*/
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件
*
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}

/**
* 自定义拦截器
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
return interceptor;
}
}

+ 151
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/MybatisPlusInterceptor.java View File

@@ -0,0 +1,151 @@
package com.tuoheng.admin.config.sql;

import com.tuoheng.common.core.utils.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.*;

/**
* like字符转义
* @author chenyukun
*/
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class})})
public class MybatisPlusInterceptor implements Interceptor {

/**
* SQL语句like
*/
private final static String SQL_LIKE = " like ";

/**
* SQL语句占位符
*/
private final static String SQL_PLACEHOLDER = "?";

/**
* SQL语句占位符分隔
*/
private final static String SQL_PLACEHOLDER_REGEX = "\\?";

/**
* 所有的转义器
*/
private static Map<Class, AbstractLikeSqlConverter> converterMap = new HashMap<>(4);

static {
converterMap.put(Map.class, new MapLikeSqlConverter());
// converterMap.put(Object.class, new ObjectLikeSqlConverter());
}

@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取sql及参数信息
Object[] args = invocation.getArgs();
MappedStatement statement = (MappedStatement) args[0];
Object parameterObject = args[1];
BoundSql boundSql = statement.getBoundSql(parameterObject);
String sql = boundSql.getSql();
this.transferLikeSql(sql, parameterObject, boundSql);
return invocation.proceed();
}

@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties arg0) {
}

/**
* 修改包含like的SQL语句
*
* @param sql SQL语句
* @param parameterObject 参数对象
* @param boundSql 绑定SQL对象
*/
private void transferLikeSql(String sql, Object parameterObject, BoundSql boundSql) {
// 判断是否有like关键字
if (!isEscape(sql)) {
return;
}
sql = sql.replaceAll(" {2}", " ");
// 获取关键字的个数(去重)
Set<String> fields = this.getKeyFields(sql, boundSql);
if (fields == null) {
return;
}
// 此处可以增强,不止是支持Map对象,Map对象仅用于传入的条件为Map或者使用@Param传入的对象被Mybatis转为的Map
AbstractLikeSqlConverter converter;
// 对关键字进行特殊字符“清洗”,如果有特殊字符的,在特殊字符前添加转义字符(\)
if (parameterObject instanceof Map) {
converter = converterMap.get(Map.class);
} else {
converter = converterMap.get(Object.class);
}
converter.convert(sql, fields, parameterObject);
}

/**
* 是否需要转义
*
* @param sql SQL语句
* @return true/false
*/
private boolean isEscape(String sql) {
return this.hasLike(sql) && this.hasPlaceholder(sql);
}

/**
* 判断SQL语句中是否含有like关键字
*
* @param str SQL语句
* @return true/false
*/
private boolean hasLike(String str) {
if (StringUtils.isBlank(str)) {
return false;
}
return str.toLowerCase().contains(SQL_LIKE);
}

/**
* 判断SQL语句中是否包含SQL占位符
*
* @param str SQL语句
* @return true/false
*/
private boolean hasPlaceholder(String str) {
if (StringUtils.isBlank(str)) {
return false;
}
return str.toLowerCase().contains(SQL_PLACEHOLDER);
}

/**
* 获取需要替换的所有字段集合
*
* @param sql 完整SQL语句
* @param boundSql 绑定的SQL对象
* @return 字段集合列表
*/
private Set<String> getKeyFields(String sql, BoundSql boundSql) {
String[] params = sql.split(SQL_PLACEHOLDER_REGEX);
Set<String> fields = new HashSet<>();
for (int i = 0; i < params.length; i++) {
if (this.hasLike(params[i])) {
String field = boundSql.getParameterMappings().get(i).getProperty();
fields.add(field);
}
}
return fields;
}

}

+ 26
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/config/sql/ObjectLikeSqlConverter.java View File

@@ -0,0 +1,26 @@
package com.tuoheng.admin.config.sql;

import com.tuoheng.admin.config.sql.AbstractLikeSqlConverter;

/**
* 通用参数的转换器
*
* @author chenyukun
*/
public class ObjectLikeSqlConverter extends AbstractLikeSqlConverter<Object> {

@Override
public void transferWrapper(String field, Object parameter) {
// 尚未发现这种情况
}

@Override
public void transferSelf(String field, Object parameter) {
// 尚未发现这种情况
}

@Override
public void transferSplice(String field, Object parameter) {
this.resolveObj(field, parameter);
}
}

+ 26
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/constant/OidcUrlConstant.java View File

@@ -0,0 +1,26 @@
package com.tuoheng.admin.constant;

/**
* oidc认证平台常量url
* @Author xiaoying
* @Date 2022/10/18 10:52
*/
public class OidcUrlConstant {

/**
* 判断username是否已存在
*/
public static String USER_JUDGE = "/oidc/admin/user/judge/create/{username}";
/**
* 判断username是否已存在
*/
public static String USER_CREATE = "/oidc/admin/user/create";
/**
* 判断username是否已存在
*/
public static String USER_UPDATEPASS = "/oidc/admin/user/updatePass";
/**
* 修改用户角色
*/
public static String USER_UPDATEROLE = "/oidc/admin/user/updateRole";
}

+ 35
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/constant/UserConstant.java View File

@@ -0,0 +1,35 @@
package com.tuoheng.admin.constant;

import java.util.HashMap;
import java.util.Map;

/**
* <p>
* 用户管理 模块常量
* </p>
*
* @author 拓恒
* @since 2020-04-20
*/
public class UserConstant {

/**
* 性别
*/
public static Map<Integer, String> USER_GENDER_LIST = new HashMap<Integer, String>() {
{
put(1, "男");
put(2, "女");
put(3, "保密");
}
};
/**
* 状态
*/
public static Map<Integer, String> USER_STATUS_LIST = new HashMap<Integer, String>() {
{
put(1, "正常");
put(2, "禁用");
}
};
}

+ 63
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/controller/AliyunOssController.java View File

@@ -0,0 +1,63 @@
package com.tuoheng.admin.controller;

import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.tuoheng.admin.service.IAliyunOssService;
import com.tuoheng.admin.service.impl.AliyunOssServiceImpl;
import com.tuoheng.common.core.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.net.URL;
import java.util.List;

/**
* 阿里云对象存储OSS 前端控制器
*
* @author WangHaoran
* @since 2022-03-15
*/
@RestController
@RequestMapping("/aliyunOss")
public class AliyunOssController {

@Autowired
IAliyunOssService aliyunOssService;

/**
* 生成单个以GET方法访问的签名URL
*
* @param objectName 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
* @return
* @throws Throwable
*/
@GetMapping("/generatePresignedUrl")
public URL generatePresignedUrl(String objectName) throws Throwable {
return aliyunOssService.generatePresignedUrl(objectName);
}

/**
* 生成多个以GET方法访问的签名URL
*
* @param objectNameList 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
* 此处请填写多个Object完整路径,用于一次性获取多个Object的签名URL。
* @return
* @throws Throwable
*/
@GetMapping("/generatePresignedUrls")
public List<URL> generatePresignedUrls(String[] objectNameList) throws Throwable {
return aliyunOssService.generatePresignedUrls(objectNameList);
}

/**
* 获取securityToken
*
* @return
*/
@GetMapping("/getSecurityToken")
public JsonResult getSecurityToken() {
AssumeRoleResponse.Credentials credentials = AliyunOssServiceImpl.getSecurityToken("SessionTest");
return JsonResult.success(credentials);
}
}

+ 47
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/controller/AliyuncsVodController.java View File

@@ -0,0 +1,47 @@
package com.tuoheng.admin.controller;

import com.tuoheng.admin.service.IAliyuncsVodService;
import com.tuoheng.common.core.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* 阿里云点播服务 前端控制器
*
* @author WangHaoran
* @since 2022-03-10
*/
@RestController
@RequestMapping("/aliyuncsVod")
public class AliyuncsVodController {

@Autowired
IAliyuncsVodService aliyuncsVodService;


/**
* 获取音视频上传地址和凭证
*
* @param title
* @param fileName
* @return
*/
@GetMapping("/createUploadVideo")
public JsonResult createUploadVideo(String title, String fileName) {
return JsonResult.success(aliyuncsVodService.createUploadVideo(title, fileName));
}


/**
* 刷新音/视频上传凭证
*
* @param videoId 音频或视频ID
* @return
*/
@GetMapping("/refreshUploadVideo")
public JsonResult refreshUploadVideo(String videoId) {
return JsonResult.success(aliyuncsVodService.refreshUploadVideo(videoId));
}
}

+ 11
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/ClientRoleDto.java View File

@@ -0,0 +1,11 @@
package com.tuoheng.admin.dto;

import lombok.Data;

@Data
public class ClientRoleDto {

private String clientId;

private Integer roleId;
}

+ 16
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/ResetPwdDto.java View File

@@ -0,0 +1,16 @@
package com.tuoheng.admin.dto;

import lombok.Data;

/**
* 重置密码
*/
@Data
public class ResetPwdDto {

/**
* 用户ID
*/
private String id;

}

+ 21
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/UpdatePwdDto.java View File

@@ -0,0 +1,21 @@
package com.tuoheng.admin.dto;

import lombok.Data;

/**
* 修改密码Dto
*/
@Data
public class UpdatePwdDto {

/**
* 旧密码
*/
private String oldPassword;

/**
* 新密码
*/
private String newPassword;

}

+ 46
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/dto/UpdateUserInfoDto.java View File

@@ -0,0 +1,46 @@
package com.tuoheng.admin.dto;

import lombok.Data;

/**
* 更新个人资料
*/
@Data
public class UpdateUserInfoDto {

/**
* 个人头像
*/
private String avatar;

/**
* 真实姓名
*/
private String realname;

/**
* 昵称
*/
private String nickname;

/**
* 性别
*/
private String gender;

/**
* 手机号码
*/
private String mobile;

/**
* 个人简介
*/
private String intro;

/**
* 个性签名
*/
private String signature;

}

+ 51
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/entity/Role.java View File

@@ -0,0 +1,51 @@
package com.tuoheng.admin.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.tuoheng.common.core.common.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
* <p>
* 系统角色表
* </p>
*
* @author 拓恒
* @since 2020-10-31
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("th_role")
public class Role extends BaseEntity {

private static final long serialVersionUID = 1L;

/**
* 角色名称
*/
private String name;

/**
* 角色标签
*/
private String code;

/**
* 状态:1正常 2禁用
*/
private Integer status;

/**
* 备注
*/
private String note;

/**
* 排序
*/
private Integer sort;


}

+ 218
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/entity/User.java View File

@@ -0,0 +1,218 @@
package com.tuoheng.admin.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.util.Date;

/**
* <p>
* 后台用户管理表
* </p>
*
* @author 拓恒
* @since 2020-10-30
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("th_oauth_user")
public class User implements Serializable {

private static final long serialVersionUID = 1L;

/**
* 用户ID
*/
@TableId(value = "id", type = IdType.UUID)
private String id;

/**
* 用户编号
*/
private String code;

/**
* 真实姓名
*/
private String realname;

/**
* 昵称
*/
private String nickname;

/**
* 性别:1男 2女 3保密
*/
private Integer gender;

/**
* 头像
*/
private String avatar;

/**
* 手机号码
*/
private String mobile;

/**
* 邮箱地址
*/
private String email;

/**
* 出生日期
*/
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date birthday;

/**
* 部门ID
*/
private String deptId;

/**
* 省份编码
*/
private String provinceCode;

/**
* 城市编码
*/
private String cityCode;

/**
* 区县编码
*/
private String districtCode;
/**
* 街道编码
*/
private String streetCode;
/**
* 详细地址
*/
private String address;

/**
* 所属城市
*/
private String cityName;

/**
* 登录用户名
*/
private String username;

/**
* 登录密码
*/
private String password;

/**
* 用户类型:1管理员
*/
private Integer type;

/**
* 驾照类型:1飞行执照 2飞行许可证
*/
private Integer driverType;

/**
* 驾照编号
*/
private String driverCode;

/**
* 盐加密
*/
private String salt;

/**
* 个人简介
*/
private String intro;

/**
* 状态:1正常 2禁用
*/
private Integer status;

/**
* 备注
*/
private String note;

/**
* 显示顺序
*/
private Integer sort;

/**
* 登录次数
*/
private Integer loginNum;

/**
* 最近登录IP
*/
private String loginIp;

/**
* 最近登录时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date loginTime;

/**
* 添加人
*/
private String createUser;

/**
* 创建时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;

/**
* 更新人
*/
private String updateUser;

/**
* 更新时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;

/**
* 有效标识
*/
private Integer mark;

/**
* 角色ID
*/
@TableField(exist = false)
private String[] roleIds;

/**
* 城市集合
*/
@TableField(exist = false)
private String[] city;

}

+ 37
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/entity/UserRole.java View File

@@ -0,0 +1,37 @@
package com.tuoheng.admin.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.tuoheng.common.core.common.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
* <p>
* 人员角色表
* </p>
*
* @author 拓恒
* @since 2020-10-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("th_user_role")
public class UserRole extends BaseEntity {

private static final long serialVersionUID = 1L;


/**
* 人员ID
*/
private String userId;

/**
* 角色ID
*/
private String roleId;


}

+ 65
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/interceptor/UserInterceptor.java View File

@@ -0,0 +1,65 @@


package com.tuoheng.admin.interceptor;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tuoheng.admin.entity.User;
import com.tuoheng.admin.service.IUserService;
import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.utils.SecurityUserUtils;
import com.tuoheng.common.core.utils.StringUtils;
import com.tuoheng.common.core.utils.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
public class UserInterceptor implements HandlerInterceptor {

@Autowired
private IUserService userService;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("开始执行过滤器");
String username = SecurityUserUtils.username();

if (StringUtils.isEmpty(username)) {
throw new ServiceException(HttpStatus.BAD_REQUEST.value(),"username不能为空");
}

if(userService==null){
log.info("userService is null!!!");
BeanFactory factory = WebApplicationContextUtils
.getRequiredWebApplicationContext(request.getServletContext());
userService = (IUserService) factory
.getBean("UserServiceImpl");
}
User user = userService.getOne(Wrappers.<User>lambdaQuery()
.eq(User::getMark, 1)
.eq(User::getStatus, 1)
.eq(StringUtils.isNotEmpty(username), User::getUsername, username));
if (StringUtils.isNull(user)) {
log.error("用户信息不存在:{}", user);
return false;
}
ThreadLocalUtil.set(user);
log.info("执行完毕");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//结束方法清理内存
ThreadLocalUtil.remove();
log.info("清理ThreadLocal内存完毕");
}
}


+ 16
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/mapper/UserMapper.java View File

@@ -0,0 +1,16 @@
package com.tuoheng.admin.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tuoheng.admin.entity.User;

/**
* <p>
* 后台用户管理表 Mapper 接口
* </p>
*
* @author 拓恒
* @since 2020-10-30
*/
public interface UserMapper extends BaseMapper<User> {

}

+ 37
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/mapper/UserRoleMapper.java View File

@@ -0,0 +1,37 @@
package com.tuoheng.admin.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tuoheng.admin.entity.Role;
import com.tuoheng.admin.entity.UserRole;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
* <p>
* 人员角色表 Mapper 接口
* </p>
*
* @author 拓恒
* @since 2020-10-30
*/
public interface UserRoleMapper extends BaseMapper<UserRole> {

/**
* 根据用户ID获取角色
*
* @param userId 用户ID
* @return
*/
List<Role> getRolesByUserId(String userId);

/**
* 根据角色获取用户ID
*
*
* @param roleId 角色ID
* @return
*/
List<String> getUsersByURoleId(@Param("roleId") String roleId);

}

+ 47
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/query/UserQuery.java View File

@@ -0,0 +1,47 @@
package com.tuoheng.admin.query;

import com.tuoheng.common.core.common.BaseQuery;
import lombok.Data;

/**
* 用户查询条件
*/
@Data
public class UserQuery extends BaseQuery {

/**
* 用户账号
*/
private String username;

/**
* 真实姓名
*/
private String realname;

/**
* 性别:1男 2女 3保密
*/
private Integer gender;

/**
* 终端 1 web端 2 小程序端
*/
private Integer terminalType;

/**
* 用户类型
*/
private Integer type;

/**
* 用户状态:1在用 2停用
*/
private Integer status;

/**
* 角色ID
*/
private String roleId;

}

+ 16
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/request/OidcCreateUserRequest.java View File

@@ -0,0 +1,16 @@
package com.tuoheng.admin.request;

import com.tuoheng.admin.dto.ClientRoleDto;
import lombok.Data;

import java.util.List;

@Data
public class OidcCreateUserRequest {

private String username;

private String password;

private List<ClientRoleDto> clientRoleDtoList;
}

+ 24
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/request/OidcUpdateUserRequest.java View File

@@ -0,0 +1,24 @@
package com.tuoheng.admin.request;

import com.tuoheng.admin.dto.ClientRoleDto;
import lombok.Data;

import java.util.List;

/**
* @Author xiaoying
* @Date 2022/10/31 10:17
*/
@Data
public class OidcUpdateUserRequest {
/**
* 用户名
*/
private String username;
/**
* 客户端以及对应的权限
*/
private List<ClientRoleDto> clientRoleDtoList;


}

+ 0
- 0
tuoheng-service/tuoheng-admin/src/main/java/com/tuoheng/admin/service/IAliyunOssService.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save