refactor(user-center): 移除收货地址管理相关代码和配置

This commit is contained in:
ylweng
2025-09-12 00:08:04 +08:00
parent 33c138c839
commit d207610009
79 changed files with 0 additions and 4916 deletions

View File

@@ -1,100 +0,0 @@
# xlxumu Java后端项目
## 项目结构
```
backend-java/
├── api/ # API定义
├── common/ # 公共模块
├── config-server/ # 配置服务器
├── docs/ # 文档
├── gateway/ # 网关服务
├── registry/ # 服务注册中心
├── scripts/ # 脚本
└── services/ # 微服务
├── ai-service/ # AI服务
├── data-platform-service/ # 数据平台服务
├── farming-service/ # 农业管理服务 (端口: 8081)
├── finance-service/ # 金融服务
├── government-service/ # 政府监管服务
├── mall-service/ # 商城服务
├── trade-service/ # 交易服务
└── user-center-service/ # 用户中心服务 (端口: 8082)
```
## 技术栈
- Java 8+
- Spring Boot 2.7.x
- Spring Cloud 2021.x
- Maven 3.8.x
- MySQL 8.0
## 环境要求
1. JDK 8或更高版本
2. Maven 3.8或更高版本
3. MySQL 8.0
## 快速开始
### 1. 安装依赖
```bash
# 在backend-java根目录下执行
mvn clean install
```
### 2. 配置数据库
确保MySQL服务正在运行并创建相应的数据库
```sql
CREATE DATABASE IF NOT EXISTS xlxumu_farming;
CREATE DATABASE IF NOT EXISTS xlxumu_user;
```
### 3. 运行服务
#### 运行farming-service
```bash
cd services/farming-service
mvn spring-boot:run
```
服务将在 http://localhost:8081 启动
#### 运行user-center-service
```bash
cd services/user-center-service
mvn spring-boot:run
```
服务将在 http://localhost:8082 启动
## 服务端口分配
| 服务名称 | 端口 |
|---------|------|
| farming-service | 8081 |
| user-center-service | 8082 |
## 开发指南
1. 所有微服务都继承自根pom.xml
2. 每个服务都有独立的数据库
3. 使用Spring Boot Actuator进行健康检查
4. 使用Spring Cloud Gateway作为API网关
## 构建和部署
```bash
# 构建所有服务
mvn clean package
# 构建单个服务
cd services/farming-service
mvn clean package
```

View File

@@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<name>XlMuMu Backend Java</name>
<description>锡林郭勒盟地区智慧养殖产业平台后端Java服务</description>
<modules>
<module>api</module>
<module>gateway</module>
<module>registry</module>
<module>config-server</module>
<module>services</module>
<module>common</module>
</modules>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.boot.version>2.7.5</spring.boot.version>
<spring.cloud.version>2021.0.5</spring.cloud.version>
</properties>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
</parent>
<artifactId=ai-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name=ai-service</name>
<description>AI能力服务</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.xlxumu.ai;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AIServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AIServiceApplication.class, args);
}
}

View File

@@ -1,10 +0,0 @@
server.port=8089
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_ai?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>data-platform-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>data-platform-service</name>
<description>数据平台服务</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.xlxumu.dataplatform;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DataPlatformServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DataPlatformServiceApplication.class, args);
}
}

View File

@@ -1,10 +0,0 @@
server.port=8085
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_data?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>farming-service</artifactId>
<name>Farming Service</name>
<description>养殖管理服务</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.xlxumu.farm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FarmingServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FarmingServiceApplication.class, args);
}
}

View File

@@ -1,10 +0,0 @@
server.port=8081
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_farming?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,10 +0,0 @@
server.port=8081
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_farming?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,3 +0,0 @@
artifactId=farming-service
groupId=com.xlxumu
version=1.0.0

View File

@@ -1 +0,0 @@
/Users/ainongkeji/code/vue/xlxumu/backend-java/services/farming-service/src/main/java/com/xlxumu/farm/FarmingServiceApplication.java

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>finance-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>finance-service</name>
<description>金融服务</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.xlxumu.finance;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FinanceServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FinanceServiceApplication.class, args);
}
}

View File

@@ -1,10 +0,0 @@
server.port=8084
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_finance?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
</parent>
<artifactId=government-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name=government-service</name>
<description>政务服务</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.xlxumu.government;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GovernmentServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GovernmentServiceApplication.class, args);
}
}

View File

@@ -1,10 +0,0 @@
server.port=8086
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_government?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
</parent>
<artifactId=mall-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name=mall-service</name>
<description>商城服务</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

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

View File

@@ -1,10 +0,0 @@
server.port=8088
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_mall?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>trade-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>trade-service</name>
<description>交易服务</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.xlxumu.trade;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TradeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(TradeServiceApplication.class, args);
}
}

View File

@@ -1,10 +0,0 @@
server.port=8083
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_trade?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xlxumu</groupId>
<artifactId>backend-java</artifactId>
<version>1.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>user-center-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<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-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.xlxumu.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UserCenterApplication {
public static void main(String[] args) {
SpringApplication.run(UserCenterApplication.class, args);
}
}

View File

@@ -1,47 +0,0 @@
package com.xlxumu.user.config;
import com.xlxumu.user.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
// 获取请求头中的Authorization字段
String authorizationHeader = request.getHeader("Authorization");
// 检查Authorization字段是否存在且以"Bearer "开头
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
// 提取JWT令牌
String token = authorizationHeader.substring(7);
try {
// 验证令牌
Long userId = jwtUtil.getUserIdFromToken(token);
// 将用户ID添加到请求属性中以便在控制器中使用
request.setAttribute("userId", userId);
return true;
} catch (Exception e) {
// 令牌无效
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"code\": 401, \"message\": \"无效的访问令牌\"}");
return false;
}
} else {
// 缺少Authorization字段或格式不正确
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"code\": 401, \"message\": \"缺少访问令牌\"}");
return false;
}
}
}

View File

@@ -1,22 +0,0 @@
package com.xlxumu.user.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册JWT拦截器拦截除了注册和登录之外的所有API请求
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/users/register")
.excludePathPatterns("/api/users/login");
}
}

View File

@@ -1,175 +0,0 @@
package com.xlxumu.user.controller;
import com.xlxumu.user.entity.Address;
import com.xlxumu.user.service.AddressService;
import com.xlxumu.user.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 收货地址控制器
* 处理收货地址相关的HTTP请求
*
* @author xlxumu
* @since 2024-01-15
*/
@RestController
@RequestMapping("/api/addresses")
public class AddressController {
@Autowired
private AddressService addressService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
/**
* 创建收货地址接口
*/
@PostMapping
public ResponseEntity<Map<String, Object>> createAddress(
HttpServletRequest request,
@RequestBody Map<String, Object> requestData) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
String name = (String) requestData.get("name");
String phone = (String) requestData.get("phone");
String province = (String) requestData.get("province");
String city = (String) requestData.get("city");
String district = (String) requestData.get("district");
String detailAddress = (String) requestData.get("detailAddress");
Boolean isDefault = (Boolean) requestData.get("isDefault");
Address address = addressService.createAddress(userId, name, phone, province, city, district, detailAddress, isDefault);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "地址创建成功");
response.put("data", address);
return ResponseEntity.ok(response);
}
/**
* 获取收货地址列表接口
*/
@GetMapping
public ResponseEntity<Map<String, Object>> getAddressList(HttpServletRequest request) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
List<Address> addresses = addressService.getAddressList(userId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", addresses);
return ResponseEntity.ok(response);
}
/**
* 获取收货地址详情接口
*/
@GetMapping("/{addressId}")
public ResponseEntity<Map<String, Object>> getAddressDetail(
HttpServletRequest request,
@PathVariable Long addressId) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
Address address = addressService.getAddressDetail(userId, addressId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", address);
return ResponseEntity.ok(response);
}
/**
* 更新收货地址接口
*/
@PutMapping("/{addressId}")
public ResponseEntity<Map<String, Object>> updateAddress(
HttpServletRequest request,
@PathVariable Long addressId,
@RequestBody Map<String, Object> requestData) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
String name = (String) requestData.get("name");
String phone = (String) requestData.get("phone");
String province = (String) requestData.get("province");
String city = (String) requestData.get("city");
String district = (String) requestData.get("district");
String detailAddress = (String) requestData.get("detailAddress");
Boolean isDefault = (Boolean) requestData.get("isDefault");
Address address = addressService.updateAddress(userId, addressId, name, phone, province, city, district, detailAddress, isDefault);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "地址更新成功");
response.put("data", address);
return ResponseEntity.ok(response);
}
/**
* 删除收货地址接口
*/
@DeleteMapping("/{addressId}")
public ResponseEntity<Map<String, Object>> deleteAddress(
HttpServletRequest request,
@PathVariable Long addressId) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
addressService.deleteAddress(userId, addressId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "地址删除成功");
return ResponseEntity.ok(response);
}
}

