@@ -0,0 +1,3 @@ | |||
/.idea | |||
/tuoheng-admin/target/classes | |||
/tuoheng-system/target/classes/mapper |
@@ -0,0 +1,3 @@ | |||
# tuoheng_airport | |||
## 拓恒机场统一管理平台 |
@@ -0,0 +1,109 @@ | |||
<?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.7.1</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> | |||
<spring-cloud.version>2021.0.3</spring-cloud.version> | |||
</properties> | |||
<!-- 依赖声明 --> | |||
<dependencyManagement> | |||
<dependencies> | |||
<!-- SpringCloud依赖 --> | |||
<dependency> | |||
<groupId>org.springframework.cloud</groupId> | |||
<artifactId>spring-cloud-dependencies</artifactId> | |||
<version>${spring-cloud.version}</version> | |||
<type>pom</type> | |||
<scope>import</scope> | |||
</dependency> | |||
<!-- 子模块依赖 --> | |||
<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> | |||
<repositories> | |||
<repository> | |||
<id>public</id> | |||
<name>aliyun nexus</name> | |||
<url>https://maven.aliyun.com/repository/public</url> | |||
<releases> | |||
<enabled>true</enabled> | |||
</releases> | |||
</repository> | |||
</repositories> | |||
<pluginRepositories> | |||
<pluginRepository> | |||
<id>public</id> | |||
<name>aliyun nexus</name> | |||
<url>https://maven.aliyun.com/repository/public</url> | |||
<releases> | |||
<enabled>true</enabled> | |||
</releases> | |||
<snapshots> | |||
<enabled>false</enabled> | |||
</snapshots> | |||
</pluginRepository> | |||
</pluginRepositories> | |||
</project> |
@@ -0,0 +1,5 @@ | |||
# 拓恒机场统一管理后台 | |||
## 统一管理和硬件相关,机场地面站以及控制面板的交互 | |||
## 对业务系统提供Restful API暴漏飞行相关的能力 | |||
@@ -0,0 +1,206 @@ | |||
<?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> | |||
<!-- Consul注册中心起始依赖 --> | |||
<dependency> | |||
<groupId>org.springframework.cloud</groupId> | |||
<artifactId>spring-cloud-starter-consul-discovery</artifactId> | |||
</dependency> | |||
<!-- 核心模块 --> | |||
<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> | |||
<!-- 阿里云OSS --> | |||
<dependency> | |||
<groupId>com.aliyun.oss</groupId> | |||
<artifactId>aliyun-sdk-oss</artifactId> | |||
<version>3.10.2</version> | |||
</dependency> | |||
<!--mqtt 相关依赖--> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-integration</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework.integration</groupId> | |||
<artifactId>spring-integration-stream</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.springframework.integration</groupId> | |||
<artifactId>spring-integration-mqtt</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.quartz-scheduler</groupId> | |||
<artifactId>quartz</artifactId> | |||
<version>2.3.2</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_airport_admin</finalName> | |||
<resources> | |||
<resource> | |||
<directory>src/main/resources</directory> | |||
<filtering>true</filtering> | |||
<!-- <excludes>--> | |||
<!-- <exclude>application-dev.yml</exclude>--> | |||
<!-- <exclude>application-test.yml</exclude>--> | |||
<!-- <exclude>application-prod.yml</exclude>--> | |||
<!-- </excludes>--> | |||
</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,26 @@ | |||
package com.tuoheng.admin; | |||
import org.mybatis.spring.annotation.MapperScan; | |||
import org.springframework.boot.SpringApplication; | |||
import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | |||
import org.springframework.scheduling.annotation.EnableAsync; | |||
import org.springframework.scheduling.annotation.EnableScheduling; | |||
import org.springframework.transaction.annotation.EnableTransactionManagement; | |||
@SpringBootApplication(scanBasePackages = {"com.tuoheng.*"}) | |||
@EnableDiscoveryClient | |||
@MapperScan("com.tuoheng.**.mapper") | |||
@EnableTransactionManagement | |||
// 开启定时任务支持 | |||
@EnableScheduling | |||
@EnableAsync | |||
public class AdminApplication { | |||
public static void main(String[] args) { | |||
SpringApplication.run(AdminApplication.class, args); | |||
System.out.println("tuoheng-airport-admin 启动成功~"); | |||
} | |||
} |
@@ -0,0 +1,227 @@ | |||
package com.tuoheng.admin.config.sql; | |||
import com.tuoheng.common.utils.StringUtils; | |||
import lombok.extern.slf4j.Slf4j; | |||
import java.beans.IntrospectionException; | |||
import java.beans.PropertyDescriptor; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import java.util.Set; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: ike字符转义 | |||
* @Version: 1.0 | |||
*/ | |||
@Slf4j | |||
public abstract class AbstractLikeSqlConverter<T> { | |||
/** | |||
* SQL语句like使用关键字% | |||
*/ | |||
private final static String LIKE_SQL_KEY = "%"; | |||
/** | |||
* SQL语句需要转义的关键字 | |||
*/ | |||
private final static String[] ESCAPE_CHAR = new String[]{LIKE_SQL_KEY, "_", "\\"}; | |||
/** | |||
* mybatis-plus中like的SQL语句样式 | |||
*/ | |||
private final static String MYBATIS_PLUS_LIKE_SQL = " like ?"; | |||
/** | |||
* mybatis-plus中参数前缀 | |||
*/ | |||
private final static String MYBATIS_PLUS_WRAPPER_PREFIX = "ew.paramNameValuePairs."; | |||
/** | |||
* mybatis-plus中参数键 | |||
*/ | |||
final static String MYBATIS_PLUS_WRAPPER_KEY = "ew"; | |||
/** | |||
* mybatis-plus中参数分隔符 | |||
*/ | |||
final static String MYBATIS_PLUS_WRAPPER_SEPARATOR = "."; | |||
/** | |||
* mybatis-plus中参数分隔符替换器 | |||
*/ | |||
final static String MYBATIS_PLUS_WRAPPER_SEPARATOR_REGEX = "\\."; | |||
/** | |||
* 已经替换过的标记 | |||
*/ | |||
final static String REPLACED_LIKE_KEYWORD_MARK = "replaced.keyword"; | |||
/** | |||
* 转义特殊字符 | |||
* | |||
* @param sql SQL语句 | |||
* @param fields 字段列表 | |||
* @param parameter 参数对象 | |||
*/ | |||
public void convert(String sql, Set<String> fields, T parameter) { | |||
for (String field : fields) { | |||
if (this.hasMybatisPlusLikeSql(sql)) { | |||
if (this.hasWrapper(field)) { | |||
// 第一种情况:在业务层进行条件构造产生的模糊查询关键字,使用QueryWrapper,LambdaQueryWrapper | |||
this.transferWrapper(field, parameter); | |||
} else { | |||
// 第二种情况:未使用条件构造器,但是在service层进行了查询关键字与模糊查询符`%`手动拼接 | |||
this.transferSelf(field, parameter); | |||
} | |||
} else { | |||
// 第三种情况:在Mapper类的注解SQL中进行了模糊查询的拼接 | |||
this.transferSplice(field, parameter); | |||
} | |||
} | |||
} | |||
/** | |||
* 转义条件构造的特殊字符 | |||
* 在业务层进行条件构造产生的模糊查询关键字,使用QueryWrapper,LambdaQueryWrapper | |||
* | |||
* @param field 字段名称 | |||
* @param parameter 参数对象 | |||
*/ | |||
public abstract void transferWrapper(String field, T parameter); | |||
/** | |||
* 转义自定义条件拼接的特殊字符 | |||
* 未使用条件构造器,但是在service层进行了查询关键字与模糊查询符`%`手动拼接 | |||
* | |||
* @param field 字段名称 | |||
* @param parameter 参数对象 | |||
*/ | |||
public abstract void transferSelf(String field, T parameter); | |||
/** | |||
* 转义自定义条件拼接的特殊字符 | |||
* 在Mapper类的注解SQL中进行了模糊查询的拼接 | |||
* | |||
* @param field 字段名称 | |||
* @param parameter 参数对象 | |||
*/ | |||
public abstract void transferSplice(String field, T parameter); | |||
/** | |||
* 转义通配符 | |||
* | |||
* @param before 待转义字符串 | |||
* @return 转义后字符串 | |||
*/ | |||
String escapeChar(String before) { | |||
if (StringUtils.isNotBlank(before)) { | |||
before = before.replaceAll("\\\\", "\\\\\\\\"); | |||
before = before.replaceAll("_", "\\\\_"); | |||
before = before.replaceAll("%", "\\\\%"); | |||
} | |||
return before; | |||
} | |||
/** | |||
* 是否包含需要转义的字符 | |||
* | |||
* @param obj 待判断的对象 | |||
* @return true/false | |||
*/ | |||
boolean hasEscapeChar(Object obj) { | |||
if (!(obj instanceof String)) { | |||
return false; | |||
} | |||
return this.hasEscapeChar((String) obj); | |||
} | |||
/** | |||
* 处理对象like问题 | |||
* | |||
* @param field 对象字段 | |||
* @param parameter 对象 | |||
*/ | |||
void resolveObj(String field, Object parameter) { | |||
if (parameter == null || StringUtils.isBlank(field)) { | |||
return; | |||
} | |||
try { | |||
PropertyDescriptor descriptor = new PropertyDescriptor(field, parameter.getClass()); | |||
Method readMethod = descriptor.getReadMethod(); | |||
Object param = readMethod.invoke(parameter); | |||
if (this.hasEscapeChar(param)) { | |||
Method setMethod = descriptor.getWriteMethod(); | |||
setMethod.invoke(parameter, this.escapeChar(param.toString())); | |||
} else if (this.cascade(field)) { | |||
int index = field.indexOf(MYBATIS_PLUS_WRAPPER_SEPARATOR) + 1; | |||
this.resolveObj(field.substring(index), param); | |||
} | |||
} catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { | |||
log.error("反射 {} 的 {} get/set方法出现异常", parameter, field, e); | |||
} | |||
} | |||
/** | |||
* 判断是否是级联属性 | |||
* | |||
* @param field 字段名 | |||
* @return true/false | |||
*/ | |||
boolean cascade(String field) { | |||
if (StringUtils.isBlank(field)) { | |||
return false; | |||
} | |||
return field.contains(MYBATIS_PLUS_WRAPPER_SEPARATOR) && !this.hasWrapper(field); | |||
} | |||
/** | |||
* 是否包含mybatis-plus的包含like的SQL语句格式 | |||
* | |||
* @param sql 完整SQL语句 | |||
* @return true/false | |||
*/ | |||
private boolean hasMybatisPlusLikeSql(String sql) { | |||
if (StringUtils.isBlank(sql)) { | |||
return false; | |||
} | |||
return sql.toLowerCase().contains(MYBATIS_PLUS_LIKE_SQL); | |||
} | |||
/** | |||
* 判断是否使用mybatis-plus条件构造器 | |||
* | |||
* @param field 字段 | |||
* @return true/false | |||
*/ | |||
private boolean hasWrapper(String field) { | |||
if (StringUtils.isBlank(field)) { | |||
return false; | |||
} | |||
return field.contains(MYBATIS_PLUS_WRAPPER_PREFIX); | |||
} | |||
/** | |||
* 判断字符串是否含有需要转义的字符 | |||
* | |||
* @param str 待判断的字符串 | |||
* @return true/false | |||
*/ | |||
private boolean hasEscapeChar(String str) { | |||
if (StringUtils.isBlank(str)) { | |||
return false; | |||
} | |||
for (String s : ESCAPE_CHAR) { | |||
if (str.contains(s)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
package com.tuoheng.admin.config.sql; | |||
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: ike字符转义 | |||
* @Version: 1.0 | |||
*/ | |||
public class MapLikeSqlConverter extends AbstractLikeSqlConverter<Map> { | |||
@Override | |||
public void transferWrapper(String field, Map parameter) { | |||
AbstractWrapper wrapper = (AbstractWrapper) parameter.get(MYBATIS_PLUS_WRAPPER_KEY); | |||
parameter = wrapper.getParamNameValuePairs(); | |||
String[] keys = field.split(MYBATIS_PLUS_WRAPPER_SEPARATOR_REGEX); | |||
// ew.paramNameValuePairs.param1,截取字符串之后,获取第三个,即为参数名 | |||
String paramName = keys[2]; | |||
String mapKey = String.format("%s.%s", REPLACED_LIKE_KEYWORD_MARK, paramName); | |||
if (parameter.containsKey(mapKey) && Objects.equals(parameter.get(mapKey), true)) { | |||
return; | |||
} | |||
if (this.cascade(field)) { | |||
this.resolveCascadeObj(field, parameter); | |||
} else { | |||
Object param = parameter.get(paramName); | |||
if (this.hasEscapeChar(param)) { | |||
String paramStr = param.toString(); | |||
parameter.put(keys[2], String.format("%%%s%%", this.escapeChar(paramStr.substring(1, paramStr.length() - 1)))); | |||
} | |||
} | |||
parameter.put(mapKey, true); | |||
} | |||
@Override | |||
public void transferSelf(String field, Map parameter) { | |||
if (this.cascade(field)) { | |||
this.resolveCascadeObj(field, parameter); | |||
return; | |||
} | |||
Object param = parameter.get(field); | |||
if (this.hasEscapeChar(param)) { | |||
String paramStr = param.toString(); | |||
parameter.put(field, String.format("%%%s%%", this.escapeChar(paramStr.substring(1, paramStr.length() - 1)))); | |||
} | |||
} | |||
@Override | |||
public void transferSplice(String field, Map parameter) { | |||
if (this.cascade(field)) { | |||
this.resolveCascadeObj(field, parameter); | |||
return; | |||
} | |||
Object param = parameter.get(field); | |||
if (this.hasEscapeChar(param)) { | |||
parameter.put(field, this.escapeChar(param.toString())); | |||
} | |||
} | |||
/** | |||
* 处理级联属性 | |||
* | |||
* @param field 级联字段名 | |||
* @param parameter 参数Map对象 | |||
*/ | |||
private void resolveCascadeObj(String field, Map parameter) { | |||
int index = field.indexOf(MYBATIS_PLUS_WRAPPER_SEPARATOR); | |||
Object param = parameter.get(field.substring(0, index)); | |||
if (param == null) { | |||
return; | |||
} | |||
this.resolveObj(field.substring(index + 1), param); | |||
} | |||
} |
@@ -0,0 +1,153 @@ | |||
package com.tuoheng.admin.config.sql; | |||
import com.tuoheng.common.utils.StringUtils; | |||
import org.apache.ibatis.executor.Executor; | |||
import org.apache.ibatis.mapping.BoundSql; | |||
import org.apache.ibatis.mapping.MappedStatement; | |||
import org.apache.ibatis.plugin.*; | |||
import org.apache.ibatis.session.ResultHandler; | |||
import org.apache.ibatis.session.RowBounds; | |||
import java.util.*; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: like字符转义 防止sql注入 | |||
* @Version: 1.0 | |||
*/ | |||
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, | |||
RowBounds.class, ResultHandler.class})}) | |||
public class MybatisPlusInterceptor implements Interceptor { | |||
/** | |||
* SQL语句like | |||
*/ | |||
private final static String SQL_LIKE = " like "; | |||
/** | |||
* SQL语句占位符 | |||
*/ | |||
private final static String SQL_PLACEHOLDER = "?"; | |||
/** | |||
* SQL语句占位符分隔 | |||
*/ | |||
private final static String SQL_PLACEHOLDER_REGEX = "\\?"; | |||
/** | |||
* 所有的转义器 | |||
*/ | |||
private static Map<Class, AbstractLikeSqlConverter> converterMap = new HashMap<>(4); | |||
static { | |||
converterMap.put(Map.class, new MapLikeSqlConverter()); | |||
// converterMap.put(Object.class, new ObjectLikeSqlConverter()); | |||
} | |||
@Override | |||
public Object intercept(Invocation invocation) throws Throwable { | |||
// 获取sql及参数信息 | |||
Object[] args = invocation.getArgs(); | |||
MappedStatement statement = (MappedStatement) args[0]; | |||
Object parameterObject = args[1]; | |||
BoundSql boundSql = statement.getBoundSql(parameterObject); | |||
String sql = boundSql.getSql(); | |||
this.transferLikeSql(sql, parameterObject, boundSql); | |||
return invocation.proceed(); | |||
} | |||
@Override | |||
public Object plugin(Object target) { | |||
return Plugin.wrap(target, this); | |||
} | |||
@Override | |||
public void setProperties(Properties arg0) { | |||
} | |||
/** | |||
* 修改包含like的SQL语句 | |||
* | |||
* @param sql SQL语句 | |||
* @param parameterObject 参数对象 | |||
* @param boundSql 绑定SQL对象 | |||
*/ | |||
private void transferLikeSql(String sql, Object parameterObject, BoundSql boundSql) { | |||
// 判断是否有like关键字 | |||
if (!isEscape(sql)) { | |||
return; | |||
} | |||
sql = sql.replaceAll(" {2}", " "); | |||
// 获取关键字的个数(去重) | |||
Set<String> fields = this.getKeyFields(sql, boundSql); | |||
if (fields == null) { | |||
return; | |||
} | |||
// 此处可以增强,不止是支持Map对象,Map对象仅用于传入的条件为Map或者使用@Param传入的对象被Mybatis转为的Map | |||
AbstractLikeSqlConverter converter; | |||
// 对关键字进行特殊字符“清洗”,如果有特殊字符的,在特殊字符前添加转义字符(\) | |||
if (parameterObject instanceof Map) { | |||
converter = converterMap.get(Map.class); | |||
} else { | |||
converter = converterMap.get(Object.class); | |||
} | |||
converter.convert(sql, fields, parameterObject); | |||
} | |||
/** | |||
* 是否需要转义 | |||
* | |||
* @param sql SQL语句 | |||
* @return true/false | |||
*/ | |||
private boolean isEscape(String sql) { | |||
return this.hasLike(sql) && this.hasPlaceholder(sql); | |||
} | |||
/** | |||
* 判断SQL语句中是否含有like关键字 | |||
* | |||
* @param str SQL语句 | |||
* @return true/false | |||
*/ | |||
private boolean hasLike(String str) { | |||
if (StringUtils.isBlank(str)) { | |||
return false; | |||
} | |||
return str.toLowerCase().contains(SQL_LIKE); | |||
} | |||
/** | |||
* 判断SQL语句中是否包含SQL占位符 | |||
* | |||
* @param str SQL语句 | |||
* @return true/false | |||
*/ | |||
private boolean hasPlaceholder(String str) { | |||
if (StringUtils.isBlank(str)) { | |||
return false; | |||
} | |||
return str.toLowerCase().contains(SQL_PLACEHOLDER); | |||
} | |||
/** | |||
* 获取需要替换的所有字段集合 | |||
* | |||
* @param sql 完整SQL语句 | |||
* @param boundSql 绑定的SQL对象 | |||
* @return 字段集合列表 | |||
*/ | |||
private Set<String> getKeyFields(String sql, BoundSql boundSql) { | |||
String[] params = sql.split(SQL_PLACEHOLDER_REGEX); | |||
Set<String> fields = new HashSet<>(); | |||
for (int i = 0; i < params.length; i++) { | |||
if (this.hasLike(params[i])) { | |||
String field = boundSql.getParameterMappings().get(i).getProperty(); | |||
fields.add(field); | |||
} | |||
} | |||
return fields; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
package com.tuoheng.admin.config.sql; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 通用参数的转换器 | |||
* @Version: 1.0 | |||
*/ | |||
public class ObjectLikeSqlConverter extends AbstractLikeSqlConverter<Object> { | |||
@Override | |||
public void transferWrapper(String field, Object parameter) { | |||
// 尚未发现这种情况 | |||
} | |||
@Override | |||
public void transferSelf(String field, Object parameter) { | |||
// 尚未发现这种情况 | |||
} | |||
@Override | |||
public void transferSplice(String field, Object parameter) { | |||
this.resolveObj(field, parameter); | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
package com.tuoheng.admin.controller; | |||
import org.springframework.web.bind.annotation.GetMapping; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.RestController; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 服务健康检查 | |||
* @Version: 1.0 | |||
*/ | |||
@RestController | |||
@RequestMapping("/health") | |||
public class HealthController { | |||
/** | |||
* 健康检查接口调用 | |||
*/ | |||
@GetMapping("/hello") | |||
public String health() { | |||
return "ok"; | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
package com.tuoheng.admin.enums; | |||
import lombok.Getter; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-18 19:09 | |||
* @Description: MQTT topic 枚举。将所有和MQTT交互的topic统一维护 | |||
* %S:设备编号占位符;qos:为传输等级定义的时候自行指定;desc:描述信息方便记录日志等 | |||
* @Version: 1.0 | |||
*/ | |||
public enum MQTTTopicEnum { | |||
TOPIC_DATA_DOORMOTOR("/v1/%s/data/DoorMotor", 0, ""), | |||
TOPIC_DATA_LIFTMOTOR("/v1/%s/data/LiftMotor", 0, ""), | |||
TOPIC_DATA_FIXEDMOTOR("/v1/%s/data/FixedMotor", 0, ""), | |||
TOPIC_DATA_DRONEGOAWAY("/v1/%s/data/DroneGoAway", 0, ""), | |||
TOPIC_DATA_DRONEGOHOME("/v1/%s/data/DroneGoHome", 0, ""), | |||
TOPIC_DATA_DRONEGOSTOP("/v1/%s/data/DroneGoStop", 0, ""), | |||
TOPIC_DATA_DRONESTOP("/v1/%s/data/DroneStop", 0, ""), | |||
TOPIC_CONFIRM_DOORMOTOR("/v1/%s/confirm/DoorMotor", 0, ""), | |||
TOPIC_CONFIRM_LIFTMOTOR("/v1/%s/confirm/LiftMotor", 0, ""), | |||
TOPIC_CONFIRM_FIXEDMOTOR1("/v1/%s/confirm/FixedMotor1", 0, ""), | |||
TOPIC_CONFIRM_FIXEDMOTOR2("/v1/%s/confirm/FixedMotor2", 0, ""), | |||
TOPIC_CONFIRM_DRONEGOAWAY("/v1/%s/confirm/DroneGoAway", 0, ""), | |||
TOPIC_CONFIRM_DRONEGOHOME("/v1/%s/confirm/DroneGoHome", 0, ""), | |||
TOPIC_CONFIRM_DRONEGOSTOP("/v1/%s/confirm/DroneGoStop", 0, ""), | |||
TOPIC_CONFIRM_DRONESTOP("/v1/%s/confirm/DroneStop", 0, ""), | |||
TOPIC_CONFIRM_EDGE("/v1/%s/confirm/Edge", 0, ""), | |||
TOPIC_CONFIRM_CHGR("/v1/%s/confirm/CHGR", 0, ""), | |||
TOPIC_CONFIRM_LIGHT("/v1/%s/confirm/Light", 0, ""), | |||
TOPIC_CONTROL_DOORMOTOR("/v1/%s/control/DoorMotor", 0, ""), | |||
TOPIC_CONTROL_LIFTMOTOR("/v1/%s/control/LiftMotor", 0, ""), | |||
TOPIC_CONTROL_FIXEDMOTOR("/v1/%s/control/FixedMotor", 0, ""), | |||
TOPIC_CONTROL_DRONEGOAWAY("/v1/%s/control/DroneGoAway", 0, ""), | |||
TOPIC_CONTROL_DRONEGOHOME("/v1/%s/control/DroneGoHome", 0, ""), | |||
TOPIC_CONTROL_DRONEGOSTOP("/v1/%s/control/DroneGoStop", 0, ""), | |||
TOPIC_CONTROL_DRONESTOP("/v1/%s/control/DroneStop", 0, ""), | |||
TOPIC_CONTROL_CHGR("/v1/%s/control/CHGR", 0, ""), | |||
TOPIC_CONTROL_LIGHT("/v1/%s/control/Light", 0, ""), | |||
TOPIC_DATA_TAH("/v1/%s/data/TAH", 0, ""), | |||
TOPIC_DATA_WTH("/v1/%s/data/WTH", 0, ""), | |||
TOPIC_DATA_ACD("/v1/%s/data/ACD", 0, ""), | |||
TOPIC_DATA_UPS("/v1/%s/data/UPS", 0, ""), | |||
TOPIC_DATA_CHGR("/v1/%s/data/CHGR", 0, ""), | |||
TOPIC_DATA_LIGHT("/v1/%s/data/Light", 0, ""), | |||
TOPIC_ALARM_TAH("/v1/%s/alarm/TAH", 0, ""), | |||
TOPIC_ALARM_WTH("/v1/%s/alarm/WTH", 0, ""), | |||
TOPIC_ALARM_ACD("/v1/%s/alarm/ACD", 0, ""), | |||
TOPIC_ALARM_UPS("/v1/%s/alarm/UPS", 0, ""), | |||
TOPIC_PULL_WTH("/v1/%s/pull/WTH", 0, ""), | |||
TOPIC_POST_WTH("/v1/%s/post/WTH", 0, ""); | |||
MQTTTopicEnum(String topic, int qos, String desc) { | |||
this.topic = topic; | |||
this.qos = qos; | |||
this.desc = desc; | |||
} | |||
/** | |||
* MQTT topic | |||
*/ | |||
@Getter | |||
private String topic; | |||
/** | |||
* 对应qos等级 0-至多一次;1-至少一次;2-确保只有一次 | |||
*/ | |||
@Getter | |||
private int qos; | |||
/** | |||
* 描述 | |||
*/ | |||
@Getter | |||
private String desc; | |||
} |
@@ -0,0 +1,30 @@ | |||
package com.tuoheng.admin.enums; | |||
import com.tuoheng.common.common.ExceptionInterface; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Getter; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 10:17 | |||
* @Description: 业务异常 枚举 | |||
* 异常全局唯一,从5555依次递减 | |||
* @Version: 1.0 | |||
*/ | |||
@AllArgsConstructor | |||
public enum ServiceExceptionEnum implements ExceptionInterface { | |||
/** | |||
* 机场环境检查异常! | |||
*/ | |||
AIRPORT_ENVIORMENT_ERROR(5555, "机场环境检查异常!"), | |||
; | |||
@Getter | |||
private final int code; | |||
@Getter | |||
private final String message; | |||
} |
@@ -0,0 +1,14 @@ | |||
package com.tuoheng.admin.mapper; | |||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||
import com.tuoheng.admin.pojo.entity.Airport; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 机场表 Mapper 接口 | |||
* @Version: 1.0 | |||
*/ | |||
public interface AirportMapper extends BaseMapper<Airport> { | |||
} |
@@ -0,0 +1,100 @@ | |||
package com.tuoheng.admin.pojo.entity; | |||
import com.baomidou.mybatisplus.annotation.TableName; | |||
import com.tuoheng.common.common.BaseEntity; | |||
import lombok.Data; | |||
import lombok.EqualsAndHashCode; | |||
import lombok.experimental.Accessors; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 机场表 | |||
* @Version: 1.0 | |||
*/ | |||
@Data | |||
@EqualsAndHashCode(callSuper = true) | |||
@Accessors(chain = true) | |||
@TableName("th_airport") | |||
public class Airport extends BaseEntity { | |||
private static final long serialVersionUID = 1L; | |||
/** | |||
* 设备编号 | |||
*/ | |||
private String code; | |||
/** | |||
* 设备名称 | |||
*/ | |||
private String name; | |||
/** | |||
* 机场照片 | |||
*/ | |||
private String image; | |||
/** | |||
* 外部监控地址 | |||
*/ | |||
private String externalMonitorUrl; | |||
/** | |||
* 外部监控地址flv | |||
*/ | |||
private String flvExternalMonitorUrl; | |||
/** | |||
* 内部监控地址 | |||
*/ | |||
private String internalMonitorUrl; | |||
/** | |||
* 覆盖范围 | |||
*/ | |||
private String coverage; | |||
/** | |||
* 排序 | |||
*/ | |||
private Integer sort; | |||
/** | |||
* 备注 | |||
*/ | |||
private String note; | |||
/** | |||
* 经度 | |||
*/ | |||
private String longitude; | |||
/** | |||
* 纬度 | |||
*/ | |||
private String latitude; | |||
/** | |||
* 无人机ID | |||
*/ | |||
private Integer droneId; | |||
/** | |||
* 地面站url | |||
*/ | |||
private String groundStationUrl; | |||
/** | |||
* 控制板Id | |||
*/ | |||
private String edgeId; | |||
/** | |||
* mqtt控制板客户端Id | |||
*/ | |||
private String mqClientId; | |||
/*机场运行状态*/ | |||
private int astatus; | |||
private String address; | |||
} |
@@ -0,0 +1,15 @@ | |||
package com.tuoheng.admin.service; | |||
import com.tuoheng.admin.pojo.entity.Airport; | |||
import com.tuoheng.common.common.IBaseService; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 机场表 服务类 | |||
* @Version: 1.0 | |||
*/ | |||
public interface IAirportService extends IBaseService<Airport> { | |||
} |
@@ -0,0 +1,19 @@ | |||
package com.tuoheng.admin.service.impl; | |||
import com.tuoheng.admin.mapper.AirportMapper; | |||
import com.tuoheng.admin.pojo.entity.Airport; | |||
import com.tuoheng.admin.service.IAirportService; | |||
import com.tuoheng.common.common.BaseServiceImpl; | |||
import org.springframework.stereotype.Service; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 机场表 服务实现类 | |||
* @Version: 1.0 | |||
*/ | |||
@Service | |||
public class AirportServiceImpl extends BaseServiceImpl<AirportMapper, Airport> implements IAirportService { | |||
} |
@@ -0,0 +1,295 @@ | |||
package com.tuoheng.admin.service.mqttService; | |||
import org.springframework.lang.Nullable; | |||
import javax.net.ssl.HttpsURLConnection; | |||
import javax.net.ssl.SSLContext; | |||
import javax.net.ssl.TrustManager; | |||
import javax.net.ssl.X509TrustManager; | |||
import java.io.*; | |||
import java.net.HttpURLConnection; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.security.cert.CertificateException; | |||
import java.security.cert.X509Certificate; | |||
/** | |||
* @author ww | |||
* @date 2022/07/8 10:42 | |||
*/ | |||
public class HttpURLConnectionUtil { | |||
/** | |||
* Http get请求 | |||
* @param httpUrl 连接 | |||
* @return 响应数据 | |||
*/ | |||
public static String doGet(String httpUrl){ | |||
//链接 | |||
HttpURLConnection connection = null; | |||
InputStream is = null; | |||
BufferedReader br = null; | |||
StringBuffer result = new StringBuffer(); | |||
try { | |||
//创建连接 | |||
URL url = new URL(httpUrl); | |||
connection = (HttpURLConnection) url.openConnection(); | |||
//设置请求方式 | |||
connection.setRequestMethod("GET"); | |||
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.setRequestProperty("Content-Type", "application/json;charset=utf-8"); | |||
connection.setRequestProperty("Authorization", "Basic YWRtaW46cHVibGlj"); | |||
connection.setRequestProperty("Cookie", "jenkins-timestamper-offset=-28800000; order=id%20desc; serverType=nginx; ltd_end=-1; pro_end=-1; memSize=7768; bt_user_info=%7B%22status%22%3Atrue%2C%22msg%22%3A%22%u83B7%u53D6%u6210%u529F%21%22%2C%22data%22%3A%7B%22username%22%3A%22139****4314%22%7D%7D; sites_path=/www/wwwroot; distribution=centos8; p-1=1; lang=en-US; force=0; b6e922e8cf76dea67efb3a9292724aee=acc59469-46e3-4576-b216-81b907d80a7f.rB3Plw7uc301E0qFoEBeoP_fL4w; load_search=undefined; remember-me=YWRtaW46MTY1ODIxMDYwODA2MDoxY2ZhOTBhMzFlN2IzZTg1YzM5MWQ3Y2M4MWEzYzVlZmYzM2UzOGQ4MTVjZDZhNTUwNjQ4YjFhMjVlYTM3NWJj; JSESSIONID.fc8332ab=node01bo1jsydkd8ql1oo3srksa2k6w288.node0; screenResolution=1920x1080; b2651c13496a99bc2899b024b99bca4f=b4e55bb9-4a3e-44b6-ae8b-c054e7115182.SEaDzMgHxI4d2CGoGwNPnj3L2y4; request_token=hH1LwVtazrgz4sMI4CE1SwEVpCYgiQcHNp4EfyvPni9C32PJ; soft_remarks=%7B%22list%22%3A%5B%22%u4F01%u4E1A%u7248%u3001%u4E13%u4E1A%u7248%u63D2%u4EF6%22%2C%2215%u5929%u65E0%u7406%u7531%u9000%u6B3E%22%2C%22%u53EF%u66F4%u6362IP%22%2C%22%u5E74%u4ED8%u8D60%u90012%u5F20SSL%u8BC1%u4E66%22%2C%22%u5E74%u4ED8%u8D60%u90011000%u6761%u77ED%u4FE1%22%2C%22%u4F4E%u81F32.43%u5143/%u5929%22%2C%22%u5546%u7528%u9632%u706B%u5899%u6388%u6743%22%2C%22%u5E74%u4ED8%u53EF%u5165%u4F01%u4E1A%u7248%u670D%u52A1%u7FA4%22%2C%22%u4EA7%u54C1%u6388%u6743%u8BC1%u4E66%22%5D%2C%22pro_list%22%3A%5B%22%u4E13%u4E1A%u7248%u63D2%u4EF6%22%2C%2215%u5929%u65E0%u7406%u7531%u9000%u6B3E%22%2C%22%u53EF%u66F4%u6362IP%22%2C%22%u4F4E%u81F31.18%u5143/%u5929%22%2C%22%u5546%u7528%u9632%u706B%u5899%u6388%u6743%22%2C%22%u4EA7%u54C1%u6388%u6743%u8BC1%u4E66%22%5D%2C%22kfqq%22%3A%223007255432%22%2C%22kf%22%3A%22http%3A//q.url.cn/CDfQPS%3F_type%3Dwpa%26qidian%3Dtrue%22%2C%22qun%22%3A%22%22%2C%22kf_list%22%3A%5B%7B%22qq%22%3A%223007255432%22%2C%22kf%22%3A%22http%3A//q.url.cn/CDfQPS%3F_type%3Dwpa%26qidian%3Dtrue%22%7D%2C%7B%22qq%22%3A%222927440070%22%2C%22kf%22%3A%22http%3A//wpa.qq.com/msgrd%3Fv%3D3%26uin%3D2927440070%26site%3Dqq%26menu%3Dyes%26from%3Dmessage%26isappinstalled%3D0%22%7D%5D%2C%22wx_list%22%3A%5B%7B%22ps%22%3A%22%u552E%u524D%u54A8%u8BE2%22%2C%22kf%22%3A%22https%3A//work.weixin.qq.com/kfid/kfc72fcbde93e26a6f3%22%7D%5D%7D; load_page=null; load_type=null"); | |||
//设置连接超时时间 | |||
connection.setReadTimeout(15000); | |||
//开始连接 | |||
connection.connect(); | |||
//获取响应数据 | |||
if (connection.getResponseCode() == 200) { | |||
//获取返回的数据 | |||
is = connection.getInputStream(); | |||
if (null != is) { | |||
br = new BufferedReader(new InputStreamReader(is, "UTF-8")); | |||
String temp = null; | |||
while (null != (temp = br.readLine())) { | |||
result.append(temp); | |||
} | |||
} | |||
} | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} finally { | |||
if (null != br) { | |||
try { | |||
br.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if (null != is) { | |||
try { | |||
is.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
//关闭远程连接 | |||
connection.disconnect(); | |||
} | |||
return result.toString(); | |||
} | |||
/** | |||
* Http post请求 | |||
* @param httpUrl 连接 | |||
* @param param 参数 | |||
* @return | |||
*/ | |||
public static String doPost(String httpUrl, @Nullable String param) { | |||
StringBuffer result = new StringBuffer(); | |||
//连接 | |||
HttpURLConnection connection = null; | |||
OutputStream os = null; | |||
InputStream is = null; | |||
BufferedReader br = null; | |||
trustAllHosts(); | |||
try { | |||
//创建连接对象 | |||
URL url = new URL(httpUrl); | |||
//创建连接 | |||
connection = (HttpURLConnection) url.openConnection(); | |||
//设置请求方法 | |||
connection.setRequestMethod("POST"); | |||
//设置连接超时时间 | |||
connection.setConnectTimeout(15000); | |||
//设置读取超时时间 | |||
connection.setReadTimeout(15000); | |||
//DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个 | |||
//设置是否可读取 | |||
connection.setDoOutput(true); | |||
connection.setDoInput(true); | |||
//设置通用的请求属性 | |||
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.setRequestProperty("Content-Type", "application/json;charset=utf-8"); | |||
//拼装参数 | |||
if (null != param && (!param.equals(""))) { | |||
//设置参数 | |||
os = connection.getOutputStream(); | |||
//拼装参数 | |||
os.write(param.getBytes("UTF-8")); | |||
} | |||
//设置权限 | |||
//设置请求头等 | |||
//开启连接 | |||
//connection.connect(); | |||
//读取响应 | |||
if (connection.getResponseCode() == 200) { | |||
is = connection.getInputStream(); | |||
if (null != is) { | |||
//br = new BufferedReader(new InputStreamReader(is, "GBK")); | |||
br = new BufferedReader(new InputStreamReader(is, "UTF-8")); | |||
String temp = null; | |||
while (null != (temp = br.readLine())) { | |||
result.append(temp); | |||
result.append("\r\n"); | |||
} | |||
} | |||
} | |||
} catch (MalformedURLException e) { | |||
e.printStackTrace(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} finally { | |||
//关闭连接 | |||
if(br!=null){ | |||
try { | |||
br.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(os!=null){ | |||
try { | |||
os.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(is!=null){ | |||
try { | |||
is.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
//关闭连接 | |||
connection.disconnect(); | |||
} | |||
return result.toString(); | |||
} | |||
public static String doPut(String httpUrl, @Nullable String param) { | |||
StringBuffer result = new StringBuffer(); | |||
//连接 | |||
HttpURLConnection connection = null; | |||
OutputStream os = null; | |||
InputStream is = null; | |||
BufferedReader br = null; | |||
try { | |||
//创建连接对象 | |||
URL url = new URL(httpUrl); | |||
//创建连接 | |||
connection = (HttpURLConnection) url.openConnection(); | |||
//设置请求方法 | |||
connection.setRequestMethod("PUT"); | |||
//设置连接超时时间 | |||
connection.setConnectTimeout(15000); | |||
//设置读取超时时间 | |||
connection.setReadTimeout(15000); | |||
//DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个 | |||
//设置是否可读取 | |||
connection.setDoOutput(true); | |||
connection.setDoInput(true); | |||
//设置通用的请求属性 | |||
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.setRequestProperty("Content-Type", "application/json;charset=utf-8"); | |||
//拼装参数 | |||
if (null != param && (!param.equals(""))) { | |||
//设置参数 | |||
os = connection.getOutputStream(); | |||
//拼装参数 | |||
os.write(param.getBytes("UTF-8")); | |||
} | |||
//设置权限 | |||
//设置请求头等 | |||
//开启连接 | |||
//connection.connect(); | |||
//读取响应 | |||
if (connection.getResponseCode() == 200) { | |||
is = connection.getInputStream(); | |||
if (null != is) { | |||
//br = new BufferedReader(new InputStreamReader(is, "GBK")); | |||
br = new BufferedReader(new InputStreamReader(is, "UTF-8")); | |||
String temp = null; | |||
while (null != (temp = br.readLine())) { | |||
result.append(temp); | |||
result.append("\r\n"); | |||
} | |||
} | |||
} | |||
} catch (MalformedURLException e) { | |||
e.printStackTrace(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} finally { | |||
//关闭连接 | |||
if(br!=null){ | |||
try { | |||
br.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(os!=null){ | |||
try { | |||
os.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(is!=null){ | |||
try { | |||
is.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
//关闭连接 | |||
connection.disconnect(); | |||
} | |||
return result.toString(); | |||
} | |||
public static void main(String[] args) { | |||
String message = doPost("https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13026194071", ""); | |||
System.out.println(message); | |||
} | |||
/** | |||
* Trust every server - dont check for any certificate | |||
*/ | |||
private static void trustAllHosts() { | |||
final String TAG = "trustAllHosts"; | |||
// Create a trust manager that does not validate certificate chains | |||
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { | |||
public X509Certificate[] getAcceptedIssuers() { | |||
return new X509Certificate[]{}; | |||
} | |||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |||
//Log.i(TAG, "checkClientTrusted"); | |||
} | |||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |||
//Log.i(TAG, "checkServerTrusted"); | |||
} | |||
}}; | |||
// Install the all-trusting trust manager | |||
try { | |||
SSLContext sc = SSLContext.getInstance("TLS"); | |||
sc.init(null, trustAllCerts, new java.security.SecureRandom()); | |||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
package com.tuoheng.admin.service.mqttService; | |||
import org.springframework.beans.factory.annotation.Value; | |||
import org.springframework.stereotype.Controller; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.ResponseBody; | |||
@Controller | |||
public class MqHttp { | |||
@Value("${spring.mqtt.onlineUrl}") | |||
String url; | |||
@RequestMapping("/doGetClient") | |||
@ResponseBody | |||
public String doGetClient(){ | |||
HttpURLConnectionUtil httpURLConnectionUtil = new HttpURLConnectionUtil(); | |||
//String urls=url.replace("tcp","http").replace("1883","18083"); | |||
//String urls="https://mqtt.t-aaron.com"; | |||
String a = httpURLConnectionUtil.doGet(""+url+"/api/v4/clients?_page=1&_limit=100&_=1657249001745"); | |||
return a; | |||
} | |||
//http://124.223.218.130:18083/api/v4/nodes/emqx@127.0.0.1/subscriptions/001497326DAA2502?_=1657257768467 | |||
@RequestMapping("/doGetClientById") | |||
@ResponseBody | |||
public String doGetClientById(String clientId){ | |||
HttpURLConnectionUtil httpURLConnectionUtil = new HttpURLConnectionUtil(); | |||
//String urls=url.replace("tcp","http").replace("1883","18083"); | |||
//String urls="https://mqtt.t-aaron.com"; | |||
String a = httpURLConnectionUtil.doGet(""+url+"/api/v4/clients/"+clientId+"?_=1657257768467"); | |||
return a; | |||
} | |||
} | |||
@@ -0,0 +1,249 @@ | |||
package com.tuoheng.admin.service.mqttService.consumer; | |||
import com.alibaba.fastjson.JSON; | |||
import com.alibaba.fastjson.JSONObject; | |||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |||
import com.tuoheng.admin.pojo.entity.Airport; | |||
import com.tuoheng.admin.service.IAirportService; | |||
import com.tuoheng.admin.utils.SpringUtil; | |||
import com.tuoheng.common.utils.RedisUtils; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; | |||
import org.eclipse.paho.client.mqttv3.MqttCallback; | |||
import org.eclipse.paho.client.mqttv3.MqttMessage; | |||
import java.text.DateFormat; | |||
import java.text.SimpleDateFormat; | |||
import java.util.ArrayList; | |||
import java.util.Date; | |||
import java.util.List; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: MQTT 消息监听回调 | |||
* @Version: 1.0 | |||
*/ | |||
@Slf4j | |||
public class MqttConsumerCallBack implements MqttCallback{ | |||
/** | |||
* 客户端断开连接的回调 | |||
*/ | |||
@Override | |||
public void connectionLost(Throwable throwable) { | |||
System.out.println("与服务器断开连接,可重连"); | |||
/*MqttProviderConfig client = SpringUtil.getBean(MqttProviderConfig.class); | |||
System.out.println(client.isconnect()); | |||
if (!client.isconnect()) { | |||
client.connect(); | |||
System.out.println("重连成功!"); | |||
}*/ | |||
} | |||
DateFormat bf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |||
/** | |||
* 消息到达的回调 | |||
*/ | |||
@Override | |||
public void messageArrived(String topic, MqttMessage message) throws Exception { | |||
try { | |||
log.info("接收消息主题 : {}\n{}",topic,JSONObject.parse(message.getPayload())); | |||
RedisUtils redisUtils = SpringUtil.getBean(RedisUtils.class); | |||
String edgId = topic.split("/")[2]; | |||
String command = topic.substring(edgId.length() + 4, topic.length()); | |||
if (!(command.contains("data/")||command.contains("alarm/"))) { | |||
redisUtils.hset(edgId, command, message, 100); | |||
}else{ | |||
//上报数据换算 | |||
message = getMathValue(message,command,redisUtils,edgId); | |||
redisUtils.hset(edgId, command, message); | |||
redisUtils.hset(edgId+"_data", command, message); | |||
if(command.contains("alarm")) { | |||
command = command.replace("alarm", "data"); | |||
redisUtils.hset(edgId, command, message); | |||
redisUtils.hset(edgId+"_data", command, message); | |||
} | |||
getWth(command,redisUtils,edgId, message); | |||
} | |||
//saveStatus(edgId,command,message); | |||
//消息日志入库 | |||
//saveLog(edgId, command, message); | |||
//保存机场的运行状态 | |||
saveAirportRedisStatus(command,redisUtils,edgId, message); | |||
}catch (Exception e){ | |||
log.error("",e); | |||
e.printStackTrace(); | |||
} | |||
} | |||
/** | |||
* 保存机场的运行状态 | |||
* @param command | |||
* @param redisUtils | |||
* @param edgId | |||
* @param message | |||
*/ | |||
private void saveAirportRedisStatus(String command, RedisUtils redisUtils, String edgId, MqttMessage message) { | |||
JSONObject jsonObject = (JSONObject)JSONObject.parse(message.getPayload()); | |||
IAirportService airportService = SpringUtil.getBean(IAirportService.class); | |||
QueryWrapper queryWrapper = new QueryWrapper(); | |||
queryWrapper.eq("edge_id",edgId); | |||
queryWrapper.eq("mark",1); | |||
List<Airport> list = airportService.list(queryWrapper); | |||
if (list.size()>0){ | |||
edgId = list.get(0).getCode(); | |||
} | |||
/** | |||
* 1,2 舱门(命令接收,动作完成) | |||
* 3,4 升降器(命令接收,动作完成) | |||
* 5,6 固定器(命令接收,动作完成) | |||
* 7,8 出舱(命令接收,动作完成) | |||
* 9,10 回舱(命令接收,动作完成) | |||
* 11 任务中 | |||
* 12 返航中 | |||
* 13 悬停中 | |||
*/ | |||
if(command.contains("confirm/DoorMotor")&&jsonObject.get("msg").toString().contains("SUCCESS")) { | |||
if(jsonObject.get("msg")!=null&&jsonObject.get("msg").toString().contains("SUCCESS")){ | |||
redisUtils.hset("airportRunStatus",edgId,"1"); | |||
} | |||
}else if (command.contains("data/DoorMotor")){ | |||
if(jsonObject.get("parm")!=null&&(JSONObject.toJSONString(jsonObject.get("parm"))).contains("true")){ | |||
redisUtils.hset("airportRunStatus",edgId,"2"); | |||
} | |||
}else if(command.contains("confirm/LiftMotor")) { | |||
if(jsonObject.get("msg")!=null&&jsonObject.get("msg").toString().contains("SUCCESS")){ | |||
redisUtils.hset("airportRunStatus",edgId,"3"); | |||
} | |||
}else if (command.contains("data/LiftMotor")){ | |||
if(jsonObject.get("parm")!=null&&(JSONObject.toJSONString(jsonObject.get("parm"))).contains("true")){ | |||
redisUtils.hset("airportRunStatus",edgId,"4"); | |||
} | |||
}else if(command.contains("confirm/FixedMotor")) { | |||
if(jsonObject.get("msg")!=null&&jsonObject.get("msg").toString().contains("SUCCESS")){ | |||
redisUtils.hset("airportRunStatus",edgId,"5"); | |||
} | |||
}else if (command.contains("data/FixedMotor")){ | |||
if(jsonObject.get("parm")!=null&&(JSONObject.toJSONString(jsonObject.get("parm"))).contains("true")){ | |||
redisUtils.hset("airportRunStatus",edgId,"6"); | |||
} | |||
}else if(command.contains("confirm/DroneGoAway")) { | |||
if(jsonObject.get("msg")!=null&&jsonObject.get("msg").toString().contains("SUCCESS")){ | |||
redisUtils.hset("airportRunStatus",edgId,"7"); | |||
} | |||
}else if (command.contains("data/DroneGoAway")){ | |||
if(jsonObject.get("parm")!=null&&(JSONObject.toJSONString(jsonObject.get("parm"))).contains("true")){ | |||
redisUtils.hset("airportRunStatus",edgId,"8"); | |||
} | |||
}else if(command.contains("confirm/DroneGoHome")) { | |||
if(jsonObject.get("msg")!=null&&jsonObject.get("msg").toString().contains("SUCCESS")){ | |||
redisUtils.hset("airportRunStatus",edgId,"9"); | |||
} | |||
}else if (command.contains("data/DroneGoHome")){ | |||
if(jsonObject.get("parm")!=null&&(JSONObject.toJSONString(jsonObject.get("parm"))).contains("true")){ | |||
redisUtils.hset("airportRunStatus",edgId,"10"); | |||
} | |||
} | |||
} | |||
//上报数据换算封装 | |||
private MqttMessage getMathValue(MqttMessage message,String command,RedisUtils redisUtils,String edgeId) { | |||
JSONObject jsonObject = (JSONObject)JSONObject.parse(message.getPayload()); | |||
JSONObject parmObjectList = (JSONObject)jsonObject.get("parm"); | |||
if(command.contains("/WTH")) { | |||
JSONObject parmNew = (JSONObject) parmObjectList.clone(); | |||
parmNew.put("WDIRNAME", getMathValueWDIR(parmObjectList.get("WDIR")==null?"0":parmObjectList.get("WDIR").toString())); | |||
parmNew.put("WDIR", String.format("%.2f",Double.parseDouble(parmObjectList.get("WDIR")==null?"0":parmObjectList.get("WDIR").toString())/10)); | |||
parmNew.put("WSPD", String.format("%.2f", Double.parseDouble(parmObjectList.get("WSPD")==null?"0":parmObjectList.get("WSPD").toString()) / 100)); | |||
parmNew.put("Rainfull", String.format("%.2f",Double.parseDouble(parmObjectList.get("Rainfull")==null?"0":parmObjectList.get("Rainfull").toString())*0.3)); | |||
parmNew.put("Hpa", String.format("%.2f",Double.parseDouble(parmObjectList.get("Hpa")==null?"0":parmObjectList.get("Hpa").toString())*0.001)); | |||
parmNew.put("Hum", String.format("%.2f",Double.parseDouble(parmObjectList.get("Hum")==null?"0":parmObjectList.get("Hum").toString())*0.1)); | |||
parmNew.put("Tmp", String.format("%.2f",Double.parseDouble(parmObjectList.get("Tmp")==null?"0":parmObjectList.get("Tmp").toString())*0.1)); | |||
parmNew.put("Lux", String.format("%.2f",Double.parseDouble(parmObjectList.get("Lux")==null?"0":parmObjectList.get("Lux").toString())*0.1)); | |||
parmNew.put("Nosie", String.format("%.2f",Double.parseDouble(parmObjectList.get("Nosie")==null?"0":parmObjectList.get("Nosie").toString())*0.1)); | |||
parmNew.put("Dew", String.format("%.2f",Double.parseDouble(parmObjectList.get("Dew")==null?"0":parmObjectList.get("Dew").toString())*0.1)); | |||
String acd = redisUtils.hget("acd",edgeId)==null?"":redisUtils.hget("acd",edgeId).toString(); | |||
parmNew.put("ACDTmp",acd); | |||
jsonObject.put("parmNew",parmNew); | |||
}else if(command.contains("/TAH")) { | |||
JSONObject parmNew = (JSONObject) parmObjectList.clone(); | |||
parmNew.put("Hum", String.format("%.2f",Double.parseDouble(parmObjectList.get("Hum")==null?"0":parmObjectList.get("Hum").toString())*0.1)); | |||
parmNew.put("Tmp", String.format("%.2f",Double.parseDouble(parmObjectList.get("Tmp")==null?"0":parmObjectList.get("Tmp").toString())*0.1)); | |||
jsonObject.put("parmNew",parmNew); | |||
} | |||
if (command.contains("/ACD")){ | |||
JSONObject parmNew = (JSONObject) parmObjectList.clone(); | |||
parmNew.put("ACDTmp", String.format("%.2f",Double.parseDouble(parmObjectList.get("Tmp")==null?"0":parmObjectList.get("Tmp").toString())*0.1)); | |||
jsonObject.put("parmNew",parmNew); | |||
redisUtils.hset("acd",edgeId,String.format("%.2f",Double.parseDouble(parmObjectList.get("Tmp")==null?"0":parmObjectList.get("Tmp").toString())*0.1),180); | |||
} | |||
if (command.contains("DoorMotor")||command.contains("DroneGoAway")){ | |||
} | |||
message.setPayload(jsonObject.toJSONString().getBytes()); | |||
return message; | |||
} | |||
private Object getMathValueWDIR(String wdir) { | |||
double dr = Double.parseDouble(wdir)/10; | |||
double resultde=dr-180; | |||
if (resultde==0){ | |||
return "北风"; | |||
} | |||
if (resultde>0&&resultde<90){ | |||
return "东北风"; | |||
} | |||
if (resultde==90){ | |||
return "东风"; | |||
} | |||
if (resultde>90&&resultde<180){ | |||
return "东南风"; | |||
} | |||
if (resultde==180){ | |||
return "南风"; | |||
} | |||
if (resultde>-90&&resultde<0){ | |||
return "西北风"; | |||
} | |||
if (resultde==-90){ | |||
return "西风"; | |||
} | |||
if (resultde>-180&&resultde<-90){ | |||
return "西南风"; | |||
} | |||
return ""; | |||
} | |||
/** | |||
* 消息发布成功的回调 | |||
*/ | |||
@Override | |||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { | |||
} | |||
public void getWth(String command,RedisUtils redisUtils,String edgId,MqttMessage message){ | |||
if(command.contains("data/WTH")||command.contains("data/TAH")){ | |||
JSONObject json = (JSONObject) JSON.parse(message.getPayload()); | |||
List list = (List) redisUtils.get(edgId+command+"list"); | |||
if(list==null) { | |||
list = new ArrayList(); | |||
} | |||
if(list.size()>3){ | |||
list.remove(0); | |||
} | |||
JSONObject map = (JSONObject)json.get("parm"); | |||
map.put("date", new Date()); | |||
list.add(map); | |||
redisUtils.set(edgId+command+"list",list); | |||
System.out.println(json.get("parm")); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,49 @@ | |||
package com.tuoheng.admin.service.mqttService.send; | |||
import org.eclipse.paho.client.mqttv3.IMqttAsyncClient; | |||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; | |||
import org.eclipse.paho.client.mqttv3.MqttCallback; | |||
import org.eclipse.paho.client.mqttv3.MqttMessage; | |||
import org.springframework.beans.factory.annotation.Value; | |||
import org.springframework.context.annotation.Configuration; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: MQTT 消息发送回调 | |||
* @Version: 1.0 | |||
*/ | |||
@Configuration | |||
public class MqttProviderCallBack implements MqttCallback{ | |||
@Value("${spring.mqtt.client.id}") | |||
private String clientId; | |||
/** | |||
* 与服务器断开的回调 | |||
*/ | |||
@Override | |||
public void connectionLost(Throwable cause) { | |||
System.out.println(clientId+"与服务器断开连接"); | |||
} | |||
/** | |||
* 消息到达的回调 | |||
*/ | |||
@Override | |||
public void messageArrived(String topic, MqttMessage message) throws Exception { | |||
} | |||
/** | |||
* 消息发布成功的回调 | |||
*/ | |||
@Override | |||
public void deliveryComplete(IMqttDeliveryToken token) { | |||
IMqttAsyncClient client = token.getClient(); | |||
System.out.println(client.getClientId()+"发布消息成功!"); | |||
} | |||
} | |||
@@ -0,0 +1,201 @@ | |||
package com.tuoheng.admin.service.mqttService.send; | |||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |||
import com.tuoheng.admin.enums.MQTTTopicEnum; | |||
import com.tuoheng.admin.pojo.entity.Airport; | |||
import com.tuoheng.admin.service.IAirportService; | |||
import com.tuoheng.admin.service.mqttService.consumer.MqttConsumerCallBack; | |||
import com.tuoheng.common.utils.IpUtils; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.eclipse.paho.client.mqttv3.*; | |||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.beans.factory.annotation.Value; | |||
import org.springframework.context.annotation.Configuration; | |||
import javax.annotation.PostConstruct; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: MQTT配置类 | |||
* @Version: 1.0 | |||
*/ | |||
@Configuration | |||
@Slf4j | |||
public class MqttProviderConfig { | |||
@Value("${spring.mqtt.username}") | |||
private String username; | |||
@Value("${spring.mqtt.password}") | |||
private String password; | |||
@Value("${spring.mqtt.url}") | |||
private String hostUrl; | |||
@Value("${spring.mqtt.client.id}") | |||
private String clientId; | |||
@Value("${spring.mqtt.default.topic}") | |||
private String defaultTopic; | |||
/** | |||
* 客户端对象 | |||
*/ | |||
private MqttClient client; | |||
@Autowired | |||
private IAirportService airportService; | |||
/** | |||
* 在bean初始化后连接到服务器 | |||
*/ | |||
@PostConstruct | |||
public void init(){ | |||
connect(); | |||
} | |||
/** | |||
* 客户端连接服务端 | |||
*/ | |||
public void connect(){ | |||
try{ | |||
String ip = IpUtils.getHostIp(); | |||
//创建MQTT客户端对象 | |||
client = new MqttClient(hostUrl,ip,new MemoryPersistence()); | |||
//连接设置 | |||
MqttConnectOptions options = new MqttConnectOptions(); | |||
//是否清空session,设置false表示服务器会保留客户端的连接记录(订阅主题,qos),客户端重连之后能获取到服务器在客户端断开连接期间推送的消息 | |||
//设置为true表示每次连接服务器都是以新的身份 | |||
options.setCleanSession(true); | |||
//设置连接用户名 | |||
options.setUserName(username); | |||
//设置连接密码 | |||
options.setPassword(password.toCharArray()); | |||
//设置超时时间,单位为秒 | |||
options.setConnectionTimeout(100); | |||
//设置心跳时间 单位为秒,表示服务器每隔 1.5*20秒的时间向客户端发送心跳判断客户端是否在线 | |||
options.setKeepAliveInterval(20); | |||
//设置遗嘱消息的话题,若客户端和服务器之间的连接意外断开,服务器将发布客户端的遗嘱信息 | |||
options.setWill("willTopic",(ip + "与服务器断开连接").getBytes(),0,false); | |||
//防止 ERROR o.e.p.c.mqttv3.internal.ClientState - Timed out as no activity 错误 | |||
options.setConnectionTimeout(0); | |||
//mqttClient.reconnect(); 这个方法或者回调已经设置了重连 | |||
//options.setAutomaticReconnect(true); | |||
//设置回调 | |||
client.setCallback(new MqttConsumerCallBack()); | |||
client.connect(options); | |||
QueryWrapper wrapper = new QueryWrapper(); | |||
wrapper.eq("mark",1); | |||
List airportList = airportService.list(wrapper); | |||
/** | |||
* 遍历所有的设备,一次订阅每个设备的对应事件的topic | |||
*/ | |||
airportList.forEach(item ->{ | |||
Airport airport = (Airport)item; | |||
Arrays.stream(MQTTTopicEnum.values()).forEach(mqttTopicEnum -> { | |||
try { | |||
client.subscribe(String.format(mqttTopicEnum.getTopic(),airport.getEdgeId()),mqttTopicEnum.getQos()); | |||
} catch (MqttException e) { | |||
log.error("订阅设备:{},对应topic:{}异常:{}",airport.getEdgeId(),mqttTopicEnum.getTopic(),e); | |||
} | |||
}); | |||
}); | |||
} catch(MqttException e){ | |||
log.error("MQTT链接异常:{}",e); | |||
} | |||
} | |||
public boolean isconnect() { | |||
try { | |||
String ip = IpUtils.getHostIp(); | |||
//创建MQTT客户端对象 | |||
client = new MqttClient(hostUrl,ip,new MemoryPersistence()); | |||
}catch (Exception e){ | |||
log.error("MQTT链接异常:{}",e); | |||
} | |||
return client.isConnected(); | |||
} | |||
/** | |||
* MQTT发布消息 | |||
* @param qos | |||
* @param retained | |||
* @param topic | |||
* @param message | |||
* @return | |||
*/ | |||
public MqttDeliveryToken publish(int qos,boolean retained,String topic,String message){ | |||
if (!client.isConnected()){ | |||
connect(); | |||
} | |||
MqttDeliveryToken token=null; | |||
MqttMessage mqttMessage = new MqttMessage(); | |||
mqttMessage.setQos(qos); | |||
mqttMessage.setRetained(retained); | |||
mqttMessage.setPayload(message.getBytes()); | |||
//主题的目的地,用于发布/订阅信息 | |||
MqttTopic mqttTopic = client.getTopic(topic); | |||
//提供一种机制来跟踪消息的传递进度 | |||
//用于在以非阻塞方式(在后台运行)执行发布是跟踪消息的传递进度 | |||
try { | |||
//将指定消息发布到主题,但不等待消息传递完成,返回的token可用于跟踪消息的传递状态 | |||
//一旦此方法干净地返回,消息就已被客户端接受发布,当连接可用,将在后台完成消息传递。 | |||
token = mqttTopic.publish(mqttMessage); | |||
token.waitForCompletion(); | |||
} catch (MqttException e) { | |||
log.error("MQTT topic:{},message:{},消息发送异常:{}",topic,message,e); | |||
} | |||
return token; | |||
} | |||
/** | |||
* 断开连接 | |||
*/ | |||
public void disConnect(){ | |||
try { | |||
client.disconnect(); | |||
} catch (MqttException e) { | |||
log.error("MQTT断开链接异常:{}",e); | |||
} | |||
} | |||
/** | |||
* 订阅主题 | |||
*/ | |||
public void subscribe(String topic,int qos){ | |||
try { | |||
client.subscribe(topic,qos); | |||
} catch (MqttException e) { | |||
log.error("MQTT订阅topic:{}异常:{}",topic,e); | |||
} | |||
} | |||
public MqttClient getClient(){ | |||
return client; | |||
} | |||
/** | |||
* 订阅集成列表 | |||
*/ | |||
public void subscribeAllAirport(Airport airport) throws MqttException { | |||
if (!client.isConnected()){ | |||
connect(); | |||
} | |||
Arrays.stream(MQTTTopicEnum.values()).forEach(mqttTopicEnum -> { | |||
try { | |||
client.subscribe(String.format(mqttTopicEnum.getTopic(),airport.getEdgeId()),mqttTopicEnum.getQos()); | |||
} catch (MqttException e) { | |||
log.error("订阅设备:{},对应topic:{}异常:{}",airport.getEdgeId(),mqttTopicEnum.getTopic(),e); | |||
} | |||
}); | |||
} | |||
} | |||
@@ -0,0 +1,230 @@ | |||
package com.tuoheng.admin.utils; | |||
import com.aliyun.oss.OSSClient; | |||
import com.aliyun.oss.model.ObjectMetadata; | |||
import com.aliyun.oss.model.PutObjectResult; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.beans.factory.annotation.Value; | |||
import org.springframework.stereotype.Component; | |||
import org.springframework.web.multipart.MultipartFile; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.util.*; | |||
/** | |||
* 描述: 阿里云OSS工具类 | |||
* 版权: Copyright (c) 2020 | |||
* 公司: XXX | |||
* 作者: yanghj | |||
* 版本: 4.0 | |||
* 创建日期: 2020/9/16 11:38 | |||
*/ | |||
@Component | |||
@Slf4j | |||
public class AliyunOSSUtil { | |||
@Value("${aliyun.oss.endpoint:}") | |||
private String endpoint; | |||
@Value("${aliyun.oss.accessKeyId:}") | |||
private String accessKeyId; | |||
@Value("${aliyun.oss.accessKeySecret:}") | |||
private String accessKeySecret; | |||
@Value("${aliyun.oss.bucketName:}") | |||
private String bucketName; | |||
//文件存储目录 | |||
@Value("${aliyun.oss.filedir:}") | |||
private String filedir; | |||
//-----------------对外功能---------------- | |||
/** | |||
* 1、单个文件上传 | |||
* @param file | |||
* @return 返回完整URL地址 | |||
*/ | |||
public String uploadFile(MultipartFile file) | |||
{ | |||
String fileUrl = uploadImg2Oss(file); | |||
String str = getFileUrl(fileUrl); | |||
return str.trim(); | |||
} | |||
/** | |||
* 1、单个文件上传(指定文件名(带后缀)) | |||
* @param file | |||
* @return 返回完整URL地址 | |||
*/ | |||
public String uploadFile(MultipartFile file,String fileName) | |||
{ | |||
try | |||
{ | |||
InputStream inputStream = file.getInputStream(); | |||
this.uploadFile2OSS(inputStream, fileName); | |||
return fileName; | |||
} | |||
catch (Exception e) | |||
{ | |||
return "上传失败"; | |||
} | |||
} | |||
/** | |||
* 2、多文件上传 | |||
* @param fileList | |||
* @return 返回完整URL,逗号分隔 | |||
*/ | |||
public String uploadFile(List<MultipartFile> fileList) { | |||
String fileUrl = ""; | |||
String str = ""; | |||
String photoUrl = ""; | |||
for(int i = 0;i< fileList.size();i++){ | |||
fileUrl = uploadImg2Oss(fileList.get(i)); | |||
str = getFileUrl(fileUrl); | |||
if(i == 0){ | |||
photoUrl = str; | |||
}else { | |||
photoUrl += "," + str; | |||
} | |||
} | |||
return photoUrl.trim(); | |||
} | |||
/** | |||
* 3、通过文件名获取文完整件路径 | |||
* @param fileUrl | |||
* @return 完整URL路径 | |||
*/ | |||
public String getFileUrl(String fileUrl) | |||
{ | |||
if (fileUrl !=null && fileUrl.length()>0) { | |||
String[] split = fileUrl.split("/"); | |||
String url = this.getUrl(this.filedir + split[split.length - 1]); | |||
return url; | |||
} | |||
return null; | |||
} | |||
//-----------内部辅助功能------------------------ | |||
//获取去掉参数的完整路径 | |||
private String getShortUrl(String url) | |||
{ | |||
String[] imgUrls = url.split("\\?"); | |||
return imgUrls[0].trim(); | |||
} | |||
// 获得url链接 | |||
private String getUrl(String key) { | |||
// 设置URL过期时间为20年 3600l* 1000*24*365*20 | |||
Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24 * 365 * 20); | |||
// 生成URL | |||
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret); | |||
URL url = ossClient.generatePresignedUrl(bucketName, key, expiration); | |||
if (url != null) | |||
{ | |||
return getShortUrl(url.toString()); | |||
} | |||
return null; | |||
} | |||
// 上传文件 | |||
private String uploadImg2Oss(MultipartFile file) | |||
{ | |||
//1、限制最大文件为20M | |||
if (file.getSize() > 1024 * 1024 *20) | |||
{ | |||
return "图片太大"; | |||
} | |||
String fileName = file.getOriginalFilename(); | |||
String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase(); //文件后缀 | |||
String uuid = UUID.randomUUID().toString(); | |||
String name = uuid + suffix; | |||
try | |||
{ | |||
InputStream inputStream = file.getInputStream(); | |||
this.uploadFile2OSS(inputStream, name); | |||
return name; | |||
} | |||
catch (Exception e) | |||
{ | |||
return "上传失败"; | |||
} | |||
} | |||
// 上传文件(指定文件名) | |||
public String uploadFile2OSS(InputStream instream, String fileName) | |||
{ | |||
String ret = ""; | |||
try { | |||
//创建上传Object的Metadata | |||
ObjectMetadata objectMetadata = new ObjectMetadata(); | |||
objectMetadata.setContentLength(instream.available()); | |||
objectMetadata.setCacheControl("no-cache"); | |||
objectMetadata.setHeader("Pragma", "no-cache"); | |||
objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf(".")))); | |||
objectMetadata.setContentDisposition("inline;filename=" + fileName); | |||
//上传文件 | |||
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret); | |||
PutObjectResult putResult = ossClient.putObject(bucketName, filedir + fileName, instream, objectMetadata); | |||
ret = putResult.getETag(); | |||
} catch (IOException e) { | |||
log.error(e.getMessage(), e); | |||
} finally { | |||
try { | |||
if (instream != null) { | |||
instream.close(); | |||
} | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
return ret; | |||
} | |||
private static String getcontentType(String FilenameExtension) | |||
{ | |||
if (FilenameExtension.equalsIgnoreCase(".bmp")) { | |||
return "image/bmp"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".gif")) { | |||
return "image/gif"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".jpeg") || | |||
FilenameExtension.equalsIgnoreCase(".jpg") || | |||
FilenameExtension.equalsIgnoreCase(".png")) { | |||
return "image/jpeg"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".html")) { | |||
return "text/html"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".txt")) { | |||
return "text/plain"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".vsd")) { | |||
return "application/vnd.visio"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".pptx") || | |||
FilenameExtension.equalsIgnoreCase(".ppt")) { | |||
return "application/vnd.ms-powerpoint"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".docx") || | |||
FilenameExtension.equalsIgnoreCase(".doc")) { | |||
return "application/msword"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".xml")) { | |||
return "text/xml"; | |||
} | |||
if (FilenameExtension.equalsIgnoreCase(".pdf")) { | |||
return "application/pdf"; | |||
} | |||
return "image/jpeg"; | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
package com.tuoheng.admin.utils; | |||
import lombok.Data; | |||
/** | |||
* @author chenjiandong | |||
* @description: TODO | |||
* @date 2022/11/23 16:50 | |||
*/ | |||
@Data | |||
public class AliyunOssResult { | |||
/** | |||
* code:200成功 | |||
* code: 400失败 | |||
*/ | |||
private int code; | |||
/** | |||
* 上传成功的返回url | |||
*/ | |||
private String url; | |||
/** | |||
* 提示信息 | |||
*/ | |||
private String msg; | |||
} |
@@ -0,0 +1,61 @@ | |||
package com.tuoheng.admin.utils; | |||
import org.quartz.CronExpression; | |||
import java.text.ParseException; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import java.util.Objects; | |||
/** | |||
* | |||
*/ | |||
public class CronUtils { | |||
private static final SimpleDateFormat sdf = new SimpleDateFormat("ss mm HH dd MM ?"); | |||
/*** | |||
* 功能描述:日期转换cron表达式 | |||
* @param date | |||
* @return | |||
*/ | |||
public static String formatDateByPattern(Date date) { | |||
String formatTimeStr = null; | |||
if (Objects.nonNull(date)) { | |||
formatTimeStr = sdf.format(date); | |||
} | |||
return formatTimeStr; | |||
} | |||
/*** | |||
* convert Date to cron, eg "0 07 10 15 1 ?" | |||
* @param date : 时间点 | |||
* @return | |||
*/ | |||
public static String getCron(Date date) { | |||
return formatDateByPattern(date); | |||
} | |||
public static String getSdf(String datestr) throws ParseException { | |||
// 创建日期格式化对象 | |||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |||
// 将日期字符串解析为Date对象 | |||
Date date = sdf.parse(datestr); | |||
// 创建Cron表达式生成器 | |||
CronExpression cronExpression = new CronExpression(String.valueOf(date)); | |||
// 获取生成的Cron表达式 | |||
String expression = cronExpression.getCronExpression(); | |||
return expression; | |||
} | |||
} | |||
@@ -0,0 +1,40 @@ | |||
package com.tuoheng.admin.utils; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import java.util.UUID; | |||
/** | |||
* @author chenjiandong | |||
* @description: 生成随机序列号 | |||
* @date 2022/11/9 15:59 | |||
*/ | |||
public class GenerateDroneSerialNumber { | |||
public static String[] chars = new String[] { | |||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | |||
"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" | |||
}; | |||
public static String generateShortUuid() { | |||
StringBuffer shortBuffer = new StringBuffer(); | |||
String uuid = UUID.randomUUID().toString().replace("-", ""); | |||
for (int i = 0; i < 8; i++) { | |||
String str = uuid.substring(i * 4, i * 4 + 4); | |||
int x = Integer.parseInt(str, 16); | |||
shortBuffer.append(chars[x % 34]); | |||
} | |||
return shortBuffer.toString(); | |||
} | |||
public static String getDateCode() { | |||
Date d = new Date(); | |||
SimpleDateFormat sdf = new SimpleDateFormat("YYMM"); | |||
String sdfDateCode = sdf.format(d); | |||
System.out.println("格式化后的日期年月code:" + sdfDateCode); | |||
return sdfDateCode; | |||
} | |||
} |
@@ -0,0 +1,295 @@ | |||
package com.tuoheng.admin.utils; | |||
import org.springframework.lang.Nullable; | |||
import javax.net.ssl.HttpsURLConnection; | |||
import javax.net.ssl.SSLContext; | |||
import javax.net.ssl.TrustManager; | |||
import javax.net.ssl.X509TrustManager; | |||
import java.io.*; | |||
import java.net.HttpURLConnection; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.security.cert.CertificateException; | |||
import java.security.cert.X509Certificate; | |||
/** | |||
* @author ww | |||
* @date 2022/07/8 10:42 | |||
*/ | |||
public class HttpURLConnectionUtil { | |||
/** | |||
* Http get请求 | |||
* @param httpUrl 连接 | |||
* @return 响应数据 | |||
*/ | |||
public static String doGet(String httpUrl){ | |||
//链接 | |||
HttpURLConnection connection = null; | |||
InputStream is = null; | |||
BufferedReader br = null; | |||
StringBuffer result = new StringBuffer(); | |||
try { | |||
//创建连接 | |||
URL url = new URL(httpUrl); | |||
connection = (HttpURLConnection) url.openConnection(); | |||
//设置请求方式 | |||
connection.setRequestMethod("GET"); | |||
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.setRequestProperty("Content-Type", "application/json;charset=utf-8"); | |||
connection.setRequestProperty("Authorization", "Basic YWRtaW46cHVibGlj"); | |||
connection.setRequestProperty("Cookie", "jenkins-timestamper-offset=-28800000; order=id%20desc; serverType=nginx; ltd_end=-1; pro_end=-1; memSize=7768; bt_user_info=%7B%22status%22%3Atrue%2C%22msg%22%3A%22%u83B7%u53D6%u6210%u529F%21%22%2C%22data%22%3A%7B%22username%22%3A%22139****4314%22%7D%7D; sites_path=/www/wwwroot; distribution=centos8; p-1=1; lang=en-US; force=0; b6e922e8cf76dea67efb3a9292724aee=acc59469-46e3-4576-b216-81b907d80a7f.rB3Plw7uc301E0qFoEBeoP_fL4w; load_search=undefined; remember-me=YWRtaW46MTY1ODIxMDYwODA2MDoxY2ZhOTBhMzFlN2IzZTg1YzM5MWQ3Y2M4MWEzYzVlZmYzM2UzOGQ4MTVjZDZhNTUwNjQ4YjFhMjVlYTM3NWJj; JSESSIONID.fc8332ab=node01bo1jsydkd8ql1oo3srksa2k6w288.node0; screenResolution=1920x1080; b2651c13496a99bc2899b024b99bca4f=b4e55bb9-4a3e-44b6-ae8b-c054e7115182.SEaDzMgHxI4d2CGoGwNPnj3L2y4; request_token=hH1LwVtazrgz4sMI4CE1SwEVpCYgiQcHNp4EfyvPni9C32PJ; soft_remarks=%7B%22list%22%3A%5B%22%u4F01%u4E1A%u7248%u3001%u4E13%u4E1A%u7248%u63D2%u4EF6%22%2C%2215%u5929%u65E0%u7406%u7531%u9000%u6B3E%22%2C%22%u53EF%u66F4%u6362IP%22%2C%22%u5E74%u4ED8%u8D60%u90012%u5F20SSL%u8BC1%u4E66%22%2C%22%u5E74%u4ED8%u8D60%u90011000%u6761%u77ED%u4FE1%22%2C%22%u4F4E%u81F32.43%u5143/%u5929%22%2C%22%u5546%u7528%u9632%u706B%u5899%u6388%u6743%22%2C%22%u5E74%u4ED8%u53EF%u5165%u4F01%u4E1A%u7248%u670D%u52A1%u7FA4%22%2C%22%u4EA7%u54C1%u6388%u6743%u8BC1%u4E66%22%5D%2C%22pro_list%22%3A%5B%22%u4E13%u4E1A%u7248%u63D2%u4EF6%22%2C%2215%u5929%u65E0%u7406%u7531%u9000%u6B3E%22%2C%22%u53EF%u66F4%u6362IP%22%2C%22%u4F4E%u81F31.18%u5143/%u5929%22%2C%22%u5546%u7528%u9632%u706B%u5899%u6388%u6743%22%2C%22%u4EA7%u54C1%u6388%u6743%u8BC1%u4E66%22%5D%2C%22kfqq%22%3A%223007255432%22%2C%22kf%22%3A%22http%3A//q.url.cn/CDfQPS%3F_type%3Dwpa%26qidian%3Dtrue%22%2C%22qun%22%3A%22%22%2C%22kf_list%22%3A%5B%7B%22qq%22%3A%223007255432%22%2C%22kf%22%3A%22http%3A//q.url.cn/CDfQPS%3F_type%3Dwpa%26qidian%3Dtrue%22%7D%2C%7B%22qq%22%3A%222927440070%22%2C%22kf%22%3A%22http%3A//wpa.qq.com/msgrd%3Fv%3D3%26uin%3D2927440070%26site%3Dqq%26menu%3Dyes%26from%3Dmessage%26isappinstalled%3D0%22%7D%5D%2C%22wx_list%22%3A%5B%7B%22ps%22%3A%22%u552E%u524D%u54A8%u8BE2%22%2C%22kf%22%3A%22https%3A//work.weixin.qq.com/kfid/kfc72fcbde93e26a6f3%22%7D%5D%7D; load_page=null; load_type=null"); | |||
//设置连接超时时间 | |||
connection.setReadTimeout(15000); | |||
//开始连接 | |||
connection.connect(); | |||
//获取响应数据 | |||
if (connection.getResponseCode() == 200) { | |||
//获取返回的数据 | |||
is = connection.getInputStream(); | |||
if (null != is) { | |||
br = new BufferedReader(new InputStreamReader(is, "UTF-8")); | |||
String temp = null; | |||
while (null != (temp = br.readLine())) { | |||
result.append(temp); | |||
} | |||
} | |||
} | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} finally { | |||
if (null != br) { | |||
try { | |||
br.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if (null != is) { | |||
try { | |||
is.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
//关闭远程连接 | |||
connection.disconnect(); | |||
} | |||
return result.toString(); | |||
} | |||
/** | |||
* Http post请求 | |||
* @param httpUrl 连接 | |||
* @param param 参数 | |||
* @return | |||
*/ | |||
public static String doPost(String httpUrl, @Nullable String param) { | |||
StringBuffer result = new StringBuffer(); | |||
//连接 | |||
HttpURLConnection connection = null; | |||
OutputStream os = null; | |||
InputStream is = null; | |||
BufferedReader br = null; | |||
trustAllHosts(); | |||
try { | |||
//创建连接对象 | |||
URL url = new URL(httpUrl); | |||
//创建连接 | |||
connection = (HttpURLConnection) url.openConnection(); | |||
//设置请求方法 | |||
connection.setRequestMethod("POST"); | |||
//设置连接超时时间 | |||
connection.setConnectTimeout(15000); | |||
//设置读取超时时间 | |||
connection.setReadTimeout(15000); | |||
//DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个 | |||
//设置是否可读取 | |||
connection.setDoOutput(true); | |||
connection.setDoInput(true); | |||
//设置通用的请求属性 | |||
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.setRequestProperty("Content-Type", "application/json;charset=utf-8"); | |||
//拼装参数 | |||
if (null != param && (!param.equals(""))) { | |||
//设置参数 | |||
os = connection.getOutputStream(); | |||
//拼装参数 | |||
os.write(param.getBytes("UTF-8")); | |||
} | |||
//设置权限 | |||
//设置请求头等 | |||
//开启连接 | |||
//connection.connect(); | |||
//读取响应 | |||
if (connection.getResponseCode() == 200) { | |||
is = connection.getInputStream(); | |||
if (null != is) { | |||
//br = new BufferedReader(new InputStreamReader(is, "GBK")); | |||
br = new BufferedReader(new InputStreamReader(is, "UTF-8")); | |||
String temp = null; | |||
while (null != (temp = br.readLine())) { | |||
result.append(temp); | |||
result.append("\r\n"); | |||
} | |||
} | |||
} | |||
} catch (MalformedURLException e) { | |||
e.printStackTrace(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} finally { | |||
//关闭连接 | |||
if(br!=null){ | |||
try { | |||
br.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(os!=null){ | |||
try { | |||
os.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(is!=null){ | |||
try { | |||
is.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
//关闭连接 | |||
connection.disconnect(); | |||
} | |||
return result.toString(); | |||
} | |||
public static String doPut(String httpUrl, @Nullable String param) { | |||
StringBuffer result = new StringBuffer(); | |||
//连接 | |||
HttpURLConnection connection = null; | |||
OutputStream os = null; | |||
InputStream is = null; | |||
BufferedReader br = null; | |||
try { | |||
//创建连接对象 | |||
URL url = new URL(httpUrl); | |||
//创建连接 | |||
connection = (HttpURLConnection) url.openConnection(); | |||
//设置请求方法 | |||
connection.setRequestMethod("PUT"); | |||
//设置连接超时时间 | |||
connection.setConnectTimeout(15000); | |||
//设置读取超时时间 | |||
connection.setReadTimeout(15000); | |||
//DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个 | |||
//设置是否可读取 | |||
connection.setDoOutput(true); | |||
connection.setDoInput(true); | |||
//设置通用的请求属性 | |||
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.setRequestProperty("Content-Type", "application/json;charset=utf-8"); | |||
//拼装参数 | |||
if (null != param && (!param.equals(""))) { | |||
//设置参数 | |||
os = connection.getOutputStream(); | |||
//拼装参数 | |||
os.write(param.getBytes("UTF-8")); | |||
} | |||
//设置权限 | |||
//设置请求头等 | |||
//开启连接 | |||
//connection.connect(); | |||
//读取响应 | |||
if (connection.getResponseCode() == 200) { | |||
is = connection.getInputStream(); | |||
if (null != is) { | |||
//br = new BufferedReader(new InputStreamReader(is, "GBK")); | |||
br = new BufferedReader(new InputStreamReader(is, "UTF-8")); | |||
String temp = null; | |||
while (null != (temp = br.readLine())) { | |||
result.append(temp); | |||
result.append("\r\n"); | |||
} | |||
} | |||
} | |||
} catch (MalformedURLException e) { | |||
e.printStackTrace(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} finally { | |||
//关闭连接 | |||
if(br!=null){ | |||
try { | |||
br.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(os!=null){ | |||
try { | |||
os.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if(is!=null){ | |||
try { | |||
is.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
//关闭连接 | |||
connection.disconnect(); | |||
} | |||
return result.toString(); | |||
} | |||
public static void main(String[] args) { | |||
String message = doPost("https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13026194071", ""); | |||
System.out.println(message); | |||
} | |||
/** | |||
* Trust every server - dont check for any certificate | |||
*/ | |||
private static void trustAllHosts() { | |||
final String TAG = "trustAllHosts"; | |||
// Create a trust manager that does not validate certificate chains | |||
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { | |||
public X509Certificate[] getAcceptedIssuers() { | |||
return new X509Certificate[]{}; | |||
} | |||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |||
//Log.i(TAG, "checkClientTrusted"); | |||
} | |||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |||
//Log.i(TAG, "checkServerTrusted"); | |||
} | |||
}}; | |||
// Install the all-trusting trust manager | |||
try { | |||
SSLContext sc = SSLContext.getInstance("TLS"); | |||
sc.init(null, trustAllCerts, new java.security.SecureRandom()); | |||
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,66 @@ | |||
package com.tuoheng.admin.utils; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.data.redis.core.StringRedisTemplate; | |||
import org.springframework.stereotype.Component; | |||
import org.springframework.util.StringUtils; | |||
/** | |||
* redis分布式锁 | |||
* @author :小肖 | |||
* @date :Created in 2022/2/10 13:28 | |||
*/ | |||
@Component | |||
@Slf4j | |||
public class RedisLock { | |||
@Autowired | |||
private StringRedisTemplate redisTemplate; | |||
/** | |||
* 加锁 | |||
* @param key | |||
* @param value | |||
* @return | |||
*/ | |||
public boolean lock(String key,String value){ | |||
if(redisTemplate.opsForValue().setIfAbsent(key,value)){ | |||
// 加锁成功 | |||
return true; | |||
} | |||
// 如果锁过期 | |||
String currentValue = redisTemplate.opsForValue().get(key); | |||
if(!StringUtils.isEmpty(currentValue) && | |||
Long.parseLong(currentValue) < System.currentTimeMillis()){ | |||
String oldValue = redisTemplate.opsForValue().getAndSet(key,value); | |||
if(!StringUtils.isEmpty(oldValue) && | |||
oldValue.equals(oldValue)){ | |||
return true; | |||
} | |||
} | |||
// 锁已经被其它线程获取 | |||
return false; | |||
} | |||
/** | |||
* 解锁 | |||
* @param key | |||
* @param value | |||
*/ | |||
public void unlock(String key,String value){ | |||
try{ | |||
String currentValue = redisTemplate.opsForValue().get(key); | |||
if(!StringUtils.isEmpty(currentValue) && | |||
currentValue.equals(value)){ | |||
redisTemplate.opsForValue().getOperations().delete(key); | |||
} | |||
}catch (Exception e){ | |||
log.error("【redis 分布式锁】 解锁异常,{}",e); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,60 @@ | |||
package com.tuoheng.admin.utils; | |||
import org.springframework.beans.BeansException; | |||
import org.springframework.context.ApplicationContext; | |||
import org.springframework.context.ApplicationContextAware; | |||
import org.springframework.stereotype.Component; | |||
/** | |||
* 实现ApplicationContextAware接口,并加入Component注解,让spring扫描到该bean | |||
* 该类用于在普通Java类中注入bean,普通Java类中用@Autowired是无法注入bean的 | |||
*/ | |||
@Component | |||
public class SpringUtil implements ApplicationContextAware { | |||
private static ApplicationContext applicationContext; | |||
@Override | |||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { | |||
if(SpringUtil.applicationContext == null) { | |||
SpringUtil.applicationContext = applicationContext; | |||
} | |||
} | |||
/** | |||
* 获取applicationContext | |||
*/ | |||
public static ApplicationContext getApplicationContext() { | |||
return applicationContext; | |||
} | |||
/** | |||
*通过name获取 Bean. | |||
* @param name | |||
* @return | |||
*/ | |||
public static Object getBean(String name){ | |||
return getApplicationContext().getBean(name); | |||
} | |||
/** | |||
* 通过class获取Bean. | |||
* @param clazz | |||
* @param <T> | |||
* @return | |||
*/ | |||
public static <T> T getBean(Class<T> clazz){ | |||
return getApplicationContext().getBean(clazz); | |||
} | |||
/** | |||
* 通过name,以及Clazz返回指定的Bean | |||
* @param name | |||
* @param clazz | |||
* @param <T> | |||
* @return | |||
*/ | |||
public static <T> T getBean(String name,Class<T> clazz){ | |||
return getApplicationContext().getBean(name, clazz); | |||
} | |||
} |
@@ -0,0 +1,217 @@ | |||
# 自定义配置 | |||
tuoheng: | |||
# 图片域名 | |||
# 后期要修改 | |||
#image-url: http://images.airport.dev.taauav.com | |||
image-url: #http://192.168.11.22:30079/airport/uploads/ | |||
spring: | |||
# 注册中心consul地址 | |||
cloud: | |||
consul: | |||
host: 192.168.11.13 # consul 所在服务地址 | |||
port: 8500 # consul 服务端口 | |||
discovery: | |||
# 是否启用服务发现 | |||
enabled: true | |||
# 配置服务注册 | |||
register: true | |||
deregister: true | |||
## consul ip地址 | |||
hostname: 192.168.11.13 | |||
# 注册到consul的服务名称 | |||
service-name: ${spring.application.name} # 服务提供者名称 | |||
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} #实例ID | |||
heartbeat: | |||
enabled: true | |||
prefer-ip-address: true | |||
health-check-path: /actuator/health #健康检查 | |||
health-check-interval: 10s | |||
# 配置数据源 | |||
datasource: | |||
# 使用阿里的Druid连接池 | |||
type: com.alibaba.druid.pool.DruidDataSource | |||
driver-class-name: com.mysql.cj.jdbc.Driver | |||
# 填写你数据库的url、登录名、密码和数据库名 | |||
url: jdbc:mysql://192.168.11.13:3306/tuoheng_airport?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 | |||
mqtt: | |||
onlineUrl: http://192.168.11.22:18083 | |||
#MQTT服务地址,端口号默认11883,如果有多个,用逗号隔开 | |||
url: tcp://192.168.11.22:1883 | |||
#用户名 | |||
username: admin | |||
#密码 | |||
password: public | |||
#客户端id(不能重复) | |||
client: | |||
id: provider-id | |||
#MQTT默认的消息推送主题,实际可在调用接口是指定 | |||
default: | |||
topic: topic | |||
# Redis数据源 | |||
redis: | |||
# 缓存库默认索引0 | |||
database: 9 | |||
# Redis服务器地址 | |||
host: 192.168.11.13 | |||
# 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: 100MB | |||
# 上传文件总的最大值 | |||
max-request-size: 500MB | |||
#邮件配置 | |||
mail: | |||
# 设置邮箱主机 | |||
host: smtp.qq.com | |||
# 开启邮箱POP3/SMTP服务,获取客户端授权码(注意并不是邮箱密码,而是授权码) | |||
password: | |||
# 邮箱的用户名 | |||
username: | |||
properties: | |||
mail: | |||
smtp: | |||
# 设置是否需要认证,如果为true,那么用户名和密码就必须的。如果设置false,可以不设置用户名和密码,当然也得看你的对接的平台是否支持无密码进行访问的。 | |||
auth: true | |||
starttls: | |||
# STARTTLS[1] 是对纯文本通信协议的扩展。它提供一种方式将纯文本连接升级为加密连接(TLS或SSL),而不是另外使用一个端口作加密通信。 | |||
enable: true | |||
require: true | |||
alisms: | |||
accessKeyId: | |||
accessKeySecret: | |||
regionId: cn-hangzhou | |||
signName: 拓恒 | |||
templateCode: | |||
file: | |||
#上传的服务器上的映射文件夹 | |||
accessPath: /uploads/ | |||
#静态资源对外暴露的访问路径 | |||
staticAccessPath: /** | |||
#静态资源实际存储路径 | |||
uploadFolder: /home/airport/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 | |||
#踢出之前用户还是之后用户 | |||
kickoutAfter: true | |||
# 最大同时在线人数,-1 表示无限制 | |||
maxSession: 1 | |||
# 代码生成 | |||
generate: | |||
# 作者 | |||
author: 拓恒 | |||
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool | |||
packageName: com.tuoheng.system | |||
# 模块名 | |||
moduleName: tuoheng-system | |||
# 自动去除表前缀,默认是true | |||
autoRemovePre: true | |||
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔) | |||
tablePrefix: sys_ | |||
# 阿里云存储参数配置 | |||
aliyun: | |||
oss: | |||
endpoint: "https://oss-cn-shanghai.aliyuncs.com" | |||
accessKeyId: "LTAI5tCMz1nQ3U6jQj8tR8XQ" | |||
accessKeySecret: "qH9CwhQwKhNY2g8MyZnHFhhIYqQgTB" | |||
bucketName: "th-airport" | |||
filedir: "devFile/" |
@@ -0,0 +1,196 @@ | |||
# 自定义配置 | |||
tuoheng: | |||
# 图片域名 | |||
# 后期要修改 | |||
#image-url: http://images.airport.dev.taauav.com | |||
image-url: http://192.168.144.88:30079/ | |||
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_airport?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=true&tinyInt1isBit=false | |||
username: th | |||
password: th | |||
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 | |||
mqtt: | |||
onlineUrl: http://127.0.0.1:18083 | |||
#MQTT服务地址,端口号默认11883,如果有多个,用逗号隔开 | |||
url: tcp://127.0.0.1:1883 | |||
#用户名 | |||
username: admin | |||
#密码 | |||
password: admin##123 | |||
#客户端id(不能重复) | |||
client: | |||
id: provider-id | |||
#MQTT默认的消息推送主题,实际可在调用接口是指定 | |||
default: | |||
topic: topic | |||
# Redis数据源 | |||
redis: | |||
# 缓存库默认索引0 | |||
database: 9 | |||
# 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: 100MB | |||
# 上传文件总的最大值 | |||
max-request-size: 500MB | |||
#邮件配置 | |||
mail: | |||
# 设置邮箱主机 | |||
host: smtp.qq.com | |||
# 开启邮箱POP3/SMTP服务,获取客户端授权码(注意并不是邮箱密码,而是授权码) | |||
password: | |||
# 邮箱的用户名 | |||
username: | |||
properties: | |||
mail: | |||
smtp: | |||
# 设置是否需要认证,如果为true,那么用户名和密码就必须的。如果设置false,可以不设置用户名和密码,当然也得看你的对接的平台是否支持无密码进行访问的。 | |||
auth: true | |||
starttls: | |||
# STARTTLS[1] 是对纯文本通信协议的扩展。它提供一种方式将纯文本连接升级为加密连接(TLS或SSL),而不是另外使用一个端口作加密通信。 | |||
enable: true | |||
require: true | |||
alisms: | |||
accessKeyId: | |||
accessKeySecret: | |||
regionId: cn-hangzhou | |||
signName: 拓恒 | |||
templateCode: | |||
file: | |||
#上传的服务器上的映射文件夹 | |||
accessPath: /uploads/ | |||
#静态资源对外暴露的访问路径 | |||
staticAccessPath: /** | |||
#静态资源实际存储路径 | |||
uploadFolder: /home/airport/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 | |||
#踢出之前用户还是之后用户 | |||
kickoutAfter: true | |||
# 最大同时在线人数,-1 表示无限制 | |||
maxSession: 1 | |||
# 代码生成 | |||
generate: | |||
# 作者 | |||
author: 拓恒 | |||
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool | |||
packageName: com.tuoheng.system | |||
# 模块名 | |||
moduleName: tuoheng-system | |||
# 自动去除表前缀,默认是true | |||
autoRemovePre: true | |||
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔) | |||
tablePrefix: sys_ | |||
# 阿里云存储参数配置 | |||
aliyun: | |||
oss: | |||
endpoint: "https://oss-cn-shanghai.aliyuncs.com" | |||
accessKeyId: "LTAI5tCMz1nQ3U6jQj8tR8XQ" | |||
accessKeySecret: "qH9CwhQwKhNY2g8MyZnHFhhIYqQgTB" | |||
bucketName: "th-airport" | |||
filedir: "devFile/" |
@@ -0,0 +1,216 @@ | |||
# 自定义配置 | |||
tuoheng: | |||
# 图片域名 | |||
# 后期要修改 | |||
#image-url: http://images.airport.dev.taauav.com | |||
image-url: #http://192.168.11.22:30079/airport/uploads/ | |||
spring: | |||
# 注册中心consul地址 | |||
cloud: | |||
consul: | |||
host: 172.16.5.12 # consul 所在服务地址 | |||
port: 8500 # consul 服务端口 | |||
discovery: # 是否启用服务发现 | |||
enabled: true | |||
# 配置服务注册 | |||
register: true | |||
deregister: true | |||
## consul ip地址 | |||
hostname: 172.16.5.12 | |||
# 注册到consul的服务名称 | |||
service-name: ${spring.application.name} # 服务提供者名称 | |||
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} #实例ID | |||
heartbeat: | |||
enabled: true | |||
prefer-ip-address: true | |||
health-check-path: /actuator/health #健康检查 | |||
health-check-interval: 10s | |||
# 配置数据源 | |||
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_airport?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 | |||
mqtt: | |||
onlineUrl: https://mqtt.t-aaron.com | |||
#MQTT服务地址,端口号默认11883,如果有多个,用逗号隔开 | |||
url: tcp://mqtt.t-aaron.com:10883 | |||
#用户名 | |||
username: admin | |||
#密码 | |||
password: admin##123 | |||
#客户端id(不能重复) | |||
client: | |||
id: provider-id | |||
#MQTT默认的消息推送主题,实际可在调用接口是指定 | |||
default: | |||
topic: topic | |||
# Redis数据源 | |||
redis: | |||
# 缓存库默认索引0 | |||
database: 9 | |||
# 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: 100MB | |||
# 上传文件总的最大值 | |||
max-request-size: 500MB | |||
#邮件配置 | |||
mail: | |||
# 设置邮箱主机 | |||
host: smtp.qq.com | |||
# 开启邮箱POP3/SMTP服务,获取客户端授权码(注意并不是邮箱密码,而是授权码) | |||
password: | |||
# 邮箱的用户名 | |||
username: | |||
properties: | |||
mail: | |||
smtp: | |||
# 设置是否需要认证,如果为true,那么用户名和密码就必须的。如果设置false,可以不设置用户名和密码,当然也得看你的对接的平台是否支持无密码进行访问的。 | |||
auth: true | |||
starttls: | |||
# STARTTLS[1] 是对纯文本通信协议的扩展。它提供一种方式将纯文本连接升级为加密连接(TLS或SSL),而不是另外使用一个端口作加密通信。 | |||
enable: true | |||
require: true | |||
alisms: | |||
accessKeyId: | |||
accessKeySecret: | |||
regionId: cn-hangzhou | |||
signName: 拓恒 | |||
templateCode: | |||
file: | |||
#上传的服务器上的映射文件夹 | |||
accessPath: /uploads/ | |||
#静态资源对外暴露的访问路径 | |||
staticAccessPath: /** | |||
#静态资源实际存储路径 | |||
uploadFolder: /home/airport/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 | |||
#踢出之前用户还是之后用户 | |||
kickoutAfter: true | |||
# 最大同时在线人数,-1 表示无限制 | |||
maxSession: 1 | |||
# 代码生成 | |||
generate: | |||
# 作者 | |||
author: 拓恒 | |||
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool | |||
packageName: com.tuoheng.system | |||
# 模块名 | |||
moduleName: tuoheng-system | |||
# 自动去除表前缀,默认是true | |||
autoRemovePre: true | |||
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔) | |||
tablePrefix: sys_ | |||
# 阿里云存储参数配置 | |||
aliyun: | |||
oss: | |||
endpoint: "https://oss-cn-shanghai.aliyuncs.com" | |||
accessKeyId: "LTAI5tCMz1nQ3U6jQj8tR8XQ" | |||
accessKeySecret: "qH9CwhQwKhNY2g8MyZnHFhhIYqQgTB" | |||
bucketName: "th-airport" | |||
filedir: "prodFile/" |
@@ -0,0 +1,217 @@ | |||
# 自定义配置 | |||
tuoheng: | |||
# 图片域名 | |||
# 后期要修改 | |||
#image-url: http://images.airport.dev.taauav.com | |||
image-url: #http://192.168.11.22:30079/airport/uploads/ | |||
spring: | |||
# 注册中心consul地址 | |||
cloud: | |||
consul: | |||
host: 172.15.1.11 # consul 所在服务地址 | |||
port: 8500 # consul 服务端口 | |||
discovery: | |||
# 是否启用服务发现 | |||
enabled: true | |||
# 配置服务注册 | |||
register: true | |||
deregister: true | |||
## consul ip地址 | |||
hostname: 172.15.1.11 | |||
# 注册到consul的服务名称 | |||
service-name: ${spring.application.name} # 服务提供者名称 | |||
instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} #实例ID | |||
heartbeat: | |||
enabled: true | |||
prefer-ip-address: true | |||
health-check-path: /actuator/health #健康检查 | |||
health-check-interval: 10s | |||
# 配置数据源 | |||
datasource: | |||
# 使用阿里的Druid连接池 | |||
type: com.alibaba.druid.pool.DruidDataSource | |||
driver-class-name: com.mysql.cj.jdbc.Driver | |||
# 填写你数据库的url、登录名、密码和数据库名 | |||
url: jdbc:mysql://rm-uf6z740323e8053pj.mysql.rds.aliyuncs.com:3306/tuoheng_airport?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 | |||
mqtt: | |||
onlineUrl: http://106.15.120.154:18083 | |||
#MQTT服务地址,端口号默认11883,如果有多个,用逗号隔开 | |||
url: tcp://106.15.120.154:1883 | |||
#用户名 | |||
username: admin | |||
#密码 | |||
password: admin##123 | |||
#客户端id(不能重复) | |||
client: | |||
id: provider-id | |||
#MQTT默认的消息推送主题,实际可在调用接口是指定 | |||
default: | |||
topic: topic | |||
# Redis数据源 | |||
redis: | |||
# 缓存库默认索引0 | |||
database: 9 | |||
# Redis服务器地址 | |||
host: r-uf6cdzjifj20jszykr.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: 100MB | |||
# 上传文件总的最大值 | |||
max-request-size: 500MB | |||
#邮件配置 | |||
mail: | |||
# 设置邮箱主机 | |||
host: smtp.qq.com | |||
# 开启邮箱POP3/SMTP服务,获取客户端授权码(注意并不是邮箱密码,而是授权码) | |||
password: | |||
# 邮箱的用户名 | |||
username: | |||
properties: | |||
mail: | |||
smtp: | |||
# 设置是否需要认证,如果为true,那么用户名和密码就必须的。如果设置false,可以不设置用户名和密码,当然也得看你的对接的平台是否支持无密码进行访问的。 | |||
auth: true | |||
starttls: | |||
# STARTTLS[1] 是对纯文本通信协议的扩展。它提供一种方式将纯文本连接升级为加密连接(TLS或SSL),而不是另外使用一个端口作加密通信。 | |||
enable: true | |||
require: true | |||
alisms: | |||
accessKeyId: | |||
accessKeySecret: | |||
regionId: cn-hangzhou | |||
signName: 拓恒 | |||
templateCode: | |||
file: | |||
#上传的服务器上的映射文件夹 | |||
accessPath: /uploads/ | |||
#静态资源对外暴露的访问路径 | |||
staticAccessPath: /** | |||
#静态资源实际存储路径 | |||
uploadFolder: /home/airport/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 | |||
#踢出之前用户还是之后用户 | |||
kickoutAfter: true | |||
# 最大同时在线人数,-1 表示无限制 | |||
maxSession: 1 | |||
# 代码生成 | |||
generate: | |||
# 作者 | |||
author: 拓恒 | |||
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool | |||
packageName: com.tuoheng.system | |||
# 模块名 | |||
moduleName: tuoheng-system | |||
# 自动去除表前缀,默认是true | |||
autoRemovePre: true | |||
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔) | |||
tablePrefix: sys_ | |||
# 阿里云存储参数配置 | |||
aliyun: | |||
oss: | |||
endpoint: "https://oss-cn-shanghai.aliyuncs.com" | |||
accessKeyId: "LTAI5tCMz1nQ3U6jQj8tR8XQ" | |||
accessKeySecret: "qH9CwhQwKhNY2g8MyZnHFhhIYqQgTB" | |||
bucketName: "th-airport" | |||
filedir: "testFile/" |
@@ -0,0 +1,37 @@ | |||
# 端口配置 | |||
server: | |||
port: 9160 | |||
spring: | |||
profiles: | |||
active: @package.environment@ | |||
application: | |||
name: tuoheng-airport-platform | |||
main: | |||
allow-bean-definition-overriding: true | |||
mvc: | |||
view: | |||
prefix: classpath:/templates/ | |||
suffix: .html | |||
# 服务模块 | |||
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 | |||
call-setters-on-nulls: true |
@@ -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_airport_platform/tuoheng_airport.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_airport_platform/tuoheng_airport.%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,26 @@ | |||
com\tuoheng\admin\utils\GenerateDroneSerialNumber.class | |||
com\tuoheng\admin\pojo\entity\Airport.class | |||
com\tuoheng\admin\config\sql\AbstractLikeSqlConverter.class | |||
com\tuoheng\admin\service\mqttService\send\MqttProviderCallBack.class | |||
com\tuoheng\admin\AdminApplication.class | |||
com\tuoheng\admin\utils\CronUtils.class | |||
com\tuoheng\admin\config\sql\ObjectLikeSqlConverter.class | |||
com\tuoheng\admin\enums\ServiceExceptionEnum.class | |||
com\tuoheng\admin\config\sql\MapLikeSqlConverter.class | |||
com\tuoheng\admin\utils\AliyunOSSUtil.class | |||
com\tuoheng\admin\utils\RedisLock.class | |||
com\tuoheng\admin\utils\SpringUtil.class | |||
com\tuoheng\admin\service\impl\AirportServiceImpl.class | |||
com\tuoheng\admin\service\mqttService\HttpURLConnectionUtil$1.class | |||
com\tuoheng\admin\utils\HttpURLConnectionUtil.class | |||
com\tuoheng\admin\utils\AliyunOssResult.class | |||
com\tuoheng\admin\mapper\AirportMapper.class | |||
com\tuoheng\admin\service\mqttService\MqHttp.class | |||
com\tuoheng\admin\service\IAirportService.class | |||
com\tuoheng\admin\service\mqttService\HttpURLConnectionUtil.class | |||
com\tuoheng\admin\enums\MQTTTopicEnum.class | |||
com\tuoheng\admin\service\mqttService\consumer\MqttConsumerCallBack.class | |||
com\tuoheng\admin\utils\HttpURLConnectionUtil$1.class | |||
com\tuoheng\admin\controller\HealthController.class | |||
com\tuoheng\admin\config\sql\MybatisPlusInterceptor.class | |||
com\tuoheng\admin\service\mqttService\send\MqttProviderConfig.class |
@@ -0,0 +1,24 @@ | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\utils\AliyunOssResult.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\service\mqttService\MqHttp.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\service\mqttService\consumer\MqttConsumerCallBack.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\enums\MQTTTopicEnum.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\enums\ServiceExceptionEnum.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\utils\SpringUtil.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\config\sql\MapLikeSqlConverter.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\config\sql\AbstractLikeSqlConverter.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\mapper\AirportMapper.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\controller\HealthController.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\utils\GenerateDroneSerialNumber.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\config\sql\ObjectLikeSqlConverter.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\pojo\entity\Airport.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\service\IAirportService.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\service\mqttService\HttpURLConnectionUtil.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\service\impl\AirportServiceImpl.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\utils\CronUtils.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\config\sql\MybatisPlusInterceptor.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\utils\HttpURLConnectionUtil.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\utils\AliyunOSSUtil.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\AdminApplication.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\service\mqttService\send\MqttProviderConfig.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\utils\RedisLock.java | |||
D:\tuohengWorkSpace\tuoheng_airport_platform\tuoheng-admin\src\main\java\com\tuoheng\admin\service\mqttService\send\MqttProviderCallBack.java |
@@ -0,0 +1,153 @@ | |||
<?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> | |||
<!--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> | |||
</dependencies> | |||
</project> |
@@ -0,0 +1,148 @@ | |||
package com.tuoheng.common.advice; | |||
import com.tuoheng.common.common.SysExceptionEnum; | |||
import com.tuoheng.common.exception.ServiceException; | |||
import com.tuoheng.common.utils.JacksonUtil; | |||
import com.tuoheng.common.utils.JsonResult; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.dao.DataAccessException; | |||
import org.springframework.http.HttpStatus; | |||
import org.springframework.http.ResponseEntity; | |||
import org.springframework.util.CollectionUtils; | |||
import org.springframework.validation.BindException; | |||
import org.springframework.validation.BindingResult; | |||
import org.springframework.validation.FieldError; | |||
import org.springframework.validation.ObjectError; | |||
import org.springframework.web.HttpRequestMethodNotSupportedException; | |||
import org.springframework.web.bind.MethodArgumentNotValidException; | |||
import org.springframework.web.bind.MissingServletRequestParameterException; | |||
import org.springframework.web.bind.annotation.ExceptionHandler; | |||
import org.springframework.web.bind.annotation.ResponseBody; | |||
import org.springframework.web.bind.annotation.RestControllerAdvice; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.validation.ConstraintViolationException; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 自定义异常处理器 | |||
* @Version: 1.0 | |||
*/ | |||
@RestControllerAdvice | |||
@Slf4j | |||
public class CustomExceptionHandler { | |||
/** | |||
* 密码校验异常 | |||
*/ | |||
@ExceptionHandler(BindException.class) | |||
@ResponseBody | |||
public ResponseEntity<JsonResult<Void>> handleAuthenticationException(BindException e) { | |||
BindingResult bindingResult = e.getBindingResult(); | |||
StringBuilder errorMessage = new StringBuilder(); | |||
for (FieldError fieldError : bindingResult.getFieldErrors()) { | |||
// errorMessage.append(fieldError.getField()).append(fieldError.getDefaultMessage()).append(" "); | |||
errorMessage.append(fieldError.getDefaultMessage()).append(" "); | |||
} | |||
log.error("参数格式错误:{}", errorMessage); | |||
return new ResponseEntity<>(JsonResult.error(JsonResult.ERROR, errorMessage.toString()), HttpStatus.OK); | |||
} | |||
/** | |||
* 请求方式不支持 | |||
*/ | |||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class) | |||
public ResponseEntity<JsonResult<Void>> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, | |||
HttpServletRequest request) | |||
{ | |||
String requestURI = request.getRequestURI(); | |||
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); | |||
return new ResponseEntity<>(JsonResult.error(SysExceptionEnum.SYS_EXCEPTION.getCode(), | |||
e.getMessage()), HttpStatus.BAD_REQUEST); | |||
} | |||
/** | |||
* 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是ConstraintViolationException | |||
*/ | |||
@ExceptionHandler(ConstraintViolationException.class) | |||
@ResponseBody | |||
public ResponseEntity<JsonResult<Void>> handleConstraintViolationException(ConstraintViolationException e) { | |||
String message = e.getConstraintViolations() | |||
.stream() | |||
.map(constraintViolation -> constraintViolation.getMessage()) | |||
.collect(Collectors.joining(" ")); | |||
log.error("参数格式错误:{}", message); | |||
return new ResponseEntity<>(JsonResult.error(JsonResult.ERROR, message), HttpStatus.OK); | |||
} | |||
/** | |||
* 校验异常处理 | |||
* 处理请求参数格式错误 @RequestBody上使用@Valid 实体上使用@NotNull等 | |||
*/ | |||
@ExceptionHandler(MethodArgumentNotValidException.class) | |||
@ResponseBody | |||
public ResponseEntity<JsonResult<Void>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { | |||
JsonResult<Void> error = JsonResult.error(SysExceptionEnum.PARAMETER_EMPTY_EXCEPTION.getCode(), | |||
SysExceptionEnum.PARAMETER_EMPTY_EXCEPTION.getMessage()); | |||
BindingResult result = e.getBindingResult(); | |||
List<FieldError> fieldErrors = result.getFieldErrors(); | |||
if (!CollectionUtils.isEmpty(fieldErrors)) { | |||
error.setMsg(fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(" "))); | |||
} else { | |||
if (!CollectionUtils.isEmpty(result.getAllErrors())) { | |||
ObjectError currError = result.getAllErrors().get(0); | |||
// error.setMsg(currError.getObjectName() + currError.getDefaultMessage()); | |||
error.setMsg(currError.getDefaultMessage()); | |||
} | |||
} | |||
log.error("参数格式错误:{}", JacksonUtil.obj2StringPretty(error)); | |||
return new ResponseEntity<>(error, HttpStatus.OK); | |||
} | |||
/** | |||
* 校验异常处理 | |||
*/ | |||
@ExceptionHandler(MissingServletRequestParameterException.class) | |||
@ResponseBody | |||
public ResponseEntity<JsonResult<Void>> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) { | |||
log.error("参数格式错误:", e); | |||
return new ResponseEntity<>(JsonResult.error(JsonResult.ERROR, e.getMessage()), HttpStatus.OK); | |||
} | |||
/** | |||
* 系统业务异常处理 | |||
*/ | |||
@ExceptionHandler(ServiceException.class) | |||
@ResponseBody | |||
public ResponseEntity<JsonResult<Void>> handleServiceException(ServiceException e) { | |||
// 打印业务异常日志 | |||
log.warn("系统业务逻辑异常,异常状态码 {},异常信息:{}", e.code, e.getMessage()); | |||
return new ResponseEntity<>(JsonResult.error(e.getCode(), e.getMsg()), HttpStatus.OK); | |||
} | |||
/** | |||
* 系统数据访问异常处理 | |||
*/ | |||
@ExceptionHandler(DataAccessException.class) | |||
@ResponseBody | |||
public ResponseEntity<JsonResult<Void>> handleDataAccessException(DataAccessException e) { | |||
log.error("系统数据访问异常,异常信息:", e); | |||
return new ResponseEntity<>(JsonResult.error(SysExceptionEnum.DATAACCESS_EXCEPTION.getCode(), | |||
SysExceptionEnum.DATAACCESS_EXCEPTION.getMessage()), HttpStatus.BAD_REQUEST); | |||
} | |||
/** | |||
* 系统异常处理 | |||
*/ | |||
@ExceptionHandler(Exception.class) | |||
@ResponseBody | |||
public ResponseEntity<JsonResult<Void>> handleException(Exception e) { | |||
log.error("系统异常,异常信息:", e); | |||
return new ResponseEntity<>(JsonResult.error(SysExceptionEnum.SYS_EXCEPTION.getCode(), | |||
SysExceptionEnum.SYS_EXCEPTION.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR); | |||
} | |||
} |
@@ -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,64 @@ | |||
package com.tuoheng.common.common; | |||
import com.baomidou.mybatisplus.annotation.FieldFill; | |||
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 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; | |||
/** | |||
* 创建时间 | |||
*/ | |||
@TableField(fill = FieldFill.INSERT_UPDATE) | |||
@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; | |||
/** | |||
* 更新时间 | |||
*/ | |||
@TableField(fill = FieldFill.INSERT_UPDATE) | |||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") | |||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") | |||
private Date updateTime; | |||
/** | |||
* 有效标识 | |||
*/ | |||
private Integer mark; | |||
/** | |||
* 租户id | |||
*/ | |||
private Integer tenantId; | |||
} |
@@ -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,42 @@ | |||
package com.tuoheng.common.config; | |||
import lombok.Data; | |||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||
import org.springframework.context.annotation.Configuration; | |||
/** | |||
* 阿里短信配置类 | |||
*/ | |||
// 让Spring启动的时候扫描到该类,并添加到Spring容器中 | |||
@Configuration | |||
// 设置前缀 | |||
@ConfigurationProperties(prefix = "spring.alisms") | |||
@Data | |||
public class AliSmsConfig { | |||
/** | |||
* KEY | |||
*/ | |||
private String accessKeyId; | |||
/** | |||
* 密钥 | |||
*/ | |||
private String accessKeySecret; | |||
/** | |||
* 区域ID | |||
*/ | |||
private String regionId; | |||
/** | |||
* 短信签名 | |||
*/ | |||
private String signName; | |||
/** | |||
* 短信模板ID | |||
*/ | |||
private String templateCode; | |||
} |
@@ -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,27 @@ | |||
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)); | |||
paginationInterceptor.setLimit(Integer.MAX_VALUE); | |||
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,187 @@ | |||
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.listener.RedisMessageListenerContainer; | |||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; | |||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; | |||
import org.springframework.data.redis.serializer.RedisSerializer; | |||
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; | |||
} | |||
/** | |||
* 使CacheComponent的redisTemplate组件的key使用StringRedisSerializer而非默认的JdkSerializationRedisSerializer | |||
* 避免key出现字节码的情况 | |||
* @param factory redis链接 | |||
* @return RedisTemplate | |||
*/ | |||
/*@Bean | |||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { | |||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); | |||
redisTemplate.setConnectionFactory(factory); | |||
RedisSerializer redisSerializer = new StringRedisSerializer(); | |||
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); | |||
//key使用StringRedisSerializer序列化 | |||
redisTemplate.setKeySerializer(redisSerializer); | |||
//value使用jackson2JsonRedisSerializer序列化 | |||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); | |||
return redisTemplate; | |||
}*/ | |||
/** | |||
* 创建Redis消息监听者容器 | |||
* @param factory | |||
* @return | |||
*/ | |||
@Bean("redisMessageListenerContainer") | |||
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory){ | |||
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); | |||
container.setConnectionFactory(factory); | |||
return container; | |||
} | |||
} |
@@ -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 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,105 @@ | |||
package com.tuoheng.common.controller; | |||
import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
import com.tuoheng.common.config.CommonConfig; | |||
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.*; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import java.io.*; | |||
@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); | |||
} | |||
} | |||
/** | |||
* 下载文件 | |||
* | |||
* @param fileName 文件名 | |||
* @param response | |||
* @return | |||
*/ | |||
@GetMapping("/downloadFile/{fileName}") | |||
public OutputStream downloadFile(@PathVariable("fileName") String fileName, HttpServletResponse response) { | |||
// 替换域名 | |||
if (fileName.contains(CommonConfig.imageURL)) { | |||
fileName = fileName.replaceAll(CommonConfig.imageURL, ""); | |||
} | |||
// 文件地址 | |||
String filePath = UploadFileConfig.uploadFolder + fileName; | |||
if (fileName != null) { | |||
//设置文件路径 | |||
File file = new File(filePath); | |||
if (file.exists()) { | |||
byte[] buffer = new byte[1024]; | |||
FileInputStream fis = null; | |||
BufferedInputStream bis = null; | |||
try { | |||
fis = new FileInputStream(file); | |||
bis = new BufferedInputStream(fis); | |||
OutputStream os = response.getOutputStream(); | |||
int i = bis.read(buffer); | |||
while (i != -1) { | |||
os.write(buffer, 0, i); | |||
i = bis.read(buffer); | |||
} | |||
return os; | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} finally { | |||
if (bis != null) { | |||
try { | |||
bis.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
if (fis != null) { | |||
try { | |||
fis.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
} |
@@ -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: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 业务异常枚举 | |||
* @Version: 1.0 | |||
*/ | |||
@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,65 @@ | |||
package com.tuoheng.common.exception; | |||
import com.tuoheng.common.common.ExceptionInterface; | |||
import com.tuoheng.common.utils.JsonResult; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
/** | |||
* @Author: 吴彬 | |||
* @CreateTime: 2023-05-22 19:09 | |||
* @Description: 业务异常类(业务处理时手动抛出异常) | |||
* @Version: 1.0 | |||
*/ | |||
@Getter | |||
@Setter | |||
public class ServiceException extends RuntimeException { | |||
static final long serialVersionUID = -7034897190745766938L; | |||
/** | |||
* 异常码 | |||
*/ | |||
public int code; | |||
/** | |||
* 异常描述,兼容JsonResult | |||
*/ | |||
private String msg; | |||
/** | |||
* 构造器 | |||
* | |||
* @param exceptionInfo | |||
*/ | |||
public ServiceException(ExceptionInterface exceptionInfo) { | |||
super(exceptionInfo.getMessage()); | |||
this.msg = exceptionInfo.getMessage(); | |||
this.code = exceptionInfo.getCode(); | |||
} | |||
/** | |||
* 构造器 | |||
* | |||
* @param code | |||
* @param msg | |||
*/ | |||
public ServiceException(int code, String msg) { | |||
super(msg); | |||
this.msg = msg; | |||
this.code = code; | |||
} | |||
/** | |||
* 构造器 | |||
* | |||
* @param msg | |||
*/ | |||
public ServiceException(String msg) { | |||
super(msg); | |||
this.msg = msg; | |||
this.code = JsonResult.ERROR; | |||
} | |||
} | |||
@@ -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,71 @@ | |||
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) { | |||
Map<String, Object> map = new HashMap<>(); | |||
try { | |||
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.put("fileName", nameList.get(nameList.size() - 1)); | |||
map.put("fileUrl", imageUrl); | |||
}catch (Exception e){ | |||
System.out.println(e.getMessage()); | |||
e.printStackTrace(); | |||
} | |||
return JsonResult.success(map, "上传成功"); | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
package com.tuoheng.common.utils; | |||
import org.springframework.web.multipart.MultipartFile; | |||
import java.io.*; | |||
public class BASE64DecodedMultipartFile implements MultipartFile { | |||
private final byte[] imgContent; | |||
private final String header; | |||
public BASE64DecodedMultipartFile(byte[] imgContent, String header) { | |||
this.imgContent = imgContent; | |||
this.header = header.split(";")[0]; | |||
} | |||
@Override | |||
public String getName() { | |||
// TODO - implementation depends on your requirements | |||
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1]; | |||
} | |||
@Override | |||
public String getOriginalFilename() { | |||
// TODO - implementation depends on your requirements | |||
return System.currentTimeMillis() + (int)Math.random() * 10000 + "." + header.split("/")[1]; | |||
} | |||
@Override | |||
public String getContentType() { | |||
// TODO - implementation depends on your requirements | |||
return header.split(":")[1]; | |||
} | |||
@Override | |||
public boolean isEmpty() { | |||
return imgContent == null || imgContent.length == 0; | |||
} | |||
@Override | |||
public long getSize() { | |||
return imgContent.length; | |||
} | |||
@Override | |||
public byte[] getBytes() throws IOException { | |||
return imgContent; | |||
} | |||
@Override | |||
public InputStream getInputStream() throws IOException { | |||
return new ByteArrayInputStream(imgContent); | |||
} | |||
@Override | |||
public void transferTo(File dest) throws IOException, IllegalStateException { | |||
new FileOutputStream(dest).write(imgContent); | |||
} | |||
} |
@@ -0,0 +1,94 @@ | |||
package com.tuoheng.common.utils; | |||
import com.tuoheng.common.common.BaseResponse; | |||
import com.tuoheng.common.common.ExceptionInterface; | |||
import com.tuoheng.common.common.SysExceptionEnum; | |||
import com.tuoheng.common.constant.Constant; | |||
import com.tuoheng.common.exception.ServiceException; | |||
/** | |||
* 响应包装工具类 | |||
* | |||
* @author zhu_zishuang | |||
* @date 2021-03-12 | |||
*/ | |||
public final class BaseResponseUtil { | |||
/** | |||
* 成功编码 | |||
*/ | |||
private static final Integer SUCCESS_CODE = 200; | |||
/** | |||
* 默认操作成功提示 | |||
*/ | |||
private static final String DEFAULT_SUCCESS_MESSAGE = "操作成功"; | |||
/** | |||
* 构造器私有,防止外部实例化 | |||
*/ | |||
private BaseResponseUtil() { | |||
// 防止反射 | |||
throw new ServiceException(SysExceptionEnum.SYS_EXCEPTION); | |||
} | |||
/** | |||
* 包裹响应对象,此方法适合写操作没有数据实体场景下调用 | |||
* | |||
* @return 响应实体 | |||
*/ | |||
public static BaseResponse<Object> success() { | |||
return new BaseResponse<>().setCode(SUCCESS_CODE).setMessage(DEFAULT_SUCCESS_MESSAGE); | |||
} | |||
/** | |||
* 包裹响应对象,此方法适合查询操作有数据实体场景下调用 | |||
* | |||
* @param data 数据实体 | |||
* @return 响应实体 | |||
*/ | |||
public static BaseResponse<Object> success(Object data) { | |||
return success().setData(data); | |||
} | |||
/** | |||
* 包裹响应对象,此方法适合 增、删、改 操作有数据实体场景下调用 | |||
* | |||
* @param operationEnum | |||
* @return | |||
*/ | |||
public static BaseResponse<Object> success(ExceptionInterface operationEnum) { | |||
return success().setCode(operationEnum.getCode()).setMessage(operationEnum.getMessage()); | |||
} | |||
/** | |||
* 包裹响应对象,校验框架异常 场景下调用 | |||
* | |||
* @param message 异常消息 | |||
* @return 响应实体 | |||
*/ | |||
public static BaseResponse<Object> fail(Integer code, String message) { | |||
return new BaseResponse<>().setStatus(Constant.FAIL).setCode(code).setMessage(message); | |||
} | |||
/** | |||
* 包裹响应对象,自定义业务异常 场景下调用 | |||
* | |||
* @param baseResponseCode | |||
* @return | |||
*/ | |||
public static BaseResponse<Object> fail(ExceptionInterface baseResponseCode) { | |||
return new BaseResponse<>().setStatus(Constant.FAIL).setCode(baseResponseCode.getCode()).setMessage(baseResponseCode.getMessage()); | |||
} | |||
/** | |||
* 包裹响应对象,系统异常 场景下调用 | |||
* | |||
* @param sysExceptionEnum | |||
* @return 响应实体 | |||
*/ | |||
public static BaseResponse<Object> error(ExceptionInterface sysExceptionEnum) { | |||
return new BaseResponse<>().setStatus(Constant.ERROR).setCode(sysExceptionEnum.getCode()).setMessage(sysExceptionEnum.getMessage()); | |||
} | |||
} | |||
@@ -0,0 +1,89 @@ | |||
package com.tuoheng.common.utils; | |||
import java.nio.charset.Charset; | |||
import java.nio.charset.StandardCharsets; | |||
/** | |||
* 字符串工具集 | |||
*/ | |||
public class CharsetKit { | |||
/** | |||
* ISO-8859-1 | |||
*/ | |||
public static final String ISO_8859_1 = "ISO-8859-1"; | |||
/** | |||
* UTF-8 | |||
*/ | |||
public static final String UTF_8 = "UTF-8"; | |||
/** | |||
* GBK | |||
*/ | |||
public static final String GBK = "GBK"; | |||
/** | |||
* ISO-8859-1 | |||
*/ | |||
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); | |||
/** | |||
* UTF-8 | |||
*/ | |||
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); | |||
/** | |||
* GBK | |||
*/ | |||
public static final Charset CHARSET_GBK = Charset.forName(GBK); | |||
/** | |||
* 转换为Charset对象 | |||
* | |||
* @param charset 字符集,为空则返回默认字符集 | |||
* @return Charset | |||
*/ | |||
public static Charset charset(String charset) { | |||
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); | |||
} | |||
/** | |||
* 转换字符串的字符集编码 | |||
* | |||
* @param source 字符串 | |||
* @param srcCharset 源字符集,默认ISO-8859-1 | |||
* @param destCharset 目标字符集,默认UTF-8 | |||
* @return 转换后的字符集 | |||
*/ | |||
public static String convert(String source, String srcCharset, String destCharset) { | |||
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); | |||
} | |||
/** | |||
* 转换字符串的字符集编码 | |||
* | |||
* @param source 字符串 | |||
* @param srcCharset 源字符集,默认ISO-8859-1 | |||
* @param destCharset 目标字符集,默认UTF-8 | |||
* @return 转换后的字符集 | |||
*/ | |||
public static String convert(String source, Charset srcCharset, Charset destCharset) { | |||
if (null == srcCharset) { | |||
srcCharset = StandardCharsets.ISO_8859_1; | |||
} | |||
if (null == destCharset) { | |||
srcCharset = StandardCharsets.UTF_8; | |||
} | |||
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) { | |||
return source; | |||
} | |||
return new String(source.getBytes(srcCharset), destCharset); | |||
} | |||
/** | |||
* @return 系统字符集编码 | |||
*/ | |||
public static String systemCharset() { | |||
return Charset.defaultCharset().name(); | |||
} | |||
} |
@@ -0,0 +1,253 @@ | |||
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.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
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; | |||
} | |||
} |
@@ -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, CharsetKit.CHARSET_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,136 @@ | |||
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; | |||
/** | |||
* 时间工具类 | |||
*/ | |||
public final class DateUtils extends org.apache.commons.lang3.time.DateUtils { | |||
public static String YYYY = "yyyy"; | |||
public static String YYYY_MM = "yyyy-MM"; | |||
public static String YYYY_MM_DD = "yyyy-MM-dd"; | |||
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; | |||
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; | |||
private static String[] parsePatterns = { | |||
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", | |||
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", | |||
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; | |||
/** | |||
* 获取当前时间 | |||
* | |||
* @return | |||
*/ | |||
public static Date now() { | |||
return new Date(); | |||
} | |||
/** | |||
* 获取当前日期, 默认格式为yyyy-MM-dd | |||
* | |||
* @return String | |||
*/ | |||
public static String getDate() { | |||
return dateTimeNow(YYYY_MM_DD); | |||
} | |||
public static final String getTime() { | |||
return dateTimeNow(YYYY_MM_DD_HH_MM_SS); | |||
} | |||
public static final String dateTimeNow() { | |||
return dateTimeNow(YYYYMMDDHHMMSS); | |||
} | |||
public static final String dateTimeNow(final String format) { | |||
return parseDateToStr(format, new Date()); | |||
} | |||
public static final String dateTime(final Date date) { | |||
return parseDateToStr(YYYY_MM_DD, date); | |||
} | |||
public static final String parseDateToStr(final String format, final Date date) { | |||
return new SimpleDateFormat(format).format(date); | |||
} | |||
public static final Date dateTime(final String format, final String ts) { | |||
try { | |||
return new SimpleDateFormat(format).parse(ts); | |||
} catch (ParseException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
/** | |||
* 日期路径 即年/月/日 如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 + "分钟"; | |||
} | |||
} |
@@ -0,0 +1,61 @@ | |||
package com.tuoheng.common.utils; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import java.util.concurrent.locks.Lock; | |||
/** | |||
* 生成无人机产品识别码 | |||
*/ | |||
public class DroneCodeUtils { | |||
public static final String[] X36_ARRAY = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z".split(","); | |||
/** | |||
* @param brand 品牌 eg:THJS | |||
* @param series 系列 eg:Y0 | |||
* @param type 型号 eg:A 一代 | |||
* @return | |||
*/ | |||
public String createDroneCode(String brand, String series, String type) throws InterruptedException { | |||
return brand + series + type + createCode(); | |||
} | |||
/** | |||
* 生成不重复的36进制字符串 | |||
* @return | |||
* @throws InterruptedException | |||
*/ | |||
public String createCode() throws InterruptedException { | |||
String createCode=""; | |||
synchronized (this) { | |||
Date date = new Date(); | |||
SimpleDateFormat dateFormat = new SimpleDateFormat("MMddHHmmssSS"); | |||
SimpleDateFormat dateFormaty = new SimpleDateFormat("yyyy"); | |||
String code = dateFormat.format(date); | |||
String nowYear = dateFormaty.format(date); | |||
long addSum = (long) ((Integer.parseInt(nowYear) - 2021) * 12 * Math.pow(10, 11)); | |||
Thread.sleep(100); | |||
String string36 = tenTo36(Long.parseLong(code) + addSum); | |||
createCode=nowYear + string36; | |||
} | |||
return createCode; | |||
} | |||
/** | |||
* 十进制转36精制 | |||
* @param num | |||
* @return | |||
*/ | |||
public static String tenTo36(long num) { | |||
StringBuffer sBuffer = new StringBuffer(); | |||
if (num == 0) { | |||
sBuffer.append("0"); | |||
} | |||
while (num > 0) { | |||
sBuffer.append(X36_ARRAY[Integer.parseInt(String.valueOf(num % 36))]); | |||
num = num / 36; | |||
} | |||
return sBuffer.reverse().toString(); | |||
} | |||
} |
@@ -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,110 @@ | |||
package com.tuoheng.common.utils; | |||
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; | |||
} | |||
} |
@@ -0,0 +1,186 @@ | |||
package com.tuoheng.common.utils; | |||
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(); | |||
} | |||
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,132 @@ | |||
package com.tuoheng.common.utils; | |||
import com.fasterxml.jackson.annotation.JsonInclude; | |||
import com.fasterxml.jackson.databind.DeserializationFeature; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import com.fasterxml.jackson.databind.ObjectMapper; | |||
import com.fasterxml.jackson.databind.SerializationFeature; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.util.StringUtils; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Map; | |||
public class JacksonUtil { | |||
private final static Logger LOGGER = LoggerFactory.getLogger(JacksonUtil.class); | |||
private final static ObjectMapper objectMapper = new ObjectMapper(); | |||
private final static SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |||
private JacksonUtil(){} | |||
static { | |||
//序列化的时候序列对象的所有属性 | |||
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); | |||
//反序列化的时候如果多了其他属性,不抛出异常 | |||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | |||
//如果是空对象的时候,不抛异常 | |||
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); | |||
//取消时间的转化格式,默认是时间戳,可以取消,同时需要设置要表现的时间格式 | |||
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); | |||
objectMapper.setDateFormat(dateformat); | |||
} | |||
/** | |||
* 转换为 JSON 字符串 | |||
* | |||
* @param obj | |||
* @return | |||
*/ | |||
public static <T> String obj2json(T obj) { | |||
if(obj != null){ | |||
try { | |||
return obj instanceof String ? (String)obj : objectMapper.writeValueAsString(obj); | |||
} catch (Exception e) { | |||
LOGGER.error("对象转字符串异常: {}", e); | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* 漂亮的转换为 JSON 字符串 | |||
* | |||
* @param obj | |||
* @return | |||
*/ | |||
public static <T> String obj2StringPretty(T obj) { | |||
if(obj != null){ | |||
try { | |||
return obj instanceof String ? (String)obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); | |||
} catch (Exception e) { | |||
LOGGER.error("对象转字符串异常: {}", e); | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* 转换为 JavaBean | |||
* | |||
* @param str | |||
* @param clazz | |||
* @return | |||
* @throws Exception | |||
*/ | |||
public static <T> T json2pojo(String str, Class<T> clazz) { | |||
if(StringUtils.hasLength(str) && clazz != null){ | |||
try { | |||
return clazz.equals(String.class)? (T)str : objectMapper.readValue(str,clazz); | |||
} catch (Exception e) { | |||
LOGGER.error("字符串转对象异常: {}", e); | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* 将 Map 转换为 JavaBean | |||
* | |||
* @param map | |||
* @param clazz | |||
* @return | |||
*/ | |||
public static <T> T map2pojo(Map map, Class<T> clazz) { | |||
return objectMapper.convertValue(map, clazz); | |||
} | |||
/** | |||
* 将 JSON 对象转换为 JavaBean | |||
* | |||
* @param obj | |||
* @param clazz | |||
* @return | |||
*/ | |||
public static <T> T obj2pojo(Object obj, Class<T> clazz) { | |||
return objectMapper.convertValue(obj, clazz); | |||
} | |||
/** | |||
* 将指定节点的 JSON 数据转换为 JavaBean | |||
* | |||
* @param str | |||
* @param treeNode | |||
* @param clazz | |||
* @return | |||
*/ | |||
public static <T> T json2pojoByTree(String str, String treeNode, Class<T> clazz) { | |||
if(StringUtils.hasLength(str) && StringUtils.hasLength(str) && clazz == null){ | |||
try { | |||
JsonNode jsonNode = objectMapper.readTree(str); | |||
JsonNode data = jsonNode.findPath(treeNode); | |||
return json2pojo(data.toString(), clazz); | |||
} catch (Exception e) { | |||
LOGGER.error("字符串按节点转对象异常: {}", e); | |||
} | |||
} | |||
return null; | |||
} | |||
} |
@@ -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;//CommonConstants.SUCCESS; | |||
/** | |||
* 失败 | |||
*/ | |||
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,168 @@ | |||
package com.tuoheng.common.utils; | |||
import lombok.extern.slf4j.Slf4j; | |||
import java.lang.reflect.Field; | |||
import java.util.*; | |||
/** | |||
* map工具类 | |||
* | |||
*/ | |||
@Slf4j | |||
public class MapUtils { | |||
/** | |||
* map的参数组装拼接 | |||
* | |||
* @param map | |||
* @return | |||
*/ | |||
public static String MapParamToStr(Map<String, Object> map) { | |||
if (map == null) return ""; | |||
// 定义初始化 | |||
StringBuilder sb = new StringBuilder(); | |||
int total = 1; | |||
int size = map.size(); | |||
for (Map.Entry<String, Object> entry : map.entrySet()) { | |||
String key = entry.getKey(); | |||
Object value = entry.getValue(); | |||
if (total >= 0 && total < size) { | |||
sb.append(key + "=" + value + "&"); | |||
} else if (total == size) { | |||
sb.append(key + "=" + value); | |||
} | |||
total++; | |||
} | |||
return sb.toString(); | |||
} | |||
/** | |||
* 利用反射将map集合封装成bean对象 | |||
* | |||
* @param map | |||
* @param clazz | |||
* @return | |||
*/ | |||
public static <T> T mapToBean(Map<String, Object> map, Class<?> clazz) throws Exception { | |||
Object obj = clazz.newInstance(); | |||
if (map != null && !map.isEmpty() && map.size() > 0) { | |||
for (Map.Entry<String, Object> entry : map.entrySet()) { | |||
String propertyName = entry.getKey(); // 属性名 | |||
Object value = entry.getValue(); // 属性值 | |||
String setMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); | |||
Field field = getClassField(clazz, propertyName); //获取和map的key匹配的属性名称 | |||
if (field == null) { | |||
continue; | |||
} | |||
Class<?> fieldTypeClass = field.getType(); | |||
value = convertValType(value, fieldTypeClass); | |||
try { | |||
clazz.getMethod(setMethodName, field.getType()).invoke(obj, value); | |||
} catch (NoSuchMethodException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} | |||
return (T) obj; | |||
} | |||
/** | |||
* 对象转map | |||
* | |||
* @param obj | |||
* @return | |||
*/ | |||
public static Map<String, Object> objToMap(Object obj) { | |||
LinkedHashMap<String, Object> map = new LinkedHashMap<>(); | |||
Field[] fields = obj.getClass().getDeclaredFields(); // 获取f对象对应类中的所有属性域 | |||
Field[] superFields = obj.getClass().getSuperclass().getDeclaredFields(); | |||
List<Field> fieldsList = Arrays.asList(fields); | |||
ArrayList<Field> fieldArrayList = new ArrayList<>(fieldsList); | |||
for (Field superField : superFields) { | |||
fieldArrayList.add(superField); | |||
} | |||
Collections.reverse(fieldArrayList); | |||
for (int i = 0; i < fieldArrayList.size(); i++) { | |||
String varName = fieldArrayList.get(i).getName(); | |||
varName = varName.toLowerCase(); // 将key置为小写,默认为对象的属性 | |||
try { | |||
boolean accessFlag = fieldArrayList.get(i).isAccessible(); // 获取原来的访问控制权限 | |||
fieldArrayList.get(i).setAccessible(true); // 修改访问控制权限 | |||
Object o = fieldArrayList.get(i).get(obj); // 获取在对象f中属性fields[i]对应的对象中的变量 | |||
if (o != null) { | |||
map.put(varName, o.toString()); | |||
} | |||
fieldArrayList.get(i).setAccessible(accessFlag); // 恢复访问控制权限 | |||
} catch (IllegalArgumentException ex) { | |||
ex.printStackTrace(); | |||
} catch (IllegalAccessException ex) { | |||
ex.printStackTrace(); | |||
} | |||
} | |||
return map; | |||
} | |||
/** | |||
* 根据给定对象类匹配对象中的特定字段 | |||
* | |||
* @param clazz | |||
* @param fieldName | |||
* @return | |||
*/ | |||
private static Field getClassField(Class<?> clazz, String fieldName) { | |||
if (Object.class.getName().equals(clazz.getName())) { | |||
return null; | |||
} | |||
Field[] declaredFields = clazz.getDeclaredFields(); | |||
for (Field field : declaredFields) { | |||
if (field.getName().equals(fieldName)) { | |||
return field; | |||
} | |||
} | |||
Class<?> superClass = clazz.getSuperclass(); //如果该类还有父类,将父类对象中的字段也取出 | |||
if (superClass != null) { //递归获取 | |||
return getClassField(superClass, fieldName); | |||
} | |||
return null; | |||
} | |||
/** | |||
* 将map的value值转为实体类中字段类型匹配的方法 | |||
* | |||
* @param value | |||
* @param fieldTypeClass | |||
* @return | |||
*/ | |||
private static Object convertValType(Object value, Class<?> fieldTypeClass) { | |||
Object retVal = null; | |||
if (Long.class.getName().equals(fieldTypeClass.getName()) | |||
|| long.class.getName().equals(fieldTypeClass.getName())) { | |||
retVal = Long.parseLong(value.toString()); | |||
} else if (Integer.class.getName().equals(fieldTypeClass.getName()) | |||
|| int.class.getName().equals(fieldTypeClass.getName())) { | |||
retVal = Integer.parseInt(value.toString()); | |||
} else if (Float.class.getName().equals(fieldTypeClass.getName()) | |||
|| float.class.getName().equals(fieldTypeClass.getName())) { | |||
retVal = Float.parseFloat(value.toString()); | |||
} else if (Double.class.getName().equals(fieldTypeClass.getName()) | |||
|| double.class.getName().equals(fieldTypeClass.getName())) { | |||
retVal = Double.parseDouble(value.toString()); | |||
} else { | |||
retVal = value; | |||
} | |||
return retVal; | |||
} | |||
} |
@@ -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((Collection<String>) 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,319 @@ | |||
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.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<>(); | |||
/** | |||
* 构造函数 | |||
*/ | |||
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,kml,mp3,wma,wav,avi,acc,waypoints"); | |||
} | |||
/** | |||
* 文件上传 | |||
* | |||
* @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); | |||
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); | |||
return result; | |||
} | |||
/** | |||
* 上传验证并初始化目录 | |||
* | |||
* @param request | |||
* @return | |||
*/ | |||
private String validateFields(HttpServletRequest request, String name) { | |||
String errorInfo = ""; | |||
// 获取内容类型 | |||
String contentType = request.getContentType(); | |||
int contentLength = request.getContentLength(); | |||
// 初始化上传路径,不存在则创建 | |||
try { | |||
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(); | |||
} | |||
} | |||
}catch (Exception e){ | |||
e.printStackTrace(); | |||
System.out.println(e.getMessage()); | |||
} | |||
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 = item.getString(); | |||
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(e.getMessage()); | |||
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; | |||
} | |||
} |