commit 5990a4f052fe09cb30870daff17040dc69ca11f3 Author: cuianbing <2668052199@qq.com> Date: Tue Dec 30 11:02:57 2025 +0800 init diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -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 diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..5678dc7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..63e9001 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..6522237 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..732146c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sonarlint.xml b/.idea/sonarlint.xml new file mode 100644 index 0000000..d16ff45 --- /dev/null +++ b/.idea/sonarlint.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..57471c5 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# 客户投诉处理系统的设计与实现(Customer complaint handling system) + +## 功能内容 +- [x] 用户注册页(用户名、密码)、 +- [x] 用户登录页(用户名、密码)、 +- [ ] 用户投诉页(投诉事由、具体内容、解决诉求)、 +- [ ] 用户查看投诉记录列表页(投诉事由、投诉时间、投诉状态:有效/已撤销、操作:修改/删除)、 +- [ ] 用户查看投诉详情页(结构类似于用户投诉页,带修改按钮和撤销按钮)。 + +设计程序的数据库结构,并据此在DBMS中实现用户表和投诉表。 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2397c2c --- /dev/null +++ b/pom.xml @@ -0,0 +1,136 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + com.rensijin.cchs + rensijin-cchs + 1.0.0 + rensijin-cchs + 任思瑾的客户投诉处理系统 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.baomidou + mybatis-plus-boot-starter + 3.4.1 + + + + mysql + mysql-connector-java + + + + com.alibaba + druid + 1.2.1 + + + + org.springframework.boot + spring-boot-starter-aop + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + commons-io + commons-io + 2.5 + + + + + com.github.whvcse + easy-captcha + 1.6.2 + + + + org.projectlombok + lombok + + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + + + com.alibaba + fastjson + 1.2.50 + + + + cn.hutool + hutool-all + 5.7.16 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.3.5.RELEASE + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + + true + + true + + + + + EasyJavaTemplate + + + + \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/App.java b/src/main/java/cn/wujiangbo/App.java new file mode 100644 index 0000000..df386f2 --- /dev/null +++ b/src/main/java/cn/wujiangbo/App.java @@ -0,0 +1,21 @@ +package cn.wujiangbo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; + +/** + * @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("**************************************"); + } + +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/annotation/IgnoreAuth.java b/src/main/java/cn/wujiangbo/annotation/IgnoreAuth.java new file mode 100644 index 0000000..c282f35 --- /dev/null +++ b/src/main/java/cn/wujiangbo/annotation/IgnoreAuth.java @@ -0,0 +1,13 @@ +package cn.wujiangbo.annotation; + +import java.lang.annotation.*; + +/** + * @Desc: 忽略Token验证 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface IgnoreAuth { + +} diff --git a/src/main/java/cn/wujiangbo/annotation/RateLimit.java b/src/main/java/cn/wujiangbo/annotation/RateLimit.java new file mode 100644 index 0000000..749f5a1 --- /dev/null +++ b/src/main/java/cn/wujiangbo/annotation/RateLimit.java @@ -0,0 +1,25 @@ +package cn.wujiangbo.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 "请勿重复点击"; +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/config/cors/CorsFilterConfig.java b/src/main/java/cn/wujiangbo/config/cors/CorsFilterConfig.java new file mode 100644 index 0000000..5f6e027 --- /dev/null +++ b/src/main/java/cn/wujiangbo/config/cors/CorsFilterConfig.java @@ -0,0 +1,39 @@ +package cn.wujiangbo.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); + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/config/date/DateConfig.java b/src/main/java/cn/wujiangbo/config/date/DateConfig.java new file mode 100644 index 0000000..ed4ca11 --- /dev/null +++ b/src/main/java/cn/wujiangbo/config/date/DateConfig.java @@ -0,0 +1,78 @@ +package cn.wujiangbo.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 localDateConverter() { + return new Converter() { + @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 localDateTimeConverter() { + return new Converter() { + @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); + }; + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/config/date/JacksonObjectMapper.java b/src/main/java/cn/wujiangbo/config/date/JacksonObjectMapper.java new file mode 100644 index 0000000..d8f3e83 --- /dev/null +++ b/src/main/java/cn/wujiangbo/config/date/JacksonObjectMapper.java @@ -0,0 +1,49 @@ +package cn.wujiangbo.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); + } +} diff --git a/src/main/java/cn/wujiangbo/config/mp/MyBatiesPlusConfiguration.java b/src/main/java/cn/wujiangbo/config/mp/MyBatiesPlusConfiguration.java new file mode 100644 index 0000000..daaf3dc --- /dev/null +++ b/src/main/java/cn/wujiangbo/config/mp/MyBatiesPlusConfiguration.java @@ -0,0 +1,23 @@ +package cn.wujiangbo.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.wujiangbo.mapper") +public class MyBatiesPlusConfiguration { + + /* + * 分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); + return paginationInterceptor; + } +} diff --git a/src/main/java/cn/wujiangbo/config/redis/RedisConfig.java b/src/main/java/cn/wujiangbo/config/redis/RedisConfig.java new file mode 100644 index 0000000..2b89b0f --- /dev/null +++ b/src/main/java/cn/wujiangbo/config/redis/RedisConfig.java @@ -0,0 +1,39 @@ +package cn.wujiangbo.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; + +/** + *

Redis配置类