View File

@@ -1,90 +0,0 @@
package com.xlxumu.user.controller;
import com.xlxumu.user.entity.Feedback;
import com.xlxumu.user.service.FeedbackService;
import com.xlxumu.user.service.PointsService;
import com.xlxumu.user.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 用户反馈控制器
* 处理用户反馈相关的HTTP请求
*
* @author xlxumu
* @since 2024-01-15
*/
@RestController
@RequestMapping("/api/feedback")
public class FeedbackController {
@Autowired
private FeedbackService feedbackService;
@Autowired
private PointsService pointsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
/**
* 提交反馈接口
*/
@PostMapping
public ResponseEntity<Map<String, Object>> submitFeedback(
HttpServletRequest request,
@RequestBody Map<String, String> requestData) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
String title = requestData.get("title");
String content = requestData.get("content");
String type = requestData.get("type");
String contactInfo = requestData.get("contactInfo");
Feedback feedback = feedbackService.submitFeedback(userId, title, content, type, contactInfo);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "反馈提交成功");
response.put("data", feedback);
return ResponseEntity.ok(response);
}
/**
* 获取反馈列表接口
*/
@GetMapping
public ResponseEntity<Map<String, Object>> getFeedbackList(HttpServletRequest request) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
List<Feedback> feedbacks = feedbackService.getFeedbackList(userId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", feedbacks);
return ResponseEntity.ok(response);
}
}

View File

@@ -1,19 +0,0 @@
package com.xlxumu.user.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 等级管理控制器
* 提供用户等级查询、等级列表查询等API接口
*
* @author xlxumu
* @since 2024-01-15
*/
@RestController
@RequestMapping("/api/v1/users")
public class LevelController {
// TODO: 实现获取用户当前等级接口
// TODO: 实现获取等级列表接口
}

View File

@@ -1,109 +0,0 @@
package com.xlxumu.user.controller;
import com.xlxumu.user.entity.Message;
import com.xlxumu.user.service.MessageService;
import com.xlxumu.user.service.PointsService;
import com.xlxumu.user.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 消息通知控制器
* 处理用户消息相关的HTTP请求
*
* @author xlxumu
* @since 2024-01-15
*/
@RestController
@RequestMapping("/api/messages")
public class MessageController {
@Autowired
private MessageService messageService;
@Autowired
private PointsService pointsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
/**
* 获取消息列表接口
*/
@GetMapping
public ResponseEntity<Map<String, Object>> getMessageList(HttpServletRequest request) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
List<Message> messages = messageService.getMessageList(userId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", messages);
return ResponseEntity.ok(response);
}
/**
* 标记消息为已读接口
*/
@PutMapping("/{messageId}/read")
public ResponseEntity<Map<String, Object>> markMessageAsRead(
HttpServletRequest request,
@PathVariable Long messageId) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
messageService.markMessageAsRead(messageId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "标记成功");
return ResponseEntity.ok(response);
}
/**
* 删除消息接口
*/
@DeleteMapping("/{messageId}")
public ResponseEntity<Map<String, Object>> deleteMessage(
HttpServletRequest request,
@PathVariable Long messageId) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
messageService.deleteMessage(messageId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "删除成功");
return ResponseEntity.ok(response);
}
}

View File

@@ -1,123 +0,0 @@
package com.xlxumu.user.controller;
import com.xlxumu.user.entity.Level;
import com.xlxumu.user.entity.PointsRecord;
import com.xlxumu.user.service.LevelService;
import com.xlxumu.user.service.PointsService;
import com.xlxumu.user.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 积分管理控制器
* 处理用户积分相关的HTTP请求
*
* @author xlxumu
* @since 2024-01-15
*/
@RestController
@RequestMapping("/api/points")
public class PointsController {
@Autowired
private PointsService pointsService;
@Autowired
private LevelService levelService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
/**
* 获取用户积分余额接口
*/
@GetMapping("/balance")
public ResponseEntity<Map<String, Object>> getUserPointsBalance(HttpServletRequest request) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
Integer balance = pointsService.getUserPointsBalance(userId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", Map.of("balance", balance));
return ResponseEntity.ok(response);
}
/**
* 获取积分记录列表接口
*/
@GetMapping("/records")
public ResponseEntity<Map<String, Object>> getPointsRecordList(HttpServletRequest request) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
List<PointsRecord> records = pointsService.getPointsRecordList(userId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", records);
return ResponseEntity.ok(response);
}
/**
* 获取用户当前等级接口
*/
@GetMapping("/level")
public ResponseEntity<Map<String, Object>> getUserCurrentLevel(HttpServletRequest request) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("code", 401);
errorResponse.put("message", "无效的访问令牌");
return ResponseEntity.status(401).body(errorResponse);
}
Level level = levelService.getUserCurrentLevel(userId);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", level);
return ResponseEntity.ok(response);
}
/**
* 获取等级列表接口
*/
@GetMapping("/levels")
public ResponseEntity<Map<String, Object>> getLevelList() {
List<Level> levels = levelService.getLevelList();
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", levels);
return ResponseEntity.ok(response);
}
}

View File

