删除过时文档,优化项目结构

This commit is contained in:
2025-09-10 20:04:14 +08:00
parent 02fe7d11da
commit f80848fc0f
31 changed files with 1055 additions and 0 deletions

148
backend-java/README.md Normal file
View File

@@ -0,0 +1,148 @@
# 宁夏智慧养殖监管平台 - 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月*

144
backend-java/pom.xml Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,9 @@
package com.nxxmdata.farmmonitor.dto;
import lombok.Data;
@Data
public class AuthRequest {
private String username;
private String password;
}

View File

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

View File

@@ -0,0 +1,10 @@
package com.nxxmdata.farmmonitor.dto;
import lombok.Data;
@Data
public class RegisterRequest {
private String username;
private String email;
private String password;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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