Browse Source

签入版本

master
zongjl 2 years ago
parent
commit
bd1c0dacb1
100 changed files with 11529 additions and 0 deletions
  1. +40
    -0
      .gitignore
  2. +76
    -0
      pom.xml
  3. +219
    -0
      tuoheng-admin/pom.xml
  4. +19
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/AdminApplication.java
  5. +69
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/controller/TenantController.java
  6. +101
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/dto/TenantDto.java
  7. +108
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/entity/Tenant.java
  8. +16
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/mapper/TenantMapper.java
  9. +17
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/query/TenantQuery.java
  10. +45
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/service/ITenantService.java
  11. +190
    -0
      tuoheng-admin/src/main/java/com/tuoheng/admin/service/impl/TenantServiceImpl.java
  12. +156
    -0
      tuoheng-admin/src/main/resources/application-dev.yml
  13. +155
    -0
      tuoheng-admin/src/main/resources/application-local.yml
  14. +156
    -0
      tuoheng-admin/src/main/resources/application-prod.yml
  15. +155
    -0
      tuoheng-admin/src/main/resources/application-test.yml
  16. +25
    -0
      tuoheng-admin/src/main/resources/application.yml
  17. +4
    -0
      tuoheng-admin/src/main/resources/log4j.properties
  18. +32
    -0
      tuoheng-admin/src/main/resources/logback.xml
  19. +5
    -0
      tuoheng-admin/src/main/resources/mapper/TenantMapper.xml
  20. +47
    -0
      tuoheng-admin/src/main/resources/redis.properties
  21. BIN
      tuoheng-admin/src/main/resources/template/ExportReport.docx
  22. +162
    -0
      tuoheng-common/pom.xml
  23. +112
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/annotation/Excel.java
  24. +18
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/annotation/Excels.java
  25. +36
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/annotation/Log.java
  26. +4
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/BaseController.java
  27. +56
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/BaseEntity.java
  28. +19
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/BaseQuery.java
  29. +37
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/BaseResponse.java
  30. +188
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/BaseServiceImpl.java
  31. +23
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/ExceptionInterface.java
  32. +100
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/IBaseService.java
  33. +52
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/OperationEnum.java
  34. +96
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/common/SysExceptionEnum.java
  35. +26
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/CommonConfig.java
  36. +40
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/I18nConfig.java
  37. +26
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/MybatisPlusConfig.java
  38. +49
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/QrImage.java
  39. +154
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/RedisConfig.java
  40. +58
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/ThreadPoolConfig.java
  41. +40
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/UploadFileConfig.java
  42. +83
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/config/WebMvcConfig.java
  43. +103
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/constant/CommonConstants.java
  44. +49
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/constant/Constant.java
  45. +30
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/constant/RedisConstant.java
  46. +50
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/controller/CommonController.java
  47. +52
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/controller/UploadController.java
  48. +18
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/enums/LogStatus.java
  49. +68
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/enums/LogType.java
  50. +23
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/enums/OperType.java
  51. +84
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/exception/BaseException.java
  52. +37
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/exception/CustomException.java
  53. +39
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/exception/ExceptionConstantEnum.java
  54. +39
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/exception/ServiceException.java
  55. +14
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/exception/user/CaptchaException.java
  56. +16
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/exception/user/UserException.java
  57. +14
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/exception/user/UserNotExistsException.java
  58. +35
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/service/IUploadService.java
  59. +66
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/service/impl/UploadServiceImpl.java
  60. +266
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/CommonUtils.java
  61. +850
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/ConvertUtil.java
  62. +152
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/DateUtils.java
  63. +695
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/ExcelUtils.java
  64. +193
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/FileUtils.java
  65. +244
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/HttpUtils.java
  66. +294
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/IpUtils.java
  67. +97
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/JsonResult.java
  68. +15
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/LogUtils.java
  69. +23
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/MessageUtils.java
  70. +608
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/RedisUtils.java
  71. +320
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/ReflectUtils.java
  72. +118
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/ServletUtils.java
  73. +102
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/SpringUtils.java
  74. +387
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/StringUtils.java
  75. +73
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/ThreadUtils.java
  76. +323
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/UploadUtils.java
  77. +186
    -0
      tuoheng-common/src/main/java/com/tuoheng/common/utils/VerifyUtil.java
  78. +36
    -0
      tuoheng-common/src/main/resources/i18n/messages.properties
  79. +54
    -0
      tuoheng-generator/pom.xml
  80. +78
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/config/GenConfig.java
  81. +147
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/constant/GenConstants.java
  82. +20
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/controller/GenTableColumnController.java
  83. +128
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/controller/GenTableController.java
  84. +16
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/dto/GenTableDto.java
  85. +153
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/entity/GenTable.java
  86. +148
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/entity/GenTableColumn.java
  87. +50
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/mapper/GenTableColumnMapper.java
  88. +80
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/mapper/GenTableMapper.java
  89. +31
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/query/GenTableQuery.java
  90. +26
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/service/IGenTableColumnService.java
  91. +90
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/service/IGenTableService.java
  92. +37
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/service/impl/GenTableColumnServiceImpl.java
  93. +227
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/service/impl/GenTableServiceImpl.java
  94. +916
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/utils/CodeGenerateUtils.java
  95. +140
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/utils/CodeGenerator.java
  96. +89
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/utils/ColumnClass.java
  97. +41
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/utils/FreeMarkerUtils.java
  98. +209
    -0
      tuoheng-generator/src/main/java/com/tuoheng/generator/utils/GenUtils.java
  99. +116
    -0
      tuoheng-generator/src/main/resources/mapper/GenTableColumnMapper.xml
  100. +0
    -0
      tuoheng-generator/src/main/resources/mapper/GenTableMapper.xml

+ 40
- 0
.gitignore View File

@@ -0,0 +1,40 @@
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/

/.idea
/.vscode
/.svn
tuoheng-ui
target/
HELP.md

+ 76
- 0
pom.xml View File

@@ -0,0 +1,76 @@
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>com.tuoheng</groupId>
<artifactId>tuoheng</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--父模块打包类型必须为pom-->
<packaging>pom</packaging>
<name>tuoheng</name>
<description>Demo project for Spring Boot</description>

<!-- 子模块依赖 -->
<modules>
<module>tuoheng-common</module>
<module>tuoheng-generator</module>
<module>tuoheng-system</module>
<module>tuoheng-admin</module>
</modules>

<properties>
<java.version>1.8</java.version>
<!-- 表示打包时跳过mvn test -->
<maven.test.skip>true</maven.test.skip>
<!--全局配置项目版本号-->
<version>0.0.1-SNAPSHOT</version>
</properties>

<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- 子模块依赖 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-common</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-generator</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-system</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-admin</artifactId>
<version>${version}</version>
</dependency>

<!-- 第三方依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
</dependencyManagement>

</project>

+ 219
- 0
tuoheng-admin/pom.xml View File

@@ -0,0 +1,219 @@
<?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要使用顶层的父模块-->
<parent>
<artifactId>tuoheng</artifactId>
<groupId>com.tuoheng</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-admin</artifactId>
<packaging>jar</packaging>
<name>tuoheng-admin</name>
<description>Demo project for Spring Boot</description>



<!-- 依赖声明 -->
<dependencies>
<!-- 核心模块 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-system</artifactId>
</dependency>
<!-- 代码生成 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-generator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 引入阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.15.Final</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-amqp -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>[0.4, 0.5)</version>
</dependency>

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.1</version>
</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-5gbox</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
<include>**/*.yml</include>
</includes>
</resource>

<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.docx</include>
</includes>
</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.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>

</project>

+ 19
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/AdminApplication.java View File

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

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//排除原有的Multipart配置
@SpringBootApplication(scanBasePackages = {"com.tuoheng.*"}, exclude = {MultipartAutoConfiguration.class})
@MapperScan("com.tuoheng.**.mapper")
@EnableTransactionManagement
public class AdminApplication {

public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}

}

+ 69
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/controller/TenantController.java View File

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

import com.tuoheng.admin.dto.TenantDto;
import com.tuoheng.admin.query.TenantQuery;
import com.tuoheng.admin.service.ITenantService;
import com.tuoheng.common.common.BaseController;
import com.tuoheng.common.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
* <p>
* 企业管理表 前端控制器
* </p>
*
* @author 拓恒
* @since 2022-07-15
*/
@RestController
@RequestMapping("/tenant")
public class TenantController extends BaseController {
@Autowired
private ITenantService tenantService;

/**
* 获取职级列表
*
* @param levelQuery 查询条件
* @return
*/
@GetMapping("/index")
public JsonResult index(TenantQuery levelQuery) {
return tenantService.getTenantList(levelQuery);
}

/**
* 添加职级
*
* @param tenantDto 实体对象
* @return
*/
@PostMapping("/add")
public JsonResult add(@RequestBody TenantDto tenantDto) {
return tenantService.addTenant(tenantDto);
}

/**
* 编辑职级
*
* @param tenantDto 实体对象
* @return
*/
@PutMapping("/edit")
public JsonResult edit(@RequestBody TenantDto tenantDto) {

return tenantService.editTenant(tenantDto);
}

/**
* 删除职级
*
* @param tenantIds 职级ID
* @return
*/
@DeleteMapping("/delete/{tenantIds}")
public JsonResult delete(@PathVariable("tenantIds") Integer[] tenantIds) {
return tenantService.deleteByIds(tenantIds);
}
}

+ 101
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/dto/TenantDto.java View File

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

import lombok.Data;

/**
* 租户Dto
*/
@Data
public class TenantDto {

/**
* 租户ID
*/
private Integer id;

/**
* 租户名称
*/
private String name;

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

/**
* 租户LOGO
*/
private String logo;

/**
* 上级ID
*/
private Integer pid;

/**
* 租户类型:1政府 2企业 3组织
*/
private Integer type;

/**
* 租户电话
*/
private String phone;

/**
* 租户邮箱
*/
private String email;

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

/**
* 市区编号
*/
private String cityCode;

/**
* 区县编号
*/
private String districtCode;

/**
* 详细地址
*/
private String address;

/**
* 租户简介
*/
private String intro;

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

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

/**
* 排序号
*/
private Integer sort;

/**
* 登录账号
*/
private String username;

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

}

+ 108
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/entity/Tenant.java View File

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

import com.baomidou.mybatisplus.annotation.TableName;

import java.time.LocalDateTime;

import com.tuoheng.common.common.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
* <p>
* 企业管理表
* </p>
*
* @author 拓恒
* @since 2022-07-25
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("th_tenant")
public class Tenant extends BaseEntity {

private static final long serialVersionUID = 1L;

/**
* 租户名称
*/
private String name;

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

/**
* 租户LOGO
*/
private String logo;

/**
* 上级ID
*/
private Integer pid;

/**
* 租户类型:1政府 2企业 3组织
*/
private Integer type;

/**
* 租户电话
*/
private String phone;

/**
* 租户邮箱
*/
private String email;

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

/**
* 市区编号
*/
private String cityCode;

/**
* 区县编号
*/
private String districtCode;

/**
* 详细地址
*/
private String address;

/**
* 租户简介
*/
private String intro;

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

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

/**
* 排序号
*/
private Integer sort;

/**
* 租户超管账号
*/
private String username;

}

+ 16
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/mapper/TenantMapper.java View File

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

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tuoheng.admin.entity.Tenant;

/**
* <p>
* 企业管理表 Mapper 接口
* </p>
*
* @author 拓恒
* @since 2022-07-15
*/
public interface TenantMapper extends BaseMapper<Tenant> {

}

+ 17
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/query/TenantQuery.java View File

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

import com.tuoheng.common.common.BaseQuery;
import lombok.Data;

/**
* 租户查询条件
*/
@Data
public class TenantQuery extends BaseQuery {

/**
* 租户名称
*/
private String name;

}

+ 45
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/service/ITenantService.java View File

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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tuoheng.admin.dto.TenantDto;
import com.tuoheng.admin.entity.Tenant;
import com.tuoheng.admin.query.TenantQuery;
import com.tuoheng.common.common.IBaseService;
import com.tuoheng.common.utils.JsonResult;

/**
* <p>
* 企业管理表 服务类
* </p>
*
* @author 拓恒
* @since 2022-07-15
*/
public interface ITenantService extends IBaseService<Tenant> {

/**
* 获取租户分页列表
*
* @param tenantQuery 查询条件
* @return
*/
JsonResult getTenantList(TenantQuery tenantQuery);

/**
* 添加租户
*
* @param tenantDto 实体对象
* @return
*/
JsonResult addTenant(TenantDto tenantDto);

/**
* 更新租户
*
* @param tenantDto 实体对象
* @return
*/
JsonResult editTenant(TenantDto tenantDto);


}

+ 190
- 0
tuoheng-admin/src/main/java/com/tuoheng/admin/service/impl/TenantServiceImpl.java View File