+ */ +@Configuration +public class RedisConfig { + + @Bean + public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { + // 设置序列化 + Jackson2JsonRedisSerializer 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 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; + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/config/swagger/Swagger2.java b/src/main/java/cn/wujiangbo/config/swagger/Swagger2.java new file mode 100644 index 0000000..881aaa4 --- /dev/null +++ b/src/main/java/cn/wujiangbo/config/swagger/Swagger2.java @@ -0,0 +1,79 @@ +package cn.wujiangbo.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.wujiangbo.controller"))//扫描包 + .paths(PathSelectors.any()) + .build() + /* 设置安全模式,swagger可以设置访问token */ + .securitySchemes(securitySchemes()); + } + + /** + * 安全模式,这里指定token通过头请求头传递 + */ + private List securitySchemes() + { + List apiKeyList = new ArrayList(); + apiKeyList.add(new ApiKey("token", "token", In.HEADER.toValue())); + return apiKeyList; + } + + /** + * 默认的安全上引用 + */ + private List defaultAuth() + { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + List 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(); + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/config/web/WebConfig.java b/src/main/java/cn/wujiangbo/config/web/WebConfig.java new file mode 100644 index 0000000..0cdc626 --- /dev/null +++ b/src/main/java/cn/wujiangbo/config/web/WebConfig.java @@ -0,0 +1,58 @@ +package cn.wujiangbo.config.web; + +import cn.wujiangbo.config.date.JacksonObjectMapper; +import cn.wujiangbo.interceptor.LoginInterceptor; +import cn.wujiangbo.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> 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); + } + +} diff --git a/src/main/java/cn/wujiangbo/constants/ErrorCode.java b/src/main/java/cn/wujiangbo/constants/ErrorCode.java new file mode 100644 index 0000000..4fbef28 --- /dev/null +++ b/src/main/java/cn/wujiangbo/constants/ErrorCode.java @@ -0,0 +1,44 @@ +package cn.wujiangbo.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; + } +} diff --git a/src/main/java/cn/wujiangbo/constants/SystemConstants.java b/src/main/java/cn/wujiangbo/constants/SystemConstants.java new file mode 100644 index 0000000..b9a4611 --- /dev/null +++ b/src/main/java/cn/wujiangbo/constants/SystemConstants.java @@ -0,0 +1,51 @@ +package cn.wujiangbo.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"; +} diff --git a/src/main/java/cn/wujiangbo/controller/LoginController.java b/src/main/java/cn/wujiangbo/controller/LoginController.java new file mode 100644 index 0000000..2cdd28c --- /dev/null +++ b/src/main/java/cn/wujiangbo/controller/LoginController.java @@ -0,0 +1,134 @@ +package cn.wujiangbo.controller; + +import cn.hutool.crypto.SecureUtil; +import cn.wujiangbo.annotation.IgnoreAuth; +import cn.wujiangbo.constants.ErrorCode; +import cn.wujiangbo.constants.SystemConstants; +import cn.wujiangbo.domain.system.SysUser; +import cn.wujiangbo.exception.MyException; +import cn.wujiangbo.mapper.system.SysUserMapper; +import cn.wujiangbo.result.JSONResult; +import cn.wujiangbo.util.MyTools; +import cn.wujiangbo.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 queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_name", user.getUsername()); + List 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(); + } +} diff --git a/src/main/java/cn/wujiangbo/controller/RegisterController.java b/src/main/java/cn/wujiangbo/controller/RegisterController.java new file mode 100644 index 0000000..5af70ae --- /dev/null +++ b/src/main/java/cn/wujiangbo/controller/RegisterController.java @@ -0,0 +1,65 @@ +package cn.wujiangbo.controller; + + +import cn.hutool.crypto.SecureUtil; +import cn.wujiangbo.annotation.IgnoreAuth; +import cn.wujiangbo.constants.ErrorCode; +import cn.wujiangbo.constants.SystemConstants; +import cn.wujiangbo.domain.app.AppUser; +import cn.wujiangbo.domain.system.SysUser; +import cn.wujiangbo.exception.MyException; +import cn.wujiangbo.result.JSONResult; +import cn.wujiangbo.service.system.SysUserService; +import cn.wujiangbo.util.DateUtils; +import cn.wujiangbo.util.MyTools; +import cn.wujiangbo.vo.UserTokenVo; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; +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; + +import java.math.BigDecimal; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @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 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, "注册成功,快去登录吧!"); + } +} diff --git a/src/main/java/cn/wujiangbo/controller/TestController.java b/src/main/java/cn/wujiangbo/controller/TestController.java new file mode 100644 index 0000000..e3f093e --- /dev/null +++ b/src/main/java/cn/wujiangbo/controller/TestController.java @@ -0,0 +1,24 @@ +package cn.wujiangbo.controller; + +import cn.wujiangbo.annotation.RateLimit; +import cn.wujiangbo.result.JSONResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

测试类

+ * + */ +@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("成功发送一条短信"); + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/controller/app/AppSuggestionController.java b/src/main/java/cn/wujiangbo/controller/app/AppSuggestionController.java new file mode 100644 index 0000000..5cd8eab --- /dev/null +++ b/src/main/java/cn/wujiangbo/controller/app/AppSuggestionController.java @@ -0,0 +1,139 @@ +package cn.wujiangbo.controller.app; + +import cn.wujiangbo.domain.app.AppSuggestion; +import cn.wujiangbo.result.PageList; +import cn.wujiangbo.service.app.AppSuggestionService; +import cn.wujiangbo.query.app.AppSuggestionQuery; +import cn.wujiangbo.controller.base.BaseController; +import cn.wujiangbo.util.DateUtils; +import cn.wujiangbo.result.JSONResult; +import cn.wujiangbo.result.PageList; +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 queryWrapper = new QueryWrapper(); + queryWrapper.orderByDesc("id"); + List 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 page = appSuggestionService.selectMySqlPage(query); + return JSONResult.success(new PageList<>(page.getTotal(), page.getRecords())); + } + + + +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/controller/base/BaseController.java b/src/main/java/cn/wujiangbo/controller/base/BaseController.java new file mode 100644 index 0000000..312464e --- /dev/null +++ b/src/main/java/cn/wujiangbo/controller/base/BaseController.java @@ -0,0 +1,99 @@ +package cn.wujiangbo.controller.base; + +import cn.wujiangbo.constants.ErrorCode; +import cn.wujiangbo.constants.SystemConstants; +import cn.wujiangbo.domain.app.AppUser; +import cn.wujiangbo.domain.system.SysUser; +import cn.wujiangbo.exception.MyException; +import cn.wujiangbo.service.app.AppUserService; +import cn.wujiangbo.util.MyTools; +import cn.wujiangbo.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; + + @Resource + private AppUserService appUserService; + + /** + * 获取APP用户昵称 + */ + public String getAppNickName() { + Long appUserId = getAppUserId(); + if (appUserId != null) { + AppUser one = appUserService.getById(appUserId); + if (one != null) { + return one.getNickName(); + } + } + return null; + } + + /** + * 获取APP用户ID + */ + public Long getAppUserId() { + HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); + if (request != null) { + String headerToken = request.getHeader("token"); + if (MyTools.hasLength(headerToken)) { + String userInfo = redisCache.getCacheObject(SystemConstants.LOGIN_TOKEN_KEY_APP + headerToken); + AppUser user = JSONObject.parseObject(userInfo, AppUser.class); + return user.getId(); + } else { + throw new MyException("您没有权限进行此操作!"); + } + } + return null; + } + + /** + * 获取登录人的信息 + * + * @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(); + } +} diff --git a/src/main/java/cn/wujiangbo/controller/system/SysUserController.java b/src/main/java/cn/wujiangbo/controller/system/SysUserController.java new file mode 100644 index 0000000..2d6e77c --- /dev/null +++ b/src/main/java/cn/wujiangbo/controller/system/SysUserController.java @@ -0,0 +1,145 @@ +package cn.wujiangbo.controller.system; + +import cn.hutool.crypto.SecureUtil; +import cn.wujiangbo.constants.SystemConstants; +import cn.wujiangbo.controller.base.BaseController; +import cn.wujiangbo.domain.system.SysUser; +import cn.wujiangbo.query.system.SysUserQuery; +import cn.wujiangbo.result.JSONResult; +import cn.wujiangbo.result.PageList; +import cn.wujiangbo.service.system.SysUserService; +import cn.wujiangbo.util.DateUtils; +import cn.wujiangbo.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.beans.factory.annotation.Autowired; +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 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 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); + } +} diff --git a/src/main/java/cn/wujiangbo/domain/app/AppSuggestion.java b/src/main/java/cn/wujiangbo/domain/app/AppSuggestion.java new file mode 100644 index 0000000..716c85b --- /dev/null +++ b/src/main/java/cn/wujiangbo/domain/app/AppSuggestion.java @@ -0,0 +1,59 @@ +package cn.wujiangbo.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.wujiangbo.domain.base.BaseDomain; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 意见反馈表 + *

+ * + * @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; + +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/domain/app/AppUser.java b/src/main/java/cn/wujiangbo/domain/app/AppUser.java new file mode 100644 index 0000000..531e9e1 --- /dev/null +++ b/src/main/java/cn/wujiangbo/domain/app/AppUser.java @@ -0,0 +1,99 @@ +package cn.wujiangbo.domain.app; + +import java.math.BigDecimal; +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.wujiangbo.domain.base.BaseDomain; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * APP用户信息表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@ApiModel(value="app_user 表对应的实体对象", description="APP用户信息表") +public class AppUser 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 = "update_time") + private LocalDateTime updateTime; + + @ApiModelProperty(value = "登录账号") + @TableField(value = "login_name") + private String loginName; + + @ApiModelProperty(value = "登录密码") + @TableField(value = "login_pass") + private String loginPass; + + @ApiModelProperty(value = "昵称") + @TableField(value = "nick_name") + private String nickName; + + @ApiModelProperty(value = "用户头像") + @TableField(value = "user_img") + private String userImg; + + @ApiModelProperty(value = "用户性别(0:男;1:女)") + @TableField(value = "user_sex") + private Integer userSex; + + @ApiModelProperty(value = "用户手机号") + @TableField(value = "user_phone") + private String userPhone; + + @ApiModelProperty(value = "用户状态(1:正常;2:限制登录)") + @TableField(value = "user_status") + private Integer userStatus; + + @ApiModelProperty(value = "限制登录原因") + @TableField(value = "user_error") + private String userError; + + @ApiModelProperty(value = "用户个人简介") + @TableField(value = "user_brief") + private String userBrief; + + @ApiModelProperty(value = "最后一次登录时间") + @TableField(value = "last_login_time") + private LocalDateTime lastLoginTime; + + @ApiModelProperty(value = "注册时间") + @TableField(value = "register_time") + private LocalDateTime registerTime; + + @ApiModelProperty(value = "账户余额") + @TableField(value = "user_money") + private BigDecimal userMoney; + + @ApiModelProperty(value = "是否是管理员(1:是;2:否)") + @TableField(value = "admin_flag") + private Integer adminFlag; + + /*********************************************************************************** + ***********************************************************************************/ + + @ApiModelProperty(value = "新密码") + @TableField(exist = false) + private String password2; + + @ApiModelProperty(value = "短信验证码") + @TableField(exist = false) + private String smsCode; +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/domain/base/BaseDomain.java b/src/main/java/cn/wujiangbo/domain/base/BaseDomain.java new file mode 100644 index 0000000..3a99d53 --- /dev/null +++ b/src/main/java/cn/wujiangbo/domain/base/BaseDomain.java @@ -0,0 +1,22 @@ +package cn.wujiangbo.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; + +} diff --git a/src/main/java/cn/wujiangbo/domain/system/SysUser.java b/src/main/java/cn/wujiangbo/domain/system/SysUser.java new file mode 100644 index 0000000..a0b73d6 --- /dev/null +++ b/src/main/java/cn/wujiangbo/domain/system/SysUser.java @@ -0,0 +1,85 @@ +package cn.wujiangbo.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.wujiangbo.domain.base.BaseDomain; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 用户信息表 + *

