当前位置: 首页 > news >正文

Java Web API 开发完整指南

在这里插入图片描述

文章目录

    • 技术栈选择
    • 1. 项目搭建和基础配置
      • 1.1 创建 Spring Boot 项目
      • 1.2 应用配置文件
    • 2. 核心架构和原理
      • 2.1 分层架构
      • 2.2 请求流程
    • 3. 完整实现代码
      • 3.1 实体类 (Entity)
      • 3.2 数据访问层 (Repository)
      • 3.3 JWT 工具类
      • 3.4 Spring Security 配置
      • 3.5 DTO 和数据验证
      • 3.6 控制器 (Controller)
      • 3.7 业务服务层 (Service)
      • 3.8 数据初始化
      • 3.9 定时任务
      • 3.10 全局异常处理
      • 3.11 应用主类
    • 4. API 测试和使用
      • 4.1 启动应用
      • 4.2 API 文档访问
      • 4.3 测试 API
    • 5. 核心原理总结
      • 5.1 安全流程
      • 5.2 数据流程
      • 5.3 定时任务原理

在这里插入图片描述

技术栈选择

  • 框架: Spring Boot 3.x
  • 安全: Spring Security + JWT
  • 数据: Spring Data JPA + H2/MySQL
  • 文档: OpenAPI 3 (Swagger)
  • 任务调度: Spring Scheduler
  • 构建工具: Maven

1. 项目搭建和基础配置

1.1 创建 Spring Boot 项目

使用 Spring Initializr 或以下 Maven 配置:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0</version><relativePath/></parent><groupId>com.example</groupId><artifactId>java-webapi</artifactId><version>1.0.0</version><name>Java Web API</name><properties><java.version>17</java.version></properties><dependencies><!-- Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Security --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- JPA --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- Validation --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!-- H2 Database --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency><!-- JWT --><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><!-- OpenAPI --><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>2.3.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

1.2 应用配置文件

application.yml

server:port: 8080servlet:context-path: /apispring:datasource:url: jdbc:h2:mem:testdbdriver-class-name: org.h2.Driverusername: sapassword: jpa:database-platform: org.hibernate.dialect.H2Dialecthibernate:ddl-auto: create-dropshow-sql: trueproperties:hibernate:format_sql: trueh2:console:enabled: truepath: /h2-consoleapp:jwt:secret: "mySecretKeymySecretKeymySecretKeymySecretKeymySecretKeymySecretKey"expiration: 86400000 # 24 hours

2. 核心架构和原理

2.1 分层架构

Controller层 (REST端点)↓
Service层 (业务逻辑)↓
Repository层 (数据访问)↓
Database

2.2 请求流程

HTTP请求 → 安全过滤器 → 控制器 → 服务层 → 数据层 → 数据库↓
HTTP响应 ← 控制器 ← 服务层 ← 数据层

3. 完整实现代码

3.1 实体类 (Entity)

User.java

package com.example.javawebapi.entity;import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;@Entity
@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "username"),@UniqueConstraint(columnNames = "email")
})
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@NotBlank@Size(max = 50)private String username;@NotBlank@Size(max = 120)private String password;@NotBlank@Size(max = 50)@Emailprivate String email;@ManyToMany(fetch = FetchType.LAZY)@JoinTable(name = "user_roles",joinColumns = @JoinColumn(name = "user_id"),inverseJoinColumns = @JoinColumn(name = "role_id"))private Set<Role> roles = new HashSet<>();private boolean enabled = true;private LocalDateTime createdAt;private LocalDateTime updatedAt;@PrePersistprotected void onCreate() {createdAt = LocalDateTime.now();updatedAt = LocalDateTime.now();}@PreUpdateprotected void onUpdate() {updatedAt = LocalDateTime.now();}// Constructorspublic User() {}public User(String username, String email, String password) {this.username = username;this.email = email;this.password = password;}// Getters and Setterspublic 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 getEmail() { return email; }public void setEmail(String email) { this.email = email; }public Set<Role> getRoles() { return roles; }public void setRoles(Set<Role> roles) { this.roles = roles; }public boolean isEnabled() { return enabled; }public void setEnabled(boolean enabled) { this.enabled = enabled; }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; }
}

Role.java

