@@ -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 |
@@ -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> |
@@ -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> |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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> { | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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> |
@@ -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> |
@@ -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 |
@@ -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> |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
} |
@@ -0,0 +1,4 @@ | |||
package com.tuoheng.common.common; | |||
public class BaseController { | |||
} |
@@ -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; | |||
} |
@@ -0,0 +1,19 @@ | |||
package com.tuoheng.common.common; | |||
import lombok.Data; | |||
/** | |||
* 查询对象基类 | |||
*/ | |||
@Data | |||
public class BaseQuery { | |||
/** | |||
* 页码 | |||
*/ | |||
private Integer page; | |||
/** | |||
* 每页数 | |||
*/ | |||
private Integer limit; | |||
} |
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
}; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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"; | |||
} |
@@ -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"; | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
package com.tuoheng.common.enums; | |||
/** | |||
* 操作状态 | |||
*/ | |||
public enum LogStatus { | |||
/** | |||
* 成功 | |||
*/ | |||
SUCCESS, | |||
/** | |||
* 失败 | |||
*/ | |||
FAIL, | |||
} |
@@ -0,0 +1,68 @@ | |||
package com.tuoheng.common.enums; | |||
/** | |||
* 日志类型 | |||
*/ | |||
public enum LogType { | |||
/** | |||
* 其它 | |||
*/ | |||
OTHER, | |||
/** | |||
* 新增 | |||
*/ | |||
INSERT, | |||
/** | |||
* 修改 | |||
*/ | |||
UPDATE, | |||
/** | |||
* 删除 | |||
*/ | |||
DELETE, | |||
/** | |||
* 授权 | |||
*/ | |||
GRANT, | |||
/** | |||
* 导出 | |||
*/ | |||
EXPORT, | |||
/** | |||
* 导入 | |||
*/ | |||
IMPORT, | |||
/** | |||
* 强退 | |||
*/ | |||
FORCE, | |||
/** | |||
* 生成代码 | |||
*/ | |||
GENCODE, | |||
/** | |||
* 清空数据 | |||
*/ | |||
CLEAN, | |||
/** | |||
* 状态 | |||
*/ | |||
STATUS, | |||
/** | |||
* 重置密码 | |||
*/ | |||
RESETPWD, | |||
} |
@@ -0,0 +1,23 @@ | |||
package com.tuoheng.common.enums; | |||
/** | |||
* 操作类型 | |||
*/ | |||
public enum OperType { | |||
/** | |||
* 其它 | |||
*/ | |||
OTHER, | |||
/** | |||
* 后台用户 | |||
*/ | |||
MANAGE, | |||
/** | |||
* 手机端用户 | |||
*/ | |||
MOBILE | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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, "上传成功"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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("^整$", "零元整"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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() + "]"; | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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}] |
@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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"; | |||
} |
@@ -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 { | |||
} |
@@ -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); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
package com.tuoheng.generator.dto; | |||
import lombok.Data; | |||
/** | |||
* 一键生成Dto | |||
*/ | |||
@Data | |||
public class GenTableDto { | |||
/** | |||
* 业务表名称(多个使用逗号“,”分隔) | |||
*/ | |||
private String tableNames; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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("删除成功"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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> |