Browse Source

init project

codingliang 2 years ago
commit
f7a89636af
100 changed files with 5374 additions and 0 deletions
  1. 33 0
      .gitignore
  2. 211 0
      pom.xml
  3. 13 0
      src/main/java/com/study/mall/CloudMallApplication.java
  4. 23 0
      src/main/java/com/study/mall/common/config/MyThreadConfig.java
  5. 22 0
      src/main/java/com/study/mall/common/config/MybatisPlusConfig.java
  6. 26 0
      src/main/java/com/study/mall/common/config/RedissonConfig.java
  7. 18 0
      src/main/java/com/study/mall/common/config/ScheduledConfig.java
  8. 19 0
      src/main/java/com/study/mall/common/config/WeMpConfig.java
  9. 24 0
      src/main/java/com/study/mall/common/config/WebDataConvertConfig.java
  10. 43 0
      src/main/java/com/study/mall/common/config/WebMvcConfig.java
  11. 62 0
      src/main/java/com/study/mall/common/exception/BizCodeEnum.java
  12. 134 0
      src/main/java/com/study/mall/common/exception/MyExceptionHandler.java
  13. 65 0
      src/main/java/com/study/mall/common/exception/RRException.java
  14. 36 0
      src/main/java/com/study/mall/common/utils/BaseResult.java
  15. 48 0
      src/main/java/com/study/mall/common/utils/CommonResult.java
  16. 83 0
      src/main/java/com/study/mall/common/utils/DateTimeZoneUtil.java
  17. 99 0
      src/main/java/com/study/mall/common/utils/FileIOUtil.java
  18. 235 0
      src/main/java/com/study/mall/common/utils/IpUtil.java
  19. 153 0
      src/main/java/com/study/mall/common/utils/JwtOperator.java
  20. 55 0
      src/main/java/com/study/mall/common/utils/MyQuery.java
  21. 33 0
      src/main/java/com/study/mall/common/utils/PageParam.java
  22. 100 0
      src/main/java/com/study/mall/common/utils/PageUtils.java
  23. 31 0
      src/main/java/com/study/mall/common/utils/ServletUtil.java
  24. 44 0
      src/main/java/com/study/mall/common/xss/SQLFilter.java
  25. 50 0
      src/main/java/com/study/mall/controller/AboutShopController.java
  26. 119 0
      src/main/java/com/study/mall/controller/AdminInfoController.java
  27. 38 0
      src/main/java/com/study/mall/controller/AppController.java
  28. 87 0
      src/main/java/com/study/mall/controller/BrandCategoryRelationController.java
  29. 87 0
      src/main/java/com/study/mall/controller/BrandInfoController.java
  30. 87 0
      src/main/java/com/study/mall/controller/CarouselController.java
  31. 108 0
      src/main/java/com/study/mall/controller/CartController.java
  32. 77 0
      src/main/java/com/study/mall/controller/ExpressCompanyController.java
  33. 64 0
      src/main/java/com/study/mall/controller/FileController.java
  34. 75 0
      src/main/java/com/study/mall/controller/GoodsCategoryController.java
  35. 90 0
      src/main/java/com/study/mall/controller/GoodsCommentController.java
  36. 173 0
      src/main/java/com/study/mall/controller/GoodsController.java
  37. 87 0
      src/main/java/com/study/mall/controller/NavigationController.java
  38. 51 0
      src/main/java/com/study/mall/controller/OrderConsigneeInfoController.java
  39. 214 0
      src/main/java/com/study/mall/controller/OrderController.java
  40. 118 0
      src/main/java/com/study/mall/controller/OrderExpressInfoController.java
  41. 94 0
      src/main/java/com/study/mall/controller/PayController.java
  42. 70 0
      src/main/java/com/study/mall/controller/PayOrderController.java
  43. 51 0
      src/main/java/com/study/mall/controller/PayRefundController.java
  44. 64 0
      src/main/java/com/study/mall/controller/SearchHotController.java
  45. 80 0
      src/main/java/com/study/mall/controller/ServiceTagController.java
  46. 87 0
      src/main/java/com/study/mall/controller/UserAddressController.java
  47. 74 0
      src/main/java/com/study/mall/controller/UserGoodsCollectController.java
  48. 79 0
      src/main/java/com/study/mall/controller/UserGoodsFootprintController.java
  49. 87 0
      src/main/java/com/study/mall/controller/UserSearchHistoryController.java
  50. 17 0
      src/main/java/com/study/mall/dao/AboutShopDao.java
  51. 17 0
      src/main/java/com/study/mall/dao/AdminInfoDao.java
  52. 17 0
      src/main/java/com/study/mall/dao/BrandCategoryRelationDao.java
  53. 17 0
      src/main/java/com/study/mall/dao/BrandInfoDao.java
  54. 17 0
      src/main/java/com/study/mall/dao/CarouselDao.java
  55. 17 0
      src/main/java/com/study/mall/dao/ExpressCompanyDao.java
  56. 17 0
      src/main/java/com/study/mall/dao/GoodsCategoryDao.java
  57. 17 0
      src/main/java/com/study/mall/dao/GoodsCommentDao.java
  58. 17 0
      src/main/java/com/study/mall/dao/GoodsDao.java
  59. 17 0
      src/main/java/com/study/mall/dao/GoodsDetailDao.java
  60. 22 0
      src/main/java/com/study/mall/dao/GoodsSkuDao.java
  61. 17 0
      src/main/java/com/study/mall/dao/GoodsSkuSaleAttrValueDao.java
  62. 17 0
      src/main/java/com/study/mall/dao/GoodsTagDao.java
  63. 17 0
      src/main/java/com/study/mall/dao/NavigationDao.java
  64. 17 0
      src/main/java/com/study/mall/dao/OrderConsigneeInfoDao.java
  65. 17 0
      src/main/java/com/study/mall/dao/OrderDetailDao.java
  66. 17 0
      src/main/java/com/study/mall/dao/OrderExpressInfoDao.java
  67. 25 0
      src/main/java/com/study/mall/dao/OrderInfoDao.java
  68. 17 0
      src/main/java/com/study/mall/dao/PayOrderDao.java
  69. 24 0
      src/main/java/com/study/mall/dao/PayRefundDao.java
  70. 17 0
      src/main/java/com/study/mall/dao/SearchHotDao.java
  71. 17 0
      src/main/java/com/study/mall/dao/ServiceTagDao.java
  72. 17 0
      src/main/java/com/study/mall/dao/UserAddressDao.java
  73. 17 0
      src/main/java/com/study/mall/dao/UserGoodsCollectDao.java
  74. 17 0
      src/main/java/com/study/mall/dao/UserGoodsFootprintDao.java
  75. 16 0
      src/main/java/com/study/mall/dao/UserInfoDao.java
  76. 17 0
      src/main/java/com/study/mall/dao/UserSearchHistoryDao.java
  77. 26 0
      src/main/java/com/study/mall/dto/AdminLoginDTO.java
  78. 55 0
      src/main/java/com/study/mall/dto/AdminOrderQueryDTO.java
  79. 37 0
      src/main/java/com/study/mall/dto/ConfirmOrderDTO.java
  80. 81 0
      src/main/java/com/study/mall/dto/CreateOrderDTO.java
  81. 39 0
      src/main/java/com/study/mall/dto/GoodHotOrLimitedChangeDTO.java
  82. 43 0
      src/main/java/com/study/mall/dto/GoodsCommentQueryDTO.java
  83. 155 0
      src/main/java/com/study/mall/dto/GoodsDetailDTO.java
  84. 36 0
      src/main/java/com/study/mall/dto/OrderDeliveryDTO.java
  85. 30 0
      src/main/java/com/study/mall/dto/OrderModifyPriceDTO.java
  86. 37 0
      src/main/java/com/study/mall/dto/OrderRefundDTO.java
  87. 31 0
      src/main/java/com/study/mall/dto/OrderStatisticsQueryDTO.java
  88. 46 0
      src/main/java/com/study/mall/dto/PayOrderQueryDTO.java
  89. 30 0
      src/main/java/com/study/mall/dto/PayRefundQueryDTO.java
  90. 26 0
      src/main/java/com/study/mall/dto/ServiceTagQueryDTO.java
  91. 41 0
      src/main/java/com/study/mall/dto/SkuSaleAttrDTO.java
  92. 70 0
      src/main/java/com/study/mall/dto/SukInfoDTO.java
  93. 40 0
      src/main/java/com/study/mall/dto/UserInfoUpdateDTO.java
  94. 33 0
      src/main/java/com/study/mall/dto/UserPhoneInfoUpdateDTO.java
  95. 42 0
      src/main/java/com/study/mall/entity/AboutShopEntity.java
  96. 72 0
      src/main/java/com/study/mall/entity/AdminInfoEntity.java
  97. 35 0
      src/main/java/com/study/mall/entity/BaseOperateEntity.java
  98. 35 0
      src/main/java/com/study/mall/entity/BrandCategoryRelationEntity.java
  99. 35 0
      src/main/java/com/study/mall/entity/BrandInfoEntity.java
  100. 0 0
      src/main/java/com/study/mall/entity/CarouselEntity.java

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 211 - 0
pom.xml

@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.study</groupId>
+    <artifactId>cloud-mall</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>cloud-mall</name>
+    <description>cloud-mall</description>
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <spring-boot.version>2.6.13</spring-boot.version>
+
+        <!-- Tools -->
+        <mybatisplus.boot.starter.version>3.5.3.1</mybatisplus.boot.starter.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>${mybatisplus.boot.starter.version}</version>
+        </dependency>
+
+        <!-- validator -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- jwt -->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-api</artifactId>
+            <version>0.10.7</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-impl</artifactId>
+            <version>0.10.7</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-jackson</artifactId>
+            <version>0.10.7</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>3.16.1</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <!-- 本地缓存 -->
+        <dependency>
+            <groupId>net.oschina.j2cache</groupId>
+            <artifactId>j2cache-spring-boot2-starter</artifactId>
+            <version>2.8.0-release</version>
+        </dependency>
+        <dependency>
+            <groupId>net.oschina.j2cache</groupId>
+            <artifactId>j2cache-core</artifactId>
+            <version>2.8.0-release</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-crypto</artifactId>
+        </dependency>
+
+        <!-- xk-time -->
+        <dependency>
+            <groupId>com.github.xkzhangsan</groupId>
+            <artifactId>xk-time</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+
+        <!-- hutool cache -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-core</artifactId>
+            <version>5.3.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-apache-httpclient</artifactId>
+            <version>0.4.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>3.21.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+        </dependency>
+    </dependencies>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- smart doc -->
+            <plugin>
+                <groupId>com.github.shalousun</groupId>
+                <artifactId>smart-doc-maven-plugin</artifactId>
+                <version>2.1.4</version>
+                <configuration>
+                    <!--指定生成文档的使用的配置文件,配置文件放在自己的项目中-->
+                    <configFile>./src/main/resources/smart-doc.json</configFile>
+                    <!--指定项目名称-->
+                    <projectName>云商城-后台服务</projectName>
+
+                    <includes>
+                        <!--格式为:groupId:artifactId;参考如下-->
+                        <include>com.chuanghai:patrol-parent</include>
+                    </includes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <!--如果不需要在执行编译时启动smart-doc,则将phase注释掉-->
+                        <phase>compile</phase>
+                        <goals>
+                            <!--smart-doc提供了html、openapi、markdown等goal,可按需配置-->
+                            <goal>html</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 13 - 0
src/main/java/com/study/mall/CloudMallApplication.java

@@ -0,0 +1,13 @@
+package com.study.mall;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class CloudMallApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(CloudMallApplication.class, args);
+    }
+
+}

+ 23 - 0
src/main/java/com/study/mall/common/config/MyThreadConfig.java

@@ -0,0 +1,23 @@
+package com.study.mall.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+@Configuration
+public class MyThreadConfig {
+
+    @Bean
+    public ThreadPoolExecutor threadPoolExecutor() {
+        return new ThreadPoolExecutor(20,
+                200,
+                10, TimeUnit.SECONDS,
+                new LinkedBlockingDeque<>(100000),
+                Executors.defaultThreadFactory(),
+                new ThreadPoolExecutor.AbortPolicy());
+    }
+}

+ 22 - 0
src/main/java/com/study/mall/common/config/MybatisPlusConfig.java

@@ -0,0 +1,22 @@
+package com.study.mall.common.config;
+
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Author: codingliang
+ * @Description: mp.mybatis 分页配置
+ * @Version: V1.0
+ **/
+@Configuration
+public class MybatisPlusConfig {
+
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor mpi = new MybatisPlusInterceptor();
+        mpi.addInnerInterceptor(new PaginationInnerInterceptor());
+        return mpi;
+    }
+}

+ 26 - 0
src/main/java/com/study/mall/common/config/RedissonConfig.java

@@ -0,0 +1,26 @@
+package com.study.mall.common.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * redisson配置
+ *
+ * @auther: codingliang
+ * @date: 2023-10-19 13:20
+ * @description: redisson配置
+ */
+@Configuration
+public class RedissonConfig {
+
+    @Bean
+    public RedissonClient redissonClient(@Value("${spring.redis.host}") String url, @Value("${spring.redis.password}") String password) {
+        Config config = new Config();
+        config.useSingleServer().setUsername("default").setPassword(password).setAddress("redis://"+url+":6379");
+        return Redisson.create(config);
+    }
+}

+ 18 - 0
src/main/java/com/study/mall/common/config/ScheduledConfig.java

@@ -0,0 +1,18 @@
+package com.study.mall.common.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * 调度配置
+ *
+ * @auther: codingliang
+ * @date: 2023/5/19 23:15
+ * @description: 调度配置
+ */
+@EnableAsync
+@EnableScheduling
+@Configuration
+public class ScheduledConfig {
+}

+ 19 - 0
src/main/java/com/study/mall/common/config/WeMpConfig.java

@@ -0,0 +1,19 @@
+package com.study.mall.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Author: codingliang
+ * @Description: 微信小程序配置
+ * @Date: 2020-06-04 11:22
+ * @Version: V1.0
+ **/
+@Configuration
+@ConfigurationProperties(prefix="wechat.mp")
+@Data
+public class WeMpConfig {
+    private String appId;
+    private String secret;
+}

+ 24 - 0
src/main/java/com/study/mall/common/config/WebDataConvertConfig.java

@@ -0,0 +1,24 @@
+package com.study.mall.common.config;
+
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * 序列换成json时,将所有的long变成string
+ *
+ * @auther: codingliang
+ * @date: 2023-09-28 13:38
+ * @description: 序列换成json时,将所有的long变成string
+ */
+@Configuration
+public class WebDataConvertConfig implements WebMvcConfigurer {
+    @Bean
+    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
+        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
+                .serializerByType(Long.class, ToStringSerializer.instance)
+                .serializerByType(Long.TYPE, ToStringSerializer.instance);
+    }
+}

+ 43 - 0
src/main/java/com/study/mall/common/config/WebMvcConfig.java

@@ -0,0 +1,43 @@
+package com.study.mall.common.config;
+
+import com.study.mall.common.utils.JwtOperator;
+import com.study.mall.interceptor.AdminTokenInterceptor;
+import com.study.mall.interceptor.CorsInterceptor;
+import com.study.mall.interceptor.UserTokenInterceptor;
+import com.study.mall.service.AdminInfoService;
+import com.study.mall.third.user.UserClient;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * webmvc配置
+ *
+ * @auther: codingliang
+ * @date: 2023-09-01 13:52
+ * @description: webmvc配置
+ */
+@RequiredArgsConstructor
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+    private final JwtOperator jwtOperator;
+    private final AdminInfoService adminInfoService;
+    private final UserClient userClient;
+    private final StringRedisTemplate stringRedisTemplate;
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new CorsInterceptor()).addPathPatterns("/**");
+
+        registry.addInterceptor(new UserTokenInterceptor(userClient, stringRedisTemplate))
+                    .addPathPatterns("/**/user/**")
+                    .excludePathPatterns("/user/open/wechatMpLogin");
+
+        registry.addInterceptor(new AdminTokenInterceptor(jwtOperator, adminInfoService))
+                    .addPathPatterns("/**/admin/**")
+                    .excludePathPatterns("/admin/open/login");
+    }
+}