@@ -1,165 +0,0 @@
package com.xlxumu.user.controller;
import com.xlxumu.user.entity.User;
import com.xlxumu.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 用户管理控制器
* 处理用户相关的HTTP请求
*
* @author xlxumu
* @since 2024-01-15
*/
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
/**
* 用户注册接口
*/
@PostMapping("/register")
public ResponseEntity<Map<String, Object>> register(@RequestBody Map<String, String> request) {
String username = request.get("username");
String password = request.get("password");
String email = request.get("email");
String phone = request.get("phone");
User user = userService.register(username, password, email, phone);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "注册成功");
response.put("data", user);
return ResponseEntity.ok(response);
}
/**
* 用户登录接口
*/
@PostMapping("/login")
public ResponseEntity<Map<String, Object>> login(@RequestBody Map<String, String> request) {
String username = request.get("username");
String password = request.get("password");
String token = userService.login(username, password);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "登录成功");
response.put("data", Map.of("token", token));
return ResponseEntity.ok(response);
}
/**
* 获取用户信息
* @param request HTTP请求
* @return 用户信息
*/
@GetMapping("/info")
public ResponseEntity<ApiResponse<User>> getUserInfo(HttpServletRequest request) {
// 从JWT令牌中获取用户ID
Long userId = jwtTokenUtil.getUserIdFromRequest(request);
if (userId == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new ApiResponse<>(401, "无效的访问令牌", null));
}
try {
User user = userService.getUserById(userId);
return ResponseEntity.ok(new ApiResponse<>(200, "获取成功", user));
} catch (UserException e) {
return ResponseEntity.badRequest().body(new ApiResponse<>(e.getCode(), e.getMessage(), null));
}
}
/**
* 更新用户信息接口
*/
@PutMapping("/info")
public ResponseEntity<Map<String, Object>> updateUserInfo(
@RequestHeader("Authorization") String token,
@RequestBody Map<String, String> request) {
String nickname = request.get("nickname");
String avatar = request.get("avatar");
String gender = request.get("gender");
String birthday = request.get("birthday");
User user = userService.updateUserInfo(token, nickname, avatar, gender, birthday);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "更新成功");
response.put("data", user);
return ResponseEntity.ok(response);
}
/**
* 修改密码接口
*/
@PutMapping("/password")
public ResponseEntity<Map<String, Object>> changePassword(
@RequestHeader("Authorization") String token,
@RequestBody Map<String, String> request) {
String oldPassword = request.get("oldPassword");
String newPassword = request.get("newPassword");
userService.changePassword(token, oldPassword, newPassword);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "密码修改成功");
return ResponseEntity.ok(response);
}
/**
* 管理员获取用户列表接口
*/
@GetMapping("/list")
public ResponseEntity<Map<String, Object>> getUserList(
@RequestHeader("Authorization") String token,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
List<User> users = userService.getUserList(token, page, size);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "获取成功");
response.put("data", users);
return ResponseEntity.ok(response);
}
/**
* 管理员更新用户状态接口
*/
@PutMapping("/{userId}/status")
public ResponseEntity<Map<String, Object>> updateUserStatus(
@RequestHeader("Authorization") String token,
@PathVariable Long userId,
@RequestBody Map<String, Integer> request) {
Integer status = request.get("status");
userService.updateUserStatus(token, userId, status);
Map<String, Object> response = new HashMap<>();
response.put("code", 200);
response.put("message", "状态更新成功");
return ResponseEntity.ok(response);
}
}

View File