package com.example.javawebapi.entity;import jakarta.persistence.*;@Entity
@Table(name = "roles")
public class Role {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer id;@Enumerated(EnumType.STRING)@Column(length = 20)private ERole name;public Role() {}public Role(ERole name) {this.name = name;}// Getters and Setterspublic Integer getId() { return id; }public void setId(Integer id) { this.id = id; }public ERole getName() { return name; }public void setName(ERole name) { this.name = name; }
}enum ERole {ROLE_USER,ROLE_ADMIN
}

3.2 数据访问层 (Repository)

UserRepository.java

package com.example.javawebapi.repository;import com.example.javawebapi.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> findByUsername(String username);Optional<User> findByEmail(String email);Boolean existsByUsername(String username);Boolean existsByEmail(String email);
}

RoleRepository.java

package com.example.javawebapi.repository;import com.example.javawebapi.entity.ERole;
import com.example.javawebapi.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;import java.util.Optional;@Repository
public interface RoleRepository extends JpaRepository<Role, Integer> {Optional<Role> findByName(ERole name);
}

3.3 JWT 工具类

JwtUtils.java

package com.example.javawebapi.security.jwt;import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;import java.security.Key;
import java.util.Date;@Component
public class JwtUtils {private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);@Value("${app.jwt.secret}")private String jwtSecret;@Value("${app.jwt.expiration}")private int jwtExpirationMs;public String generateJwtToken(Authentication authentication) {UserDetails userPrincipal = (UserDetails) authentication.getPrincipal();return Jwts.builder().setSubject((userPrincipal.getUsername())).setIssuedAt(new Date()).setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)).signWith(key(), SignatureAlgorithm.HS256).compact();}private Key key() {return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));}public String getUserNameFromJwtToken(String token) {return Jwts.parserBuilder().setSigningKey(key()).build().parseClaimsJws(token).getBody().getSubject();}public boolean validateJwtToken(String authToken) {try {Jwts.parserBuilder().setSigningKey(key()).build().parseClaimsJws(authToken);return true;} catch (MalformedJwtException e) {logger.error("Invalid JWT token: {}", e.getMessage());} catch (ExpiredJwtException e) {logger.error("JWT token is expired: {}", e.getMessage());} catch (UnsupportedJwtException e) {logger.error("JWT token is unsupported: {}", e.getMessage());} catch (IllegalArgumentException e) {logger.error("JWT claims string is empty: {}", e.getMessage());}return false;}
}

3.4 Spring Security 配置

WebSecurityConfig.java

package com.example.javawebapi.security;import com.example.javawebapi.security.jwt.AuthTokenFilter;
import com.example.javawebapi.security.services.UserDetailsServiceImpl;
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.authentication.dao.DaoAuthenticationProvider;
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.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
@EnableMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {@AutowiredUserDetailsServiceImpl userDetailsService;@Beanpublic AuthTokenFilter authenticationJwtTokenFilter() {return new AuthTokenFilter();}@Beanpublic DaoAuthenticationProvider authenticationProvider() {DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();authProvider.setUserDetailsService(userDetailsService);authProvider.setPasswordEncoder(passwordEncoder());return authProvider;}@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {return authConfig.getAuthenticationManager();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf(csrf -> csrf.disable()).sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).authorizeHttpRequests(auth -> auth.requestMatchers("/auth/**").permitAll().requestMatchers("/h2-console/**").permitAll().requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll().anyRequest().authenticated());http.authenticationProvider(authenticationProvider());http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);// For H2 consolehttp.headers(headers -> headers.frameOptions(frame -> frame.sameOrigin()));return http.build();}
}

AuthTokenFilter.java

package com.example.javawebapi.security.jwt;import com.example.javawebapi.security.services.UserDetailsServiceImpl;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;import java.io.IOException;public class AuthTokenFilter extends OncePerRequestFilter {@Autowiredprivate JwtUtils jwtUtils;@Autowiredprivate UserDetailsServiceImpl userDetailsService;private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {try {String jwt = parseJwt(request);if (jwt != null && jwtUtils.validateJwtToken(jwt)) {String username = jwtUtils.getUserNameFromJwtToken(jwt);UserDetails userDetails = userDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authentication);}} catch (Exception e) {logger.error("Cannot set user authentication: {}", e);}filterChain.doFilter(request, response);}private String parseJwt(HttpServletRequest request) {String headerAuth = request.getHeader("Authorization");if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {return headerAuth.substring(7);}return null;}
}