@@ -0,0 +1,190 @@
package com.tuoheng.admin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tuoheng.admin.dto.TenantDto;
import com.tuoheng.admin.entity.Tenant;
import com.tuoheng.admin.mapper.TenantMapper;
import com.tuoheng.admin.query.TenantQuery;
import com.tuoheng.admin.service.ITenantService;
import com.tuoheng.common.common.BaseServiceImpl;
import com.tuoheng.common.config.CommonConfig;
import com.tuoheng.common.utils.*;
import com.tuoheng.system.entity.User;
import com.tuoheng.system.mapper.UserMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
* <p>
* 企业管理表 服务实现类
* </p>
*
* @author 拓恒
* @since 2022-07-15
*/
@Service
public class TenantServiceImpl extends BaseServiceImpl<TenantMapper, Tenant> implements ITenantService {

@Autowired
private TenantMapper tenantMapper;
@Autowired
private UserMapper userMapper;

/**
* 获取租户列表
*
* @param tenantQuery 查询条件
* @return
*/
@Override
public JsonResult getTenantList(TenantQuery tenantQuery) {
// 查询条件
QueryWrapper<Tenant> queryWrapper = new QueryWrapper<>();
// 租户名称
if (!StringUtils.isEmpty(tenantQuery.getName())) {
queryWrapper.like("name", tenantQuery.getName());
}
queryWrapper.eq("mark", 1);
queryWrapper.orderByAsc("sort");

// 查询分页数据
IPage<Tenant> page = new Page<>(tenantQuery.getPage(), tenantQuery.getLimit());
IPage<Tenant> pageData = tenantMapper.selectPage(page, queryWrapper);
pageData.convert(x -> {
// 租户Logo
if (!StringUtils.isEmpty(x.getLogo())) {
x.setLogo(CommonUtils.getImageURL(x.getLogo()));
}
return x;
});
return JsonResult.success(pageData);
}

/**
* 添加租户
*
* @param tenantDto 实体对象
* @return
*/
@Override
public JsonResult addTenant(TenantDto tenantDto) {
// 验证租户是否已存在
Integer count = tenantMapper.selectCount(new LambdaQueryWrapper<Tenant>()
.eq(Tenant::getCode, tenantDto.getCode())
.eq(Tenant::getMark, 1));
if (count > 0) {
return JsonResult.error("系统中已经存在相同的租户编码");
}
// 参数转换
Tenant tenant = new Tenant();
BeanUtils.copyProperties(tenantDto, tenant);
// 租户头像
if (StringUtils.isNotNull(tenantDto.getLogo()) && tenantDto.getLogo().contains(CommonConfig.imageURL)) {
tenant.setLogo(tenantDto.getLogo().replaceAll(CommonConfig.imageURL, ""));
}
// 新建租户数据
int count2 = tenantMapper.insert(tenant);
if (count2 == 0) {
return JsonResult.error("租户创建失败");
}

// 创建租户账号
Map<String, String> accountMap = new HashMap<>();
accountMap.put("tenant_id", tenant.getId().toString());
accountMap.put("tenant_name", tenant.getName());
accountMap.put("username", tenantDto.getUsername());
accountMap.put("password", tenantDto.getPassword());
// 添加
accountMap.put("type", "1");

// 调用网络请求处理租户账号信息
String result = handleTenantAccount(accountMap);
if (!result.equals("SUCCESS")) {
return JsonResult.error(result);
}
return JsonResult.success();
}

/**
* 更新
*
* @param tenantDto 实体对象
* @return
*/
@Override
public JsonResult editTenant(TenantDto tenantDto) {
// 查询租户信息
Tenant tenant = tenantMapper.selectById(tenantDto.getId());
if (StringUtils.isNull(tenant)) {
return JsonResult.error("租户信息不存在");
}
// 验证账号
Integer count = tenantMapper.selectCount(new LambdaQueryWrapper<Tenant>()
.ne(Tenant::getId, tenant.getId())
.eq(Tenant::getCode, tenantDto.getCode())
.eq(Tenant::getMark, 1));
if (count > 0) {
return JsonResult.error("系统中已经存在相同的租户编码");
}
BeanUtils.copyProperties(tenantDto, tenant);
// 租户头像
if (StringUtils.isNotNull(tenantDto.getLogo()) && tenantDto.getLogo().contains(CommonConfig.imageURL)) {
tenant.setLogo(tenantDto.getLogo().replaceAll(CommonConfig.imageURL, ""));
}
// 更新租户信息
int count2 = tenantMapper.updateById(tenant);
if (count2 == 0) {
return JsonResult.error("更新租户信息失败");
}

// 更新租户账号
Map<String, String> accountMap = new HashMap<>();
accountMap.put("tenant_id", tenant.getId().toString());
accountMap.put("tenant_name", tenant.getName());
accountMap.put("username", tenantDto.getUsername());
accountMap.put("password", tenantDto.getPassword());
// 更新
accountMap.put("type", "2");

// 调用网络请求处理租户账号信息
String result = handleTenantAccount(accountMap);
if (!result.equals("SUCCESS")) {
return JsonResult.error(result);
}
return JsonResult.success();
}

/**
* 处理租户账号
*
* @param accountMap 账号信息
* @return
*/
private String handleTenantAccount(Map<String, String> accountMap) {
// 参数转换
JSONObject jsonParam = new JSONObject();
CommonUtils.toJsonObject(accountMap, jsonParam);
JSONObject jsonObject = null;
// 结果
String result = "";
try {
// 调用远程API接口
String data = HttpUtils.send("https://hhz.t-aaron.com/api/tenant/account", jsonParam, "UTF-8");
jsonObject = JSONObject.parseObject(data);
// 结果值
result = jsonObject.getString("result");
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}

+ 156
- 0
tuoheng-admin/src/main/resources/application-dev.yml View File

@@ -0,0 +1,156 @@
# 端口配置
server:
port: 9057
servlet:
# 项目的前缀名
context-path: /api

# 自定义配置
tuoheng:
# 图片域名
image-url: http://images.5gbox.yunhengwang.net/

spring:
# 配置数据源
datasource:
# 使用阿里的Druid连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# 填写你数据库的url、登录名、密码和数据库名
url: jdbc:mysql://192.168.11.11:3306/tuoheng_hhz_tenant?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=true&tinyInt1isBit=false
username: root
password: idontcare
druid:
# 连接池的配置信息
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 5
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
# 配置DruidStatFilter
webStatFilter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
# 配置DruidStatViewServlet
statViewServlet:
url-pattern: "/druid/*"
# IP白名单(没有配置或者为空,则允许所有访问)
allow: 127.0.0.1,192.168.163.1
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.1.73
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: admin
# 登录密码
login-password: 123456

# Redis数据源
redis:
# 缓存库默认索引0
database: 0
# Redis服务器地址
host: 192.168.11.11
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 6000
# 默认的数据过期时间,主要用于shiro权限管理
expire: 2592000
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 1 # 连接池中的最小空闲连接

servlet:
multipart:
# 过滤springmvc的文件上传
enabled: false
# 单个文件最大值
max-file-size: 50MB
# 上传文件总的最大值
max-request-size: 100MB

file:
#上传的服务器上的映射文件夹
accessPath: /uploads/
#静态资源对外暴露的访问路径
staticAccessPath: /**
#静态资源实际存储路径
uploadFolder: /data/java/tuoheng_hhz_tenant/uploads/

# Shiro
shiro:
cipher-key: f/SX5TIve5WWzT4aQlABJA==
cookie-name: shiro-cookie2
user:
# 登录地址
loginUrl: /login
# 权限认证失败地址
unauthorizedUrl: /unauth
# 首页地址
indexUrl: /index
# 验证码开关
captchaEnabled: true
# 验证码类型 math 数组计算 char 字符
captchaType: math
cookie:
# 设置Cookie的域名 默认空,即当前访问的域名
domain:
# 设置cookie的有效访问路径
path: /
# 设置HttpOnly属性
httpOnly: true
# 设置Cookie的过期时间,天为单位
maxAge: 30
session:
# Session超时时间(默认30分钟)
expireTime: 300
# 同步session到数据库的周期(默认1分钟)
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性,默认就是10分钟
validationInterval: 10

# 代码生成
generate:
# 作者
author: 拓恒
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: com.tuoheng.system
# 模块名
moduleName: tuoheng-system
# 自动去除表前缀,默认是true
autoRemovePre: true
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: sys_


# 日志记录
logging:
config: classpath:logback.xml

+ 155
- 0
tuoheng-admin/src/main/resources/application-local.yml View File

@@ -0,0 +1,155 @@
# 端口配置
server:
port: 9057
servlet:
# 项目的前缀名
context-path: /api

# 自定义配置
tuoheng:
# 图片域名
image-url: http://localhost:9057/api/

spring:
# 配置数据源
datasource:
# 使用阿里的Druid连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# 填写你数据库的url、登录名、密码和数据库名
url: jdbc:mysql://127.0.0.1:3306/tuoheng_hhz_tenant?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=true&tinyInt1isBit=false
username: root
password:
druid:
# 连接池的配置信息
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 5
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
# 配置DruidStatFilter
webStatFilter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
# 配置DruidStatViewServlet
statViewServlet:
url-pattern: "/druid/*"
# IP白名单(没有配置或者为空,则允许所有访问)
allow: 127.0.0.1,192.168.163.1
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.1.73
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: admin
# 登录密码
login-password: 123456

# Redis数据源
redis:
# 缓存库默认索引0
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 6000
# 默认的数据过期时间,主要用于shiro权限管理
expire: 2592000
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 1 # 连接池中的最小空闲连接

servlet:
multipart:
# 过滤springmvc的文件上传
enabled: false
# 单个文件最大值
max-file-size: 50MB
# 上传文件总的最大值
max-request-size: 100MB

file:
#上传的服务器上的映射文件夹
accessPath: /uploads/
#静态资源对外暴露的访问路径
staticAccessPath: /**
#静态资源实际存储路径
uploadFolder: E:\Gitea仓库源码\tuoheng_hhz_tenant\uploads\

# Shiro
shiro:
cipher-key: f/SX5TIve5WWzT4aQlABJA==
cookie-name: shiro-cookie2
user:
# 登录地址
loginUrl: /login
# 权限认证失败地址
unauthorizedUrl: /unauth
# 首页地址
indexUrl: /index
# 验证码开关
captchaEnabled: true
# 验证码类型 math 数组计算 char 字符
captchaType: math
cookie:
# 设置Cookie的域名 默认空,即当前访问的域名
domain:
# 设置cookie的有效访问路径
path: /
# 设置HttpOnly属性
httpOnly: true
# 设置Cookie的过期时间,天为单位
maxAge: 30
session:
# Session超时时间(默认30分钟)
expireTime: 300
# 同步session到数据库的周期(默认1分钟)
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性,默认就是10分钟
validationInterval: 10

# 代码生成
generate:
# 作者
author: 拓恒
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: com.tuoheng.admin
# 模块名
moduleName: tuoheng-admin
# 自动去除表前缀,默认是true
autoRemovePre: true
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: th_

# 日志记录
logging:
config: classpath:logback.xml

+ 156
- 0
tuoheng-admin/src/main/resources/application-prod.yml View File

@@ -0,0 +1,156 @@
# 端口配置
server:
port: 9057
servlet:
# 项目的前缀名
context-path: /api

# 自定义配置
tuoheng:
# 图片域名
image-url: http://images.5gbox.taauav.com/

spring:
# 配置数据源
datasource:
# 使用阿里的Druid连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# 填写你数据库的url、登录名、密码和数据库名
url: jdbc:mysql://rm-uf6x76i111rb1eo48.mysql.rds.aliyuncs.com:3306/tuoheng_hhz_tenant?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=true&tinyInt1isBit=false
username: root
password: TH22#2022
druid:
# 连接池的配置信息
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 5
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
# 配置DruidStatFilter
webStatFilter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
# 配置DruidStatViewServlet
statViewServlet:
url-pattern: "/druid/*"
# IP白名单(没有配置或者为空,则允许所有访问)
allow: 127.0.0.1,192.168.163.1
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.1.73
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: admin
# 登录密码
login-password: 123456

# Redis数据源
redis:
# 缓存库默认索引0
database: 0
# Redis服务器地址
host: r-uf6r5lm7c7sfdv3ehb.redis.rds.aliyuncs.com
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 6000
# 默认的数据过期时间,主要用于shiro权限管理
expire: 2592000
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 1 # 连接池中的最小空闲连接

servlet:
multipart:
# 过滤springmvc的文件上传
enabled: false
# 单个文件最大值
max-file-size: 50MB
# 上传文件总的最大值
max-request-size: 100MB

file:
#上传的服务器上的映射文件夹
accessPath: /uploads/
#静态资源对外暴露的访问路径
staticAccessPath: /**
#静态资源实际存储路径
uploadFolder: /data/java/tuoheng_hhz_tenant/uploads/

# Shiro
shiro:
cipher-key: f/SX5TIve5WWzT4aQlABJA==
cookie-name: shiro-cookie2
user:
# 登录地址
loginUrl: /login
# 权限认证失败地址
unauthorizedUrl: /unauth
# 首页地址
indexUrl: /index
# 验证码开关
captchaEnabled: true
# 验证码类型 math 数组计算 char 字符
captchaType: math
cookie:
# 设置Cookie的域名 默认空,即当前访问的域名
domain:
# 设置cookie的有效访问路径
path: /
# 设置HttpOnly属性
httpOnly: true
# 设置Cookie的过期时间,天为单位
maxAge: 30
session:
# Session超时时间(默认30分钟)
expireTime: 300
# 同步session到数据库的周期(默认1分钟)
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性,默认就是10分钟
validationInterval: 10

# 代码生成
generate:
# 作者
author: 拓恒
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: com.tuoheng.system
# 模块名
moduleName: tuoheng-system
# 自动去除表前缀,默认是true
autoRemovePre: true
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: sys_


# 日志记录
logging:
config: classpath:logback.xml

+ 155
- 0
tuoheng-admin/src/main/resources/application-test.yml View File

@@ -0,0 +1,155 @@
# 端口配置
server:
port: 9057
servlet:
# 项目的前缀名
context-path: /api

# 自定义配置
tuoheng:
# 图片域名
image-url: http://images.5gbox.yunhengzhizao.cn/

spring:
# 配置数据源
datasource:
# 使用阿里的Druid连接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# 填写你数据库的url、登录名、密码和数据库名
url: jdbc:mysql://192.168.11.242:3306/tuoheng_hhz_tenant?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=true&tinyInt1isBit=false
username: root
password: idontcare
druid:
# 连接池的配置信息
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 5
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
# 配置DruidStatFilter
webStatFilter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
# 配置DruidStatViewServlet
statViewServlet:
url-pattern: "/druid/*"
# IP白名单(没有配置或者为空,则允许所有访问)
allow: 127.0.0.1,192.168.163.1
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.1.73
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: admin
# 登录密码
login-password: 123456

# Redis数据源
redis:
# 缓存库默认索引0
database: 0
# Redis服务器地址
host: 192.168.11.242
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 6000
# 默认的数据过期时间,主要用于shiro权限管理
expire: 2592000
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 1 # 连接池中的最小空闲连接

servlet:
multipart:
# 过滤springmvc的文件上传
enabled: false
# 单个文件最大值
max-file-size: 50MB
# 上传文件总的最大值
max-request-size: 100MB

file:
#上传的服务器上的映射文件夹
accessPath: /uploads/
#静态资源对外暴露的访问路径
staticAccessPath: /**
#静态资源实际存储路径
uploadFolder: /data/java/tuoheng_hhz_tenant/uploads/

# Shiro
shiro:
cipher-key: f/SX5TIve5WWzT4aQlABJA==
cookie-name: shiro-cookie2
user:
# 登录地址
loginUrl: /login
# 权限认证失败地址
unauthorizedUrl: /unauth
# 首页地址
indexUrl: /index
# 验证码开关
captchaEnabled: true
# 验证码类型 math 数组计算 char 字符
captchaType: math
cookie:
# 设置Cookie的域名 默认空,即当前访问的域名
domain:
# 设置cookie的有效访问路径
path: /
# 设置HttpOnly属性
httpOnly: true
# 设置Cookie的过期时间,天为单位
maxAge: 30
session:
# Session超时时间(默认30分钟)
expireTime: 300
# 同步session到数据库的周期(默认1分钟)
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性,默认就是10分钟
validationInterval: 10

# 代码生成
generate:
# 作者
author: 拓恒
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: com.tuoheng.system
# 模块名
moduleName: tuoheng-system
# 自动去除表前缀,默认是true
autoRemovePre: true
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: sys_

# 日志记录
logging:
config: classpath:logback.xml

+ 25
- 0
tuoheng-admin/src/main/resources/application.yml View File

@@ -0,0 +1,25 @@
spring:
profiles:
active: @package.environment@

# 服务模块
devtools:
restart:
# 热部署开关
enabled: false

# 自定义国际化配置
messages:
# 国际化资源文件路径
basename: i18n/messages
encoding: UTF-8

# MyBatis
mybatis-plus:
mapper-locations: classpath*:mapper/*Mapper.xml
# 实体扫描,多个package用逗号或者分号分隔
type-aliases-package: com.tuoheng.**.mapper
configuration:
map-underscore-to-camel-case: true
use-generated-keys: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

+ 4
- 0
tuoheng-admin/src/main/resources/log4j.properties View File

@@ -0,0 +1,4 @@
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

+ 32
- 0
tuoheng-admin/src/main/resources/logback.xml View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/data/java/logs/tuoheng_5gbox/tuoheng_5gbox.log</file>
<!-- <file>/Users/zhuzs/Documents/file/logs/tuoheng_5gai.log</file>-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- <fileNamePattern>/Users/zhuzs/Documents/file/logs/tuoheng_5gai.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
<fileNamePattern>/data/java/logs/tuoheng_5gbox/tuoheng_5gbox.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- project default level -->
<logger name="com.tuoheng" level="DEBUG" />

<!--log4jdbc -->
<logger name="jdbc.sqltiming" level="DEBUG"/>

<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="rollingFile" />
</root>
</configuration>

+ 5
- 0
tuoheng-admin/src/main/resources/mapper/TenantMapper.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tuoheng.admin.mapper.TenantMapper">

</mapper>

+ 47
- 0
tuoheng-admin/src/main/resources/redis.properties View File

@@ -0,0 +1,47 @@
#Matser的ip地址
redis.host=127.0.0.1
#端口号
redis.port=6379
#如果有密码
redis.password=
#客户端超时时间单位是毫秒 默认是2000
redis.timeout=10000

# 连接池最大连接数(使用负值表示没有限制) 默认 8
redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
redis.lettuce.pool.min-idle=0

#最大空闲数
redis.maxIdle=300
#连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
#redis.maxActive=600
#控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
redis.maxTotal=1000
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
redis.maxWaitMillis=1000
#连接的最小空闲时间 默认1800000毫秒(30分钟)
redis.minEvictableIdleTimeMillis=300000
#每次释放连接的最大数目,默认3
redis.numTestsPerEvictionRun=1024
#逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
redis.timeBetweenEvictionRunsMillis=30000
#是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
redis.testOnBorrow=true
#在空闲时检查有效性, 默认false
redis.testWhileIdle=true

#redis集群配置
#spring.redis.cluster.nodes=192.168.177.128:7001,192.168.177.128:7002,192.168.177.128:7003,192.168.177.128:7004,192.168.177.128:7005,192.168.177.128:7006
#spring.redis.cluster.max-redirects=3

#哨兵模式
#redis.sentinel.host1=192.168.177.128
#redis.sentinel.port1=26379

#redis.sentinel.host2=172.20.1.231
#redis.sentinel.port2=26379

BIN
tuoheng-admin/src/main/resources/template/ExportReport.docx View File


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

@@ -0,0 +1,162 @@
<?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要使用顶层的父模块-->
<parent>
<artifactId>tuoheng</artifactId>
<groupId>com.tuoheng</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-common</artifactId>
<packaging>jar</packaging>
<name>tuoheng-common</name>
<description>Demo project for Spring Boot</description>

<!-- 依赖声明 -->
<dependencies>
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.6.2</version>
</dependency>
<!--mybatis-plus 起始依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!-- WEB 模块依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redis 起始依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- UserAgent工具类 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.20</version>
</dependency>
<!-- Excel依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beat1</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- 阿里短信SDK -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.1.0</version>
</dependency>
<!-- 邮件发送起始依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- thymeleaf 模板引擎依赖(如:模板邮件) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 极光推送 -->
<dependency>
<groupId>cn.jpush.api</groupId>
<artifactId>jpush-client</artifactId>
<version>3.3.10</version>
</dependency>
<!-- 文件压缩、解压缩 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.8.1</version>
</dependency>
<!-- JWT依赖 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<!-- 二维码生成依赖 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.0</version>
</dependency>

<!-- https://gitee.com/loolly/hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.4.4</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-log</artifactId>
<version>5.4.4</version>
</dependency>

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
</dependencies>

</project>

+ 112
- 0
tuoheng-common/src/main/java/com/tuoheng/common/annotation/Excel.java View File

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

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 自定义导出Excel
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel {

/**
* 导出到Excel中的名字.
*/
String name() default "";

/**
* 日期格式, 如: yyyy-MM-dd
*/
String dateFormat() default "";

/**
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
*/
String readConverterExp() default "";

/**
* 导出类型(0数字 1字符串)
*/
ColumnType cellType() default ColumnType.STRING;

/**
* 导出时在excel中每个列的高度 单位为字符
*/
double height() default 14;

/**
* 导出时在excel中每个列的宽 单位为字符
*/
double width() default 16;

/**
* 文字后缀,如% 90 变成90%
*/
String suffix() default "";

/**
* 当值为空时,字段的默认值
*/
String defaultValue() default "";

/**
* 提示信息
*/
String prompt() default "";

/**
* 设置只能选择不能输入的列内容.
*/
String[] combo() default {};

/**
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/
boolean isExport() default true;

/**
* 另一个类中的属性名称,支持多级获取,以小数点隔开
*/
String targetAttr() default "";

/**
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
*/
Type type() default Type.ALL;

/**
* 导出类型枚举
*/
enum Type {
ALL(0), EXPORT(1), IMPORT(2);
private final int value;

Type(int value) {
this.value = value;
}

public int value() {
return this.value;
}
}

/**
* 列类型枚举
*/
enum ColumnType {
NUMERIC(0), STRING(1);
private final int value;

ColumnType(int value) {
this.value = value;
}

public int value() {
return this.value;
}
}

}

+ 18
- 0
tuoheng-common/src/main/java/com/tuoheng/common/annotation/Excels.java View File

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

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 自定义导出Excel注解集
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Excels {

// Excel数组
Excel[] value();

}

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

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

import com.tuoheng.common.enums.LogType;
import com.tuoheng.common.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;

}

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

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

public class BaseController {
}

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

@@ -0,0 +1,56 @@
package com.tuoheng.common.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 牧羊人
* @date 2019/11/28
*/
@Data
public class BaseEntity implements Serializable {

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

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

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

/**
* 更新人
*/
private Integer 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/src/main/java/com/tuoheng/common/common/BaseQuery.java View File

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

import lombok.Data;

/**
* 查询对象基类
*/
@Data
public class BaseQuery {
/**
* 页码
*/
private Integer page;

/**
* 每页数
*/
private Integer limit;
}

+ 37
- 0
tuoheng-common/src/main/java/com/tuoheng/common/common/BaseResponse.java View File

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

import com.tuoheng.common.constant.Constant;
import lombok.Data;
import lombok.experimental.Accessors;

/**
* 结果集
*
* @author zhu_zishuang
* @date 2021-03-12
*/
@Data
@Accessors(chain = true)
public class BaseResponse<T> {

/**
* success:成功,fail:业务返回的失败,error:非业务异常失败
*/
private String status = Constant.SUCCESS;

/**
* 状态码
**/
private Integer code;

/**
* 结果描述
**/
private String message;

/**
* 结果数据
**/
private T data;
}


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

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

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tuoheng.common.utils.DateUtils;
import com.tuoheng.common.utils.JsonResult;
import org.springframework.util.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 query 查询条件
* @return
*/
@Override
public JsonResult getList(BaseQuery query) {
return null;
}

/**
* 根据ID获取记录信息
*
* @param id 记录ID
* @return
*/
@Override
public JsonResult info(Integer id) {
if (id == null && id <= 0) {
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.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.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 && entity.getId() > 0) {
// 修改记录
return this.update(entity);
} else {
// 新增记录
return this.add(entity);
}
}

/**
* 删除记录
*
* @param entity 实体对象
* @return
*/
@Override
public JsonResult delete(T entity) {
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(Integer id) {
if (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(Integer[] ids) {
if (StringUtils.isEmpty(ids)) {
return JsonResult.error("记录ID不能为空");
}
// String[] item = ids.split(",");
// 设置Mark=0
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.set("mark", 0);
updateWrapper.in("id", ids);
boolean result = update(updateWrapper);
if (!result) {
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/src/main/java/com/tuoheng/common/common/ExceptionInterface.java View File

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

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

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

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

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

import com.baomidou.mybatisplus.extension.service.IService;
import com.tuoheng.common.utils.JsonResult;

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


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

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

/**
* 根据ID获取记录信息
*
* @param id 记录ID
* @return
*/
JsonResult info(Integer 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(Integer id);

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

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

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

}

+ 52
- 0
tuoheng-common/src/main/java/com/tuoheng/common/common/OperationEnum.java View File

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

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;

/**
* 全局枚举常量类
*
* @author zhu_zishuang
* @date 2021-03-12
*/
@Accessors(chain = true)
@AllArgsConstructor
public enum OperationEnum implements ExceptionInterface {
/**
* 登陆成功
*/
LOGIN_SUCCESS(200, "登陆成功!"),
/**
* 新增操作成功
*/
SAVE_SUCCESS(201, "新增成功!"),
/**
* 修改操作成功
*/
UPDATE_SUCCESS(202, "修改成功!"),
/**
* 删除操作成功
*/
DELETE_SUCCESS(203, "删除成功!"),

/**
* 操作异常
*/
OPERATION_ERROR(204, "操作失败!"),
/**
* 操作成功
*/
OPERATION_SUCCESS(205, "操作成功!");
/**
* 结果类型CODE
*/
@Getter
private final int code;

/**
* 结果类型描述
*/
@Getter
private final String message;
}

+ 96
- 0
tuoheng-common/src/main/java/com/tuoheng/common/common/SysExceptionEnum.java View File

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

import lombok.AllArgsConstructor;
import lombok.Getter;

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

/**
* 登录用户名不能为空
*/
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 message;
}

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

@@ -0,0 +1,26 @@
package com.tuoheng.common.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;

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

}

+ 40
- 0
tuoheng-common/src/main/java/com/tuoheng/common/config/I18nConfig.java View File

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

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.util.Locale;

/**
* 国际化配置文件
*/
@Configuration
public class I18nConfig implements WebMvcConfigurer {

@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
// 默认语言
slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
return slr;
}

@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
// 参数名
lci.setParamName("lang");
return lci;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}

}

+ 26
- 0
tuoheng-common/src/main/java/com/tuoheng/common/config/MybatisPlusConfig.java View File

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

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
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() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}

+ 49
- 0
tuoheng-common/src/main/java/com/tuoheng/common/config/QrImage.java View File

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

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class QrImage {

/**
* 二维码的内容(非空)
*/
private String qrCodeContent;

/**
* 二维码的宽度(非空)
*/
private Integer qrCodeWidth;

/**
* 二维码的高度(非空)
*/
private Integer qrCodeHeight;

/**
* 二维码内嵌图片的文件路径(为空则表示:二维码中间不嵌套图片)
*/
private String embeddedImgFilePath;

/**
* 文字的大小(即:正方形文字的长度、宽度)(非空)
*/
private Integer wordSize;

/**
* 文字的内容(非空)
*/
private String wordContent;

/**
* 二维码文件的输出路径(非空)
*/
private String qrCodeFileOutputPath;

}

+ 154
- 0
tuoheng-common/src/main/java/com/tuoheng/common/config/RedisConfig.java View File

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

import com.tuoheng.common.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
//@PropertySource("classpath:redis.properties")
public class RedisConfig {

@Value("${spring.redis.host}")
private String hostName;
@Value("${spring.redis.port}")
private Integer port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private Integer timeout;
/*
@Value("${redis.maxIdle}")
private Integer maxIdle;

@Value("${redis.maxTotal}")
private Integer maxTotal;

@Value("${redis.maxWaitMillis}")
private Integer maxWaitMillis;

@Value("${redis.minEvictableIdleTimeMillis}")
private Integer minEvictableIdleTimeMillis;

@Value("${redis.numTestsPerEvictionRun}")
private Integer numTestsPerEvictionRun;

@Value("${redis.timeBetweenEvictionRunsMillis}")
private long timeBetweenEvictionRunsMillis;

@Value("${redis.testOnBorrow}")
private boolean testOnBorrow;

@Value("${redis.testWhileIdle}")
private boolean testWhileIdle;
*/
/**
* JedisPoolConfig 连接池
* @return

@Bean public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空闲数
jedisPoolConfig.setMaxIdle(maxIdle);
// 连接池的最大数据库连接数
jedisPoolConfig.setMaxTotal(maxTotal);
// 最大建立连接等待时间
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
// 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
// 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
jedisPoolConfig.setTestOnBorrow(testOnBorrow);
// 在空闲时检查有效性, 默认false
jedisPoolConfig.setTestWhileIdle(testWhileIdle);
return jedisPoolConfig;
}

/**
* 单机版配置
* @Title: JedisConnectionFactory
* @param @param jedisPoolConfig
* @param @return
* @return JedisConnectionFactory
* @autor lpl
* @date 2018年2月24日
* @throws

@Bean public JedisConnectionFactory jedisConnectionFactory(){
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(hostName);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setPassword(password);

JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder();
jedisClientConfigurationBuilder.connectTimeout(Duration.ofMillis(timeout));

JedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration,jedisClientConfigurationBuilder.build());

return factory;
}
*/
/**
* 实例化 RedisTemplate 对象 jredis实现方式,springboot2.x以后使用下面的方法
*
* @return
@Bean public RedisTemplate<String, Object> functionDomainRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
return redisTemplate;
}
*/
/**
* lettuce实现redis方式
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
return redisTemplate;
}

/**
* 设置数据存入 redis 的序列化方式,并开启事务
*
* @param redisTemplate
* @param factory
*/
private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
//如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 开启事务
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(factory);
}

/**
* 注入封装RedisTemplate
*
* @return RedisUtil
* @throws
* @Title: redisUtil
* @autor lpl
* @date 2017年12月21日
*/
@Bean(name = "redisUtils")
public RedisUtils redisUtils(RedisTemplate<String, Object> redisTemplate) {
RedisUtils redisUtil = new RedisUtils();
redisUtil.setRedisTemplate(redisTemplate);
return redisUtil;
}
}