+ 62 - 0
src/main/java/com/study/mall/common/exception/BizCodeEnum.java

@@ -0,0 +1,62 @@
+package com.study.mall.common.exception;
+
+/***
+ * 错误码和错误信息定义类
+ * 1. 错误码定义规则为5为数字
+ * 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
+ * 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
+ * 错误码列表:
+ *  10: 通用
+ *  11: 参数
+ *  12: 角色
+ *  13: 用户
+ *  14: 权限
+ *  15: 文件
+ *  16: 业务
+ */
+public enum BizCodeEnum {
+    UNKNOW_EXCEPTION(10000,"系统未知异常"),
+    METHOD_NOT_SUPPORT(10001, "请求方法不支持"),
+    REQUEST_HEADER_MISSING(10002, "缺少必要的请求头"),
+    INVALID_PARAM(11001,"参数格式校验失败"),
+    BODY_IS_EMPTY(11002, "body为空"),
+    PARAMETER_ERROR(11003, "参数异常"),
+    INVALID_TIME_FORMAT(11004, "无效的时间格式"),
+    SYSTEM_ERROR(11005, "系统异常"),
+    ROLE_IS_EXIST(12000, "角色已存在"),
+    TELEPHONE_IS_EXIST(13000, "手机号码已存在"),
+    LOGIN_ERROR(13001, "登录失败"),
+    USER_STATUS_ERROR(13002, "用户状态异常"),
+    TOKEN_INVALID(13003, "无效的token"),
+    TOKEN_IS_EMPTY(13004, "token为空"),
+    USER_IS_NOT_EXIST(13007, "用户不存在"),
+    PAY_SING_IS_NOT_MATCHING(14001, "支付签名验证失败"),
+    GET_PAY_PARAM_ERROR(14002, "支付参数获取失败"),
+    PAY_VERIFIER_ERROR(14003, "支付验签失败"),
+    PAY_RESULT_QUERY_ERROR(14004, "支付结果查询失败"),
+    EXPRESS_QUERY_ERROR(15001, "快递查询失败"),
+    THIRD_SERVER_REQUEST_ERROR(15002, "第三方服务请求失败"),
+    DATA_IS_EXIST(16000, "数据已存在"),
+    DATA_IS_NOT_EXIST(16001, "数据不存在"),
+    BATCH_EXECUTOR_ERROR(16003, "批量操作数据库失败"),
+    IMG_SUFFIX_NOT_SUPPORT(16006, "文件格式不支持"),
+    FILE_UPLOAD_ERROR(16007, "文件上传错误"),
+    FILE_IS_NOT_EXIT(16008, "临时文件不存在"),
+    FILE_IS_EMPTY(16007, "文件为空"),
+    FILE_IS_TOO_BIG(16008, "文件太大"),;
+
+    private int code;
+    private String msg;
+    BizCodeEnum(int code, String msg){
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 134 - 0
src/main/java/com/study/mall/common/exception/MyExceptionHandler.java

@@ -0,0 +1,134 @@
+package com.study.mall.common.exception;
+
+import com.study.mall.common.utils.CommonResult;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpMediaTypeNotSupportedException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingRequestHeaderException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.multipart.MaxUploadSizeExceededException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 统一异常处理
+ *
+ * @auther: codingliang
+ * @date: 2023/6/12 23:46
+ * @description: 统一异常处理
+ */
+@RestControllerAdvice
+public class MyExceptionHandler {
+
+    /**
+     * 处理参数校验异常
+     * @param e
+     * @return
+     */
+    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
+    public CommonResult handleValidException(Exception e) {
+        Map<String, String> map = new HashMap<>();
+        if (e instanceof MethodArgumentNotValidException) {
+            MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
+            exception.getBindingResult().getFieldErrors().forEach(item -> {
+                String errMessage = item.getDefaultMessage();
+                String errField = item.getField();
+                map.put(errField, errMessage);
+            });
+        } else if (e instanceof BindException) {
+            BindException exception = (BindException) e;
+            exception.getBindingResult().getFieldErrors().forEach(item -> {
+                String errMessage = item.getDefaultMessage();
+                String errField = item.getField();
+                map.put(errField, errMessage);
+            });
+        }
+        return CommonResult.fail(Integer.toString(BizCodeEnum.INVALID_PARAM.getCode()), BizCodeEnum.INVALID_PARAM.getMsg()).setResult(map);
+    }
+
+    /**
+     * 数据库索引重复
+     * @return
+     */
+    @ExceptionHandler(DuplicateKeyException.class)
+    public CommonResult handleSQLIntegrityConstraintViolationException() {
+        return CommonResult.fail(Integer.toString(BizCodeEnum.DATA_IS_EXIST.getCode()), BizCodeEnum.DATA_IS_EXIST.getMsg());
+    }
+
+    /**
+     * 请求方法不支持
+     * @return
+     */
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public CommonResult handleRequestMethodNotSupported() {
+        return CommonResult.fail(Integer.toString(BizCodeEnum.METHOD_NOT_SUPPORT.getCode()), BizCodeEnum.METHOD_NOT_SUPPORT.getMsg());
+    }
+
+    /**
+     * 缺少请求头
+     * @return
+     */
+    @ExceptionHandler(MissingRequestHeaderException.class)
+    public CommonResult handleRequestHeaderMissing() {
+        return CommonResult.fail(Integer.toString(BizCodeEnum.REQUEST_HEADER_MISSING.getCode()), BizCodeEnum.REQUEST_HEADER_MISSING.getMsg());
+    }
+
+    /**
+     * 参数缺失
+     * @return
+     */
+    @ExceptionHandler(MissingServletRequestParameterException.class)
+    public CommonResult handleMissingServletRequestParameterException() {
+        return CommonResult.fail(Integer.toString(BizCodeEnum.PARAMETER_ERROR.getCode()), BizCodeEnum.PARAMETER_ERROR.getMsg());
+    }
+
+    /**
+     * 文件过大
+     * @return
+     */
+    @ExceptionHandler(MaxUploadSizeExceededException.class)
+    public CommonResult handleMaxUploadSizeExceededException() {
+        return CommonResult.fail(Integer.toString(BizCodeEnum.FILE_IS_TOO_BIG.getCode()), BizCodeEnum.FILE_IS_TOO_BIG.getMsg());
+    }
+
+    /**
+     * body为空
+     * @return
+     */
+    @ExceptionHandler(HttpMessageNotReadableException.class)
+    public CommonResult handleMessageNotReadableException() {
+        return CommonResult.fail(Integer.toString(BizCodeEnum.BODY_IS_EMPTY.getCode()), BizCodeEnum.BODY_IS_EMPTY.getMsg());
+    }
+
+    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
+    public CommonResult handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
+        return CommonResult.fail(Integer.toString(BizCodeEnum.PARAMETER_ERROR.getCode()), "参数类型错误:" + e.getMessage());
+    }
+
+    /**
+     * 自定义异常
+     * @param e
+     * @return
+     */
+    @ExceptionHandler(RRException.class)
+    public CommonResult handleRRException(RRException e) {
+        return CommonResult.fail(Integer.toString(e.getCode()), e.getMsg());
+    }
+
+    /**
+     * 未知异常
+     * @param throwable
+     * @return
+     */
+    @ExceptionHandler(Throwable.class)
+    public CommonResult handleException(Throwable throwable) {
+        throwable.printStackTrace();
+        return CommonResult.fail(Integer.toString(BizCodeEnum.UNKNOW_EXCEPTION.getCode()), BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
+    }
+}

+ 65 - 0
src/main/java/com/study/mall/common/exception/RRException.java

@@ -0,0 +1,65 @@
+package com.study.mall.common.exception;
+
+/**
+ * 自定义异常
+ *
+ * @auther: codingliang
+ * @date: 2023/6/12 23:41
+ * @description: 自定义异常
+ */
+public class RRException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    private String msg;
+    private int code = 500;
+
+    public RRException(String msg) {
+        super(msg);
+        this.msg = msg;
+    }
+
+    public RRException(String msg, Throwable e) {
+        super(msg, e);
+        this.msg = msg;
+    }
+
+    public RRException(String msg, int code) {
+        super(msg);
+        this.msg = msg;
+        this.code = code;
+    }
+
+    public RRException(BizCodeEnum bizCodeEnum) {
+        super(bizCodeEnum.getMsg());
+        this.msg = bizCodeEnum.getMsg();
+        this.code = bizCodeEnum.getCode();
+    }
+
+    public RRException(BizCodeEnum bizCodeEnum, String msg) {
+        super(bizCodeEnum.getMsg());
+        this.msg = msg;
+        this.code = bizCodeEnum.getCode();
+    }
+
+    public RRException(String msg, int code, Throwable e) {
+        super(msg, e);
+        this.msg = msg;
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+}

+ 36 - 0
src/main/java/com/study/mall/common/utils/BaseResult.java

@@ -0,0 +1,36 @@
+package com.study.mall.common.utils;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 接口统一返回基类
+ *
+ * @auther: codingliang
+ * @date: 2023/6/12 23:47
+ * @description: 接口统一返回基类
+ */
+@Data
+public abstract class BaseResult<T> implements Serializable {
+
+    /**
+     * 接口调用结果标识
+     */
+    private boolean success = false;
+
+    /**
+     * 接口调用结果信息
+     */
+    private String message;
+
+    /**
+     * 接口调用业务码
+     */
+    private String code;
+
+    /**
+     * 接口调用返回数据
+     */
+    private T data;
+}

+ 48 - 0
src/main/java/com/study/mall/common/utils/CommonResult.java

@@ -0,0 +1,48 @@
+package com.study.mall.common.utils;
+
+import java.io.Serializable;
+
+/**
+ * 接口统一返回
+ *
+ * @auther: codingliang
+ * @date: 2023/6/12 23:50
+ * @description: 接口统一返回
+ */
+public class CommonResult<T> extends BaseResult implements Serializable {
+
+    private static final long serialVersionUID = 3616484754899974346L;
+
+    public static CommonResult ok() {
+        return ok("1", "执行成功");
+    }
+
+    public static <T> CommonResult<T> ok(String code, String msg) {
+        return baseCreate(code, msg, true);
+    }
+
+    public static CommonResult fail() {
+        return fail("-1", "执行失败");
+    }
+
+    public static CommonResult fail(String code, String msg) {
+        return baseCreate(code, msg, false);
+    }
+
+    private static <T> CommonResult<T> baseCreate(String code, String msg, boolean success) {
+        CommonResult result = new CommonResult();
+        result.setCode(code);
+        result.setSuccess(success);
+        result.setMessage(msg);
+        return result;
+    }
+
+    public CommonResult<T> setResult(T data) {
+        this.setData(data);
+        return this;
+    }
+
+    public T getData() {
+        return (T) super.getData();
+    }
+}

+ 83 - 0
src/main/java/com/study/mall/common/utils/DateTimeZoneUtil.java

@@ -0,0 +1,83 @@
+package com.study.mall.common.utils;
+
+import com.xkzhangsan.time.converter.DateTimeConverterUtil;
+import com.xkzhangsan.time.formatter.DateTimeFormatterUtil;
+import org.springframework.util.StringUtils;
+
+import java.io.Serializable;
+import java.time.ZonedDateTime;
+import java.util.Date;
+
+/**
+ * 时间工具类
+ * <p>
+ * 依赖 xk-time
+ * @author YunGouOS
+ */
+public class DateTimeZoneUtil implements Serializable {
+
+    private static final long serialVersionUID = -1331008203306650395L;
+
+    /**
+     * 时间转 TimeZone
+     * <p>
+     * 2020-08-17T16:46:37+08:00
+     *
+     * @param time 时间戳
+     * @return {@link String}  TimeZone 格式时间字符串
+     * @throws Exception 异常信息
+     */
+    public static String dateToTimeZone(long time) throws Exception {
+        return dateToTimeZone(new Date(time));
+    }
+
+    /**
+     * 时间转 TimeZone
+     * <p>
+     * 2020-08-17T16:46:37+08:00
+     *
+     * @param date {@link Date}
+     * @return {@link String} TimeZone 格式时间字符串
+     * @throws Exception 异常信息
+     */
+    public static String dateToTimeZone(Date date) throws Exception {
+        String time;
+        if (date == null) {
+            throw new Exception("date is not null");
+        }
+        ZonedDateTime zonedDateTime = DateTimeConverterUtil.toZonedDateTime(date);
+        time = DateTimeFormatterUtil.format(zonedDateTime, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_XXX_FMT);
+        return time;
+    }
+
+    /**
+     * TimeZone 时间转标准时间
+     * <p>
+     * 2020-08-17T16:46:37+08:00 to 2020-08-17 16:46:37
+     *
+     * @param str TimeZone格式时间字符串
+     * @return {@link String} 标准时间字符串
+     * @throws Exception 异常信息
+     */
+    public static String timeZoneDateToStr(String str) throws Exception {
+        String time;
+        if (!StringUtils.hasText(str)) {
+            throw new Exception("str is not null");
+        }
+        ZonedDateTime zonedDateTime = DateTimeFormatterUtil.parseToZonedDateTime(str, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_XXX_FMT);
+        if (zonedDateTime == null) {
+            throw new Exception("str to zonedDateTime fail");
+        }
+        time = zonedDateTime.format(DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_FMT);
+        return time;
+    }
+
+
+    public static void main(String[] args) throws Exception {
+        String timeZone = dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
+        String timeZone2 = dateToTimeZone(new Date());
+        System.out.println(timeZone + " " + timeZone2);
+        String date = timeZoneDateToStr(timeZone);
+        System.out.println(date);
+    }
+}

+ 99 - 0
src/main/java/com/study/mall/common/utils/FileIOUtil.java

@@ -0,0 +1,99 @@
+package com.study.mall.common.utils;
+
+import com.study.mall.common.exception.BizCodeEnum;
+import com.study.mall.common.exception.RRException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @Author: codingliang
+ * @Description: 文件读写操作
+ * @Date: 2021-06-04 17:53
+ * @Version: V1.0
+ **/
+public class FileIOUtil {
+
+    /**
+     * 读取文件内容
+     * @param filePath 文件鹿家
+     * @return {@link String} 文件内容
+     * @throws Exception 异常信息
+     */
+    public static String getFileContentAsString(String filePath) {
+        return readUtf8String(new File(filePath));
+    }
+
+    /**
+     * 获取证书
+     *
+     * @param inputStream 证书文件
+     * @return {@link X509Certificate} 获取证书
+     */
+    public static X509Certificate getCertificate(InputStream inputStream) {
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X509");
+            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
+            cert.checkValidity();
+            return cert;
+        } catch (CertificateExpiredException e) {
+            throw new RuntimeException("证书已过期", e);
+        } catch (CertificateNotYetValidException e) {
+            throw new RuntimeException("证书尚未生效", e);
+        } catch (CertificateException e) {
+            throw new RuntimeException("无效的证书", e);
+        }
+    }
+
+    /**
+     * 读取文件所有数据
+     * 文件的长度不能超过 {@link Integer#MAX_VALUE}
+     * @return 字节码
+     * @throws IOException IO异常
+     */
+    private static byte[] readBytes(File file) throws RRException {
+        long len = file.length();
+        if (len >= Integer.MAX_VALUE) {
+            throw new RRException(BizCodeEnum.FILE_IS_TOO_BIG, "文件超长");
+        }
+
+        byte[] bytes = new byte[(int) len];
+        FileInputStream in = null;
+        int readLength;
+        try {
+            in = new FileInputStream(file);
+            readLength = in.read(bytes);
+            if(readLength < len){
+                throw new RRException(BizCodeEnum.FILE_IS_EMPTY, "文件读取异常");
+            }
+        } catch (Exception e) {
+            throw new RRException(BizCodeEnum.FILE_IS_EMPTY, "文件读取异常");
+        } finally {
+            try {
+                in.close();
+            } catch (IOException e) {
+                // 静默关闭
+            }
+        }
+
+        return bytes;
+    }
+
+    /**
+     * 读取文件所有数据成字符串
+     * @return 文件内容
+     * @throws IOException IO异常
+     */
+    public static String readUtf8String(File file) {
+        byte[] bytes = readBytes(file);
+        return new String(bytes, StandardCharsets.UTF_8);
+    }
+}

+ 235 - 0
src/main/java/com/study/mall/common/utils/IpUtil.java

@@ -0,0 +1,235 @@
+package com.study.mall.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * my-mall
+ *
+ * @author wcp
+ * @since 2023/6/14 9:49
+ * https://www.cnblogs.com/CoderGeshu/p/15395136.html
+ */
+@Slf4j
+public class IpUtil {
+    private static final String UNKNOWN = "unknown";
+    private static final String LOCALHOST_IP = "127.0.0.1";
+    // 客户端与服务器同为一台机器,获取的 ip 有时候是 ipv6 格式
+    private static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";
+    private static final String SEPARATOR = ",";
+
+    /**
+     * 获取客户端IP
+     *
+     * @param request 请求对象
+     * @return IP地址
+     */
+    public static String getIp(HttpServletRequest request) {
+        if (request == null) {
+            return UNKNOWN;
+        }
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Forwarded-For");
+        }
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Real-IP");
+        }
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+
+        return LOCALHOST_IPV6.equals(ip) ? LOCALHOST_IP : getMultistageReverseProxyIp(ip);
+    }
+
+    /**
+     * 检查是否为内部IP地址
+     *
+     * @param addr byte地址
+     * @return 结果
+     */
+    private static boolean internalIp(byte[] addr) {
+        if (addr == null || addr.length < 2) {
+            return true;
+        }
+        final byte b0 = addr[0];
+        final byte b1 = addr[1];
+        // 10.x.x.x/8
+        final byte SECTION_1 = 0x0A;
+        // 172.16.x.x/12
+        final byte SECTION_2 = (byte) 0xAC;
+        final byte SECTION_3 = (byte) 0x10;
+        final byte SECTION_4 = (byte) 0x1F;
+        // 192.168.x.x/16
+        final byte SECTION_5 = (byte) 0xC0;
+        final byte SECTION_6 = (byte) 0xA8;
+        switch (b0) {
+            case SECTION_1:
+                return true;
+            case SECTION_2:
+                if (b1 >= SECTION_3 && b1 <= SECTION_4) {
+                    return true;
+                }
+            case SECTION_5:
+                switch (b1) {
+                    case SECTION_6:
+                        return true;
+                }
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 将IPv4地址转换成字节
+     *
+     * @param text IPv4地址
+     * @return byte 字节
+     */
+    public static byte[] textToNumericFormatV4(String text) {
+        if (text.length() == 0) {
+            return null;
+        }
+
+        byte[] bytes = new byte[4];
+        String[] elements = text.split("\\.", -1);
+        try {
+            long l;
+            int i;
+            switch (elements.length) {
+                case 1:
+                    l = Long.parseLong(elements[0]);
+                    if ((l < 0L) || (l > 4294967295L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
+                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 2:
+                    l = Integer.parseInt(elements[0]);
+                    if ((l < 0L) || (l > 255L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l & 0xFF);
+                    l = Integer.parseInt(elements[1]);
+                    if ((l < 0L) || (l > 16777215L)) {
+                        return null;
+                    }
+                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 3:
+                    for (i = 0; i < 2; ++i) {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    l = Integer.parseInt(elements[2]);
+                    if ((l < 0L) || (l > 65535L)) {
+                        return null;
+                    }
+                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 4:
+                    for (i = 0; i < 4; ++i) {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    break;
+                default:
+                    return null;
+            }
+        } catch (NumberFormatException e) {
+            return null;
+        }
+        return bytes;
+    }
+
+
+    /**
+     * 从多级反向代理中获得第一个非unknown IP地址
+     *
+     * @param ip 获得的IP地址
+     * @return 第一个非unknown IP地址
+     */
+    public static String getMultistageReverseProxyIp(String ip) {
+        // 多级反向代理检测
+        if (ip != null && ip.indexOf(SEPARATOR) > 0) {
+            final String[] ips = ip.trim().split(SEPARATOR);
+            for (String subIp : ips) {
+                if (!isUnknown(subIp)) {
+                    ip = subIp;
+                    break;
+                }
+            }
+        }
+        return substring(ip, 0, 255);
+    }
+
+    /**
+     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
+     *
+     * @param checkString 被检测的字符串
+     * @return 是否未知
+     */
+    public static boolean isUnknown(String checkString) {
+        return !StringUtils.hasText(checkString) || UNKNOWN.equalsIgnoreCase(checkString);
+    }
+
+
+    /**
+     * 截取字符串
+     *
+     * @param str   字符串
+     * @param start 开始
+     * @param end   结束
+     * @return 结果
+     */
+    public static String substring(final String str, int start, int end) {
+        if (str == null) {
+            return Strings.EMPTY;
+        }
+
+        if (end < 0) {
+            end = str.length() + end;
+        }
+        if (start < 0) {
+            start = str.length() + start;
+        }
+
+        if (end > str.length()) {
+            end = str.length();
+        }
+
+        if (start > end) {
+            return Strings.EMPTY;
+        }
+
+        if (start < 0) {
+            start = 0;
+        }
+        if (end < 0) {
+            end = 0;
+        }
+
+        return str.substring(start, end);
+    }
+}

+ 153 - 0
src/main/java/com/study/mall/common/utils/JwtOperator.java

@@ -0,0 +1,153 @@
+package com.study.mall.common.utils;
+
+import com.study.mall.common.exception.BizCodeEnum;
+import com.study.mall.common.exception.RRException;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Header;
+import io.jsonwebtoken.Jwt;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.SecretKey;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Author: codingliang
+ * @Description: JWT操作类
+ * @Date: 2020-06-03 11:54
+ * @Version: V1.0
+ **/
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class JwtOperator {
+
+    /**
+     * 秘钥
+     * - 默认aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrsssttt
+     */
+    @Value("${jwt.secret:aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrsssttt}")
+    private String secret;
+
+    /**
+     * 有效期,单位秒
+     * - 默认2周
+     */
+    @Value("${jwt.expire-time-in-second:1209600}")
+    private Long expirationTimeInSecond;
+
+    /**
+     * 获取过期时间
+     * @return
+     */
+    public Long getExpirationTimeInSecond() {
+        return this.expirationTimeInSecond;
+    }
+
+    /**
+     * 从token中获取claim
+     *
+     * @param token token
+     * @return claim
+     */
+    /**
+     * 从token中获取claim
+     *
+     * @param token token
+     * @return claim
+     */
+    public Claims getClaimsFromToken(String token) throws RRException {
+        try {
+            return Jwts.parser()
+                    .setSigningKey(this.secret.getBytes())
+                    .parseClaimsJws(token)
+                    .getBody();
+        } catch (Exception e) {
+            throw new RRException(BizCodeEnum.TOKEN_INVALID);
+        }
+    }
+
+    /**
+     * 获取token的过期时间
+     *
+     * @param token token
+     * @return 过期时间
+     */
+    public Date getExpirationDateFromToken(String token) {
+        return getClaimsFromToken(token)
+                .getExpiration();
+    }
+
+    /**
+     * 判断token是否过期
+     *
+     * @param token token
+     * @return 已过期返回true,未过期返回false
+     */
+    private Boolean isTokenExpired(String token) {
+        Date expiration = getExpirationDateFromToken(token);
+        return expiration.before(new Date());
+    }
+
+    /**
+     * 为指定用户生成token
+     *
+     * @param body 用户信息
+     * @return token
+     */
+    public String generateToken(Map<String, Object> body) {
+        Date createdTime = new Date();
+        Date expirationTime = new Date(System.currentTimeMillis() + getExpirationTimeInSecond() * 1000);
+
+        byte[] keyBytes = secret.getBytes();
+        SecretKey key = Keys.hmacShaKeyFor(keyBytes);
+
+        return Jwts.builder()
+                .setClaims(body)
+                .setIssuedAt(createdTime)
+                .setExpiration(expirationTime)
+                .signWith(key, SignatureAlgorithm.HS256)
+                .compact();
+    }
+
+    /**
+     * 判断token是否非法
+     *
+     * @param token token
+     * @return 未过期返回true,否则返回false
+     */
+    public Boolean validateToken(String token) {
+        return !isTokenExpired(token);
+    }
+
+    public static void main(String[] args) {
+        // 1. 初始化
+        JwtOperator jwtOperator = new JwtOperator();
+        jwtOperator.expirationTimeInSecond = 1209600L;
+        jwtOperator.secret = "aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrsssttt";
+
+        // 2.设置用户信息
+        Map<String, Object> objectObjectHashMap = new HashMap<>();
+        objectObjectHashMap.put("userId", "ff8080817f622622017f6c4f80b50004");
+
+        // 测试1: 生成token
+        String token = jwtOperator.generateToken(objectObjectHashMap);
+        System.out.println(token);
+
+        Jwt result = Jwts.parser().setSigningKey(jwtOperator.secret.getBytes()).parse(token);
+
+        Object jwtBody = result.getBody();
+        Header header = result.getHeader();
+
+        System.out.println(result);
+        System.out.println(jwtBody);
+        System.out.println(header);
+    }
+}

+ 55 - 0
src/main/java/com/study/mall/common/utils/MyQuery.java

@@ -0,0 +1,55 @@
+package com.study.mall.common.utils;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.study.mall.common.xss.SQLFilter;
+import org.springframework.util.StringUtils;
+
+/**
+ * 分页参数设置
+ *
+ * @auther: codingliang
+ * @date: 2023/6/13 10:16
+ * @description: 分页参数设置
+ */
+public class MyQuery<T> {
+    public IPage<T> getPage(PageParam params) {
+        return this.getPage(params, null, false);
+    }
+
+    public IPage<T> getPage(PageParam params, String defaultOrderField, boolean isAsc) {
+
+        //分页对象
+        Page<T> page = new Page<>(params.getCurPage(), params.getPageSize());
+
+        //排序字段
+        //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
+        String orderField = SQLFilter.sqlInject(params.getOrderField());
+        String order = params.getOrder();
+
+
+        //前端字段排序
+        if(StringUtils.hasText(orderField) && StringUtils.hasText(order)){
+            if("asc".equalsIgnoreCase(order)) {
+                return  page.addOrder(OrderItem.asc(orderField));
+            }else {
+                return page.addOrder(OrderItem.desc(orderField));
+            }
+        }
+
+        // 没有排序字段,则不排序
+        if(StringUtils.isEmpty(defaultOrderField)){
+            return page;
+        }
+
+        //默认排序
+        if(isAsc) {
+            page.addOrder(OrderItem.asc(defaultOrderField));
+        }else {
+            page.addOrder(OrderItem.desc(defaultOrderField));
+        }
+
+        return page;
+    }
+}

+ 33 - 0
src/main/java/com/study/mall/common/utils/PageParam.java

@@ -0,0 +1,33 @@
+package com.study.mall.common.utils;
+
+import lombok.Data;
+
+/**
+ * 分页参数
+ *
+ * @auther: codingliang
+ * @date: 2023/6/13 10:17
+ * @description: 分页参数
+ */
+@Data
+public class PageParam {
+    /**
+     * 当前页
+     */
+    private Integer curPage = 1;
+
+    /**
+     * 每页大小
+     */
+    private Integer pageSize = 10;
+
+    /**
+     * 排序字段
+     */
+    private String orderField;
+
+    /**
+     * 排序方式,可选值:asc、desc
+     */
+    private String order;
+}

+ 100 - 0
src/main/java/com/study/mall/common/utils/PageUtils.java

@@ -0,0 +1,100 @@
+package com.study.mall.common.utils;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 分页工具类
+ * @author Mark sunlightcs@gmail.com
+ */
+public class PageUtils<T> implements Serializable {
+	private static final long serialVersionUID = 1L;
+	/**
+	 * 总记录数
+	 */
+	private int totalCount;
+	/**
+	 * 每页记录数
+	 */
+	private int pageSize;
+	/**
+	 * 总页数
+	 */
+	private int totalPage;
+	/**
+	 * 当前页数
+	 */
+	private int currPage;
+	/**
+	 * 列表数据
+	 */
+	private List<T> list;
+
+	/**
+	 * 分页
+	 * @param list        列表数据
+	 * @param totalCount  总记录数
+	 * @param pageSize    每页记录数
+	 * @param currPage    当前页数
+	 */
+	public PageUtils(List<T> list, int totalCount, int pageSize, int currPage) {
+		this.list = list;
+		this.totalCount = totalCount;
+		this.pageSize = pageSize;
+		this.currPage = currPage;
+		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
+	}
+
+	/**
+	 * 分页
+	 */
+	public PageUtils(IPage<T> page) {
+		this.list = page.getRecords();
+		this.totalCount = (int)page.getTotal();
+		this.pageSize = (int)page.getSize();
+		this.currPage = (int)page.getCurrent();
+		this.totalPage = (int)page.getPages();
+	}
+
+	public int getTotalCount() {
+		return totalCount;
+	}
+
+	public void setTotalCount(int totalCount) {
+		this.totalCount = totalCount;
+	}
+
+	public int getPageSize() {
+		return pageSize;
+	}
+
+	public void setPageSize(int pageSize) {
+		this.pageSize = pageSize;
+	}
+
+	public int getTotalPage() {
+		return totalPage;
+	}
+
+	public void setTotalPage(int totalPage) {
+		this.totalPage = totalPage;
+	}
+
+	public int getCurrPage() {
+		return currPage;
+	}
+
+	public void setCurrPage(int currPage) {
+		this.currPage = currPage;
+	}
+
+	public List<?> getList() {
+		return list;
+	}
+
+	public void setList(List<T> list) {
+		this.list = list;
+	}
+}

+ 31 - 0
src/main/java/com/study/mall/common/utils/ServletUtil.java

@@ -0,0 +1,31 @@
+package com.study.mall.common.utils;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.util.Objects;
+
+/**
+ * my-mall
+ *
+ * @author wcp
+ * @since 2023/6/23 21:14
+ */
+public class ServletUtil {
+    public static final String HEADER_TOKEN = "token";
+
+    public static String getHeaderToken() {
+        return ServletUtil.getRequest().getHeader(HEADER_TOKEN);
+    }
+
+    public static HttpSession getSession() {
+        return ServletUtil.getRequest().getSession();
+    }
+
+
+    public static HttpServletRequest getRequest() {
+        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+    }
+}

+ 44 - 0
src/main/java/com/study/mall/common/xss/SQLFilter.java

@@ -0,0 +1,44 @@
+package com.study.mall.common.xss;
+
+import com.study.mall.common.exception.RRException;
+import org.springframework.util.StringUtils;
+
+/**
+ * SQL过滤
+ *
+ * @auther: codingliang
+ * @date: 2023/6/13 10:18
+ * @description: SQL过滤
+ */
+public class SQLFilter {
+    /**
+     * SQL注入过滤
+     * @param str  待验证的字符串
+     */
+    public static String sqlInject(String str){
+        if (StringUtils.hasText(str)) {
+            //去掉'|"|;|\字符
+            str = StringUtils.replace(str, "'", "");
+            str = StringUtils.replace(str, "\"", "");
+            str = StringUtils.replace(str, ";", "");
+            str = StringUtils.replace(str, "\\", "");
+
+            //转换成小写
+            str = str.toLowerCase();
+
+            //非法字符
+            String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
+
+            //判断是否包含非法字符
+            for(String keyword : keywords){
+                if(str.indexOf(keyword) != -1){
+                    throw new RRException("包含非法字符");
+                }
+            }
+
+            return str;
+        } else {
+            return null;
+        }
+    }
+}

+ 50 - 0
src/main/java/com/study/mall/controller/AboutShopController.java

@@ -0,0 +1,50 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.entity.AboutShopEntity;
+import com.study.mall.service.AboutShopService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 关于我
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("aboutShop")
+public class AboutShopController {
+
+    private final AboutShopService aboutShopService;
+
+    public AboutShopController(AboutShopService aboutShopService) {
+        this.aboutShopService = aboutShopService;
+    }
+
+
+    /**
+     * 关于我详情
+     */
+    @GetMapping("open/info")
+    public CommonResult<AboutShopEntity> info(){
+		AboutShopEntity one = aboutShopService.getOne(null);
+
+        return CommonResult.ok().setResult(one);
+    }
+
+    /**
+     * 修改关于我
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> addOrUpdate(@RequestBody @Validated AboutShopEntity aboutShop){
+		aboutShopService.addOrUpdate(aboutShop);
+
+        return CommonResult.ok();
+    }
+}

+ 119 - 0
src/main/java/com/study/mall/controller/AdminInfoController.java

@@ -0,0 +1,119 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.exception.BizCodeEnum;
+import com.study.mall.common.exception.RRException;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.AdminLoginDTO;
+import com.study.mall.entity.AdminInfoEntity;
+import com.study.mall.service.AdminInfoService;
+import com.study.mall.vo.LoginUserVO;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+
+/**
+ * 管理员信息
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("admin")
+public class AdminInfoController {
+
+    private final AdminInfoService adminInfoService;
+
+    public AdminInfoController(AdminInfoService adminInfoService) {
+        this.adminInfoService = adminInfoService;
+    }
+
+    /**
+     * 管理员登录
+     * @param dto
+     * @return
+     */
+    @PostMapping("open/login")
+    public CommonResult<LoginUserVO> login(@RequestBody @Validated AdminLoginDTO dto) {
+        LoginUserVO vo = adminInfoService.login(dto);
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 管理员列表
+     */
+    @GetMapping("/list")
+    public CommonResult<PageUtils<AdminInfoEntity>> list(PageParam pageParam){
+        PageUtils page = adminInfoService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 管理员详情
+     * @param id 管理员id
+     */
+    @GetMapping("/info/{id}")
+    public CommonResult<AdminInfoEntity> info(@PathVariable("id") Long id){
+		AdminInfoEntity adminInfo = adminInfoService.getById(id);
+
+        return CommonResult.ok().setResult(adminInfo);
+    }
+
+    /**
+     * 新增管理员
+     */
+    @PostMapping("/save")
+    public CommonResult<Void> save(@RequestBody @Validated AdminInfoEntity adminInfo){
+		adminInfoService.add(adminInfo);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改用户
+     */
+    @PutMapping("/update")
+    public CommonResult<Void> update(@RequestBody @Validated AdminInfoEntity adminInfo){
+        if (adminInfo.getId() == null) {
+            throw new RRException(BizCodeEnum.PARAMETER_ERROR, "id不能为空");
+        }
+        adminInfo.setPassword(null);
+        adminInfoService.update(adminInfo);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改用户密码
+     * @param password 新密码
+     * @param userId 用户id 待修改用户的id
+     * @apiNote 只有超级管理员才能修改其他用户密码
+     */
+    @PutMapping("/password")
+    public CommonResult<Void> updatePassword(Long userId, String password){
+        adminInfoService.updatePassword(userId, password);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除用户
+     */
+    @DeleteMapping("/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		adminInfoService.delete(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 38 - 0
src/main/java/com/study/mall/controller/AppController.java

@@ -0,0 +1,38 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.service.AppService;
+
+import com.study.mall.vo.AppIndexVO;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * app端使用到的聚合接口
+ *
+ * @auther: codingliang
+ * @date: 2023/7/11 21:05
+ * @description: 聚合接口
+ */
+@RestController
+@RequestMapping("/app")
+public class AppController {
+
+    private final AppService appService;
+
+    public AppController(AppService appService) {
+        this.appService = appService;
+    }
+
+    /**
+     * 首页
+     * @return
+     * @apiNote 包含首页轮播图、金刚墙、限时精选、热门推荐数据
+     */
+    @GetMapping("open/index")
+    public CommonResult<AppIndexVO> index() {
+        AppIndexVO index = appService.index();
+        return CommonResult.ok().setResult(index);
+    }
+}

+ 87 - 0
src/main/java/com/study/mall/controller/BrandCategoryRelationController.java

@@ -0,0 +1,87 @@
+package com.study.mall.controller;
+
+import java.util.Arrays;
+
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.study.mall.entity.BrandCategoryRelationEntity;
+import com.study.mall.service.BrandCategoryRelationService;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+
+/**
+ * 品牌分类
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ * @ignore
+ */
+@RestController
+@RequestMapping("brandCategoryRelation")
+public class BrandCategoryRelationController {
+
+    private final BrandCategoryRelationService brandCategoryRelationService;
+
+    public BrandCategoryRelationController(BrandCategoryRelationService brandCategoryRelationService) {
+        this.brandCategoryRelationService = brandCategoryRelationService;
+    }
+
+    /**
+     * 列表
+     */
+    @GetMapping("/list")
+    public CommonResult<PageUtils<BrandCategoryRelationEntity>> list(PageParam pageParam){
+        PageUtils page = brandCategoryRelationService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 信息
+     */
+    @PostMapping("/info/{id}")
+    public CommonResult<BrandCategoryRelationEntity> info(@PathVariable("id") Long id){
+		BrandCategoryRelationEntity brandCategoryRelation = brandCategoryRelationService.getById(id);
+
+        return CommonResult.ok().setResult(brandCategoryRelation);
+    }
+
+    /**
+     * 保存
+     */
+    @PostMapping("/save")
+    public CommonResult<Void> save(@RequestBody BrandCategoryRelationEntity brandCategoryRelation){
+		brandCategoryRelationService.save(brandCategoryRelation);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改
+     */
+    @PutMapping("/update")
+    public CommonResult<Void> update(@RequestBody BrandCategoryRelationEntity brandCategoryRelation){
+		brandCategoryRelationService.updateById(brandCategoryRelation);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除
+     */
+    @DeleteMapping("/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		brandCategoryRelationService.removeByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 87 - 0
src/main/java/com/study/mall/controller/BrandInfoController.java

@@ -0,0 +1,87 @@
+package com.study.mall.controller;
+
+import java.util.Arrays;
+
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.study.mall.entity.BrandInfoEntity;
+import com.study.mall.service.BrandInfoService;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+
+/**
+ * 品牌信息
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ * @ignore
+ */
+@RestController
+@RequestMapping("brand")
+public class BrandInfoController {
+
+    private final BrandInfoService brandInfoService;
+
+    public BrandInfoController(BrandInfoService brandInfoService) {
+        this.brandInfoService = brandInfoService;
+    }
+
+    /**
+     * 列表
+     */
+    @GetMapping("/list")
+    public CommonResult<PageUtils<BrandInfoEntity>> list(PageParam pageParam){
+        PageUtils page = brandInfoService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 信息
+     */
+    @PostMapping("/info/{id}")
+    public CommonResult<BrandInfoEntity> info(@PathVariable("id") Long id){
+		BrandInfoEntity brandInfo = brandInfoService.getById(id);
+
+        return CommonResult.ok().setResult(brandInfo);
+    }
+
+    /**
+     * 保存
+     */
+    @PostMapping("/save")
+    public CommonResult<Void> save(@RequestBody BrandInfoEntity brandInfo){
+		brandInfoService.save(brandInfo);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改
+     */
+    @PutMapping("/update")
+    public CommonResult<Void> update(@RequestBody BrandInfoEntity brandInfo){
+		brandInfoService.updateById(brandInfo);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除
+     */
+    @DeleteMapping("/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		brandInfoService.removeByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 87 - 0
src/main/java/com/study/mall/controller/CarouselController.java

@@ -0,0 +1,87 @@
+package com.study.mall.controller;
+
+import java.util.Arrays;
+
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.study.mall.entity.CarouselEntity;
+import com.study.mall.service.CarouselService;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+
+/**
+ * 轮播图
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("carousel")
+public class CarouselController {
+
+    private final CarouselService carouselService;
+
+    public CarouselController(CarouselService carouselService) {
+        this.carouselService = carouselService;
+    }
+
+    /**
+     * 轮播图列表
+     */
+    @GetMapping("open/list")
+    public CommonResult<PageUtils<CarouselEntity>> list(PageParam pageParam){
+        PageUtils page = carouselService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 轮播图信息
+     */
+    @PostMapping("admin/info/{id}")
+    public CommonResult<CarouselEntity> info(@PathVariable("id") Long id){
+		CarouselEntity carousel = carouselService.getById(id);
+
+        return CommonResult.ok().setResult(carousel);
+    }
+
+    /**
+     * 新增轮播图
+     */
+    @PostMapping("admin/add")
+    public CommonResult<Void> add(@RequestBody @Validated CarouselEntity carousel){
+		carouselService.add(carousel);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改轮播图
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> update(@RequestBody @Validated CarouselEntity carousel){
+		carouselService.update(carousel);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除轮播图
+     */
+    @DeleteMapping("admin/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		carouselService.removeByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 108 - 0
src/main/java/com/study/mall/controller/CartController.java

@@ -0,0 +1,108 @@
+package com.study.mall.controller;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.service.CartService;
+import com.study.mall.vo.CartVO;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+
+/**
+ * 购物车接口
+ *
+ * @auther: codingliang
+ * @date: 2023/7/19 22:28
+ * @description: 购物车
+ */
+@RestController
+@RequestMapping("user/cart")
+public class CartController {
+
+    private final CartService cartService;
+
+    public CartController(CartService cartService) {
+        this.cartService = cartService;
+    }
+
+    /**
+     * 用户获取购物车
+     * @return
+     * @throws JsonProcessingException
+     */
+    @GetMapping
+    public CommonResult<CartVO> getCart() {
+        CartVO cart = cartService.getCart();
+
+        return CommonResult.ok().setResult(cart);
+    }
+
+    /**
+     * 商品加入购物车
+     * @param goodId 商品id
+     * @param skuId skuId 商品开启sku后该值不能为空
+     * @param num 数量
+     * @return
+     */
+    @PutMapping
+    public CommonResult<Void> addCart(@RequestParam Long goodId, Long skuId, @RequestParam Integer num) {
+        cartService.addToCart(goodId, skuId, num);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 选中/取消选中购物车中某件商品
+     * @param key 购物车项key
+     * @param check 是否选中 1是,其他否
+     * @return
+     */
+    @PutMapping("/check/{key}")
+    public CommonResult<Void> checkItem(@PathVariable String key, String check){
+        cartService.checkItem(key, check);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 批量选中/取消选中购物车中某件商品
+     * @param keys 购物项key 多个key使用,分割
+     * @param check 是否选中 1是,其他否
+     * @return
+     */
+    @PutMapping("/batchCheck")
+    public CommonResult<Void> batchCheckItem(String keys, String check){
+        cartService.batchCheckItem(keys, check);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除购物车中某件商品
+     * @param key 购物车项key
+     * @return
+     */
+    @DeleteMapping("{key}")
+    public CommonResult<Void> deleteGood(@PathVariable String key){
+        cartService.deleteItem(key);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 清空购物车
+     * @return
+     */
+    @DeleteMapping("clear")
+    public CommonResult<Void> clearCart(){
+        cartService.clearCart();
+
+        return CommonResult.ok();
+    }
+}

+ 77 - 0
src/main/java/com/study/mall/controller/ExpressCompanyController.java

@@ -0,0 +1,77 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.entity.ExpressCompanyEntity;
+import com.study.mall.service.ExpressCompanyService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+
+/**
+ * 快递公司
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-04 22:14:38
+ */
+@RestController
+@RequestMapping("expressCompany")
+public class ExpressCompanyController {
+
+    private final ExpressCompanyService expressCompanyService;
+
+    public ExpressCompanyController(ExpressCompanyService expressCompanyService) {
+        this.expressCompanyService = expressCompanyService;
+    }
+
+    /**
+     * 快递公司列表
+     */
+    @GetMapping("open/list")
+    public CommonResult<PageUtils<ExpressCompanyEntity>> list(PageParam pageParam){
+        PageUtils page = expressCompanyService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 新增快递公司
+     * @apiNote 快递公司编码不能随便乱填,具体参考快递100,参考链接:https://api.kuaidi100.com/document/5f0ffb5ebc8da837cbd8aefc#section_1
+     */
+    @PostMapping("admin/add")
+    public CommonResult<Void> add(@RequestBody @Validated ExpressCompanyEntity expressCompany){
+		expressCompanyService.add(expressCompany);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改快递公司
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> update(@RequestBody @Validated ExpressCompanyEntity expressCompany){
+		expressCompanyService.update(expressCompany);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除快递公司
+     * @param ids id集合
+     */
+    @DeleteMapping("admin/delete")
+    public CommonResult<Void> deleteByIds(@RequestBody Long[] ids){
+        expressCompanyService.deleteByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 64 - 0
src/main/java/com/study/mall/controller/FileController.java

@@ -0,0 +1,64 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.exception.BizCodeEnum;
+import com.study.mall.common.exception.RRException;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.service.FileService;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 文件服务
+ *
+ * @auther: codingliang
+ * @date: 2023-10-07 16:54
+ * @description: 文件服务
+ */
+@RequestMapping("file/open")
+@RestController
+public class FileController {
+
+    private final FileService fileService;
+
+    public FileController(FileService fileService) {
+        this.fileService = fileService;
+    }
+
+    /**
+     * 文件上传
+     * @param file 文件内容
+     * @return
+     * @apiNote 文件上传接口,文件大小不能超过5M,只支持jpg、jpeg、bmp、png类型的文件
+     */
+    @PostMapping
+    public CommonResult<String> extraVideoUpload(MultipartFile file) {
+        if (file == null || file.isEmpty()) {
+            throw new RRException(BizCodeEnum.FILE_IS_EMPTY);
+        }
+        long fileSize = file.getSize() / 1048576;
+        if (fileSize > 5) { // 图片大小必须小于5M
+            throw new RRException(BizCodeEnum.FILE_IS_TOO_BIG);
+        }
+        String tempFileName = fileService.fileUpload(file);
+        return CommonResult.ok().setResult(tempFileName);
+    }
+
+    /**
+     * 删除文件
+     * @param url 文件浏览路径
+     * @return
+     */
+    @DeleteMapping
+    public CommonResult<Void> deleteTempFile(@RequestParam String url) {
+        fileService.deleteFile(url);
+
+        return CommonResult.ok();
+    }
+}

+ 75 - 0
src/main/java/com/study/mall/controller/GoodsCategoryController.java

@@ -0,0 +1,75 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.entity.GoodsCategoryEntity;
+import com.study.mall.service.GoodsCategoryService;
+import com.study.mall.vo.CategoryTreeVO;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 商品分类
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("goodsCategory")
+public class GoodsCategoryController {
+
+    private final GoodsCategoryService goodsCategoryService;
+
+    public GoodsCategoryController(GoodsCategoryService goodsCategoryService) {
+        this.goodsCategoryService = goodsCategoryService;
+    }
+
+    /**
+     * 分类树形列表
+     */
+    @GetMapping("open/list")
+    public CommonResult<List<CategoryTreeVO>> list(){
+        List<CategoryTreeVO> vos = goodsCategoryService.treeList();
+
+        return CommonResult.ok().setResult(vos);
+    }
+
+    /**
+     * 新增分类
+     */
+    @PostMapping("admin/save")
+    public CommonResult<Void> save(@RequestBody @Validated GoodsCategoryEntity goodsCategory){
+		goodsCategoryService.saveCategory(goodsCategory);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改分类
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> update(@RequestBody @Validated GoodsCategoryEntity goodsCategory){
+		goodsCategoryService.updateCategoryById(goodsCategory);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除分类
+     */
+    @DeleteMapping("/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		goodsCategoryService.removeCategoryByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 90 - 0
src/main/java/com/study/mall/controller/GoodsCommentController.java

@@ -0,0 +1,90 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.GoodsCommentQueryDTO;
+import com.study.mall.entity.GoodsCommentEntity;
+import com.study.mall.service.GoodsCommentService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+
+/**
+ * 商品评价
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("goodsComment")
+public class GoodsCommentController {
+
+    private final GoodsCommentService goodsCommentService;
+
+    public GoodsCommentController(GoodsCommentService goodsCommentService) {
+        this.goodsCommentService = goodsCommentService;
+    }
+
+    /**
+     * 评论列表
+     * @apiNote orderField可选值:reviewCnt评分,createTime评价时间
+     */
+    @GetMapping({"open/list", "admin/list"})
+    public CommonResult<PageUtils<GoodsCommentEntity>> list(PageParam pageParam, GoodsCommentQueryDTO dto){
+        PageUtils page = goodsCommentService.queryPage(pageParam, dto);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 订单评价详情
+     */
+    @GetMapping("open/info/{id}")
+    public CommonResult<GoodsCommentEntity> info(@PathVariable("id") Long id){
+		GoodsCommentEntity goodsComment = goodsCommentService.getById(id);
+
+        return CommonResult.ok().setResult(goodsComment);
+    }
+
+    /**
+     * 新增订单评论
+     */
+    @PostMapping("user/save")
+    public CommonResult<Void> save(@RequestBody @Validated GoodsCommentEntity goodsComment){
+		goodsCommentService.add(goodsComment);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改订单评论状态
+     * @param commentId 评论id
+     * @param state 1显示,其他隐藏
+     */
+    @PutMapping("admin/{commentId}/{state}")
+    public CommonResult<Void> updateState(@PathVariable Long commentId, @PathVariable String state){
+        goodsCommentService.updateState(commentId, state);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除订单评价
+     */
+    @DeleteMapping("admin/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		goodsCommentService.removeByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 173 - 0
src/main/java/com/study/mall/controller/GoodsController.java

@@ -0,0 +1,173 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.GoodHotOrLimitedChangeDTO;
+import com.study.mall.dto.GoodsDetailDTO;
+import com.study.mall.service.GoodsService;
+import com.study.mall.vo.GoodsDetailForAdminVO;
+import com.study.mall.vo.GoodsDetailVO;
+import com.study.mall.vo.GoodsListForAppVO;
+import com.study.mall.vo.GoodsListVO;
+import com.study.mall.vo.GoodsQueryVO;
+import com.study.mall.vo.SkuItemSaleAttrVO;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.constraints.Min;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * 商品
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("goods")
+public class GoodsController {
+
+    private final GoodsService goodsService;
+
+    public GoodsController(GoodsService goodsService) {
+        this.goodsService = goodsService;
+    }
+
+    /**
+     * 商品列表(app端)
+     * @return
+     * @apiNote 提供商品按分类、关键字等分页检索功能。orderField可用值:collectCnt 收藏量、saleCnt 销量、price 价格,
+     */
+    @GetMapping("open/page")
+    public CommonResult<GoodsListForAppVO> userPage(PageParam pageParam, @Validated GoodsQueryVO queryVO) {
+        PageUtils vo = goodsService.userPage(pageParam, queryVO);
+
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 商品详情(app端)
+     * @param id 商品id
+     * @return
+     */
+    @GetMapping("open/{id}")
+    public CommonResult<GoodsDetailVO> detail(@PathVariable("id") Long id) throws ExecutionException, InterruptedException {
+        GoodsDetailVO vo = goodsService.detail(id);
+
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 商品列表(管理端)
+     */
+    @GetMapping("admin/list")
+    public CommonResult<PageUtils<GoodsListVO>> list(PageParam pageParam, @Validated GoodsQueryVO queryVO){
+        PageUtils page = goodsService.queryPage(pageParam, queryVO);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 修改商品排序
+     * @param id 商品id
+     * @param sort 新排序,不能小于0
+     * @return
+     */
+    @PutMapping("admin/sort/{id}")
+    public CommonResult<Void> updateSort(@PathVariable("id") Long id,
+                                   @Validated
+                                   @Min(value = 0, message = "排序不能小于0")
+                                   @RequestParam(defaultValue = "0") Integer sort){
+        goodsService.updateSort(id, sort);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 商品热门/精选状态修改
+     * @param dto
+     * @return
+     */
+    @PutMapping("admin/hot-limited-change")
+    public CommonResult<Void> hotOrLimitedChange(@RequestBody @Validated GoodHotOrLimitedChangeDTO dto) {
+        goodsService.hotOrLimitedChange(dto);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 商品详情(管理员端)
+     * @param id 商品id
+     */
+    @GetMapping("admin/info/{id}")
+    public CommonResult<GoodsDetailForAdminVO> info(@PathVariable("id") Long id){
+        GoodsDetailForAdminVO goods = goodsService.detailForAdmin(id);
+
+        return CommonResult.ok().setResult(goods);
+    }
+
+    /**
+     * 新增商品
+     */
+    @PostMapping("admin/add")
+    public CommonResult<Void> add(@RequestBody @Validated GoodsDetailDTO dto){
+		goodsService.add(dto);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改商品
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> update(@Validated @RequestBody GoodsDetailDTO dto){
+		goodsService.updateGoods(dto);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 商品下架
+     * @param ids 商品id集合
+     */
+    @DeleteMapping("admin/off")
+    public CommonResult<Void> off(@RequestBody Long[] ids){
+		goodsService.off(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 商品上架
+     * @param ids 商品id集合
+     */
+    @DeleteMapping("admin/online")
+    public CommonResult<Void> online(@RequestBody Long[] ids){
+        goodsService.online(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 商品浏览量+1
+     * @param goodsId
+     * @return
+     */
+    @GetMapping("open/share-increase/{goodsId}")
+    public CommonResult<Void> shareIncrease(@PathVariable String goodsId) {
+        goodsService.shareIncrease(goodsId);
+        return CommonResult.ok();
+    }
+}

+ 87 - 0
src/main/java/com/study/mall/controller/NavigationController.java

@@ -0,0 +1,87 @@
+package com.study.mall.controller;
+
+import java.util.Arrays;
+
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.study.mall.entity.NavigationEntity;
+import com.study.mall.service.NavigationService;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+
+/**
+ * 导航(金刚区)
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("navigation")
+public class NavigationController {
+
+    private final NavigationService navigationService;
+
+    public NavigationController(NavigationService navigationService) {
+        this.navigationService = navigationService;
+    }
+
+    /**
+     * 导航列表
+     */
+    @GetMapping("open/list")
+    public CommonResult<PageUtils<NavigationEntity>> list(PageParam pageParam){
+        PageUtils page = navigationService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 导航详情
+     */
+    @GetMapping("admin/info/{id}")
+    public CommonResult<NavigationEntity> info(@PathVariable("id") Long id){
+		NavigationEntity navigation = navigationService.getById(id);
+
+        return CommonResult.ok().setResult(navigation);
+    }
+
+    /**
+     * 新增导航
+     */
+    @PostMapping("admin/add")
+    public CommonResult<Void> add(@RequestBody @Validated NavigationEntity navigation){
+		navigationService.add(navigation);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改导航
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> update(@RequestBody @Validated NavigationEntity navigation){
+		navigationService.update(navigation);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除导航
+     */
+    @DeleteMapping("admin/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		navigationService.removeByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 51 - 0
src/main/java/com/study/mall/controller/OrderConsigneeInfoController.java

@@ -0,0 +1,51 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.entity.OrderConsigneeInfoEntity;
+import com.study.mall.service.OrderConsigneeInfoService;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 订单收货人信息
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("orderConsignee")
+public class OrderConsigneeInfoController {
+
+    private final OrderConsigneeInfoService orderConsigneeInfoService;
+
+    public OrderConsigneeInfoController(OrderConsigneeInfoService orderConsigneeInfoService) {
+        this.orderConsigneeInfoService = orderConsigneeInfoService;
+    }
+
+    /**
+     * 查看订单收货信息
+     * @param orderId 订单id
+     */
+    @PostMapping("admin/info/{orderId}")
+    public CommonResult<OrderConsigneeInfoEntity> info(@PathVariable("orderId") Long orderId){
+		OrderConsigneeInfoEntity orderConsigneeInfo = orderConsigneeInfoService.getByOrderId(orderId);
+
+        return CommonResult.ok().setResult(orderConsigneeInfo);
+    }
+
+    /**
+     * 修改订单收货信息
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> update(@RequestBody OrderConsigneeInfoEntity orderConsigneeInfo){
+		orderConsigneeInfoService.updateById(orderConsigneeInfo);
+
+        return CommonResult.ok();
+    }
+
+}

+ 214 - 0
src/main/java/com/study/mall/controller/OrderController.java

@@ -0,0 +1,214 @@
+package com.study.mall.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.study.mall.common.exception.BizCodeEnum;
+import com.study.mall.common.exception.RRException;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.AdminOrderQueryDTO;
+import com.study.mall.dto.ConfirmOrderDTO;
+import com.study.mall.dto.CreateOrderDTO;
+import com.study.mall.dto.OrderModifyPriceDTO;
+import com.study.mall.dto.OrderRefundDTO;
+import com.study.mall.dto.OrderStatisticsQueryDTO;
+import com.study.mall.service.OrderInfoService;
+import com.study.mall.vo.ConfirmOrderVO;
+import com.study.mall.vo.CreateOrderVO;
+import com.study.mall.vo.OrderDetailForAdminVO;
+import com.study.mall.vo.OrderDetailForUserVO;
+import com.study.mall.vo.OrderListForAdminVO;
+import com.study.mall.vo.OrderListForUserVO;
+import com.study.mall.vo.OrderStatisticsVO;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 订单
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("order")
+public class OrderController {
+
+    private final OrderInfoService orderInfoService;
+
+    public OrderController(OrderInfoService orderInfoService) {
+        this.orderInfoService = orderInfoService;
+    }
+
+    /**
+     * 确认订单
+     * @param dto
+     * @return
+     */
+    @PostMapping("user/order/confirm")
+    public CommonResult<ConfirmOrderVO> confirmOrder(@RequestBody @Validated ConfirmOrderDTO dto) {
+        if ("1".equals(dto.getType())) {
+            if (ObjectUtil.hasEmpty(dto.getGoodId(), dto.getNum())) {
+                throw new RRException(BizCodeEnum.PARAMETER_ERROR, "商品id、数量不能为空");
+            }
+        }
+
+        ConfirmOrderVO confirmOrder = orderInfoService.confirmOrder(dto);
+        return CommonResult.ok().setResult(confirmOrder);
+    }
+
+    /**
+     * 提交订单
+     * @param dto
+     * @return
+     */
+    @PostMapping("user/order/submit")
+    public CommonResult<CreateOrderVO> submitOrder(@RequestBody @Validated CreateOrderDTO dto) {
+        CreateOrderVO vo = orderInfoService.submitOrder(dto);
+
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 订单列表(app端)
+     * @param orderState 订单状态,默认为7
+     * @apiNote 订单列表(app端),orderState可选值:1等待付款、2等待发货、3等待收货、4等待评论、5完成、7全部
+     */
+    @GetMapping("user/list")
+    public CommonResult<PageUtils<OrderListForUserVO>> userPage(PageParam pageParam, @RequestParam(defaultValue = "7") String orderState){
+        PageUtils page = orderInfoService.userPage(pageParam, orderState);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 订单详情
+     * @param id 订单id
+     * @apiNote 用户端订单详情
+     */
+    @GetMapping("user/info/{id}")
+    public CommonResult<OrderDetailForUserVO> orderDetailForUser(@PathVariable("id") Long id){
+        OrderDetailForUserVO vo = orderInfoService.orderDetailForUser(id);
+
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 取消订单
+     * @param id 订单id
+     * @return
+     * @apiNote 用户端取消订单,注意订单支付后不可取消
+     */
+    @PutMapping("user/cancel/{id}")
+    public CommonResult<Void> cancelOrder(@PathVariable("id") Long id) {
+        orderInfoService.cancelOrder(id);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 确认收货
+     * @param id 订单id
+     * @return
+     * @apiNote 用户确认收货
+     */
+    @PutMapping("user/receipt/{id}")
+    public CommonResult<Void> receiptOrder(@PathVariable("id") Long id) {
+        orderInfoService.receiptOrder(id);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 申请退款
+     * @param id 订单id
+     * @return
+     * @apiNote 用户申请退款,只有待发货状态的订单才能申请退款
+     */
+    @PutMapping("user/apply/refund/{id}")
+    public CommonResult<Void> applyRefund(@PathVariable("id") Long id, @RequestBody OrderRefundDTO refundDTO) {
+        orderInfoService.applyRefund(id, refundDTO);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除订单
+     * @param id 订单id
+     * @apiNote 用户端删除订单,注意订单在取消状态下才能被删除
+     */
+    @DeleteMapping("user/delete/{id}")
+    public CommonResult<Void> deleteOrder(@PathVariable("id") Long id){
+		orderInfoService.deleteOrder(id);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 订单列表(管理端)
+     * @param pageParam
+     * @param queryDTO 查询参数
+     * @return 管理端查询订单列表
+     */
+    @GetMapping("admin/list")
+    public CommonResult<PageUtils<OrderListForAdminVO>> adminPage(PageParam pageParam, AdminOrderQueryDTO queryDTO){
+        PageUtils page = orderInfoService.adminPage(pageParam, queryDTO);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 订单详情(管理端)
+     * @param id 订单id
+     * @return 管理端查询订单详情
+     */
+    @GetMapping("admin/info/{id}")
+    public CommonResult<OrderDetailForAdminVO> orderDetailForAdmin(@PathVariable Long id){
+        OrderDetailForAdminVO vo = orderInfoService.orderDetailForAdmin(id);
+
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 订单统计
+     * @param queryDTO 查询条件
+     * @return
+     * @apiNote 查询指定范围时间内订指定状态的所有订单总金额。state可选值:2等待发货、3等待收货、4等待评论、5完成,如果不传,则查询所有状态为2、3、4、5的所有订单总金额
+     */
+    @GetMapping("admin/order-statistics")
+    public CommonResult<OrderStatisticsVO> orderStatistics(OrderStatisticsQueryDTO queryDTO) {
+        OrderStatisticsVO vo = orderInfoService.orderStatistics(queryDTO);
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 订单改价(管理端)
+     * @param modifyPriceDTO
+     * @return
+     * @apiNote 只有待付款状态下的订单才能改价
+     */
+    @PutMapping("admin/modify-price")
+    public CommonResult<OrderDetailForAdminVO> modifyPrice(@RequestBody @Validated OrderModifyPriceDTO modifyPriceDTO){
+        orderInfoService.modifyPrice(modifyPriceDTO);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 订单商品列表
+     * @param id 订单id
+     * @return
+     */
+    @GetMapping("admin/order/goods/{id}")
+    public CommonResult<List<OrderListForUserVO.OrderDetailVO>> orderGoods(@PathVariable Long id) {
+        List<OrderListForUserVO.OrderDetailVO> vo = orderInfoService.orderGoodsList(id);
+        return CommonResult.ok().setResult(vo);
+    }
+}

+ 118 - 0
src/main/java/com/study/mall/controller/OrderExpressInfoController.java

@@ -0,0 +1,118 @@
+package com.study.mall.controller;
+
+import cn.hutool.core.map.MapUtil;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.OrderDeliveryDTO;
+import com.study.mall.entity.OrderExpressInfoEntity;
+import com.study.mall.service.OrderExpressInfoService;
+import com.study.mall.vo.OrderExpressInfoVO;
+import org.checkerframework.checker.units.qual.C;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+/**
+ * 订单物流信息
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-10-11 22:51:33
+ */
+@RestController
+@RequestMapping("orderExpress")
+public class OrderExpressInfoController {
+
+    private final OrderExpressInfoService orderExpressInfoService;
+
+    public OrderExpressInfoController(OrderExpressInfoService orderExpressInfoService) {
+        this.orderExpressInfoService = orderExpressInfoService;
+    }
+
+    /**
+     * 物流信息列表
+     */
+    @GetMapping("admin/list")
+    public CommonResult<PageUtils<OrderExpressInfoEntity>> list(PageParam pageParam){
+        PageUtils page = orderExpressInfoService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 订单发货
+     */
+    @PostMapping("admin/delivery")
+    public CommonResult<Void> delivery(@RequestBody @Validated OrderDeliveryDTO dto){
+        orderExpressInfoService.add(dto);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除发货信息
+     * @param id 订单发货物流id
+     */
+    @DeleteMapping("admin/delete/{id}")
+    public CommonResult<Void> delete(@PathVariable Long id){
+        orderExpressInfoService.delete(id);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 根据订单id查询物流信息
+     * @param orderId 订单id
+     * @return
+     */
+    @GetMapping("open/order/{orderId}")
+    public CommonResult<OrderExpressInfoVO> getByOrderId(@PathVariable Long orderId) {
+        OrderExpressInfoVO vo = orderExpressInfoService.getByOrderId(orderId);
+
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 根据订单快递id查询物流信息
+     * @param orderExpressId 订单快递id
+     * @return
+     */
+    @GetMapping("open/order-express/{orderExpressId}")
+    public CommonResult<OrderExpressInfoVO> getByOrderExpressId(@PathVariable Long orderExpressId) {
+        OrderExpressInfoVO vo = orderExpressInfoService.getByOrderExpressId(orderExpressId);
+
+        return CommonResult.ok().setResult(vo);
+    }
+
+    /**
+     * 订阅回调通知
+     * @param orderId
+     * @param request
+     * @return 快递100调用
+     */
+    @GetMapping("open/notify")
+    public ResponseEntity<Object> notify(@RequestParam Long orderId, HttpServletRequest request) {
+        orderExpressInfoService.subNotify(orderId, request);
+
+        Map<String, Object> result = MapUtil.<String, Object>builder()
+                .put("result", true)
+                .put("returnCode", "200")
+                .put("message", "提交成功")
+                .build();
+        // 响应500
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
+    }
+}

+ 94 - 0
src/main/java/com/study/mall/controller/PayController.java

@@ -0,0 +1,94 @@
+package com.study.mall.controller;
+
+import cn.hutool.core.map.MapUtil;
+import com.study.mall.common.exception.RRException;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.third.pay.wechat.WechatPayHandler;
+import com.study.mall.third.pay.wechat.dto.WechatPayQueryResultDTO;
+import com.study.mall.vo.JSAPIPayParamVO;
+import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+/**
+ * 支付服务
+ *
+ * @auther: codingliang
+ * @date: 2023-10-09 21:18
+ * @description: 支付服务
+ */
+@RestController
+@RequestMapping("pay")
+public class PayController {
+
+    private final WechatPayHandler wechatPayHandler;
+
+    public PayController(WechatPayHandler wechatPayHandler) {
+        this.wechatPayHandler = wechatPayHandler;
+    }
+
+    /**
+     * 获取微信小程序支付参数
+     * @param orderId 订单id
+     * @return
+     */
+    @GetMapping("wx/user/getJsApiPayParam/{orderId}")
+    public CommonResult<JSAPIPayParamVO> getJsApiPayParam(@PathVariable Long orderId) {
+        JSAPIPayParamVO jsapiTrading = wechatPayHandler.createJsapiTrading(orderId);
+        return CommonResult.ok().setResult(jsapiTrading);
+    }
+
+    /**
+     * 微信支付成功回调(成功后无需响应内容)
+     *
+     * @param httpEntity   微信请求信息
+     * @return 正常响应200,否则响应500
+     */
+    @PostMapping("wx/open/notify")
+    public ResponseEntity<Object> wxPayNotify(HttpEntity<String> httpEntity) {
+        try {
+            // 获取请求头
+            HttpHeaders headers = httpEntity.getHeaders();
+
+            // 构建微信请求数据对象
+            NotificationRequest request = new NotificationRequest.Builder()
+                    .withSerialNumber(headers.getFirst("Wechatpay-Serial")) //证书序列号(微信平台)
+                    .withNonce(headers.getFirst("Wechatpay-Nonce"))  //随机串
+                    .withTimestamp(headers.getFirst("Wechatpay-Timestamp")) //时间戳
+                    .withSignature(headers.getFirst("Wechatpay-Signature")) //签名字符串
+                    .withBody(httpEntity.getBody())
+                    .build();
+
+            // 微信通知的业务处理
+            wechatPayHandler.payNotify(request);
+        } catch (RRException e) {
+            Map<String, Object> result = MapUtil.<String, Object>builder()
+                    .put("code", "FAIL")
+                    .put("message", e.getMsg())
+                    .build();
+            // 响应500
+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
+        }
+        return ResponseEntity.ok(null);
+    }
+
+    /**
+     * 交易结果查询
+     * @param payNo 支付编号
+     * @return
+     */
+    @GetMapping("wx/open/queryTrading/{payNo}")
+    public CommonResult<WechatPayQueryResultDTO> wxQueryTrading(@PathVariable String payNo) {
+        WechatPayQueryResultDTO dto = wechatPayHandler.queryTrading(payNo);
+        return CommonResult.ok().setResult(dto);
+    }
+}

+ 70 - 0
src/main/java/com/study/mall/controller/PayOrderController.java

@@ -0,0 +1,70 @@
+package com.study.mall.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.study.mall.common.exception.BizCodeEnum;
+import com.study.mall.common.exception.RRException;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.PayOrderQueryDTO;
+import com.study.mall.entity.PayOrderEntity;
+import com.study.mall.service.PayOrderService;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * 支付订单
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Controller
+@RequestMapping("payOrder")
+public class PayOrderController {
+
+    private final PayOrderService payOrderService;
+
+    public PayOrderController(PayOrderService payOrderService) {
+        this.payOrderService = payOrderService;
+    }
+
+    /**
+     * 支付订单列表
+     */
+    @GetMapping("admin/list")
+    public CommonResult<PageUtils<PayOrderEntity>> list(PageParam pageParam, PayOrderQueryDTO queryDTO){
+        PageUtils page = payOrderService.queryPage(pageParam, queryDTO);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 订单支付信息
+     * @param orderId 订单id
+     */
+    @GetMapping("admin/info/{orderId}")
+    public CommonResult<PayOrderEntity> infoByOrderId(@PathVariable Long orderId){
+        PayOrderEntity payOrder = payOrderService.getByOrderId(orderId);
+
+        return CommonResult.ok().setResult(payOrder);
+    }
+
+    /**
+     * 订单支付信息
+     * @param payOrderId 支付订单id
+     */
+    @GetMapping("admin/info/getByPayOrderId")
+    public CommonResult<PayOrderEntity> infoByPayOrderId(@RequestParam Long payOrderId){
+        PayOrderEntity payOrder = payOrderService.getById(payOrderId);
+
+        if (ObjectUtil.isNull(payOrder)) {
+            throw new RRException(BizCodeEnum.PARAMETER_ERROR, "支付订单存在");
+        }
+
+        return CommonResult.ok().setResult(payOrder);
+    }
+}

+ 51 - 0
src/main/java/com/study/mall/controller/PayRefundController.java

@@ -0,0 +1,51 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.PayRefundQueryDTO;
+import com.study.mall.service.PayRefundService;
+import com.study.mall.vo.PayRefundVO;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 支付退款
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("payRefund")
+public class PayRefundController {
+
+    private final PayRefundService payRefundService;
+
+    public PayRefundController(PayRefundService payRefundService) {
+        this.payRefundService = payRefundService;
+    }
+
+    /**
+     * 支付退款列表
+     */
+    @GetMapping("admin/list")
+    public CommonResult<PageUtils<PayRefundVO>> list(PageParam pageParam, PayRefundQueryDTO queryDTO){
+        PageUtils page = payRefundService.queryPage(pageParam, queryDTO);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 退款详细信息
+     * @param payOrderId 支付订单id
+     */
+    @GetMapping("admin/info/{payOrderId}")
+    public CommonResult<PayRefundVO> infoByOrderId(@PathVariable Long payOrderId){
+        PayRefundVO vo = payRefundService.getByPayOrderId(payOrderId);
+
+        return CommonResult.ok().setResult(vo);
+    }
+}

+ 64 - 0
src/main/java/com/study/mall/controller/SearchHotController.java

@@ -0,0 +1,64 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.entity.SearchHotEntity;
+import com.study.mall.service.SearchHotService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+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.util.Arrays;
+
+/**
+ * 热门搜索
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("searchHot")
+public class SearchHotController {
+
+    private final SearchHotService searchHotService;
+
+    public SearchHotController(SearchHotService searchHotService) {
+        this.searchHotService = searchHotService;
+    }
+
+    /**
+     * 历史热门搜索列表
+     */
+    @GetMapping("open/list")
+    public CommonResult<PageUtils<SearchHotEntity>> list(PageParam pageParam){
+        PageUtils page = searchHotService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 新增热门搜索
+     */
+    @PostMapping("admin/add")
+    public CommonResult<Void> add(@RequestBody @Validated SearchHotEntity searchHot){
+		searchHotService.add(searchHot);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除热门搜索
+     */
+    @DeleteMapping("admin/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		searchHotService.removeByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 80 - 0
src/main/java/com/study/mall/controller/ServiceTagController.java

@@ -0,0 +1,80 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.exception.BizCodeEnum;
+import com.study.mall.common.exception.RRException;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.dto.ServiceTagQueryDTO;
+import com.study.mall.entity.ServiceTagEntity;
+import com.study.mall.service.ServiceTagService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 服务标签
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("serviceTag")
+public class ServiceTagController {
+
+    private final ServiceTagService serviceTagService;
+
+    public ServiceTagController(ServiceTagService serviceTagService) {
+        this.serviceTagService = serviceTagService;
+    }
+
+    /**
+     * 服务标签列表
+     */
+    @GetMapping("admin/list")
+    public CommonResult<PageUtils<ServiceTagEntity>> list(PageParam pageParam, ServiceTagQueryDTO queryDTO){
+        PageUtils page = serviceTagService.queryPage(pageParam, queryDTO);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 服务标签信息
+     */
+    @PostMapping("admin/info/{id}")
+    public CommonResult<ServiceTagEntity> info(@PathVariable("id") Long id){
+		ServiceTagEntity serviceTag = serviceTagService.getById(id);
+
+        return CommonResult.ok().setResult(serviceTag);
+    }
+
+    /**
+     * 新增服务标签
+     */
+    @PostMapping("admin/add")
+    public CommonResult<Void> add(@RequestBody @Validated ServiceTagEntity serviceTag){
+		serviceTagService.add(serviceTag);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改服务标签
+     */
+    @PutMapping("admin/update")
+    public CommonResult<Void> update(@RequestBody @Validated ServiceTagEntity serviceTag){
+        if (serviceTag.getId() == null) {
+            throw new RRException(BizCodeEnum.PARAMETER_ERROR, "id不能为空");
+        }
+
+		serviceTagService.update(serviceTag);
+
+        return CommonResult.ok();
+    }
+}

+ 87 - 0
src/main/java/com/study/mall/controller/UserAddressController.java

@@ -0,0 +1,87 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.entity.UserAddressEntity;
+import com.study.mall.service.UserAddressService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 用户地址
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("address")
+public class UserAddressController {
+
+    private final UserAddressService userAddressService;
+
+    public UserAddressController(UserAddressService userAddressService) {
+        this.userAddressService = userAddressService;
+    }
+
+    /**
+     * 用户地址列表
+     */
+    @GetMapping("user/list")
+    public CommonResult<List<UserAddressEntity>> list(){
+        List<UserAddressEntity> list = userAddressService.queryByUser();
+
+        return CommonResult.ok().setResult(list);
+    }
+
+    /**
+     * 用户地址详情
+     * @param id 地址id
+     */
+    @PostMapping("/info/{id}")
+    public CommonResult<UserAddressEntity> info(@PathVariable("id") Long id){
+		UserAddressEntity userAddress = userAddressService.getById(id);
+
+        return CommonResult.ok().setResult(userAddress);
+    }
+
+    /**
+     * 新增用户地址
+     */
+    @PostMapping("user/save")
+    public CommonResult<Void> save(@RequestBody @Validated UserAddressEntity userAddress){
+		userAddressService.add(userAddress);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 用户地址修改
+     */
+    @PutMapping("user/update")
+    public CommonResult<Void> update(@RequestBody @Validated UserAddressEntity userAddress){
+		userAddressService.update(userAddress);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除用户地址
+     * @param ids 地址id
+     */
+    @DeleteMapping("user/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		userAddressService.delete(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 74 - 0
src/main/java/com/study/mall/controller/UserGoodsCollectController.java

@@ -0,0 +1,74 @@
+package com.study.mall.controller;
+
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+import com.study.mall.entity.UserGoodsCollectEntity;
+import com.study.mall.service.UserGoodsCollectService;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 用户商品收藏
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("collect")
+public class UserGoodsCollectController {
+
+    private final UserGoodsCollectService userGoodsCollectService;
+
+    public UserGoodsCollectController(UserGoodsCollectService userGoodsCollectService) {
+        this.userGoodsCollectService = userGoodsCollectService;
+    }
+
+    /**
+     * 用户收藏列表
+     */
+    @GetMapping("user/list")
+    public CommonResult<PageUtils<UserGoodsCollectEntity>> list(PageParam pageParam){
+        PageUtils page = userGoodsCollectService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 新增/取消收藏
+     * @param goodsId 商品id
+     * @apiNote 没有收藏的商品调用该接口标识收藏商品,已收藏的商品调用该接口标识取消收藏
+     */
+    @PostMapping("user/{goodsId}")
+    public CommonResult<Void> addOrCancelCollect(@PathVariable Long goodsId){
+		userGoodsCollectService.addOrCancelCollect(goodsId);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 获取用户是否收藏商品
+     * @param goodsId 商品id
+     * @return
+     */
+    @GetMapping("user/{goodsId}")
+    public CommonResult<Boolean> isCollected(@PathVariable Long goodsId) {
+        boolean flag = userGoodsCollectService.isCollected(goodsId);
+        return CommonResult.ok().setResult(flag);
+    }
+
+    /**
+     * 清空收藏
+     */
+    @DeleteMapping("user/clear")
+    public CommonResult<Void> delete(){
+		userGoodsCollectService.removeAllCollect();
+
+        return CommonResult.ok();
+    }
+}

+ 79 - 0
src/main/java/com/study/mall/controller/UserGoodsFootprintController.java

@@ -0,0 +1,79 @@
+package com.study.mall.controller;
+
+import java.util.Arrays;
+
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.study.mall.entity.UserGoodsFootprintEntity;
+import com.study.mall.service.UserGoodsFootprintService;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+
+/**
+ * 用户商品足迹
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@RestController
+@RequestMapping("footprint")
+public class UserGoodsFootprintController {
+
+    private final UserGoodsFootprintService userGoodsFootprintService;
+
+    public UserGoodsFootprintController(UserGoodsFootprintService userGoodsFootprintService) {
+        this.userGoodsFootprintService = userGoodsFootprintService;
+    }
+
+    /**
+     * 用户足迹列表
+     */
+    @GetMapping("user/list")
+    public CommonResult<PageUtils<UserGoodsFootprintEntity>> list(PageParam pageParam){
+        PageUtils page = userGoodsFootprintService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 新增商品足迹
+     * @param goodsId 商品id
+     * @apiNote 用户每次进入商品详情时都要调用一次
+     */
+    @PostMapping("user/{goodsId}/add")
+    public CommonResult<Void> save(@PathVariable Long goodsId){
+		userGoodsFootprintService.add(goodsId);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除足迹
+     * @param ids 足迹id集合
+     */
+    @DeleteMapping("user/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		userGoodsFootprintService.delete(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 清空足迹
+     */
+    @DeleteMapping("user/clear")
+    public CommonResult<Void> clear(){
+        userGoodsFootprintService.clear();
+
+        return CommonResult.ok();
+    }
+}

+ 87 - 0
src/main/java/com/study/mall/controller/UserSearchHistoryController.java

@@ -0,0 +1,87 @@
+package com.study.mall.controller;
+
+import java.util.Arrays;
+
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.study.mall.entity.UserSearchHistoryEntity;
+import com.study.mall.service.UserSearchHistoryService;
+import com.study.mall.common.utils.CommonResult;
+import com.study.mall.common.utils.PageParam;
+import com.study.mall.common.utils.PageUtils;
+
+/**
+ * 搜索历史记录
+ *  前端使用缓存记录用户搜索记录
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ * @ignore
+ */
+@RestController
+@RequestMapping("usersearchhistory")
+public class UserSearchHistoryController {
+
+    private final UserSearchHistoryService userSearchHistoryService;
+
+    public UserSearchHistoryController(UserSearchHistoryService userSearchHistoryService) {
+        this.userSearchHistoryService = userSearchHistoryService;
+    }
+
+    /**
+     * 列表
+     */
+    @GetMapping("/list")
+    public CommonResult<PageUtils<UserSearchHistoryEntity>> list(PageParam pageParam){
+        PageUtils page = userSearchHistoryService.queryPage(pageParam);
+
+        return CommonResult.ok().setResult(page);
+    }
+
+    /**
+     * 信息
+     */
+    @PostMapping("/info/{id}")
+    public CommonResult<UserSearchHistoryEntity> info(@PathVariable("id") Long id){
+		UserSearchHistoryEntity userSearchHistory = userSearchHistoryService.getById(id);
+
+        return CommonResult.ok().setResult(userSearchHistory);
+    }
+
+    /**
+     * 保存
+     */
+    @PostMapping("/save")
+    public CommonResult<Void> save(@RequestBody UserSearchHistoryEntity userSearchHistory){
+		userSearchHistoryService.save(userSearchHistory);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 修改
+     */
+    @PutMapping("/update")
+    public CommonResult<Void> update(@RequestBody UserSearchHistoryEntity userSearchHistory){
+		userSearchHistoryService.updateById(userSearchHistory);
+
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除
+     */
+    @DeleteMapping("/delete")
+    public CommonResult<Void> delete(@RequestBody Long[] ids){
+		userSearchHistoryService.removeByIds(Arrays.asList(ids));
+
+        return CommonResult.ok();
+    }
+}

+ 17 - 0
src/main/java/com/study/mall/dao/AboutShopDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.AboutShopEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 关于我
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface AboutShopDao extends BaseMapper<AboutShopEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/AdminInfoDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.AdminInfoEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 管理员信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface AdminInfoDao extends BaseMapper<AdminInfoEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/BrandCategoryRelationDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.BrandCategoryRelationEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 品牌分类
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface BrandCategoryRelationDao extends BaseMapper<BrandCategoryRelationEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/BrandInfoDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.BrandInfoEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 品牌信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface BrandInfoDao extends BaseMapper<BrandInfoEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/CarouselDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.CarouselEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 轮播图
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface CarouselDao extends BaseMapper<CarouselEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/ExpressCompanyDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.ExpressCompanyEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 快递公司
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-04 22:14:38
+ */
+@Mapper
+public interface ExpressCompanyDao extends BaseMapper<ExpressCompanyEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/GoodsCategoryDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.GoodsCategoryEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品分类
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface GoodsCategoryDao extends BaseMapper<GoodsCategoryEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/GoodsCommentDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.GoodsCommentEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品评价
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface GoodsCommentDao extends BaseMapper<GoodsCommentEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/GoodsDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.GoodsEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface GoodsDao extends BaseMapper<GoodsEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/GoodsDetailDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.GoodsDetailEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品详情
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface GoodsDetailDao extends BaseMapper<GoodsDetailEntity> {
+	
+}

+ 22 - 0
src/main/java/com/study/mall/dao/GoodsSkuDao.java

@@ -0,0 +1,22 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.GoodsSkuEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.study.mall.vo.SkuItemSaleAttrVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * sku信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-11-22 21:58:39
+ */
+@Mapper
+public interface GoodsSkuDao extends BaseMapper<GoodsSkuEntity> {
+
+    List<SkuItemSaleAttrVO> getSkuSaleAttrByGoodsId(@Param("goodsId") Long goodsId);
+}

+ 17 - 0
src/main/java/com/study/mall/dao/GoodsSkuSaleAttrValueDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.GoodsSkuSaleAttrValueEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品sku销售属性&值
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-11-22 21:58:39
+ */
+@Mapper
+public interface GoodsSkuSaleAttrValueDao extends BaseMapper<GoodsSkuSaleAttrValueEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/GoodsTagDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.GoodsTagEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品标签
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface GoodsTagDao extends BaseMapper<GoodsTagEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/NavigationDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.NavigationEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 导航(金刚区)
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface NavigationDao extends BaseMapper<NavigationEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/OrderConsigneeInfoDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.OrderConsigneeInfoEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 订单收货人信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface OrderConsigneeInfoDao extends BaseMapper<OrderConsigneeInfoEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/OrderDetailDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.OrderDetailEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 订单详情
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface OrderDetailDao extends BaseMapper<OrderDetailEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/OrderExpressInfoDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.study.mall.entity.OrderExpressInfoEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 订单物流信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-10-11 22:51:33
+ */
+@Mapper
+public interface OrderExpressInfoDao extends BaseMapper<OrderExpressInfoEntity> {
+	
+}

+ 25 - 0
src/main/java/com/study/mall/dao/OrderInfoDao.java

@@ -0,0 +1,25 @@
+package com.study.mall.dao;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.study.mall.dto.AdminOrderQueryDTO;
+import com.study.mall.entity.OrderInfoEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.study.mall.vo.OrderDetailForAdminVO;
+import com.study.mall.vo.OrderListForAdminVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 订单
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface OrderInfoDao extends BaseMapper<OrderInfoEntity> {
+
+    IPage<OrderListForAdminVO> adminPage(@Param("page") IPage<OrderInfoEntity> page, @Param("queryDTO") AdminOrderQueryDTO queryDTO);
+
+    OrderDetailForAdminVO orderDetailForAdmin(@Param("orderId") Long orderId);
+}

+ 17 - 0
src/main/java/com/study/mall/dao/PayOrderDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.PayOrderEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 支付订单
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface PayOrderDao extends BaseMapper<PayOrderEntity> {
+	
+}

+ 24 - 0
src/main/java/com/study/mall/dao/PayRefundDao.java

@@ -0,0 +1,24 @@
+package com.study.mall.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.study.mall.dto.PayRefundQueryDTO;
+import com.study.mall.entity.PayRefundEntity;
+import com.study.mall.vo.PayRefundVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 支付退款
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface PayRefundDao extends BaseMapper<PayRefundEntity> {
+
+    IPage<PayRefundVO> pageByCondition(@Param("page") IPage<PayRefundEntity> page, @Param("queryDTO") PayRefundQueryDTO queryDTO);
+
+    PayRefundVO selectByPayOrderId(@Param("payOrderId") Long payOrderId);
+}

+ 17 - 0
src/main/java/com/study/mall/dao/SearchHotDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.SearchHotEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 热门搜索
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface SearchHotDao extends BaseMapper<SearchHotEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/ServiceTagDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.ServiceTagEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 服务标签
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface ServiceTagDao extends BaseMapper<ServiceTagEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/UserAddressDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.UserAddressEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 用户地址
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface UserAddressDao extends BaseMapper<UserAddressEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/UserGoodsCollectDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.UserGoodsCollectEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 用户商品收藏
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface UserGoodsCollectDao extends BaseMapper<UserGoodsCollectEntity> {
+	
+}

+ 17 - 0
src/main/java/com/study/mall/dao/UserGoodsFootprintDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.UserGoodsFootprintEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 用户商品足迹
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface UserGoodsFootprintDao extends BaseMapper<UserGoodsFootprintEntity> {
+	
+}

+ 16 - 0
src/main/java/com/study/mall/dao/UserInfoDao.java

@@ -0,0 +1,16 @@
+package com.study.mall.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.study.mall.entity.UserInfoEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 用户信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface UserInfoDao extends BaseMapper<UserInfoEntity> {
+}

+ 17 - 0
src/main/java/com/study/mall/dao/UserSearchHistoryDao.java

@@ -0,0 +1,17 @@
+package com.study.mall.dao;
+
+import com.study.mall.entity.UserSearchHistoryEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 搜索历史记录
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Mapper
+public interface UserSearchHistoryDao extends BaseMapper<UserSearchHistoryEntity> {
+	
+}

+ 26 - 0
src/main/java/com/study/mall/dto/AdminLoginDTO.java

@@ -0,0 +1,26 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 管理员登录
+ *
+ * @auther: codingliang
+ * @date: 2023-09-07 20:48
+ * @description: 管理员登录dto
+ */
+@Data
+public class AdminLoginDTO {
+    /**
+     * 用户名
+     */
+    @NotBlank(message = "用户名不能为空")
+    private String username;
+    /**
+     * 密码
+     */
+    @NotBlank(message = "密码不能为空")
+    private String password;
+}

+ 55 - 0
src/main/java/com/study/mall/dto/AdminOrderQueryDTO.java

@@ -0,0 +1,55 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+/**
+ * 管理端订单查询dto
+ *
+ * @auther: codingliang
+ * @date: 2023-09-04 21:26
+ * @description: 管理端订单查询dto
+ */
+@Data
+public class AdminOrderQueryDTO {
+    /**
+     * 状态,精确搜索 1等待付款、2等待发货、3等待收货、4等待评论、5完成、7全部
+     */
+    private String state;
+    /**
+     * 订单号,模糊搜索
+     */
+    private String orderNo;
+    /**
+     * 下单人姓名,模糊搜索
+     */
+    private String userName;
+    /**
+     * 下单人手机号,精确搜索
+     */
+    private String userPhone;
+    /**
+     * 收货人姓名,模糊搜索
+     */
+    private String orderConsignee;
+    /**
+     * 收货人手机号,精确搜索
+     */
+    private String orderConsigneeTel;
+    /**
+     * 支付方式 1 微信支付 2余额支付 3支付宝 4网银 5其他
+     */
+    private String payWay;
+    /**
+     * 下单时间-开始 yyyy-MM-dd
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startTime;
+    /**
+     * 下单时间-结束
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endTime;
+}

+ 37 - 0
src/main/java/com/study/mall/dto/ConfirmOrderDTO.java

@@ -0,0 +1,37 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+/**
+ * 确认订单
+ *
+ * @auther: codingliang
+ * @date: 2023/7/25 22:27
+ * @description: 确认订单
+ */
+@Data
+public class ConfirmOrderDTO implements Serializable {
+
+    /**
+     * 类型 1直接购买订单确认、2购物创建订单确认
+     */
+    @NotBlank(message = "类型不能为空")
+    @Pattern(regexp = "(1|2)", message = "类型只能为1或者2")
+    private String type;
+    /**
+     * 商品id type为1时该值不能为空
+     */
+    private Long goodId;
+    /**
+     * skuId type为1且商品开启sku时该值不能为空
+     */
+    private Long skuId;
+    /**
+     * 购买数量 type为1时该值不能为空
+     */
+    private Integer num;
+}

+ 81 - 0
src/main/java/com/study/mall/dto/CreateOrderDTO.java

@@ -0,0 +1,81 @@
+package com.study.mall.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 创建订单req
+ *
+ * @auther: codingliang
+ * @date: 2023/7/24 23:44
+ * @description: 创建订单req
+ */
+@Data
+public class CreateOrderDTO implements Serializable {
+    /**
+     * 提交令牌(防重提交)
+     */
+    @NotBlank(message = "防重令牌不能为空")
+    private String submitToken;
+    /**
+     * 用户地址id
+     */
+    @NotNull(message = "用户地址id不能为空")
+    private Long userAddressId;
+    /**
+     * 买家备注
+     */
+    private String buyerRemark;
+    /**
+     * 订单实际付款金额 用于价格校验
+     */
+    @NotNull(message = "订单价格不能为空")
+    private BigDecimal orderPaidAmt;
+    /**
+     * 提交类型 1直接创建订单、2购物车创建订单
+     */
+    @NotNull(message = "提交类型不能为空")
+    @Pattern(regexp = "(1|2)", message = "提交类型只能为1或者2")
+    private String submitType;
+    /**
+     * 订单来源;1小程序 2公众号 3其它
+     */
+    @NotNull(message = "订单来源不能为空")
+    @Pattern(regexp = "(1|2|3)", message = "订单来源只能为1、2或者3")
+    private String orderFrom;
+    /**
+     * 商品列表
+     */
+    @NotNull(message = "商品信息不能为空")
+    @Size(min = 1, message = "商品信息不能为空")
+    private List<CreateOrderDetailDTO> orderDetails;
+
+    @Data
+    public static class CreateOrderDetailDTO {
+        /**
+         * key 程序使用
+         */
+        @JsonIgnore
+        private String key;
+        /**
+         * 商品id
+         */
+        private Long goodsId;
+        /**
+         * skuId 商品开启sku后该值不能为空
+         */
+        private Long skuId;
+        /**
+         * 商品数量
+         */
+        private Integer goodsCount;
+    }
+}

+ 39 - 0
src/main/java/com/study/mall/dto/GoodHotOrLimitedChangeDTO.java

@@ -0,0 +1,39 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.util.List;
+
+/**
+ * 商品热门或限时精选改变dto
+ *
+ * @auther: codingliang
+ * @date: 2023-10-19 22:36
+ * @description: 商品热门或限时精选改变dto
+ */
+@Data
+public class GoodHotOrLimitedChangeDTO {
+
+    /**
+     * 操作种类:1热门推荐、2限时精选
+     */
+    @NotBlank(message = "操作种类不能为空")
+    @Pattern(regexp = "(1|2)", message = "操作种类只能为1或2")
+    private String action;
+    /**
+     * 商品id集合
+     */
+    @NotNull(message = "商品id集合不能为空")
+    @Size(min = 1, message = "商品id集合不能为空")
+    private List<Long> goodIds;
+    /**
+     * 操作类型:1新增、2取消
+     */
+    @NotBlank(message = "操作类型不能为空")
+    @Pattern(regexp = "(0|1)", message = "操作类型只能为0或1")
+    private String type;
+}

+ 43 - 0
src/main/java/com/study/mall/dto/GoodsCommentQueryDTO.java

@@ -0,0 +1,43 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+/**
+ * 订单评论查询dto
+ *
+ * @auther: codingliang
+ * @date: 2023-09-07 21:40
+ * @description: 订单评论查询dto
+ */
+@Data
+public class GoodsCommentQueryDTO {
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+    /**
+     * 商品id
+     */
+    private Long goodsId;
+    /**
+     * skuId
+     */
+    private Long skuId;
+    /**
+     * 用户id
+     */
+    private String userId;
+    /**
+     * 是否有图;1是 2否
+     */
+    private String hasImg;
+    /**
+     * 评论类别;1差评 2中评 3好评
+     */
+    private String reviewType;
+    /**
+     * 评论状态,0隐藏 1显示
+     */
+    private String state;
+}

+ 155 - 0
src/main/java/com/study/mall/dto/GoodsDetailDTO.java

@@ -0,0 +1,155 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 商品详情dto
+ *
+ * @auther: codingliang
+ * @date: 2023-09-03 21:28
+ * @description: 商品详情dto
+ */
+@Data
+public class GoodsDetailDTO {
+    /**
+     * 商品id,修改时不能为空
+     */
+    private Long id;
+    /**
+     * 一级分类id
+     */
+    @NotNull(message = "一级分类id不能为空")
+    private Long categoryOneId;
+    /**
+     * 二级分类id
+     */
+    @NotNull(message = "二级分类id不能为空")
+    private Long categoryTwoId;
+    /**
+     * 商品名称
+     */
+    @NotBlank(message = "商品名称不能为空")
+    private String name;
+    /**
+     * 排序
+     */
+    @NotNull(message = "排序不能为空")
+    private Integer sort;
+    /**
+     * 是否热门推荐;0否1是
+     */
+    @NotBlank(message = "是否热门推荐不能为空")
+    @Pattern(regexp = "(0|1)", message = "是否热门推荐只能为0,1")
+    private String hot;
+    /**
+     * 是否限时精选;0否1是
+     */
+    @NotBlank(message = "是否限时精选不能为空")
+    @Pattern(regexp = "(0|1)", message = "是否限时精选只能为0,1")
+    private String limited;
+    /**
+     * 商品状态;0下架 1在售 2 待审核
+     */
+    @NotBlank(message = "商品状态不能为空")
+    @Pattern(regexp = "(0|1|2)", message = "商品状态只能为0,1或2")
+    private String state;
+    /**
+     * 商品图片地址,第一张图片为商品主图;多张图片使用,分割
+     */
+    @NotBlank(message = "商品图片不能为空")
+    private String imgs;
+    /**
+     * 销售价格
+     */
+    @NotNull(message = "销售价格不能为空")
+    @Min(value = 0, message = "销售价格不能小于0")
+    private BigDecimal price;
+    /**
+     * 市场价格
+     */
+    @NotNull(message = "市场价格不能为空")
+    @Min(value = 0, message = "市场价格不能小于0")
+    private BigDecimal marketPrice;
+    /**
+     * 限购数量,0为不限购
+     */
+    @NotNull(message = "限购数量不能为空")
+    private Integer limit;
+    /**
+     * 库存数量
+     */
+    @NotNull(message = "库存数量不能为空")
+    private Integer stockNum;
+    /**
+     * 收藏量
+     */
+    @NotNull(message = "收藏量不能为空")
+    private Integer collectCnt;
+    /**
+     * 已售量
+     */
+    @NotNull(message = "已售量不能为空")
+    private Integer saleCnt;
+    /**
+     * 浏览量
+     */
+    @NotNull(message = "浏览量不能为空")
+    private Integer visitCnt;
+    /**
+     * 分享量
+     */
+    @NotNull(message = "分享量不能为空")
+    private Integer shareCnt;
+    /**
+     * 是否显示收藏数量;0隐藏 1显示
+     */
+    @NotBlank(message = "是否显示收藏数量不能为空")
+    @Pattern(regexp = "(0|1)", message = "是否显示收藏数量只能为0,1")
+    private String showCollect;
+    /**
+     * 是否显示已售数量;0隐藏 1显示
+     */
+    @NotBlank(message = "是否显示已售数量不能为空")
+    @Pattern(regexp = "(0|1)", message = "是否显示已售数量只能为0,1")
+    private String showSale;
+    /**
+     * 是否显示访问数量;0隐藏 1显示
+     */
+    @NotBlank(message = "是否显示访问数量不能为空")
+    @Pattern(regexp = "(0|1)", message = "是否显示访问数量只能为0,1")
+    private String showVisit;
+    /**
+     * 是否显示分享数量;0隐藏 1显示
+     */
+    @NotBlank(message = "是否显示分享数量不能为空")
+    @Pattern(regexp = "(0|1)", message = "是否显示分享数量只能为0,1")
+    private String showShare;
+    /**
+     * 商品详情
+     */
+    @NotBlank(message = "商品详情不能为空")
+    private String desc;
+    /**
+     * 服务标签id集合
+     */
+    private List<Long> serviceTagIds;
+    /**
+     * 是否开启sku;1是0否
+     */
+    @NotBlank(message = "是否开启sku不能为空")
+    @Pattern(regexp = "(0|1)", message = "是否开启sku只能为0、1")
+    private String enableSku;
+    /**
+     * sku集合,开启sku后该值不能为空
+     */
+    @Valid
+    private List<SukInfoDTO> skus;
+}

+ 36 - 0
src/main/java/com/study/mall/dto/OrderDeliveryDTO.java

@@ -0,0 +1,36 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 订单发货dto
+ *
+ * @auther: codingliang
+ * @date: 2023-09-04 22:17
+ * @description: 订单发货dto
+ */
+@Data
+public class OrderDeliveryDTO {
+    /**
+     * 订单发货物流id,修改时不能为空
+     */
+    private Long orderExpressId;
+    /**
+     * 订单id
+     */
+    @NotNull(message = "订单id不能为空")
+    private Long orderId;
+    /**
+     * 快递id
+     */
+    @NotNull(message = "快递id不能为空")
+    private Long expressId;
+    /**
+     * 快递单号
+     */
+    @NotBlank(message = "快递单号不能为空")
+    private String expressNo;
+}

+ 30 - 0
src/main/java/com/study/mall/dto/OrderModifyPriceDTO.java

@@ -0,0 +1,30 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/**
+ * 订单修改价格dto
+ *
+ * @auther: codingliang
+ * @date: 2023-10-16 22:18
+ * @description: 订单修改价格dto
+ */
+@Data
+public class OrderModifyPriceDTO {
+
+    /**
+     * 订单id
+     */
+    @NotNull(message = "订单id不能为空")
+    public Long orderId;
+    /**
+     * 新价格
+     */
+    @NotNull(message = "新价格不能为空")
+    @DecimalMin(value = "0.01", message = "新价格不能小于0.01")
+    private BigDecimal newPrice;
+}

+ 37 - 0
src/main/java/com/study/mall/dto/OrderRefundDTO.java

@@ -0,0 +1,37 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/**
+ * 订单退款dto
+ *
+ * @auther: codingliang
+ * @date: 2023-12-06 10:30
+ * @description: 订单退款dto
+ */
+@Data
+public class OrderRefundDTO {
+    /**
+     * 货物状态
+     */
+    @NotBlank(message = "货物状态不能为空")
+    private String goodsState;
+    /**
+     * 退款原因
+     */
+    @NotBlank(message = "退款原因不能为空")
+    private String refundReason;
+    /**
+     * 退款金额
+     */
+    @NotNull(message = "退款金额不能为空")
+    private BigDecimal refundAmt;
+    /**
+     * 退款说明
+     */
+    private String remark;
+}

+ 31 - 0
src/main/java/com/study/mall/dto/OrderStatisticsQueryDTO.java

@@ -0,0 +1,31 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDate;
+
+/**
+ * 订单统计查询dto
+ *
+ * @auther: codingliang
+ * @date: 2023-11-29 21:40
+ * @description: 订单总金额查询dto
+ */
+@Data
+public class OrderStatisticsQueryDTO {
+    /**
+     * 订单状态 详情查看接口注释
+     */
+    private String state;
+    /**
+     * 下单时间-开始 yyyy-MM-dd
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate startTime;
+    /**
+     * 下单时间-结束
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate endTime;
+}

+ 46 - 0
src/main/java/com/study/mall/dto/PayOrderQueryDTO.java

@@ -0,0 +1,46 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+/**
+ * 支付订单查询dto
+ *
+ * @auther: codingliang
+ * @date: 2023-10-18 23:18
+ * @description: 支付订单查询dto
+ */
+@Data
+public class PayOrderQueryDTO {
+    /**
+     * 支付编号
+     */
+    private String payNo;
+    /**
+     * 订单id
+     */
+    private Long orderId;
+    /**
+     * 用户id
+     */
+    private String userId;
+    /**
+     * 支付用户id
+     */
+    private String thirdUserId;
+    /**
+     * 第三方支付订单id
+     */
+    private String payId;
+    /**
+     * 支付途径;1 微信支付 2余额支付 3支付宝 4网银 5其他
+     */
+    private String payWay;
+    /**
+     * 状态;1 待付款 2已付款
+     */
+    private String state;
+    /**
+     * 退款标识;0否、1是
+     */
+    private String refundFlag;
+}

+ 30 - 0
src/main/java/com/study/mall/dto/PayRefundQueryDTO.java

@@ -0,0 +1,30 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+/**
+ * 支付退款查询dto
+ *
+ * @auther: codingliang
+ * @date: 2023-10-18 23:25
+ * @description: 支付退款查询dto
+ */
+@Data
+public class PayRefundQueryDTO {
+    /**
+     * 支付订单id
+     */
+    private Long payOrderId;
+    /**
+     * 支付订单号
+     */
+    private String payNo;
+    /**
+     * 退款单号
+     */
+    private String refundNo;
+    /**
+     * 退款状态 1申请成功、2退款成功、3退款异常
+     */
+    private String state;
+}

+ 26 - 0
src/main/java/com/study/mall/dto/ServiceTagQueryDTO.java

@@ -0,0 +1,26 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.Pattern;
+
+/**
+ * 服务标签查询dto
+ *
+ * @auther: codingliang
+ * @date: 2023-11-21 13:39
+ * @description: 服务标签查询dto
+ */
+@Data
+public class ServiceTagQueryDTO {
+
+    /**
+     * 标签名称,模糊查询
+     */
+    private String tagName;
+    /**
+     * 状态; 0禁用 1启用 2全部
+     */
+    @Pattern(regexp = "(0|1|2)", message = "状态只能为1、2或0")
+    private String state;
+}

+ 41 - 0
src/main/java/com/study/mall/dto/SkuSaleAttrDTO.java

@@ -0,0 +1,41 @@
+package com.study.mall.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * sku销售属性
+ *
+ * @auther: codingliang
+ * @date: 2023-11-23 8:14
+ * @description: sku销售属性
+ */
+@Data
+public class SkuSaleAttrDTO {
+    /**
+     * 属性id,修改时不能为空
+     */
+    private Long attrId;
+    /**
+     * skuId
+     */
+    private Long skuId;
+    /**
+     * 属性名称
+     */
+    @NotBlank(message = "属性名称不能为空")
+    private String attrName;
+    /**
+     * 属性值
+     */
+    @NotBlank(message = "属性值不能为空")
+    private String attrValue;
+
+    /**
+     * 顺序,不支持页面修改
+     */
+    @JsonIgnore
+    private Integer attrSort;
+}

+ 70 - 0
src/main/java/com/study/mall/dto/SukInfoDTO.java

@@ -0,0 +1,70 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * sku信息
+ *
+ * @auther: codingliang
+ * @date: 2023-11-22 23:38
+ * @description: sku信息
+ */
+@Data
+public class SukInfoDTO {
+    /**
+     * skuId,修改时不能为空
+     */
+    private Long skuId;
+    /**
+     * sku名称 销售属性值使用 + 拼接
+     */
+    @NotBlank(message = "sku名称不能为空")
+    private String skuName;
+    /**
+     * sku描述
+     */
+    private String skuDesc;
+    /**
+     * sku图片
+     */
+    @NotBlank(message = "sku图片不能为空")
+    private String skuImg;
+    /**
+     * 销售价格
+     */
+    @NotNull(message = "销售价格不能为空")
+    private BigDecimal price;
+    /**
+     * 市场价格
+     */
+    @NotNull(message = "市场价格不能为空")
+    private BigDecimal marketPrice;
+    /**
+     * 库存
+     */
+    @NotNull(message = "库存不能为空")
+    @Min(value = 1, message = "库存不能小于1")
+    private Long stockNum;
+    /**
+     * 状态;0不可售 1可售
+     */
+    @NotBlank(message = "状态不能为空")
+    @Pattern(regexp = "(0|1)", message = "状态只能为0或1")
+    private String state;
+    /**
+     * 销售属性
+     */
+    @Valid
+    @NotNull(message = "销售属性不能为空")
+    @Size(min = 1, message = "销售属性不能为空")
+    private List<SkuSaleAttrDTO> saleAttrs;
+}

+ 40 - 0
src/main/java/com/study/mall/dto/UserInfoUpdateDTO.java

@@ -0,0 +1,40 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+
+/**
+ * 用户信息更新dto
+ *
+ * @auther: codingliang
+ * @date: 2023-09-01 14:22
+ * @description: 用户信息更新dto
+ */
+@Data
+public class UserInfoUpdateDTO {
+
+    /**
+     * 昵称
+     */
+    @NotBlank(message = "昵称不能为空")
+    private String nickname;
+    /**
+     * 用户性别; 0未知 1 男性 2 女性
+     */
+    @NotBlank(message = "性别不能为空")
+    @Pattern(regexp = "(1|2)", message = "性别只能为1或2")
+    private String gender;
+    /**
+     * 邮箱
+     */
+    @NotBlank(message = "邮箱不能为空")
+    @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$", message = "邮箱格式错误")
+    private String email;
+    /**
+     * 头像地址
+     */
+    @NotBlank(message = "头像地址不能为空")
+    private String avatar;
+}

+ 33 - 0
src/main/java/com/study/mall/dto/UserPhoneInfoUpdateDTO.java

@@ -0,0 +1,33 @@
+package com.study.mall.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+
+/**
+ * 用户手机号信息更新dto
+ *
+ * @auther: codingliang
+ * @date: 2023-09-01 14:11
+ * @description: 用户手机号信息更新dto
+ */
+@Data
+public class UserPhoneInfoUpdateDTO {
+
+    /**
+     * 新手机号码
+     */
+    @NotBlank(message = "手机号码不能为空")
+    private String newPhone;
+    /**
+     * 类别 1微信自动获取手机号 2短信验证码认证
+     */
+    @NotBlank(message = "类别不能为空")
+    @Pattern(regexp = "(1|2)", message = "类别只能为1或2")
+    private String type;
+    /**
+     * 验证码,type为2时该值不能为空
+     */
+    private String code;
+}

+ 42 - 0
src/main/java/com/study/mall/entity/AboutShopEntity.java

@@ -0,0 +1,42 @@
+package com.study.mall.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+/**
+ * 关于我
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Data
+@TableName("mall_about_shop")
+public class AboutShopEntity extends BaseOperateEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * id
+	 */
+	@TableId
+	private Long id;
+
+	/**
+	 * 类型;1网页 2内容
+	 */
+	@NotBlank(message = "类型不能为空")
+	private String type;
+	/**
+	 * 网页地址;type为1时必填
+	 */
+	private String url;
+	/**
+	 * 富文本内容;type为2时必填
+	 */
+	private String descInfo;
+
+}

+ 72 - 0
src/main/java/com/study/mall/entity/AdminInfoEntity.java

@@ -0,0 +1,72 @@
+package com.study.mall.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+/**
+ * 管理员信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Data
+@TableName("mall_admin_info")
+public class AdminInfoEntity extends BaseOperateEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * id,修改时不能为空
+	 */
+	@TableId
+	private Long id;
+	/**
+	 * 用户名称
+	 */
+	@NotBlank(message = "用户名称不能为空")
+	private String username;
+	/**
+	 * 手机号
+	 */
+	@NotBlank(message = "手机号不能为空")
+	private String phone;
+	/**
+	 * 头像
+	 */
+	@NotBlank(message = "头像不能为空")
+	private String avatar;
+	/**
+	 * 密码
+	 */
+	private String password;
+	/**
+	 * 状态;0禁用 1 正常
+	 */
+	@NotBlank(message = "状态不能为空")
+	@Pattern(regexp = "(0|1)", message = "状态只能为0或1")
+	private String state;
+
+	/**
+	 * 性别;1 男性 2 女性
+	 */
+	@NotBlank(message = "性别不能为空")
+	@Pattern(regexp = "(0|1)", message = "性别只能为0或1")
+	private String gender;
+
+	@JsonIgnore
+	public String getPassword() {
+		return password;
+	}
+
+	@JsonProperty
+	public void setPassword(String password) {
+		this.password = password;
+	}
+}

+ 35 - 0
src/main/java/com/study/mall/entity/BaseOperateEntity.java

@@ -0,0 +1,35 @@
+package com.study.mall.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 基本操作类
+ *
+ * @auther: codingliang
+ * @date: 2023-09-01 10:32
+ * @description: 基本操作类,记录更新时间、创建时间、更新人、创建人
+ */
+@Data
+public class BaseOperateEntity {
+    /**
+     * 创建人
+     */
+    private Long createBy;
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+    /**
+     * 更新人
+     */
+    private Long updateBy;
+}

+ 35 - 0
src/main/java/com/study/mall/entity/BrandCategoryRelationEntity.java

@@ -0,0 +1,35 @@
+package com.study.mall.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 品牌分类
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Data
+@TableName("mall_brand_category_relation")
+public class BrandCategoryRelationEntity extends BaseOperateEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * id
+	 */
+	@TableId
+	private Long id;
+	/**
+	 * 品牌id
+	 */
+	private Long brandId;
+	/**
+	 * 一级分类id
+	 */
+	private Long goodsCategoryId;
+
+}

+ 35 - 0
src/main/java/com/study/mall/entity/BrandInfoEntity.java

@@ -0,0 +1,35 @@
+package com.study.mall.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 品牌信息
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2023-09-01 09:43:35
+ */
+@Data
+@TableName("mall_brand_info")
+public class BrandInfoEntity extends BaseOperateEntity implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * id
+	 */
+	@TableId
+	private Long id;
+	/**
+	 * 品牌名称
+	 */
+	private String name;
+	/**
+	 * 品牌图标
+	 */
+	private String icon;
+
+}

+ 0 - 0
src/main/java/com/study/mall/entity/CarouselEntity.java


Some files were not shown because too many files changed in this diff