+ */ +@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; + +} diff --git a/src/main/java/cn/wujiangbo/dto/AppSuggestionVO.java b/src/main/java/cn/wujiangbo/dto/AppSuggestionVO.java new file mode 100644 index 0000000..d56dc66 --- /dev/null +++ b/src/main/java/cn/wujiangbo/dto/AppSuggestionVO.java @@ -0,0 +1,25 @@ +package cn.wujiangbo.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; +} + diff --git a/src/main/java/cn/wujiangbo/dto/UserToken.java b/src/main/java/cn/wujiangbo/dto/UserToken.java new file mode 100644 index 0000000..37d0fb3 --- /dev/null +++ b/src/main/java/cn/wujiangbo/dto/UserToken.java @@ -0,0 +1,16 @@ +package cn.wujiangbo.dto; + +import lombok.Data; + +@Data +public class UserToken { + /** + * 用户ID + */ + private Long id; + + /** + * 用户真实姓名 + */ + private String nickName; +} diff --git a/src/main/java/cn/wujiangbo/exception/GlobalExceptionHandler.java b/src/main/java/cn/wujiangbo/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..c977bd6 --- /dev/null +++ b/src/main/java/cn/wujiangbo/exception/GlobalExceptionHandler.java @@ -0,0 +1,43 @@ +package cn.wujiangbo.exception; + +import cn.wujiangbo.constants.ErrorCode; +import cn.wujiangbo.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()); + } +} diff --git a/src/main/java/cn/wujiangbo/exception/MyException.java b/src/main/java/cn/wujiangbo/exception/MyException.java new file mode 100644 index 0000000..9be8538 --- /dev/null +++ b/src/main/java/cn/wujiangbo/exception/MyException.java @@ -0,0 +1,23 @@ +package cn.wujiangbo.exception; + +import cn.wujiangbo.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(); + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/interceptor/LoginInterceptor.java b/src/main/java/cn/wujiangbo/interceptor/LoginInterceptor.java new file mode 100644 index 0000000..4a87bc0 --- /dev/null +++ b/src/main/java/cn/wujiangbo/interceptor/LoginInterceptor.java @@ -0,0 +1,79 @@ +package cn.wujiangbo.interceptor; + +import cn.wujiangbo.annotation.IgnoreAuth; +import cn.wujiangbo.constants.ErrorCode; +import cn.wujiangbo.constants.SystemConstants; +import cn.wujiangbo.exception.MyException; +import cn.wujiangbo.util.MyTools; +import org.springframework.beans.factory.annotation.Autowired; +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/"); + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/interceptor/RateLimitInterceptor.java b/src/main/java/cn/wujiangbo/interceptor/RateLimitInterceptor.java new file mode 100644 index 0000000..0e0aadc --- /dev/null +++ b/src/main/java/cn/wujiangbo/interceptor/RateLimitInterceptor.java @@ -0,0 +1,90 @@ +package cn.wujiangbo.interceptor; + +import cn.wujiangbo.annotation.RateLimit; +import cn.wujiangbo.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; + +/** + *

防刷限流的拦截器