+ 58
- 0
tuoheng-common/src/main/java/com/tuoheng/common/config/ThreadPoolConfig.java View File

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

import com.tuoheng.common.utils.ThreadUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
* 线程池配置
*/
@Configuration
public class ThreadPoolConfig {

// 核心线程池大小
private int corePoolSize = 50;

// 最大可创建的线程数
private int maxPoolSize = 200;

// 队列最大长度
private int queueCapacity = 1000;

// 线程池维护线程所允许的空闲时间
private int keepAliveSeconds = 300;

@Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(maxPoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
// 线程池对拒绝任务(无线程可用)的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}

/**
* 执行周期性或定时任务
*/
@Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService() {
return new ScheduledThreadPoolExecutor(corePoolSize,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
ThreadUtils.printException(r, t);
}
};
}

}

+ 40
- 0
tuoheng-common/src/main/java/com/tuoheng/common/config/UploadFileConfig.java View File

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

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

/**
* 文件上传配置
*/
@Configuration
@Data
public class UploadFileConfig {
/**
* 上传目录
*/
public static String uploadFolder;
/**
* 访问路径
*/
public static String staticAccessPath;
/**
* 上传服务器的映射文件夹
*/
public static String accessPath;

@Value("${file.uploadFolder}")
public void setUploadFolder(String path) {
uploadFolder = path;
}

@Value("${file.staticAccessPath}")
public void setStaticAccessPath(String path) {
staticAccessPath = path;
}

@Value("${file.accessPath}")
public void setAccessPath(String path) {
accessPath = path;
}
}

+ 83
- 0
tuoheng-common/src/main/java/com/tuoheng/common/config/WebMvcConfig.java View File

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

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
* 设置虚拟路径,访问绝对路径下资源
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

@Value("${file.staticAccessPath}")
private String staticAccessPath;
@Value("${file.uploadFolder}")
private String uploadFolder;

static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE"};

/**
* 注册静态文件的自定义映射路径
*
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
// 定义到新文件夹
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
// 定义到指定目录
registry.addResourceHandler(staticAccessPath)
.addResourceLocations("file:" + uploadFolder);
}

/**
* 跨域问题解决
*
* @param registry
*/
@Override
protected void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods(ORIGINS)
.maxAge(3600);
}

/**
* 跨域配置
*
* @return
*/
private CorsConfiguration corsConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setMaxAge(3600L);
return corsConfiguration;
}

/**
* 跨域过滤器
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfig());
return new CorsFilter(source);
}

}

+ 103
- 0
tuoheng-common/src/main/java/com/tuoheng/common/constant/CommonConstants.java View File

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

/**
* 系统公共常量
*/
public class CommonConstants {

/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";

/**
* GBK 字符集
*/
public static final String GBK = "GBK";

/**
* http请求
*/
public static final String HTTP = "http://";

/**
* https请求
*/
public static final String HTTPS = "https://";

/**
* 成功标记
*/
public static final Integer SUCCESS = 200;

/**
* 失败标记
*/
public static final Integer FAIL = 500;

/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";

/**
* 注销
*/
public static final String LOGOUT = "Logout";

/**
* 注册
*/
public static final String REGISTER = "Register";

/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";

/**
* 当前记录起始索引
*/
public static final String PAGE_NUM = "pageNum";

/**
* 每页显示记录数
*/
public static final String PAGE_SIZE = "pageSize";

/**
* 排序列
*/
public static final String ORDER_BY_COLUMN = "orderByColumn";

/**
* 排序的方向 "desc" 或者 "asc".
*/
public static final String IS_ASC = "isAsc";

/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";

/**
* 验证码有效期(分钟)
*/
public static final Integer CAPTCHA_EXPIRATION = 2;

/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";

/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";

/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";

}

+ 49
- 0
tuoheng-common/src/main/java/com/tuoheng/common/constant/Constant.java View File

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

/**
* 常量类
*
* @author: zhu_zishuang
* @date: 2020-04-22 14:22
*/
public final class Constant {
/**
* 构造器私有化
*/
private Constant() {
// 可抛出异常,防止通过反射实例化对象
}

/**
* 返回结果 success:成功,fail:业务返回的失败,error:非业务异常失败
*/
public static final String SUCCESS = "success";
public static final String FAIL = "fail";
public static final String ERROR = "error";

/**
* 常用数值
*/
public static final Integer ZERO = 0;
public static final Integer ONE = 1;
public static final Long MAX_PAGE_SIZE = 100_000L;


/**
* 常用字符
*/
public static final String SPLIT_CLASS = " ";
public static final String LOG_INFO_PREFIX = "登录异常,异常信息:{}";

/**
* 是否
*/
public static final Byte YES = 1;
public static final Byte NO = 0;
public static final Integer YES_INT = 1;

/**
* 平台管理员
*/
public static final String ADMIN = "admin";
}

+ 30
- 0
tuoheng-common/src/main/java/com/tuoheng/common/constant/RedisConstant.java View File

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

/**
* redis常量类
*/
public interface RedisConstant {

/**
* TOKEN前缀
*/
String REDIS_PREFIX_LOGIN = "login_token_%s";
/**
* 过期时间2小时
*/
Integer REDIS_EXPIRE_TWO = 7200;
/**
* 过期时间15分
*/
Integer REDIS_EXPIRE_EMAIL = 900;
/**
* 过期时间5分钟
*/
Integer REDIS_EXPIRE_KAPTCHA = 300;
/**
* 暂无过期时间
*/
Integer REDIS_EXPIRE_NULL = -1;


}

+ 50
- 0
tuoheng-common/src/main/java/com/tuoheng/common/controller/CommonController.java View File

@@ -0,0 +1,50 @@
package com.tuoheng.common.controller;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.tuoheng.common.config.UploadFileConfig;
import com.tuoheng.common.utils.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/common")
public class CommonController {

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

/**
* 下载文件
*
* @param fileName 文件名
* @param isDelete 是否下载后删除
* @param request 网络请求
* @param response
*/
@GetMapping("/download")
public void downloadFile(String fileName, boolean isDelete, HttpServletRequest request, HttpServletResponse response) {
try {
if (!FileUtils.isValidFilename(fileName)) {
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = UploadFileConfig.uploadFolder + fileName;
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition", "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, realFileName));
FileUtils.writeBytes(filePath, response.getOutputStream());
if (isDelete) {
// 删除文件
FileUtils.deleteFile(filePath);
}
} catch (Exception e) {
log.error("下载文件失败", e);
}
}

}

+ 52
- 0
tuoheng-common/src/main/java/com/tuoheng/common/controller/UploadController.java View File

@@ -0,0 +1,52 @@
package com.tuoheng.common.controller;

import com.tuoheng.common.service.IUploadService;
import com.tuoheng.common.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
* <p>
* 角色菜单关联表 前端控制器
* </p>
*
* @author 拓恒
* @since 2020-10-30
*/
@RestController
@RequestMapping("/upload")
public class UploadController {

@Autowired
private IUploadService uploadService;

/**
* 上传图片
*
* @param request 网络请求
* @param name 目录名
* @return
*/
@PostMapping("/uploadImage/{name}")
public JsonResult uploadImage(HttpServletRequest request, @PathVariable("name") String name) {
return uploadService.uploadImage(request, name);
}

/**
* 上传文件(非图片)
*
* @param request 网络请求
* @param name 目录名
* @return
*/
@PostMapping("/uploadFile/{name}")
public JsonResult uploadFile(HttpServletRequest request, @PathVariable("name") String name) {
return uploadService.uploadFile(request, name);
}

}

+ 18
- 0
tuoheng-common/src/main/java/com/tuoheng/common/enums/LogStatus.java View File

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

/**
* 操作状态
*/
public enum LogStatus {

/**
* 成功
*/
SUCCESS,

/**
* 失败
*/
FAIL,

}

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

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

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

/**
* 其它
*/
OTHER,

/**
* 新增
*/
INSERT,

/**
* 修改
*/
UPDATE,

/**
* 删除
*/
DELETE,

/**
* 授权
*/
GRANT,

/**
* 导出
*/
EXPORT,

/**
* 导入
*/
IMPORT,

/**
* 强退
*/
FORCE,

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

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

/**
* 状态
*/
STATUS,

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

}

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

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

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

/**
* 其它
*/
OTHER,

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

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

}

+ 84
- 0
tuoheng-common/src/main/java/com/tuoheng/common/exception/BaseException.java View File

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

import com.tuoheng.common.utils.MessageUtils;
import org.springframework.util.StringUtils;

/**
* 异常基类
*/
public class BaseException extends RuntimeException {

private static final long serialVersionUID = 1L;

/**
* 所属模块
*/
private String module;

/**
* 错误码
*/
private String code;

/**
* 错误码对应的参数
*/
private Object[] args;

/**
* 错误消息
*/
private String defaultMessage;

public BaseException(String module, String code, Object[] args, String defaultMessage) {
this.module = module;
this.code = code;
this.args = args;
this.defaultMessage = defaultMessage;
}

public BaseException(String module, String code, Object[] args) {
this(module, code, args, null);
}

public BaseException(String module, String defaultMessage) {
this(module, null, null, defaultMessage);
}

public BaseException(String code, Object[] args) {
this(null, code, args, null);
}

public BaseException(String defaultMessage) {
this(null, null, null, defaultMessage);
}

@Override
public String getMessage() {
String message = null;
if (!StringUtils.isEmpty(code)) {
message = MessageUtils.message(code, args);
}
if (message == null) {
message = defaultMessage;
}
return message;
}

public String getModule() {
return module;
}

public String getCode() {
return code;
}

public Object[] getArgs() {
return args;
}

public String getDefaultMessage() {
return defaultMessage;
}

}

+ 37
- 0
tuoheng-common/src/main/java/com/tuoheng/common/exception/CustomException.java View File

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

/**
* 自定义异常类
*/
public class CustomException extends RuntimeException {

private static final long serialVersionUID = 1L;

private Integer code;

private String message;

public CustomException(String message) {
this.message = message;
}

public CustomException(String message, Integer code) {
this.message = message;
this.code = code;
}

public CustomException(String message, Throwable e) {
super(message, e);
this.message = message;
}

@Override
public String getMessage() {
return message;
}

public Integer getCode() {
return code;
}

}

+ 39
- 0
tuoheng-common/src/main/java/com/tuoheng/common/exception/ExceptionConstantEnum.java View File

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

import com.tuoheng.common.common.ExceptionInterface;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;

/**
* 业务异常枚举
*
* @author zhu_zishuang
* @date 2020-09-17
*/
@Accessors(chain = true)
@AllArgsConstructor
public enum ExceptionConstantEnum implements ExceptionInterface {
/**
* 存在错误参数 304
*/
PARAMS_NOT_RIGHT(304, "存在错误参数"),

/**
* SQL异常
**/
SQL_ERROR_EXCEPTION(501, "SQL执行异常!");

/**
* 结果类型CODE
*/
@Getter
private final int code;

/**
* 结果类型描述
*/
@Getter
private final String message;
}


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

@@ -0,0 +1,39 @@
package com.tuoheng.common.exception;
import com.tuoheng.common.common.ExceptionInterface;

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

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

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

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

}


+ 14
- 0
tuoheng-common/src/main/java/com/tuoheng/common/exception/user/CaptchaException.java View File

@@ -0,0 +1,14 @@
package com.tuoheng.common.exception.user;

/**
* 验证码异常处理类
*/
public class CaptchaException extends UserException {

private static final long serialVersionUID = 1L;

public CaptchaException() {
super("user.jcaptcha.error", null);
}

}

+ 16
- 0
tuoheng-common/src/main/java/com/tuoheng/common/exception/user/UserException.java View File

@@ -0,0 +1,16 @@
package com.tuoheng.common.exception.user;

import com.tuoheng.common.exception.BaseException;

/**
* 用户异常处理类
*/
public class UserException extends BaseException {

private static final long serialVersionUID = 1L;

public UserException(String code, Object[] args) {
super("user", code, args, null);
}

}

+ 14
- 0
tuoheng-common/src/main/java/com/tuoheng/common/exception/user/UserNotExistsException.java View File

@@ -0,0 +1,14 @@
package com.tuoheng.common.exception.user;

/**
* 用户不存在异常
*/
public class UserNotExistsException extends UserException {

private static final long serialVersionUID = 1L;

public UserNotExistsException() {
super("user.not.exists", null);
}

}

+ 35
- 0
tuoheng-common/src/main/java/com/tuoheng/common/service/IUploadService.java View File

@@ -0,0 +1,35 @@
package com.tuoheng.common.service;

import com.tuoheng.common.utils.JsonResult;

import javax.servlet.http.HttpServletRequest;

/**
* <p>
* 文件上传 服务类
* </p>
*
* @author 拓恒
* @since 2020-10-30
*/
public interface IUploadService {

/**
* 上传图片
*
* @param request 网络请求
* @param name 目录名
* @return
*/
JsonResult uploadImage(HttpServletRequest request, String name);

/**
* 上传文件
*
* @param request 网络请求
* @param name 目录名
* @return
*/
JsonResult uploadFile(HttpServletRequest request, String name);

}

+ 66
- 0
tuoheng-common/src/main/java/com/tuoheng/common/service/impl/UploadServiceImpl.java View File

@@ -0,0 +1,66 @@
package com.tuoheng.common.service.impl;

import com.tuoheng.common.service.IUploadService;
import com.tuoheng.common.utils.CommonUtils;
import com.tuoheng.common.utils.JsonResult;
import com.tuoheng.common.utils.UploadUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* <p>
* 文件上传 服务实现类
* </p>
*
* @author 拓恒
* @since 2020-10-30
*/
@Service
public class UploadServiceImpl implements IUploadService {

@Autowired
private UploadUtils uploadUtils;

/**
* 上传图片
*
* @param request 网络请求
* @param name 目录名
* @return
*/
@Override
public JsonResult uploadImage(HttpServletRequest request, String name) {
UploadUtils uploadUtils = new UploadUtils();
Map<String, Object> result = uploadUtils.uploadFile(request, name);
List<String> imageList = (List<String>) result.get("image");
String imageUrl = CommonUtils.getImageURL(imageList.get(imageList.size() - 1));
return JsonResult.success(imageUrl, "上传成功");
}

/**
* 上传文件
*
* @param request 网络请求
* @param name 目录名
* @return
*/
@Override
public JsonResult uploadFile(HttpServletRequest request, String name) {
UploadUtils uploadUtils = new UploadUtils();
uploadUtils.setDirName("files");
Map<String, Object> result = uploadUtils.uploadFile(request, name);
List<String> nameList = (List<String>) result.get("name");
List<String> imageList = (List<String>) result.get("image");
String imageUrl = CommonUtils.getImageURL(imageList.get(imageList.size() - 1));
Map<String, Object> map = new HashMap<>();
map.put("fileName", nameList.get(nameList.size() - 1));
map.put("fileUrl", imageUrl);
return JsonResult.success(map, "上传成功");
}

}

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

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

import com.alibaba.fastjson.JSONObject;
import com.tuoheng.common.config.CommonConfig;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

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

/**
* 验证邮箱是否正确
*
* @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;
}

/**
* Map对象转Object
*
* @param map
* @param resultJson
* @return
*/
public static JSONObject toJsonObject(Map<String, String> map, JSONObject resultJson) {
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
resultJson.put(key, map.get(key));
}
return resultJson;
}

}

+ 850
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/ConvertUtil.java View File

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

import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Set;

