From 59d24e74f4498659ddfe7ba2806b3286e9f06a23 Mon Sep 17 00:00:00 2001 From: ylweng Date: Thu, 11 Sep 2025 01:31:53 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=8C=E5=AE=8C=E5=96=84=E9=9C=80=E6=B1=82?= =?UTF-8?q?=E5=92=8C=E6=8A=80=E6=9C=AF=E7=BB=86=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin_website/src/views/Orders.vue | 382 +++++++++++++++ admin_website/src/views/Statistics.vue | 454 ++++++++++++++++++ .../common/common_1756737289808-860828577.txt | 1 + .../common/common_1756737304923-784117070.txt | 1 + docs/API接口文档.md | 4 +- docs/README.md | 3 + docs/项目总览.md | 12 +- java-backend/pom.xml | 105 ++++ .../com/aijianhua/backend/Application.java | 11 + .../backend/config/SecurityConfig.java | 50 ++ .../backend/config/SwaggerResourceConfig.java | 18 + .../backend/config/WebMvcConfig.java | 22 + .../backend/controller/AuthController.java | 75 +++ .../backend/controller/HealthController.java | 28 ++ .../backend/controller/UploadController.java | 88 ++++ .../aijianhua/backend/dto/ApiResponse.java | 38 ++ .../aijianhua/backend/dto/LoginRequest.java | 21 + .../aijianhua/backend/dto/PageResponse.java | 62 +++ .../backend/dto/RegisterRequest.java | 42 ++ .../aijianhua/backend/dto/UploadResponse.java | 58 +++ .../aijianhua/backend/dto/UserResponse.java | 81 ++++ .../com/aijianhua/backend/entity/Upload.java | 155 ++++++ .../com/aijianhua/backend/entity/User.java | 144 ++++++ .../backend/exception/BusinessException.java | 18 + .../exception/GlobalExceptionHandler.java | 72 +++ .../exception/UnauthorizedException.java | 7 + .../backend/interceptor/JwtInterceptor.java | 36 ++ .../backend/repository/UploadRepository.java | 13 + .../backend/repository/UserRepository.java | 17 + .../security/JwtAuthenticationEntryPoint.java | 25 + .../security/JwtAuthenticationFilter.java | 58 +++ .../backend/service/AuthService.java | 111 +++++ .../backend/service/UploadService.java | 119 +++++ .../com/aijianhua/backend/util/JwtUtil.java | 82 ++++ java-backend/src/main/resources/api-docs.yaml | 437 +++++++++++++++++ .../src/main/resources/application.yml | 47 ++ .../db/migration/V1__Initial_Setup.sql | 29 ++ java-backend/target/classes/api-docs.yaml | 437 +++++++++++++++++ java-backend/target/classes/application.yml | 47 ++ .../com/aijianhua/backend/Application.class | Bin 0 -> 731 bytes .../backend/config/SecurityConfig.class | Bin 0 -> 4283 bytes .../config/SwaggerResourceConfig.class | Bin 0 -> 1343 bytes .../backend/config/WebMvcConfig.class | Bin 0 -> 1502 bytes .../backend/controller/AuthController.class | Bin 0 -> 4009 bytes .../backend/controller/HealthController.class | Bin 0 -> 1423 bytes .../backend/controller/UploadController.class | Bin 0 -> 4861 bytes .../aijianhua/backend/dto/ApiResponse.class | Bin 0 -> 2246 bytes .../aijianhua/backend/dto/LoginRequest.class | Bin 0 -> 791 bytes .../backend/dto/PageResponse$PageData.class | Bin 0 -> 1214 bytes .../backend/dto/PageResponse$Pagination.class | Bin 0 -> 830 bytes .../aijianhua/backend/dto/PageResponse.class | Bin 0 -> 2370 bytes .../backend/dto/RegisterRequest.class | Bin 0 -> 1295 bytes .../backend/dto/UploadResponse.class | Bin 0 -> 1689 bytes .../aijianhua/backend/dto/UserResponse.class | Bin 0 -> 2164 bytes .../com/aijianhua/backend/entity/Upload.class | Bin 0 -> 4008 bytes .../com/aijianhua/backend/entity/User.class | Bin 0 -> 3836 bytes .../backend/exception/BusinessException.class | Bin 0 -> 707 bytes .../exception/GlobalExceptionHandler.class | Bin 0 -> 6441 bytes .../exception/UnauthorizedException.class | Bin 0 -> 456 bytes .../backend/interceptor/JwtInterceptor.class | Bin 0 -> 2241 bytes .../backend/repository/UploadRepository.class | Bin 0 -> 1123 bytes .../backend/repository/UserRepository.class | Bin 0 -> 1204 bytes .../JwtAuthenticationEntryPoint.class | Bin 0 -> 1431 bytes .../security/JwtAuthenticationFilter.class | Bin 0 -> 3459 bytes .../backend/service/AuthService.class | Bin 0 -> 4561 bytes .../backend/service/UploadService.class | Bin 0 -> 6151 bytes .../com/aijianhua/backend/util/JwtUtil.class | Bin 0 -> 3742 bytes .../db/migration/V1__Initial_Setup.sql | 29 ++ .../compile/default-compile/createdFiles.lst | 28 ++ .../compile/default-compile/inputFiles.lst | 26 + 70 files changed, 3487 insertions(+), 6 deletions(-) create mode 100644 admin_website/src/views/Orders.vue create mode 100644 admin_website/src/views/Statistics.vue create mode 100644 backend/uploads/common/common_1756737289808-860828577.txt create mode 100644 backend/uploads/common/common_1756737304923-784117070.txt create mode 100644 java-backend/pom.xml create mode 100644 java-backend/src/main/java/com/aijianhua/backend/Application.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/config/SecurityConfig.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/config/SwaggerResourceConfig.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/config/WebMvcConfig.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/controller/AuthController.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/controller/HealthController.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/controller/UploadController.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/dto/ApiResponse.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/dto/LoginRequest.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/dto/PageResponse.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/dto/RegisterRequest.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/dto/UploadResponse.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/dto/UserResponse.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/entity/Upload.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/entity/User.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/exception/BusinessException.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/exception/GlobalExceptionHandler.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/exception/UnauthorizedException.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/interceptor/JwtInterceptor.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/repository/UploadRepository.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/repository/UserRepository.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationFilter.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/service/AuthService.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/service/UploadService.java create mode 100644 java-backend/src/main/java/com/aijianhua/backend/util/JwtUtil.java create mode 100644 java-backend/src/main/resources/api-docs.yaml create mode 100644 java-backend/src/main/resources/application.yml create mode 100644 java-backend/src/main/resources/db/migration/V1__Initial_Setup.sql create mode 100644 java-backend/target/classes/api-docs.yaml create mode 100644 java-backend/target/classes/application.yml create mode 100644 java-backend/target/classes/com/aijianhua/backend/Application.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/config/SecurityConfig.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/config/SwaggerResourceConfig.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/config/WebMvcConfig.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/controller/AuthController.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/controller/HealthController.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/controller/UploadController.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/ApiResponse.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/LoginRequest.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/PageResponse$PageData.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/PageResponse$Pagination.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/PageResponse.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/RegisterRequest.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/UploadResponse.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/dto/UserResponse.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/entity/Upload.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/entity/User.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/exception/BusinessException.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/exception/GlobalExceptionHandler.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/exception/UnauthorizedException.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/interceptor/JwtInterceptor.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/repository/UploadRepository.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/repository/UserRepository.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/security/JwtAuthenticationFilter.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/service/AuthService.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/service/UploadService.class create mode 100644 java-backend/target/classes/com/aijianhua/backend/util/JwtUtil.class create mode 100644 java-backend/target/classes/db/migration/V1__Initial_Setup.sql create mode 100644 java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst diff --git a/admin_website/src/views/Orders.vue b/admin_website/src/views/Orders.vue new file mode 100644 index 0000000..831d61f --- /dev/null +++ b/admin_website/src/views/Orders.vue @@ -0,0 +1,382 @@ + + + + + \ No newline at end of file diff --git a/admin_website/src/views/Statistics.vue b/admin_website/src/views/Statistics.vue new file mode 100644 index 0000000..a779420 --- /dev/null +++ b/admin_website/src/views/Statistics.vue @@ -0,0 +1,454 @@ + + + + + \ No newline at end of file diff --git a/backend/uploads/common/common_1756737289808-860828577.txt b/backend/uploads/common/common_1756737289808-860828577.txt new file mode 100644 index 0000000..d670460 --- /dev/null +++ b/backend/uploads/common/common_1756737289808-860828577.txt @@ -0,0 +1 @@ +test content diff --git a/backend/uploads/common/common_1756737304923-784117070.txt b/backend/uploads/common/common_1756737304923-784117070.txt new file mode 100644 index 0000000..d670460 --- /dev/null +++ b/backend/uploads/common/common_1756737304923-784117070.txt @@ -0,0 +1 @@ +test content diff --git a/docs/API接口文档.md b/docs/API接口文档.md index 6375cda..336544c 100644 --- a/docs/API接口文档.md +++ b/docs/API接口文档.md @@ -6,7 +6,9 @@ ## 基础信息 -- **Base URL**: `http://localhost:3200/api/v1` +- **Base URL**: + - Node.js后端: `http://localhost:3000/api/v1` + - Java后端: `http://localhost:3200` - **认证方式**: Bearer Token (JWT) - **响应格式**: JSON - **字符编码**: UTF-8 diff --git a/docs/README.md b/docs/README.md index da3f835..d900b16 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,6 +9,9 @@ - SQLite(开发环境) - MySQL(生产环境) - Redis +- Java +- Spring Boot +- Maven ## 文档结构 - 需求文档: 项目业务需求和功能说明 diff --git a/docs/项目总览.md b/docs/项目总览.md index 770c01a..9ad3008 100644 --- a/docs/项目总览.md +++ b/docs/项目总览.md @@ -1,10 +1,10 @@ # 爱鉴花项目总览 -## 项目概述 -爱鉴花是一款通过AI图片识别植物类型的微信小程序应用,为用户提供花卉相关信息、购买、配送等服务。 +## 项目简介 +爱鉴花是一个集花卉识别、植物知识科普、在线商城于一体的综合性微信小程序平台。用户可以通过拍照识别花卉,获取详细的植物信息,同时可以在商城中购买相关产品。 ## 项目组成 -1. **微信小程序 (uni-app)** - 用户端应用,提供植物识别、商城购物、配送服务等功能 +1. **微信小程序 (uni-app)** - 前端用户界面,提供植物识别、植物知识、商城购物、配送服务等功能 2. **后端接口 (Node.js)** - 提供RESTful API服务,包括植物识别、用户管理、商品管理、订单管理等 3. **后台管理系统 (Vue3)** - 管理后台,用于用户管理、商品管理、订单管理、数据统计等 4. **官方网站 (HTML5 Bootstrap)** - 公司展示网站,提供产品介绍、公司信息、联系方式等 @@ -13,8 +13,10 @@ ## 技术架构 - **前端技术栈**: uni-app、Vue3、Element Plus、Bootstrap -- **后端技术栈**: Node.js、Express.js、MySQL(生产环境)、SQLite(开发环境)、Redis -- **开发工具**: HBuilderX、VSCode、Git +- **后端技术栈**: + - Node.js、Express.js、MySQL(生产环境)、SQLite(开发环境)、Redis + - Java Spring Boot(新后端,用于替代部分Node.js功能) +- **开发工具**: HBuilderX、VSCode、Git、Maven - **部署环境**: Nginx、Docker、云服务器 ## 项目文档 diff --git a/java-backend/pom.xml b/java-backend/pom.xml new file mode 100644 index 0000000..b10090f --- /dev/null +++ b/java-backend/pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + + com.aijianhua + backend + 1.0.0 + jar + + 爱鉴花后端服务 + 爱鉴花小程序Java版后端服务 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.0 + + + + + 1.8 + UTF-8 + UTF-8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-validation + + + + + mysql + mysql-connector-java + 8.0.28 + + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + org.apache.commons + commons-lang3 + + + + + org.projectlombok + lombok + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.flywaydb + flyway-core + + + + org.flywaydb + flyway-mysql + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/Application.java b/java-backend/src/main/java/com/aijianhua/backend/Application.java new file mode 100644 index 0000000..28b354b --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/Application.java @@ -0,0 +1,11 @@ +package com.aijianhua.backend; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/config/SecurityConfig.java b/java-backend/src/main/java/com/aijianhua/backend/config/SecurityConfig.java new file mode 100644 index 0000000..0d2bde2 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/config/SecurityConfig.java @@ -0,0 +1,50 @@ +package com.aijianhua.backend.config; + +import com.aijianhua.backend.security.JwtAuthenticationEntryPoint; +import com.aijianhua.backend.security.JwtAuthenticationFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + + @Autowired + private JwtAuthenticationFilter jwtAuthenticationFilter; + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable() + .authorizeRequests() + .antMatchers("/api/v1/auth/**").permitAll() + .antMatchers("/health").permitAll() + .anyRequest().authenticated() + .and() + .exceptionHandling() + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + // 添加JWT过滤器 + http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/config/SwaggerResourceConfig.java b/java-backend/src/main/java/com/aijianhua/backend/config/SwaggerResourceConfig.java new file mode 100644 index 0000000..e315d4b --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/config/SwaggerResourceConfig.java @@ -0,0 +1,18 @@ +package com.aijianhua.backend.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class SwaggerResourceConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("swagger-ui.html") + .addResourceLocations("classpath:/META-INF/resources/"); + + registry.addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/"); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/config/WebMvcConfig.java b/java-backend/src/main/java/com/aijianhua/backend/config/WebMvcConfig.java new file mode 100644 index 0000000..e355238 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/config/WebMvcConfig.java @@ -0,0 +1,22 @@ +package com.aijianhua.backend.config; + +import com.aijianhua.backend.interceptor.JwtInterceptor; +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 WebMvcConfig implements WebMvcConfigurer { + + @Autowired + private JwtInterceptor jwtInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册JWT拦截器,排除认证相关接口 + registry.addInterceptor(jwtInterceptor) + .addPathPatterns("/api/v1/**") + .excludePathPatterns("/api/v1/auth/**"); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/controller/AuthController.java b/java-backend/src/main/java/com/aijianhua/backend/controller/AuthController.java new file mode 100644 index 0000000..7d8d3a1 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/controller/AuthController.java @@ -0,0 +1,75 @@ +package com.aijianhua.backend.controller; + +import com.aijianhua.backend.dto.ApiResponse; +import com.aijianhua.backend.dto.LoginRequest; +import com.aijianhua.backend.dto.RegisterRequest; +import com.aijianhua.backend.dto.UserResponse; +import com.aijianhua.backend.entity.User; +import com.aijianhua.backend.service.AuthService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api/v1/auth") +public class AuthController { + + @Autowired + private AuthService authService; + + /** + * 用户注册 + */ + @PostMapping("/register") + public ApiResponse> register(@Valid @RequestBody RegisterRequest registerRequest) { + User user = authService.register(registerRequest); + + // 生成JWT token + String token = authService.generateToken(user); + + // 构造响应数据 + Map data = new HashMap<>(); + data.put("user_id", user.getId()); + data.put("username", user.getUsername()); + data.put("phone", user.getPhone()); + data.put("email", user.getEmail()); + data.put("user_type", user.getUserType()); + data.put("token", token); + + return ApiResponse.created(data); + } + + /** + * 用户登录 + */ + @PostMapping("/login") + public ApiResponse> login(@Valid @RequestBody LoginRequest loginRequest) { + User user = authService.login(loginRequest); + + // 生成JWT token + String token = authService.generateToken(user); + + // 构造响应数据 + Map data = new HashMap<>(); + data.put("user_id", user.getId()); + data.put("username", user.getUsername()); + data.put("phone", user.getPhone()); + data.put("email", user.getEmail()); + data.put("user_type", user.getUserType()); + data.put("avatar_url", user.getAvatarUrl()); + data.put("token", token); + + return ApiResponse.success("登录成功", data); + } + + /** + * 获取当前用户信息 + */ + @GetMapping("/me") + public ApiResponse getCurrentUser(@RequestAttribute("userId") Long userId) { + UserResponse userResponse = authService.getUserInfo(userId); + return ApiResponse.success(userResponse); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/controller/HealthController.java b/java-backend/src/main/java/com/aijianhua/backend/controller/HealthController.java new file mode 100644 index 0000000..c02b61e --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/controller/HealthController.java @@ -0,0 +1,28 @@ +package com.aijianhua.backend.controller; + +import com.aijianhua.backend.dto.ApiResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 健康检查控制器 + */ +@RestController +@RequestMapping("/health") +public class HealthController { + + @GetMapping + public ApiResponse> healthCheck() { + Map healthInfo = new HashMap<>(); + healthInfo.put("status", "UP"); + healthInfo.put("timestamp", LocalDateTime.now()); + healthInfo.put("service", "aijianhua-backend"); + + return ApiResponse.success(healthInfo); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/controller/UploadController.java b/java-backend/src/main/java/com/aijianhua/backend/controller/UploadController.java new file mode 100644 index 0000000..dbcc512 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/controller/UploadController.java @@ -0,0 +1,88 @@ +package com.aijianhua.backend.controller; + +import com.aijianhua.backend.dto.ApiResponse; +import com.aijianhua.backend.dto.PageResponse; +import com.aijianhua.backend.dto.UploadResponse; +import com.aijianhua.backend.entity.Upload; +import com.aijianhua.backend.service.UploadService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api/v1/upload") +public class UploadController { + + @Autowired + private UploadService uploadService; + + /** + * 文件上传 + */ + @PostMapping + public ApiResponse uploadFile( + @RequestParam("file") MultipartFile file, + @RequestParam(value = "type", required = false) String type, + HttpServletRequest request) throws IOException { + + // 从请求中获取用户ID + Long userId = (Long) request.getAttribute("userId"); + + // 上传文件 + Upload upload = uploadService.uploadFile(file, type, userId); + + // 构造响应数据 + UploadResponse uploadResponse = new UploadResponse(); + uploadResponse.setUrl(upload.getFilePath()); + uploadResponse.setFilename(upload.getStoredName()); + uploadResponse.setOriginalName(upload.getOriginalName()); + uploadResponse.setSize(upload.getFileSize()); + uploadResponse.setMimeType(upload.getMimeType()); + uploadResponse.setUploadType(upload.getUploadType()); + + return ApiResponse.success("上传成功", uploadResponse); + } + + /** + * 获取上传文件列表 + */ + @GetMapping + public PageResponse getUploads( + @RequestParam(value = "page", defaultValue = "1") int page, + @RequestParam(value = "limit", defaultValue = "10") int limit, + @RequestParam(value = "type", required = false) String type, + HttpServletRequest request) { + + // 从请求中获取用户ID + Long userId = (Long) request.getAttribute("userId"); + + // 获取文件列表 + Page uploads = uploadService.getUploads(userId, type, page, limit); + + return PageResponse.success(uploads); + } + + /** + * 删除上传文件 + */ + @DeleteMapping("/{id}") + public ApiResponse> deleteUpload( + @PathVariable Long id, + HttpServletRequest request) throws IOException { + + // 从请求中获取用户ID + Long userId = (Long) request.getAttribute("userId"); + + // 删除文件 + uploadService.deleteUpload(id, userId); + + Map data = new HashMap<>(); + data.put("message", "删除成功"); + return ApiResponse.success(data); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/dto/ApiResponse.java b/java-backend/src/main/java/com/aijianhua/backend/dto/ApiResponse.java new file mode 100644 index 0000000..e131be9 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/dto/ApiResponse.java @@ -0,0 +1,38 @@ +package com.aijianhua.backend.dto; + +import lombok.Data; + +@Data +public class ApiResponse { + private Integer code; + private String message; + private T data; + + public ApiResponse() {} + + public ApiResponse(Integer code, String message, T data) { + this.code = code; + this.message = message; + this.data = data; + } + + public static ApiResponse success(T data) { + return new ApiResponse<>(200, "操作成功", data); + } + + public static ApiResponse success(String message, T data) { + return new ApiResponse<>(200, message, data); + } + + public static ApiResponse created(T data) { + return new ApiResponse<>(201, "创建成功", data); + } + + public static ApiResponse error(Integer code, String message) { + return new ApiResponse<>(code, message, null); + } + + public static ApiResponse error(String message) { + return new ApiResponse<>(500, message, null); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/dto/LoginRequest.java b/java-backend/src/main/java/com/aijianhua/backend/dto/LoginRequest.java new file mode 100644 index 0000000..272fd56 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/dto/LoginRequest.java @@ -0,0 +1,21 @@ +package com.aijianhua.backend.dto; + +import lombok.Data; +import javax.validation.constraints.NotBlank; + +@Data +public class LoginRequest { + @NotBlank(message = "登录账号不能为空") + private String login; + + @NotBlank(message = "密码不能为空") + private String password; + + public String getLogin() { + return login; + } + + public String getPassword() { + return password; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/dto/PageResponse.java b/java-backend/src/main/java/com/aijianhua/backend/dto/PageResponse.java new file mode 100644 index 0000000..2ac4c33 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/dto/PageResponse.java @@ -0,0 +1,62 @@ +package com.aijianhua.backend.dto; + +import lombok.Data; +import org.springframework.data.domain.Page; + +@Data +public class PageResponse { + private Integer code; + private String message; + private PageData data; + + public PageResponse() {} + + public PageResponse(Integer code, String message, PageData data) { + this.code = code; + this.message = message; + this.data = data; + } + + public static PageResponse success(Page page) { + PageData pageData = new PageData<>(); + pageData.setItems(page.getContent()); + pageData.setPagination(new Pagination( + page.getNumber() + 1, + page.getSize(), + page.getTotalElements(), + page.getTotalPages() + )); + return new PageResponse<>(200, "获取成功", pageData); + } + + @Data + public static class PageData { + private Iterable items; + private Pagination pagination; + + public void setItems(Iterable items) { + this.items = items; + } + + public void setPagination(Pagination pagination) { + this.pagination = pagination; + } + } + + @Data + public static class Pagination { + private Integer page; + private Integer limit; + private Long total; + private Integer pages; + + public Pagination() {} + + public Pagination(Integer page, Integer limit, Long total, Integer pages) { + this.page = page; + this.limit = limit; + this.total = total; + this.pages = pages; + } + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/dto/RegisterRequest.java b/java-backend/src/main/java/com/aijianhua/backend/dto/RegisterRequest.java new file mode 100644 index 0000000..ba6e8dc --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/dto/RegisterRequest.java @@ -0,0 +1,42 @@ +package com.aijianhua.backend.dto; + +import lombok.Data; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +@Data +public class RegisterRequest { + @NotBlank(message = "用户名不能为空") + private String username; + + @NotBlank(message = "密码不能为空") + @Size(min = 6, message = "密码长度不能少于6位") + private String password; + + @NotBlank(message = "手机号不能为空") + private String phone; + + private String email; + + private String userType = "farmer"; + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getPhone() { + return phone; + } + + public String getEmail() { + return email; + } + + public String getUserType() { + return userType; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/dto/UploadResponse.java b/java-backend/src/main/java/com/aijianhua/backend/dto/UploadResponse.java new file mode 100644 index 0000000..9fcbafb --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/dto/UploadResponse.java @@ -0,0 +1,58 @@ +package com.aijianhua.backend.dto; + +public class UploadResponse { + private String url; + private String filename; + private String originalName; + private Long size; + private String mimeType; + private String uploadType; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public String getOriginalName() { + return originalName; + } + + public void setOriginalName(String originalName) { + this.originalName = originalName; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + public String getUploadType() { + return uploadType; + } + + public void setUploadType(String uploadType) { + this.uploadType = uploadType; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/dto/UserResponse.java b/java-backend/src/main/java/com/aijianhua/backend/dto/UserResponse.java new file mode 100644 index 0000000..d33dfd9 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/dto/UserResponse.java @@ -0,0 +1,81 @@ +package com.aijianhua.backend.dto; + +import lombok.Data; +import java.time.LocalDateTime; + +@Data +public class UserResponse { + private Long id; + private String username; + private String phone; + private String email; + private String userType; + private String avatarUrl; + private LocalDateTime createdAt; + private LocalDateTime lastLogin; + + // 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 getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getLastLogin() { + return lastLogin; + } + + public void setLastLogin(LocalDateTime lastLogin) { + this.lastLogin = lastLogin; + } +} diff --git a/java-backend/src/main/java/com/aijianhua/backend/entity/Upload.java b/java-backend/src/main/java/com/aijianhua/backend/entity/Upload.java new file mode 100644 index 0000000..ac002cf --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/entity/Upload.java @@ -0,0 +1,155 @@ +package com.aijianhua.backend.entity; + +import lombok.Data; +import javax.persistence.*; +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name = "uploads") +public class Upload { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "user_id", nullable = false) + private Long userId; + + @Column(name = "original_name", nullable = false) + private String originalName; + + @Column(name = "stored_name", nullable = false) + private String storedName; + + @Column(name = "file_path", nullable = false) + private String filePath; + + @Column(name = "file_size", nullable = false) + private Long fileSize; + + @Column(name = "mime_type", nullable = false) + private String mimeType; + + @Column(name = "file_type") + private String fileType; + + @Column(name = "upload_type", nullable = false) + private String uploadType; + + @Column(nullable = false) + private String status = "active"; + + @Column(name = "created_at", nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @PrePersist + protected void onCreate() { + createdAt = LocalDateTime.now(); + updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + updatedAt = LocalDateTime.now(); + } + + // 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 getOriginalName() { + return originalName; + } + + public void setOriginalName(String originalName) { + this.originalName = originalName; + } + + public String getStoredName() { + return storedName; + } + + public void setStoredName(String storedName) { + this.storedName = storedName; + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public Long getFileSize() { + return fileSize; + } + + public void setFileSize(Long fileSize) { + this.fileSize = fileSize; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + public String getFileType() { + return fileType; + } + + public void setFileType(String fileType) { + this.fileType = fileType; + } + + public String getUploadType() { + return uploadType; + } + + public void setUploadType(String uploadType) { + this.uploadType = uploadType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String 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; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/entity/User.java b/java-backend/src/main/java/com/aijianhua/backend/entity/User.java new file mode 100644 index 0000000..3741ba9 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/entity/User.java @@ -0,0 +1,144 @@ +package com.aijianhua.backend.entity; + +import lombok.Data; +import javax.persistence.*; +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name = "users") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, unique = true) + private String username; + + @Column(name = "password_hash", nullable = false) + private String password; + + @Column(nullable = false, unique = true) + private String phone; + + @Column(unique = true) + private String email; + + @Column(name = "user_type", nullable = false) + private String userType; + + @Column(name = "avatar_url") + private String avatarUrl; + + @Column(nullable = false) + private Integer status = 1; + + @Column(name = "created_at", nullable = false, updatable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @Column(name = "last_login") + private LocalDateTime lastLogin; + + @PrePersist + protected void onCreate() { + createdAt = LocalDateTime.now(); + updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + updatedAt = LocalDateTime.now(); + } + + // 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 getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + 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; + } + + public LocalDateTime getLastLogin() { + return lastLogin; + } + + public void setLastLogin(LocalDateTime lastLogin) { + this.lastLogin = lastLogin; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/exception/BusinessException.java b/java-backend/src/main/java/com/aijianhua/backend/exception/BusinessException.java new file mode 100644 index 0000000..6d96b39 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/exception/BusinessException.java @@ -0,0 +1,18 @@ +package com.aijianhua.backend.exception; + +public class BusinessException extends RuntimeException { + private int code = 400; + + public BusinessException(String message) { + super(message); + } + + public BusinessException(int code, String message) { + super(message); + this.code = code; + } + + public int getCode() { + return code; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/exception/GlobalExceptionHandler.java b/java-backend/src/main/java/com/aijianhua/backend/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..cf2b34c --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/exception/GlobalExceptionHandler.java @@ -0,0 +1,72 @@ +package com.aijianhua.backend.exception; + +import com.aijianhua.backend.dto.ApiResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.HashMap; +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理参数验证异常(RequestBody参数验证) + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity>> handleValidationExceptions(MethodArgumentNotValidException ex) { + Map errors = new HashMap<>(); + ex.getBindingResult().getAllErrors().forEach((error) -> { + String fieldName = ((FieldError) error).getField(); + String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + return ResponseEntity.badRequest().body(new ApiResponse<>(400, "参数验证失败", errors)); + } + + /** + * 处理参数验证异常(方法调用时的验证) + */ + @ExceptionHandler(ConstraintViolationException.class) + public ResponseEntity>> handleConstraintViolationException(ConstraintViolationException ex) { + Map errors = new HashMap<>(); + for (ConstraintViolation violation : ex.getConstraintViolations()) { + String propertyPath = violation.getPropertyPath().toString(); + String message = violation.getMessage(); + errors.put(propertyPath, message); + } + return ResponseEntity.badRequest().body(new ApiResponse<>(400, "参数验证失败", errors)); + } + + /** + * 处理业务异常 + */ + @ExceptionHandler(BusinessException.class) + public ResponseEntity> handleBusinessException(BusinessException ex) { + return ResponseEntity.status(ex.getCode()).body(new ApiResponse<>(ex.getCode(), ex.getMessage(), null)); + } + + /** + * 处理未授权异常 + */ + @ExceptionHandler(UnauthorizedException.class) + public ResponseEntity> handleUnauthorizedException(UnauthorizedException ex) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new ApiResponse<>(401, ex.getMessage(), null)); + } + + /** + * 处理其他所有未处理的异常 + */ + @ExceptionHandler(Exception.class) + public ResponseEntity> handleGenericException(Exception ex) { + // 记录日志 + ex.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ApiResponse<>(500, "系统内部错误", null)); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/exception/UnauthorizedException.java b/java-backend/src/main/java/com/aijianhua/backend/exception/UnauthorizedException.java new file mode 100644 index 0000000..29fbeb4 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/exception/UnauthorizedException.java @@ -0,0 +1,7 @@ +package com.aijianhua.backend.exception; + +public class UnauthorizedException extends RuntimeException { + public UnauthorizedException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/interceptor/JwtInterceptor.java b/java-backend/src/main/java/com/aijianhua/backend/interceptor/JwtInterceptor.java new file mode 100644 index 0000000..f6dbe08 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/interceptor/JwtInterceptor.java @@ -0,0 +1,36 @@ +package com.aijianhua.backend.interceptor; + +import com.aijianhua.backend.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; + +@Component +public class JwtInterceptor implements HandlerInterceptor { + + @Autowired + private JwtUtil jwtUtil; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String authorizationHeader = request.getHeader("Authorization"); + + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + String token = authorizationHeader.substring(7); + + if (jwtUtil.validateToken(token) && !jwtUtil.isTokenExpired(token)) { + Long userId = jwtUtil.getUserIdFromToken(token); + request.setAttribute("userId", userId); + return true; + } + } + + // 未提供有效的认证token + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().write("{\"code\":401,\"message\":\"未提供有效的认证token\",\"data\":null}"); + return false; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/repository/UploadRepository.java b/java-backend/src/main/java/com/aijianhua/backend/repository/UploadRepository.java new file mode 100644 index 0000000..d2d4e7b --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/repository/UploadRepository.java @@ -0,0 +1,13 @@ +package com.aijianhua.backend.repository; + +import com.aijianhua.backend.entity.Upload; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UploadRepository extends JpaRepository { + Page findByUserId(Long userId, Pageable pageable); + Page findByUserIdAndUploadType(Long userId, String uploadType, Pageable pageable); +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/repository/UserRepository.java b/java-backend/src/main/java/com/aijianhua/backend/repository/UserRepository.java new file mode 100644 index 0000000..256ffad --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/repository/UserRepository.java @@ -0,0 +1,17 @@ +package com.aijianhua.backend.repository; + +import com.aijianhua.backend.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.Optional; + +@Repository +public interface UserRepository extends JpaRepository { + Optional findByUsernameOrPhoneOrEmailAndStatus(String username, String phone, String email, Integer status); + Optional findByUsername(String username); + Optional findByPhone(String phone); + Optional findByEmail(String email); + Boolean existsByUsername(String username); + Boolean existsByPhone(String phone); + Boolean existsByEmail(String email); +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.java b/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..f0ac403 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,25 @@ +package com.aijianhua.backend.security; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + + // 返回未授权的JSON响应 + response.getWriter().write("{\"code\":401,\"message\":\"未提供有效的认证token\",\"data\":null}"); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationFilter.java b/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..2754c1c --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationFilter.java @@ -0,0 +1,58 @@ +package com.aijianhua.backend.security; + +import com.aijianhua.backend.entity.User; +import com.aijianhua.backend.repository.UserRepository; +import com.aijianhua.backend.util.JwtUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; + +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserRepository userRepository; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + String authorizationHeader = request.getHeader("Authorization"); + + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + String token = authorizationHeader.substring(7); + + if (jwtUtil.validateToken(token) && !jwtUtil.isTokenExpired(token)) { + Long userId = jwtUtil.getUserIdFromToken(token); + + // 从数据库获取用户信息 + User user = userRepository.findById(userId).orElse(null); + + if (user != null && user.getStatus() == 1) { + // 创建认证对象 + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + // 设置安全上下文 + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + } + + filterChain.doFilter(request, response); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/service/AuthService.java b/java-backend/src/main/java/com/aijianhua/backend/service/AuthService.java new file mode 100644 index 0000000..775c2f3 --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/service/AuthService.java @@ -0,0 +1,111 @@ +package com.aijianhua.backend.service; + +import com.aijianhua.backend.dto.LoginRequest; +import com.aijianhua.backend.dto.RegisterRequest; +import com.aijianhua.backend.dto.UserResponse; +import com.aijianhua.backend.entity.User; +import com.aijianhua.backend.exception.BusinessException; +import com.aijianhua.backend.repository.UserRepository; +import com.aijianhua.backend.util.JwtUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import java.time.LocalDateTime; +import java.util.Optional; + +@Service +public class AuthService { + + @Autowired + private UserRepository userRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private JwtUtil jwtUtil; + + /** + * 用户注册 + */ + public User register(RegisterRequest registerRequest) { + // 检查用户是否已存在 + if (userRepository.existsByUsername(registerRequest.getUsername()) || + userRepository.existsByPhone(registerRequest.getPhone()) || + (registerRequest.getEmail() != null && userRepository.existsByEmail(registerRequest.getEmail()))) { + throw new BusinessException("用户名、手机号或邮箱已存在"); + } + + // 创建用户 + User user = new User(); + user.setUsername(registerRequest.getUsername()); + user.setPassword(passwordEncoder.encode(registerRequest.getPassword())); + user.setPhone(registerRequest.getPhone()); + user.setEmail(registerRequest.getEmail()); + user.setUserType(registerRequest.getUserType()); + user.setCreatedAt(LocalDateTime.now()); + user.setUpdatedAt(LocalDateTime.now()); + + return userRepository.save(user); + } + + /** + * 用户登录 + */ + public User login(LoginRequest loginRequest) { + // 查询用户(支持用户名、手机号、邮箱登录) + Optional userOptional = userRepository.findByUsernameOrPhoneOrEmailAndStatus( + loginRequest.getLogin(), + loginRequest.getLogin(), + loginRequest.getLogin(), + 1 + ); + + if (!userOptional.isPresent()) { + throw new BusinessException("用户不存在或已被禁用"); + } + + User user = userOptional.get(); + + // 验证密码 + if (!passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) { + throw new BusinessException("密码不正确"); + } + + // 更新最后登录时间 + user.setLastLogin(LocalDateTime.now()); + userRepository.save(user); + + return user; + } + + /** + * 生成JWT token + */ + public String generateToken(User user) { + return jwtUtil.generateToken(user.getId(), user.getUsername(), user.getUserType()); + } + + /** + * 获取用户信息 + */ + public UserResponse getUserInfo(Long userId) { + Optional userOptional = userRepository.findById(userId); + if (!userOptional.isPresent()) { + throw new BusinessException("用户不存在"); + } + + User user = userOptional.get(); + UserResponse userResponse = new UserResponse(); + userResponse.setId(user.getId()); + userResponse.setUsername(user.getUsername()); + userResponse.setPhone(user.getPhone()); + userResponse.setEmail(user.getEmail()); + userResponse.setUserType(user.getUserType()); + userResponse.setAvatarUrl(user.getAvatarUrl()); + userResponse.setCreatedAt(user.getCreatedAt()); + userResponse.setLastLogin(user.getLastLogin()); + + return userResponse; + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/service/UploadService.java b/java-backend/src/main/java/com/aijianhua/backend/service/UploadService.java new file mode 100644 index 0000000..b5cbb8b --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/service/UploadService.java @@ -0,0 +1,119 @@ +package com.aijianhua.backend.service; + +import com.aijianhua.backend.entity.Upload; +import com.aijianhua.backend.exception.BusinessException; +import com.aijianhua.backend.repository.UploadRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.UUID; + +@Service +public class UploadService { + + @Autowired + private UploadRepository uploadRepository; + + private static final String UPLOAD_DIR = "uploads/"; + + /** + * 文件上传 + */ + public Upload uploadFile(MultipartFile file, String uploadType, Long userId) throws IOException { + // 创建上传目录 + String typeDir = uploadType != null ? uploadType : "common"; + Path uploadPath = Paths.get(UPLOAD_DIR + typeDir); + if (!Files.exists(uploadPath)) { + Files.createDirectories(uploadPath); + } + + // 生成唯一文件名 + String originalFilename = file.getOriginalFilename(); + String fileExtension = ""; + if (originalFilename != null && originalFilename.contains(".")) { + fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".")); + } + String storedName = typeDir + "_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8) + fileExtension; + + // 保存文件 + Path filePath = uploadPath.resolve(storedName); + Files.write(filePath, file.getBytes()); + + // 保存文件记录到数据库 + Upload upload = new Upload(); + upload.setUserId(userId); + upload.setOriginalName(originalFilename); + upload.setStoredName(storedName); + upload.setFilePath("/" + uploadPath.toString() + "/" + storedName); + upload.setFileSize(file.getSize()); + upload.setMimeType(file.getContentType()); + upload.setFileType(getFileType(file.getContentType())); + upload.setUploadType(typeDir); + upload.setCreatedAt(LocalDateTime.now()); + upload.setUpdatedAt(LocalDateTime.now()); + + return uploadRepository.save(upload); + } + + /** + * 获取文件类型 + */ + private String getFileType(String mimeType) { + if (mimeType == null) { + return "other"; + } + if (mimeType.startsWith("image/")) { + return "image"; + } + if (mimeType.startsWith("video/")) { + return "video"; + } + if (mimeType.startsWith("audio/")) { + return "audio"; + } + return "other"; + } + + /** + * 获取上传文件列表 + */ + public Page getUploads(Long userId, String type, int page, int limit) { + Pageable pageable = PageRequest.of(page - 1, limit, Sort.by(Sort.Direction.DESC, "createdAt")); + + if (type != null && !type.isEmpty()) { + return uploadRepository.findByUserIdAndUploadType(userId, type, pageable); + } + + return uploadRepository.findByUserId(userId, pageable); + } + + /** + * 删除上传文件 + */ + public void deleteUpload(Long id, Long userId) throws IOException { + // 查询文件信息 + Upload upload = uploadRepository.findById(id).orElse(null); + if (upload == null || !upload.getUserId().equals(userId)) { + throw new BusinessException("文件不存在"); + } + + // 删除物理文件 + Path filePath = Paths.get(upload.getFilePath().substring(1)); // 移除开头的 "/" + if (Files.exists(filePath)) { + Files.delete(filePath); + } + + // 删除数据库记录 + uploadRepository.deleteById(id); + } +} \ No newline at end of file diff --git a/java-backend/src/main/java/com/aijianhua/backend/util/JwtUtil.java b/java-backend/src/main/java/com/aijianhua/backend/util/JwtUtil.java new file mode 100644 index 0000000..587d70d --- /dev/null +++ b/java-backend/src/main/java/com/aijianhua/backend/util/JwtUtil.java @@ -0,0 +1,82 @@ +package com.aijianhua.backend.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; + +@Component +public class JwtUtil { + + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiration}") + private Long expiration; + + /** + * 生成JWT token + */ + public String generateToken(Long userId, String username, String userType) { + Map claims = new HashMap<>(); + claims.put("userId", userId); + claims.put("username", username); + claims.put("user_type", userType); + return Jwts.builder() + .setClaims(claims) + .setSubject(username) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + + /** + * 验证JWT token + */ + public Boolean validateToken(String token) { + try { + Jwts.parser().setSigningKey(secret).parseClaimsJws(token); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 从token中获取用户ID + */ + public Long getUserIdFromToken(String token) { + Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + return Long.parseLong(claims.get("userId").toString()); + } + + /** + * 从token中获取用户名 + */ + public String getUsernameFromToken(String token) { + Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + return claims.getSubject(); + } + + /** + * 从token中获取用户类型 + */ + public String getUserTypeFromToken(String token) { + Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + return claims.get("user_type").toString(); + } + + /** + * 检查token是否过期 + */ + public Boolean isTokenExpired(String token) { + Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + Date expiration = claims.getExpiration(); + return expiration.before(new Date()); + } +} \ No newline at end of file diff --git a/java-backend/src/main/resources/api-docs.yaml b/java-backend/src/main/resources/api-docs.yaml new file mode 100644 index 0000000..b4a4681 --- /dev/null +++ b/java-backend/src/main/resources/api-docs.yaml @@ -0,0 +1,437 @@ +openapi: 3.0.0 +info: + title: 爱鉴花小程序API文档 + description: 爱鉴花小程序后端API接口文档 + version: 1.0.0 + +servers: + - url: http://localhost:8080/api/v1 + description: 本地开发服务器 + +paths: + /auth/register: + post: + summary: 用户注册 + description: 用户注册接口,支持用户名、手机号、邮箱注册 + operationId: register + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterRequest' + responses: + '200': + description: 注册成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUser' + '400': + description: 请求参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '409': + description: 用户已存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /auth/login: + post: + summary: 用户登录 + description: 用户登录接口,支持用户名、手机号、邮箱登录 + operationId: login + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LoginRequest' + responses: + '200': + description: 登录成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUser' + '400': + description: 请求参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '401': + description: 用户名或密码错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /auth/me: + get: + summary: 获取当前用户信息 + description: 获取当前登录用户信息 + operationId: getCurrentUser + security: + - bearerAuth: [] + responses: + '200': + description: 获取成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUser' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '404': + description: 用户不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /upload: + post: + summary: 上传文件 + description: 上传文件接口,支持图片、文档等文件类型 + operationId: uploadFile + security: + - bearerAuth: [] + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: 上传成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUpload' + '400': + description: 请求参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '500': + description: 服务器内部错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /upload/list: + get: + summary: 获取上传文件列表 + description: 获取当前用户上传的文件列表 + operationId: getUploads + security: + - bearerAuth: [] + responses: + '200': + description: 获取成功 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Upload' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /upload/{id}: + delete: + summary: 删除上传文件 + description: 删除指定ID的上传文件 + operationId: deleteUpload + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 删除成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseString' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '404': + description: 文件不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /health: + get: + summary: 服务健康检查 + description: 检查服务运行状态 + operationId: healthCheck + responses: + '200': + description: 服务正常 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseHealth' + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + + schemas: + RegisterRequest: + type: object + required: + - username + - password + - phone + properties: + username: + type: string + description: 用户名 + password: + type: string + minLength: 6 + description: 密码 + phone: + type: string + description: 手机号 + email: + type: string + format: email + description: 邮箱 + userType: + type: string + default: farmer + description: 用户类型 + + LoginRequest: + type: object + required: + - login + - password + properties: + login: + type: string + description: 登录凭证(用户名/手机号/邮箱) + password: + type: string + description: 密码 + + ApiResponseMap: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + type: object + description: 响应数据 + + ApiResponseUser: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + $ref: '#/components/schemas/UserResponse' + + ApiResponseUpload: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + $ref: '#/components/schemas/UploadResponse' + + ApiResponseError: + type: object + properties: + code: + type: integer + description: 错误码 + message: + type: string + description: 错误消息 + data: + type: object + nullable: true + description: 错误数据 + + UserResponse: + type: object + properties: + id: + type: integer + description: 用户ID + username: + type: string + description: 用户名 + phone: + type: string + description: 手机号 + email: + type: string + format: email + description: 邮箱 + userType: + type: string + description: 用户类型 + avatarUrl: + type: string + description: 头像URL + createdAt: + type: string + format: date-time + description: 创建时间 + lastLogin: + type: string + format: date-time + description: 最后登录时间 + + UploadResponse: + type: object + properties: + url: + type: string + description: 文件访问URL + filename: + type: string + description: 存储文件名 + originalName: + type: string + description: 原始文件名 + size: + type: integer + description: 文件大小 + mimeType: + type: string + description: MIME类型 + uploadType: + type: string + description: 上传类型 + + PageResponseUpload: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/Upload' + pagination: + $ref: '#/components/schemas/Pagination' + + Upload: + type: object + properties: + id: + type: integer + description: 文件ID + userId: + type: integer + description: 用户ID + originalName: + type: string + description: 原始文件名 + storedName: + type: string + description: 存储文件名 + filePath: + type: string + description: 文件路径 + fileSize: + type: integer + description: 文件大小 + mimeType: + type: string + description: MIME类型 + fileType: + type: string + description: 文件类型 + uploadType: + type: string + description: 上传类型 + createdAt: + type: string + format: date-time + description: 创建时间 + updatedAt: + type: string + format: date-time + description: 更新时间 + + Pagination: + type: object + properties: + page: + type: integer + description: 当前页码 + limit: + type: integer + description: 每页数量 + total: + type: integer + description: 总记录数 + pages: + type: integer + description: 总页数 \ No newline at end of file diff --git a/java-backend/src/main/resources/application.yml b/java-backend/src/main/resources/application.yml new file mode 100644 index 0000000..8a1a861 --- /dev/null +++ b/java-backend/src/main/resources/application.yml @@ -0,0 +1,47 @@ +server: + port: 3200 + +spring: + application: + name: aijianhua-backend + datasource: + url: jdbc:mysql://129.211.213.226:9527/xlxumudata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai + username: root + password: aiotAiot123! + driver-class-name: com.mysql.cj.jdbc.Driver + hikari: + maximum-pool-size: 20 + minimum-idle: 5 + connection-timeout: 30000 + idle-timeout: 10000 + max-lifetime: 1800000 + connection-test-query: SELECT 1 + jpa: + hibernate: + ddl-auto: update + show-sql: false + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL8Dialect + format_sql: true + open-in-view: false + flyway: + enabled: false + servlet: + multipart: + max-file-size: 10MB + max-request-size: 10MB + +# JWT配置 +jwt: + secret: xluMubackendSecretKey2024! + expiration: 604800000 # 7天 + +# 日志配置 +logging: + level: + com.aijianhua: INFO + org.springframework.web: INFO + org.hibernate.SQL: INFO + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" \ No newline at end of file diff --git a/java-backend/src/main/resources/db/migration/V1__Initial_Setup.sql b/java-backend/src/main/resources/db/migration/V1__Initial_Setup.sql new file mode 100644 index 0000000..e7824c7 --- /dev/null +++ b/java-backend/src/main/resources/db/migration/V1__Initial_Setup.sql @@ -0,0 +1,29 @@ +-- 创建用户表 +CREATE TABLE IF NOT EXISTS users ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + phone VARCHAR(20) UNIQUE, + email VARCHAR(100) UNIQUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + is_active BOOLEAN DEFAULT TRUE +); + +-- 创建文件上传表 +CREATE TABLE IF NOT EXISTS uploads ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT NOT NULL, + original_name VARCHAR(255) NOT NULL, + file_path VARCHAR(500) NOT NULL, + file_type VARCHAR(50) NOT NULL, + file_size BIGINT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); + +-- 创建索引 +CREATE INDEX idx_users_username ON users(username); +CREATE INDEX idx_users_phone ON users(phone); +CREATE INDEX idx_users_email ON users(email); +CREATE INDEX idx_uploads_user_id ON uploads(user_id); \ No newline at end of file diff --git a/java-backend/target/classes/api-docs.yaml b/java-backend/target/classes/api-docs.yaml new file mode 100644 index 0000000..b4a4681 --- /dev/null +++ b/java-backend/target/classes/api-docs.yaml @@ -0,0 +1,437 @@ +openapi: 3.0.0 +info: + title: 爱鉴花小程序API文档 + description: 爱鉴花小程序后端API接口文档 + version: 1.0.0 + +servers: + - url: http://localhost:8080/api/v1 + description: 本地开发服务器 + +paths: + /auth/register: + post: + summary: 用户注册 + description: 用户注册接口,支持用户名、手机号、邮箱注册 + operationId: register + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterRequest' + responses: + '200': + description: 注册成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUser' + '400': + description: 请求参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '409': + description: 用户已存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /auth/login: + post: + summary: 用户登录 + description: 用户登录接口,支持用户名、手机号、邮箱登录 + operationId: login + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LoginRequest' + responses: + '200': + description: 登录成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUser' + '400': + description: 请求参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '401': + description: 用户名或密码错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /auth/me: + get: + summary: 获取当前用户信息 + description: 获取当前登录用户信息 + operationId: getCurrentUser + security: + - bearerAuth: [] + responses: + '200': + description: 获取成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUser' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '404': + description: 用户不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /upload: + post: + summary: 上传文件 + description: 上传文件接口,支持图片、文档等文件类型 + operationId: uploadFile + security: + - bearerAuth: [] + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: 上传成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseUpload' + '400': + description: 请求参数错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '500': + description: 服务器内部错误 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /upload/list: + get: + summary: 获取上传文件列表 + description: 获取当前用户上传的文件列表 + operationId: getUploads + security: + - bearerAuth: [] + responses: + '200': + description: 获取成功 + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Upload' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /upload/{id}: + delete: + summary: 删除上传文件 + description: 删除指定ID的上传文件 + operationId: deleteUpload + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: 删除成功 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseString' + '401': + description: 未授权 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + '404': + description: 文件不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseError' + + /health: + get: + summary: 服务健康检查 + description: 检查服务运行状态 + operationId: healthCheck + responses: + '200': + description: 服务正常 + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponseHealth' + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + + schemas: + RegisterRequest: + type: object + required: + - username + - password + - phone + properties: + username: + type: string + description: 用户名 + password: + type: string + minLength: 6 + description: 密码 + phone: + type: string + description: 手机号 + email: + type: string + format: email + description: 邮箱 + userType: + type: string + default: farmer + description: 用户类型 + + LoginRequest: + type: object + required: + - login + - password + properties: + login: + type: string + description: 登录凭证(用户名/手机号/邮箱) + password: + type: string + description: 密码 + + ApiResponseMap: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + type: object + description: 响应数据 + + ApiResponseUser: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + $ref: '#/components/schemas/UserResponse' + + ApiResponseUpload: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + $ref: '#/components/schemas/UploadResponse' + + ApiResponseError: + type: object + properties: + code: + type: integer + description: 错误码 + message: + type: string + description: 错误消息 + data: + type: object + nullable: true + description: 错误数据 + + UserResponse: + type: object + properties: + id: + type: integer + description: 用户ID + username: + type: string + description: 用户名 + phone: + type: string + description: 手机号 + email: + type: string + format: email + description: 邮箱 + userType: + type: string + description: 用户类型 + avatarUrl: + type: string + description: 头像URL + createdAt: + type: string + format: date-time + description: 创建时间 + lastLogin: + type: string + format: date-time + description: 最后登录时间 + + UploadResponse: + type: object + properties: + url: + type: string + description: 文件访问URL + filename: + type: string + description: 存储文件名 + originalName: + type: string + description: 原始文件名 + size: + type: integer + description: 文件大小 + mimeType: + type: string + description: MIME类型 + uploadType: + type: string + description: 上传类型 + + PageResponseUpload: + type: object + properties: + code: + type: integer + description: 响应码 + message: + type: string + description: 响应消息 + data: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/Upload' + pagination: + $ref: '#/components/schemas/Pagination' + + Upload: + type: object + properties: + id: + type: integer + description: 文件ID + userId: + type: integer + description: 用户ID + originalName: + type: string + description: 原始文件名 + storedName: + type: string + description: 存储文件名 + filePath: + type: string + description: 文件路径 + fileSize: + type: integer + description: 文件大小 + mimeType: + type: string + description: MIME类型 + fileType: + type: string + description: 文件类型 + uploadType: + type: string + description: 上传类型 + createdAt: + type: string + format: date-time + description: 创建时间 + updatedAt: + type: string + format: date-time + description: 更新时间 + + Pagination: + type: object + properties: + page: + type: integer + description: 当前页码 + limit: + type: integer + description: 每页数量 + total: + type: integer + description: 总记录数 + pages: + type: integer + description: 总页数 \ No newline at end of file diff --git a/java-backend/target/classes/application.yml b/java-backend/target/classes/application.yml new file mode 100644 index 0000000..8a1a861 --- /dev/null +++ b/java-backend/target/classes/application.yml @@ -0,0 +1,47 @@ +server: + port: 3200 + +spring: + application: + name: aijianhua-backend + datasource: + url: jdbc:mysql://129.211.213.226:9527/xlxumudata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai + username: root + password: aiotAiot123! + driver-class-name: com.mysql.cj.jdbc.Driver + hikari: + maximum-pool-size: 20 + minimum-idle: 5 + connection-timeout: 30000 + idle-timeout: 10000 + max-lifetime: 1800000 + connection-test-query: SELECT 1 + jpa: + hibernate: + ddl-auto: update + show-sql: false + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL8Dialect + format_sql: true + open-in-view: false + flyway: + enabled: false + servlet: + multipart: + max-file-size: 10MB + max-request-size: 10MB + +# JWT配置 +jwt: + secret: xluMubackendSecretKey2024! + expiration: 604800000 # 7天 + +# 日志配置 +logging: + level: + com.aijianhua: INFO + org.springframework.web: INFO + org.hibernate.SQL: INFO + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" \ No newline at end of file diff --git a/java-backend/target/classes/com/aijianhua/backend/Application.class b/java-backend/target/classes/com/aijianhua/backend/Application.class new file mode 100644 index 0000000000000000000000000000000000000000..ae14b73378cd24e84c38a2c0209de4a1d11611bf GIT binary patch literal 731 zcmah{OK;Oa5dJnz>NErzQYe(iq3R{gfxVz!f+|5IPUazk!hzG+**crryU}`0`?q=m zao`8=qY$&EQhbPnCC_MH-|T!dzyJLF1>hx~_t3&lgmxbt>Az!c8xlYMzYkKJ6PK16RcX3Z(Y+WYH zwbLfMa8#%(>n>$tt(UXf*{I|;t}+72DBe6}np0U$zBW8FAHXK3@iyet8n3RsoLY0C zv&vDDt40fUhwwz8J+%uZupeuq-d9DU+~<%hFpOA>6uby+9T*hDrTf)4BcgipA;v)sJymFk_o7u{x>a7mX8#JbQ5oi)P`cxUO3pLlJ z4&xeQeZ2~SYw%|BJ%GF>%I>UJA%crlFz6C5MrD+ylIK)|}I&Z9Bg7O~=-kR6g!4yHU@K z%ID(o>2P@2RqjYZmVD(3Y`_<}D>~eRHnYhha2|4Snvyehmk3P++$# z`$fk!pQuUoxU4+i6Zm0sOVvjyvs`kO=aF2uU27y>BBWL=cD=Ph*KG32P$i$EC)J$k z`R>Ya5{CqK&C5lpThgA>bACYR4!kL_QKx^Cv@mEjZgae>GGhyT^Ar~*Nz(2J8A`T|OH zmXy0-`XiRrfdNubFDhyI#URF~Gz{UiKuX#xF<%7skS;Z7F^<6C84YIxgFAvODcd&< z>8nCu=N*kzi`yk3ZMM5`Uc>viKsKu7fCZ$@7{6Fdx4?r}!NvxwH4+YY;zKa%7d3nY zRdX}FG0NkcEHUE|W0b83OveI+!^HCkOm!*Se5;--cP+!DC7k-!ys#Oblo zw5!7MI^kHRvBFK9n;MzQWHY%O59bY~VSQ^1bq-TW+}1FSnXPlNMH~e7#<6b%^wSH7 zXhd?L1&S@Rv4!7Z8M&k3F765J|5sJGVp^eay71B!A)3hobzfkrB`JcPxON}ww>{Q|$FKr3gSu$N!pxO2`l_pVU zOx&2;PoFaK# zov2sS6-#3p9cl`iF8FHMuZKIzIBG+}()=>s=s_DcRAgl&Hx<+N}fKYXpDVlxwvSx{us2eV5k>#tFlb2Q$mMVBI z@fyYVgyZ?qphAL|L?NJEvu)*u+f^~lUkey53rh18RsjZgp^fNdfy1?7&2&EXVNjRC zJ4hf!ag>UzjV`zGkD3eudA7FmZG^q7u?>9*wt4a8v%nEL--7RL15Y7-38yGNgU{eC zZI(|h8h|+z*%B}@&&7ht=lBlBb^L+kou}yhnZMgmn}4`&en&jN>fR%cZHI*gBtl!y z=~Mt@cCdm}1-qW1tAc&)f8zB!iS9RY6&!ws-U?2{J^i(w3I@YZdIjggS?>+}h7T(E zxPnaB9{Uy93MOX;+5cJh=M_AdsUba&9bEMo0u87#oSo?4p{kVz&>YPC; zjZ-|(hj?h6A;PmEvVD=qF*5oN8xA8<3bFBO0*}A833h`peLmYz4l~rl_9EL${9opj ZmAiO?FWKnkkR$jC-|(*7%lEes{{Ubkg((04 literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/config/SwaggerResourceConfig.class b/java-backend/target/classes/com/aijianhua/backend/config/SwaggerResourceConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..638dea93a70b360264ec4c7ede1ec8d99c9fda6f GIT binary patch literal 1343 zcmb_cZBG+H5Pp^x?kq*1U=@4=U$8C08iRhY#srB(VvD9FCB{$NyXCs&dPnxQAV145 znwaPh@JAWvt}RqUOi21=XZL1q=9!mge*OOb6Tk-6GZ;h4LOP3aOfbx}#j)VN2t5A2 z*_MuBn0ToIWnM9)3dM#6`!A!q(JJt4WEiHS6XAJMuXWXW%XItYDUaWb`RR zPPpzrN(Q&^sdA3K2drGIj4Esbsca+1aL4gQ6deiEdcmu2_BPjccDK3igN=9w^SEXq zpT+e!@#;tsFw74nUkRNAS7c*>VKS~~Tj+?FN;YmXto$G7z}muXhNn*0;X<{Q2wGji zo5DGifjj6*z1Q18(YKObS-8va`ts@R%Vzc1>G|ktsTtB+p(|;GDk_k>-A+^LJ<;^( zOD@jPZwRg8cmHGBv{b~fQMo+iGQ-?Z{rZzd&UOnUo0QXXvB6;LvvGYlLf6E;sx+<8 z{UBl%8L0_;rk?O*Tg4??ys%g6F*O(#YTdx7j%=t%Q9(D)$VOhCUkH literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/config/WebMvcConfig.class b/java-backend/target/classes/com/aijianhua/backend/config/WebMvcConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..5cfb83252d3580179e2435c81fceb689d2f83134 GIT binary patch literal 1502 zcmb_cZBG+H5PlX4SI){yc~Mk+!MC<3D`<>KjR_K8AVm$B65|*5u1mY6-6Pw*7C!ou zObjL_`UCt?#<^19NUDXz54W>>yEF65%ro=r_xGOw9^s*jKJ+_Cq%eR%hS92M3SJYs z%-?!d>05@ur%EgPjG;f1Ee;`xAqQ>>=a6E^`azuwRaHV)Lcu-ZZ%bX`exSEhnQuyO zt?4hf4-CWAmR-?S8ei_%z%VQpx@)WBM||~!PTs{ZMjVW$Forb4i@=n5W5+06-ZG*t zTY=f;E$Q)wG|if{hd_kZffZH-n#T~V%d%=%vq#WGsT8|l_?#*9GW}ZUQcaqeT0YxT zsgsz0;%Vc|JD508jSU+`nZy)>%f*i3%>|yzxwwdF2bWT~j4KQ)y+EJZKf?&+>Z<|M9?-^1ucXe*r%ucvS$if>%*`n9km^>p zjymO4*F2oLAv?F^oXF8$n3Z;iZbQGZrtb5$ zGbc0$y+q_m(wJkIrLQlVTqJMN{2L^Bn`CrHO%YB8jkMoHi82`|pp4`~Sh0cD4_SZI#EvJznjWo@) nam-+X;7+!^OdVM2cp;m(k9qRO>Gc4kLxlW6dtEq+XA$@VLmI%h literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/controller/AuthController.class b/java-backend/target/classes/com/aijianhua/backend/controller/AuthController.class new file mode 100644 index 0000000000000000000000000000000000000000..da5ddf08f5ba1f11e7b4a7f42836485ee4225792 GIT binary patch literal 4009 zcmcInTXz#x6#h<=HkS^i1O#dYxk_6uW3^al3Q{VUY6_(-MMT9(GEJwXGhr?*MZDD; z>WeQv_~c*EwOoL*^auDq(Es3r%kNAk>4YX-fwg$ZoH={W-e>Rce0!grzyACEPXGh> zCW#hAVu&heMVmn9ytb&RMa?Xz7qjzv&J}1IHcZ1kDG=%Dok<{$L<~sLIEptosFfw-*~49C@Nfr*|5TjpI$oeY*u>Nh>zanrpG*6OBfxXbEgy6L;M zMZt5}DzKrTo4T#J`m{wH1O^*z7B1-r0YV0V2?Lc0mH7Ib$kFOcd9Z=A8XZ9Dd2Ukv*dyo3Xc zX4L_1&hsyMq{FeEkiTV)q}NKqwu41+^ztO6&Y0ffz&3*;1NX_Sc72vSy@YOzKX_G97v!%h@^!K!DSAfNDgj$ISSo zI;-Fu&eNTuRWL}V@kV5l${D%lNoX6#n*vEDyQ|sPJ=;euqhMSjq7c;)|I1~Y$X%r5 zpC2DS`s0Vc?|%R2+n*#dmlRB5is3q5E~h(=@7@|7*W*P~IQjrwRxpDrtMnK%XDxxD zFswdp*8^43s&Y6qdJ0#i<2=ud& zmn{2+n$c#(Ng#EeHgz?F@e1eA_`R^ z#*hl}Bgk`F$di&1!J6vB)mv*3WVQw<9<5zEyw+++5)`A8G}t+=yK`24LX$_#%Yi46 zm@*2c=6W_y?7L@xaNwI?)LB!TbX7Wgv@R!?^sJgSc;klXIAJ+1ZI|Rl!s@Z86+K3i zP%9@Zu%njyvhdaLf4h&@EtRSUPlHLJ&d67q+f%Dr#jZxbd0zvTowoAJG=6D4#G9&c zYYDCR)w9axrgspy+w|J?3Q*{Bc>2R{Q-eF8gOz#Ivu);)tZV|upQsv!oFUw8GFN3Q z&>6}PzoN3>%Wsv!DX<Zz~l_o%CxuBckc zP#61E*KxzUtc~L}j!};6_xXI6GnJ#@*xGj=;upTO;5|O&XRz6R zpHFFk3veADaAb1|jo+p6zlcx{*nPhucJLlHjLVlp_ptfGLu|WxA6-Myu4w9cN?!O4 zdm^~PSr2D@)!7lwUarnwg>ef%IgEX{xf%t_@4G5$@gv~uoEeU-i>tm|{b#;Q)%1%4i149tY9TcVv-cR0$Z!LudRc#(5I6wBL;@C}56|8Pt?G zlqK_&+@PdYP#H8WVO#J~?%*PmKkFKVgA#7?TLNM$2b({Kzjk>pa^mtQ*ywp>I7LSQ z=Sl$QnP&;-7{Pt3f@rD&Zt6l;^Z_PT;XOhI0sV|&fWQnAfMW#mINyc{Z<_E96W$ZB z2-$7+SgR1PR3To$B9<6w0?Sp1OI3&qYao`A5X6ggpbYV?IuI{60r72o$Wxb$ognlP zjvWES)8mI8;B6UhnfLN9F>s!)j`^YNDzC1F(t$hp$Pc9zALA3Q4tQ{fYGo%stvdNx jl?N;S!SheEz~@rv&`b-y@VEWaU!UUqE6%^J>fHSwt3qV6 literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/controller/HealthController.class b/java-backend/target/classes/com/aijianhua/backend/controller/HealthController.class new file mode 100644 index 0000000000000000000000000000000000000000..c8148da9c749a8e06dc215d4566dfe9b7bdda695 GIT binary patch literal 1423 zcmb7E>rN9v6#k|Kb}2=mNV%zaLs}3<1Qacj5R76{F9F0D|2W+a?Z9?--3!DA@O|_b zsEH5YLmAI(3kXzG=f}*P>-Wu>GxPJ;w;urJ@hF7^k_Ot+Xh#P_?~d3L+!juSzbx%Y zD`eue#8KUITq; zWYEvheG*Agl+ud`VKG-c3tKp^$)8u57+~lORZS9VjaUp~$iQ$KBN$~EjFW0BFS?en zAB#|Kl0>kMyU#G1Yot8yQZR9u!3d*!T!?K0%4+|Bu(DG^1c>XFZ!ZC6u0)iq?!o~HWIJEFUA+I8uVme~k>wk$Hs@*9W}pv~G^gth zn8Iz67^X3UWE}j7R-Kf8hw=6RoyDn4DwF<-3rW10%3M4|_Go`8bEUC8#MRFfl7xoI z5))tmChhv^CmF*KL5{?**?Q^*tceNYdWYa=DMC}KYwpr+jx-7SSQlv3#P7xO{diuC SwHdNMAo(F#3-7=JEd2(H8-pMK literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/controller/UploadController.class b/java-backend/target/classes/com/aijianhua/backend/controller/UploadController.class new file mode 100644 index 0000000000000000000000000000000000000000..8d5577bbeed22cef7d3afb57ec4be3618ad4ad82 GIT binary patch literal 4861 zcmd5Bp`JWX$gW!AWR}CnjmcoDya!c6NnXSb#`~M8Q7g!XJ-S! zm%g_YZPnV=+S*E6`u43or)S05qy5~!Lwim?_8;*0+&i;7voIT?9zA}TnS1Zt-|zmO z=l62&{m=XVd>g<){56XNk{P5lq|qgC(-~vM(94Eh(r5E$%z`J-b=a~k?}$KhaA>g` z-5jacOn0i-gDiS7&@}X-PhhtcJ+JfEO4;=EWzVbX$N5_D2jt>Dmw36vfdY)_L z>z*mFXK*@PbAiKlX<{fc(!A$~v;mm2rE^R7ufqDWCgPR(hpc=u6to{+Hp&Itt#;^xkkl2=eTF}b7o$z)XSb#HC#`hX||-y zM1-S&w#bO2hcw0;WZItPtp-@g><)p!_?bn|38u}PwW?#+%q(t0GK-xU$Y7U-+p$|< zSG;iBG6FsHyEJ^x@RkL(3`U(C0FcV>&@hN023gJYPPt`)o8tmxQJSz7f$2rmeeHIT2U87hf(1M1OIK_M*3BKuEW;(iz zVk{Ee!Ln0RL$OIyG(1BuIu*mR^*N(ta+QbiwG1ASpii^nbOtS_hp6Y`lkz(KYoU#5 zRB*qp;W2!JZYi29lctZDIkXnwAY?LlLSU1sfpyO+>&K1S@{Cc<;&CLqQJ|YD^bsL+ zgVCwIck%N7UcKV`y$2;MXJBbKgR=~iPze>Vv{&n_%=biX2s{~~z2)1m3I{_nsw$FQ zTVNta$yx+O;%q`7H(zIQs+fyb&B~X}N!xZj!?Rd1asGcc2?G%jiqTyPy9}K3vWsB<_=uke_*ig9C z%ke?;5i0o&_tK69{@OGn0ZVF|8H=TGE!!ySv64upLbnGA$bfU3yZRmK_l-^F5hJ2V z1-3j;sFKBc)PeH0t%M}^`2u084tEf|egmU)_Wtt)v#O#hgYOA!R>&+zpPFs`p`A0P zx9k+>47nS7rpt)fuwa#J!>haGfjn%=pp90N4|Y>beaH|1@Y>zc~kE z;mHDXZA?ALBTp-&xEU@PJl!t(z87NxiLp_EC!(84cntV>4sYLa5>}B;moAk1L)*Tn za-?nKaEA!=Z%jcW@Dl#EYuSXo#&(H>#GtGN${f z&dWtVFUGR&B;@6iUx&ReeyjYZ_~mt(?pLr7-68JYZj;DtIflYh&B3&sJ}eia-^hFz^FD3H-1{_eJ)9#Aip65|{Wq zSL1xyOvvUcoF$Jv5jNuTe!97MB$-eN_BA kKF>W0QKPdZKb$J?2R3B%Tv6{os>w2q|HS^ETLORi02cs_@&Et; literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/dto/ApiResponse.class b/java-backend/target/classes/com/aijianhua/backend/dto/ApiResponse.class new file mode 100644 index 0000000000000000000000000000000000000000..21f01d7f19aff9028b914bebf78a79e56f45f9fc GIT binary patch literal 2246 zcmbtV+inv_82-jiaGW^7PK*nMHlzu~UI$D$^bkj>qDmm7grFv}#N}i?I2)36v|c0i z4Wdd&NL;oOuK*Vj2t=>jK1ah7^t$RdyR*$iaTHT-c4lYi|4#pS{O3P!egkk5^mZDoB^xuL+RdC&L41%Y(A(#T>6*$jqr7(q_plH1;{NpI7W z{zg~U)}{MM`OR80Y}XcdydPC(r|ox?z<}Fsa+p{;fWPa9s-=RuMjXrGH1YzOZPn?> z7I%(YJ6FTN^IOrz@f;>lBwka7^6;)$F8!47Nd{+gIEPOK3P%XZ@>p(l)yhMGQu%Jh zB1$9;;etT!{j(>3z5Dh3?$iCBpAS>y=Q^TEfw^*z5^KrGwN{L@N@EC91m55MW&iD) z7+4^?>a~0sb_2RjudUT-?uRI>(@UPO?sd1r(Qe+Cf!tQ13Miu5Uo-@$G}wnu*LB%&fx2Cn zq}87q3b`}CHg`1bg|epU4c#R=GE@m8vi8AZs4lhp8l!k zt?TcqzJoBuD&L(u+pkX%P4#nolFcIWJ>AXSlM+QE(h|UO~L%B#lda z>dzq1mwe{p4Y-Ul-ztYz9KLC|N!Dq&UD6J4ENVEXx`&K2yN6Nd${q>_=p|MFque=$ zEM<;S=mZK8n-kX?HX=oKw3=dMNSiF`YnqH&ODVEl}*69Tg#h1vMQn#RtxmXH1%uRtZuk%^ea+dKhEeM+UUhzMlbw- zqc`}MAD@HojnNTp)Ts*NF=ZXDiR_)bzpt literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/dto/LoginRequest.class b/java-backend/target/classes/com/aijianhua/backend/dto/LoginRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..39acbab3138da014ce2d14adfccb48bba8c53fc1 GIT binary patch literal 791 zcma)4&rcIU6#i!0vZY-tw4k6OdXeJ6xp>2vsEMZr36S2WyOU+gb_RE6QIE#No8iR4 zn)t0_xn0TnPvX2;Y^_Au%ikNg!@=%7yaMw2-E>v3yy`2i)68?_V0S~O< z4HGK8Az!32A(BFrxeV3DMT1QnD;=(8lvg}dGQQ%jNRpQ(4j2|TQf*a7HdUfpk$kMR zvBD~&6Ncph%PYPoA{7jR+^2+%h0-?RYsNmIE9|T?xE+}!B9sjC{SV)JCkJPTpL+X8 zr^oNl-kzKucl)2a42#39wqEZJx2yKPyz75_GYrZwonsZJIRpPSF5!tIm#OY*o7VaH^ zeWMQt*T`mRz{NaS?{@(faGgAc8@Ne!7<>r#DJw+1bi&H+i) BwAKIs literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/dto/PageResponse$PageData.class b/java-backend/target/classes/com/aijianhua/backend/dto/PageResponse$PageData.class new file mode 100644 index 0000000000000000000000000000000000000000..a2ed33364795cefaa8963fa0109ddb7e890b07e4 GIT binary patch literal 1214 zcmb7DU2hUW6g|V&0#d11snz<86=>qdX!;<8#MGEHK_!;(;M)Kb7=&H2yO{X1d@v?H z_yhb=#xu)OsA2-yWM}T3JLlYc?ww!1fBXdS0@W;Hh+9bHkVHygcO*Ycdn}!S{k}U= zy+9yU*NzSv0`YRClR+983)vj5ASYn=+=(sqNK0oplXh43J}IYf_XF2%$$|Qy{Hg2s zs$`7UGLQmE9jJ*fu-9BNodwF1-La|}^s71Ku`7_B%7J!dpj}7cd2@53=u%A}bFK$O zn0ZRzU=3fr-L5qlmpFC%49PdOqu$LXUFEe+Is%2J+mqvt^t7=fXCfGC7VvC~l)~Cc zRJ@G$WxBvT*%oY(dfHb3H{M2B=(bzg$UcK2x>Ezb-cX+?{zn^+p@zudR;HQ!^?8xiiO6-sxESzVao&V)ruIUC?9#vkj%kd~C&rJ@08BTu3bZ-9+{fwTd*c5(tyf$H z*JSlO#Mkh6kAHIvg5BWXfG_|>>~p<&$#XzU;1+HZ*1&xXiFv&kXwftU#7S?vsLnh-$h+=Uv<*l%Z~|Qt$jtT_yGLf2fTvVx=&X hmZ6Ra^W4TG%KOyBi2D$axEfK@D6y^#>nfpw%pYG}6qo=2 literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/dto/PageResponse$Pagination.class b/java-backend/target/classes/com/aijianhua/backend/dto/PageResponse$Pagination.class new file mode 100644 index 0000000000000000000000000000000000000000..67bf05da04d6cf70c0d7c228431ceb3089af451b GIT binary patch literal 830 zcmb7C$!-%t5PfZr?br-SoUmosAwtQpj1WOAj<`fZiZqZ2kninr%WgC7iDufI`6Uh( z5(hqjk3zie1lb3K;8NAKy{cE$KYo7u4qy-49n?^7AqdexQ(%1}KglGQW|SNaCMvT6 z&3$dOeI-!e+3mNnf_4j?5a$pIJkE+~BK1T|GoHz0AhVCk43nWPl4Chi?^JbCm`ZKa z&_-Ha7=hq~5rNHg(dy7xHBx2Ip|6HmbI^@kPqlTPZio$R(qjuNbI!O_nHFZ`%Pxkv z*A!WBudT*2+7sF#&%Bixd;ThSxlS*W9w#ya$>PxJ)ad7SxUSE5sKczC!83z*B5d zhNlULaFv!TzD96Y{F%Bz9l7H8{v56N!5rt~hjXmQTfrO`7KjlsfoB}>Iof!ERlMX_ zJ$BglUG`3q&bkoO({NKno`@qCx!;7ke>pM%uJhdumrgQLHI z@j|`w*1w<^rDA8i^1|_d;P@*XpLcg-+bJ`q7tYS?Ip;m+ectE&I_HnSfB6-_1=uO{ zAYq`_L?4bQ3~$&EZL49sb!%yDLstWZBXf@H1oH}sOt#XGB>D}cOdN%&Fje)MmhEgf zw!7Z8tu?#)K)W@o7I@aOUDtQCzv;QYR_LvIH4ev0yZA*n&~@D^2;`uNAq*=RP3`+s zR7meRxe~M-w;mo$n>dD1;??ZHRybekj=-d_xkiMy+314~$0HLqzqZWsWCR9y!P9$j@A%5)|hxz!GwhE;O>pdipM zns^Ck6q3FUih*wW3gekQ{!`Yn*BZKztr$2027~C~o^4vPhC9}BKng|O5TQD&vrUp8& zl3qWB3Cv3!zoSsv7r(gD_J;JJC`5n8k!(eBbj8F~EYKu#L~C(e6=pMsD8X2Zc}(KE zg8A1s+fTp!{?A9>J^lKJ6x-lkVSiI$^*`9h4RHv|QSoOhO#g~gXHm3UY_i$IBFvS` zh4}*8Zy{{wp_1e3sFuo7pwhNp)oxVmmLuy}*c+@n%y_qvBL3KZm@hXwP%~XJ?hqZm zrGs^^wrop_vW-aN?*9|q$f88p@Y~fY?=gktOsSh&qLA&W~@})i95WNP4`R+W5gVCj19g~@7n>@&Z*XoMbZdLUSM~ZGl+Q0MGoRdq0 zy;XEw-CAhazOR{yq#TLDkm59MM4VyM_3$A~@XrU0vmSYf!jbO`6pG<|ktdYAko><# z$rX-@V_$9?>L*STDDf}bAk3}sA0EJMEOE8GPx3xj0(X;o0{4h!dpV8@TrR%_BR9Q; zf!xd%Mt0H1r~wS}7+&BG8Vc$%Jae{ z+7l=5a6XWrGN=YBAdbKaO_uRNO!zk#AwYQt$5*#8Udrd5;Do|sypZ3)#41;ltkruz zBg5%Ag=lhKCKoBW6iT-7_G4V$L2`8jzw<=;T7DZhex%JPoKv(3-n~iEO=BD<_?_kT zKaG>Ph*P*s*#b_70f-zbqk<2qlVmzRqO)v4u6FlU|J_^Uo;cg5sM2xrV;YVU{s}&% Wv=<-(gAs literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/dto/RegisterRequest.class b/java-backend/target/classes/com/aijianhua/backend/dto/RegisterRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..eb56632c25cdaccb4f6a78d740bfbd1ee6743ec9 GIT binary patch literal 1295 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 literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/entity/User.class b/java-backend/target/classes/com/aijianhua/backend/entity/User.class new file mode 100644 index 0000000000000000000000000000000000000000..9e5553bea333db4d506204d9e833a5536b8b7020 GIT binary patch literal 3836 zcmai$TUS#@6vy|3Ku9=PR>fK^ihwpY0u_jrwx)+#j)zJ6awaqTGQYiN&z}7K&!2x0(N)^bQHpvpl(wjs z`WWrsw72a-({}5HrHxHq4H@;_a$F~zVbn7@RnAdAWiynsXn-t6!yWaa8}d5$8D+NZ zX2h4CF&djJPL=j(+|1HG8p_aqi-u{0(L~j26>MkIvE4>w7dGtbbMDp(+zp*@x3Crn zpM61Shf%=jfWcpm4$^3b#wou)I4Qcewdjd7Pew=Q>j&!Thm zKBN8!LAtg;9Es_zgubISr!2}#%`H0!c09i(Hu%7z3u3W%tKqp^tQ0J|Bv*LLcA8@4 zLyNAw-C}ijOR8P7Xj&|0an_;julZ8-Ba3dxD4KQSHGXE%b}? z3yZ78)hCRO82rz9&8X!HJvVALZLs#Bz6q5Rxz3A7&KRS#%JN`4jg^KSG>`~!0F@9s zG0Lf=R3g8LiLQZ)jUvd(;}yOk&_^u=IgznSQ>83D=hdJvRB~Lt7_~OIzp6||WHpv; z-w|`Ym<}5ba(Slozn4J7=DBmSCK;VD^$VG(dr?ZApIBWGwXat7&o+`MrOw`JX2D{%eGM2{@D-b8Azjg} zXY`#=bh|_PvM_1ujKw2qtB6pVAsvm)mgMSnEkq6OJ=5tHh7@7`@$v7%hWWeI2k-6e%9Hh?es9Io2Om6x{i zqUj~f;PigmDY{?64AM`*f(I!fkh`VCi=YLg81GOI!J?@AJrKd9#1oLPh013TpsVf` zlxQ4_cysZ6h=k2SkzpLn|3NIDenXkpH2519QnZNg2&M7O;X477(_~>>!iuGgXqi68 zEKQFfO-YBd+Tl?C4IOw*<7znGak&pc5EUqcH)9`Nj=3As?!jX<9Nlv}w3^gGnae z$n>0=rh6Cbo~jpYgK4J=lWP2$X;?C~=&*rlJjwK}k;z5$hW<33%+q&Z`o0U3dUG_> zQOUGrWICQ?`oYNb!pszV5>%dk1kK&<-g%}(1u6ot;eyo=H}l=@uDWLn5@ zB%?1X8HegYFMMCjb)x3;zX(p0j+KBI2sj7UT^zFJLlKWu_F0Z*y!3}@Bxk2G(i>oX#fBK literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/exception/GlobalExceptionHandler.class b/java-backend/target/classes/com/aijianhua/backend/exception/GlobalExceptionHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..c3f08398d4453884cd3195ca3171a72f3997c73a GIT binary patch literal 6441 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 HZ>akpn%~8! literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/exception/UnauthorizedException.class b/java-backend/target/classes/com/aijianhua/backend/exception/UnauthorizedException.class new file mode 100644 index 0000000000000000000000000000000000000000..1bff234b5892331dd4175286b1e0947324b6e0eb GIT binary patch literal 456 zcmbVJyH3ME5S$B13?YyZ1VuVJ9ujUq6hUbaR0bge>DTtkxe%Yx`HT>MMTJDc2k=pd zJstuHD(6XG7nJm1hjMF(E-z9wGbYT>l zhuUa2R9M@LzI7vKwaErs;{fvt`$>_9q^Fw9q@pmUfYe|XoA zij);Pkv4o*Pub{#9+D5ae8zl)d}^8bzUd%F<(c zPL^_ZY^7FfR8%(M6YZPo|2f63cftk&*{MHDu54Ao%D2%-M0y7 zxvqIKN<0N&untMu0S9YX&LHh*3}h(-OWtgG)nf`$YLKI zisE9F*fzJvo7nHbb9mmuej5jHP~cQ4s5;V}ccov6rBjrp1?86=*Vig6shSQ#=klT+ zUnlAO{Gy)Lt|xG~&|Equ*NB;0`3!P+!NOr1M{raix3vh1b4Pk^S!y*E&>ewe%>v($ z+u$HtCcu}B-#hxZ4#>=B&P;Gd2cni-80b$UNbA(`=$Qq=*Y~ws$p)ZlrLz?9(#+tq~ zi*iGdbu8x%e)9tRWv%A9r3Agsd=&WkQbmSTcyW4a^u+m2T*RvuUbFE!h6v8B03Fo= zKcWxYs9_{vxqUr#uf~I>n42-`M{K--O9pdFPim>-NFYtjCCoQ%jA6XqA+w=NGzskK zZQ#)joa^ilU1u;o69U7Z5E*5a8$5gJ^gynvqDan>%B?*7Vdbl@|9t%2%EK>LzWw5_ z2cJLr@%tw~eWndEasxS{MCJzl*z-Qk;0mrg(v6=2Ua!tVD1PT@n%2>|y2!j{cUT}SNHLey_I3=l`s4D~|>CMQ{HFV=Jtt&3= zoq0An+Ey7Bk+tPx6Iq<37dR@c2M-ohIdQ7u;L>e}(utVb5?i zY@idfTDkwlAUkK8CXC9o7=| z47T?Ff@ia>OE|QIWB1XwN}eG30Q*+SQ-f{Cd(LLtmhn;w=|=-SgUh(kf`M-F%`%4h zvy4#|>GBc^sYf)Nf^qgF9R;7i40iGT+s$FUhx2YPCP+l6Tg*d+xrxX%L5nfttTt_%I1RhD4E>GiN1~X*YufC`zPpo2Ts%e`D674|Al_ al&N5ze_bi60EIy@llp~Z_0|ef1^xwPTy8S} literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/repository/UploadRepository.class b/java-backend/target/classes/com/aijianhua/backend/repository/UploadRepository.class new file mode 100644 index 0000000000000000000000000000000000000000..ff4976acdac37441d4f4358f035a0d4cebfd09cc GIT binary patch literal 1123 zcmc&z%T5A85bOcvB`7}7_y-yjCnkDYV}b`04Mqauy(rVM^ zHNUITt$e*m!V-gg8}E^KQF;8P-WCm;gam^VZ9E?MMk=pquqPh0>2Mb<^0tqYm{&fI z0U2bQQn}~-S|H4&%b>nj8pD^g@|@D2z^?A0RJ@Fyz)_v(52hHPdx2!o?|_$ zHnL|Cie|z=QidF!|AE8&>OD>bY?$8}g3QY9d?P2O4dNUbn5pW}G{lAMl4FIROLiC; zMlM%Ea=s_-WFRTsMWwVwE48Au9!yPoKv5RjQV#fd!yMX825~yewE8jH-z20U25EXq r#~?%33Y~0JgdCMuVQo~-#Ruj5x0ZFn8a8jh=HR0(DA1jt3EKc4j{Yx15FMvYwjZ=m%2)ZiA&QXj1x|~QS_!09sZuq9D{`{##_7gh*B6Uee=;T8#M6Ot?^ECG@Bed?1DwQYYNX z+&JZpo$~ii+OxSE(JG@GWARDwOz4#N24gw&5p@{7GB)Kdw@RnyR!rn)V=s6jyx`+p zG!c(;Q3Eo1a;|i8I1PO?%6j&6WHgSq6QQyLo%Fr%g=6$_zgze1`_L!;%gB-TGL<%d zR@N0>WxSVrWwgj*yz4~zkx5QPpzozc)3u_a#i*SJUN~hS#;D^eV(WdCYH+kje*3>9 zUw0SJOKPutIji^$Ub21pPZ{km;C00>oGf{DSuUF;m)TSqRo-m4_;L9~Iq&M}GkSV; z`L_&@cmGMF%e=JFt81XlFoli2DeO?bQyG-8dwG#w z1T8b#J1a1{iTt3P8f5Z7YXen5kkH=qg=`&!DUF}zlGj@lWB(Yfz}i^u2s;|l8ntL0 z-p(p*;Mjy+gKfdKVJ*5IR+)CHYi;nIr*0y(+f0S(vMQu*HB$k!PTi(EU=jM3fVh3P d83GVO_nM&quu?(n(S3L=dO#0xb^!H==r;(%T?qgH literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.class b/java-backend/target/classes/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.class new file mode 100644 index 0000000000000000000000000000000000000000..54679e90ae9de2a3b777dafb431b6383609a9638 GIT binary patch literal 1431 zcmbtUOHUI~6#g!+DW$v$2q>Ub#TE+#iV74>kU+##A%M8PonG64c5a!u!z0Fpi3?pA zb>T)?x^kg$qrn9~z~5nzUtv5mtsq7r(an9FbMAK@_dDmy_s`n^hAlXV1TGzuwt=vh(usw^xsL-@Vy= z|4_+gVMXGRG*>(_YPq@GgCLIMgocg~I=!5m{J0PLVyIm6qS0`YVbqX$otsN0x3VtR zQ`{iPG!@Bk$!0^pxu(Wlm8DXY>O5&Fdt+8oq5oq|`Adp6IDHEA#Jzg`n5 z{cq2yP!p6aLw(Y;#BDd967~X5C3%@)2thI2=HECxpD*n6x! zI-63M47HrTbn>TjhX0A2A-IR+Xc+v3bJH_>8VwhzT@N;3sqgk|sOfJBm6hpP?lFnl zg}ysDFJ0RZQ>Mp@Q-`pz-vei8pL2<-d9i3ZCUIxnvLv-7m6))4|NKGZNJvGEu20B3 zjR4|$0^R7MfkZB8I(a({C0ZkN(`je4SN47a`{1ij)9R@~gXRpap`roKqK9tupNOK| zf4o9q6(sA7hqWzKmm%KBUTmSB4qIp<=C^)C`#xycH*P`z%`|6P(SbJKL2nVHCR*-oWWu97q}-96o3cYo9V^Y7n&2XGMI zMNoxm4Iv#hsAV|dxZ{SGc1?SH%;hODR$QxDn@xDPbom@OmZnMIOG(=&Pw4IA>8damf$ws)q++HZ93Yqi($S&*i{W!qTL@B>Wh0&ip?K-Kz zv*r~%8*r!?6!M339L5WDL555Wi?rjJ(sAb)_ALRTTaYo-tqUr#dK^WEhM10HIL=^H zMs!JihVYnaC%fnRlMF4z{tw0{MMCCl*U#c$S~Uq*X*`Ke4P83A(L-SP(3Xf$uQ_h7 zSWqbgLPM{o)+>gYp%uJ1-9ml;o$d2yBZ+fs}RmmGZw z0~*fiIETTK8VDpPe$$o<`R~_oo?);OyA+y%mvn;fl}!{h#66E_C|TMleraeJVOYC> zQkU!UxdGFY5e%a`f+375Uc1C_yg~|!YCFIxx8noe<5(8uiSiO_9o2A!;oP#$D~>D+ z;F5@!`g}@AZd%@mlW`Lwg3HRq%ebcF6}+mNCSzL3K!(A~dAuS`QYHOgj!{~Na6<=2 zTv4Nt1!qdAF<)z=5hNirjOiE$@#o29{YW^jpe~{Unw7>#K!82Db)RGTBp;#f54Kdw zR)}mli`2i9n9^YBNP)=h=zsQ&s+*7~O(esimgQ0ReJfR>I;uw+H#N9AJV=J9s@#PH z=eWOTf}7-UIO*iyg3j_v7%6!tV}8{xm?@lkX~*^iT}w9&XQjsz^*BjlqSXVYEzV_9ap7LzWS*F7z)5gx zl)I){2b&=|Vfyz~CZhrmEb%DPeT{ig6wA28m<*|MaF&=R%28S@7Qj`8W>HdnBvqimv@m*{6!jscC5A0DqEyk?T}6L19)cl5t6KV=_IGJ^ zS+qwv^d)9U!k|+|-!*NIz<%~sX6aKI0FAhF^r`0ra0|C-6~b$H9n~OZc9rDnXzyWr zlQxgKDs+URp(nT(4K=OKV$FTrjfNVvES~A8Y5N5mqBU7;$ztbyIQivnT7Hik`Q_e@ zTKah~T04&;RbW}1_yeapw5aw3$D(BDbQWhqKVt7=3|)z8>@kL~Ji>)XxY!Ynh9BcH zt**9b@p2Z|e?=l1o`+e5-R-;P;Z#FKR}B^2eu@bMT?E@`2ydoYaR)lFlLnABT*oeA z)IGR^z4!_T@Bl~f6Af+(iE9+?9jwP2coSig9>!aEn=rVJ6L^PCG_rIX@8UfIm{182 zQ@`HFT_44V_y8aJ344f-@GRp_+_< S)Io|W-(UNm-xTuwE$|O|V;CF& literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/com/aijianhua/backend/service/AuthService.class b/java-backend/target/classes/com/aijianhua/backend/service/AuthService.class new file mode 100644 index 0000000000000000000000000000000000000000..b32bc9226057c8dc683b56c7febcdc93f9818fe9 GIT binary patch literal 4561 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 literal 0 HcmV?d00001 diff --git a/java-backend/target/classes/db/migration/V1__Initial_Setup.sql b/java-backend/target/classes/db/migration/V1__Initial_Setup.sql new file mode 100644 index 0000000..e7824c7 --- /dev/null +++ b/java-backend/target/classes/db/migration/V1__Initial_Setup.sql @@ -0,0 +1,29 @@ +-- 创建用户表 +CREATE TABLE IF NOT EXISTS users ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + phone VARCHAR(20) UNIQUE, + email VARCHAR(100) UNIQUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + is_active BOOLEAN DEFAULT TRUE +); + +-- 创建文件上传表 +CREATE TABLE IF NOT EXISTS uploads ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT NOT NULL, + original_name VARCHAR(255) NOT NULL, + file_path VARCHAR(500) NOT NULL, + file_type VARCHAR(50) NOT NULL, + file_size BIGINT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); + +-- 创建索引 +CREATE INDEX idx_users_username ON users(username); +CREATE INDEX idx_users_phone ON users(phone); +CREATE INDEX idx_users_email ON users(email); +CREATE INDEX idx_uploads_user_id ON uploads(user_id); \ No newline at end of file diff --git a/java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..a5bc914 --- /dev/null +++ b/java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,28 @@ +com/aijianhua/backend/repository/UploadRepository.class +com/aijianhua/backend/security/JwtAuthenticationFilter.class +com/aijianhua/backend/controller/UploadController.class +com/aijianhua/backend/service/AuthService.class +com/aijianhua/backend/dto/UserResponse.class +com/aijianhua/backend/dto/UploadResponse.class +com/aijianhua/backend/util/JwtUtil.class +com/aijianhua/backend/dto/PageResponse$Pagination.class +com/aijianhua/backend/dto/ApiResponse.class +com/aijianhua/backend/config/SecurityConfig.class +com/aijianhua/backend/interceptor/JwtInterceptor.class +com/aijianhua/backend/config/WebMvcConfig.class +com/aijianhua/backend/Application.class +com/aijianhua/backend/dto/RegisterRequest.class +com/aijianhua/backend/service/UploadService.class +com/aijianhua/backend/exception/GlobalExceptionHandler.class +com/aijianhua/backend/security/JwtAuthenticationEntryPoint.class +com/aijianhua/backend/entity/User.class +com/aijianhua/backend/repository/UserRepository.class +com/aijianhua/backend/exception/UnauthorizedException.class +com/aijianhua/backend/config/SwaggerResourceConfig.class +com/aijianhua/backend/dto/LoginRequest.class +com/aijianhua/backend/dto/PageResponse.class +com/aijianhua/backend/dto/PageResponse$PageData.class +com/aijianhua/backend/entity/Upload.class +com/aijianhua/backend/controller/HealthController.class +com/aijianhua/backend/controller/AuthController.class +com/aijianhua/backend/exception/BusinessException.class diff --git a/java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..44fb63d --- /dev/null +++ b/java-backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,26 @@ +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationFilter.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/config/SecurityConfig.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/exception/UnauthorizedException.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/dto/UserResponse.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/dto/ApiResponse.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/controller/UploadController.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/exception/BusinessException.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/entity/User.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/dto/UploadResponse.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/service/AuthService.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/util/JwtUtil.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/repository/UserRepository.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/interceptor/JwtInterceptor.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/repository/UploadRepository.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/controller/HealthController.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/security/JwtAuthenticationEntryPoint.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/config/WebMvcConfig.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/entity/Upload.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/Application.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/dto/LoginRequest.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/exception/GlobalExceptionHandler.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/dto/PageResponse.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/dto/RegisterRequest.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/config/SwaggerResourceConfig.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/controller/AuthController.java +/Users/ainongkeji/code/vue/aijianhua/java-backend/src/main/java/com/aijianhua/backend/service/UploadService.java