UserDetailsServiceImpl.java

package com.example.javawebapi.security.services;import com.example.javawebapi.entity.User;
import com.example.javawebapi.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 org.springframework.transaction.annotation.Transactional;@Service
public class UserDetailsServiceImpl implements UserDetailsService {@AutowiredUserRepository userRepository;@Override@Transactionalpublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));return UserDetailsImpl.build(user);}
}

UserDetailsImpl.java

package com.example.javawebapi.security.services;import com.example.javawebapi.entity.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;public class UserDetailsImpl implements UserDetails {private static final long serialVersionUID = 1L;private Long id;private String username;private String email;@JsonIgnoreprivate String password;private Collection<? extends GrantedAuthority> authorities;public UserDetailsImpl(Long id, String username, String email, String password,Collection<? extends GrantedAuthority> authorities) {this.id = id;this.username = username;this.email = email;this.password = password;this.authorities = authorities;}public static UserDetailsImpl build(User user) {List<GrantedAuthority> authorities = user.getRoles().stream().map(role -> new SimpleGrantedAuthority(role.getName().name())).collect(Collectors.toList());return new UserDetailsImpl(user.getId(),user.getUsername(),user.getEmail(),user.getPassword(),authorities);}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}public Long getId() { return id; }public String getEmail() { return email; }@Overridepublic String getPassword() { return password; }@Overridepublic String getUsername() { return username; }@Overridepublic boolean isAccountNonExpired() { return true; }@Overridepublic boolean isAccountNonLocked() { return true; }@Overridepublic boolean isCredentialsNonExpired() { return true; }@Overridepublic boolean isEnabled() { return true; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;UserDetailsImpl user = (UserDetailsImpl) o;return Objects.equals(id, user.id);}
}

3.5 DTO 和数据验证

LoginRequest.java

package com.example.javawebapi.payload.request;import jakarta.validation.constraints.NotBlank;public class LoginRequest {@NotBlankprivate String username;@NotBlankprivate String password;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; }
}

SignupRequest.java

package com.example.javawebapi.payload.request;import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.Set;public class SignupRequest {@NotBlank@Size(min = 3, max = 20)private String username;@NotBlank@Size(max = 50)@Emailprivate String email;private Set<String> role;@NotBlank@Size(min = 6, max = 40)private String password;public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getPassword() { return password; }public void setPassword(String password) { this.password = password; }public Set<String> getRole() { return this.role; }public void setRole(Set<String> role) { this.role = role; }
}

JwtResponse.java

package com.example.javawebapi.payload.response;import java.util.List;public class JwtResponse {private String token;private String type = "Bearer";private Long id;private String username;private String email;private List<String> roles;public JwtResponse(String accessToken, Long id, String username, String email, List<String> roles) {this.token = accessToken;this.id = id;this.username = username;this.email = email;this.roles = roles;}// Getters and Setterspublic String getAccessToken() { return token; }public void setAccessToken(String accessToken) { this.token = accessToken; }public String getTokenType() { return type; }public void setTokenType(String tokenType) { this.type = tokenType; }public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public List<String> getRoles() { return roles; }
}

MessageResponse.java

package com.example.javawebapi.payload.response;public class MessageResponse {private String message;public MessageResponse(String message) {this.message = message;}public String getMessage() { return message; }public void setMessage(String message) { this.message = message; }
}

3.6 控制器 (Controller)

AuthController.java