/**
* 类型转换器
*/
public class ConvertUtil {

/**
* 转换为字符串<br>
* 如果给定的值为null,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static String toStr(Object value, String defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof String) {
return (String) value;
}
return value.toString();
}

/**
* 转换为字符串<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static String toStr(Object value) {
return toStr(value, null);
}

/**
* 转换为字符<br>
* 如果给定的值为null,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Character toChar(Object value, Character defaultValue) {
if (null == value) {
return defaultValue;
}
if (value instanceof Character) {
return (Character) value;
}

final String valueStr = toStr(value, null);
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
}

/**
* 转换为字符<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Character toChar(Object value) {
return toChar(value, null);
}

/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Byte toByte(Object value, Byte defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Byte) {
return (Byte) value;
}
if (value instanceof Number) {
return ((Number) value).byteValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Byte.parseByte(valueStr);
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Byte toByte(Object value) {
return toByte(value, null);
}

/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Short toShort(Object value, Short defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Short) {
return (Short) value;
}
if (value instanceof Number) {
return ((Number) value).shortValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Short.parseShort(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Short toShort(Object value) {
return toShort(value, null);
}

/**
* 转换为Number<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Number toNumber(Object value, Number defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Number) {
return (Number) value;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return NumberFormat.getInstance().parse(valueStr);
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为Number<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Number toNumber(Object value) {
return toNumber(value, null);
}

/**
* 转换为int<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Integer toInt(Object value, Integer defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Integer) {
return (Integer) value;
}
if (value instanceof Number) {
return ((Number) value).intValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Integer.parseInt(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为int<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Integer toInt(Object value) {
return toInt(value, null);
}

/**
* 转换为Integer数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String str) {
return toIntArray(",", str);
}

/**
* 转换为Long数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String str) {
return toLongArray(",", str);
}

/**
* 转换为Integer数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Integer[]{};
}
String[] arr = str.split(split);
final Integer[] ints = new Integer[arr.length];
for (int i = 0; i < arr.length; i++) {
final Integer v = toInt(arr[i], 0);
ints[i] = v;
}
return ints;
}

/**
* 转换为Long数组<br>
*
* @param split 分隔符
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String split, String str) {
if (StringUtils.isEmpty(str)) {
return new Long[]{};
}
String[] arr = str.split(split);
final Long[] longs = new Long[arr.length];
for (int i = 0; i < arr.length; i++) {
final Long v = toLong(arr[i], null);
longs[i] = v;
}
return longs;
}

/**
* 转换为String数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static String[] toStrArray(String str) {
return toStrArray(",", str);
}

/**
* 转换为String数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static String[] toStrArray(String split, String str) {
return str.split(split);
}

/**
* 转换为long<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Long toLong(Object value, Long defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Long) {
return (Long) value;
}
if (value instanceof Number) {
return ((Number) value).longValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).longValue();
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为long<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Long toLong(Object value) {
return toLong(value, null);
}

/**
* 转换为double<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Double toDouble(Object value, Double defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Double) {
return (Double) value;
}
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
// 支持科学计数法
return new BigDecimal(valueStr.trim()).doubleValue();
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为double<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Double toDouble(Object value) {
return toDouble(value, null);
}

/**
* 转换为Float<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Float toFloat(Object value, Float defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Float) {
return (Float) value;
}
if (value instanceof Number) {
return ((Number) value).floatValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Float.parseFloat(valueStr.trim());
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为Float<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Float toFloat(Object value) {
return toFloat(value, null);
}

/**
* 转换为boolean<br>
* String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Boolean toBool(Object value, Boolean defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
valueStr = valueStr.trim().toLowerCase();
switch (valueStr) {
case "true":
return true;
case "false":
return false;
case "yes":
return true;
case "ok":
return true;
case "no":
return false;
case "1":
return true;
case "0":
return false;
default:
return defaultValue;
}
}

/**
* 转换为boolean<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Boolean toBool(Object value) {
return toBool(value, null);
}

/**
* 转换为Enum对象<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
*
* @param clazz Enum的Class
* @param value 值
* @param defaultValue 默认值
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {
if (value == null) {
return defaultValue;
}
if (clazz.isAssignableFrom(value.getClass())) {
@SuppressWarnings("unchecked")
E myE = (E) value;
return myE;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return Enum.valueOf(clazz, valueStr);
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为Enum对象<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
*
* @param clazz Enum的Class
* @param value 值
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {
return toEnum(clazz, value, null);
}

/**
* 转换为BigInteger<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigInteger toBigInteger(Object value, BigInteger defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigInteger) {
return (BigInteger) value;
}
if (value instanceof Long) {
return BigInteger.valueOf((Long) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigInteger(valueStr);
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为BigInteger<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigInteger toBigInteger(Object value) {
return toBigInteger(value, null);
}

/**
* 转换为BigDecimal<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {
if (value == null) {
return defaultValue;
}
if (value instanceof BigDecimal) {
return (BigDecimal) value;
}
if (value instanceof Long) {
return new BigDecimal((Long) value);
}
if (value instanceof Double) {
return new BigDecimal((Double) value);
}
if (value instanceof Integer) {
return new BigDecimal((Integer) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr)) {
return defaultValue;
}
try {
return new BigDecimal(valueStr);
} catch (Exception e) {
return defaultValue;
}
}

/**
* 转换为BigDecimal<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value) {
return toBigDecimal(value, null);
}

/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @return 字符串
*/
public static String utf8Str(Object obj) {
return str(obj, Charset.forName("UTF_8"));
}

/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charsetName 字符集
* @return 字符串
*/
public static String str(Object obj, String charsetName) {
return str(obj, Charset.forName(charsetName));
}

/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charset 字符集
* @return 字符串
*/
public static String str(Object obj, Charset charset) {
if (null == obj) {
return null;
}

if (obj instanceof String) {
return (String) obj;
} else if (obj instanceof byte[] || obj instanceof Byte[]) {
return str((Byte[]) obj, charset);
} else if (obj instanceof ByteBuffer) {
return str((ByteBuffer) obj, charset);
}
return obj.toString();
}

/**
* 将byte数组转为字符串
*
* @param bytes byte数组
* @param charset 字符集
* @return 字符串
*/
public static String str(byte[] bytes, String charset) {
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
}

/**
* 解码字节码
*
* @param data 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 解码后的字符串
*/
public static String str(byte[] data, Charset charset) {
if (data == null) {
return null;
}

if (null == charset) {
return new String(data);
}
return new String(data, charset);
}

/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, String charset) {
if (data == null) {
return null;
}

return str(data, Charset.forName(charset));
}

/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, Charset charset) {
if (null == charset) {
charset = Charset.defaultCharset();
}
return charset.decode(data).toString();
}

// ----------------------------------------------------------------------- 全角半角转换

/**
* 半角转全角
*
* @param input String.
* @return 全角字符串.
*/
public static String toSBC(String input) {
return toSBC(input, null);
}

/**
* 半角转全角
*
* @param input String
* @param notConvertSet 不替换的字符集合
* @return 全角字符串.
*/
public static String toSBC(String input, Set<Character> notConvertSet) {
char c[] = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (null != notConvertSet && notConvertSet.contains(c[i])) {
// 跳过不替换的字符
continue;
}

if (c[i] == ' ') {
c[i] = '\u3000';
} else if (c[i] < '\177') {
c[i] = (char) (c[i] + 65248);

}
}
return new String(c);
}

/**
* 全角转半角
*
* @param input String.
* @return 半角字符串
*/
public static String toDBC(String input) {
return toDBC(input, null);
}

/**
* 替换全角为半角
*
* @param text 文本
* @param notConvertSet 不替换的字符集合
* @return 替换后的字符
*/
public static String toDBC(String text, Set<Character> notConvertSet) {
char c[] = text.toCharArray();
for (int i = 0; i < c.length; i++) {
if (null != notConvertSet && notConvertSet.contains(c[i])) {
// 跳过不替换的字符
continue;
}

if (c[i] == '\u3000') {
c[i] = ' ';
} else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {
c[i] = (char) (c[i] - 65248);
}
}
String returnString = new String(c);

return returnString;
}

/**
* 数字金额大写转换 先写个完整的然后将如零拾替换成零
*
* @param n 数字
* @return 中文大写数字
*/
public static String digitUppercase(double n) {
String[] fraction = {"角", "分"};
String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};

String head = n < 0 ? "负" : "";
n = Math.abs(n);

String s = "";
for (int i = 0; i < fraction.length; i++) {
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
}
if (s.length() < 1) {
s = "整";
}
int integerPart = (int) Math.floor(n);

for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
String p = "";
for (int j = 0; j < unit[1].length && n > 0; j++) {
p = digit[integerPart % 10] + unit[1][j] + p;
integerPart = integerPart / 10;
}
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
}
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
}

}

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

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

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

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

/**
* 时间工具类
*
* @author zhuzishuang
* @date 2021/10/8
*/
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 YYYYMMDD = "yyyyMMdd";

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

/**
* 日期路径 即年/月/日 如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);
}

}

+ 695
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/ExcelUtils.java View File

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

import com.tuoheng.common.annotation.Excel;
import com.tuoheng.common.annotation.Excels;
import com.tuoheng.common.config.UploadFileConfig;
import com.tuoheng.common.exception.CustomException;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;

/**
* 导出Excel工具类
*/
public class ExcelUtils<T> {

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

/**
* Excel sheet最大行数,默认65536
*/
public static final int sheetSize = 65536;

/**
* 工作表名称
*/
private String sheetName;

/**
* 导出类型(EXPORT:导出数据;IMPORT:导入模板)
*/
private Excel.Type type;

/**
* 工作薄对象
*/
private Workbook wb;

/**
* 工作表对象
*/
private Sheet sheet;

/**
* 样式列表
*/
private Map<String, CellStyle> styles;

/**
* 导入导出数据列表
*/
private List<T> list;

/**
* 注解列表
*/
private List<Object[]> fields;

/**
* 实体对象
*/
public Class<T> clazz;

public ExcelUtils(Class<T> clazz) {
this.clazz = clazz;
}

public void init(List<T> list, String sheetName, Excel.Type type) {
if (list == null) {
list = new ArrayList<T>();
}
this.list = list;
this.sheetName = sheetName;
this.type = type;
createExcelField();
createWorkbook();
}

/**
* 对excel表单默认第一个索引名转换成list
*
* @param is 输入流
* @return 转换后集合
*/
public List<T> importExcel(InputStream is) throws Exception {
return importExcel(StringUtils.EMPTY, is);
}

/**
* 对excel表单指定表格索引名转换成list
*
* @param sheetName 表格索引名
* @param is 输入流
* @return 转换后集合
*/
public List<T> importExcel(String sheetName, InputStream is) throws Exception {
this.type = Excel.Type.IMPORT;
this.wb = WorkbookFactory.create(is);
List<T> list = new ArrayList<T>();
Sheet sheet = null;
if (StringUtils.isNotEmpty(sheetName)) {
// 如果指定sheet名,则取指定sheet中的内容.
sheet = wb.getSheet(sheetName);
} else {
// 如果传入的sheet名不存在则默认指向第1个sheet.
sheet = wb.getSheetAt(0);
}

if (sheet == null) {
throw new IOException("文件sheet不存在");
}

int rows = sheet.getPhysicalNumberOfRows();

if (rows > 0) {
// 定义一个map用于存放excel列的序号和field.
Map<String, Integer> cellMap = new HashMap<String, Integer>();
// 获取表头
Row heard = sheet.getRow(0);
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) {
Cell cell = heard.getCell(i);
if (StringUtils.isNotNull(cell != null)) {
String value = this.getCellValue(heard, i).toString();
cellMap.put(value, i);
} else {
cellMap.put(null, i);
}
}
// 有数据时才处理 得到类的所有field.
Field[] allFields = clazz.getDeclaredFields();
// 定义一个map用于存放列的序号和field.
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
for (int col = 0; col < allFields.length; col++) {
Field field = allFields[col];
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) {
// 设置类的私有字段属性可访问.
field.setAccessible(true);
Integer column = cellMap.get(attr.name());
fieldsMap.put(column, field);
}
}
for (int i = 1; i < rows; i++) {
// 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i);
T entity = null;
for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet()) {
Object val = this.getCellValue(row, entry.getKey());

// 如果不存在实例则新建.
entity = (entity == null ? clazz.newInstance() : entity);
// 从map中得到对应列的field.
Field field = fieldsMap.get(entry.getKey());
// 取得类型,并根据对象类型设置值.
Class<?> fieldType = field.getType();
if (String.class == fieldType) {
String s = ConvertUtil.toStr(val);
if (StringUtils.endsWith(s, ".0")) {
val = StringUtils.substringBefore(s, ".0");
} else {
val = ConvertUtil.toStr(val);
}
} else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
val = ConvertUtil.toInt(val);
} else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
val = ConvertUtil.toLong(val);
} else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
val = ConvertUtil.toDouble(val);
} else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
val = ConvertUtil.toFloat(val);
} else if (BigDecimal.class == fieldType) {
val = ConvertUtil.toBigDecimal(val);
} else if (Date.class == fieldType) {
if (val instanceof String) {
val = DateUtils.parseDate(val);
} else if (val instanceof Double) {
val = DateUtil.getJavaDate((Double) val);
}
}
if (StringUtils.isNotNull(fieldType)) {
Excel attr = field.getAnnotation(Excel.class);
String propertyName = field.getName();
if (StringUtils.isNotEmpty(attr.targetAttr())) {
propertyName = field.getName() + "." + attr.targetAttr();
} else if (StringUtils.isNotEmpty(attr.readConverterExp())) {
val = reverseByExp(String.valueOf(val), attr.readConverterExp());
}
ReflectUtils.invokeSetter(entity, propertyName, val);
}
}
list.add(entity);
}
}
return list;
}

/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public JsonResult exportExcel(List<T> list, String sheetName) {
this.init(list, sheetName, Excel.Type.EXPORT);
return exportExcel();
}

/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param sheetName 工作表的名称
* @return 结果
*/
public JsonResult importTemplateExcel(String sheetName) {
this.init(null, sheetName, Excel.Type.IMPORT);
return exportExcel();
}

/**
* 对list数据源将其里面的数据导入到excel表单
*
* @return 结果
*/
public JsonResult exportExcel() {
OutputStream out = null;
try {
// 取出一共有多少个sheet.
double sheetNo = Math.ceil(list.size() / sheetSize);
for (int index = 0; index <= sheetNo; index++) {
createSheet(sheetNo, index);

// 产生一行
Row row = sheet.createRow(0);
int column = 0;
// 写入各个字段的列头名称
for (Object[] os : fields) {
Excel excel = (Excel) os[1];
this.createCell(excel, row, column++);
}
if (Excel.Type.EXPORT.equals(type)) {
fillExcelData(index, row);
}
}
String filename = encodingFilename(sheetName);
out = new FileOutputStream(getAbsoluteFile(filename));
wb.write(out);
return JsonResult.success(filename, "导出成功");
} catch (Exception e) {
log.error("导出Excel异常{}", e.getMessage());
throw new CustomException("导出Excel失败,请联系网站管理员!");
} finally {
if (wb != null) {
try {
wb.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}

/**
* 填充excel数据
*
* @param index 序号
* @param row 单元格行
*/
public void fillExcelData(int index, Row row) {
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
for (int i = startNo; i < endNo; i++) {
row = sheet.createRow(i + 1 - startNo);
// 得到导出对象.
T vo = (T) list.get(i);
int column = 0;
for (Object[] os : fields) {
Field field = (Field) os[0];
Excel excel = (Excel) os[1];
// 设置实体类私有属性可访问
field.setAccessible(true);
this.addCell(excel, row, vo, field, column++);
}
}
}

/**
* 创建表格样式
*
* @param wb 工作薄对象
* @return 样式列表
*/
private Map<String, CellStyle> createStyles(Workbook wb) {
// 写入各条记录,每条记录对应excel表中的一行
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
CellStyle style = wb.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
style.setFont(dataFont);
styles.put("data", style);

style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
Font headerFont = wb.createFont();
headerFont.setFontName("Arial");
headerFont.setFontHeightInPoints((short) 10);
headerFont.setBold(true);
headerFont.setColor(IndexedColors.WHITE.getIndex());
style.setFont(headerFont);
styles.put("header", style);

return styles;
}

/**
* 创建单元格
*/
public Cell createCell(Excel attr, Row row, int column) {
// 创建列
Cell cell = row.createCell(column);
// 写入列信息
cell.setCellValue(attr.name());
setDataValidation(attr, row, column);
cell.setCellStyle(styles.get("header"));
return cell;
}

/**
* 设置单元格信息
*
* @param value 单元格值
* @param attr 注解相关
* @param cell 单元格信息
*/
public void setCellVo(Object value, Excel attr, Cell cell) {
if (Excel.ColumnType.STRING == attr.cellType()) {
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
} else if (Excel.ColumnType.NUMERIC == attr.cellType()) {
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(Integer.parseInt(value + ""));
}
}

/**
* 创建表格样式
*/
public void setDataValidation(Excel attr, Row row, int column) {
if (attr.name().indexOf("注:") >= 0) {
sheet.setColumnWidth(column, 6000);
} else {
// 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
row.setHeight((short) (attr.height() * 20));
}
// 如果设置了提示信息则鼠标放上去提示.
if (StringUtils.isNotEmpty(attr.prompt())) {
// 这里默认设了2-101列提示.
setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);
}
// 如果设置了combo属性则本列只能选择不能输入
if (attr.combo().length > 0) {
// 这里默认设了2-101列只能选择不能输入.
setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
}
}

/**
* 添加单元格
*/
public Cell addCell(Excel attr, Row row, T vo, Field field, int column) {
Cell cell = null;
try {
// 设置行高
row.setHeight((short) (attr.height() * 20));
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
if (attr.isExport()) {
// 创建cell
cell = row.createCell(column);
cell.setCellStyle(styles.get("data"));

// 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr);
String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) {
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
} else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) {
cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
} else {
// 设置列类型
setCellVo(value, attr, cell);
}
}
} catch (Exception e) {
log.error("导出Excel失败{}", e);
}
return cell;
}

/**
* 设置 POI XSSFSheet 单元格提示
*
* @param sheet 表单
* @param promptTitle 提示标题
* @param promptContent 提示内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
*/
public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
int firstCol, int endCol) {
DataValidationHelper helper = sheet.getDataValidationHelper();
DataValidationConstraint constraint = helper.createCustomConstraint("DD1");
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
DataValidation dataValidation = helper.createValidation(constraint, regions);
dataValidation.createPromptBox(promptTitle, promptContent);
dataValidation.setShowPromptBox(true);
sheet.addValidationData(dataValidation);
}

/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) {
DataValidationHelper helper = sheet.getDataValidationHelper();
// 加载下拉列表内容
DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
DataValidation dataValidation = helper.createValidation(constraint, regions);
// 处理Excel兼容性问题
if (dataValidation instanceof XSSFDataValidation) {
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
} else {
dataValidation.setSuppressDropDownArrow(false);
}

sheet.addValidationData(dataValidation);
}

/**
* 解析导出值 0=男,1=女,2=未知
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @return 解析后值
* @throws Exception
*/
public static String convertByExp(String propertyValue, String converterExp) throws Exception {
try {
String[] convertSource = converterExp.split(",");
for (String item : convertSource) {
String[] itemArray = item.split("=");
if (itemArray[0].equals(propertyValue)) {
return itemArray[1];
}
}
} catch (Exception e) {
throw e;
}
return propertyValue;
}

/**
* 反向解析值 男=0,女=1,未知=2
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @return 解析后值
* @throws Exception
*/
public static String reverseByExp(String propertyValue, String converterExp) throws Exception {
try {
String[] convertSource = converterExp.split(",");
for (String item : convertSource) {
String[] itemArray = item.split("=");
if (itemArray[1].equals(propertyValue)) {
return itemArray[0];
}
}
} catch (Exception e) {
throw e;
}
return propertyValue;
}

/**
* 编码文件名
*/
public String encodingFilename(String filename) {
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
return filename;
}

/**
* 获取下载路径
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename) {
String downloadPath = UploadFileConfig.uploadFolder + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists()) {
desc.getParentFile().mkdirs();
}
return downloadPath;
}

/**
* 获取bean中的属性值
*
* @param vo 实体对象
* @param field 字段
* @param excel 注解
* @return 最终的属性值
* @throws Exception
*/
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception {
Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr())) {
String target = excel.targetAttr();
if (target.indexOf(".") > -1) {
String[] targets = target.split("[.]");
for (String name : targets) {
o = getValue(o, name);
}
} else {
o = getValue(o, target);
}
}
return o;
}

/**
* 以类的属性的get方法方法形式获取值
*
* @param o
* @param name
* @return value
* @throws Exception
*/
private Object getValue(Object o, String name) throws Exception {
if (StringUtils.isNotEmpty(name)) {
Class<?> clazz = o.getClass();
String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method method = clazz.getMethod(methodName);
o = method.invoke(o);
}
return o;
}

/**
* 得到所有定义字段
*/
private void createExcelField() {
this.fields = new ArrayList<Object[]>();
List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields) {
// 单注解
if (field.isAnnotationPresent(Excel.class)) {
putToField(field, field.getAnnotation(Excel.class));
}

// 多注解
if (field.isAnnotationPresent(Excels.class)) {
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel excel : excels) {
putToField(field, excel);
}
}
}
}

/**
* 放到字段集合中
*/
private void putToField(Field field, Excel attr) {
if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) {
this.fields.add(new Object[]{field, attr});
}
}

/**
* 创建一个工作簿
*/
public void createWorkbook() {
this.wb = new SXSSFWorkbook(500);
}

/**
* 创建工作表
*
* @param sheetNo sheet数量
* @param index 序号
*/
public void createSheet(double sheetNo, int index) {
this.sheet = wb.createSheet();
this.styles = createStyles(wb);
// 设置工作表的名称.
if (sheetNo == 0) {
wb.setSheetName(index, sheetName);
} else {
wb.setSheetName(index, sheetName + index);
}
}

/**
* 获取单元格值
*
* @param row 获取的行
* @param column 获取单元格列号
* @return 单元格值
*/
public Object getCellValue(Row row, int column) {
if (row == null) {
return row;
}
Object val = "";
try {
Cell cell = row.getCell(column);
if (cell != null) {
if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) {
val = cell.getNumericCellValue();
if (HSSFDateUtil.isCellDateFormatted(cell)) {
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
} else {
if ((Double) val % 1 > 0) {
val = new DecimalFormat("0.00").format(val);
} else {
val = new DecimalFormat("0").format(val);
}
}
} else if (cell.getCellTypeEnum() == CellType.STRING) {
val = cell.getStringCellValue();
} else if (cell.getCellTypeEnum() == CellType.BOOLEAN) {
val = cell.getBooleanCellValue();
} else if (cell.getCellTypeEnum() == CellType.ERROR) {
val = cell.getErrorCellValue();
}

}
} catch (Exception e) {
return val;
}
return val;
}

}

+ 193
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/FileUtils.java View File

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

import cn.hutool.core.util.ObjectUtil;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLEncoder;

