Compare commits
3 Commits
0616352d2a
...
08e4f05233
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08e4f05233 | ||
|
|
cdf19f2314 | ||
| 5990a4f052 |
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
20
.idea/compiler.xml
generated
Normal file
20
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="BUILD_PROCESS_HEAP_SIZE" value="2048" />
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="rensijin-cchs-server" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="rensijin-cchs-server" options="-parameters" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/encodings.xml
generated
Normal file
6
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
30
.idea/jarRepositories.xml
generated
Normal file
30
.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="http://nexus.lg.china-yongfeng.com/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="g-siba0859-EasyJava-bobo" />
|
||||
<option name="name" value="bobo" />
|
||||
<option name="url" value="https://g-siba0859-maven.pkg.coding.net/repository/EasyJava/bobo/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/misc.xml
generated
Normal file
12
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
10
.idea/sonarlint.xml
generated
Normal file
10
.idea/sonarlint.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SonarLintProjectSettings">
|
||||
<option name="moduleMapping">
|
||||
<map>
|
||||
<entry key="rensijin-cchs" value="SpringBoot" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
136
pom.xml
Normal file
136
pom.xml
Normal file
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId> org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.rensijin.cchs</groupId>
|
||||
<artifactId>rensijin-cchs-server</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>rensijin-cchs</name>
|
||||
<description>任思瑾的客户投诉处理系统</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>2.9.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>2.9.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
|
||||
<!--图片验证码-->
|
||||
<dependency>
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
<artifactId>easy-captcha</artifactId>
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.50</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.7.16</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.3.5.RELEASE</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.12.4</version>
|
||||
<configuration>
|
||||
<!--测试包下的代码出错不影响项目的编译-->
|
||||
<testFailureIgnore>true</testFailureIgnore>
|
||||
<!--跳过测试包代码-->
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<finalName>EasyJavaTemplate</finalName>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
19
src/main/java/cn/rensijin/cchs/App.java
Normal file
19
src/main/java/cn/rensijin/cchs/App.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package cn.rensijin.cchs;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @desc:系统启动类
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class App {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(App.class, args);
|
||||
System.out.println("**************************************");
|
||||
System.out.println("**************系统启动成功**************");
|
||||
System.out.println("**************************************");
|
||||
}
|
||||
|
||||
}
|
||||
13
src/main/java/cn/rensijin/cchs/annotation/IgnoreAuth.java
Normal file
13
src/main/java/cn/rensijin/cchs/annotation/IgnoreAuth.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package cn.rensijin.cchs.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @Desc: 忽略Token验证
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface IgnoreAuth {
|
||||
|
||||
}
|
||||
25
src/main/java/cn/rensijin/cchs/annotation/RateLimit.java
Normal file
25
src/main/java/cn/rensijin/cchs/annotation/RateLimit.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package cn.rensijin.cchs.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 用于防刷限流的注解
|
||||
* 默认是5秒内只能调用一次
|
||||
*/
|
||||
@Target({ ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RateLimit {
|
||||
|
||||
/** 限流的key */
|
||||
String key() default "limit:";
|
||||
|
||||
/** 周期,单位是秒 */
|
||||
int cycle() default 5;
|
||||
|
||||
/** 请求次数 */
|
||||
int count() default 1;
|
||||
|
||||
/** 默认提示信息 */
|
||||
String msg() default "请勿重复点击";
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package cn.rensijin.cchs.config.cors;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 跨域配置
|
||||
*/
|
||||
@Configuration
|
||||
public class CorsFilterConfig {
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
//1.添加CORS配置信息
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
//1) 允许的域(*表示允许所有)
|
||||
config.addAllowedOriginPattern("*");
|
||||
//2) 是否发送Cookie信息
|
||||
config.setAllowCredentials(true);
|
||||
//3) 允许的请求方式
|
||||
config.addAllowedMethod("OPTIONS");
|
||||
config.addAllowedMethod("HEAD");
|
||||
config.addAllowedMethod("GET");
|
||||
config.addAllowedMethod("PUT");
|
||||
config.addAllowedMethod("POST");
|
||||
config.addAllowedMethod("DELETE");
|
||||
config.addAllowedMethod("PATCH");
|
||||
// 4)允许的头信息
|
||||
config.addAllowedHeader("*");
|
||||
//2.添加映射路径,我们拦截一切请求
|
||||
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
|
||||
configSource.registerCorsConfiguration("/**", config);
|
||||
//3.返回新的CorsFilter.
|
||||
return new CorsFilter(configSource);
|
||||
}
|
||||
}
|
||||
78
src/main/java/cn/rensijin/cchs/config/date/DateConfig.java
Normal file
78
src/main/java/cn/rensijin/cchs/config/date/DateConfig.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package cn.rensijin.cchs.config.date;
|
||||
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* @description 全局时间配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class DateConfig {
|
||||
|
||||
private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
||||
private static final String DATE_PATTERN = "yyyy-MM-dd";
|
||||
|
||||
/**
|
||||
* string转localdate
|
||||
*/
|
||||
@Bean
|
||||
public Converter<String, LocalDate> localDateConverter() {
|
||||
return new Converter<String, LocalDate>() {
|
||||
@Override
|
||||
public LocalDate convert(String source) {
|
||||
if (source.trim().length() == 0)
|
||||
return null;
|
||||
try {
|
||||
return LocalDate.parse(source);
|
||||
} catch (Exception e) {
|
||||
return LocalDate.parse(source, DateTimeFormatter.ofPattern(DATE_PATTERN));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* string转localdatetime
|
||||
*/
|
||||
@Bean
|
||||
public Converter<String, LocalDateTime> localDateTimeConverter() {
|
||||
return new Converter<String, LocalDateTime>() {
|
||||
@Override
|
||||
public LocalDateTime convert(String source) {
|
||||
if (source.trim().length() == 0)
|
||||
return null;
|
||||
// 先尝试ISO格式: 2019-07-15T16:00:00
|
||||
try {
|
||||
return LocalDateTime.parse(source);
|
||||
} catch (Exception e) {
|
||||
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DATE_TIME_PATTERN));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一配置
|
||||
*/
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
|
||||
JavaTimeModule module = new JavaTimeModule();
|
||||
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
|
||||
return builder -> {
|
||||
builder.simpleDateFormat(DATE_TIME_PATTERN);
|
||||
builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_PATTERN)));
|
||||
builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)));
|
||||
builder.modules(module);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.rensijin.cchs.config.date;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
|
||||
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
|
||||
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
|
||||
*/
|
||||
public class JacksonObjectMapper extends ObjectMapper {
|
||||
|
||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String DATE_TIME_FORMAT_NO_SECOND = "yyyy-MM-dd HH:mm";
|
||||
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||
|
||||
public JacksonObjectMapper() {
|
||||
super();
|
||||
//收到未知属性时不报异常
|
||||
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
||||
//反序列化时,属性不存在的兼容处理
|
||||
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
|
||||
SimpleModule simpleModule = new SimpleModule()
|
||||
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
|
||||
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
|
||||
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
|
||||
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
|
||||
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
|
||||
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
|
||||
|
||||
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
|
||||
this.registerModule(simpleModule);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.rensijin.cchs.config.mp;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @description: MyBatiesPlus配置类
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan("cn.rensijin.cchs.mapper")
|
||||
public class MyBatiesPlusConfiguration {
|
||||
|
||||
/*
|
||||
* 分页插件
|
||||
*/
|
||||
@Bean
|
||||
public PaginationInterceptor paginationInterceptor() {
|
||||
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
|
||||
return paginationInterceptor;
|
||||
}
|
||||
}
|
||||
39
src/main/java/cn/rensijin/cchs/config/redis/RedisConfig.java
Normal file
39
src/main/java/cn/rensijin/cchs/config/redis/RedisConfig.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package cn.rensijin.cchs.config.redis;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* <p>Redis配置类</p>
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
|
||||
// 设置序列化
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(om);
|
||||
// 配置redisTemplate
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
|
||||
RedisSerializer<?> stringSerializer = new StringRedisSerializer();
|
||||
redisTemplate.setKeySerializer(stringSerializer);// key序列化
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
|
||||
redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
|
||||
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
||||
79
src/main/java/cn/rensijin/cchs/config/swagger/Swagger2.java
Normal file
79
src/main/java/cn/rensijin/cchs/config/swagger/Swagger2.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package cn.rensijin.cchs.config.swagger;
|
||||
|
||||
import io.swagger.models.auth.In;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.*;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Swagger接口文档配置类
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
public class Swagger2 {
|
||||
|
||||
//默认路径:http://127.0.0.1:port/swagger-ui.html
|
||||
|
||||
@Bean
|
||||
public Docket createRestApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
// 是否启用Swagger
|
||||
.enable(true)
|
||||
// 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
|
||||
.apiInfo(apiInfo())
|
||||
// 设置哪些接口暴露给Swagger展示
|
||||
.select()
|
||||
//.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))//扫描所有有注解的api
|
||||
//.apis(RequestHandlerSelectors.any())//扫描所有
|
||||
.apis(RequestHandlerSelectors.basePackage("cn.rensijin.cchs.controller"))//扫描包
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
/* 设置安全模式,swagger可以设置访问token */
|
||||
.securitySchemes(securitySchemes());
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全模式,这里指定token通过头请求头传递
|
||||
*/
|
||||
private List<SecurityScheme> securitySchemes()
|
||||
{
|
||||
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
|
||||
apiKeyList.add(new ApiKey("token", "token", In.HEADER.toValue()));
|
||||
return apiKeyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的安全上引用
|
||||
*/
|
||||
private List<SecurityReference> defaultAuth()
|
||||
{
|
||||
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
||||
authorizationScopes[0] = authorizationScope;
|
||||
List<SecurityReference> securityReferences = new ArrayList<>();
|
||||
securityReferences.add(new SecurityReference("token", authorizationScopes));
|
||||
return securityReferences;
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
// 用ApiInfoBuilder进行定制
|
||||
return new ApiInfoBuilder()
|
||||
// 设置标题
|
||||
.title("标题:接口文档")
|
||||
// 描述
|
||||
.description("描述:用户前后端联调接口文档")
|
||||
// 作者信息
|
||||
.contact(new Contact("任思瑾", null, ""))
|
||||
// 版本
|
||||
.version("版本号:1.0.0")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
58
src/main/java/cn/rensijin/cchs/config/web/WebConfig.java
Normal file
58
src/main/java/cn/rensijin/cchs/config/web/WebConfig.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package cn.rensijin.cchs.config.web;
|
||||
|
||||
import cn.rensijin.cchs.config.date.JacksonObjectMapper;
|
||||
import cn.rensijin.cchs.interceptor.LoginInterceptor;
|
||||
import cn.rensijin.cchs.interceptor.RateLimitInterceptor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* web配置
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfig extends WebMvcConfigurationSupport {
|
||||
|
||||
@Resource
|
||||
private LoginInterceptor loginInterceptor;
|
||||
|
||||
@Resource
|
||||
private RateLimitInterceptor rateLimitInterceptor;
|
||||
|
||||
//扩展SpringMVC框架的消息转化器,例如实现返回日期时间的格式化
|
||||
@Override
|
||||
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
|
||||
//将java对象序列化为json数据,为消息转换器设置序列转换器
|
||||
converter.setObjectMapper(new JacksonObjectMapper());
|
||||
//将自己的消息转换器加入容器中
|
||||
converters.add(0, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(rateLimitInterceptor);
|
||||
registry.addInterceptor(loginInterceptor)
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns("/", "/static/**", "/file/download/**")
|
||||
.excludePathPatterns("/login/**", "/user/info", "/test/**","/user/register");
|
||||
}
|
||||
|
||||
/**
|
||||
* springboot 2.0配置WebMvcConfigurationSupport之后,会导致默认配置被覆盖,要访问静态资源需要重写addResourceHandlers方法
|
||||
*/
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/**")
|
||||
.addResourceLocations("classpath:/resources/")
|
||||
.addResourceLocations("classpath:/static/");
|
||||
super.addResourceHandlers(registry);
|
||||
}
|
||||
|
||||
}
|
||||
44
src/main/java/cn/rensijin/cchs/constants/ErrorCode.java
Normal file
44
src/main/java/cn/rensijin/cchs/constants/ErrorCode.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package cn.rensijin.cchs.constants;
|
||||
|
||||
/**
|
||||
* 系统错误码
|
||||
*/
|
||||
public enum ErrorCode {
|
||||
|
||||
SYSTEM_SUCCESS("0000", "操作成功!"),
|
||||
|
||||
ERROR_CODE_1001("1001", "操作失败,请稍候再试!"),
|
||||
ERROR_CODE_1002("1002", "认证状态失效,请重新登录!"),
|
||||
ERROR_CODE_1003("1003", "登录账号不能为空!"),
|
||||
ERROR_CODE_1004("1004", "登录密码不能为空!"),
|
||||
ERROR_CODE_1005("1005", "登录账号不存在!"),
|
||||
ERROR_CODE_1006("1006", "登录账号存在多个!"),
|
||||
ERROR_CODE_1007("1007", "登录密码错误!"),
|
||||
ERROR_CODE_1008("1008", "Token错误或失效!"),
|
||||
ERROR_CODE_1009("1009", "UUID不能为空!"),
|
||||
ERROR_CODE_1010("1010", "图片验证码不能为空!"),
|
||||
ERROR_CODE_1011("1011", "图片验证码已过期,请点击图片刷新!"),
|
||||
ERROR_CODE_1012("1012", "图片验证码错误,请重新输入!"),
|
||||
|
||||
|
||||
SYSTEM_ERROR("9999", "系统开小差了,请稍后再试!");
|
||||
|
||||
//错误码
|
||||
private String code;
|
||||
|
||||
//错误信息
|
||||
private String message;
|
||||
|
||||
ErrorCode(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package cn.rensijin.cchs.constants;
|
||||
|
||||
/**
|
||||
* @description 系统常量类
|
||||
*/
|
||||
public class SystemConstants {
|
||||
|
||||
/**
|
||||
* APP端保存注册短信验证码key
|
||||
*/
|
||||
public static final String TOKEN_PHONE_KEY_REGISTER = "app_sms_code_register:";
|
||||
|
||||
/**
|
||||
* 令牌在Redis中保存时长
|
||||
*/
|
||||
public static final int TOKEN_REDIS_ALIVE_TIME = 2;
|
||||
|
||||
/**
|
||||
* APP端保存短信验证码key
|
||||
*/
|
||||
public static final String TOKEN_PHONE_KEY = "app_sms_code:";
|
||||
|
||||
/**
|
||||
* 登录时图片验证码存Redis的超时时间(单位:分钟)
|
||||
*/
|
||||
public final static int LOGIN_CAPTCHA_EXPIRATION = 2;
|
||||
|
||||
/**
|
||||
* 登录时图片验证码存Redis的key前缀
|
||||
*/
|
||||
public static final String CAPTCHA_CODE_KEY = "captcha_code:";
|
||||
|
||||
/**
|
||||
* 文件存储路径(项目跟路径下面的files文件夹)
|
||||
*/
|
||||
public static final String FILES_DIR = "/files/";
|
||||
|
||||
/**
|
||||
* APP用户登录 redis key
|
||||
*/
|
||||
public static final String LOGIN_TOKEN_KEY_APP = "login_app_tokens:";
|
||||
|
||||
//登录成功之后token超时时间(单位:分钟)
|
||||
public final static int LOGIN_TIME_OUT = 60;
|
||||
|
||||
//新用户注册的默认登录密码
|
||||
public final static String DEFAULT_USER_LOGIN_PWD = "123456";
|
||||
|
||||
//新用户注册的默认头像
|
||||
public final static String DEFAULT_USER_AVATAR = "https://easyjava.oss-cn-chengdu.aliyuncs.com/common/0161a7079e574da287dc182bdf756abc.jpg";
|
||||
}
|
||||
134
src/main/java/cn/rensijin/cchs/controller/LoginController.java
Normal file
134
src/main/java/cn/rensijin/cchs/controller/LoginController.java
Normal file
@@ -0,0 +1,134 @@
|
||||
package cn.rensijin.cchs.controller;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.rensijin.cchs.annotation.IgnoreAuth;
|
||||
import cn.rensijin.cchs.constants.ErrorCode;
|
||||
import cn.rensijin.cchs.constants.SystemConstants;
|
||||
import cn.rensijin.cchs.domain.system.SysUser;
|
||||
import cn.rensijin.cchs.exception.MyException;
|
||||
import cn.rensijin.cchs.mapper.system.SysUserMapper;
|
||||
import cn.rensijin.cchs.result.JSONResult;
|
||||
import cn.rensijin.cchs.util.MyTools;
|
||||
import cn.rensijin.cchs.vo.UserTokenVo;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.wf.captcha.SpecCaptcha;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @desc 系统登录API
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/login")
|
||||
public class LoginController {
|
||||
|
||||
@Resource
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 登录页面获取图片验证码
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@GetMapping("/getLoginImageCode/{uuid}")
|
||||
public JSONResult getLoginImageCode(@PathVariable("uuid") String uuid) {
|
||||
// 验证码内容存Redis的key值
|
||||
String verifyKey = SystemConstants.CAPTCHA_CODE_KEY + uuid;
|
||||
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 4);
|
||||
//设置验证码的类型(可不设置,使用默认值)
|
||||
specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
||||
String code = specCaptcha.text().toLowerCase();
|
||||
|
||||
//图片验证码存Redis
|
||||
redisTemplate.opsForValue().set(verifyKey, code, SystemConstants.LOGIN_CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||
|
||||
return JSONResult.success(specCaptcha.toBase64());
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统登录接口
|
||||
*
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@PostMapping("/login")
|
||||
public JSONResult login(@RequestBody SysUser user) {
|
||||
//入参校验
|
||||
if (!MyTools.hasLength(user.getUsername())) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1003);
|
||||
}
|
||||
if (!MyTools.hasLength(user.getPassword())) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1004);
|
||||
}
|
||||
if (!MyTools.hasLength(user.getUuid())) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1009);
|
||||
}
|
||||
if (!MyTools.hasLength(user.getImageCode())) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1010);
|
||||
}
|
||||
|
||||
//到Redis获取验证码
|
||||
String verifyKey = SystemConstants.CAPTCHA_CODE_KEY + user.getUuid();
|
||||
String imagesCodeFromRedis = (String) redisTemplate.opsForValue().get(verifyKey);
|
||||
if (!MyTools.hasLength(imagesCodeFromRedis)) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1011);
|
||||
}
|
||||
//开始对比图片验证码
|
||||
if (!imagesCodeFromRedis.equals(user.getImageCode())) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1012);
|
||||
}
|
||||
|
||||
//查看账号是否存在
|
||||
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_name", user.getUsername());
|
||||
List<SysUser> sysUserList = sysUserMapper.selectList(queryWrapper);
|
||||
if (CollectionUtils.isEmpty(sysUserList)) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1005);
|
||||
}
|
||||
if (sysUserList.size() > 1) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1006);
|
||||
}
|
||||
|
||||
//开始验证密码是否正确
|
||||
SysUser sysUser = sysUserList.get(0);
|
||||
if (!sysUser.getPassword().equalsIgnoreCase(SecureUtil.md5(user.getPassword()))) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1007);
|
||||
}
|
||||
|
||||
//用户信息存Redis
|
||||
String token = MyTools.getLoginToken();
|
||||
//用户信息存储到Redis
|
||||
redisTemplate.opsForValue().set(SystemConstants.LOGIN_TOKEN_KEY_APP + token, JSONObject.toJSONString(sysUser), SystemConstants.LOGIN_TIME_OUT, TimeUnit.MINUTES);
|
||||
|
||||
//返回token及相关用户信息给前端
|
||||
UserTokenVo vo = new UserTokenVo();
|
||||
vo.setToken(token);
|
||||
vo.setAvatar(sysUser.getAvatar());
|
||||
vo.setUserName(sysUser.getUsername());
|
||||
vo.setRealName(sysUser.getRealName());
|
||||
return JSONResult.success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出系统
|
||||
*
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/logout")
|
||||
public JSONResult getUSerInfo(@RequestParam("token") String token) {
|
||||
redisTemplate.delete(token);
|
||||
return JSONResult.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package cn.rensijin.cchs.controller;
|
||||
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.rensijin.cchs.annotation.IgnoreAuth;
|
||||
import cn.rensijin.cchs.domain.system.SysUser;
|
||||
import cn.rensijin.cchs.exception.MyException;
|
||||
import cn.rensijin.cchs.result.JSONResult;
|
||||
import cn.rensijin.cchs.service.system.SysUserService;
|
||||
import cn.rensijin.cchs.util.MyTools;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @desc 用户注册
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class RegisterController {
|
||||
|
||||
@Autowired
|
||||
private SysUserService sysUserService;
|
||||
|
||||
@IgnoreAuth
|
||||
@PostMapping("/register")
|
||||
public JSONResult login(@RequestBody SysUser user) {
|
||||
if (!MyTools.hasLength(user.getUsername())) {
|
||||
throw new MyException("账号不能为空!");
|
||||
}
|
||||
System.out.println(user);
|
||||
//查询用户名是否被注册
|
||||
QueryWrapper<SysUser> queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq("user_name", user.getUsername());
|
||||
SysUser one = sysUserService.getOne(queryWrapper);
|
||||
if (one != null) {
|
||||
throw new MyException("账号已被注册,请更换!");
|
||||
}
|
||||
|
||||
SysUser sysUser = new SysUser();
|
||||
BeanUtils.copyProperties(user, sysUser);
|
||||
|
||||
sysUser.setPassword(SecureUtil.md5(user.getPassword()));
|
||||
sysUser.setAvatar("https://20241211oss.oss-cn-beijing.aliyuncs.com/202412/NewsApp/image/3_20241211143629.png");
|
||||
//数据入库
|
||||
System.out.println(sysUser);
|
||||
sysUserService.save(sysUser);
|
||||
return JSONResult.successMessage(true, "注册成功,快去登录吧!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.rensijin.cchs.controller;
|
||||
|
||||
import cn.rensijin.cchs.annotation.RateLimit;
|
||||
import cn.rensijin.cchs.result.JSONResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>测试类</p>
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
public class TestController {
|
||||
|
||||
//cycle秒内只能访问count次
|
||||
@RateLimit(key= "testLimit:", count = 2, cycle = 2, msg = "同志,不要请求这么快,好吗")
|
||||
@GetMapping("/test001")
|
||||
public JSONResult test001() {
|
||||
System.out.println("成功发送一条短信");
|
||||
return JSONResult.success("成功发送一条短信");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package cn.rensijin.cchs.controller.app;
|
||||
|
||||
import cn.rensijin.cchs.domain.app.AppSuggestion;
|
||||
import cn.rensijin.cchs.result.PageList;
|
||||
import cn.rensijin.cchs.service.app.AppSuggestionService;
|
||||
import cn.rensijin.cchs.query.app.AppSuggestionQuery;
|
||||
import cn.rensijin.cchs.controller.base.BaseController;
|
||||
import cn.rensijin.cchs.util.DateUtils;
|
||||
import cn.rensijin.cchs.result.JSONResult;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 意见反馈表 API接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/appSuggestion")
|
||||
@Api(value = "/appSuggestion", tags = {"意见反馈表 API接口"})
|
||||
public class AppSuggestionController extends BaseController{
|
||||
|
||||
@Autowired
|
||||
public AppSuggestionService appSuggestionService;
|
||||
|
||||
/**
|
||||
* 新增数据到【意见反馈表】
|
||||
*/
|
||||
@PostMapping(value="/save")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "AppSuggestion", name = "appSuggestion", value = "")
|
||||
})
|
||||
@ApiOperation(value = "新增数据到【意见反馈表】", notes = "新增数据到【意见反馈表】", httpMethod = "POST")
|
||||
public JSONResult save(@RequestBody AppSuggestion appSuggestion){
|
||||
appSuggestion.setCreateTime(DateUtils.getCurrentLocalDateTime());
|
||||
// 获取当前用户真实姓名,如果获取失败则使用默认值
|
||||
String currentUserName = getCurrentUserRealName();
|
||||
if (currentUserName != null && !currentUserName.trim().isEmpty()) {
|
||||
appSuggestion.setCreateUserName(currentUserName);
|
||||
} else {
|
||||
appSuggestion.setCreateUserName("匿名用户"); // 或者根据业务需求设置其他默认值
|
||||
}
|
||||
appSuggestion.setAppUserId(getCurrentUserId());
|
||||
appSuggestion.setStatus("有效"); // 默认为有效状态
|
||||
appSuggestionService.save(appSuggestion);
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改【意见反馈表】表数据
|
||||
*/
|
||||
@PostMapping(value="/update")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "AppSuggestion", name = "appSuggestion", value = "")
|
||||
})
|
||||
@ApiOperation(value = "修改【意见反馈表】表数据", notes = "修改【意见反馈表】表数据", httpMethod = "POST")
|
||||
public JSONResult update(@RequestBody AppSuggestion appSuggestion){
|
||||
appSuggestion.setUpdateUserName(getCurrentUserRealName());
|
||||
appSuggestionService.updateById(appSuggestion);
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除【意见反馈表】数据
|
||||
*/
|
||||
@PostMapping(value="/batchDelete")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "AppSuggestionQuery", name = "query", value = "")
|
||||
})
|
||||
@ApiOperation(value = "批量删除【意见反馈表】数据", notes = "批量删除【意见反馈表】数据", httpMethod = "POST")
|
||||
public JSONResult batchDelete(@RequestBody AppSuggestionQuery query){
|
||||
//批量删除数据库数据
|
||||
appSuggestionService.removeByIds(Arrays.asList(query.getIds()));
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个删除【意见反馈表】数据
|
||||
*/
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "path", dataType = "long", name = "id", value = "")
|
||||
})
|
||||
@ApiOperation(value = "单个删除【意见反馈表】数据", notes = "单个删除【意见反馈表】数据", httpMethod = "DELETE")
|
||||
@DeleteMapping("/singleDelete/{id}")
|
||||
public JSONResult batchDelete(@PathVariable("id") Long id){
|
||||
//单个删除数据库数据
|
||||
appSuggestionService.removeById(id);
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询【意见反馈表】详情数据
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "path", dataType = "long", name = "id", value = "")
|
||||
})
|
||||
@ApiOperation(value = "根据ID查询【意见反馈表】详情数据", notes = "根据ID查询【意见反馈表】详情数据", httpMethod = "GET")
|
||||
public JSONResult get(@PathVariable("id")Long id){
|
||||
return JSONResult.success(appSuggestionService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询【意见反馈表】所有数据(不分页)
|
||||
*/
|
||||
@GetMapping(value = "/list")
|
||||
@ApiOperation(value = "查询【意见反馈表】所有数据(不分页)", notes = "查询【意见反馈表】所有数据(不分页)", httpMethod = "GET")
|
||||
public JSONResult list(){
|
||||
QueryWrapper<AppSuggestion> queryWrapper = new QueryWrapper();
|
||||
queryWrapper.orderByDesc("id");
|
||||
List<AppSuggestion> list = appSuggestionService.list(queryWrapper);
|
||||
return JSONResult.success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询【意见反馈表】数据(分页)
|
||||
* @param query 查询对象
|
||||
* @return PageList 分页对象
|
||||
*/
|
||||
@PostMapping(value = "/pagelist")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "AppSuggestionQuery", name = "query", value = "查询对象")
|
||||
})
|
||||
@ApiOperation(value = "查询【意见反馈表】数据(分页)", notes = "查询【意见反馈表】数据(分页)", httpMethod = "POST")
|
||||
public JSONResult pagelist(@RequestBody AppSuggestionQuery query){
|
||||
Page<AppSuggestion> page = appSuggestionService.selectMySqlPage(query);
|
||||
return JSONResult.success(new PageList<>(page.getTotal(), page.getRecords()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cn.rensijin.cchs.controller.base;
|
||||
|
||||
import cn.rensijin.cchs.constants.ErrorCode;
|
||||
import cn.rensijin.cchs.constants.SystemConstants;
|
||||
import cn.rensijin.cchs.domain.system.SysUser;
|
||||
import cn.rensijin.cchs.exception.MyException;
|
||||
import cn.rensijin.cchs.util.MyTools;
|
||||
import cn.rensijin.cchs.util.RedisCache;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @des: Controller的基础类
|
||||
*/
|
||||
public class BaseController {
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取登录人的信息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SysUser getCurrentUser() {
|
||||
//获取 HttpServletRequest 对象
|
||||
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
|
||||
//从请求头中获取 token 值
|
||||
String token = request.getHeader("token");
|
||||
if (!MyTools.hasLength(token)) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1002.getMessage());
|
||||
}
|
||||
String userInfoString = redisCache.getCacheObject(SystemConstants.LOGIN_TOKEN_KEY_APP + token);
|
||||
if (!MyTools.hasLength(userInfoString)) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1002.getMessage());
|
||||
}
|
||||
SysUser sysUser = JSONObject.parseObject(userInfoString, SysUser.class);
|
||||
return sysUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录人的用户ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Long getCurrentUserId() {
|
||||
return getCurrentUser().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录人的真实姓名
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getCurrentUserRealName() {
|
||||
return getCurrentUser().getRealName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package cn.rensijin.cchs.controller.system;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.rensijin.cchs.constants.SystemConstants;
|
||||
import cn.rensijin.cchs.controller.base.BaseController;
|
||||
import cn.rensijin.cchs.domain.system.SysUser;
|
||||
import cn.rensijin.cchs.query.system.SysUserQuery;
|
||||
import cn.rensijin.cchs.result.JSONResult;
|
||||
import cn.rensijin.cchs.result.PageList;
|
||||
import cn.rensijin.cchs.service.system.SysUserService;
|
||||
import cn.rensijin.cchs.util.DateUtils;
|
||||
import cn.rensijin.cchs.util.MyTools;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @desc 用户信息表 API接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
@Api(value = "/user", tags = {"用户信息表 API接口"})
|
||||
public class SysUserController extends BaseController{
|
||||
|
||||
@Resource
|
||||
public SysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 新增数据到【用户信息表】
|
||||
*/
|
||||
@PostMapping(value="/save")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "SysUser", name = "sysUser", value = "")
|
||||
})
|
||||
@ApiOperation(value = "新增数据到【用户信息表】", notes = "新增数据到【用户信息表】", httpMethod = "POST")
|
||||
public JSONResult save(@RequestBody SysUser sysUser){
|
||||
sysUser.setCreateTime(DateUtils.getCurrentLocalDateTime());
|
||||
sysUser.setCreateUserId(getCurrentUserId());
|
||||
sysUser.setPassword(SecureUtil.md5(sysUser.getPassword()));//密码加密
|
||||
if(!MyTools.hasLength(sysUser.getAvatar())){
|
||||
sysUser.setAvatar(SystemConstants.DEFAULT_USER_AVATAR);//默认头像
|
||||
}
|
||||
sysUserService.save(sysUser);
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改【用户信息表】表数据
|
||||
*/
|
||||
@PostMapping(value="/update")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "SysUser", name = "sysUser", value = "")
|
||||
})
|
||||
@ApiOperation(value = "修改【用户信息表】表数据", notes = "修改【用户信息表】表数据", httpMethod = "POST")
|
||||
public JSONResult update(@RequestBody SysUser sysUser){
|
||||
sysUser.setUpdateTime(DateUtils.getCurrentLocalDateTime());
|
||||
sysUser.setUpdateUserId(getCurrentUserId());
|
||||
sysUserService.updateById(sysUser);
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除【用户信息表】数据
|
||||
*/
|
||||
@PostMapping(value="/batchDelete")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "SysUserQuery", name = "query", value = "")
|
||||
})
|
||||
@ApiOperation(value = "批量删除【用户信息表】数据", notes = "批量删除【用户信息表】数据", httpMethod = "POST")
|
||||
public JSONResult batchDelete(@RequestBody SysUserQuery query){
|
||||
//批量删除数据库数据
|
||||
sysUserService.removeByIds(Arrays.asList(query.getIds()));
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个删除【用户信息表】数据
|
||||
*/
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "path", dataType = "long", name = "id", value = "")
|
||||
})
|
||||
@ApiOperation(value = "单个删除【用户信息表】数据", notes = "单个删除【用户信息表】数据", httpMethod = "DELETE")
|
||||
@DeleteMapping("/singleDelete/{id}")
|
||||
public JSONResult batchDelete(@PathVariable("id") Long id){
|
||||
//单个删除数据库数据
|
||||
sysUserService.removeById(id);
|
||||
return JSONResult.success(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询【用户信息表】详情数据
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "path", dataType = "long", name = "id", value = "")
|
||||
})
|
||||
@ApiOperation(value = "根据ID查询【用户信息表】详情数据", notes = "根据ID查询【用户信息表】详情数据", httpMethod = "GET")
|
||||
public JSONResult get(@PathVariable("id")Long id){
|
||||
return JSONResult.success(sysUserService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询【用户信息表】所有数据(不分页)
|
||||
*/
|
||||
@GetMapping(value = "/list")
|
||||
@ApiOperation(value = "查询【用户信息表】所有数据(不分页)", notes = "查询【用户信息表】所有数据(不分页)", httpMethod = "GET")
|
||||
public JSONResult list(){
|
||||
List<SysUser> list = sysUserService.list(null);
|
||||
return JSONResult.success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询【用户信息表】数据(分页)
|
||||
* @param query 查询对象
|
||||
* @return PageList 分页对象
|
||||
*/
|
||||
@PostMapping(value = "/pagelist")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(paramType = "body", dataType = "SysUserQuery", name = "query", value = "查询对象")
|
||||
})
|
||||
@ApiOperation(value = "查询【用户信息表】数据(分页)", notes = "查询【用户信息表】数据(分页)", httpMethod = "POST")
|
||||
public JSONResult pagelist(@RequestBody SysUserQuery query){
|
||||
IPage<SysUser> page = sysUserService.selectMyPage(query);
|
||||
return JSONResult.success(new PageList<>(page.getTotal(), page.getRecords()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户个人信息
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
public JSONResult getUSerInfo(@RequestParam("token") String token){
|
||||
return sysUserService.getUSerInfo(token);
|
||||
}
|
||||
}
|
||||
59
src/main/java/cn/rensijin/cchs/domain/app/AppSuggestion.java
Normal file
59
src/main/java/cn/rensijin/cchs/domain/app/AppSuggestion.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package cn.rensijin.cchs.domain.app;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import java.time.LocalDateTime;
|
||||
import java.io.Serializable;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import cn.rensijin.cchs.domain.base.BaseDomain;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 意见反馈表
|
||||
* </p>
|
||||
*
|
||||
* @date 2025-02-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@ApiModel(value="app_suggestion 表对应的实体对象", description="意见反馈表")
|
||||
public class AppSuggestion extends BaseDomain implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "主键ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "提意见时间")
|
||||
@TableField(value = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty(value = "提意见人ID")
|
||||
@TableField(value = "user_id")
|
||||
private Long appUserId;
|
||||
|
||||
@ApiModelProperty(value = "意见内容")
|
||||
@TableField(value = "suggestion_countent")
|
||||
private String suggestionCountent;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "投诉事由")
|
||||
@TableField(value = "complaint")
|
||||
private String complaint;
|
||||
|
||||
@ApiModelProperty(value = "解决诉求")
|
||||
@TableField(value = "demands")
|
||||
private String demands;
|
||||
|
||||
@ApiModelProperty(value = "投诉状态")
|
||||
@TableField(value = "status")
|
||||
private String status;
|
||||
|
||||
}
|
||||
22
src/main/java/cn/rensijin/cchs/domain/base/BaseDomain.java
Normal file
22
src/main/java/cn/rensijin/cchs/domain/base/BaseDomain.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package cn.rensijin.cchs.domain.base;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @desc 基础Domain类
|
||||
*/
|
||||
@Data
|
||||
public class BaseDomain implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "创建人名称")
|
||||
@TableField(exist = false)
|
||||
private String createUserName;
|
||||
|
||||
@ApiModelProperty(value = "更新人名称")
|
||||
@TableField(exist = false)
|
||||
private String updateUserName;
|
||||
|
||||
}
|
||||
85
src/main/java/cn/rensijin/cchs/domain/system/SysUser.java
Normal file
85
src/main/java/cn/rensijin/cchs/domain/system/SysUser.java
Normal file
@@ -0,0 +1,85 @@
|
||||
package cn.rensijin.cchs.domain.system;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import java.time.LocalDateTime;
|
||||
import java.io.Serializable;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import cn.rensijin.cchs.domain.base.BaseDomain;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户信息表
|
||||
* </p>
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@ApiModel(value="sys_user 表对应的实体对象", description="用户信息表")
|
||||
public class SysUser extends BaseDomain implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "用户ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "用户账号")
|
||||
@TableField(value = "user_name")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty(value = "用户账号")
|
||||
@TableField(value = "real_name")
|
||||
private String realName;
|
||||
|
||||
@ApiModelProperty(value = "用户邮箱")
|
||||
@TableField(value = "email")
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty(value = "手机号码")
|
||||
@TableField(value = "phonenumber")
|
||||
private String phonenumber;
|
||||
|
||||
@ApiModelProperty(value = "头像地址")
|
||||
@TableField(value = "avatar")
|
||||
private String avatar;
|
||||
|
||||
@ApiModelProperty(value = "密码")
|
||||
@TableField(value = "password")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "备注")
|
||||
@TableField(value = "remark")
|
||||
private String remark;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
@TableField(value = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty(value = "创建人")
|
||||
@TableField(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
@ApiModelProperty(value = "更新时间")
|
||||
@TableField(value = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty(value = "更新人")
|
||||
@TableField(value = "update_user_id")
|
||||
private Long updateUserId;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "UUID")
|
||||
@TableField(exist = false)
|
||||
private String uuid;
|
||||
|
||||
@ApiModelProperty(value = "图片验证码内容")
|
||||
@TableField(exist = false)
|
||||
private String imageCode;
|
||||
|
||||
}
|
||||
25
src/main/java/cn/rensijin/cchs/dto/AppSuggestionVO.java
Normal file
25
src/main/java/cn/rensijin/cchs/dto/AppSuggestionVO.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package cn.rensijin.cchs.dto;
|
||||
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class AppSuggestionVO {
|
||||
|
||||
private Long id;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String suggestionCountent;
|
||||
|
||||
|
||||
private String complaint;
|
||||
|
||||
private String demands;
|
||||
|
||||
private String status;
|
||||
|
||||
private String realName;
|
||||
}
|
||||
|
||||
16
src/main/java/cn/rensijin/cchs/dto/UserToken.java
Normal file
16
src/main/java/cn/rensijin/cchs/dto/UserToken.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package cn.rensijin.cchs.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserToken {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户真实姓名
|
||||
*/
|
||||
private String nickName;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.rensijin.cchs.exception;
|
||||
|
||||
import cn.rensijin.cchs.constants.ErrorCode;
|
||||
import cn.rensijin.cchs.result.JSONResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* 全局异常处理类
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 自定义异常
|
||||
*/
|
||||
@ExceptionHandler(MyException.class)
|
||||
public JSONResult MyException(MyException e){
|
||||
log.error(e.getLocalizedMessage());
|
||||
return JSONResult.error(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 算术异常
|
||||
*/
|
||||
@ExceptionHandler(ArithmeticException.class)
|
||||
public JSONResult methodArithmeticException(ArithmeticException e){
|
||||
log.error(e.getLocalizedMessage());
|
||||
return JSONResult.error("发生算术异常,请稍后再试!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果发生上面没有捕获的异常,那么统一走这个异常捕获,相当于是最大的一个范围
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public JSONResult exceptionHandler(Exception e){
|
||||
e.printStackTrace();
|
||||
log.error(e.getLocalizedMessage());
|
||||
return JSONResult.error(ErrorCode.SYSTEM_ERROR.getMessage());
|
||||
}
|
||||
}
|
||||
23
src/main/java/cn/rensijin/cchs/exception/MyException.java
Normal file
23
src/main/java/cn/rensijin/cchs/exception/MyException.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package cn.rensijin.cchs.exception;
|
||||
|
||||
import cn.rensijin.cchs.constants.ErrorCode;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 自定义异常类
|
||||
*/
|
||||
@Data
|
||||
public class MyException extends RuntimeException {
|
||||
|
||||
private String code;
|
||||
private String message;
|
||||
|
||||
public MyException(String message){
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public MyException(ErrorCode errorCode){
|
||||
this.code = errorCode.getCode();
|
||||
this.message = errorCode.getMessage();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cn.rensijin.cchs.interceptor;
|
||||
|
||||
import cn.rensijin.cchs.annotation.IgnoreAuth;
|
||||
import cn.rensijin.cchs.constants.ErrorCode;
|
||||
import cn.rensijin.cchs.constants.SystemConstants;
|
||||
import cn.rensijin.cchs.exception.MyException;
|
||||
import cn.rensijin.cchs.util.MyTools;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 校验登录的拦截器
|
||||
*/
|
||||
@Component
|
||||
public class LoginInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
//前置拦截
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
// 放行静态资源请求
|
||||
if (isStaticResourceRequest(request)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(handler instanceof HandlerMethod)) {
|
||||
//不是请求方法,则直接放行
|
||||
return true;
|
||||
}
|
||||
|
||||
IgnoreAuth annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
|
||||
if (annotation != null) {
|
||||
//用IgnoreAuth注解标识的接口,直接放行
|
||||
return true;
|
||||
}
|
||||
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
Method method = handlerMethod.getMethod();
|
||||
String methodName = method.getName();
|
||||
System.out.println("methodName=" + methodName);
|
||||
|
||||
//1、从请求头中获取token
|
||||
String token = request.getHeader("token");
|
||||
if (!MyTools.hasLength(token)) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1002.getMessage());
|
||||
}
|
||||
|
||||
//根据token从Redis中获取到用户信息
|
||||
String userInfo = (String) redisTemplate.opsForValue().get(SystemConstants.LOGIN_TOKEN_KEY_APP + token);
|
||||
if (MyTools.hasLength(userInfo)) {
|
||||
//重新设置超时时间
|
||||
redisTemplate.opsForValue().set(SystemConstants.LOGIN_TOKEN_KEY_APP + token, userInfo, SystemConstants.LOGIN_TIME_OUT, TimeUnit.MINUTES);
|
||||
//放行
|
||||
return true;
|
||||
} else {
|
||||
//Redis中拿不到用户信息,抛异常
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1002.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStaticResourceRequest(HttpServletRequest request) {
|
||||
String uri = request.getRequestURI();
|
||||
// 根据你的静态资源路径配置来判断
|
||||
return uri.startsWith("/static/") || uri.startsWith("/images/") || uri.startsWith("/Resource/");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package cn.rensijin.cchs.interceptor;
|
||||
|
||||
import cn.rensijin.cchs.annotation.RateLimit;
|
||||
import cn.rensijin.cchs.exception.MyException;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* <p>防刷限流的拦截器</p>
|
||||
*/
|
||||
@Component
|
||||
public class RateLimitInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Integer> redisTemplate;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
// 如果请求的是方法,则需要做校验
|
||||
if (handler instanceof HandlerMethod) {
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
// 获取目标方法上是否有指定注解
|
||||
RateLimit rateLimit = handlerMethod.getMethodAnnotation(RateLimit.class);
|
||||
if (rateLimit == null) {
|
||||
//说明目标方法上没有 RateLimit 注解
|
||||
return true;
|
||||
}
|
||||
//代码执行到此,说明目标方法上有 RateLimit 注解,所以需要校验这个请求是不是在刷接口
|
||||
// 获取请求IP地址 192.168.12.13
|
||||
String ip = getIpAddr(request);
|
||||
// 请求url路径 /test/test001
|
||||
String uri = request.getRequestURI();
|
||||
//存到redis中的key
|
||||
String key = rateLimit.key() + ip + ":" + uri;//testLimit:192.168.12.13:/test/test001
|
||||
// 缓存中存在key,在限定访问周期内已经调用过当前接口
|
||||
//2秒内发了10次请求
|
||||
if (redisTemplate.hasKey(key)) {
|
||||
// 访问次数自增1
|
||||
redisTemplate.opsForValue().increment(key, 1);
|
||||
// 超出访问次数限制
|
||||
if (redisTemplate.opsForValue().get(key) > rateLimit.count()) {
|
||||
throw new MyException(rateLimit.msg());
|
||||
}
|
||||
// 未超出访问次数限制,不进行任何操作,返回true
|
||||
} else {
|
||||
// 第一次设置数据,过期时间为注解确定的访问周期
|
||||
redisTemplate.opsForValue().set(key, 1, rateLimit.cycle(), TimeUnit.SECONDS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//如果请求的不是方法,直接放行
|
||||
return true;
|
||||
}
|
||||
|
||||
//获取请求的归属IP地址
|
||||
private String getIpAddr(HttpServletRequest request) {
|
||||
String ipAddress = null;
|
||||
try {
|
||||
ipAddress = request.getHeader("x-forwarded-for");
|
||||
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||
ipAddress = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||
ipAddress = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||
ipAddress = request.getRemoteAddr();
|
||||
}
|
||||
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
|
||||
if (ipAddress != null && ipAddress.length() > 15) {
|
||||
// = 15
|
||||
if (ipAddress.indexOf(",") > 0) {
|
||||
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ipAddress = "";
|
||||
}
|
||||
return ipAddress;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.rensijin.cchs.mapper.app;
|
||||
|
||||
import cn.rensijin.cchs.domain.app.AppSuggestion;
|
||||
import cn.rensijin.cchs.dto.AppSuggestionVO;
|
||||
import cn.rensijin.cchs.query.app.AppSuggestionQuery;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 意见反馈表 Mapper接口
|
||||
* </p>
|
||||
*/
|
||||
public interface AppSuggestionMapper extends BaseMapper<AppSuggestion> {
|
||||
|
||||
//查询分页列表数据
|
||||
List<AppSuggestion> selectMySqlPage(Page<AppSuggestion> page, @Param("query") AppSuggestionQuery query);
|
||||
|
||||
|
||||
@Select("SELECT a.*, s.real_name as realName" +
|
||||
"FROM app_suggestion a " +
|
||||
"LEFT JOIN sys_user s ON a.user_id = s.id " +
|
||||
"ORDER BY a.id DESC")
|
||||
List<AppSuggestionVO> selectWithUserInfo();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cn.rensijin.cchs.mapper.system;
|
||||
|
||||
import cn.rensijin.cchs.domain.system.SysUser;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户信息表 Mapper接口
|
||||
* </p>
|
||||
*/
|
||||
public interface SysUserMapper extends BaseMapper<SysUser> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.rensijin.cchs.query.app;
|
||||
|
||||
import cn.rensijin.cchs.query.base.BaseQuery;
|
||||
|
||||
/**
|
||||
* 意见反馈表-查询对象
|
||||
*/
|
||||
public class AppSuggestionQuery extends BaseQuery{
|
||||
}
|
||||
17
src/main/java/cn/rensijin/cchs/query/base/BaseQuery.java
Normal file
17
src/main/java/cn/rensijin/cchs/query/base/BaseQuery.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package cn.rensijin.cchs.query.base;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 基础查询对象
|
||||
*/
|
||||
@Data
|
||||
public class BaseQuery implements Serializable {
|
||||
|
||||
private Long[] ids; //批量删除时,前端传来的主键ID集合
|
||||
private String keyword;//关键字
|
||||
|
||||
private Integer current = 1; //当前页
|
||||
private Integer size = 10; //每页显示多少条
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.rensijin.cchs.query.system;
|
||||
|
||||
import cn.rensijin.cchs.query.base.BaseQuery;
|
||||
|
||||
/**
|
||||
* @desc 用户信息表-查询对象
|
||||
*/
|
||||
public class SysUserQuery extends BaseQuery{
|
||||
}
|
||||
124
src/main/java/cn/rensijin/cchs/result/JSONResult.java
Normal file
124
src/main/java/cn/rensijin/cchs/result/JSONResult.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package cn.rensijin.cchs.result;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 统一返回结果对象
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "响应数据封装类")
|
||||
public class JSONResult implements Serializable {
|
||||
|
||||
@ApiModelProperty(value = "响应状态描述(true:成功;false:失败;)")
|
||||
private boolean success = true;
|
||||
|
||||
@ApiModelProperty(value = "响应描述")
|
||||
private String message = "操作成功";
|
||||
|
||||
//成功统一返回0000,其余编码全部是错误码
|
||||
@ApiModelProperty(value = "响应状态码")
|
||||
private String code = "0000";
|
||||
|
||||
//是否展示提示信息(默认不展示)
|
||||
@ApiModelProperty(value = "是否展示提示信息")
|
||||
private boolean showMessage = false;
|
||||
|
||||
//返回的数据
|
||||
@ApiModelProperty(value = "响应数据")
|
||||
private Object data;
|
||||
|
||||
//创建当前实例
|
||||
public static JSONResult success(){
|
||||
return new JSONResult();
|
||||
}
|
||||
|
||||
//创建当前实例
|
||||
public static JSONResult success(boolean showMessage){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setShowMessage(showMessage);
|
||||
return instance;
|
||||
}
|
||||
|
||||
//创建当前实例
|
||||
public static JSONResult success(Object obj){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setData(obj);
|
||||
return instance;
|
||||
}
|
||||
|
||||
//创建当前实例
|
||||
public static JSONResult success(Object obj, boolean showMessage){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setData(obj);
|
||||
instance.setShowMessage(showMessage);
|
||||
return instance;
|
||||
}
|
||||
|
||||
//创建当前实例
|
||||
public static JSONResult successMessage(boolean showMessage, String message){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setShowMessage(showMessage);
|
||||
instance.setMessage(message);
|
||||
return instance;
|
||||
}
|
||||
|
||||
//成功,但是返回不同消息代码
|
||||
public static JSONResult success(Object obj, String code){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setSuccess(true);
|
||||
instance.setCode(code);
|
||||
instance.setData(obj);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static JSONResult success(String code, String message){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setSuccess(true);
|
||||
instance.setCode(code);
|
||||
instance.setMessage(message);
|
||||
return instance;
|
||||
}
|
||||
|
||||
//创建当前实例
|
||||
public static JSONResult error(){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setCode("9999");
|
||||
instance.setSuccess(false);
|
||||
instance.setMessage("系统发生异常,请稍后再试!");
|
||||
return instance;
|
||||
}
|
||||
|
||||
//创建当前实例
|
||||
public static JSONResult error(String message){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setCode("9999");
|
||||
instance.setSuccess(false);
|
||||
instance.setMessage(message);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static JSONResult error(String message, Object obj){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setCode("9999");
|
||||
instance.setMessage(message);
|
||||
instance.setSuccess(false);
|
||||
instance.setData(obj);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static boolean hasLength(String str) {
|
||||
return org.springframework.util.StringUtils.hasLength(str);
|
||||
}
|
||||
|
||||
public static JSONResult error(String code, String message){
|
||||
JSONResult instance = new JSONResult();
|
||||
instance.setCode(hasLength(code) ? code : "9999");
|
||||
instance.setMessage(message);
|
||||
instance.setSuccess(false);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
33
src/main/java/cn/rensijin/cchs/result/PageList.java
Normal file
33
src/main/java/cn/rensijin/cchs/result/PageList.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package cn.rensijin.cchs.result;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页对象
|
||||
*/
|
||||
@Data
|
||||
public class PageList<T> {
|
||||
|
||||
private long total;
|
||||
private List<T> rows = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PageList{" +
|
||||
"total=" + total +
|
||||
", rows=" + rows +
|
||||
'}';
|
||||
}
|
||||
|
||||
//提供有参构造方法,方便测试
|
||||
public PageList(long total, List<T> rows) {
|
||||
this.total = total;
|
||||
this.rows = rows;
|
||||
}
|
||||
//除了有参构造方法,还需要提供一个无参构造方法
|
||||
public PageList() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.rensijin.cchs.service.app;
|
||||
|
||||
import cn.rensijin.cchs.domain.app.AppSuggestion;
|
||||
import cn.rensijin.cchs.dto.AppSuggestionVO;
|
||||
import cn.rensijin.cchs.mapper.app.AppSuggestionMapper;
|
||||
import cn.rensijin.cchs.query.app.AppSuggestionQuery;
|
||||
import cn.rensijin.cchs.util.MyTools;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.stereotype.Service;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 意见反馈表 服务实现类
|
||||
* </p>
|
||||
*/
|
||||
@Transactional
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AppSuggestionService extends ServiceImpl<AppSuggestionMapper, AppSuggestion>{
|
||||
|
||||
@Resource
|
||||
private AppSuggestionMapper appsuggestionMapper;
|
||||
|
||||
//查询分页列表数据(使用QueryWrapper操作)
|
||||
public Page<AppSuggestion> selectMyPage(AppSuggestionQuery query) {
|
||||
QueryWrapper<AppSuggestion> wrapper = new QueryWrapper<>();
|
||||
if (MyTools.hasLength(query.getKeyword())) {
|
||||
wrapper.and(i -> i.like("id", query.getKeyword()));
|
||||
}
|
||||
//排序
|
||||
wrapper.orderByDesc("id");
|
||||
Page<AppSuggestion> page = new Page<>(query.getCurrent(), query.getSize());
|
||||
return super.page(page, wrapper);
|
||||
}
|
||||
|
||||
//查询分页列表数据(自己写SQL)
|
||||
public Page<AppSuggestion> selectMySqlPage(AppSuggestionQuery query) {
|
||||
Page<AppSuggestion> page = new Page<>(query.getCurrent(), query.getSize());
|
||||
List<AppSuggestion> list = appsuggestionMapper.selectMySqlPage(page, query);
|
||||
return page.setRecords(list);
|
||||
}
|
||||
|
||||
|
||||
public List<AppSuggestionVO> selectWithUserInfo(){
|
||||
return appsuggestionMapper.selectWithUserInfo();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.rensijin.cchs.service.system;
|
||||
|
||||
import cn.rensijin.cchs.vo.UploadFileVo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* <p>文件上传接口</p>
|
||||
*/
|
||||
public interface FileService {
|
||||
|
||||
/**
|
||||
* 单个文件上传方法
|
||||
* @param multipartFile 文件
|
||||
* @param folderName 保存文件夹名称
|
||||
*/
|
||||
UploadFileVo uploadFile(MultipartFile multipartFile, String folderName);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.rensijin.cchs.service.system;
|
||||
|
||||
import cn.rensijin.cchs.constants.ErrorCode;
|
||||
import cn.rensijin.cchs.constants.SystemConstants;
|
||||
import cn.rensijin.cchs.domain.system.SysUser;
|
||||
import cn.rensijin.cchs.exception.MyException;
|
||||
import cn.rensijin.cchs.mapper.system.SysUserMapper;
|
||||
import cn.rensijin.cchs.query.system.SysUserQuery;
|
||||
import cn.rensijin.cchs.result.JSONResult;
|
||||
import cn.rensijin.cchs.util.MyTools;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户信息表 服务实现类
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional
|
||||
public class SysUserService extends ServiceImpl<SysUserMapper, SysUser> {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
//查询分页列表数据
|
||||
public IPage<SysUser> selectMyPage(SysUserQuery query) {
|
||||
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
|
||||
if (MyTools.hasLength(query.getKeyword())) {
|
||||
wrapper.and(i -> i.like("user_name", query.getKeyword()));
|
||||
}
|
||||
//排序
|
||||
wrapper.orderByDesc("create_time").orderByDesc("id");
|
||||
IPage<SysUser> page = new Page<>(query.getCurrent(), query.getSize());
|
||||
return super.page(page, wrapper);
|
||||
}
|
||||
|
||||
//获取用户个人信息
|
||||
public JSONResult getUSerInfo(String token) {
|
||||
if (StringUtils.hasLength(token)) {
|
||||
Object userInfo = redisTemplate.opsForValue().get(SystemConstants.LOGIN_TOKEN_KEY_APP + token);
|
||||
if (userInfo == null) {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1002.getMessage());
|
||||
}
|
||||
SysUser sysUser = JSONObject.parseObject(userInfo.toString(), SysUser.class);
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("name", sysUser.getUsername());
|
||||
map.put("avatar", sysUser.getAvatar());
|
||||
return JSONResult.success(map);
|
||||
} else {
|
||||
throw new MyException(ErrorCode.ERROR_CODE_1008.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.rensijin.cchs.service.system.impl;
|
||||
|
||||
import cn.rensijin.cchs.exception.MyException;
|
||||
import cn.rensijin.cchs.service.system.FileService;
|
||||
import cn.rensijin.cchs.util.DateUtils;
|
||||
import cn.rensijin.cchs.vo.UploadFileVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>文件上传-保存到服务器本地磁盘</p>
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class FileServiceLocalImpl implements FileService {
|
||||
|
||||
@Value("${server.port}")
|
||||
private String port;
|
||||
|
||||
@Override
|
||||
public UploadFileVo uploadFile(MultipartFile file, String folderName) {
|
||||
if (file.isEmpty()) {
|
||||
throw new MyException("上传文件不能为空!");
|
||||
}
|
||||
UploadFileVo vo = new UploadFileVo();
|
||||
try {
|
||||
String fileExt = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
|
||||
File path = new File(ResourceUtils.getURL("classpath:").getPath());
|
||||
if (!path.exists()) {
|
||||
path = new File("");
|
||||
}
|
||||
String localPath = "/UploadFiles/" + DateUtils.getCurrentYearMonth() + "/" + folderName + "/";
|
||||
File upload = new File(path.getAbsolutePath(), localPath);
|
||||
if (!upload.exists()) {
|
||||
upload.mkdirs();
|
||||
}
|
||||
String fileName = new Date().getTime() + "." + fileExt;
|
||||
File dest = new File(upload.getAbsolutePath() + "/" + fileName);
|
||||
file.transferTo(dest);
|
||||
//如果使用idea或者eclipse重启项目,发现之前上传的图片或者文件丢失,将下面一行代码注释打开
|
||||
FileUtils.copyFile(dest, new File("E:\\workspace\\EasyJavaTemplateMaster\\EasyJavaTemplate\\SpringBoot\\src\\main\\resources\\static\\UploadFiles" + "/" + DateUtils.getCurrentYearMonth() + "/" + folderName + "/" + fileName));
|
||||
//封装返回数据
|
||||
vo.setFileName(fileName);
|
||||
vo.setFileSize(file.getSize());
|
||||
vo.setFileFullPath("http://localhost:" + port + "/static/UploadFiles/" + DateUtils.getCurrentYearMonth() + "/" + folderName + "/" + fileName);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new MyException("上传文件到本地磁盘异常:" + e.getMessage());
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
197
src/main/java/cn/rensijin/cchs/util/DateUtils.java
Normal file
197
src/main/java/cn/rensijin/cchs/util/DateUtils.java
Normal file
@@ -0,0 +1,197 @@
|
||||
package cn.rensijin.cchs.util;
|
||||
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 时间工具类
|
||||
*/
|
||||
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
||||
{
|
||||
public static String YYYY = "yyyy";
|
||||
|
||||
public static String YYYYMM = "yyyyMM";
|
||||
|
||||
public static String MM = "MM";
|
||||
|
||||
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"};
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(getCurrentDateString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前年月
|
||||
*/
|
||||
public static String getCurrentYearMonth()
|
||||
{
|
||||
return dateTimeNow(YYYYMM);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前月份
|
||||
*/
|
||||
public static String getMonth()
|
||||
{
|
||||
return dateTimeNow(MM);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Date型日期
|
||||
*
|
||||
* @return Date() 当前日期
|
||||
*/
|
||||
public static Date getNowDate()
|
||||
{
|
||||
return new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期, 默认格式为yyyy-MM-dd
|
||||
*/
|
||||
public static String getDate()
|
||||
{
|
||||
return dateTimeNow(YYYY_MM_DD);
|
||||
}
|
||||
|
||||
public static String getYear()
|
||||
{
|
||||
return dateTimeNow(YYYY);
|
||||
}
|
||||
|
||||
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 String getCurrentDateString()
|
||||
{
|
||||
return parseDateToStr(YYYY_MM_DD_HH_MM_SS, new Date());
|
||||
}
|
||||
|
||||
public static final String getCurrentDateString(String dateExpression)
|
||||
{
|
||||
return parseDateToStr(dateExpression, new Date());
|
||||
}
|
||||
|
||||
public static final LocalDateTime getCurrentLocalDateTime()
|
||||
{
|
||||
return LocalDateTime.now();
|
||||
}
|
||||
|
||||
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 + "分钟";
|
||||
}
|
||||
}
|
||||
57
src/main/java/cn/rensijin/cchs/util/IdUtils.java
Normal file
57
src/main/java/cn/rensijin/cchs/util/IdUtils.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package cn.rensijin.cchs.util;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* ID生成器工具类
|
||||
*/
|
||||
public class IdUtils {
|
||||
|
||||
/**
|
||||
* 功能说明 获取随机UUID数,去掉了 -
|
||||
*/
|
||||
public static String getSimpleUUID() {
|
||||
return StringUtils.replace(java.util.UUID.randomUUID().toString(), "-", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机UUID
|
||||
*
|
||||
* @return 随机UUID
|
||||
*/
|
||||
public static String randomUUID()
|
||||
{
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的UUID,去掉了横线
|
||||
*
|
||||
* @return 简化的UUID,去掉了横线
|
||||
*/
|
||||
public static String simpleUUID()
|
||||
{
|
||||
return UUID.randomUUID().toString(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
|
||||
*
|
||||
* @return 随机UUID
|
||||
*/
|
||||
public static String fastUUID()
|
||||
{
|
||||
return UUID.fastUUID().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
|
||||
*
|
||||
* @return 简化的UUID,去掉了横线
|
||||
*/
|
||||
public static String fastSimpleUUID()
|
||||
{
|
||||
return UUID.fastUUID().toString(true);
|
||||
}
|
||||
}
|
||||
199
src/main/java/cn/rensijin/cchs/util/MyTools.java
Normal file
199
src/main/java/cn/rensijin/cchs/util/MyTools.java
Normal file
@@ -0,0 +1,199 @@
|
||||
package cn.rensijin.cchs.util;
|
||||
|
||||
import cn.hutool.core.codec.Base64Encoder;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.rensijin.cchs.constants.SystemConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @desc 工具类
|
||||
*/
|
||||
@Slf4j
|
||||
public class MyTools {
|
||||
|
||||
public static void main(String[] args){
|
||||
System.out.println(SecureUtil.md5("123456"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的完整路径
|
||||
*/
|
||||
public static String getFileUploadPath(String fileFullName) {
|
||||
String uploadPath = System.getProperty("user.dir");
|
||||
return uploadPath + SystemConstants.FILES_DIR + fileFullName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 获取随机用户昵称
|
||||
* 返回长度:20
|
||||
*/
|
||||
public synchronized static String getNickName() {
|
||||
return getRandomChar(12).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 判断字符串是否有长度
|
||||
*/
|
||||
public static boolean hasLength(String str) {
|
||||
return org.springframework.util.StringUtils.hasLength(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 获取token值
|
||||
*/
|
||||
public static String getLoginToken() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 将本地图片转成Base64数据
|
||||
*/
|
||||
public static String ImageToBase64(String imgPath) {
|
||||
byte[] data = null;
|
||||
// 读取图片字节数组
|
||||
try {
|
||||
InputStream in = new FileInputStream(imgPath);
|
||||
data = new byte[in.available()];
|
||||
in.read(data);
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
log.error("图片转Base64数据时发生异常:{}", e.getLocalizedMessage());
|
||||
}
|
||||
// 对字节数组Base64编码
|
||||
Base64Encoder encoder = new Base64Encoder();
|
||||
// 返回Base64编码过的字节数组字符串
|
||||
return "data:img/jpg;base64," + encoder.encode(Objects.requireNonNull(data));
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: 验证密码,必须是6-18位长度,必须由数字和字母组成,并且要同时含有数字和字母,且长度要在6-18位之间
|
||||
*/
|
||||
public static boolean checkPassword(String str){
|
||||
boolean checkResult = false;
|
||||
if(!StringUtils.isBlank(str)){
|
||||
String regEx = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$";
|
||||
Pattern p = Pattern.compile(regEx);
|
||||
Matcher m = p.matcher(str);
|
||||
if(m.matches()){
|
||||
checkResult = true;
|
||||
}
|
||||
}
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: 验证字母和数字,必须是6-18位长度
|
||||
*/
|
||||
public static boolean checkNumChar(String str){
|
||||
boolean checkResult = false;
|
||||
if(!StringUtils.isBlank(str)){
|
||||
String regEx = "^[0-9A-Za-z]{6,18}$";
|
||||
Pattern p = Pattern.compile(regEx);
|
||||
Matcher m = p.matcher(str);
|
||||
if(m.matches()){
|
||||
checkResult = true;
|
||||
}
|
||||
}
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: 验证手机号
|
||||
*/
|
||||
public static boolean checkPhone(String phone){
|
||||
boolean checkResult = false;
|
||||
if(!StringUtils.isBlank(phone)){
|
||||
if(phone.length() == 11){
|
||||
String regEx = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(17[013678])|(18[0, 5-9]))\\d{8}$";
|
||||
Pattern p = Pattern.compile(regEx);
|
||||
Matcher m = p.matcher(phone);
|
||||
if(m.matches()){
|
||||
checkResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: 验证邮箱格式
|
||||
*/
|
||||
public static boolean checkEmail(String email){
|
||||
boolean checkResult = false;
|
||||
if(!StringUtils.isBlank(email)){
|
||||
String regEx = "([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
|
||||
Pattern p = Pattern.compile(regEx);
|
||||
Matcher m = p.matcher(email);
|
||||
if(m.matches()){
|
||||
checkResult = true;
|
||||
}
|
||||
}
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Description: 获取指定位数的随机整数
|
||||
*/
|
||||
public synchronized static String getRandomNum(int num) {
|
||||
Random random = new Random();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 1; i <= num; i++) {
|
||||
sb.append(random.nextInt(9));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取指定串中随机指定位数的字符串
|
||||
*/
|
||||
public synchronized static String getRandomChar(int num) {
|
||||
//先定义取值范围
|
||||
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
StringBuffer value = new StringBuffer();
|
||||
for (int i = 0; i < num; i++) {
|
||||
value.append(chars.charAt((int)(Math.random() * chars.length())));
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: 获取当前时间字符串(yyyyMMddHHmmss)
|
||||
*/
|
||||
public synchronized static String getCurrentTimeStr() {
|
||||
Date date = new Date();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
return dateFormat.format(date);
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: 根据MultipartFile文件获取图片Base64数据
|
||||
*/
|
||||
public static String MutipartFileToBase64(MultipartFile file) {
|
||||
String base64EncoderImg = "";
|
||||
try {
|
||||
Base64Encoder encoder = new Base64Encoder();
|
||||
base64EncoderImg = "data:img/jpg;base64," + encoder.encode(file.getBytes());
|
||||
} catch (Exception e) {
|
||||
log.error("根据MultipartFile文件获取Base64数据,异常:{}", e);
|
||||
}
|
||||
return base64EncoderImg;
|
||||
}
|
||||
|
||||
|
||||
//随机获取指定区间的整数
|
||||
public synchronized static String getRandomDotString(int min, int max) {
|
||||
Random rand = new Random();
|
||||
StringBuffer result = new StringBuffer();
|
||||
result.append(rand.nextInt(max - min + 1) + min);
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
251
src/main/java/cn/rensijin/cchs/util/RedisCache.java
Normal file
251
src/main/java/cn/rensijin/cchs/util/RedisCache.java
Normal file
@@ -0,0 +1,251 @@
|
||||
package cn.rensijin.cchs.util;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.BoundSetOperations;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Redis 工具类
|
||||
*/
|
||||
@Component
|
||||
public class RedisCache
|
||||
{
|
||||
@Autowired
|
||||
public RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 清空Redis所有缓存数据
|
||||
*/
|
||||
public void clearAllRedisData()
|
||||
{
|
||||
Set<String> keys = redisTemplate.keys("*");
|
||||
redisTemplate.delete(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value)
|
||||
{
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
* @param timeout 时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
|
||||
{
|
||||
if(timeout == -1){
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}else{
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout)
|
||||
{
|
||||
return expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @param unit 时间单位
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout, final TimeUnit unit)
|
||||
{
|
||||
return redisTemplate.expire(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> T getCacheObject(final String key)
|
||||
{
|
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||
return operation.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public boolean deleteObject(final String key)
|
||||
{
|
||||
if(redisTemplate.hasKey(key)){
|
||||
return redisTemplate.delete(key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除集合对象
|
||||
*
|
||||
* @param collection 多个对象
|
||||
* @return
|
||||
*/
|
||||
public long deleteObject(final Collection collection)
|
||||
{
|
||||
return redisTemplate.delete(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存List数据
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param dataList 待缓存的List数据
|
||||
* @return 缓存的对象
|
||||
*/
|
||||
public <T> long setCacheList(final String key, final List<T> dataList)
|
||||
{
|
||||
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
||||
return count == null ? 0 : count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的list对象
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> List<T> getCacheList(final String key)
|
||||
{
|
||||
return redisTemplate.opsForList().range(key, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Set
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @param dataSet 缓存的数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
|
||||
{
|
||||
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
|
||||
Iterator<T> it = dataSet.iterator();
|
||||
while (it.hasNext())
|
||||
{
|
||||
setOperation.add(it.next());
|
||||
}
|
||||
return setOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的set
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Set<T> getCacheSet(final String key)
|
||||
{
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Map
|
||||
*
|
||||
* @param key
|
||||
* @param dataMap
|
||||
*/
|
||||
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
|
||||
{
|
||||
if (dataMap != null) {
|
||||
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的Map
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Map<String, T> getCacheMap(final String key)
|
||||
{
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 往Hash中存入数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @param value 值
|
||||
*/
|
||||
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
|
||||
{
|
||||
redisTemplate.opsForHash().put(key, hKey, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return Hash中的对象
|
||||
*/
|
||||
public <T> T getCacheMapValue(final String key, final String hKey)
|
||||
{
|
||||
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
||||
return opsForHash.get(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKeys Hash键集合
|
||||
* @return Hash对象集合
|
||||
*/
|
||||
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
|
||||
{
|
||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
public Collection<String> keys(final String pattern)
|
||||
{
|
||||
return redisTemplate.keys(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 判断Redis中是否存在指定的key
|
||||
*/
|
||||
public boolean exists(String key) {
|
||||
return redisTemplate.hasKey(key);
|
||||
}
|
||||
}
|
||||
14
src/main/java/cn/rensijin/cchs/vo/LoginSuccessVo.java
Normal file
14
src/main/java/cn/rensijin/cchs/vo/LoginSuccessVo.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package cn.rensijin.cchs.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* <p>登录成功后,返回前端的对象</p>
|
||||
*/
|
||||
@Data
|
||||
public class LoginSuccessVo {
|
||||
private String token;//token
|
||||
private String refToken;//刷新token
|
||||
private Long userId;//用户ID
|
||||
private Integer roleId;
|
||||
}
|
||||
15
src/main/java/cn/rensijin/cchs/vo/UploadFileVo.java
Normal file
15
src/main/java/cn/rensijin/cchs/vo/UploadFileVo.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package cn.rensijin.cchs.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* <p>文件上传成功后返回前端参数</p>
|
||||
*/
|
||||
@Data
|
||||
public class UploadFileVo {
|
||||
|
||||
private String fileFullPath;//文件全路径
|
||||
private String fileName;//文件名称
|
||||
private String filePrefix;//文件存储路径的前缀
|
||||
private Long fileSize;//文件大小
|
||||
}
|
||||
15
src/main/java/cn/rensijin/cchs/vo/UserTokenVo.java
Normal file
15
src/main/java/cn/rensijin/cchs/vo/UserTokenVo.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package cn.rensijin.cchs.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @desc 登录成功之后,返回前端的对象
|
||||
*/
|
||||
@Data
|
||||
public class UserTokenVo {
|
||||
|
||||
private String token;
|
||||
private String userName;
|
||||
private String realName;
|
||||
private String avatar;
|
||||
}
|
||||
70
src/main/resources/application.yml
Normal file
70
src/main/resources/application.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
server:
|
||||
#启动端口
|
||||
port: 8002
|
||||
tomcat:
|
||||
#设置字符编码
|
||||
uri-encoding: UTF-8
|
||||
spring:
|
||||
application:
|
||||
#系统服务名
|
||||
name: EasyJavaTemplate
|
||||
#MySQL数据库相关配置信息
|
||||
datasource:
|
||||
url: jdbc:mysql://192.168.100.201:3306/rensijin-cchs?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root #数据库账号
|
||||
password: Abc123654 #数据库密码
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
#Redis 缓存相关参数配置
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379 #端口
|
||||
timeout: 5000 #连接超时 毫秒
|
||||
password: Redis11 #密码
|
||||
jedis:
|
||||
pool:
|
||||
maxActive: 30 #给定时间可以分配的最大连接数。 使用负值表示没有限制
|
||||
maxIdle: 30 #最大空闲连接数
|
||||
minIdle: 10 # 最小空间连接数
|
||||
maxWait: -1 #连接池最大等待时间 -1没有限制
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
servlet:
|
||||
multipart:
|
||||
#单个文件上传大小限制
|
||||
max-file-size: 30MB
|
||||
#单次上传文件总大小限制
|
||||
max-request-size: 100MB
|
||||
|
||||
#MyBatis-Plus相关配置
|
||||
mybatis-plus:
|
||||
#指定Mapper.xml路径,如果与Mapper路径相同的话,可省略
|
||||
mapper-locations: classpath:cn/wujiangbo/mapper/*Mapper.xml
|
||||
configuration:
|
||||
#开启驼峰大小写自动转换
|
||||
map-underscore-to-camel-case: true
|
||||
#开启控制台sql输出
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
easyjava:
|
||||
#版本号
|
||||
version: 2.0.5
|
||||
#系统类型标识
|
||||
systemType: 'xxx'
|
||||
#用户注册默认头像地址
|
||||
userDefaultAvatarPath: https://img2.baidu.com/it/u=1016407180,2828407920&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800
|
||||
|
||||
#OSS相关配置
|
||||
file:
|
||||
#文件存储方案(1:文件本地;2:存阿里云OSS)
|
||||
filescheme: 1
|
||||
download:
|
||||
#文件下载用到的服务器IP地址
|
||||
ip: localhost
|
||||
alicloud:
|
||||
enable: true #是否开启OSS上传
|
||||
bucket-name: xxx #上传空间bucket
|
||||
access-key: xxx #你的key
|
||||
secret-key: xxx #你的秘钥
|
||||
endpoint: oss-cn-beijing.aliyuncs.com #上传端点
|
||||
0
src/main/resources/banner.txt
Normal file
0
src/main/resources/banner.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.rensijin.cchs.mapper.app.AppSuggestionMapper">
|
||||
|
||||
<select id="selectMySqlPage" resultType="cn.rensijin.cchs.domain.app.AppSuggestion">
|
||||
select t1.*, t2.real_name as createUserName
|
||||
from app_suggestion t1
|
||||
left join sys_user t2 on t1.user_id = t2.id
|
||||
<where>
|
||||
<if test="query.keyword != null and query.keyword != '' ">
|
||||
and t1.complaint like concat('%', #{query.keyword}, '%')
|
||||
</if>
|
||||
</where>
|
||||
order by t1.id desc
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.rensijin.cchs.mapper.system.SysUserMapper">
|
||||
|
||||
</mapper>
|
||||
145
src/main/resources/logback-spring.xml
Normal file
145
src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,145 @@
|
||||
<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
|
||||
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
|
||||
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
|
||||
<!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
|
||||
<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 动态日志级别 -->
|
||||
<jmxConfigurator />
|
||||
<!-- 定义日志文件 输出位置 -->
|
||||
<property name="log_dir" value="C:/LOGS/EasyJavaTemplate" />
|
||||
<!-- 日志最大的历史 30天 -->
|
||||
<property name="maxHistory" value="30" />
|
||||
<!-- 单个日志文件的最大大小 -->
|
||||
<property name="maxFileSize" value="5MB" />
|
||||
<!--格式化输出:%d表示日期,%t:表示线程名,%-5level:级别从左显示5个字符宽度,%c:类全路径,%msg:日志消息,%M:方法名,%L:日志所属行号,%n:换行符(Windows平台为"\r\n",Unix平台为"\n") -->
|
||||
<property name="FORMAT" value="%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c.%M:%L:%msg%n"/>
|
||||
|
||||
|
||||
<!-- ConsoleAppender 控制台输出日志 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>
|
||||
<!-- 设置日志输出格式 -->
|
||||
${FORMAT}
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- ERROR级别日志 -->
|
||||
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
|
||||
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 过滤器,只记录WARN级别的日志 -->
|
||||
<!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 设置过滤级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 用于配置符合过滤条件的操作 -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 用于配置不符合过滤条件的操作 -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!--
|
||||
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
|
||||
%i:当文件大小超过maxFileSize时,按照i进行文件滚动,i的值从0开始递增
|
||||
-->
|
||||
<fileNamePattern>
|
||||
${log_dir}/error/%d{yyyy-MM-dd}/error-%i.log
|
||||
</fileNamePattern>
|
||||
<!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6, 则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除 -->
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>
|
||||
<!-- 设置日志输出格式 -->
|
||||
${FORMAT}
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- WARN级别日志 appender -->
|
||||
<appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 过滤器,只记录WARN级别的日志 -->
|
||||
<!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 设置过滤级别 -->
|
||||
<level>WARN</level>
|
||||
<!-- 用于配置符合过滤条件的操作 -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 用于配置不符合过滤条件的操作 -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_dir}/warn/%d{yyyy-MM-dd}/warn-%i.log</fileNamePattern>
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FORMAT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- INFO级别日志 appender -->
|
||||
<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_dir}/info/%d{yyyy-MM-dd}/info-%i.log</fileNamePattern>
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FORMAT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- DEBUG级别日志 appender -->
|
||||
<appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>DEBUG</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_dir}/debug/%d{yyyy-MM-dd}/debug-%i.log</fileNamePattern>
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FORMAT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- root级别 -->
|
||||
<root>
|
||||
<!-- 只有该级别日志及以上级别日志才会输出到指定渠道 -->
|
||||
<!-- 测试:debug。上生产环境时,需要改成info或error -->
|
||||
<level value="info" />
|
||||
<!-- 控制台输出渠道 -->
|
||||
<appender-ref ref="console" />
|
||||
<!-- 文件输出渠道 -->
|
||||
<appender-ref ref="ERROR" />
|
||||
<appender-ref ref="INFO" />
|
||||
<appender-ref ref="WARN" />
|
||||
<appender-ref ref="DEBUG" />
|
||||
</root>
|
||||
</configuration>
|
||||
70
target/classes/application.yml
Normal file
70
target/classes/application.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
server:
|
||||
#启动端口
|
||||
port: 8002
|
||||
tomcat:
|
||||
#设置字符编码
|
||||
uri-encoding: UTF-8
|
||||
spring:
|
||||
application:
|
||||
#系统服务名
|
||||
name: EasyJavaTemplate
|
||||
#MySQL数据库相关配置信息
|
||||
datasource:
|
||||
url: jdbc:mysql://192.168.100.201:3306/rensijin-cchs?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root #数据库账号
|
||||
password: Abc123654 #数据库密码
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
#Redis 缓存相关参数配置
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379 #端口
|
||||
timeout: 5000 #连接超时 毫秒
|
||||
password: Redis11 #密码
|
||||
jedis:
|
||||
pool:
|
||||
maxActive: 30 #给定时间可以分配的最大连接数。 使用负值表示没有限制
|
||||
maxIdle: 30 #最大空闲连接数
|
||||
minIdle: 10 # 最小空间连接数
|
||||
maxWait: -1 #连接池最大等待时间 -1没有限制
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
servlet:
|
||||
multipart:
|
||||
#单个文件上传大小限制
|
||||
max-file-size: 30MB
|
||||
#单次上传文件总大小限制
|
||||
max-request-size: 100MB
|
||||
|
||||
#MyBatis-Plus相关配置
|
||||
mybatis-plus:
|
||||
#指定Mapper.xml路径,如果与Mapper路径相同的话,可省略
|
||||
mapper-locations: classpath:cn/wujiangbo/mapper/*Mapper.xml
|
||||
configuration:
|
||||
#开启驼峰大小写自动转换
|
||||
map-underscore-to-camel-case: true
|
||||
#开启控制台sql输出
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
easyjava:
|
||||
#版本号
|
||||
version: 2.0.5
|
||||
#系统类型标识
|
||||
systemType: 'xxx'
|
||||
#用户注册默认头像地址
|
||||
userDefaultAvatarPath: https://img2.baidu.com/it/u=1016407180,2828407920&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=800
|
||||
|
||||
#OSS相关配置
|
||||
file:
|
||||
#文件存储方案(1:文件本地;2:存阿里云OSS)
|
||||
filescheme: 1
|
||||
download:
|
||||
#文件下载用到的服务器IP地址
|
||||
ip: localhost
|
||||
alicloud:
|
||||
enable: true #是否开启OSS上传
|
||||
bucket-name: xxx #上传空间bucket
|
||||
access-key: xxx #你的key
|
||||
secret-key: xxx #你的秘钥
|
||||
endpoint: oss-cn-beijing.aliyuncs.com #上传端点
|
||||
0
target/classes/banner.txt
Normal file
0
target/classes/banner.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.rensijin.cchs.mapper.app.AppSuggestionMapper">
|
||||
|
||||
<select id="selectMySqlPage" resultType="cn.rensijin.cchs.domain.app.AppSuggestion">
|
||||
select t1.*, t2.real_name as createUserName
|
||||
from app_suggestion t1
|
||||
left join sys_user t2 on t1.user_id = t2.id
|
||||
<where>
|
||||
<if test="query.keyword != null and query.keyword != '' ">
|
||||
and t1.complaint like concat('%', #{query.keyword}, '%')
|
||||
</if>
|
||||
</where>
|
||||
order by t1.id desc
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.rensijin.cchs.mapper.system.SysUserMapper">
|
||||
|
||||
</mapper>
|
||||
145
target/classes/logback-spring.xml
Normal file
145
target/classes/logback-spring.xml
Normal file
@@ -0,0 +1,145 @@
|
||||
<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
|
||||
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
|
||||
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
|
||||
<!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
|
||||
<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 动态日志级别 -->
|
||||
<jmxConfigurator />
|
||||
<!-- 定义日志文件 输出位置 -->
|
||||
<property name="log_dir" value="C:/LOGS/EasyJavaTemplate" />
|
||||
<!-- 日志最大的历史 30天 -->
|
||||
<property name="maxHistory" value="30" />
|
||||
<!-- 单个日志文件的最大大小 -->
|
||||
<property name="maxFileSize" value="5MB" />
|
||||
<!--格式化输出:%d表示日期,%t:表示线程名,%-5level:级别从左显示5个字符宽度,%c:类全路径,%msg:日志消息,%M:方法名,%L:日志所属行号,%n:换行符(Windows平台为"\r\n",Unix平台为"\n") -->
|
||||
<property name="FORMAT" value="%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c.%M:%L:%msg%n"/>
|
||||
|
||||
|
||||
<!-- ConsoleAppender 控制台输出日志 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>
|
||||
<!-- 设置日志输出格式 -->
|
||||
${FORMAT}
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- ERROR级别日志 -->
|
||||
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
|
||||
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 过滤器,只记录WARN级别的日志 -->
|
||||
<!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 设置过滤级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 用于配置符合过滤条件的操作 -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 用于配置不符合过滤条件的操作 -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!--
|
||||
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
|
||||
%i:当文件大小超过maxFileSize时,按照i进行文件滚动,i的值从0开始递增
|
||||
-->
|
||||
<fileNamePattern>
|
||||
${log_dir}/error/%d{yyyy-MM-dd}/error-%i.log
|
||||
</fileNamePattern>
|
||||
<!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6, 则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除 -->
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>
|
||||
<!-- 设置日志输出格式 -->
|
||||
${FORMAT}
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- WARN级别日志 appender -->
|
||||
<appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 过滤器,只记录WARN级别的日志 -->
|
||||
<!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 设置过滤级别 -->
|
||||
<level>WARN</level>
|
||||
<!-- 用于配置符合过滤条件的操作 -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 用于配置不符合过滤条件的操作 -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_dir}/warn/%d{yyyy-MM-dd}/warn-%i.log</fileNamePattern>
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FORMAT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- INFO级别日志 appender -->
|
||||
<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_dir}/info/%d{yyyy-MM-dd}/info-%i.log</fileNamePattern>
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FORMAT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- DEBUG级别日志 appender -->
|
||||
<appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>DEBUG</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log_dir}/debug/%d{yyyy-MM-dd}/debug-%i.log</fileNamePattern>
|
||||
<maxHistory>${maxHistory}</maxHistory>
|
||||
<!-- 日志文件的最大大小 -->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${maxFileSize}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FORMAT}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- root级别 -->
|
||||
<root>
|
||||
<!-- 只有该级别日志及以上级别日志才会输出到指定渠道 -->
|
||||
<!-- 测试:debug。上生产环境时,需要改成info或error -->
|
||||
<level value="info" />
|
||||
<!-- 控制台输出渠道 -->
|
||||
<appender-ref ref="console" />
|
||||
<!-- 文件输出渠道 -->
|
||||
<appender-ref ref="ERROR" />
|
||||
<appender-ref ref="INFO" />
|
||||
<appender-ref ref="WARN" />
|
||||
<appender-ref ref="DEBUG" />
|
||||
</root>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user