chore: 删除爱鉴花后端项目
- 移除所有源代码文件和配置文件 - 删除 Maven 项目对象模型文件 (pom.xml) - 移除 API 文档 (api-docs.yaml)
This commit is contained in:
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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/");
|
||||
}
|
||||
}
|
||||
@@ -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/**");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.aijianhua.backend.exception;
|
||||
|
||||
public class UnauthorizedException extends RuntimeException {
|
||||
public UnauthorizedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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: 总页数
|
||||
@@ -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"
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user