/**
* 文件处理工具类
*/
public class FileUtils {

public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";

/**
* 验证文件名是否含有特殊字符
*
* @param filename
* @return
*/
public static boolean isValidFilename(String filename) {
return filename.matches(FILENAME_PATTERN);
}

/**
* 下载文件并重新编码
*
* @param request 网络请求
* @param fileName 文件名
* @return
* @throws UnsupportedEncodingException
*/
public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
throws UnsupportedEncodingException {
final String agent = request.getHeader("USER-AGENT");
String filename = fileName;
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
filename = new String(fileName.getBytes(), "ISO8859-1");
} else if (agent.contains("Chrome")) {
// google浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}

/**
* 输出指定文件的Byte数组
*
* @param filePath
* @param os
* @throws IOException
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException {
FileInputStream fis = null;
try {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0) {
os.write(b, 0, length);
}
} catch (IOException e) {
throw e;
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}

/**
* 删除文件
*
* @param filePath 文件路径
* @return
*/
public static boolean deleteFile(String filePath) {
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
flag = true;
}
return flag;
}

/**
* MultipartFile 转 File
*
* @param mFile
* @param filePathName
*/
public static File multipartFileToFile(MultipartFile mFile, String filePathName) {
File file = null;
if (ObjectUtil.isNull(mFile)) {
throw new RuntimeException("图片不能为空!");
} else {
InputStream ins = null;
try {
ins = mFile.getInputStream();
file = new File(filePathName);
inputStreamToFile(ins, file);
ins.close();

} catch (IOException e) {
e.printStackTrace();
}
return file;
}
}

/**
* File 转 MultipartFile
*
* @param file
* @throws Exception
*/
public static void fileToMultipartFile(File file) throws Exception {

FileInputStream fileInput = new FileInputStream(file);
MultipartFile toMultipartFile = new MockMultipartFile("file", file.getName(), "text/plain", getBytesByFile(fileInput));
toMultipartFile.getInputStream();

}


public static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 将 File 转换成 Byte数组
*
* @param fis
* @return
*/
public static byte[] getBytesByFile(FileInputStream fis) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024 * 1024 * 10];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
byte[] data = bos.toByteArray();
bos.close();
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

}

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

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

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;

/**
* 通用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();
}

/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
String urlNameString = url + "?" + param;
log.info("sendPost - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection conn = realUrl.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);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info("recv - {}", result);
} catch (ConnectException e) {
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
} catch (SocketTimeoutException e) {
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
} catch (IOException e) {
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
} catch (Exception e) {
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}

/**
* 发送post请求
*
* @param url 路径
* @param jsonObject 参数(json类型)
* @param encoding 编码格式
* @return
* @throws ParseException
* @throws IOException
*/
public static String send(String url, JSONObject jsonObject, String encoding) throws ParseException, IOException {
String body = "";

//创建httpclient对象
CloseableHttpClient client = HttpClients.createDefault();
//创建post方式请求对象
HttpPost httpPost = new HttpPost(url);

//装填参数
StringEntity s = new StringEntity(jsonObject.toString(), "utf-8");
s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
"application/json"));
//设置参数到请求对象中
httpPost.setEntity(s);
System.out.println("请求地址:" + url);
// System.out.println("请求参数:"+nvps.toString());

//设置header信息
//指定报文头【Content-type】、【User-Agent】
// httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setHeader("Content-type", "application/json");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

//执行请求操作,并拿到结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost);
//获取结果实体
HttpEntity entity = response.getEntity();
if (entity != null) {
//按指定编码转换结果实体为String类型
body = EntityUtils.toString(entity, encoding);
}
EntityUtils.consume(entity);
//释放链接
response.close();
return body;
}

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

}

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

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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;

/**
* 获取IP工具类
*/
public class IpUtils {

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

/**
* 通过HttpServletRequest返回IP地址
*
* @param request HttpServletRequest
* @return ip String
* @throws Exception
*/
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" : ip;
}

public static boolean internalIp(String ip) {
byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip);
}

private static boolean internalIp(byte[] addr) {
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;
}

public static String getHostIp() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
}
return "127.0.0.1";
}

public static String getHostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
}
return "未知";
}

/**
* 通过IP地址获取MAC地址
*
* @param ip String,127.0.0.1格式
* @return mac String
* @throws Exception
*/
public String getMACAddress(String ip) throws Exception {
String line = "";
String macAddress = "";
final String MAC_ADDRESS_PREFIX = "MAC Address = ";
final String LOOPBACK_ADDRESS = "127.0.0.1";
//如果为127.0.0.1,则获取本地MAC地址。
if (LOOPBACK_ADDRESS.equals(ip)) {
InetAddress inetAddress = InetAddress.getLocalHost();
//貌似此方法需要JDK1.6。
byte[] mac = NetworkInterface.getByInetAddress(inetAddress).getHardwareAddress();
//下面代码是把mac地址拼装成String
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
if (i != 0) {
sb.append("-");
}
//mac[i] & 0xFF 是为了把byte转化为正整数
String s = Integer.toHexString(mac[i] & 0xFF);
sb.append(s.length() == 1 ? 0 + s : s);
}
//把字符串所有小写字母改为大写成为正规的mac地址并返回
macAddress = sb.toString().trim().toUpperCase();
return macAddress;
}
//获取非本地IP的MAC地址
try {
Process p = Runtime.getRuntime().exec("nbtstat -A " + ip);
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
if (line != null) {
int index = line.indexOf(MAC_ADDRESS_PREFIX);
if (index != -1) {
macAddress = line.substring(index + MAC_ADDRESS_PREFIX.length()).trim().toUpperCase();
}
}
}
br.close();
} catch (IOException e) {
e.printStackTrace(System.out);
}
return macAddress;
}

/**
* 通过IP获取地址(需要联网,调用淘宝的IP库)
*
* @param ip IP地址
* @return
*/
public static String getIpInfo(String ip) {
if ("127.0.0.1".equals(ip)) {
ip = "127.0.0.1";
}
String info = "";
try {
URL url = new URL("http://ip.taobao.com/service/getIpInfo.php?ip=" + ip);
HttpURLConnection htpcon = (HttpURLConnection) url.openConnection();
htpcon.setRequestMethod("GET");
htpcon.setDoOutput(true);
htpcon.setDoInput(true);
htpcon.setUseCaches(false);

InputStream in = htpcon.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
StringBuffer temp = new StringBuffer();
String line = bufferedReader.readLine();
while (line != null) {
temp.append(line).append("\r\n");
line = bufferedReader.readLine();
}
bufferedReader.close();
JSONObject obj = (JSONObject) JSON.parse(temp.toString());
if (obj.getIntValue("code") == 0) {
JSONObject data = obj.getJSONObject("data");
info += data.getString("country") + " ";
info += data.getString("region") + " ";
info += data.getString("city") + " ";
info += data.getString("isp");
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return info;
}

/**
* 根据IP查询地区
*
* @param ip IP地址
* @return
*/
public static String getRealAddressByIP(String ip) {
String address = "XX XX";
// 内网不查询
if (IpUtils.internalIp(ip)) {
return "内网IP";
}
String rspStr = HttpUtils.sendPost("http://ip.taobao.com/service/getIpInfo.php", "ip=" + ip);
if (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;
return address;
}

}

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

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

import com.tuoheng.common.constant.CommonConstants;

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(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/src/main/java/com/tuoheng/common/utils/LogUtils.java View File

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

/**
* 处理并记录日志文件
*/
public class LogUtils {

public static String getBlock(Object msg) {
if (msg == null) {
msg = "";
}
return "[" + msg.toString() + "]";
}

}

+ 23
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/MessageUtils.java View File

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

import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;

/**
* 获取i18n资源文件
*/
public class MessageUtils {

/**
* 根据消息键和参数 获取消息 委托给spring messageSource
*
* @param code 消息键
* @param args 参数
* @return 获取国际化翻译值
*/
public static String message(String code, Object... args) {
MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
}

}

+ 608
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/RedisUtils.java View File

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

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class RedisUtils {

private RedisTemplate<String, Object> redisTemplate;

public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
// =============================common============================

/**
* 普通缓存获取
*
* @param
* @return 值
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public Set<String> keys(String pattern) {
return redisTemplate.keys(pattern);
}

/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}

/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}

// ============================String=============================

/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}

/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}

}

/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}

/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}

// ================================Map=================================

/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}

/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}

/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}

/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}

/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}

/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}

// ============================set=============================

/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}

/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}

/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}

/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================list=================================

/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}

/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}

/**
* 按键的排序获取对应的值
*
* @param keys 多个键
* @return List<Object>
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public List<Object> mget(Collection<String> keys) {
return redisTemplate.opsForValue().multiGet(keys);
}

}

+ 320
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/ReflectUtils.java View File

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

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.*;
import java.util.Date;

/**
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数
*/
@SuppressWarnings("rawtypes")
public class ReflectUtils {

private static final String SETTER_PREFIX = "set";

private static final String GETTER_PREFIX = "get";

private static final String CGLIB_CLASS_SEPARATOR = "$$";

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

/**
* 调用Getter方法.
* 支持多级,如:对象名.对象名.方法
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
}
return (E) object;
}

/**
* 调用Setter方法, 仅匹配方法名。
* 支持多级,如:对象名.对象名.方法
*/
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i = 0; i < names.length; i++) {
if (i < names.length - 1) {
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[]{}, new Object[]{});
} else {
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[]{value});
}
}
}

/**
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
@SuppressWarnings("unchecked")
public static <E> E getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return null;
}
E result = null;
try {
result = (E) field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
}

/**
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
*/
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try {
field.set(obj, value);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常: {}", e.getMessage());
}
}

/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
* 同时匹配方法名+参数类型,
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
if (obj == null || methodName == null) {
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
return (E) method.invoke(obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}

/**
* 直接调用对象方法, 无视private/protected修饰符,
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
* 只匹配函数名,如果有多个同名函数调用第一个。
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null) {
// 如果为空不报错,直接返回空。
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i = 0; i < cs.length; i++) {
if (args[i] != null && !args[i].getClass().equals(cs[i])) {
if (cs[i] == String.class) {
args[i] = ConvertUtil.toStr(args[i]);
if (StringUtils.endsWith((String) args[i], ".0")) {
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
} else if (cs[i] == Integer.class) {
args[i] = ConvertUtil.toInt(args[i]);
} else if (cs[i] == Long.class) {
args[i] = ConvertUtil.toLong(args[i]);
} else if (cs[i] == Double.class) {
args[i] = ConvertUtil.toDouble(args[i]);
} else if (cs[i] == Float.class) {
args[i] = ConvertUtil.toFloat(args[i]);
} else if (cs[i] == Date.class) {
if (args[i] instanceof String) {
args[i] = DateUtils.parseDate(args[i]);
} else {
args[i] = DateUtil.getJavaDate((Double) args[i]);
}
}
}
}
return (E) method.invoke(obj, args);
} catch (Exception e) {
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}

/**
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {
continue;
}
}
return null;
}

/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 匹配函数名+参数类型。
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
continue;
}
}
return null;
}

/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 只匹配函数名。
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null
if (obj == null) {
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
makeAccessible(method);
return method;
}
}
}
return null;
}

/**
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}

/**
* 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}

/**
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
* 如无法找到, 返回Object.class.
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType(final Class clazz) {
return getClassGenricType(clazz, 0);
}

/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*/
public static Class getClassGenricType(final Class clazz, final int index) {
Type genType = clazz.getGenericSuperclass();

if (!(genType instanceof ParameterizedType)) {
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}

Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

if (index >= params.length || index < 0) {
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}

return (Class) params[index];
}

public static Class<?> getUserClass(Object instance) {
if (instance == null) {
throw new RuntimeException("Instance must not be null");
}
Class clazz = instance.getClass();
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass)) {
return superClass;
}
}
return clazz;

}

/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) {
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException) {
return new IllegalArgumentException(msg, e);
} else if (e instanceof InvocationTargetException) {
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
}
return new RuntimeException(msg, e);
}

}

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

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

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;

/**
* 客户端工具类
*/
public class ServletUtils {

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

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

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

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

/**
* 获取request
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes().getRequest();
}

/**
* 获取response
*/
public static HttpServletResponse getResponse() {
return getRequestAttributes().getResponse();
}

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

public static ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}

/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String 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();
}
return null;
}

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

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

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

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

}

+ 102
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/SpringUtils.java View File

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

import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
* spring工具类 方便在非spring管理环境中获取bean
*/
@Component
public class SpringUtils implements BeanFactoryPostProcessor {

/**
* Spring应用上下文环境
*/
private static ConfigurableListableBeanFactory beanFactory;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}

/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws org.springframework.beans.BeansException
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) beanFactory.getBean(name);
}

/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*/
public static <T> T getBean(Class<T> clz) throws BeansException {
T result = (T) beanFactory.getBean(clz);
return result;
}

/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return beanFactory.containsBean(name);
}

/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return beanFactory.isSingleton(name);
}

/**
* @param name
* @return Class 注册对象的类型
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getType(name);
}

/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getAliases(name);
}

/**
* 获取aop代理对象
*
* @param invoker
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) {
return (T) AopContext.currentProxy();
}

}

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

@@ -0,0 +1,387 @@
package com.tuoheng.common.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);
}

/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
// public static String format(String template, Object... params) {
// if (isEmpty(params) || isEmpty(template)) {
// return template;
// }
// return StrFormatter.format(template, params);
// }

/**
* 字符串转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();
}

}

+ 73
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/ThreadUtils.java View File

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

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

import java.util.concurrent.*;

/**
* 线程相关工具类
*/
public class ThreadUtils {

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

/**
* sleep等待,单位为毫秒
*/
public static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
return;
}
}

/**
* 停止线程池
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
* 如果仍人超時,則強制退出.
* 另对在shutdown时线程本身被调用中断做了处理.
*/
public static void shutdownAndAwaitTermination(ExecutorService pool) {
if (pool != null && !pool.isShutdown()) {
pool.shutdown();
try {
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
logger.info("Pool did not terminate");
}
}
} catch (InterruptedException ie) {
pool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}

/**
* 打印线程异常信息
*/
public static void printException(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
try {
Future<?> future = (Future<?>) r;
if (future.isDone()) {
future.get();
}
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (t != null) {
logger.error(t.getMessage(), t);
}
}

}

+ 323
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/UploadUtils.java View File

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