package com.example.javawebapi.controller;import com.example.javawebapi.entity.ERole;
import com.example.javawebapi.entity.Role;
import com.example.javawebapi.entity.User;
import com.example.javawebapi.payload.request.LoginRequest;
import com.example.javawebapi.payload.request.SignupRequest;
import com.example.javawebapi.payload.response.JwtResponse;
import com.example.javawebapi.payload.response.MessageResponse;
import com.example.javawebapi.repository.RoleRepository;
import com.example.javawebapi.repository.UserRepository;
import com.example.javawebapi.security.jwt.JwtUtils;
import com.example.javawebapi.security.services.UserDetailsImpl;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/auth")
public class AuthController {@AutowiredAuthenticationManager authenticationManager;@AutowiredUserRepository userRepository;@AutowiredRoleRepository roleRepository;@AutowiredPasswordEncoder encoder;@AutowiredJwtUtils jwtUtils;@PostMapping("/signin")public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));SecurityContextHolder.getContext().setAuthentication(authentication);String jwt = jwtUtils.generateJwtToken(authentication);UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority()).collect(Collectors.toList());return ResponseEntity.ok(new JwtResponse(jwt,userDetails.getId(),userDetails.getUsername(),userDetails.getEmail(),roles));}@PostMapping("/signup")public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) {if (userRepository.existsByUsername(signUpRequest.getUsername())) {return ResponseEntity.badRequest().body(new MessageResponse("Error: Username is already taken!"));}if (userRepository.existsByEmail(signUpRequest.getEmail())) {return ResponseEntity.badRequest().body(new MessageResponse("Error: Email is already in use!"));}// Create new user's accountUser user = new User(signUpRequest.getUsername(),signUpRequest.getEmail(),encoder.encode(signUpRequest.getPassword()));Set<String> strRoles = signUpRequest.getRole();Set<Role> roles = new HashSet<>();if (strRoles == null) {Role userRole = roleRepository.findByName(ERole.ROLE_USER).orElseThrow(() -> new RuntimeException("Error: Role is not found."));roles.add(userRole);} else {strRoles.forEach(role -> {switch (role) {case "admin":Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN).orElseThrow(() -> new RuntimeException("Error: Role is not found."));roles.add(adminRole);break;default:Role userRole = roleRepository.findByName(ERole.ROLE_USER).orElseThrow(() -> new RuntimeException("Error: Role is not found."));roles.add(userRole);}});}user.setRoles(roles);userRepository.save(user);return ResponseEntity.ok(new MessageResponse("User registered successfully!"));}
}

UserController.java

package com.example.javawebapi.controller;import com.example.javawebapi.entity.User;
import com.example.javawebapi.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;import java.util.List;@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/users")
public class UserController {@AutowiredUserRepository userRepository;@GetMapping@PreAuthorize("hasRole('ADMIN')")public List<User> getAllUsers() {return userRepository.findAll();}@GetMapping("/{id}")@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")public User getUserById(@PathVariable Long id) {return userRepository.findById(id).orElseThrow(() -> new RuntimeException("Error: User not found."));}@DeleteMapping("/{id}")@PreAuthorize("hasRole('ADMIN')")public String deleteUser(@PathVariable Long id) {userRepository.deleteById(id);return "User deleted successfully!";}
}

3.7 业务服务层 (Service)

UserService.java

package com.example.javawebapi.service;import com.example.javawebapi.entity.User;
import com.example.javawebapi.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Optional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;public List<User> findAll() {return userRepository.findAll();}public Optional<User> findById(Long id) {return userRepository.findById(id);}public User save(User user) {return userRepository.save(user);}public void deleteById(Long id) {userRepository.deleteById(id);}public boolean existsByUsername(String username) {return userRepository.existsByUsername(username);}public boolean existsByEmail(String email) {return userRepository.existsByEmail(email);}
}

3.8 数据初始化

DataLoader.java

package com.example.javawebapi.config;import com.example.javawebapi.entity.ERole;
import com.example.javawebapi.entity.Role;
import com.example.javawebapi.repository.RoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class DataLoader implements CommandLineRunner {@Autowiredprivate RoleRepository roleRepository;@Overridepublic void run(String... args) throws Exception {// Create roles if they don't existif (roleRepository.findByName(ERole.ROLE_USER).isEmpty()) {roleRepository.save(new Role(ERole.ROLE_USER));}if (roleRepository.findByName(ERole.ROLE_ADMIN).isEmpty()) {roleRepository.save(new Role(ERole.ROLE_ADMIN));}}
}

3.9 定时任务

ScheduledTasks.java

package com.example.javawebapi.task;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
import java.util.Date;@Component
public class ScheduledTasks {private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");// 每5分钟执行一次@Scheduled(fixedRate = 300000)public void reportCurrentTime() {log.info("定时任务执行 - 当前时间: {}", dateFormat.format(new Date()));}// 每天凌晨1点执行@Scheduled(cron = "0 0 1 * * ?")public void performDailyCleanup() {log.info("执行每日清理任务 - 当前时间: {}", dateFormat.format(new Date()));// 这里可以添加数据清理、统计等逻辑}// 每小时执行一次@Scheduled(cron = "0 0 * * * ?")public void performHourlyTask() {log.info("执行每小时任务 - 当前时间: {}", dateFormat.format(new Date()));// 这里可以添加缓存刷新、数据同步等逻辑}
}

3.10 全局异常处理

GlobalExceptionHandler.java

package com.example.javawebapi.exception;import com.example.javawebapi.payload.response.MessageResponse;
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 org.springframework.web.context.request.WebRequest;import java.util.HashMap;
import java.util.Map;@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<?> 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(errors);}@ExceptionHandler(RuntimeException.class)public ResponseEntity<?> handleRuntimeException(RuntimeException ex, WebRequest request) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new MessageResponse("Error: " + ex.getMessage()));}@ExceptionHandler(Exception.class)public ResponseEntity<?> globalExceptionHandler(Exception ex, WebRequest request) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new MessageResponse("An unexpected error occurred"));}
}