@@ -1,151 +0,0 @@
package com.xlxumu.user.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 收货地址实体类
*
* @author xlxumu
* @since 2024-01-15
*/
@Entity
@Table(name = "addresses")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private Long userId;
@Column(name = "receiver_name", nullable = false)
private String receiverName;
@Column(name = "receiver_phone", nullable = false)
private String receiverPhone;
@Column(name = "province", nullable = false)
private String province;
@Column(name = "city", nullable = false)
private String city;
@Column(name = "district", nullable = false)
private String district;
@Column(name = "detail_address", nullable = false)
private String detailAddress;
@Column(name = "is_default")
private Boolean isDefault = false;
private Integer status = 1;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;
// Constructors
public Address() {}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getReceiverName() {
return receiverName;
}
public void setReceiverName(String receiverName) {
this.receiverName = receiverName;
}
public String getReceiverPhone() {
return receiverPhone;
}
public void setReceiverPhone(String receiverPhone) {
this.receiverPhone = receiverPhone;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
public String getDetailAddress() {
return detailAddress;
}
public void setDetailAddress(String detailAddress) {
this.detailAddress = detailAddress;
}
public Boolean getIsDefault() {
return isDefault;
}
public void setIsDefault(Boolean isDefault) {
this.isDefault = isDefault;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -1,137 +0,0 @@
package com.xlxumu.user.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 用户反馈实体类
*
* @author xlxumu
* @since 2024-01-15
*/
@Entity
@Table(name = "feedbacks")
public class Feedback {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private Long userId;
private String title;
private String content;
private Integer type;
@Column(name = "contact_info")
private String contactInfo;
private Integer status = 1;
@Column(name = "reply_content")
private String replyContent;
@Column(name = "replied_at")
private LocalDateTime repliedAt;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;
// Constructors
public Feedback() {}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public String getContactInfo() {
return contactInfo;
}
public void setContactInfo(String contactInfo) {
this.contactInfo = contactInfo;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getReplyContent() {
return replyContent;
}
public void setReplyContent(String replyContent) {
this.replyContent = replyContent;
}
public LocalDateTime getRepliedAt() {
return repliedAt;
}
public void setRepliedAt(LocalDateTime repliedAt) {
this.repliedAt = repliedAt;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -1,117 +0,0 @@
package com.xlxumu.user.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 等级定义实体类
*
* @author xlxumu
* @since 2024-01-15
*/
@Entity
@Table(name = "levels")
public class Level {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String name;
private String description;
@Column(name = "min_points", nullable = false)
private Integer minPoints;
@Column(name = "max_points")
private Integer maxPoints;
@Column(name = "benefits")
private String benefits;
private Integer status = 1;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;
// Constructors
public Level() {}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getMinPoints() {
return minPoints;
}
public void setMinPoints(Integer minPoints) {
this.minPoints = minPoints;
}
public Integer getMaxPoints() {
return maxPoints;
}
public void setMaxPoints(Integer maxPoints) {
this.maxPoints = maxPoints;
}
public String getBenefits() {
return benefits;
}
public void setBenefits(String benefits) {
this.benefits = benefits;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -1,126 +0,0 @@
package com.xlxumu.user.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 用户消息实体类
*
* @author xlxumu
* @since 2024-01-15
*/
@Entity
@Table(name = "messages")
public class Message {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private Long userId;
@Column(name = "sender_id")
private Long senderId;
private String title;
private String content;
private Integer type;
@Column(name = "is_read")
private Boolean isRead = false;
private Integer status = 1;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "read_at")
private LocalDateTime readAt;
// Constructors
public Message() {}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getSenderId() {
return senderId;
}
public void setSenderId(Long senderId) {
this.senderId = senderId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Boolean getIsRead() {
return isRead;
}
public void setIsRead(Boolean isRead) {
this.isRead = isRead;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getReadAt() {
return readAt;
}
public void setReadAt(LocalDateTime readAt) {
this.readAt = readAt;
}
}

View File

@@ -1,84 +0,0 @@
package com.xlxumu.user.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 积分记录实体类
*
* @author xlxumu
* @since 2024-01-15
*/
@Entity
@Table(name = "points_records")
public class PointsRecord {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private Long userId;
private Integer points;
@Column(name = "change_type", nullable = false)
private String changeType;
private String description;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
// Constructors
public PointsRecord() {}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Integer getPoints() {
return points;
}
public void setPoints(Integer points) {
this.points = points;
}
public String getChangeType() {
return changeType;
}
public void setChangeType(String changeType) {
this.changeType = changeType;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
}

View File

@@ -1,180 +0,0 @@
package com.xlxumu.user.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 用户基本信息实体类
*
* @author xlxumu
* @since 2024-01-15
*/
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false, unique = true)
private String email;
private String phone;
@Column(name = "password_hash", nullable = false)
private String passwordHash;
private String nickname;
@Column(name = "avatar_url")
private String avatarUrl;
private Integer gender;
private LocalDateTime birthday;
@Column(name = "real_name")
private String realName;
@Column(name = "id_card_number")
private String idCardNumber;
private Integer status = 1;
@Column(name = "last_login_at")
private LocalDateTime lastLoginAt;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;
// Constructors
public User() {}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPasswordHash() {
return passwordHash;
}
public void setPasswordHash(String passwordHash) {
this.passwordHash = passwordHash;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public LocalDateTime getBirthday() {
return birthday;
}
public void setBirthday(LocalDateTime birthday) {
this.birthday = birthday;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getIdCardNumber() {
return idCardNumber;
}
public void setIdCardNumber(String idCardNumber) {
this.idCardNumber = idCardNumber;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getLastLoginAt() {
return lastLoginAt;
}
public void setLastLoginAt(LocalDateTime lastLoginAt) {
this.lastLoginAt = lastLoginAt;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -1,86 +0,0 @@
package com.xlxumu.user.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
/**
* 用户等级实体类
*
* @author xlxumu
* @since 2024-01-15
*/
@Entity
@Table(name = "user_levels")
public class UserLevel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false, unique = true)
private Long userId;
@Column(name = "level_id", nullable = false)
private Long levelId;
@Column(name = "current_points")
private Integer currentPoints = 0;
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;
// Constructors
public UserLevel() {}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getLevelId() {
return levelId;
}
public void setLevelId(Long levelId) {
this.levelId = levelId;
}
public Integer getCurrentPoints() {
return currentPoints;
}
public void setCurrentPoints(Integer currentPoints) {
this.currentPoints = currentPoints;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}

View File

@@ -1,56 +0,0 @@
package com.xlxumu.user.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* 全局异常处理类
*
* @author xlxumu
* @since 2024-01-15
*/
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理用户相关异常
* @param ex 异常对象
* @param request 请求对象
* @return 错误响应
*/
@ExceptionHandler(UserException.class)
public ResponseEntity<Object> handleUserException(UserException ex, WebRequest request) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("status", ex.getStatus());
body.put("error", ex.getMessage());
body.put("path", request.getDescription(false).replace("uri=", ""));
return new ResponseEntity<>(body, HttpStatus.valueOf(ex.getStatus()));
}
/**
* 处理通用异常
* @param ex 异常对象
* @param request 请求对象
* @return 错误响应
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleGenericException(Exception ex, WebRequest request) {
Map<String, Object> body = new HashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
body.put("error", "Internal Server Error");
body.put("message", ex.getMessage());
body.put("path", request.getDescription(false).replace("uri=", ""));
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

View File

@@ -1,26 +0,0 @@
package com.xlxumu.user.exception;
/**
* 用户相关自定义异常类
*
* @author xlxumu
* @since 2024-01-15
*/
public class UserException extends RuntimeException {
private int status;
public UserException(String message, int status) {
super(message);
this.status = status;
}
public UserException(String message, Throwable cause, int status) {
super(message, cause);
this.status = status;
}
public int getStatus() {
return status;
}
}

View File

@@ -1,32 +0,0 @@
package com.xlxumu.user.repository;
import com.xlxumu.user.entity.Address;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 收货地址数据访问接口
*
* @author xlxumu
* @since 2024-01-15
*/
@Repository
public interface AddressRepository extends JpaRepository<Address, Long> {
/**
* 根据用户ID查找收货地址列表
* @param userId 用户ID
* @return 收货地址列表
*/
List<Address> findByUserId(Long userId);
/**
* 根据用户ID和默认地址标识查找默认收货地址
* @param userId 用户ID
* @param isDefault 是否默认地址
* @return 收货地址
*/
Address findByUserIdAndIsDefault(Long userId, Boolean isDefault);
}

View File

@@ -1,24 +0,0 @@
package com.xlxumu.user.repository;
import com.xlxumu.user.entity.Feedback;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 用户反馈数据访问接口
*
* @author xlxumu
* @since 2024-01-15
*/
@Repository
public interface FeedbackRepository extends JpaRepository<Feedback, Long> {
/**
* 根据用户ID查找反馈列表
* @param userId 用户ID
* @return 反馈列表
*/
List<Feedback> findByUserIdOrderByCreatedAtDesc(Long userId);
}

View File

@@ -1,24 +0,0 @@
package com.xlxumu.user.repository;
import com.xlxumu.user.entity.Level;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 等级定义数据访问接口
*
* @author xlxumu
* @since 2024-01-15
*/
@Repository
public interface LevelRepository extends JpaRepository<Level, Long> {
/**
* 根据状态查找等级列表
* @param status 状态
* @return 等级列表
*/
List<Level> findByStatusOrderByMinPointsAsc(Integer status);
}

View File

@@ -1,32 +0,0 @@
package com.xlxumu.user.repository;
import com.xlxumu.user.entity.Message;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 用户消息数据访问接口
*
* @author xlxumu
* @since 2024-01-15
*/
@Repository
public interface MessageRepository extends JpaRepository<Message, Long> {
/**
* 根据用户ID查找消息列表
* @param userId 用户ID
* @return 消息列表
*/
List<Message> findByUserIdOrderByCreatedAtDesc(Long userId);
/**
* 根据用户ID和已读状态查找消息列表
* @param userId 用户ID
* @param isRead 是否已读
* @return 消息列表
*/
List<Message> findByUserIdAndIsReadOrderByCreatedAtDesc(Long userId, Boolean isRead);
}

View File

@@ -1,24 +0,0 @@
package com.xlxumu.user.repository;
import com.xlxumu.user.entity.PointsRecord;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 积分记录数据访问接口
*
* @author xlxumu
* @since 2024-01-15
*/
@Repository
public interface PointsRecordRepository extends JpaRepository<PointsRecord, Long> {
/**
* 根据用户ID查找积分记录列表
* @param userId 用户ID
* @return 积分记录列表
*/
List<PointsRecord> findByUserIdOrderByCreatedAtDesc(Long userId);
}

View File

@@ -1,24 +0,0 @@
package com.xlxumu.user.repository;
import com.xlxumu.user.entity.UserLevel;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* 用户等级数据访问接口
*
* @author xlxumu
* @since 2024-01-15
*/
@Repository
public interface UserLevelRepository extends JpaRepository<UserLevel, Long> {
/**
* 根据用户ID查找用户等级信息
* @param userId 用户ID
* @return 用户等级信息
*/
Optional<UserLevel> findByUserId(Long userId);
}

View File

@@ -1,46 +0,0 @@
package com.xlxumu.user.repository;
import com.xlxumu.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* 用户信息数据访问接口
*
* @author xlxumu
* @since 2024-01-15
*/
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
/**
* 根据用户名查找用户
* @param username 用户名
* @return 用户信息
*/
Optional<User> findByUsername(String username);
/**
* 根据邮箱查找用户
* @param email 邮箱
* @return 用户信息
*/
Optional<User> findByEmail(String email);
/**
* 根据手机号查找用户
* @param phone 手机号
* @return 用户信息
*/
Optional<User> findByPhone(String phone);
/**
* 根据用户名和密码查找用户
* @param username 用户名
* @param passwordHash 密码哈希值
* @return 用户信息
*/
Optional<User> findByUsernameAndPasswordHash(String username, String passwordHash);
}

View File

@@ -1,150 +0,0 @@
package com.xlxumu.user.service;
import com.xlxumu.user.entity.Address;
import com.xlxumu.user.exception.UserException;
import com.xlxumu.user.repository.AddressRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* 收货地址服务类
* 提供收货地址相关的业务逻辑处理
*
* @author xlxumu
* @since 2024-01-15
*/
@Service
public class AddressService {
@Autowired
private AddressRepository addressRepository;
/**
* 创建收货地址
* @param userId 用户ID
* @param receiverName 收货人姓名
* @param receiverPhone 收货人电话
* @param province 省
* @param city 市
* @param district 区
* @param detailAddress 详细地址
* @param isDefault 是否默认地址
* @return 创建的地址信息
*/
public Address createAddress(Long userId, String receiverName, String receiverPhone,
String province, String city, String district, String detailAddress,
Boolean isDefault) {
// 如果设置为默认地址,需要将其他地址设为非默认
if (isDefault != null && isDefault) {
Address defaultAddress = addressRepository.findByUserIdAndIsDefault(userId, true);
if (defaultAddress != null) {
defaultAddress.setIsDefault(false);
addressRepository.save(defaultAddress);
}
}
Address address = new Address();
address.setUserId(userId);
address.setReceiverName(receiverName);
address.setReceiverPhone(receiverPhone);
address.setProvince(province);
address.setCity(city);
address.setDistrict(district);
address.setDetailAddress(detailAddress);
address.setIsDefault(isDefault != null ? isDefault : false);
address.setStatus(1);
address.setCreatedAt(LocalDateTime.now());
address.setUpdatedAt(LocalDateTime.now());
return addressRepository.save(address);
}
/**
* 获取收货地址列表
* @param userId 用户ID
* @return 地址列表
*/
public List<Address> getAddressList(Long userId) {
return addressRepository.findByUserId(userId);
}
/**
* 获取收货地址详情
* @param addressId 地址ID
* @return 地址信息
*/
public Address getAddressDetail(Long addressId) {
Optional<Address> addressOptional = addressRepository.findById(addressId);
if (!addressOptional.isPresent()) {
throw new UserException("地址不存在", 404);
}
return addressOptional.get();
}
/**
* 更新收货地址
* @param addressId 地址ID
* @param receiverName 收货人姓名
* @param receiverPhone 收货人电话
* @param province 省
* @param city 市
* @param district 区
* @param detailAddress 详细地址
* @param isDefault 是否默认地址
* @return 更新后的地址信息
*/
public Address updateAddress(Long addressId, String receiverName, String receiverPhone,
String province, String city, String district, String detailAddress,
Boolean isDefault) {
Optional<Address> addressOptional = addressRepository.findById(addressId);
if (!addressOptional.isPresent()) {
throw new UserException("地址不存在", 404);
}
Address address = addressOptional.get();
// 如果设置为默认地址,需要将其他地址设为非默认
if (isDefault != null && isDefault) {
Address defaultAddress = addressRepository.findByUserIdAndIsDefault(address.getUserId(), true);
if (defaultAddress != null && !defaultAddress.getId().equals(addressId)) {
defaultAddress.setIsDefault(false);
addressRepository.save(defaultAddress);
}
}
address.setReceiverName(receiverName);
address.setReceiverPhone(receiverPhone);
address.setProvince(province);
address.setCity(city);
address.setDistrict(district);
address.setDetailAddress(detailAddress);
if (isDefault != null) {
address.setIsDefault(isDefault);
}
address.setUpdatedAt(LocalDateTime.now());
return addressRepository.save(address);
}
/**
* 删除收货地址
* @param addressId 地址ID
*/
public void deleteAddress(Long addressId) {
Optional<Address> addressOptional = addressRepository.findById(addressId);
if (!addressOptional.isPresent()) {
throw new UserException("地址不存在", 404);
}
Address address = addressOptional.get();
address.setStatus(0); // 软删除
address.setUpdatedAt(LocalDateTime.now());
addressRepository.save(address);
}
}

View File

@@ -1,64 +0,0 @@
package com.xlxumu.user.service;
import com.xlxumu.user.entity.Feedback;
import com.xlxumu.user.exception.UserException;
import com.xlxumu.user.repository.FeedbackRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
/**
* 用户反馈服务类
* 提供用户反馈相关的业务逻辑处理
*
* @author xlxumu
* @since 2024-01-15
*/
@Service
public class FeedbackService {
@Autowired
private FeedbackRepository feedbackRepository;
/**
* 提交反馈
* @param userId 用户ID
* @param title 反馈标题
* @param content 反馈内容
* @param type 反馈类型
* @param contactInfo 联系方式
* @return 提交的反馈对象
*/
public Feedback submitFeedback(Long userId, String title, String content, String type, String contactInfo) {
if (title == null || title.trim().isEmpty()) {
throw new UserException("反馈标题不能为空", 400);
}
if (content == null || content.trim().isEmpty()) {
throw new UserException("反馈内容不能为空", 400);
}
Feedback feedback = new Feedback();
feedback.setUserId(userId);
feedback.setTitle(title);
feedback.setContent(content);
feedback.setType(type);
feedback.setContactInfo(contactInfo);
feedback.setStatus(1); // 1-待处理
feedback.setCreatedAt(LocalDateTime.now());
feedback.setUpdatedAt(LocalDateTime.now());
return feedbackRepository.save(feedback);
}
/**
* 获取反馈列表
* @param userId 用户ID
* @return 反馈列表
*/
public List<Feedback> getFeedbackList(Long userId) {
return feedbackRepository.findByUserIdOrderByCreatedAtDesc(userId);
}
}

View File

@@ -1,57 +0,0 @@
package com.xlxumu.user.service;
import com.xlxumu.user.entity.Level;
import com.xlxumu.user.entity.UserLevel;
import com.xlxumu.user.exception.UserException;
import com.xlxumu.user.repository.LevelRepository;
import com.xlxumu.user.repository.UserLevelRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* 等级管理服务类
* 提供用户等级相关的业务逻辑处理
*
* @author xlxumu
* @since 2024-01-15
*/
@Service
public class LevelService {
@Autowired
private UserLevelRepository userLevelRepository;
@Autowired
private LevelRepository levelRepository;
/**
* 获取用户当前等级
* @param userId 用户ID
* @return 用户等级信息
*/
public Level getUserCurrentLevel(Long userId) {
Optional<UserLevel> userLevelOptional = userLevelRepository.findByUserId(userId);
if (!userLevelOptional.isPresent()) {
throw new UserException("用户等级信息不存在", 404);
}
Long levelId = userLevelOptional.get().getLevelId();
Optional<Level> levelOptional = levelRepository.findById(levelId);
if (!levelOptional.isPresent()) {
throw new UserException("等级信息不存在", 404);
}
return levelOptional.get();
}
/**
* 获取等级列表
* @return 等级列表
*/
public List<Level> getLevelList() {
return levelRepository.findByStatusOrderByMinPointsAsc(1);
}
}

View File

@@ -1,67 +0,0 @@
package com.xlxumu.user.service;
import com.xlxumu.user.entity.Message;
import com.xlxumu.user.exception.UserException;
import com.xlxumu.user.repository.MessageRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* 消息通知服务类
* 提供用户消息相关的业务逻辑处理
*
* @author xlxumu
* @since 2024-01-15
*/
@Service
public class MessageService {
@Autowired
private MessageRepository messageRepository;
/**
* 获取消息列表
* @param userId 用户ID
* @return 消息列表
*/
public List<Message> getMessageList(Long userId) {
return messageRepository.findByUserIdOrderByCreatedAtDesc(userId);
}
/**
* 标记消息为已读
* @param messageId 消息ID
*/
public void markMessageAsRead(Long messageId) {
Optional<Message> messageOptional = messageRepository.findById(messageId);
if (!messageOptional.isPresent()) {
throw new UserException("消息不存在", 404);
}
Message message = messageOptional.get();
if (!message.getIsRead()) {
message.setIsRead(true);
message.setReadAt(LocalDateTime.now());
messageRepository.save(message);
}
}
/**
* 删除消息
* @param messageId 消息ID
*/
public void deleteMessage(Long messageId) {
Optional<Message> messageOptional = messageRepository.findById(messageId);
if (!messageOptional.isPresent()) {
throw new UserException("消息不存在", 404);
}
Message message = messageOptional.get();
message.setStatus(0); // 软删除
messageRepository.save(message);
}
}

View File

@@ -1,96 +0,0 @@
package com.xlxumu.user.service;
import com.xlxumu.user.entity.PointsRecord;
import com.xlxumu.user.entity.UserLevel;
import com.xlxumu.user.exception.UserException;
import com.xlxumu.user.repository.PointsRecordRepository;
import com.xlxumu.user.repository.UserLevelRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* 积分管理服务类
* 提供用户积分相关的业务逻辑处理
*
* @author xlxumu
* @since 2024-01-15
*/
@Service
public class PointsService {
@Autowired
private UserLevelRepository userLevelRepository;
@Autowired
private PointsRecordRepository pointsRecordRepository;
/**
* 获取用户积分余额
* @param userId 用户ID
* @return 积分余额
*/
public Integer getUserPointsBalance(Long userId) {
Optional<UserLevel> userLevelOptional = userLevelRepository.findByUserId(userId);
if (!userLevelOptional.isPresent()) {
throw new UserException("用户等级信息不存在", 404);
}
return userLevelOptional.get().getCurrentPoints();
}
/**
* 获取积分记录列表
* @param userId 用户ID
* @return 积分记录列表
*/
public List<PointsRecord> getPointsRecordList(Long userId) {
return pointsRecordRepository.findByUserIdOrderByCreatedAtDesc(userId);
}
/**
* 添加积分记录
* @param userId 用户ID
* @param points 积分数量(正数表示增加,负数表示减少)
* @param changeType 变更类型
* @param description 描述
* @return 更新后的积分余额
*/
public Integer addPointsRecord(Long userId, Integer points, String changeType, String description) {
// 更新用户积分余额
Optional<UserLevel> userLevelOptional = userLevelRepository.findByUserId(userId);
UserLevel userLevel;
if (!userLevelOptional.isPresent()) {
// 创建新的用户等级记录
userLevel = new UserLevel();
userLevel.setUserId(userId);
userLevel.setLevelId(1L); // 默认等级ID
userLevel.setCurrentPoints(points > 0 ? points : 0);
userLevel.setCreatedAt(LocalDateTime.now());
userLevel.setUpdatedAt(LocalDateTime.now());
} else {
userLevel = userLevelOptional.get();
int newPoints = userLevel.getCurrentPoints() + points;
userLevel.setCurrentPoints(newPoints > 0 ? newPoints : 0);
userLevel.setUpdatedAt(LocalDateTime.now());
}
userLevelRepository.save(userLevel);
// 记录积分变更
PointsRecord pointsRecord = new PointsRecord();
pointsRecord.setUserId(userId);
pointsRecord.setPoints(points);
pointsRecord.setChangeType(changeType);
pointsRecord.setDescription(description);
pointsRecord.setCreatedAt(LocalDateTime.now());
pointsRecordRepository.save(pointsRecord);
return userLevel.getCurrentPoints();
}
}

View File

@@ -1,201 +0,0 @@
package com.xlxumu.user.service;
import com.xlxumu.user.entity.User;
import com.xlxumu.user.exception.UserException;
import com.xlxumu.user.repository.UserRepository;
import com.xlxumu.user.util.JwtUtil;
import com.xlxumu.user.util.PasswordUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* 用户服务类
* 提供用户相关的业务逻辑处理
*
* @author xlxumu
* @since 2024-01-15
*/
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordUtil passwordUtil;
@Autowired
private JwtUtil jwtUtil;
/**
* 用户注册
* @param username 用户名
* @param email 邮箱
* @param phone 手机号
* @param password 密码
* @return JWT token
*/
public String register(String username, String email, String phone, String password) {
// 检查用户名是否已存在
if (userRepository.findByUsername(username).isPresent()) {
throw new UserException("用户名已存在", 400);
}
// 检查邮箱是否已存在
if (userRepository.findByEmail(email).isPresent()) {
throw new UserException("邮箱已被注册", 400);
}
// 检查手机号是否已存在
if (userRepository.findByPhone(phone).isPresent()) {
throw new UserException("手机号已被注册", 400);
}
// 创建新用户
User user = new User();
user.setUsername(username);
user.setEmail(email);
user.setPhone(phone);
// 密码加密
String salt = passwordUtil.generateSalt();
String hashedPassword = passwordUtil.hashPassword(password, salt);
user.setPasswordHash(hashedPassword);
user.setCreatedAt(LocalDateTime.now());
user.setUpdatedAt(LocalDateTime.now());
userRepository.save(user);
// 生成JWT token
return jwtUtil.generateToken(username);
}
/**
* 用户登录
* @param username 用户名
* @param password 密码
* @return JWT token
*/
public String login(String username, String password) {
Optional<User> userOptional = userRepository.findByUsername(username);
if (!userOptional.isPresent()) {
throw new UserException("用户不存在", 400);
}
User user = userOptional.get();
// 验证密码
if (!passwordUtil.verifyPassword(password, "", user.getPasswordHash())) {
throw new UserException("密码错误", 400);
}
// 更新最后登录时间
user.setLastLoginAt(LocalDateTime.now());
userRepository.save(user);
// 生成JWT token
return jwtUtil.generateToken(username);
}
/**
* 获取用户信息
* @param userId 用户ID
* @return 用户信息
*/
public User getUserInfo(Long userId) {
Optional<User> userOptional = userRepository.findById(userId);
if (!userOptional.isPresent()) {
throw new UserException("用户不存在", 404);
}
return userOptional.get();
}
/**
* 更新用户信息
* @param userId 用户ID
* @param nickname 昵称
* @param avatarUrl 头像URL
* @param gender 性别
* @param birthday 生日
* @param realName 真实姓名
* @return 更新后的用户信息
*/
public User updateUserInfo(Long userId, String nickname, String avatarUrl, Integer gender,
LocalDateTime birthday, String realName) {
Optional<User> userOptional = userRepository.findById(userId);
if (!userOptional.isPresent()) {
throw new UserException("用户不存在", 404);
}
User user = userOptional.get();
user.setNickname(nickname);
user.setAvatarUrl(avatarUrl);
user.setGender(gender);
user.setBirthday(birthday);
user.setRealName(realName);
user.setUpdatedAt(LocalDateTime.now());
return userRepository.save(user);
}
/**
* 修改用户密码
* @param userId 用户ID
* @param oldPassword 旧密码
* @param newPassword 新密码
*/
public void changePassword(Long userId, String oldPassword, String newPassword) {
Optional<User> userOptional = userRepository.findById(userId);
if (!userOptional.isPresent()) {
throw new UserException("用户不存在", 404);
}
User user = userOptional.get();
// 验证旧密码
if (!passwordUtil.verifyPassword(oldPassword, "", user.getPasswordHash())) {
throw new UserException("旧密码错误", 400);
}
// 加密新密码
String salt = passwordUtil.generateSalt();
String hashedPassword = passwordUtil.hashPassword(newPassword, salt);
user.setPasswordHash(hashedPassword);
user.setUpdatedAt(LocalDateTime.now());
userRepository.save(user);
}
/**
* 管理员获取用户列表
* @return 用户列表
*/
public List<User> getUserList() {
return userRepository.findAll();
}
/**
* 管理员更新用户状态
* @param userId 用户ID
* @param status 状态
* @return 更新后的用户信息
*/
public User updateUserStatus(Long userId, Integer status) {
Optional<User> userOptional = userRepository.findById(userId);
if (!userOptional.isPresent()) {
throw new UserException("用户不存在", 404);
}
User user = userOptional.get();
user.setStatus(status);
user.setUpdatedAt(LocalDateTime.now());
return userRepository.save(user);
}
}

View File

@@ -1,29 +0,0 @@
package com.xlxumu.user.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class JwtTokenUtil {
@Autowired
private JwtUtil jwtUtil;
/**
* 从请求中获取用户ID
* @param request HTTP请求
* @return 用户ID
*/
public Long getUserIdFromRequest(HttpServletRequest request) {
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
String token = authorizationHeader.substring(7);
return jwtUtil.getUserIdFromToken(token);
}
return null;
}
}

View File

@@ -1,114 +0,0 @@
package com.xlxumu.user.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* JWT工具类
*
* @author xlxumu
* @since 2024-01-15
*/
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
/**
* 从token中获取用户ID
* @param token JWT token
* @return 用户ID
*/
public Long getUserIdFromToken(String token) {
return Long.parseLong(getClaimFromToken(token, Claims::getSubject));
}
/**
* 从token中获取过期时间
* @param token JWT token
* @return 过期时间
*/
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
/**
* 从token中获取自定义声明
* @param token JWT token
* @param claimsResolver 声明解析器
* @param <T> 声明类型
* @return 声明值
*/
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
/**
* 解析token中的所有声明
* @param token JWT token
* @return 所有声明
*/
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
/**
* 检查token是否过期
* @param token JWT token
* @return 是否过期
*/
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
/**
* 生成token
* @param userId 用户ID
* @return JWT token
*/
public String generateToken(Long userId) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userId.toString());
}
/**
* 创建token
* @param claims 声明
* @param subject 主题(用户ID)
* @return JWT token
*/
private String doGenerateToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 验证token
* @param token JWT token
* @param userId 用户ID
* @return 是否有效
*/
public Boolean validateToken(String token, Long userId) {
final Long tokenUserId = getUserIdFromToken(token);
return (tokenUserId.equals(userId) && !isTokenExpired(token));
}
}

View File

@@ -1,73 +0,0 @@
package com.xlxumu.user.util;
import org.springframework.stereotype.Component;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* 密码工具类
*
* @author xlxumu
* @since 2024-01-15
*/
@Component
public class PasswordUtil {
private static final String ALGORITHM = "SHA-256";
private static final int SALT_LENGTH = 32;
/**
* 生成随机盐值
* @return 盐值
*/
public String generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
return bytesToHex(salt);
}
/**
* 对密码进行哈希处理
* @param password 密码
* @param salt 盐值
* @return 哈希值
*/
public String hashPassword(String password, String salt) {
try {
MessageDigest md = MessageDigest.getInstance(ALGORITHM);
md.update(salt.getBytes());
byte[] hashedPassword = md.digest(password.getBytes());
return bytesToHex(hashedPassword);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Error hashing password", e);
}
}
/**
* 验证密码
* @param password 密码
* @param salt 盐值
* @param hashedPassword 哈希值
* @return 是否匹配
*/
public boolean verifyPassword(String password, String salt, String hashedPassword) {
String newHash = hashPassword(password, salt);
return newHash.equals(hashedPassword);
}
/**
* 将字节数组转换为十六进制字符串
* @param bytes 字节数组
* @return 十六进制字符串
*/
private String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}

View File

@@ -1,335 +0,0 @@
openapi: 3.0.3
info:
title: 用户中心服务 - 收货地址管理API
description: 用户收货地址管理接口
version: 1.0.0
paths:
/api/addresses:
post:
summary: 创建收货地址
description: 创建新的收货地址
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 收货人姓名
phone:
type: string
description: 收货人电话
province:
type: string
description: 省份
city:
type: string
description: 城市
district:
type: string
description: 区县
detailAddress:
type: string
description: 详细地址
isDefault:
type: boolean
description: 是否默认地址
required:
- name
- phone
- province
- city
- district
- detailAddress
responses:
'200':
description: 地址创建成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "地址创建成功"
data:
$ref: '#/components/schemas/Address'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
summary: 获取收货地址列表
description: 获取当前用户的所有收货地址
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
type: array
items:
$ref: '#/components/schemas/Address'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/addresses/{addressId):
get:
summary: 获取收货地址详情
description: 获取指定收货地址的详细信息
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
- name: addressId
in: path
required: true
schema:
type: integer
format: int64
description: 地址ID
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
$ref: '#/components/schemas/Address'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 地址不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
put:
summary: 更新收货地址
description: 更新指定收货地址的信息
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
- name: addressId
in: path
required: true
schema:
type: integer
format: int64
description: 地址ID
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: 收货人姓名
phone:
type: string
description: 收货人电话
province:
type: string
description: 省份
city:
type: string
description: 城市
district:
type: string
description: 区县
detailAddress:
type: string
description: 详细地址
isDefault:
type: boolean
description: 是否默认地址
responses:
'200':
description: 地址更新成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "地址更新成功"
data:
$ref: '#/components/schemas/Address'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 地址不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
delete:
summary: 删除收货地址
description: 删除指定收货地址
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
- name: addressId
in: path
required: true
schema:
type: integer
format: int64
description: 地址ID
responses:
'200':
description: 地址删除成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "地址删除成功"
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 地址不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
Address:
type: object
properties:
id:
type: integer
format: int64
description: 地址ID
userId:
type: integer
format: int64
description: 用户ID
name:
type: string
description: 收货人姓名
phone:
type: string
description: 收货人电话
province:
type: string
description: 省份
city:
type: string
description: 城市
district:
type: string
description: 区县
detailAddress:
type: string
description: 详细地址
isDefault:
type: boolean
description: 是否默认地址
status:
type: integer
description: 地址状态 (1-正常, 0-删除)
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
ErrorResponse:
type: object
properties:
timestamp:
type: string
format: date-time
description: 错误时间戳
status:
type: integer
description: HTTP状态码
error:
type: string
description: 错误信息
path:
type: string
description: 请求路径

View File

@@ -1,156 +0,0 @@
openapi: 3.0.3
info:
title: 用户中心服务 - 用户反馈API
description: 用户反馈提交、查询等接口
version: 1.0.0
paths:
/api/feedback:
post:
summary: 提交反馈
description: 用户提交反馈意见
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
description: 反馈标题
content:
type: string
description: 反馈内容
type:
type: string
description: 反馈类型
contactInfo:
type: string
description: 联系方式
required:
- title
- content
responses:
'200':
description: 反馈提交成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "反馈提交成功"
data:
$ref: '#/components/schemas/Feedback'
'400':
description: 请求参数错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
summary: 获取反馈列表
description: 获取当前用户的反馈列表
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
type: array
items:
$ref: '#/components/schemas/Feedback'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
Feedback:
type: object
properties:
id:
type: integer
format: int64
description: 反馈ID
userId:
type: integer
format: int64
description: 用户ID
title:
type: string
description: 反馈标题
content:
type: string
description: 反馈内容
type:
type: string
description: 反馈类型
contactInfo:
type: string
description: 联系方式
status:
type: integer
description: 反馈状态 (1-待处理, 2-处理中, 3-已处理)
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
ErrorResponse:
type: object
properties:
timestamp:
type: string
format: date-time
description: 错误时间戳
status:
type: integer
description: HTTP状态码
error:
type: string
description: 错误信息
path:
type: string
description: 请求路径

View File

@@ -1,190 +0,0 @@
openapi: 3.0.3
info:
title: 用户中心服务 - 消息通知API
description: 用户消息查询、标记已读、删除等接口
version: 1.0.0
paths:
/api/messages:
get:
summary: 获取消息列表
description: 获取当前用户的消息列表
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
type: array
items:
$ref: '#/components/schemas/Message'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/messages/{messageId}/read:
put:
summary: 标记消息为已读
description: 将指定消息标记为已读状态
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
- name: messageId
in: path
required: true
schema:
type: integer
format: int64
description: 消息ID
responses:
'200':
description: 标记成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "标记成功"
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 消息不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/messages/{messageId}:
delete:
summary: 删除消息
description: 删除指定消息
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
- name: messageId
in: path
required: true
schema:
type: integer
format: int64
description: 消息ID
responses:
'200':
description: 删除成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "删除成功"
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 消息不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
Message:
type: object
properties:
id:
type: integer
format: int64
description: 消息ID
userId:
type: integer
format: int64
description: 用户ID
title:
type: string
description: 消息标题
content:
type: string
description: 消息内容
type:
type: string
description: 消息类型
isRead:
type: boolean
description: 是否已读
readAt:
type: string
format: date-time
description: 阅读时间
status:
type: integer
description: 消息状态 (1-正常, 0-删除)
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
ErrorResponse:
type: object
properties:
timestamp:
type: string
format: date-time
description: 错误时间戳
status:
type: integer
description: HTTP状态码
error:
type: string
description: 错误信息
path:
type: string
description: 请求路径

View File

@@ -1,69 +0,0 @@
openapi: 3.0.3
info:
title: 用户中心服务API
description: 用户中心服务提供用户管理、收货地址、积分、消息通知、用户反馈等核心功能的RESTful API接口
version: 1.0.0
servers:
- url: http://localhost:8080
description: 本地开发环境
paths:
# 用户管理相关接口
/api/users/register:
$ref: './user-api.yaml#/paths/~1api~1users~1register'
/api/users/login:
$ref: './user-api.yaml#/paths/~1api~1users~1login'
/api/users/info:
$ref: './user-api.yaml#/paths/~1api~1users~1info'
/api/users/password:
$ref: './user-api.yaml#/paths/~1api~1users~1password'
/api/users/list:
$ref: './user-api.yaml#/paths/~1api~1users~1list'
/api/users/{userId}/status:
$ref: './user-api.yaml#/paths/~1api~1users~1{userId}~1status'
# 收货地址相关接口
/api/addresses:
$ref: './address-api.yaml#/paths/~1api~1addresses'
/api/addresses/{addressId}:
$ref: './address-api.yaml#/paths/~1api~1addresses~1{addressId}'
# 积分管理相关接口
/api/points/balance:
$ref: './points-api.yaml#/paths/~1api~1points~1balance'
/api/points/records:
$ref: './points-api.yaml#/paths/~1api~1points~1records'
/api/points/level:
$ref: './points-api.yaml#/paths/~1api~1points~1level'
/api/points/levels:
$ref: './points-api.yaml#/paths/~1api~1points~1levels'
# 消息通知相关接口
/api/messages:
$ref: './message-api.yaml#/paths/~1api~1messages'
/api/messages/{messageId}/read:
$ref: './message-api.yaml#/paths/~1api~1messages~1{messageId}~1read'
/api/messages/{messageId}:
$ref: './message-api.yaml#/paths/~1api~1messages~1{messageId}'
# 用户反馈相关接口
/api/feedback:
$ref: './feedback-api.yaml#/paths/~1api~1feedback'
components:
schemas:
User:
$ref: './user-api.yaml#/components/schemas/User'
Address:
$ref: './address-api.yaml#/components/schemas/Address'
PointsRecord:
$ref: './points-api.yaml#/components/schemas/PointsRecord'
Level:
$ref: './points-api.yaml#/components/schemas/Level'
Message:
$ref: './message-api.yaml#/components/schemas/Message'
Feedback:
$ref: './feedback-api.yaml#/components/schemas/Feedback'
ErrorResponse:
$ref: './user-api.yaml#/components/schemas/ErrorResponse'

View File

@@ -1,213 +0,0 @@
openapi: 3.0.3
info:
title: 用户中心服务 - 积分管理API
description: 用户积分查询、积分记录查询等接口
version: 1.0.0
paths:
/api/points/balance:
get:
summary: 获取用户积分余额
description: 获取当前用户的积分余额
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
type: object
properties:
balance:
type: integer
description: 积分余额
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/points/records:
get:
summary: 获取积分记录列表
description: 获取当前用户的积分变动记录列表
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
type: array
items:
$ref: '#/components/schemas/PointsRecord'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/points/level:
get:
summary: 获取用户当前等级
description: 获取当前用户的等级信息
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
$ref: '#/components/schemas/Level'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/points/levels:
get:
summary: 获取等级列表
description: 获取所有可用的用户等级列表
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
type: array
items:
$ref: '#/components/schemas/Level'
components:
schemas:
PointsRecord:
type: object
properties:
id:
type: integer
format: int64
description: 记录ID
userId:
type: integer
format: int64
description: 用户ID
changeType:
type: string
description: 变动类型 (earn-获得, consume-消费)
points:
type: integer
description: 积分数量
description:
type: string
description: 描述
createdAt:
type: string
format: date-time
description: 创建时间
Level:
type: object
properties:
id:
type: integer
format: int64
description: 等级ID
name:
type: string
description: 等级名称
minPoints:
type: integer
description: 最小积分要求
maxPoints:
type: integer
description: 最大积分要求
discountRate:
type: number
format: double
description: 折扣率
status:
type: integer
description: 状态 (1-启用, 0-禁用)
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
ErrorResponse:
type: object
properties:
timestamp:
type: string
format: date-time
description: 错误时间戳
status:
type: integer
description: HTTP状态码
error:
type: string
description: 错误信息
path:
type: string
description: 请求路径

View File

@@ -1,413 +0,0 @@
openapi: 3.0.3
info:
title: 用户中心服务 - 用户管理API
description: 用户注册、登录、信息管理等接口
version: 1.0.0
paths:
/api/users/register:
post:
summary: 用户注册
description: 用户注册接口,创建新用户账户
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
description: 用户名
password:
type: string
description: 密码
email:
type: string
description: 邮箱
phone:
type: string
description: 手机号
required:
- username
- password
responses:
'200':
description: 注册成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "注册成功"
data:
$ref: '#/components/schemas/User'
'400':
description: 请求参数错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/login:
post:
summary: 用户登录
description: 用户登录接口,获取访问令牌
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
description: 用户名
password:
type: string
description: 密码
required:
- username
- password
responses:
'200':
description: 登录成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "登录成功"
data:
type: object
properties:
token:
type: string
description: JWT访问令牌
'401':
description: 用户名或密码错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/info:
get:
summary: 获取用户信息
description: 获取当前登录用户的详细信息
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
$ref: '#/components/schemas/User'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
put:
summary: 更新用户信息
description: 更新当前登录用户的个人信息
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
nickname:
type: string
description: 昵称
avatar:
type: string
description: 头像URL
gender:
type: string
description: 性别
birthday:
type: string
format: date
description: 生日
responses:
'200':
description: 更新成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "更新成功"
data:
$ref: '#/components/schemas/User'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/password:
put:
summary: 修改密码
description: 修改用户登录密码
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
oldPassword:
type: string
description: 旧密码
newPassword:
type: string
description: 新密码
required:
- oldPassword
- newPassword
responses:
'200':
description: 密码修改成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "密码修改成功"
'401':
description: 未授权访问或旧密码错误
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/list:
get:
summary: 获取用户列表
description: 管理员获取用户列表(分页)
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
- name: page
in: query
schema:
type: integer
default: 1
description: 页码
- name: size
in: query
schema:
type: integer
default: 10
description: 每页数量
responses:
'200':
description: 获取成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "获取成功"
data:
type: array
items:
$ref: '#/components/schemas/User'
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 权限不足
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/{userId}/status:
put:
summary: 更新用户状态
description: 管理员更新用户状态
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
description: JWT访问令牌 (Bearer token)
- name: userId
in: path
required: true
schema:
type: integer
format: int64
description: 用户ID
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: integer
description: 用户状态 (1-正常, 0-禁用)
required:
- status
responses:
'200':
description: 状态更新成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
example: 200
message:
type: string
example: "状态更新成功"
'401':
description: 未授权访问
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 权限不足
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: 用户不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
User:
type: object
properties:
id:
type: integer
format: int64
description: 用户ID
username:
type: string
description: 用户名
email:
type: string
description: 邮箱
phone:
type: string
description: 手机号
nickname:
type: string
description: 昵称
avatar:
type: string
description: 头像URL
gender:
type: string
description: 性别
birthday:
type: string
format: date
description: 生日
status:
type: integer
description: 用户状态 (1-正常, 0-禁用)
createdAt:
type: string
format: date-time
description: 创建时间
updatedAt:
type: string
format: date-time
description: 更新时间
ErrorResponse:
type: object
properties:
timestamp:
type: string
format: date-time
description: 错误时间戳
status:
type: integer
description: HTTP状态码
error:
type: string
description: 错误信息
path:
type: string
description: 请求路径

View File

@@ -1,17 +0,0 @@
spring.application.name=user-center-service
server.port=8080
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_user?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# JWT配置
jwt.secret=xlxumu_user_center_secret_key_2024
jwt.expiration=86400000

View File

@@ -1,10 +0,0 @@
server.port=8082
spring.datasource.url=jdbc:mysql://localhost:3306/xlxumu_user?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

View File

@@ -1 +0,0 @@
/Users/ainongkeji/code/vue/xlxumu/backend-java/services/user-center-service/src/main/java/com/xlxumu/user/UserCenterApplication.java