import com.tuoheng.common.config.UploadFileConfig;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
* 上传文件工具类
*/
@Component
public class UploadUtils {
// 表单字段常量
public static final String FORM_FIELDS = "form_fields";
// 文件域常量
public static final String FILE_FIELDS = "file";
// 定义允许上传的文件扩展名
private Map<String, String> extMap = new HashMap<String, String>();
// 文件保存目录路径
private String uploadPath = UploadFileConfig.uploadFolder;
// 文件的目录名
private String dirName = "images";
// 上传临时路径
private static final String TEMP_PATH = "temp";
// 临时存相对路径
private String tempPath = uploadPath + TEMP_PATH;
// 单个文件最大上传大小(10M)
private long fileMaxSize = 1024 * 1024 * 10;
// 最大文件大小(100M)
private long maxSize = 1024 * 1024 * 100;
// 文件保存目录url
private String saveUrl;
// 文件最终的url包括文件名
private List<String> fileUrlList = new ArrayList<>();
// 上传文件原名
private List<String> fileNameList = new ArrayList<>();
// 表单参数
private Map<String,String> paramMap = new HashMap();

/**
* 构造函数
*/
public UploadUtils() {
// 其中images,flashs,medias,files,对应文件夹名称,对应dirName
// key文件夹名称
// value该文件夹内可以上传文件的后缀名
extMap.put("images", "gif,jpg,jpeg,png,bmp");
extMap.put("flashs", "swf,flv");
extMap.put("medias", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
extMap.put("files", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2,mp3,mp4,mp4,mov");
}

/**
* 文件上传
*
* @param request
* @return
*/
@SuppressWarnings("unchecked")
public Map<String, Object> uploadFile(HttpServletRequest request, String name) {
// 验证文件并返回错误信息
String error = this.validateFields(request, name);
// 初始化表单元素
Map<String, Object> fieldsMap = new HashMap<String, Object>();
if (error.equals("")) {
fieldsMap = this.initFields(request);
}
List<FileItem> fiList = (List<FileItem>) fieldsMap.get(UploadUtils.FILE_FIELDS);
paramMap = (Map) fieldsMap.get(UploadUtils.FORM_FIELDS);
if (fiList != null) {
for (FileItem item : fiList) {
// 上传文件并返回错误信息
error = this.saveFile(item);
}
}
// 返回结果
Map<String, Object> result = new HashMap<>();
result.put("error", error);
result.put("image", this.fileUrlList);
result.put("name", this.fileNameList);
result.put("param", this.paramMap);
return result;
}

/**
* 上传验证并初始化目录
*
* @param request
* @return
*/
private String validateFields(HttpServletRequest request, String name) {
String errorInfo = "";
// 获取内容类型
String contentType = request.getContentType();
int contentLength = request.getContentLength();
// 初始化上传路径,不存在则创建
File uploadDir = new File(uploadPath);
// 目录不存在则创建
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
if (contentType == null || !contentType.startsWith("multipart")) {
// TODO
System.out.println("请求不包含multipart/form-data流");
errorInfo = "请求不包含multipart/form-data流";
} else if (maxSize < contentLength) {
// TODO
System.out.println("上传文件大小超出文件最大大小");
errorInfo = "上传文件大小超出文件最大大小[" + maxSize + "]";
} else if (!ServletFileUpload.isMultipartContent(request)) {
// TODO
errorInfo = "请选择文件";
} else if (!uploadDir.isDirectory()) {
// TODO
errorInfo = "上传目录[" + uploadPath + "]不存在";
} else if (!uploadDir.canWrite()) {
// TODO
errorInfo = "上传目录[" + uploadPath + "]没有写权限";
} else if (!extMap.containsKey(dirName)) {
// TODO
errorInfo = "目录名不正确";
} else {
// 上传路径
uploadPath = UploadFileConfig.uploadFolder + dirName + "/" + name + "/";
// 保存目录Url
saveUrl = "/" + dirName + "/" + name + "/";

// 创建一级目录
File saveDirFile = new File(uploadPath);
if (!saveDirFile.exists()) {
saveDirFile.mkdirs();
}

// 创建二级目录(格式:年月日)
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String ymd = sdf.format(new Date());
uploadPath += ymd + "/";
saveUrl += ymd + "/";
File dirFile = new File(uploadPath);
if (!dirFile.exists()) {
dirFile.mkdirs();
}

// 创建上传临时目录
File file = new File(tempPath);
if (!file.exists()) {
file.mkdirs();
}
}
return errorInfo;
}

/**
* 处理上传内容
*
* @return
*/
// @SuppressWarnings("unchecked")
private Map<String, Object> initFields(HttpServletRequest request) {
// 存储表单字段和非表单字段
Map<String, Object> map = new HashMap<String, Object>();
// 第一步:判断request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
// 第二步:解析request
if (isMultipart) {
// 设置环境:创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 阀值,超过这个值才会写到临时目录,否则在内存中
factory.setSizeThreshold(1024 * 1024 * 10);
// 设置上传文件的临时目录
factory.setRepository(new File(tempPath));
// 核心操作类:创建一个文件上传解析器。
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置文件名称编码(解决上传"文件名"的中文乱码)
upload.setHeaderEncoding("UTF-8");
// 限制单个文件上传大小
upload.setFileSizeMax(fileMaxSize);
// 限制总上传文件大小
upload.setSizeMax(maxSize);
// 使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> items = null;
try {
items = upload.parseRequest(request);
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

// 第3步:处理uploaded items
if (items != null && items.size() > 0) {
Iterator<FileItem> iter = items.iterator();
// 文件域对象
List<FileItem> list = new ArrayList<FileItem>();
// 表单字段
Map<String, String> fields = new HashMap<String, String>();
while (iter.hasNext()) {
FileItem item = iter.next();
// 处理所有表单元素和文件域表单元素
if (item.isFormField()) {
// 如果fileitem中封装的是普通输入项的数据(输出名、值)
String name = item.getFieldName();// 普通输入项数据的名
String value = null;
try {
value = item.getString("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
fields.put(name, value);
} else {
//如果fileitem中封装的是上传文件,得到上传的文件名称
// 文件域表单元素
list.add(item);
}
}
map.put(FORM_FIELDS, fields);
map.put(FILE_FIELDS, list);
}
}
return map;
}

/**
* 保存文件
*
* @param item
* @return
*/
private String saveFile(FileItem item) {
String error = "";
String fileName = item.getName();
String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

if (item.getSize() > maxSize) { // 检查文件大小
// TODO
error = "上传文件大小超过限制";
} else if (!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(fileExt)) {// 检查扩展名
error = "上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。";
} else {
// 存储文件重命名
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String newFileName = df.format(new Date()) + new Random().nextInt(1000) + "." + fileExt;

// 新增文件原名数组(带后缀)
fileNameList.add(fileName);
// 新增值文件数组
String filePath = saveUrl + newFileName;
fileUrlList.add(filePath);

// 写入文件
try {
File uploadedFile = new File(uploadPath, newFileName);
item.write(uploadedFile);
} catch (IOException e) {
e.printStackTrace();
System.out.println("上传失败了!!!");
} catch (Exception e) {
e.printStackTrace();
}
}
return error;
}

/**
* *********************get/set方法*********************************
*/
public String getSaveUrl() {
return saveUrl;
}

public String getUploadPath() {
return uploadPath;
}

public long getMaxSize() {
return maxSize;
}

public void setMaxSize(long maxSize) {
this.maxSize = maxSize;
}

public Map<String, String> getExtMap() {
return extMap;
}

public void setExtMap(Map<String, String> extMap) {
this.extMap = extMap;
}

public String getDirName() {
return dirName;
}

public void setDirName(String dirName) {
this.dirName = dirName;
}

public String getTempPath() {
return tempPath;
}

public void setTempPath(String tempPath) {
this.tempPath = tempPath;
}

public List getfileUrlList() {
return fileUrlList;
}

public void setfileUrlList(List fileUrlList) {
this.fileUrlList = fileUrlList;
}
}

+ 186
- 0
tuoheng-common/src/main/java/com/tuoheng/common/utils/VerifyUtil.java View File

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

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
* 获取验证码工具类
*/
public class VerifyUtil {

private static Random random = new Random();
/**
* 验证码的宽
*/
private int width = 165;
/**
* 验证码的高
*/
private int height = 45;
/**
* 验证码中夹杂的干扰线数量
*/
private int lineSize = 30;
/**
* 验证码字符个数
*/
private int randomStrNum = 4;

private String randomString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ";

/**
* 字体的设置
*
* @return
*/
private Font getFont() {
return new Font("Times New Roman", Font.ROMAN_BASELINE, 40);
}

/**
* 颜色的设置
*
* @param fc
* @param bc
* @return
*/
private static Color getRandomColor(int fc, int bc) {

fc = Math.min(fc, 255);
bc = Math.min(bc, 255);

int r = fc + random.nextInt(bc - fc - 16);
int g = fc + random.nextInt(bc - fc - 14);
int b = fc + random.nextInt(bc - fc - 12);

return new Color(r, g, b);
}

/**
* 干扰线的绘制
*
* @param g
*/
private void drawLine(Graphics g) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(20);
int yl = random.nextInt(10);
g.drawLine(x, y, x + xl, y + yl);

}

/**
* 随机字符的获取
*
* @param num
* @return
*/
private String getRandomString(int num) {
num = num > 0 ? num : randomString.length();
return String.valueOf(randomString.charAt(random.nextInt(num)));
}

/**
* 字符串的绘制
*
* @param g
* @param randomStr
* @param i
* @return
*/
private String drawString(Graphics g, String randomStr, int i) {
g.setFont(getFont());
g.setColor(getRandomColor(108, 190));
String rand = getRandomString(random.nextInt(randomString.length()));
randomStr += rand;
g.translate(random.nextInt(3), random.nextInt(6));
g.drawString(rand, 40 * i + 10, 25);
return randomStr;
}


/**
* 生成随机图片
*
* @param response
*/
public void getRandomCodeImage(HttpServletResponse response) {
// BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics g = image.getGraphics();
g.fillRect(0, 0, width, height);
g.setColor(getRandomColor(105, 189));
g.setFont(getFont());
// 干扰线
for (int i = 0; i < lineSize; i++) {
drawLine(g);
}
// 随机字符
String randomStr = "";
for (int i = 0; i < randomStrNum; i++) {
randomStr = drawString(g, randomStr, i);
}
System.out.println("随机字符:" + randomStr);
g.dispose();
try {
// 将图片以png格式返回,返回的是图片
ImageIO.write(image, "PNG", response.getOutputStream());

} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 生成随机图片的base64编码字符串
*
* @return
*/
public Map<String, String> getRandomCodeBase64() {
Map<String, String> result = new HashMap<>();
// BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics g = image.getGraphics();
g.fillRect(0, 0, width, height);
g.setColor(getRandomColor(105, 189));
g.setFont(getFont());
//干扰线
for (int i = 0; i < lineSize; i++) {
drawLine(g);
}

//随机字符
String randomStr = "";
for (int i = 0; i < randomStrNum; i++) {
randomStr = drawString(g, randomStr, i);
}

g.dispose();
String base64String = "";
try {
// 直接返回图片
// 返回 base64
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "PNG", bos);

byte[] bytes = bos.toByteArray();
Base64.Encoder encoder = Base64.getEncoder();
base64String = encoder.encodeToString(bytes);

} catch (Exception e) {
e.printStackTrace();
}
result.put("randomStr", randomStr);
result.put("img", base64String);
return result;
}

}

+ 36
- 0
tuoheng-common/src/main/resources/i18n/messages.properties View File

@@ -0,0 +1,36 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功

length.not.valid=长度必须在{min}到{max}个字符之间

user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录

##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符

##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]

+ 54
- 0
tuoheng-generator/pom.xml View File

@@ -0,0 +1,54 @@
<?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要使用顶层的父模块-->
<parent>
<artifactId>tuoheng</artifactId>
<groupId>com.tuoheng</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tuoheng-generator</artifactId>
<packaging>jar</packaging>
<name>tuoheng-generator</name>
<description>Demo project for Spring Boot</description>

<!-- 依赖声明 -->
<dependencies>
<!-- 基础依赖 -->
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-common</artifactId>
</dependency>
<dependency>
<groupId>com.tuoheng</groupId>
<artifactId>tuoheng-system</artifactId>
</dependency>
<!-- MySql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-plus 代码自动生成 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.2.0</version>
</dependency>
<!-- freemarker模板引擎依赖 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

</project>

+ 78
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/config/GenConfig.java View File

@@ -0,0 +1,78 @@
package com.tuoheng.generator.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
* 代码生成器相关配置
*/
@Component
@ConfigurationProperties(prefix = "generate")
public class GenConfig {

/**
* 作者
*/
public static String author;

/**
* 生成包路径
*/
public static String packageName;

/**
* 模块名
*/
public static String moduleName;

/**
* 自动去除表前缀,默认是true
*/
public static boolean autoRemovePre;

/**
* 表前缀(类名不会包含表前缀)
*/
public static String tablePrefix;

public static String getAuthor() {
return author;
}

public void setAuthor(String author) {
GenConfig.author = author;
}

public static String getPackageName() {
return packageName;
}

public void setPackageName(String packageName) {
GenConfig.packageName = packageName;
}

public static String getModuleName() {
return moduleName;
}

public void setModuleName(String moduleName) {
GenConfig.moduleName = moduleName;
}

public static boolean getAutoRemovePre() {
return autoRemovePre;
}

public void setAutoRemovePre(boolean autoRemovePre) {
GenConfig.autoRemovePre = autoRemovePre;
}

public static String getTablePrefix() {
return tablePrefix;
}

public void setTablePrefix(String tablePrefix) {
GenConfig.tablePrefix = tablePrefix;
}

}

+ 147
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/constant/GenConstants.java View File

@@ -0,0 +1,147 @@
package com.tuoheng.generator.constant;

/**
* 代码生成通用常量
*/
public class GenConstants {

/**
* 单表(增删改查)
*/
public static final String TPL_CRUD = "crud";

/**
* 树表(增删改查)
*/
public static final String TPL_TREE = "tree";

/**
* 树编码字段
*/
public static final String TREE_CODE = "treeCode";

/**
* 树父编码字段
*/
public static final String TREE_PARENT_CODE = "treeParentCode";

/**
* 树名称字段
*/
public static final String TREE_NAME = "treeName";

/**
* 数据库字符串类型
*/
public static final String[] COLUMNTYPE_STR = {"char", "varchar", "narchar", "varchar2", "tinytext", "text",
"mediumtext", "longtext"};

/**
* 数据库时间类型
*/
public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"};

/**
* 数据库数字类型
*/
public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
"bigint", "float", "float", "double", "decimal"};

/**
* 页面不需要编辑字段
*/
public static final String[] COLUMNNAME_NOT_EDIT = {"id", "create_by", "create_time", "del_flag"};

/**
* 页面不需要显示的列表字段
*/
public static final String[] COLUMNNAME_NOT_LIST = {"id", "create_by", "create_time", "del_flag", "update_by",
"update_time"};

/**
* 页面不需要查询字段
*/
public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by",
"update_time", "remark"};

/**
* Entity基类字段
*/
public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime", "remark"};

/**
* Tree基类字段
*/
public static final String[] TREE_ENTITY = {"parentName", "parentId", "orderNum", "ancestors", "children"};

/**
* 文本框
*/
public static final String HTML_INPUT = "input";

/**
* 文本域
*/
public static final String HTML_TEXTAREA = "textarea";

/**
* 下拉框
*/
public static final String HTML_SELECT = "select";

/**
* 单选框
*/
public static final String HTML_RADIO = "radio";

/**
* 复选框
*/
public static final String HTML_CHECKBOX = "checkbox";

/**
* 日期控件
*/
public static final String HTML_DATETIME = "datetime";

/**
* 字符串类型
*/
public static final String TYPE_STRING = "String";

/**
* 整型
*/
public static final String TYPE_INTEGER = "Integer";

/**
* 长整型
*/
public static final String TYPE_LONG = "Long";

/**
* 浮点型
*/
public static final String TYPE_DOUBLE = "Double";

/**
* 高精度计算类型
*/
public static final String TYPE_BIGDECIMAL = "BigDecimal";

/**
* 时间类型
*/
public static final String TYPE_DATE = "Date";

/**
* 模糊查询
*/
public static final String QUERY_LIKE = "LIKE";

/**
* 需要
*/
public static final String REQUIRE = "1";

}

+ 20
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/controller/GenTableColumnController.java View File

@@ -0,0 +1,20 @@
package com.tuoheng.generator.controller;


import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**
* <p>
* 代码生成业务表字段 前端控制器
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
@RestController
@RequestMapping("/gentablecolumn")
public class GenTableColumnController {

}

+ 128
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/controller/GenTableController.java View File

@@ -0,0 +1,128 @@
package com.tuoheng.generator.controller;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tuoheng.common.config.CommonConfig;
import com.tuoheng.common.utils.JsonResult;
import com.tuoheng.generator.dto.GenTableDto;
import com.tuoheng.generator.entity.GenTable;
import com.tuoheng.generator.entity.GenTableColumn;
import com.tuoheng.generator.query.GenTableQuery;
import com.tuoheng.generator.service.IGenTableColumnService;
import com.tuoheng.generator.service.IGenTableService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

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

/**
* <p>
* 代码生成业务表 前端控制器
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
@RestController
@RequestMapping("/gentable")
public class GenTableController {

@Autowired
private IGenTableService genTableService;

@Autowired
private IGenTableColumnService genTableColumnService;

/**
* 获取业务表列表
*
* @param genTableQuery 查询条件
* @return
*/
@GetMapping("/index")
public JsonResult index(GenTableQuery genTableQuery) {
return genTableService.getList(genTableQuery);
}

/**
* 获取数据库表
*
* @param query 查询条件
* @return
*/
@GetMapping("/genDbTableList")
public JsonResult genDbTableList(GenTableQuery query) {
IPage<GenTable> pageData = genTableService.genDbTableList(query);
return JsonResult.success(pageData, "操作成功");
}

/**
* 导入表
*
* @param tableNames 数据表
* @return
*/
@PostMapping("/importTable")
public JsonResult importTable(@RequestBody String[] tableNames) {
// 查询表信息
List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
genTableService.importGenTable(tableList);
return JsonResult.success();
}

/**
* 获取表详情信息
*
* @param tableId 表ID
* @return
*/
@GetMapping("/getTableInfo/{tableId}")
public JsonResult getTableInfo(@PathVariable("tableId") String tableId) {
GenTable table = genTableService.selectGenTableById(Integer.valueOf(tableId));
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(Integer.valueOf(tableId));
Map<String, Object> map = new HashMap<String, Object>();
map.put("info", table);
map.put("records", list);
return JsonResult.success(map, "操作成功");
}

/**
* 更新代码生成表信息
*
* @param genTable 生成表
* @return
*/
@PutMapping("/updateGenTable")
public JsonResult updateGenTable(@Validated @RequestBody GenTable genTable) {
genTableService.validateEdit(genTable);
genTableService.updateGenTable(genTable);
return JsonResult.success();
}

/**
* 删除业务表
*
* @param tableIds 业务表ID
* @return
*/
@DeleteMapping("/delete/{tableIds}")
public JsonResult delete(@PathVariable("tableIds") Integer[] tableIds) {
return genTableService.delete(tableIds);
}

/**
* 生成代码
*
* @param genTableDto 一键生成参数
* @throws Exception
*/
@PostMapping("/batchGenCode")
public JsonResult batchGenCode(@RequestBody GenTableDto genTableDto) {
String[] tableNames = genTableDto.getTableNames().split(",");
return genTableService.generatorCode(tableNames);
}

}

+ 16
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/dto/GenTableDto.java View File

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

import lombok.Data;

/**
* 一键生成Dto
*/
@Data
public class GenTableDto {

/**
* 业务表名称(多个使用逗号“,”分隔)
*/
private String tableNames;

}

+ 153
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/entity/GenTable.java View File

@@ -0,0 +1,153 @@
package com.tuoheng.generator.entity;

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

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

import javax.validation.Valid;

/**
* <p>
* 代码生成业务表
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
@Data
@Accessors(chain = true)
public class GenTable implements Serializable {

private static final long serialVersionUID = 1L;

/**
* 表ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;

/**
* 表名称
*/
private String tableName;

/**
* 表描述
*/
private String tableComment;

/**
* 实体类名称
*/
private String className;

/**
* 使用的模板(crud单表操作 tree树表操作)
*/
private String tplCategory;

/**
* 生成包路径
*/
private String packageName;

/**
* 生成模块名
*/
private String moduleName;

/**
* 生成业务名
*/
private String businessName;

/**
* 生成功能名
*/
private String functionName;

/**
* 生成功能作者
*/
private String functionAuthor;

/**
* 其它生成选项
*/
private String options;

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

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

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

/**
* 更新人
*/
private Integer 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;

/**
* 主键信息
*/
@TableField(exist = false)
private GenTableColumn pkColumn;

/**
* 表列信息
*/
@Valid
@TableField(exist = false)
private List<GenTableColumn> columns;

/**
* 树编码字段
*/
@TableField(exist = false)
private String treeCode;

/**
* 树父编码字段
*/
@TableField(exist = false)
private String treeParentCode;

/**
* 树名称字段
*/
@TableField(exist = false)
private String treeName;


}

+ 148
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/entity/GenTableColumn.java View File

@@ -0,0 +1,148 @@
package com.tuoheng.generator.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;

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

import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;

/**
* <p>
* 代码生成业务表字段
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
@Data
public class GenTableColumn implements Serializable {

private static final long serialVersionUID = 1L;

/**
* 表ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;

/**
* 归属表编号
*/
private Integer tableId;

/**
* 列名称
*/
private String columnName;

/**
* 列描述
*/
private String columnComment;

/**
* 列类型
*/
private String columnType;

/**
* JAVA类型
*/
private String javaType;

/**
* JAVA字段名
*/
private String javaField;

/**
* 是否主键(1是)
*/
private Integer isPk;

/**
* 是否自增(1是)
*/
private String isIncrement;

/**
* 是否必填(1是)
*/
private String isRequired;

/**
* 是否为插入字段(1是)
*/
private String isInsert;

/**
* 是否编辑字段(1是)
*/
private String isEdit;

/**
* 是否列表字段(1是)
*/
private String isList;

/**
* 是否查询字段(1是)
*/
private String isQuery;

/**
* 查询方式(等于、不等于、大于、小于、范围)
*/
private String queryType;

/**
* 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)
*/
private String htmlType;

/**
* 字典类型
*/
private String dictType;

/**
* 排序
*/
private Integer sort;

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

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

/**
* 更新人
*/
private Integer 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;


}

+ 50
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/mapper/GenTableColumnMapper.java View File

@@ -0,0 +1,50 @@
package com.tuoheng.generator.mapper;

import com.tuoheng.generator.entity.GenTableColumn;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import java.util.List;

/**
* <p>
* 代码生成业务表字段 Mapper 接口
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
public interface GenTableColumnMapper extends BaseMapper<GenTableColumn> {

/**
* 根据表名查询列信息
*
* @param tableName 数据表名
* @return
*/
List<GenTableColumn> selectDbTableColumnsByName(String tableName);

/**
* 插入数据表列
*
* @param TableColumn 数据表列
* @return
*/
int insertGenTableColumn(GenTableColumn TableColumn);

/**
* 获取表字段列表
*
* @param tableId 表ID
* @return
*/
List<GenTableColumn> selectGenTableColumnListByTableId(Integer tableId);

/**
* 修改业务表字段
*
* @param TableColumn 表字段
* @return
*/
int updateGenTableColumn(GenTableColumn TableColumn);

}

+ 80
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/mapper/GenTableMapper.java View File

@@ -0,0 +1,80 @@
package com.tuoheng.generator.mapper;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tuoheng.generator.entity.GenTable;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tuoheng.generator.query.GenTableQuery;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
* <p>
* 代码生成业务表 Mapper 接口
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
public interface GenTableMapper extends BaseMapper<GenTable> {

/**
* 获取业务表列表
*
* @param page 分页信息
* @param param 参数
* @return
*/
IPage<GenTable> selectGenTableList(IPage<GenTable> page, @RequestParam("param") GenTableQuery param);

/**
* 获取数据库表
*
* @param page 分页信息
* @param param 查询条件
* @return
*/
IPage<GenTable> selectDbTableList(IPage<GenTable> page, @RequestParam("param") GenTableQuery param);

/**
* 根据表明获取数据库列表
*
* @param tableNames 数据库名
* @return
*/
List<GenTable> selectDbTableListByNames(String[] tableNames);

/**
* 插入数据表
*
* @param genTable 待生成数据表
* @return
*/
int insertGenTable(GenTable genTable);

/**
* 根据表ID获取表信息
*
* @param tableId 表ID
* @return
*/
GenTable selectGenTableById(Integer tableId);

/**
* 修改业务表信息
*
* @param genTable 业务表
* @return
*/
int updateGenTable(GenTable genTable);


/**
* 根据表名查询业务表
*
* @param tableName 表名
* @return
*/
GenTable selectGenTableByName(String tableName);

}

+ 31
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/query/GenTableQuery.java View File

@@ -0,0 +1,31 @@
package com.tuoheng.generator.query;

import lombok.Data;

/**
* 表生成查询条件
*/
@Data
public class GenTableQuery {

/**
* 页码
*/
private Integer page;

/**
* 每页数
*/
private Integer limit;

/**
* 表名
*/
private String tableName;

/**
* 表描述
*/
private String tableComment;

}

+ 26
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/service/IGenTableColumnService.java View File

@@ -0,0 +1,26 @@
package com.tuoheng.generator.service;

import com.tuoheng.generator.entity.GenTableColumn;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.List;

/**
* <p>
* 代码生成业务表字段 服务类
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
public interface IGenTableColumnService extends IService<GenTableColumn> {

/**
* 查询表字段信息
*
* @param tableId 表ID
* @return
*/
List<GenTableColumn> selectGenTableColumnListByTableId(Integer tableId);

}

+ 90
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/service/IGenTableService.java View File

@@ -0,0 +1,90 @@
package com.tuoheng.generator.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tuoheng.common.utils.JsonResult;
import com.tuoheng.generator.entity.GenTable;
import com.baomidou.mybatisplus.extension.service.IService;
import com.tuoheng.generator.query.GenTableQuery;

import java.util.List;

/**
* <p>
* 代码生成业务表 服务类
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
public interface IGenTableService extends IService<GenTable> {

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

/**
* 获取数据库表
*
* @param query 查询条件
* @return
*/
IPage<GenTable> genDbTableList(GenTableQuery query);

/**
* 查询据库列表
*
* @param tableNames 表数组
* @return
*/
List<GenTable> selectDbTableListByNames(String[] tableNames);

/**
* 导入表结构
*
* @param tableList 导入表列表
*/
void importGenTable(List<GenTable> tableList);

/**
* 根据表ID获取表信息
*
* @param tableId 表ID
* @return
*/
GenTable selectGenTableById(Integer tableId);

/**
* 业务表保存参数校验
*
* @param Table 生成表
*/
void validateEdit(GenTable Table);

/**
* 更新业务表信息
*
* @param Table 业务表
*/
void updateGenTable(GenTable Table);

/**
* 生成代码
*
* @param tableNames 数据表
* @return
*/
JsonResult generatorCode(String[] tableNames);

/**
* 删除记录
*
* @param ids 业务表ID
* @return
*/
JsonResult delete(Integer[] ids);

}

+ 37
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/service/impl/GenTableColumnServiceImpl.java View File

@@ -0,0 +1,37 @@
package com.tuoheng.generator.service.impl;

