删除Java后端服务,迁移至微服务架构
This commit is contained in:
@@ -1,148 +0,0 @@
|
||||
# 宁夏智慧养殖监管平台 - Java后端
|
||||
|
||||
这是宁夏智慧养殖监管平台的Java微服务版本后端实现,使用Spring Boot框架构建。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **Java版本**: Java 17
|
||||
- **框架**: Spring Boot 3.1.0
|
||||
- **安全框架**: Spring Security
|
||||
- **数据库**: MySQL 8.0+
|
||||
- **ORM框架**: Spring Data JPA (Hibernate)
|
||||
- **API文档**: Springdoc OpenAPI (Swagger 3)
|
||||
- **认证**: JWT (JSON Web Tokens)
|
||||
- **密码加密**: BCrypt
|
||||
- **构建工具**: Maven
|
||||
- **服务器端口**: 5350
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
backend-java/
|
||||
├── src/
|
||||
│ ├── main/
|
||||
│ │ ├── java/
|
||||
│ │ │ └── com/nxxmdata/farmmonitor/
|
||||
│ │ │ ├── Application.java # 应用启动类
|
||||
│ │ │ ├── config/ # 配置类
|
||||
│ │ │ ├── controller/ # 控制器层
|
||||
│ │ │ ├── service/ # 服务层
|
||||
│ │ │ ├── repository/ # 数据访问层
|
||||
│ │ │ ├── model/ # 数据模型
|
||||
│ │ │ ├── dto/ # 数据传输对象
|
||||
│ │ │ ├── security/ # 安全相关
|
||||
│ │ │ └── exception/ # 异常处理
|
||||
│ │ └── resources/
|
||||
│ │ ├── application.yml # 应用配置
|
||||
│ │ └── application-dev.yml # 开发环境配置
|
||||
│ └── test/ # 测试代码
|
||||
├── pom.xml # Maven配置文件
|
||||
└── README.md # 项目说明文档
|
||||
```
|
||||
|
||||
## 功能模块
|
||||
|
||||
1. **用户认证模块**
|
||||
- 用户登录/注册
|
||||
- JWT Token生成与验证
|
||||
- 密码加密存储
|
||||
|
||||
2. **用户管理模块**
|
||||
- 用户信息管理
|
||||
- 角色权限管理
|
||||
|
||||
3. **农场管理模块**
|
||||
- 农场信息管理
|
||||
- 地理位置信息处理
|
||||
|
||||
4. **设备监控模块**
|
||||
- 设备状态监控
|
||||
- 传感器数据处理
|
||||
|
||||
5. **动物管理模块**
|
||||
- 动物档案管理
|
||||
- 健康状态跟踪
|
||||
|
||||
6. **预警管理模块**
|
||||
- 系统告警处理
|
||||
- 告警规则配置
|
||||
|
||||
7. **订单管理模块**
|
||||
- 产品销售管理
|
||||
- 订单处理流程
|
||||
|
||||
8. **统计分析模块**
|
||||
- 数据统计分析
|
||||
- 报表生成
|
||||
|
||||
## API文档
|
||||
|
||||
启动服务后,可通过以下地址访问API文档:
|
||||
|
||||
- Swagger UI: http://localhost:5350/swagger-ui.html
|
||||
- OpenAPI JSON: http://localhost:5350/v3/api-docs
|
||||
|
||||
## 数据库配置
|
||||
|
||||
在 `application.yml` 文件中配置数据库连接:
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://192.168.0.240:3307/nxxmdata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: aiot$Aiot123
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Java 17+
|
||||
- Maven 3.6+
|
||||
- MySQL 8.0+
|
||||
|
||||
### 构建项目
|
||||
|
||||
```bash
|
||||
mvn clean package
|
||||
```
|
||||
|
||||
### 运行项目
|
||||
|
||||
```bash
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```bash
|
||||
java -jar target/farm-monitor-1.0.0.jar
|
||||
```
|
||||
|
||||
## 开发规范
|
||||
|
||||
1. 遵循RESTful API设计规范
|
||||
2. 使用JWT进行无状态认证
|
||||
3. 密码使用BCrypt加密存储
|
||||
4. 代码注释规范清晰
|
||||
5. API文档完整
|
||||
|
||||
## 安全设计
|
||||
|
||||
1. 使用JWT Token进行身份验证
|
||||
2. 密码使用BCrypt加密存储
|
||||
3. 基于角色的访问控制(RBAC)
|
||||
4. SQL注入防护(使用JPA)
|
||||
5. XSS防护(前端处理)
|
||||
|
||||
## 性能优化
|
||||
|
||||
1. 数据库连接池配置
|
||||
2. Hibernate二级缓存(可选)
|
||||
3. API响应时间监控
|
||||
4. 数据库查询优化
|
||||
|
||||
---
|
||||
*最后更新: 2025年9月*
|
||||
@@ -1,144 +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.nxxmdata</groupId>
|
||||
<artifactId>farm-monitor</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>3.1.0</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<spring-cloud.version>2022.0.3</spring-cloud.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot Web Starter -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Data JPA -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON Web Token support -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.11.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.11.5</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.11.5</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL Connector -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Validation -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Configuration Processor -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Security Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor;
|
||||
|
||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||
import io.swagger.v3.oas.annotations.info.Info;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@OpenAPIDefinition(info = @Info(title = "宁夏智慧养殖监管平台", version = "1.0", description = "宁夏智慧养殖监管平台API文档"))
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.config;
|
||||
|
||||
import com.nxxmdata.farmmonitor.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.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
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.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
||||
return config.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.cors().and().csrf().disable()
|
||||
.authorizeHttpRequests(authz -> authz
|
||||
.requestMatchers("/api/auth/**").permitAll()
|
||||
.requestMatchers("/api-docs/**").permitAll()
|
||||
.requestMatchers("/swagger-ui/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
|
||||
|
||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.config;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info()
|
||||
.title("宁夏智慧养殖监管平台 API")
|
||||
.version("1.0.0")
|
||||
.description("宁夏智慧养殖监管平台后端API文档")
|
||||
.license(new License().name("Apache 2.0")
|
||||
.url("http://springdoc.org")))
|
||||
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
|
||||
.components(new Components()
|
||||
.addSecuritySchemes("bearerAuth",
|
||||
new SecurityScheme()
|
||||
.name("bearerAuth")
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.scheme("bearer")
|
||||
.bearerFormat("JWT")));
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.controller;
|
||||
|
||||
import com.nxxmdata.farmmonitor.dto.AuthRequest;
|
||||
import com.nxxmdata.farmmonitor.dto.AuthResponse;
|
||||
import com.nxxmdata.farmmonitor.dto.RegisterRequest;
|
||||
import com.nxxmdata.farmmonitor.model.User;
|
||||
import com.nxxmdata.farmmonitor.service.AuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@Tag(name = "Authentication", description = "用户认证相关接口")
|
||||
public class AuthController {
|
||||
|
||||
@Autowired
|
||||
private AuthService authService;
|
||||
|
||||
@PostMapping("/login")
|
||||
@Operation(summary = "用户登录", description = "用户登录接口,成功后返回JWT Token")
|
||||
public ResponseEntity<AuthResponse> login(@Valid @RequestBody AuthRequest authRequest) {
|
||||
String token = authService.authenticateUser(authRequest.getUsername(), authRequest.getPassword());
|
||||
|
||||
AuthResponse response = new AuthResponse();
|
||||
if (token != null) {
|
||||
response.setSuccess(true);
|
||||
response.setMessage("登录成功");
|
||||
response.setToken(token);
|
||||
|
||||
// 获取用户信息(不包含密码)
|
||||
// 在实际应用中,应该从数据库查询用户信息
|
||||
User user = new User();
|
||||
user.setUsername(authRequest.getUsername());
|
||||
response.setUser(user);
|
||||
} else {
|
||||
response.setSuccess(false);
|
||||
response.setMessage("用户名或密码错误");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@PostMapping("/register")
|
||||
@Operation(summary = "用户注册", description = "用户注册接口")
|
||||
public ResponseEntity<AuthResponse> register(@Valid @RequestBody RegisterRequest registerRequest) {
|
||||
User user = authService.registerUser(
|
||||
registerRequest.getUsername(),
|
||||
registerRequest.getEmail(),
|
||||
registerRequest.getPassword()
|
||||
);
|
||||
|
||||
AuthResponse response = new AuthResponse();
|
||||
if (user != null) {
|
||||
response.setSuccess(true);
|
||||
response.setMessage("注册成功");
|
||||
response.setUser(user);
|
||||
} else {
|
||||
response.setSuccess(false);
|
||||
response.setMessage("用户已存在");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AuthRequest {
|
||||
private String username;
|
||||
private String password;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.dto;
|
||||
|
||||
import com.nxxmdata.farmmonitor.model.User;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AuthResponse {
|
||||
private boolean success;
|
||||
private String message;
|
||||
private String token;
|
||||
private User user;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RegisterRequest {
|
||||
private String username;
|
||||
private String email;
|
||||
private String password;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(UsernameNotFoundException.class)
|
||||
public ResponseEntity<Object> handleUsernameNotFoundException(UsernameNotFoundException ex, WebRequest request) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("timestamp", LocalDateTime.now());
|
||||
body.put("message", "用户未找到: " + ex.getMessage());
|
||||
body.put("success", false);
|
||||
|
||||
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@ExceptionHandler(BadCredentialsException.class)
|
||||
public ResponseEntity<Object> handleBadCredentialsException(BadCredentialsException ex, WebRequest request) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("timestamp", LocalDateTime.now());
|
||||
body.put("message", "用户名或密码错误");
|
||||
body.put("success", false);
|
||||
|
||||
return new ResponseEntity<>(body, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<Object> handleGenericException(Exception ex, WebRequest request) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("timestamp", LocalDateTime.now());
|
||||
body.put("message", "服务器内部错误: " + ex.getMessage());
|
||||
body.put("success", false);
|
||||
|
||||
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "roles")
|
||||
public class Role {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
@Column(name = "created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
public class User implements UserDetails {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String username;
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String password;
|
||||
|
||||
private String phone;
|
||||
|
||||
private String avatar;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private UserStatus status = UserStatus.ACTIVE;
|
||||
|
||||
@Column(name = "created_at")
|
||||
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();
|
||||
}
|
||||
|
||||
// UserDetails接口实现
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return List.of(); // 在实际应用中应该返回用户的角色列表
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return status == UserStatus.ACTIVE;
|
||||
}
|
||||
|
||||
public enum UserStatus {
|
||||
ACTIVE, INACTIVE, SUSPENDED
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "user_roles")
|
||||
public class UserRole {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "user_id")
|
||||
private Long userId;
|
||||
|
||||
@Column(name = "role_id")
|
||||
private Long roleId;
|
||||
|
||||
@Column(name = "assigned_at")
|
||||
private LocalDateTime assignedAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
assignedAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.repository;
|
||||
|
||||
import com.nxxmdata.farmmonitor.model.Role;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface RoleRepository extends JpaRepository<Role, Long> {
|
||||
Optional<Role> findByName(String name);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.repository;
|
||||
|
||||
import com.nxxmdata.farmmonitor.model.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> findByUsername(String username);
|
||||
Optional<User> findByEmail(String email);
|
||||
Optional<User> findByUsernameOrEmail(String username, String email);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.repository;
|
||||
|
||||
import com.nxxmdata.farmmonitor.model.UserRole;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface UserRoleRepository extends JpaRepository<UserRole, Long> {
|
||||
List<UserRole> findByUserId(Long userId);
|
||||
List<UserRole> findByRoleId(Long roleId);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.security;
|
||||
|
||||
import com.nxxmdata.farmmonitor.model.User;
|
||||
import com.nxxmdata.farmmonitor.repository.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
Optional<User> userOptional = userRepository.findByUsernameOrEmail(username, username);
|
||||
|
||||
if (userOptional.isEmpty()) {
|
||||
throw new UsernameNotFoundException("User not found with username or email: " + username);
|
||||
}
|
||||
|
||||
return userOptional.get();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.security;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Autowired
|
||||
private JwtUtil jwtUtil;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
final String requestTokenHeader = request.getHeader("Authorization");
|
||||
|
||||
String username = null;
|
||||
String jwtToken = null;
|
||||
|
||||
// JWT Token is in the form "Bearer token". Remove Bearer word and get only the Token
|
||||
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
|
||||
jwtToken = requestTokenHeader.substring(7);
|
||||
try {
|
||||
username = jwtUtil.getUsernameFromToken(jwtToken);
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to get JWT Token", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Once we get the token validate it.
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
|
||||
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
|
||||
|
||||
// if token is valid configure Spring Security to manually set authentication
|
||||
if (jwtUtil.validateToken(jwtToken, userDetails.getUsername())) {
|
||||
|
||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
usernamePasswordAuthenticationToken
|
||||
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
// After setting the Authentication in the context, we specify
|
||||
// that the current user is authenticated. So it passes the
|
||||
// Spring Security Configurations successfully.
|
||||
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
|
||||
}
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.security;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Component
|
||||
public class JwtUtil {
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String secret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private Long expiration;
|
||||
|
||||
private SecretKey getSigningKey() {
|
||||
return Keys.hmacShaKeyFor(secret.getBytes());
|
||||
}
|
||||
|
||||
public String getUsernameFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getSubject);
|
||||
}
|
||||
|
||||
public Date getExpirationDateFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getExpiration);
|
||||
}
|
||||
|
||||
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
|
||||
final Claims claims = getAllClaimsFromToken(token);
|
||||
return claimsResolver.apply(claims);
|
||||
}
|
||||
|
||||
private Claims getAllClaimsFromToken(String token) {
|
||||
return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
|
||||
}
|
||||
|
||||
private Boolean isTokenExpired(String token) {
|
||||
final Date expiration = getExpirationDateFromToken(token);
|
||||
return expiration.before(new Date());
|
||||
}
|
||||
|
||||
public String generateToken(String username, String email, Long id) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("email", email);
|
||||
claims.put("id", id);
|
||||
return doGenerateToken(claims, username);
|
||||
}
|
||||
|
||||
private String doGenerateToken(Map<String, Object> claims, String subject) {
|
||||
return Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.setSubject(subject)
|
||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
|
||||
.signWith(getSigningKey(), SignatureAlgorithm.HS512)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public Boolean validateToken(String token, String username) {
|
||||
final String tokenUsername = getUsernameFromToken(token);
|
||||
return (tokenUsername.equals(username) && !isTokenExpired(token));
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.service;
|
||||
|
||||
import com.nxxmdata.farmmonitor.model.User;
|
||||
import com.nxxmdata.farmmonitor.security.JwtUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class AuthService {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private JwtUtil jwtUtil;
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
public String authenticateUser(String username, String password) {
|
||||
Optional<User> userOptional = userService.findByUsernameOrEmail(username, username);
|
||||
|
||||
if (userOptional.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
User user = userOptional.get();
|
||||
|
||||
// 使用AuthenticationManager进行认证
|
||||
try {
|
||||
Authentication authentication = authenticationManager.authenticate(
|
||||
new UsernamePasswordAuthenticationToken(username, password)
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
} catch (Exception e) {
|
||||
// 认证失败
|
||||
return null;
|
||||
}
|
||||
|
||||
// 生成JWT token
|
||||
return jwtUtil.generateToken(user.getUsername(), user.getEmail(), user.getId());
|
||||
}
|
||||
|
||||
public User registerUser(String username, String email, String password) {
|
||||
// 检查用户是否已存在
|
||||
if (userService.findByUsernameOrEmail(username, email).isPresent()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
user.setUsername(username);
|
||||
user.setEmail(email);
|
||||
user.setPassword(password);
|
||||
|
||||
return userService.saveUser(user);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.nxxmdata.farmmonitor.service;
|
||||
|
||||
import com.nxxmdata.farmmonitor.model.User;
|
||||
import com.nxxmdata.farmmonitor.repository.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
public Optional<User> findByUsername(String username) {
|
||||
return userRepository.findByUsername(username);
|
||||
}
|
||||
|
||||
public Optional<User> findByEmail(String email) {
|
||||
return userRepository.findByEmail(email);
|
||||
}
|
||||
|
||||
public Optional<User> findByUsernameOrEmail(String username, String email) {
|
||||
return userRepository.findByUsernameOrEmail(username, email);
|
||||
}
|
||||
|
||||
public User saveUser(User user) {
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
public boolean validatePassword(User user, String rawPassword) {
|
||||
return passwordEncoder.matches(rawPassword, user.getPassword());
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
server:
|
||||
port: 5350
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: farm-monitor-service
|
||||
datasource:
|
||||
url: jdbc:mysql://192.168.0.240:3307/nxxmdata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: aiot$Aiot123
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
hikari:
|
||||
maximum-pool-size: 20
|
||||
minimum-idle: 5
|
||||
connection-timeout: 30000
|
||||
idle-timeout: 600000
|
||||
max-lifetime: 1800000
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
show-sql: true
|
||||
database-platform: org.hibernate.dialect.MySQL8Dialect
|
||||
|
||||
jackson:
|
||||
time-zone: Asia/Shanghai
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
|
||||
jwt:
|
||||
secret: your_jwt_secret_key
|
||||
expiration: 86400
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.nxxmdata.farmmonitor: DEBUG
|
||||
org.springframework: INFO
|
||||
org.hibernate: INFO
|
||||
Reference in New Issue
Block a user