+ */ +@Component +public class RateLimitInterceptor implements HandlerInterceptor { + + @Resource + private RedisTemplate 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; + } +} diff --git a/src/main/java/cn/wujiangbo/mapper/app/AppSuggestionMapper.java b/src/main/java/cn/wujiangbo/mapper/app/AppSuggestionMapper.java new file mode 100644 index 0000000..0ae1a87 --- /dev/null +++ b/src/main/java/cn/wujiangbo/mapper/app/AppSuggestionMapper.java @@ -0,0 +1,30 @@ +package cn.wujiangbo.mapper.app; + +import cn.wujiangbo.domain.app.AppSuggestion; +import cn.wujiangbo.dto.AppSuggestionVO; +import cn.wujiangbo.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; + +/** +*

+* 意见反馈表 Mapper接口 +*

+*/ +public interface AppSuggestionMapper extends BaseMapper { + + //查询分页列表数据 + List selectMySqlPage(Page 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 selectWithUserInfo(); + +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/mapper/app/AppUserMapper.java b/src/main/java/cn/wujiangbo/mapper/app/AppUserMapper.java new file mode 100644 index 0000000..25f55e6 --- /dev/null +++ b/src/main/java/cn/wujiangbo/mapper/app/AppUserMapper.java @@ -0,0 +1,28 @@ +package cn.wujiangbo.mapper.app; + +import cn.wujiangbo.domain.app.AppUser; +import cn.wujiangbo.dto.AppSuggestionVO; +import cn.wujiangbo.query.app.AppSuggestionQuery; +import cn.wujiangbo.query.app.AppUserQuery; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +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; + +/** +*

+* APP用户信息表 Mapper接口 +*

+*/ +public interface AppUserMapper extends BaseMapper { + + //查询分页列表数据 + List selectMySqlPage(Page page, @Param("query") AppUserQuery query); + + + + +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/mapper/system/SysUserMapper.java b/src/main/java/cn/wujiangbo/mapper/system/SysUserMapper.java new file mode 100644 index 0000000..86a962d --- /dev/null +++ b/src/main/java/cn/wujiangbo/mapper/system/SysUserMapper.java @@ -0,0 +1,12 @@ +package cn.wujiangbo.mapper.system; + +import cn.wujiangbo.domain.system.SysUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +*

+* 用户信息表 Mapper接口 +*

+*/ +public interface SysUserMapper extends BaseMapper { +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/query/app/AppSuggestionQuery.java b/src/main/java/cn/wujiangbo/query/app/AppSuggestionQuery.java new file mode 100644 index 0000000..b294257 --- /dev/null +++ b/src/main/java/cn/wujiangbo/query/app/AppSuggestionQuery.java @@ -0,0 +1,9 @@ +package cn.wujiangbo.query.app; + +import cn.wujiangbo.query.base.BaseQuery; + +/** + * 意见反馈表-查询对象 + */ +public class AppSuggestionQuery extends BaseQuery{ +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/query/app/AppSwiperQuery.java b/src/main/java/cn/wujiangbo/query/app/AppSwiperQuery.java new file mode 100644 index 0000000..777ba36 --- /dev/null +++ b/src/main/java/cn/wujiangbo/query/app/AppSwiperQuery.java @@ -0,0 +1,15 @@ +package cn.wujiangbo.query.app; + +import cn.wujiangbo.query.base.BaseQuery; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 轮播图表-查询对象 + */ +@Data +public class AppSwiperQuery extends BaseQuery{ + + @ApiModelProperty(value = "轮播图业务类型") + private String busType; +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/query/app/AppUserQuery.java b/src/main/java/cn/wujiangbo/query/app/AppUserQuery.java new file mode 100644 index 0000000..232ec24 --- /dev/null +++ b/src/main/java/cn/wujiangbo/query/app/AppUserQuery.java @@ -0,0 +1,9 @@ +package cn.wujiangbo.query.app; + +import cn.wujiangbo.query.base.BaseQuery; + +/** + * APP用户信息表-查询对象 + */ +public class AppUserQuery extends BaseQuery{ +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/query/base/BaseQuery.java b/src/main/java/cn/wujiangbo/query/base/BaseQuery.java new file mode 100644 index 0000000..3beef2d --- /dev/null +++ b/src/main/java/cn/wujiangbo/query/base/BaseQuery.java @@ -0,0 +1,17 @@ +package cn.wujiangbo.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; //每页显示多少条 +} diff --git a/src/main/java/cn/wujiangbo/query/system/SysUserQuery.java b/src/main/java/cn/wujiangbo/query/system/SysUserQuery.java new file mode 100644 index 0000000..38f029e --- /dev/null +++ b/src/main/java/cn/wujiangbo/query/system/SysUserQuery.java @@ -0,0 +1,9 @@ +package cn.wujiangbo.query.system; + +import cn.wujiangbo.query.base.BaseQuery; + +/** + * @desc 用户信息表-查询对象 + */ +public class SysUserQuery extends BaseQuery{ +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/result/JSONResult.java b/src/main/java/cn/wujiangbo/result/JSONResult.java new file mode 100644 index 0000000..d0175d7 --- /dev/null +++ b/src/main/java/cn/wujiangbo/result/JSONResult.java @@ -0,0 +1,124 @@ +package cn.wujiangbo.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; + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/result/PageList.java b/src/main/java/cn/wujiangbo/result/PageList.java new file mode 100644 index 0000000..aac26b8 --- /dev/null +++ b/src/main/java/cn/wujiangbo/result/PageList.java @@ -0,0 +1,33 @@ +package cn.wujiangbo.result; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 分页对象 + */ +@Data +public class PageList { + + private long total; + private List rows = new ArrayList<>(); + + @Override + public String toString() { + return "PageList{" + + "total=" + total + + ", rows=" + rows + + '}'; + } + + //提供有参构造方法,方便测试 + public PageList(long total, List rows) { + this.total = total; + this.rows = rows; + } + //除了有参构造方法,还需要提供一个无参构造方法 + public PageList() { + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/service/app/AppSuggestionService.java b/src/main/java/cn/wujiangbo/service/app/AppSuggestionService.java new file mode 100644 index 0000000..c82c89c --- /dev/null +++ b/src/main/java/cn/wujiangbo/service/app/AppSuggestionService.java @@ -0,0 +1,55 @@ +package cn.wujiangbo.service.app; + +import cn.wujiangbo.domain.app.AppSuggestion; +import cn.wujiangbo.dto.AppSuggestionVO; +import cn.wujiangbo.mapper.app.AppSuggestionMapper; +import cn.wujiangbo.query.app.AppSuggestionQuery; +import cn.wujiangbo.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; + +/** + *

+ * 意见反馈表 服务实现类 + *

+ */ +@Transactional +@Service +@Slf4j +public class AppSuggestionService extends ServiceImpl{ + + @Resource + private AppSuggestionMapper appsuggestionMapper; + + //查询分页列表数据(使用QueryWrapper操作) + public Page selectMyPage(AppSuggestionQuery query) { + QueryWrapper wrapper = new QueryWrapper<>(); + if (MyTools.hasLength(query.getKeyword())) { + wrapper.and(i -> i.like("id", query.getKeyword())); + } + //排序 + wrapper.orderByDesc("id"); + Page page = new Page<>(query.getCurrent(), query.getSize()); + return super.page(page, wrapper); + } + + //查询分页列表数据(自己写SQL) + public Page selectMySqlPage(AppSuggestionQuery query) { + Page page = new Page<>(query.getCurrent(), query.getSize()); + List list = appsuggestionMapper.selectMySqlPage(page, query); + return page.setRecords(list); + } + + + public List selectWithUserInfo(){ + return appsuggestionMapper.selectWithUserInfo(); + } + + +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/service/app/AppUserService.java b/src/main/java/cn/wujiangbo/service/app/AppUserService.java new file mode 100644 index 0000000..ab6187d --- /dev/null +++ b/src/main/java/cn/wujiangbo/service/app/AppUserService.java @@ -0,0 +1,48 @@ +package cn.wujiangbo.service.app; + +import cn.wujiangbo.domain.app.AppUser; +import cn.wujiangbo.mapper.app.AppUserMapper; +import cn.wujiangbo.query.app.AppUserQuery; +import cn.wujiangbo.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; + +/** + *

+ * APP用户信息表 服务实现类 + *

+ */ +@Transactional +@Service +@Slf4j +public class AppUserService extends ServiceImpl{ + + @Resource + private AppUserMapper appuserMapper; + + //查询分页列表数据(使用QueryWrapper操作) + public Page selectMyPage(AppUserQuery query) { + QueryWrapper wrapper = new QueryWrapper<>(); + if (MyTools.hasLength(query.getKeyword())) { + wrapper.and(i -> i.like("id", query.getKeyword())); + } + //排序 + wrapper.orderByDesc("id"); + Page page = new Page<>(query.getCurrent(), query.getSize()); + return super.page(page, wrapper); + } + + //查询分页列表数据(自己写SQL) + public Page selectMySqlPage(AppUserQuery query) { + Page page = new Page<>(query.getCurrent(), query.getSize()); + List list = appuserMapper.selectMySqlPage(page, query); + return page.setRecords(list); + } + +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/service/system/FileService.java b/src/main/java/cn/wujiangbo/service/system/FileService.java new file mode 100644 index 0000000..3ecd60b --- /dev/null +++ b/src/main/java/cn/wujiangbo/service/system/FileService.java @@ -0,0 +1,17 @@ +package cn.wujiangbo.service.system; + +import cn.wujiangbo.vo.UploadFileVo; +import org.springframework.web.multipart.MultipartFile; + +/** + *

文件上传接口

+ */ +public interface FileService { + + /** + * 单个文件上传方法 + * @param multipartFile 文件 + * @param folderName 保存文件夹名称 + */ + UploadFileVo uploadFile(MultipartFile multipartFile, String folderName); +} diff --git a/src/main/java/cn/wujiangbo/service/system/SysUserService.java b/src/main/java/cn/wujiangbo/service/system/SysUserService.java new file mode 100644 index 0000000..33bfbb8 --- /dev/null +++ b/src/main/java/cn/wujiangbo/service/system/SysUserService.java @@ -0,0 +1,68 @@ +package cn.wujiangbo.service.system; + +import cn.wujiangbo.constants.ErrorCode; +import cn.wujiangbo.constants.SystemConstants; +import cn.wujiangbo.domain.system.SysUser; +import cn.wujiangbo.exception.MyException; +import cn.wujiangbo.mapper.system.SysUserMapper; +import cn.wujiangbo.query.system.SysUserQuery; +import cn.wujiangbo.result.JSONResult; +import cn.wujiangbo.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.beans.factory.annotation.Autowired; +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; + +/** + *

+ * 用户信息表 服务实现类 + *

+ */ +@Service +@Slf4j +@Transactional +public class SysUserService extends ServiceImpl { + + @Resource + private RedisTemplate redisTemplate; + + //查询分页列表数据 + public IPage selectMyPage(SysUserQuery query) { + QueryWrapper wrapper = new QueryWrapper<>(); + if (MyTools.hasLength(query.getKeyword())) { + wrapper.and(i -> i.like("user_name", query.getKeyword())); + } + //排序 + wrapper.orderByDesc("create_time").orderByDesc("id"); + IPage 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 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()); + } + } +} diff --git a/src/main/java/cn/wujiangbo/service/system/impl/FileServiceLocalImpl.java b/src/main/java/cn/wujiangbo/service/system/impl/FileServiceLocalImpl.java new file mode 100644 index 0000000..6b0b3f5 --- /dev/null +++ b/src/main/java/cn/wujiangbo/service/system/impl/FileServiceLocalImpl.java @@ -0,0 +1,58 @@ +package cn.wujiangbo.service.system.impl; + +import cn.wujiangbo.exception.MyException; +import cn.wujiangbo.service.system.FileService; +import cn.wujiangbo.util.DateUtils; +import cn.wujiangbo.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; + +/** + *

文件上传-保存到服务器本地磁盘

+ */ +@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; + } +} diff --git a/src/main/java/cn/wujiangbo/service/system/impl/FileServiceOssImpl.java b/src/main/java/cn/wujiangbo/service/system/impl/FileServiceOssImpl.java new file mode 100644 index 0000000..a6b95b3 --- /dev/null +++ b/src/main/java/cn/wujiangbo/service/system/impl/FileServiceOssImpl.java @@ -0,0 +1,127 @@ +//package cn.wujiangbo.service.system.impl; +// +//import cn.wujiangbo.dto.OssDto; +//import cn.wujiangbo.exception.MyException; +//import cn.wujiangbo.service.system.FileService; +//import cn.wujiangbo.util.DateUtils; +//import cn.wujiangbo.util.MyTools; +//import cn.wujiangbo.vo.UploadFileVo; +//import com.aliyun.oss.OSS; +//import com.aliyun.oss.OSSClientBuilder; +//import com.aliyun.oss.model.PutObjectRequest; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.stereotype.Service; +//import org.springframework.web.multipart.MultipartFile; +//import javax.annotation.Resource; +// +///** +// *

文件上传实现类

+// */ +//@Service +//@Slf4j +//public class FileServiceOssImpl implements FileService { +// +// @Resource +// private OssDto ossDto; +// +// /** +// * 文件存储方案(1:文件本地;2:存阿里云OSS) +// */ +// @Value("${file.filescheme}") +// private String filescheme; +// +// @Value("${server.port}") +// private String port; +// +// @Value("${file.download.ip}") +// private String downloadIp; +// +// /** +// * 上传文件 +// * @param multipartFile 文件 +// * @param folderName 保存文件的路径 +// * @return UploadFileVo +// */ +// @Override +// public UploadFileVo uploadFile(MultipartFile multipartFile, String folderName) { +// System.out.println("上传文件存储方案:" + ("1".equals(filescheme) ? "本地" : "OSS")); +// if ("1".equals(filescheme)) { +// /** +// * 注意,如果是存本地的话,files下面必须直接存文件,不能有其他层级了,否则下载时无法下载或预览图片了 +// */ +// //上传文件存本地方案 +// if (multipartFile.isEmpty()) { +// throw new MyException("上传文件不能为空!"); +// } +// //获取文件名 +// String fileName = extractFilename(multipartFile); +// // 封装完整的文件路径获取方法 +// String fileUploadPath = MyTools.getFileUploadPath(fileName); +// System.out.println("上传文件磁盘保存路径=" + fileUploadPath); +// try { +// java.io.File uploadFile = new java.io.File(fileUploadPath); +// java.io.File parentFile = uploadFile.getParentFile(); +// if (!parentFile.exists()) { // 如果父级不存在,也就是说files目录不存在,那么我要创建出来 +// parentFile.mkdirs(); +// } +// multipartFile.transferTo(uploadFile); +// } catch (Exception e) { +// log.error("文件上传失败", e); +// throw new MyException("上传文件失败!"); +// } +// String filePath = "http://" + downloadIp + ":" + port + "/file/download/" + fileName; +// System.out.println("上传文件完整访问路径=" + filePath); +// UploadFileVo vo = new UploadFileVo(); +// vo.setFileName(fileName); +// vo.setFilePrefix("http://" + downloadIp + ":" + port + "/file/download/"); +// vo.setFileFullPath(filePath); +// vo.setFileSize(multipartFile.getSize()); +// return vo; +// } else { +// //上传文件存OSS方案 +// if (ossDto.getEnable()) { +// if (multipartFile.isEmpty()) { +// throw new MyException("上传文件不能为空!"); +// } +// //获取文件名 +// String fileName = extractFilename(multipartFile); +// //所有文件存储必需带上年月信息 +// fileName = DateUtils.getCurrentYearMonth() + "/" + folderName + "/" + fileName; +// OSS build = new OSSClientBuilder().build(ossDto.getEndpoint(), ossDto.getAccessKey(), ossDto.getSecretKey()); +// try { +// PutObjectRequest putObjectRequest = new PutObjectRequest(ossDto.getBucketName(), fileName, multipartFile.getInputStream()); +// //将文件推到OSS服务器 +// build.putObject(putObjectRequest); +// String imagePath = "https://" + ossDto.getBucketName() + "." + ossDto.getEndpoint() + "/" + fileName; +// UploadFileVo vo = new UploadFileVo(); +// vo.setFileName(fileName); +// vo.setFilePrefix("https://" + ossDto.getBucketName() + "." + ossDto.getEndpoint() + "/"); +// vo.setFileFullPath(imagePath); +// vo.setFileSize(multipartFile.getSize()); +// return vo; +// } catch (Exception e) { +// e.printStackTrace(); +// log.error("上传文件到阿里OSS服务器发生异常:{}", e.getMessage()); +// throw new MyException("文件上传至OSS异常!"); +// } finally { +// //关闭OSSClient +// build.shutdown(); +// } +// } +// } +// return null; +// } +// +// /** +// * 编码文件名,源文件名_当前时间戳 +// * 如:用户上传的文件名是dog.png,那么此方法返回值为:dog_20231212112323.png +// */ +// public static final String extractFilename(MultipartFile file) { +// String fileName = file.getOriginalFilename(); +// fileName = fileName.substring(0, fileName.lastIndexOf(".")) + "_" + DateUtils.getCurrentDateString(DateUtils.YYYYMMDDHHMMSS) + "." + fileName.substring(fileName.lastIndexOf(".") + 1); +// return fileName; +// } +// +// +//} diff --git a/src/main/java/cn/wujiangbo/util/DateUtils.java b/src/main/java/cn/wujiangbo/util/DateUtils.java new file mode 100644 index 0000000..a3e24d9 --- /dev/null +++ b/src/main/java/cn/wujiangbo/util/DateUtils.java @@ -0,0 +1,197 @@ +package cn.wujiangbo.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 + "分钟"; + } +} diff --git a/src/main/java/cn/wujiangbo/util/IdUtils.java b/src/main/java/cn/wujiangbo/util/IdUtils.java new file mode 100644 index 0000000..5157d97 --- /dev/null +++ b/src/main/java/cn/wujiangbo/util/IdUtils.java @@ -0,0 +1,57 @@ +package cn.wujiangbo.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); + } +} diff --git a/src/main/java/cn/wujiangbo/util/MyTools.java b/src/main/java/cn/wujiangbo/util/MyTools.java new file mode 100644 index 0000000..172bfec --- /dev/null +++ b/src/main/java/cn/wujiangbo/util/MyTools.java @@ -0,0 +1,199 @@ +package cn.wujiangbo.util; + +import cn.hutool.core.codec.Base64Encoder; +import cn.hutool.crypto.SecureUtil; +import cn.wujiangbo.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(); + } +} diff --git a/src/main/java/cn/wujiangbo/util/RedisCache.java b/src/main/java/cn/wujiangbo/util/RedisCache.java new file mode 100644 index 0000000..2af0ae6 --- /dev/null +++ b/src/main/java/cn/wujiangbo/util/RedisCache.java @@ -0,0 +1,251 @@ +package cn.wujiangbo.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 keys = redisTemplate.keys("*"); + redisTemplate.delete(keys); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject(final String key, final T value) + { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public 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 getCacheObject(final String key) + { + ValueOperations 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 long setCacheList(final String key, final List dataList) + { + Long count = redisTemplate.opsForList().rightPushAll(key, dataList); + return count == null ? 0 : count; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public List getCacheList(final String key) + { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public BoundSetOperations setCacheSet(final String key, final Set dataSet) + { + BoundSetOperations setOperation = redisTemplate.boundSetOps(key); + Iterator it = dataSet.iterator(); + while (it.hasNext()) + { + setOperation.add(it.next()); + } + return setOperation; + } + + /** + * 获得缓存的set + * + * @param key + * @return + */ + public Set getCacheSet(final String key) + { + return redisTemplate.opsForSet().members(key); + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public void setCacheMap(final String key, final Map dataMap) + { + if (dataMap != null) { + redisTemplate.opsForHash().putAll(key, dataMap); + } + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheMap(final String key) + { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public 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 getCacheMapValue(final String key, final String hKey) + { + HashOperations opsForHash = redisTemplate.opsForHash(); + return opsForHash.get(key, hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public List getMultiCacheMapValue(final String key, final Collection hKeys) + { + return redisTemplate.opsForHash().multiGet(key, hKeys); + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public Collection keys(final String pattern) + { + return redisTemplate.keys(pattern); + } + + /** + * @desc 判断Redis中是否存在指定的key + */ + public boolean exists(String key) { + return redisTemplate.hasKey(key); + } +} \ No newline at end of file diff --git a/src/main/java/cn/wujiangbo/vo/LoginSuccessVo.java b/src/main/java/cn/wujiangbo/vo/LoginSuccessVo.java new file mode 100644 index 0000000..f310cc6 --- /dev/null +++ b/src/main/java/cn/wujiangbo/vo/LoginSuccessVo.java @@ -0,0 +1,16 @@ +package cn.wujiangbo.vo; + +import cn.wujiangbo.domain.app.AppUser; +import lombok.Data; + +/** + *

登录成功后,返回前端的对象

+ */ +@Data +public class LoginSuccessVo { + private String token;//token + private String refToken;//刷新token + private Long userId;//用户ID + private Integer roleId; + private AppUser appUser;//APP用户信息 +} diff --git a/src/main/java/cn/wujiangbo/vo/UploadFileVo.java b/src/main/java/cn/wujiangbo/vo/UploadFileVo.java new file mode 100644 index 0000000..3aa1522 --- /dev/null +++ b/src/main/java/cn/wujiangbo/vo/UploadFileVo.java @@ -0,0 +1,15 @@ +package cn.wujiangbo.vo; + +import lombok.Data; + +/** + *

文件上传成功后返回前端参数

+ */ +@Data +public class UploadFileVo { + + private String fileFullPath;//文件全路径 + private String fileName;//文件名称 + private String filePrefix;//文件存储路径的前缀 + private Long fileSize;//文件大小 +} diff --git a/src/main/java/cn/wujiangbo/vo/UserTokenVo.java b/src/main/java/cn/wujiangbo/vo/UserTokenVo.java new file mode 100644 index 0000000..4ffb9f8 --- /dev/null +++ b/src/main/java/cn/wujiangbo/vo/UserTokenVo.java @@ -0,0 +1,15 @@ +package cn.wujiangbo.vo; + +import lombok.Data; + +/** + * @desc 登录成功之后,返回前端的对象 + */ +@Data +public class UserTokenVo { + + private String token; + private String userName; + private String realName; + private String avatar; +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..ab30a8d --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,70 @@ +server: + #启动端口 + port: 8002 + tomcat: + #设置字符编码 + uri-encoding: UTF-8 +spring: + application: + #系统服务名 + name: EasyJavaTemplate + #MySQL数据库相关配置信息 + datasource: + url: jdbc:mysql://10.232.112.35:3306/rensijin-cchs?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root #数据库账号 + password: -w9M627JZeYo5p^3lbH0mqDa #数据库密码 + driver-class-name: com.mysql.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + #Redis 缓存相关参数配置 + redis: + host: 10.232.12.111 + 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 #上传端点 \ No newline at end of file diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/cn/wujiangbo/mapper/app/AppSuggestionMapper.xml b/src/main/resources/cn/wujiangbo/mapper/app/AppSuggestionMapper.xml new file mode 100644 index 0000000..58be687 --- /dev/null +++ b/src/main/resources/cn/wujiangbo/mapper/app/AppSuggestionMapper.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/cn/wujiangbo/mapper/app/AppUserMapper.xml b/src/main/resources/cn/wujiangbo/mapper/app/AppUserMapper.xml new file mode 100644 index 0000000..74109aa --- /dev/null +++ b/src/main/resources/cn/wujiangbo/mapper/app/AppUserMapper.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/cn/wujiangbo/mapper/system/SysUserMapper.xml b/src/main/resources/cn/wujiangbo/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000..109580b --- /dev/null +++ b/src/main/resources/cn/wujiangbo/mapper/system/SysUserMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..96d8332 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ${FORMAT} + + + + + + + + + + + + ERROR + + ACCEPT + + DENY + + + + + + ${log_dir}/error/%d{yyyy-MM-dd}/error-%i.log + + + ${maxHistory} + + + ${maxFileSize} + + + + + + ${FORMAT} + + + + + + + + + + + WARN + + ACCEPT + + DENY + + + ${log_dir}/warn/%d{yyyy-MM-dd}/warn-%i.log + ${maxHistory} + + + ${maxFileSize} + + + + ${FORMAT} + + + + + + + INFO + ACCEPT + DENY + + + ${log_dir}/info/%d{yyyy-MM-dd}/info-%i.log + ${maxHistory} + + + ${maxFileSize} + + + + ${FORMAT} + + + + + + + DEBUG + ACCEPT + DENY + + + ${log_dir}/debug/%d{yyyy-MM-dd}/debug-%i.log + ${maxHistory} + + + ${maxFileSize} + + + + ${FORMAT} + + + + + + + + + + + + + + + + + diff --git a/target/classes/application.yml b/target/classes/application.yml new file mode 100644 index 0000000..ab30a8d --- /dev/null +++ b/target/classes/application.yml @@ -0,0 +1,70 @@ +server: + #启动端口 + port: 8002 + tomcat: + #设置字符编码 + uri-encoding: UTF-8 +spring: + application: + #系统服务名 + name: EasyJavaTemplate + #MySQL数据库相关配置信息 + datasource: + url: jdbc:mysql://10.232.112.35:3306/rensijin-cchs?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root #数据库账号 + password: -w9M627JZeYo5p^3lbH0mqDa #数据库密码 + driver-class-name: com.mysql.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + #Redis 缓存相关参数配置 + redis: + host: 10.232.12.111 + 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 #上传端点 \ No newline at end of file diff --git a/target/classes/banner.txt b/target/classes/banner.txt new file mode 100644 index 0000000..e69de29 diff --git a/target/classes/cn/wujiangbo/App.class b/target/classes/cn/wujiangbo/App.class new file mode 100644 index 0000000..f4e2054 Binary files /dev/null and b/target/classes/cn/wujiangbo/App.class differ diff --git a/target/classes/cn/wujiangbo/annotation/IgnoreAuth.class b/target/classes/cn/wujiangbo/annotation/IgnoreAuth.class new file mode 100644 index 0000000..d3b035e Binary files /dev/null and b/target/classes/cn/wujiangbo/annotation/IgnoreAuth.class differ diff --git a/target/classes/cn/wujiangbo/annotation/RateLimit.class b/target/classes/cn/wujiangbo/annotation/RateLimit.class new file mode 100644 index 0000000..2379b71 Binary files /dev/null and b/target/classes/cn/wujiangbo/annotation/RateLimit.class differ diff --git a/target/classes/cn/wujiangbo/config/cors/CorsFilterConfig.class b/target/classes/cn/wujiangbo/config/cors/CorsFilterConfig.class new file mode 100644 index 0000000..3cb5e96 Binary files /dev/null and b/target/classes/cn/wujiangbo/config/cors/CorsFilterConfig.class differ diff --git a/target/classes/cn/wujiangbo/config/date/DateConfig$1.class b/target/classes/cn/wujiangbo/config/date/DateConfig$1.class new file mode 100644 index 0000000..9886b8c Binary files /dev/null and b/target/classes/cn/wujiangbo/config/date/DateConfig$1.class differ diff --git a/target/classes/cn/wujiangbo/config/date/DateConfig$2.class b/target/classes/cn/wujiangbo/config/date/DateConfig$2.class new file mode 100644 index 0000000..c12bf7e Binary files /dev/null and b/target/classes/cn/wujiangbo/config/date/DateConfig$2.class differ diff --git a/target/classes/cn/wujiangbo/config/date/DateConfig.class b/target/classes/cn/wujiangbo/config/date/DateConfig.class new file mode 100644 index 0000000..3f85d9b Binary files /dev/null and b/target/classes/cn/wujiangbo/config/date/DateConfig.class differ diff --git a/target/classes/cn/wujiangbo/config/date/JacksonObjectMapper.class b/target/classes/cn/wujiangbo/config/date/JacksonObjectMapper.class new file mode 100644 index 0000000..7720140 Binary files /dev/null and b/target/classes/cn/wujiangbo/config/date/JacksonObjectMapper.class differ diff --git a/target/classes/cn/wujiangbo/config/mp/MyBatiesPlusConfiguration.class b/target/classes/cn/wujiangbo/config/mp/MyBatiesPlusConfiguration.class new file mode 100644 index 0000000..9812feb Binary files /dev/null and b/target/classes/cn/wujiangbo/config/mp/MyBatiesPlusConfiguration.class differ diff --git a/target/classes/cn/wujiangbo/config/redis/RedisConfig.class b/target/classes/cn/wujiangbo/config/redis/RedisConfig.class new file mode 100644 index 0000000..93e763b Binary files /dev/null and b/target/classes/cn/wujiangbo/config/redis/RedisConfig.class differ diff --git a/target/classes/cn/wujiangbo/config/swagger/Swagger2.class b/target/classes/cn/wujiangbo/config/swagger/Swagger2.class new file mode 100644 index 0000000..cc05855 Binary files /dev/null and b/target/classes/cn/wujiangbo/config/swagger/Swagger2.class differ diff --git a/target/classes/cn/wujiangbo/config/web/WebConfig.class b/target/classes/cn/wujiangbo/config/web/WebConfig.class new file mode 100644 index 0000000..70a661e Binary files /dev/null and b/target/classes/cn/wujiangbo/config/web/WebConfig.class differ diff --git a/target/classes/cn/wujiangbo/constants/ErrorCode.class b/target/classes/cn/wujiangbo/constants/ErrorCode.class new file mode 100644 index 0000000..4e6345b Binary files /dev/null and b/target/classes/cn/wujiangbo/constants/ErrorCode.class differ diff --git a/target/classes/cn/wujiangbo/constants/SystemConstants.class b/target/classes/cn/wujiangbo/constants/SystemConstants.class new file mode 100644 index 0000000..3eed7d0 Binary files /dev/null and b/target/classes/cn/wujiangbo/constants/SystemConstants.class differ diff --git a/target/classes/cn/wujiangbo/controller/LoginController.class b/target/classes/cn/wujiangbo/controller/LoginController.class new file mode 100644 index 0000000..e4873b7 Binary files /dev/null and b/target/classes/cn/wujiangbo/controller/LoginController.class differ diff --git a/target/classes/cn/wujiangbo/controller/RegisterController.class b/target/classes/cn/wujiangbo/controller/RegisterController.class new file mode 100644 index 0000000..71ef5fa Binary files /dev/null and b/target/classes/cn/wujiangbo/controller/RegisterController.class differ diff --git a/target/classes/cn/wujiangbo/controller/TestController.class b/target/classes/cn/wujiangbo/controller/TestController.class new file mode 100644 index 0000000..0692fb8 Binary files /dev/null and b/target/classes/cn/wujiangbo/controller/TestController.class differ diff --git a/target/classes/cn/wujiangbo/controller/app/AppSuggestionController.class b/target/classes/cn/wujiangbo/controller/app/AppSuggestionController.class new file mode 100644 index 0000000..a18da6a Binary files /dev/null and b/target/classes/cn/wujiangbo/controller/app/AppSuggestionController.class differ diff --git a/target/classes/cn/wujiangbo/controller/base/BaseController.class b/target/classes/cn/wujiangbo/controller/base/BaseController.class new file mode 100644 index 0000000..950aded Binary files /dev/null and b/target/classes/cn/wujiangbo/controller/base/BaseController.class differ diff --git a/target/classes/cn/wujiangbo/controller/system/SysUserController.class b/target/classes/cn/wujiangbo/controller/system/SysUserController.class new file mode 100644 index 0000000..de49700 Binary files /dev/null and b/target/classes/cn/wujiangbo/controller/system/SysUserController.class differ diff --git a/target/classes/cn/wujiangbo/domain/app/AppSuggestion.class b/target/classes/cn/wujiangbo/domain/app/AppSuggestion.class new file mode 100644 index 0000000..65e4b01 Binary files /dev/null and b/target/classes/cn/wujiangbo/domain/app/AppSuggestion.class differ diff --git a/target/classes/cn/wujiangbo/domain/app/AppSwiper.class b/target/classes/cn/wujiangbo/domain/app/AppSwiper.class new file mode 100644 index 0000000..84d51bd Binary files /dev/null and b/target/classes/cn/wujiangbo/domain/app/AppSwiper.class differ diff --git a/target/classes/cn/wujiangbo/domain/app/AppUser.class b/target/classes/cn/wujiangbo/domain/app/AppUser.class new file mode 100644 index 0000000..faaae4c Binary files /dev/null and b/target/classes/cn/wujiangbo/domain/app/AppUser.class differ diff --git a/target/classes/cn/wujiangbo/domain/base/BaseDomain.class b/target/classes/cn/wujiangbo/domain/base/BaseDomain.class new file mode 100644 index 0000000..8ce5871 Binary files /dev/null and b/target/classes/cn/wujiangbo/domain/base/BaseDomain.class differ diff --git a/target/classes/cn/wujiangbo/domain/system/SysUser.class b/target/classes/cn/wujiangbo/domain/system/SysUser.class new file mode 100644 index 0000000..9a0997f Binary files /dev/null and b/target/classes/cn/wujiangbo/domain/system/SysUser.class differ diff --git a/target/classes/cn/wujiangbo/dto/AppSuggestionVO.class b/target/classes/cn/wujiangbo/dto/AppSuggestionVO.class new file mode 100644 index 0000000..18fbafe Binary files /dev/null and b/target/classes/cn/wujiangbo/dto/AppSuggestionVO.class differ diff --git a/target/classes/cn/wujiangbo/dto/UserToken.class b/target/classes/cn/wujiangbo/dto/UserToken.class new file mode 100644 index 0000000..a4c0fc1 Binary files /dev/null and b/target/classes/cn/wujiangbo/dto/UserToken.class differ diff --git a/target/classes/cn/wujiangbo/exception/GlobalExceptionHandler.class b/target/classes/cn/wujiangbo/exception/GlobalExceptionHandler.class new file mode 100644 index 0000000..8195665 Binary files /dev/null and b/target/classes/cn/wujiangbo/exception/GlobalExceptionHandler.class differ diff --git a/target/classes/cn/wujiangbo/exception/MyException.class b/target/classes/cn/wujiangbo/exception/MyException.class new file mode 100644 index 0000000..8671829 Binary files /dev/null and b/target/classes/cn/wujiangbo/exception/MyException.class differ diff --git a/target/classes/cn/wujiangbo/interceptor/LoginInterceptor.class b/target/classes/cn/wujiangbo/interceptor/LoginInterceptor.class new file mode 100644 index 0000000..00e36c1 Binary files /dev/null and b/target/classes/cn/wujiangbo/interceptor/LoginInterceptor.class differ diff --git a/target/classes/cn/wujiangbo/interceptor/RateLimitInterceptor.class b/target/classes/cn/wujiangbo/interceptor/RateLimitInterceptor.class new file mode 100644 index 0000000..bafd9de Binary files /dev/null and b/target/classes/cn/wujiangbo/interceptor/RateLimitInterceptor.class differ diff --git a/target/classes/cn/wujiangbo/mapper/app/AppSuggestionMapper.class b/target/classes/cn/wujiangbo/mapper/app/AppSuggestionMapper.class new file mode 100644 index 0000000..f12b998 Binary files /dev/null and b/target/classes/cn/wujiangbo/mapper/app/AppSuggestionMapper.class differ diff --git a/target/classes/cn/wujiangbo/mapper/app/AppSuggestionMapper.xml b/target/classes/cn/wujiangbo/mapper/app/AppSuggestionMapper.xml new file mode 100644 index 0000000..58be687 --- /dev/null +++ b/target/classes/cn/wujiangbo/mapper/app/AppSuggestionMapper.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/target/classes/cn/wujiangbo/mapper/app/AppSwiperMapper.class b/target/classes/cn/wujiangbo/mapper/app/AppSwiperMapper.class new file mode 100644 index 0000000..13f03df Binary files /dev/null and b/target/classes/cn/wujiangbo/mapper/app/AppSwiperMapper.class differ diff --git a/target/classes/cn/wujiangbo/mapper/app/AppSwiperMapper.xml b/target/classes/cn/wujiangbo/mapper/app/AppSwiperMapper.xml new file mode 100644 index 0000000..a7e2ddd --- /dev/null +++ b/target/classes/cn/wujiangbo/mapper/app/AppSwiperMapper.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/target/classes/cn/wujiangbo/mapper/app/AppUserMapper.class b/target/classes/cn/wujiangbo/mapper/app/AppUserMapper.class new file mode 100644 index 0000000..2f1be61 Binary files /dev/null and b/target/classes/cn/wujiangbo/mapper/app/AppUserMapper.class differ diff --git a/target/classes/cn/wujiangbo/mapper/app/AppUserMapper.xml b/target/classes/cn/wujiangbo/mapper/app/AppUserMapper.xml new file mode 100644 index 0000000..74109aa --- /dev/null +++ b/target/classes/cn/wujiangbo/mapper/app/AppUserMapper.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/target/classes/cn/wujiangbo/mapper/system/SysUserMapper.class b/target/classes/cn/wujiangbo/mapper/system/SysUserMapper.class new file mode 100644 index 0000000..def8c4a Binary files /dev/null and b/target/classes/cn/wujiangbo/mapper/system/SysUserMapper.class differ diff --git a/target/classes/cn/wujiangbo/mapper/system/SysUserMapper.xml b/target/classes/cn/wujiangbo/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000..109580b --- /dev/null +++ b/target/classes/cn/wujiangbo/mapper/system/SysUserMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/target/classes/cn/wujiangbo/query/app/AppSuggestionQuery.class b/target/classes/cn/wujiangbo/query/app/AppSuggestionQuery.class new file mode 100644 index 0000000..d479236 Binary files /dev/null and b/target/classes/cn/wujiangbo/query/app/AppSuggestionQuery.class differ diff --git a/target/classes/cn/wujiangbo/query/app/AppSwiperQuery.class b/target/classes/cn/wujiangbo/query/app/AppSwiperQuery.class new file mode 100644 index 0000000..c8223b0 Binary files /dev/null and b/target/classes/cn/wujiangbo/query/app/AppSwiperQuery.class differ diff --git a/target/classes/cn/wujiangbo/query/app/AppUserQuery.class b/target/classes/cn/wujiangbo/query/app/AppUserQuery.class new file mode 100644 index 0000000..f812ca6 Binary files /dev/null and b/target/classes/cn/wujiangbo/query/app/AppUserQuery.class differ diff --git a/target/classes/cn/wujiangbo/query/base/BaseQuery.class b/target/classes/cn/wujiangbo/query/base/BaseQuery.class new file mode 100644 index 0000000..bf9e031 Binary files /dev/null and b/target/classes/cn/wujiangbo/query/base/BaseQuery.class differ diff --git a/target/classes/cn/wujiangbo/query/system/SysUserQuery.class b/target/classes/cn/wujiangbo/query/system/SysUserQuery.class new file mode 100644 index 0000000..990b8b3 Binary files /dev/null and b/target/classes/cn/wujiangbo/query/system/SysUserQuery.class differ diff --git a/target/classes/cn/wujiangbo/result/JSONResult.class b/target/classes/cn/wujiangbo/result/JSONResult.class new file mode 100644 index 0000000..5d82ef7 Binary files /dev/null and b/target/classes/cn/wujiangbo/result/JSONResult.class differ diff --git a/target/classes/cn/wujiangbo/result/PageList.class b/target/classes/cn/wujiangbo/result/PageList.class new file mode 100644 index 0000000..7a6445d Binary files /dev/null and b/target/classes/cn/wujiangbo/result/PageList.class differ diff --git a/target/classes/cn/wujiangbo/service/app/AppSuggestionService.class b/target/classes/cn/wujiangbo/service/app/AppSuggestionService.class new file mode 100644 index 0000000..7d24525 Binary files /dev/null and b/target/classes/cn/wujiangbo/service/app/AppSuggestionService.class differ diff --git a/target/classes/cn/wujiangbo/service/app/AppUserService.class b/target/classes/cn/wujiangbo/service/app/AppUserService.class new file mode 100644 index 0000000..57392ba Binary files /dev/null and b/target/classes/cn/wujiangbo/service/app/AppUserService.class differ diff --git a/target/classes/cn/wujiangbo/service/system/FileService.class b/target/classes/cn/wujiangbo/service/system/FileService.class new file mode 100644 index 0000000..51eed13 Binary files /dev/null and b/target/classes/cn/wujiangbo/service/system/FileService.class differ diff --git a/target/classes/cn/wujiangbo/service/system/SysUserService.class b/target/classes/cn/wujiangbo/service/system/SysUserService.class new file mode 100644 index 0000000..b76aeb9 Binary files /dev/null and b/target/classes/cn/wujiangbo/service/system/SysUserService.class differ diff --git a/target/classes/cn/wujiangbo/service/system/impl/FileServiceLocalImpl.class b/target/classes/cn/wujiangbo/service/system/impl/FileServiceLocalImpl.class new file mode 100644 index 0000000..8a1d35b Binary files /dev/null and b/target/classes/cn/wujiangbo/service/system/impl/FileServiceLocalImpl.class differ diff --git a/target/classes/cn/wujiangbo/util/DateUtils.class b/target/classes/cn/wujiangbo/util/DateUtils.class new file mode 100644 index 0000000..8362b0a Binary files /dev/null and b/target/classes/cn/wujiangbo/util/DateUtils.class differ diff --git a/target/classes/cn/wujiangbo/util/IdUtils.class b/target/classes/cn/wujiangbo/util/IdUtils.class new file mode 100644 index 0000000..23419e6 Binary files /dev/null and b/target/classes/cn/wujiangbo/util/IdUtils.class differ diff --git a/target/classes/cn/wujiangbo/util/MyTools.class b/target/classes/cn/wujiangbo/util/MyTools.class new file mode 100644 index 0000000..483bac9 Binary files /dev/null and b/target/classes/cn/wujiangbo/util/MyTools.class differ diff --git a/target/classes/cn/wujiangbo/util/RedisCache.class b/target/classes/cn/wujiangbo/util/RedisCache.class new file mode 100644 index 0000000..18e601a Binary files /dev/null and b/target/classes/cn/wujiangbo/util/RedisCache.class differ diff --git a/target/classes/cn/wujiangbo/vo/LoginSuccessVo.class b/target/classes/cn/wujiangbo/vo/LoginSuccessVo.class new file mode 100644 index 0000000..e6778a8 Binary files /dev/null and b/target/classes/cn/wujiangbo/vo/LoginSuccessVo.class differ diff --git a/target/classes/cn/wujiangbo/vo/UploadFileVo.class b/target/classes/cn/wujiangbo/vo/UploadFileVo.class new file mode 100644 index 0000000..e7f705f Binary files /dev/null and b/target/classes/cn/wujiangbo/vo/UploadFileVo.class differ diff --git a/target/classes/cn/wujiangbo/vo/UserTokenVo.class b/target/classes/cn/wujiangbo/vo/UserTokenVo.class new file mode 100644 index 0000000..303d6d1 Binary files /dev/null and b/target/classes/cn/wujiangbo/vo/UserTokenVo.class differ diff --git a/target/classes/logback-spring.xml b/target/classes/logback-spring.xml new file mode 100644 index 0000000..96d8332 --- /dev/null +++ b/target/classes/logback-spring.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ${FORMAT} + + + + + + + + + + + + ERROR + + ACCEPT + + DENY + + + + + + ${log_dir}/error/%d{yyyy-MM-dd}/error-%i.log + + + ${maxHistory} + + + ${maxFileSize} + + + + + + ${FORMAT} + + + + + + + + + + + WARN + + ACCEPT + + DENY + + + ${log_dir}/warn/%d{yyyy-MM-dd}/warn-%i.log + ${maxHistory} + + + ${maxFileSize} + + + + ${FORMAT} + + + + + + + INFO + ACCEPT + DENY + + + ${log_dir}/info/%d{yyyy-MM-dd}/info-%i.log + ${maxHistory} + + + ${maxFileSize} + + + + ${FORMAT} + + + + + + + DEBUG + ACCEPT + DENY + + + ${log_dir}/debug/%d{yyyy-MM-dd}/debug-%i.log + ${maxHistory} + + + ${maxFileSize} + + + + ${FORMAT} + + + + + + + + + + + + + + + + + diff --git a/target/classes/smart-doc.json b/target/classes/smart-doc.json new file mode 100644 index 0000000..842c2b2 --- /dev/null +++ b/target/classes/smart-doc.json @@ -0,0 +1,8 @@ +{ + // 官网地址:https://smart-doc-group.github.io/#/?id=smart-doc + "serverUrl": "http://localhost:8002", // 服务器地址,非必须 + "isStrict": false, //是否用严格模式,严格模式强制检查注释 + "allInOne": true, // 是否将文档合并到一个文件中,一般推荐为true + "outPath": "./src/main/resources/SmartDoc", //文档的输出路径 + "projectName": "EasyJavaTemplate" //指定项目名称,用于显示在文档中 +} \ No newline at end of file