import com.tuoheng.generator.entity.GenTableColumn;
import com.tuoheng.generator.mapper.GenTableColumnMapper;
import com.tuoheng.generator.service.IGenTableColumnService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
* <p>
* 代码生成业务表字段 服务实现类
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
@Service
public class GenTableColumnServiceImpl extends ServiceImpl<GenTableColumnMapper, GenTableColumn> implements IGenTableColumnService {

@Autowired
private GenTableColumnMapper genTableColumnMapper;

/**
* 获取表字段信息
*
* @param tableId 表ID
* @return
*/
@Override
public List<GenTableColumn> selectGenTableColumnListByTableId(Integer tableId) {
return genTableColumnMapper.selectGenTableColumnListByTableId(tableId);
}

}

+ 227
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/service/impl/GenTableServiceImpl.java View File

@@ -0,0 +1,227 @@
package com.tuoheng.generator.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tuoheng.common.exception.CustomException;
import com.tuoheng.common.utils.DateUtils;
import com.tuoheng.common.utils.JsonResult;
import com.tuoheng.common.utils.StringUtils;
import com.tuoheng.generator.constant.GenConstants;
import com.tuoheng.generator.entity.GenTable;
import com.tuoheng.generator.entity.GenTableColumn;
import com.tuoheng.generator.mapper.GenTableColumnMapper;
import com.tuoheng.generator.mapper.GenTableMapper;
import com.tuoheng.generator.query.GenTableQuery;
import com.tuoheng.generator.service.IGenTableService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tuoheng.generator.utils.CodeGenerateUtils;
import com.tuoheng.generator.utils.GenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
* <p>
* 代码生成业务表 服务实现类
* </p>
*
* @author 拓恒
* @since 2020-11-06
*/
@Service
public class GenTableServiceImpl extends ServiceImpl<GenTableMapper, GenTable> implements IGenTableService {

@Autowired
private GenTableMapper genTableMapper;

@Autowired
private GenTableColumnMapper genTableColumnMapper;

@Autowired
private CodeGenerateUtils codeGenerateUtils;

/**
* 获取业务表列表
*
* @param genTableQuery 查询条件
* @return
*/
@Override
public JsonResult getList(GenTableQuery genTableQuery) {
IPage<GenTable> page = new Page<>(genTableQuery.getPage(), genTableQuery.getLimit());
IPage<GenTable> pageData = genTableMapper.selectGenTableList(page, genTableQuery);
return JsonResult.success(pageData, "操作成功");
}

/**
* 获取数据库表
*
* @param query 查询条件
* @return
*/
@Override
public IPage<GenTable> genDbTableList(GenTableQuery query) {
IPage<GenTable> page = new Page<>(query.getPage(), query.getLimit());
return genTableMapper.selectDbTableList(page, query);
}

/**
* 查询据库列表
*
* @param tableNames 表数组
* @return
*/
@Override
public List<GenTable> selectDbTableListByNames(String[] tableNames) {
return genTableMapper.selectDbTableListByNames(tableNames);
}

/**
* 导入表结构
*
* @param tableList 导入表列表
*/
@Transactional
@Override
public void importGenTable(List<GenTable> tableList) {
String operName = "内部人员";//SecurityUtils.getUsername();
for (GenTable table : tableList) {
try {
String tableName = table.getTableName();
GenUtils.initTable(table, operName);
int row = genTableMapper.insertGenTable(table);
if (row > 0) {
// 保存列信息
List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
for (GenTableColumn column : genTableColumns) {
GenUtils.initColumnField(column, table);
genTableColumnMapper.insertGenTableColumn(column);
}
}
} catch (Exception e) {
log.error("表名 " + table.getTableName() + " 导入失败:", e);
}
}
}

/**
* 根据表ID获取表信息
*
* @param tableId 表ID
* @return
*/
@Override
public GenTable selectGenTableById(Integer tableId) {
GenTable genTable = genTableMapper.selectGenTableById(tableId);
setTableFromOptions(genTable);
return genTable;
}

/**
* 设置代码生成其他选项
*
* @param genTable 待生成表
*/
public void setTableFromOptions(GenTable genTable) {
JSONObject paramsObj = JSONObject.parseObject(genTable.getOptions());
if (StringUtils.isNotNull(paramsObj)) {
String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
String treeName = paramsObj.getString(GenConstants.TREE_NAME);
genTable.setTreeCode(treeCode);
genTable.setTreeParentCode(treeParentCode);
genTable.setTreeName(treeName);
}
}

/**
* 验证编辑信息
*
* @param genTable 生成表
*/
@Override
public void validateEdit(GenTable genTable) {
if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
String options = "{}";//JSON.toJSONString(genTable.getParams());
JSONObject paramsObj = JSONObject.parseObject(options);
if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) {
throw new CustomException("树编码字段不能为空");
} else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) {
throw new CustomException("树父编码字段不能为空");
} else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) {
throw new CustomException("树名称字段不能为空");
}
}
}

/**
* 编辑业务表生成信息
*
* @param genTable 业务表
*/
@Override
public void updateGenTable(GenTable genTable) {
String options = "{}";//JSON.toJSONString(genTable.getParams());
genTable.setOptions(options);
int row = genTableMapper.updateGenTable(genTable);
if (row > 0) {
for (GenTableColumn cenTableColumn : genTable.getColumns()) {
genTableColumnMapper.updateGenTableColumn(cenTableColumn);
}
}
}

/**
* 生成数据表
*
* @param tableNames 数据表
* @return
*/
@Override
public JsonResult generatorCode(String[] tableNames) {
Integer totalNum = 0;
for (String tableName : tableNames) {
// 查询表信息
GenTable tableInfo = genTableMapper.selectGenTableByName(tableName);
try {
// 生成文件
codeGenerateUtils.generateFile(tableInfo.getTableName(), tableInfo.getTableComment());
totalNum++;
} catch (Exception e) {

}
}
return JsonResult.success(String.format("本地共生成【%s】个模块", totalNum));
}

/**
* 删除业务表
*
* @param ids 业务表ID
* @return
*/
@Override
public JsonResult delete(Integer[] ids) {
Integer totalNum = 0;
for (Integer id : ids) {
GenTable entity = genTableMapper.selectById(id);
if (entity == null) {
return JsonResult.error("业务表不存在");
}
entity.setUpdateUser(0);
entity.setUpdateTime(DateUtils.now());
entity.setMark(0);
boolean result = updateById(entity);
if (result) {
totalNum++;
}
}
if (totalNum != ids.length) {
return JsonResult.error("删除失败");
}
return JsonResult.success("删除成功");
}
}

+ 916
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/utils/CodeGenerateUtils.java View File

@@ -0,0 +1,916 @@
package com.tuoheng.generator.utils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tuoheng.common.utils.CommonUtils;
import com.tuoheng.common.utils.DateUtils;
import com.tuoheng.common.utils.StringUtils;
import com.tuoheng.system.entity.Menu;
import com.tuoheng.system.mapper.MenuMapper;
import com.tuoheng.system.utils.ShiroUtils;
import freemarker.template.Template;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@Component
@Data
public class CodeGenerateUtils {

@Autowired
private MenuMapper menuMapper;

/**
* 作者
*/
@Value("${generate.author}")
private String author = "";
/**
* 创建时间
*/
private String createTime = DateUtils.getDate();
/**
* 数据表名
*/
private String tableName = "";
/**
* 数据表前缀
*/
@Value("${generate.tablePrefix}")
private String tablePredix = "";
/**
* 表描述
*/
private String tableAnnotation = "";
/**
* 包名
*/
@Value("${generate.packageName}")
private String packageName = "";
/**
* 模块名
*/
@Value("${generate.moduleName}")
private String moduleName = "";
/**
* 自动去除表前缀
*/
@Value("${generate.autoRemovePre}")
private boolean autoRemovePre = false;
/**
* 数据库连接池
*/
@Value("${spring.datasource.url}")
private String url = "";
/**
* 数据库用户名
*/
@Value("${spring.datasource.username}")
private String username = "";
/**
* 数据库密码
*/
@Value("${spring.datasource.password}")
private String password = "";
/**
* 数据库驱动
*/
private String driver = "com.mysql.cj.jdbc.Driver";
/**
* 项目根目录
*/
String projectPath = System.getProperty("user.dir");
private String targetPath = "";
/**
* 实体对象名
*/
private String entityName = "";

/**
* 连接数据库
*
* @return
* @throws Exception
*/
public Connection getConnection() throws Exception {
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password);
return connection;
}

// /**
// * 程序主入口
// *
// * @param args
// * @throws Exception
// */
// public static void main(String[] args) throws Exception {
// CodeGenerateUtils codeGenerateUtils = new CodeGenerateUtils();
// codeGenerateUtils.generateFile("sys_demo", "演示");
// }

/**
* 根据模板创建文件
*
* @throws Exception
*/
public void generateFile(String tableName, String tableAnnotation) throws Exception {
try {
// 数据表名
this.tableName = tableName;
// 数据表描述
this.tableAnnotation = tableAnnotation;
// 实体对象名
if (this.autoRemovePre) {
this.entityName = replaceUnderLineAndUpperCase(tableName.replace(this.tablePredix, ""));
} else {
this.entityName = replaceUnderLineAndUpperCase(tableName);
}
// 目标文件路径
String[] packageArr = packageName.split("\\.");
targetPath = projectPath + "/" + moduleName + "/src/main/java/" + StringUtils.join(packageArr, "/");

// 获取数据表信息
Connection connection = getConnection();
DatabaseMetaData databaseMetaData = connection.getMetaData();
ResultSet resultSet = databaseMetaData.getColumns(connection.getCatalog(), "%", tableName, "%");

// 获取数据表列信息
Map<String, Object> dataMap = getColumnsList(resultSet);

/**
* 生成实体Entity文件
*/
generateEntityFile(dataMap);
/**
* 生成Mapper文件
*/
generateMapperFile();
/**
* 生成Dao文件
*/
generateDaoFile();
/**
* 生成查询条件文件
*/
generateQueryFile(dataMap);
/**
* 生成服务类接口文件
*/
generateIServiceFile(dataMap);
/**
* 生成服务类接口实现文件
*/
generateServiceImplFile(dataMap);
/**
* 生成实体列表Vo
*/
generateEntityListVoFile(dataMap);
/**
* 生成实体表单Vo
*/
generateEntityInfoVoFile(dataMap);
/**
* 生成模块常亮
*/
generateConstantFile(dataMap);
/**
* 生成控制器
*/
generateControllerFile(dataMap);
/**
* 生成Vue文件
*/
generateVueFile(dataMap);
/**
* 生成菜单权限
*/
generatePermission(entityName);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {

}
}

/**
* 生成实体对象Entity.java文件
*
* @param dataMap 参数
* @throws Exception
*/
private void generateEntityFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/entity/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = ".java";
// 完整的文件路径
String filePath = path + entityName + suffix;
// 模板文件
String templateName = "Entity.ftl";
File entityFile = new File(filePath);
generateFileByTemplate(templateName, entityFile, dataMap);
}

/**
* 生成Mapper.xml文件
*
* @throws Exception
*/
private void generateMapperFile() throws Exception {
// 文件路径
String path = projectPath + "/" + moduleName + "/src/main/resources/mapper/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = "Mapper.xml";
// 完整的文件路径
String filePath = path + entityName + suffix;
// 模板文件
String templateName = "Mapper.ftl";
File mapperFile = new File(filePath);
Map<String, Object> dataMap = new HashMap<>();
generateFileByTemplate(templateName, mapperFile, dataMap);
}

/**
* 生成Dao.java文件
*
* @throws Exception
*/
private void generateDaoFile() throws Exception {
// 文件路径
String path = targetPath + "/mapper/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = "Mapper.java";
// 完整的文件路径
String filePath = path + entityName + suffix;
// 模板文件
String templateName = "Dao.ftl";
File daoFile = new File(filePath);
Map<String, Object> dataMap = new HashMap<>();
generateFileByTemplate(templateName, daoFile, dataMap);
}

/**
* 生成Query.java查询文件
*
* @param dataMap 参数
* @throws Exception
*/
private void generateQueryFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/query/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = "Query.java";
// 完整的文件路径
String filePath = path + entityName + suffix;
// 模板文件
String templateName = "Query.ftl";
File queryFile = new File(filePath);
generateFileByTemplate(templateName, queryFile, dataMap);
}

/**
* 生成服务接口文件
*
* @throws Exception
*/
private void generateIServiceFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/service/";
// 初始化文件路径
initFileDir(path);
// 文件前缀
String prefix = "I";
// 文件后缀
String suffix = "Service.java";
// 完整的文件路径
String filePath = path + prefix + entityName + suffix;
// 模板文件
String templateName = "IService.ftl";
File serviceFile = new File(filePath);
generateFileByTemplate(templateName, serviceFile, dataMap);
}

/**
* 生成服务类实现文件
*
* @throws Exception
*/
private void generateServiceImplFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/service/impl/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = "ServiceImpl.java";
// 完整的文件路径
String filePath = path + entityName + suffix;
// 模板文件
String templateName = "ServiceImpl.ftl";
File serviceImplFile = new File(filePath);
generateFileByTemplate(templateName, serviceImplFile, dataMap);
}

/**
* 生成列表ListVo文件
*
* @param dataMap 参数
* @throws Exception
*/
private void generateEntityListVoFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/vo/" + entityName.toLowerCase() + "/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = ".java";
// 完整的文件路径
String filePath = path + entityName + "ListVo" + suffix;
// 模板文件
String templateName = "EntityListVo.ftl";
File listVoFile = new File(filePath);
generateFileByTemplate(templateName, listVoFile, dataMap);
}

/**
* 生成表单InfoVo文件
*
* @param dataMap 参数
* @throws Exception
*/
private void generateEntityInfoVoFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/vo/" + entityName.toLowerCase() + "/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = ".java";
// 完整的文件路径
String filePath = path + entityName + "InfoVo" + suffix;
// 模板文件
String templateName = "EntityInfoVo.ftl";
File infoVoFile = new File(filePath);
generateFileByTemplate(templateName, infoVoFile, dataMap);
}

/**
* 生成模块常量
*
* @param dataMap 参数
* @throws Exception
*/
private void generateConstantFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/constant/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = "Constant.java";
// 完整的文件路径
String filePath = path + entityName + suffix;
// 模板文件
String templateName = "Constant.ftl";
File controllerFile = new File(filePath);
generateFileByTemplate(templateName, controllerFile, dataMap);
}

/**
* 生成控制器文件
*
* @throws Exception
*/
private void generateControllerFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = targetPath + "/controller/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = "Controller.java";
// 完整的文件路径
String filePath = path + entityName + suffix;
// 模板文件
String templateName = "Controller.ftl";
File controllerFile = new File(filePath);
generateFileByTemplate(templateName, controllerFile, dataMap);
}

/**
* 生成Vue文件
*
* @param dataMap 列数据源
* @throws Exception
*/
private void generateVueFile(Map<String, Object> dataMap) throws Exception {
// 文件路径
String path = projectPath + "/tuoheng-ui/src/views/system/" + entityName.toLowerCase() + "/";
// 初始化文件路径
initFileDir(path);
// 文件后缀
String suffix = "index.vue";
// 完整的文件路径
String filePath = path + suffix;
// 模板文件
String templateName = "Index.vue.ftl";
File entityFile = new File(filePath);

List<ColumnClass> columnClasses = (List<ColumnClass>) dataMap.get("model_column");
List<ColumnClass> arrayList = new ArrayList<>();
List<ColumnClass> tempList = new ArrayList<>();
List<ColumnClass> rowList = new ArrayList<>();
for (ColumnClass columnClass : columnClasses) {
if (columnClass.getChangeColumnName().equals("CreateUser")) {
continue;
}
if (columnClass.getChangeColumnName().equals("CreateTime")) {
continue;
}
if (columnClass.getChangeColumnName().equals("UpdateUser")) {
continue;
}
if (columnClass.getChangeColumnName().equals("UpdateTime")) {
continue;
}
if (columnClass.getChangeColumnName().equals("Mark")) {
continue;
}
// 图片
if (columnClass.getColumnName().contains("cover")
|| columnClass.getColumnName().contains("avatar")
|| columnClass.getColumnName().contains("image")
|| columnClass.getColumnName().contains("logo")
|| columnClass.getColumnName().contains("pic")) {
tempList.add(columnClass);
continue;
}
// 单行显示常用字段处理
if (columnClass.getColumnName().contains("note")
|| columnClass.getColumnName().contains("remark")
|| columnClass.getColumnName().contains("content")
|| columnClass.getColumnName().contains("description")
|| columnClass.getColumnName().contains("intro")) {
rowList.add(columnClass);
continue;
}
arrayList.add(columnClass);
}
if (arrayList.size() + rowList.size() + tempList.size() > 20) {
List<List<ColumnClass>> columnClassesList = CommonUtils.split(arrayList, 2);
if (tempList.size() > 0) {
columnClassesList.add(0, tempList);
}
if (rowList.size() > 0) {
List<List<ColumnClass>> arrayColumnList = CommonUtils.split(rowList, 1);
arrayColumnList.forEach(item -> {
columnClassesList.add(item);
});
}
dataMap.put("model_column", columnClassesList);
dataMap.put("is_split", true);
} else {
dataMap.put("is_split", false);
}
generateFileByTemplate(templateName, entityFile, dataMap);
}

/**
* 生成权限节点
*
* @param entityName 实体名称
*/
private void generatePermission(String entityName) {
// 查询菜单是否存在
Menu entity = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPath, String.format("/system/%s", entityName.toLowerCase()))
.eq(Menu::getMark, 1)
.last("limit 1"));

Integer result = 0;
if (entity != null) {
// 更新
entity.setTitle(tableAnnotation);
entity.setPath(String.format("/system/%s", entityName.toLowerCase()));
entity.setComponent(String.format("/system/%s", entityName.toLowerCase()));
entity.setPermission(String.format("sys:%s:view", entityName.toLowerCase()));
entity.setUpdateUser(ShiroUtils.getUserId());
entity.setUpdateTime(DateUtils.now());
result = menuMapper.updateById(entity);
} else {
// 创建
entity = new Menu();
entity.setTitle(tableAnnotation);
entity.setIcon("el-icon-_setting");
entity.setPath(String.format("/system/%s", entityName.toLowerCase()));
entity.setComponent(String.format("/system/%s", entityName.toLowerCase()));
entity.setPermission(String.format("sys:%s:view", entityName.toLowerCase()));
entity.setPid(158); // 系统工具菜单ID
entity.setType(0);
entity.setStatus(1);
entity.setSort(5);
entity.setTarget("_self");
entity.setCreateUser(ShiroUtils.getUserId());
entity.setCreateTime(DateUtils.now());
result = menuMapper.insert(entity);
}
if (result == 1) {
// 创建或更新权限节点
String[] strings = entity.getPath().split("/");
// 模块名称
String moduleName = strings[strings.length - 1];
// 目标标题
String moduleTitle = entity.getTitle().replace("管理", "");
// 遍历权限节点
Integer[] permissionList = new Integer[]{1, 5, 10, 15, 25};
for (Integer item : permissionList) {
Menu funcInfo = new Menu();
funcInfo.setPid(entity.getId());
funcInfo.setType(1);
funcInfo.setStatus(1);
funcInfo.setSort(item);
funcInfo.setTarget(entity.getTarget());
if (item.equals(1)) {
// 查看
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle(String.format("查询%s", moduleTitle));
funcInfo.setPermission(String.format("sys:%s:index", moduleName));
} else if (item.equals(5)) {
// 添加
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle(String.format("添加%s", moduleTitle));
funcInfo.setPermission(String.format("sys:%s:add", moduleName));
} else if (item.equals(10)) {
// 修改
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle(String.format("修改%s", moduleTitle));
funcInfo.setPermission(String.format("sys:%s:edit", moduleName));
} else if (item.equals(15)) {
// 删除
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle(String.format("删除%s", moduleTitle));
funcInfo.setPermission(String.format("sys:%s:delete", moduleName));
} else if (item.equals(20)) {
// 状态
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("设置状态");
funcInfo.setPermission(String.format("sys:%s:status", moduleName));
} else if (item.equals(25)) {
// 批量删除
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("批量删除");
funcInfo.setPermission(String.format("sys:%s:dall", moduleName));
} else if (item.equals(30)) {
// 全部展开
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("全部展开");
funcInfo.setPermission(String.format("sys:%s:expand", moduleName));
} else if (item.equals(35)) {
// 全部折叠
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("全部折叠");
funcInfo.setPermission(String.format("sys:%s:collapse", moduleName));
} else if (item.equals(40)) {
// 添加子级
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("添加子级");
funcInfo.setPermission(String.format("sys:%s:addz", moduleName));
} else if (item.equals(45)) {
// 导出数据
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("导出数据");
funcInfo.setPermission(String.format("sys:%s:export", moduleName));
} else if (item.equals(50)) {
// 导入数据
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("导入数据");
funcInfo.setPermission(String.format("sys:%s:import", moduleName));
} else if (item.equals(55)) {
// 分配权限
Menu menuInfo = menuMapper.selectOne(new LambdaQueryWrapper<Menu>()
.eq(Menu::getPid, entity.getId())
.eq(Menu::getType, 1)
.eq(Menu::getSort, item)
.eq(Menu::getMark, 1)
.last("limit 1"));
if (menuInfo != null) {
funcInfo.setId(menuInfo.getId());
funcInfo.setUpdateUser(ShiroUtils.getUserId());
funcInfo.setUpdateTime(DateUtils.now());
}
funcInfo.setTitle("分配权限");
funcInfo.setPermission(String.format("sys:%s:permission", moduleName));
}
if (StringUtils.isEmpty(funcInfo.getTitle())) {
continue;
}
if (StringUtils.isNull(funcInfo.getId())) {
// 创建
menuMapper.insert(funcInfo);
} else {
// 更新
menuMapper.updateById(funcInfo);
}
}
}
}

