chore: 删除爱鉴花后端项目

- 移除所有源代码文件和配置文件
- 删除 Maven 项目对象模型文件 (pom.xml)
- 移除 API 文档 (api-docs.yaml)
This commit is contained in:
ylweng
2025-09-11 23:36:18 +08:00
parent 0f22661813
commit a420983f83
32 changed files with 0 additions and 2123 deletions

View File

@@ -1,105 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.aijianhua</groupId>
<artifactId>backend</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>爱鉴花后端服务</name>
<description>爱鉴花小程序Java版后端服务</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<!-- Spring Boot Starters -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- Apache Commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Flyway -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-mysql</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,11 +0,0 @@
package com.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);
}
}

View File

@@ -1,50 +0,0 @@
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);
}
}

View File

@@ -1,18 +0,0 @@
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/");
}
}

View File

@@ -1,22 +0,0 @@
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/**");
}
}

View File

@@ -1,75 +0,0 @@
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<Map<String, Object>> register(@Valid @RequestBody RegisterRequest registerRequest) {
User user = authService.register(registerRequest);
// 生成JWT token
String token = authService.generateToken(user);
// 构造响应数据
Map<String, Object> 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<Map<String, Object>> login(@Valid @RequestBody LoginRequest loginRequest) {
User user = authService.login(loginRequest);
// 生成JWT token
String token = authService.generateToken(user);
// 构造响应数据
Map<String, Object> 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<UserResponse> getCurrentUser(@RequestAttribute("userId") Long userId) {
UserResponse userResponse = authService.getUserInfo(userId);
return ApiResponse.success(userResponse);
}
}

View File

@@ -1,28 +0,0 @@
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<Map<String, Object>> healthCheck() {
Map<String, Object> healthInfo = new HashMap<>();
healthInfo.put("status", "UP");
healthInfo.put("timestamp", LocalDateTime.now());
healthInfo.put("service", "aijianhua-backend");
return ApiResponse.success(healthInfo);
}
}

View File

@@ -1,88 +0,0 @@
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<UploadResponse> 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<Upload> 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<Upload> uploads = uploadService.getUploads(userId, type, page, limit);
return PageResponse.success(uploads);
}
/**
* 删除上传文件
*/
@DeleteMapping("/{id}")
public ApiResponse<Map<String, String>> deleteUpload(
@PathVariable Long id,
HttpServletRequest request) throws IOException {
// 从请求中获取用户ID
Long userId = (Long) request.getAttribute("userId");
// 删除文件
uploadService.deleteUpload(id, userId);
Map<String, String> data = new HashMap<>();
data.put("message", "删除成功");
return ApiResponse.success(data);
}
}

View File

@@ -1,38 +0,0 @@
package com.aijianhua.backend.dto;
import lombok.Data;
@Data
public class ApiResponse<T> {
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 <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(200, "操作成功", data);
}
public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>(200, message, data);
}
public static <T> ApiResponse<T> created(T data) {
return new ApiResponse<>(201, "创建成功", data);
}
public static <T> ApiResponse<T> error(Integer code, String message) {
return new ApiResponse<>(code, message, null);
}
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(500, message, null);
}
}

View File

@@ -1,21 +0,0 @@
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;
}
}

View File

@@ -1,62 +0,0 @@
package com.aijianhua.backend.dto;
import lombok.Data;
import org.springframework.data.domain.Page;
@Data
public class PageResponse<T> {
private Integer code;
private String message;
private PageData<T> data;
public PageResponse() {}
public PageResponse(Integer code, String message, PageData<T> data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> PageResponse<T> success(Page<T> page) {
PageData<T> 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<T> {
private Iterable<T> items;
private Pagination pagination;
public void setItems(Iterable<T> 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;
}
}
}

View File

@@ -1,42 +0,0 @@
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;
}
}

View File

@@ -1,58 +0,0 @@
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;
}
}

View File

@@ -1,81 +0,0 @@
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;
}
}

View File

@@ -1,155 +0,0 @@
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;
}
}

View File

@@ -1,144 +0,0 @@
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;
}
}

View File

@@ -1,18 +0,0 @@
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;
}
}

View File

@@ -1,72 +0,0 @@
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<ApiResponse<Map<String, String>>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> 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<ApiResponse<Map<String, String>>> handleConstraintViolationException(ConstraintViolationException ex) {
Map<String, String> 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<ApiResponse<Object>> handleBusinessException(BusinessException ex) {
return ResponseEntity.status(ex.getCode()).body(new ApiResponse<>(ex.getCode(), ex.getMessage(), null));
}
/**
* 处理未授权异常
*/
@ExceptionHandler(UnauthorizedException.class)
public ResponseEntity<ApiResponse<Object>> handleUnauthorizedException(UnauthorizedException ex) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new ApiResponse<>(401, ex.getMessage(), null));
}
/**
* 处理其他所有未处理的异常
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Object>> handleGenericException(Exception ex) {
// 记录日志
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ApiResponse<>(500, "系统内部错误", null));
}
}

View File

@@ -1,7 +0,0 @@
package com.aijianhua.backend.exception;
public class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String message) {
super(message);
}
}

View File

@@ -1,36 +0,0 @@
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;
}
}

View File

@@ -1,13 +0,0 @@
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<Upload, Long> {
Page<Upload> findByUserId(Long userId, Pageable pageable);
Page<Upload> findByUserIdAndUploadType(Long userId, String uploadType, Pageable pageable);
}

View File

@@ -1,17 +0,0 @@
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<User, Long> {
Optional<User> findByUsernameOrPhoneOrEmailAndStatus(String username, String phone, String email, Integer status);
Optional<User> findByUsername(String username);
Optional<User> findByPhone(String phone);
Optional<User> findByEmail(String email);
Boolean existsByUsername(String username);
Boolean existsByPhone(String phone);
Boolean existsByEmail(String email);
}

View File

@@ -1,25 +0,0 @@
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}");
}
}

View File

@@ -1,58 +0,0 @@
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);
}
}

View File

@@ -1,111 +0,0 @@
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<User> 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<User> 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;
}
}

View File

@@ -1,119 +0,0 @@
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<Upload> 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);
}
}

View File

@@ -1,82 +0,0 @@
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<String, Object> 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());
}
}

View File

@@ -1,437 +0,0 @@
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: 总页数

View File

@@ -1,47 +0,0 @@
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"

View File

@@ -1,29 +0,0 @@
-- 创建用户表
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);

View File

@@ -1,28 +0,0 @@
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

View File

@@ -1,26 +0,0 @@
/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