3.11 应用主类

JavaWebApiApplication.java

package com.example.javawebapi;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class JavaWebApiApplication {public static void main(String[] args) {SpringApplication.run(JavaWebApiApplication.class, args);}
}

在这里插入图片描述

4. API 测试和使用

4.1 启动应用

mvn spring-boot:run

4.2 API 文档访问

  • Swagger UI: http://localhost:8080/api/swagger-ui.html
  • H2 数据库控制台: http://localhost:8080/api/h2-console

4.3 测试 API

注册用户:

curl -X POST http://localhost:8080/api/auth/signup \-H "Content-Type: application/json" \-d '{"username": "testuser","email": "test@example.com","password": "password123","role": ["user"]}'

登录获取token:

curl -X POST http://localhost:8080/api/auth/signin \-H "Content-Type: application/json" \-d '{"username": "testuser","password": "password123"}'

访问受保护接口:

curl -X GET http://localhost:8080/api/users \-H "Authorization: Bearer YOUR_JWT_TOKEN"

5. 核心原理总结

5.1 安全流程

  1. 用户登录 → 验证凭证 → 生成JWT
  2. 后续请求携带JWT → 过滤器验证 → 设置安全上下文
  3. 方法级权限控制 → @PreAuthorize注解

5.2 数据流程

  1. 控制器接收请求 → 数据验证
  2. 服务层处理业务逻辑
  3. 数据层访问数据库
  4. 返回响应DTO

5.3 定时任务原理

  • @Scheduled注解标记定时方法
  • Spring调度器基于线程池执行
  • 支持fixedRate、cron表达式等

http://www.dtcms.com/a/500798.html

相关文章:

  • 网站建设与管理复习知识点购物网站怎么创建
  • IEEE 802.11无线wifi帧结构
  • [SCADE编译原理] 时钟分析原理(2003)
  • 做网站的市场细分陶瓷网站制作
  • 毕设做网站具体步骤网站开发模板
  • Vue3与Vue2中使用对比
  • 做电子的外单网站有哪些的优质的成都网站建设推
  • 手机网站建设的现状河南省住房和建设厅网站
  • 企业官方网站建设费用网站免费源码
  • dz做电影网站动画制作过程
  • 哪里有网站建设加工微网站怎么注册账号
  • 《隐变量》
  • 网站建设 厦门金牛区网站建设
  • 做的好的招投标网站深圳建设工程交易服务网官网龙岗
  • 网站建设完工后在什么科目核算画册设计排版的技巧和规则
  • 《第05章 项目整体管理》备考知识点整理
  • QGIS字段计算器常用公式汇总(含实操示例)
  • 国外网站seo用哪个网站做相册视频文件
  • 迅速上排名网站优化微信公众平台号申请注册入口
  • 网站开发语言p我要注册
  • 免费传奇网站模板网站建设是管理费用的哪项费用
  • 学校网站建设所使用的技术如何知道一个网站是谁做的
  • 网站建设分金手指专业五wordpress怎么使用插件下载失败
  • 15.搜索二叉树(一)
  • 营销网站的类型西安市城乡建设厅网站
  • NET开发网站开发工程师招聘cms+wordpress模板
  • FreeHub:一个免费产品的收录平台
  • 网站建设 美词响应式相册网站
  • 网站开发规范有哪些购物网站的商品展示模块
  • 旅游订票网站开发专门做二维码的网站