/**
* 生成模板文件
*
* @param templateName 模板名称
* @param file 生成文件
* @param dataMap 生成参数
* @throws Exception
*/
private void generateFileByTemplate(String templateName, File file, Map<String, Object> dataMap) throws Exception {
Template template = FreeMarkerUtils.getTemplate(templateName);
FileOutputStream fos = new FileOutputStream(file);
dataMap.put("tableName", tableName);
dataMap.put("entityName", entityName);
dataMap.put("author", author);
dataMap.put("date", createTime);
dataMap.put("packageName", packageName);
dataMap.put("tableAnnotation", tableAnnotation);
Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
template.process(dataMap, out);
}

/**
* 获取数据表列信息
*
* @param resultSet
* @return
* @throws IOException
*/
private Map<String, Object> getColumnsList(ResultSet resultSet) throws IOException {
// 初始化Map对象
Map<String, Object> dataMap = new HashMap<>();
try {
// 获取列信息
List<ColumnClass> columnClassList = new ArrayList<>();
ColumnClass columnClass = null;
boolean hasPid = false;
boolean columnNumberValue = false;
while (resultSet.next()) {
//id字段略过
if (resultSet.getString("COLUMN_NAME").equals("id")) {
continue;
}
// 判断是否存在pid
if (resultSet.getString("COLUMN_NAME").equals("pid")) {
hasPid = true;
}
columnClass = new ColumnClass();
//获取字段名称
columnClass.setColumnName(resultSet.getString("COLUMN_NAME"));
//获取字段类型
columnClass.setColumnType(resultSet.getString("TYPE_NAME"));
//转换字段名称,如 sys_name 变成 SysName
columnClass.setChangeColumnName(replaceUnderLineAndUpperCase(resultSet.getString("COLUMN_NAME")));
//字段在数据库的注释
String remarks = resultSet.getString("REMARKS");
columnClass.setColumnComment(remarks);
// 注解分析
if (remarks.contains(":") || remarks.contains(":")) {
// 获取数字
String regets = ":|:|\\s";
//在分割的时候顺带把空格给去掉,data的格式基本为: 18:00
String[] times = remarks.split(regets);
// 标题描述
remarks = times[0];
Map<String, String> map = new HashMap<>();
List<String> columnValue = new ArrayList<>();
List<String> columnValue2 = new ArrayList<>();
Map<Integer, String> columnValueList = new HashMap<>();
for (int i = 1; i < times.length; i++) {
if (StringUtils.isEmpty(times[i])) {
continue;
}
if (times[i].contains("=")) {
String[] item = times[i].split("=");
System.out.println("Key:" + item[0] + " " + "Val:" + item[1]);
map.put(item[0], item[1]);
columnValue.add(String.format("'%s'", item[1]));
columnValue2.add(String.format("%s", item[1]));
columnValueList.put(Integer.valueOf(item[0]), item[1]);
columnNumberValue = false;
} else {
String key = Pattern.compile("[^0-9]").matcher(times[i]).replaceAll("").trim();
String value = times[i].replaceAll(key, "").trim();
System.out.println("Key:" + key + " " + "Val:" + value);
map.put(key, value);
columnValue.add(String.format("'%s'", value));
columnValue2.add(String.format("%s", value));
columnValueList.put(Integer.valueOf(key), value);
columnNumberValue = true;
}
}
columnClass.setHasColumnCommentValue(true);
columnClass.setColumnCommentName(remarks);
columnClass.setColumnCommentValue(map);
columnClass.setColumnNumberValue(columnNumberValue);
// 列值
if ((columnClass.getColumnName().equals("status") && columnValue2.size() == 2) || columnClass.getColumnName().startsWith("is_")) {
columnClass.setColumnSwitchValue(StringUtils.join(columnValue2, "|"));
columnClass.setColumnSwitch(true);
} else {
columnClass.setColumnSwitch(false);
}
columnClass.setColumnValue(StringUtils.join(columnValue, ","));
columnClass.setColumnValueList(columnValueList);
}
// 判断是否是图片字段
if (columnClass.getColumnName().contains("cover")
|| columnClass.getColumnName().contains("avatar")
|| columnClass.getColumnName().contains("image")
|| columnClass.getColumnName().contains("logo")
|| columnClass.getColumnName().contains("pic")) {
// 设置图片字段标识
columnClass.setColumnImage(true);
}
// 判断是否是多行文本字段
if (columnClass.getColumnName().contains("note")
|| columnClass.getColumnName().contains("remark")
|| columnClass.getColumnName().contains("content")
|| columnClass.getColumnName().contains("description")
|| columnClass.getColumnName().contains("intro")) {
// 设置多行文本标识
columnClass.setColumnTextArea(true);
}
columnClassList.add(columnClass);
}
dataMap.put("model_column", columnClassList);
dataMap.put("hasPid", hasPid);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return dataMap;
}

/**
* 根据路径创建文件夹
*
* @param path 路径
*/
private void initFileDir(String path) {
// 文件路径
File file = new File(path);
// 判断文件路径是否存在
if (!file.exists()) {
// 创建文件路径
file.mkdirs();
}
}

/**
* 字符串转换函数
* 如:sys_name 变成 SysName
*
* @param str 字符串
* @return
*/
public String replaceUnderLineAndUpperCase(String str) {
StringBuffer sb = new StringBuffer();
sb.append(str);
int count = sb.indexOf("_");
while (count != 0) {
int num = sb.indexOf("_", count);
count = num + 1;
if (num != -1) {
char ss = sb.charAt(count);
char ia = (char) (ss - 32);
sb.replace(count, count + 1, ia + "");
}
}
String result = sb.toString().replaceAll("_", "");
return StringUtils.capitalize(result);
}

}

+ 140
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/utils/CodeGenerator.java View File

@@ -0,0 +1,140 @@
package com.tuoheng.generator.utils;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
* 代码生成类
*
* @author 牧羊人
* @date 2019/11/28
*/
public class CodeGenerator {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}

public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();

// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/tuoheng-admin/src/main/java");
gc.setAuthor("拓恒");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);

// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/tuoheng_hhz_tenant?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("");
mpg.setDataSource(dsc);

// 包配置
PackageConfig pc = new PackageConfig();
// pc.setModuleName(scanner("模块名"));
// pc.setModuleName("university");
// pc.setParent("com.think");
pc.setParent("com.tuoheng.admin");
mpg.setPackageInfo(pc);

// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};

// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";

// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/tuoheng-admin/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录");
return false;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);

// 配置模板
TemplateConfig templateConfig = new TemplateConfig();

// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();

templateConfig.setXml(null);
mpg.setTemplate(templateConfig);

// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setSuperEntityClass("com.tuoheng.common.common.BaseEntity");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
strategy.setSuperControllerClass("com.tuoheng.common.common.BaseController");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
// strategy.setTablePrefix(pc.getModuleName() + "_");
strategy.setTablePrefix("th_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}

+ 89
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/utils/ColumnClass.java View File

@@ -0,0 +1,89 @@
package com.tuoheng.generator.utils;

import lombok.Data;

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

/**
* 数据表列
*/
@Data
public class ColumnClass {

/**
* 数据库字段名称
**/
private String columnName;

/**
* 数据库字段类型
**/
private String columnType;

/**
* 数据库字段首字母小写且去掉下划线字符串
**/
private String changeColumnName;

/**
* 数据库字段注释
**/
private String columnComment;

/**
* 是否有注解值
*/
private boolean hasColumnCommentValue;

/**
* 是否选择开关
*/
private boolean columnSwitch;

/**
* 数据库字段注释(仅包含名称)
**/
private String columnCommentName;

/**
* 数据库字段注解值
*/
private Map<String, String> columnCommentValue = new HashMap<>();

/**
* 字段值(如:1淘宝 2京东 3拼多多,需转换成:1=淘宝,2=京东,3=拼多多)
*/
private String columnValue;

/**
* 字段值列表
*/
private Map<Integer, String> columnValueList;

/**
* 字段配置至是否是数字(特殊情况下,值不一定是数字,如:hidden=隐藏)
*/
private boolean columnNumberValue;

/**
* 字段值开关(如:淘宝|京东)
*/
private String columnSwitchValue;

/**
* 字段默认值
*/
private String columnDefaultValue;

/**
* 是否是图片字段
*/
private boolean columnImage;

/**
* 是否是多行文本
*/
private boolean columnTextArea;

}

+ 41
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/utils/FreeMarkerUtils.java View File

@@ -0,0 +1,41 @@
package com.tuoheng.generator.utils;

import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

import java.io.IOException;

/**
* FreeMarker工具类
*/
public class FreeMarkerUtils {

private FreeMarkerUtils() {
}

private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);

static {
//这里比较重要,用来指定加载模板所在的路径
CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerUtils.class, "/templates"));
CONFIGURATION.setDefaultEncoding("UTF-8");
CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
}

public static Template getTemplate(String templateName) throws IOException {
try {
return CONFIGURATION.getTemplate(templateName);
} catch (IOException e) {
throw e;
}
}

public static void clearCache() {
CONFIGURATION.clearTemplateCache();
}

}

+ 209
- 0
tuoheng-generator/src/main/java/com/tuoheng/generator/utils/GenUtils.java View File

@@ -0,0 +1,209 @@
package com.tuoheng.generator.utils;

import com.tuoheng.common.utils.StringUtils;
import com.tuoheng.generator.config.GenConfig;
import com.tuoheng.generator.constant.GenConstants;
import com.tuoheng.generator.entity.GenTable;
import com.tuoheng.generator.entity.GenTableColumn;
import org.apache.commons.lang3.RegExUtils;

import java.util.Arrays;

/**
* 代码生成器工具类
*/
public class GenUtils {

/**
* 初始化表信息
*/
public static void initTable(GenTable genTable, String operName) {
genTable.setClassName(convertClassName(genTable.getTableName()));
genTable.setPackageName(GenConfig.getPackageName());
genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
genTable.setBusinessName(getBusinessName(genTable.getTableName()));
genTable.setFunctionName(replaceText(genTable.getTableComment()));
genTable.setFunctionAuthor(GenConfig.getAuthor());
genTable.setCreateUser(0);
}

/**
* 初始化列属性字段
*/
public static void initColumnField(GenTableColumn column, GenTable table) {
String dataType = getDbType(column.getColumnType());
String columnName = column.getColumnName();
column.setTableId(table.getId());
column.setCreateUser(table.getCreateUser());
// 设置java字段名
column.setJavaField(StringUtils.toCamelCase(columnName));

if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType)) {
column.setJavaType(GenConstants.TYPE_STRING);
// 字符串长度超过500设置为文本域
Integer columnLength = getColumnLength(column.getColumnType());
String htmlType = columnLength >= 500 ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
column.setHtmlType(htmlType);
} else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
column.setJavaType(GenConstants.TYPE_DATE);
column.setHtmlType(GenConstants.HTML_DATETIME);
} else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
column.setHtmlType(GenConstants.HTML_INPUT);

// 如果是浮点型
String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) {
column.setJavaType(GenConstants.TYPE_DOUBLE);
}
// 如果是整形
else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) {
column.setJavaType(GenConstants.TYPE_INTEGER);
}
// 长整形
else {
column.setJavaType(GenConstants.TYPE_LONG);
}
}

// 插入字段(默认所有字段都需要插入)
column.setIsInsert(GenConstants.REQUIRE);

// 编辑字段
if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && column.getIsPk() != 1) {
column.setIsEdit(GenConstants.REQUIRE);
}
// 列表字段
if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && column.getIsPk() != 1) {
column.setIsList(GenConstants.REQUIRE);
}
// 查询字段
if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && column.getIsPk() != 1) {
column.setIsQuery(GenConstants.REQUIRE);
}

// 查询字段类型
if (StringUtils.endsWithIgnoreCase(columnName, "name")) {
column.setQueryType(GenConstants.QUERY_LIKE);
}
// 状态字段设置单选框
if (StringUtils.endsWithIgnoreCase(columnName, "status")) {
column.setHtmlType(GenConstants.HTML_RADIO);
}
// 类型&性别字段设置下拉框
else if (StringUtils.endsWithIgnoreCase(columnName, "type")
|| StringUtils.endsWithIgnoreCase(columnName, "sex")) {
column.setHtmlType(GenConstants.HTML_SELECT);
}
}

/**
* 校验数组是否包含指定值
*
* @param arr 数组
* @param targetValue 值
* @return 是否包含
*/
public static boolean arraysContains(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}

/**
* 获取模块名
*
* @param packageName 包名
* @return 模块名
*/
public static String getModuleName(String packageName) {
int lastIndex = packageName.lastIndexOf(".");
int nameLength = packageName.length();
String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength);
return moduleName;
}

/**
* 获取业务名
*
* @param tableName 表名
* @return 业务名
*/
public static String getBusinessName(String tableName) {
int lastIndex = tableName.lastIndexOf("_");
int nameLength = tableName.length();
String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength);
return businessName;
}

/**
* 表名转换成Java类名
*
* @param tableName 表名称
* @return 类名
*/
public static String convertClassName(String tableName) {
boolean autoRemovePre = GenConfig.getAutoRemovePre();
String tablePrefix = GenConfig.getTablePrefix();
if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) {
String[] searchList = StringUtils.split(tablePrefix, ",");
tableName = replaceFirst(tableName, searchList);
}
return StringUtils.convertToCamelCase(tableName);
}

/**
* 批量替换前缀
*
* @param replacementm 替换值
* @param searchList 替换列表
* @return
*/
public static String replaceFirst(String replacementm, String[] searchList) {
String text = replacementm;
for (String searchString : searchList) {
if (replacementm.startsWith(searchString)) {
text = replacementm.replaceFirst(searchString, "");
break;
}
}
return text;
}

/**
* 关键字替换
*
* @param text 需要被替换的名字
* @return 替换后的名字
*/
public static String replaceText(String text) {
return RegExUtils.replaceAll(text, "(?:表|若依)", "");
}

/**
* 获取数据库类型字段
*
* @param columnType 列类型
* @return 截取后的列类型
*/
public static String getDbType(String columnType) {
if (StringUtils.indexOf(columnType, "(") > 0) {
return StringUtils.substringBefore(columnType, "(");
} else {
return columnType;
}
}

/**
* 获取字段长度
*
* @param columnType 列类型
* @return 截取后的列类型
*/
public static Integer getColumnLength(String columnType) {
if (StringUtils.indexOf(columnType, "(") > 0) {
String length = StringUtils.substringBetween(columnType, "(", ")");
return Integer.valueOf(length);
} else {
return 0;
}
}

}

+ 116
- 0
tuoheng-generator/src/main/resources/mapper/GenTableColumnMapper.xml View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tuoheng.generator.mapper.GenTableColumnMapper">

<resultMap type="com.tuoheng.generator.entity.GenTableColumn" id="GenTableColumnResult">
<id property="id" column="id"/>
<result property="tableId" column="table_id"/>
<result property="columnName" column="column_name"/>
<result property="columnComment" column="column_comment"/>
<result property="columnType" column="column_type"/>
<result property="javaType" column="java_type"/>
<result property="javaField" column="java_field"/>
<result property="isPk" column="is_pk"/>
<result property="isIncrement" column="is_increment"/>
<result property="isRequired" column="is_required"/>
<result property="isInsert" column="is_insert"/>
<result property="isEdit" column="is_edit"/>
<result property="isList" column="is_list"/>
<result property="isQuery" column="is_query"/>
<result property="queryType" column="query_type"/>
<result property="htmlType" column="html_type"/>
<result property="dictType" column="dict_type"/>
<result property="sort" column="sort"/>
<result property="createUser" column="create_user"/>
<result property="createTime" column="create_time"/>
<result property="updateUser" column="update_user"/>
<result property="updateTime" column="update_time"/>
</resultMap>

<!-- 根据表明获取列信息 -->
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
order by ordinal_position
</select>

<!-- 插入表列信息 -->
<insert id="insertGenTableColumn" parameterType="com.tuoheng.generator.entity.GenTableColumn" useGeneratedKeys="true"
keyProperty="id">
insert into gen_table_column (
<if test="tableId != null and tableId != ''">table_id,</if>
<if test="columnName != null and columnName != ''">column_name,</if>
<if test="columnComment != null and columnComment != ''">column_comment,</if>
<if test="columnType != null and columnType != ''">column_type,</if>
<if test="javaType != null and javaType != ''">java_type,</if>
<if test="javaField != null and javaField != ''">java_field,</if>
<if test="isPk != null and isPk != ''">is_pk,</if>
<if test="isIncrement != null and isIncrement != ''">is_increment,</if>
<if test="isRequired != null and isRequired != ''">is_required,</if>
<if test="isInsert != null and isInsert != ''">is_insert,</if>
<if test="isEdit != null and isEdit != ''">is_edit,</if>
<if test="isList != null and isList != ''">is_list,</if>
<if test="isQuery != null and isQuery != ''">is_query,</if>
<if test="queryType != null and queryType != ''">query_type,</if>
<if test="htmlType != null and htmlType != ''">html_type,</if>
<if test="dictType != null and dictType != ''">dict_type,</if>
<if test="sort != null">sort,</if>
<if test="createUser != null and createUser != ''">create_user,</if>
create_time
)values(
<if test="tableId != null and tableId != ''">#{tableId},</if>
<if test="columnName != null and columnName != ''">#{columnName},</if>
<if test="columnComment != null and columnComment != ''">#{columnComment},</if>
<if test="columnType != null and columnType != ''">#{columnType},</if>
<if test="javaType != null and javaType != ''">#{javaType},</if>
<if test="javaField != null and javaField != ''">#{javaField},</if>
<if test="isPk != null and isPk != ''">#{isPk},</if>
<if test="isIncrement != null and isIncrement != ''">#{isIncrement},</if>
<if test="isRequired != null and isRequired != ''">#{isRequired},</if>
<if test="isInsert != null and isInsert != ''">#{isInsert},</if>
<if test="isEdit != null and isEdit != ''">#{isEdit},</if>
<if test="isList != null and isList != ''">#{isList},</if>
<if test="isQuery != null and isQuery != ''">#{isQuery},</if>
<if test="queryType != null and queryType != ''">#{queryType},</if>
<if test="htmlType != null and htmlType != ''">#{htmlType},</if>
<if test="dictType != null and dictType != ''">#{dictType},</if>
<if test="sort != null">#{sort},</if>
<if test="createUser != null and createUser != ''">#{createUser},</if>
sysdate()
)
</insert>


<sql id="selectGenTableColumnVo">
select id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_user, create_time, update_user, update_time from gen_table_column
</sql>
<!-- 获取表字段列表 -->
<select id="selectGenTableColumnListByTableId" parameterType="Integer" resultMap="GenTableColumnResult">
<include refid="selectGenTableColumnVo"/>
where table_id = #{tableId}
order by sort
</select>

<!-- 更新业务表字段 -->
<update id="updateGenTableColumn" parameterType="com.tuoheng.generator.entity.GenTableColumn">
update gen_table_column
<set>
column_comment = #{columnComment},
java_type = #{javaType},
java_field = #{javaField},
is_insert = #{isInsert},
is_edit = #{isEdit},
is_list = #{isList},
is_query = #{isQuery},
is_required = #{isRequired},
query_type = #{queryType},
html_type = #{htmlType},
dict_type = #{dictType},
sort = #{sort},
update_user = #{updateUser},
update_time = sysdate()
</set>
where id = #{id}
</update>

</mapper>

+ 0
- 0
tuoheng-generator/src/main/resources/mapper/GenTableMapper.xml View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save