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