Spring Boot 是由 Pivotal 团队提供的一个开源框架,旨在简化基于 Spring 的应用开发。它通过自动配置、起步依赖和命令行界面等特性,使得开发者可以快速地创建独立的、生产级别的基于 Spring 的应用程序。Spring Boot 适用于各种类型的应用,包括 Web 应用、微服务、批处理应用等。
主要特性
- 自动配置:Spring Boot 根据类路径中的依赖项自动配置应用程序。
- 起步依赖:提供了一系列的“starter”依赖,简化了 Maven 或 Gradle 项目的依赖管理。
- 嵌入式服务器:内置 Tomcat、Jetty 或 Undertow 服务器,无需额外配置即可运行 Web 应用。
- 命令行接口 (CLI):提供了一个强大的命令行工具来帮助开发和部署 Spring Boot 应用程序。
- Actuator:提供了生产就绪的功能,如健康检查、指标收集、外部化配置等。
示例项目:图书管理系统
假设我们要开发一个简单的图书管理系统,包含用户注册、登录、书籍管理和订单管理等功能。我们将使用 Spring Boot 来快速搭建这个系统。
项目结构
深色版本
book-management-system/
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── bookmanagement
│ │ │ ├── BookManagementApplication.java
│ │ │ ├── controller
│ │ │ │ ├── BookController.java
│ │ │ │ ├── UserController.java
│ │ │ ├── model
│ │ │ │ ├── Book.java
│ │ │ │ ├── User.java
│ │ │ ├── repository
│ │ │ │ ├── BookRepository.java
│ │ │ │ ├── UserRepository.java
│ │ │ ├── service
│ │ │ │ ├── BookService.java
│ │ │ │ ├── UserService.java
│ │ │ ├── security
│ │ │ │ ├── SecurityConfig.java
│ │ │ │ ├── UserDetailsServiceImpl.java
│ │ │ │ ├── JwtUtils.java
│ │ │ │ ├── JwtAuthEntryPoint.java
│ │ │ │ ├── JwtAuthTokenFilter.java
│ │ │ ├── exception
│ │ │ │ ├── ResourceNotFoundException.java
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ ├── static
│ │ │ ├── templates
└── pom.xml
1. 项目初始化
首先,创建一个新的 Maven 项目并添加 Spring Boot 依赖。
xml
深色版本
<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.example</groupId>
<artifactId>book-management-system</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<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>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.h2</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. 创建主类
创建 BookManagementApplication
类作为 Spring Boot 应用程序的入口点。
java
深色版本
package com.example.bookmanagement;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BookManagementApplication {
public static void main(String[] args) {
SpringApplication.run(BookManagementApplication.class, args);
}
}
3. 数据模型
定义 User
和 Book
实体类。
java
深色版本
package com.example.bookmanagement.model;
import javax.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
// Getters and Setters
}
@Entity
@Table(name = "books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
private double price;
// Getters and Setters
}
4. 数据库操作
创建 UserRepository
和 BookRepository
接口。
java
深色版本
package com.example.bookmanagement.repository;
import com.example.bookmanagement.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
package com.example.bookmanagement.repository;
import com.example.bookmanagement.model.Book;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookRepository extends JpaRepository<Book, Long> {
}
5. 业务逻辑
创建 UserService
和 BookService
类。
java
深色版本
package com.example.bookmanagement.service;
import com.example.bookmanagement.model.User;
import com.example.bookmanagement.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
public User save(User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
package com.example.bookmanagement.service;
import com.example.bookmanagement.model.Book;
import com.example.bookmanagement.repository.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
@Autowired
private BookRepository bookRepository;
public List<Book> getAllBooks() {
return bookRepository.findAll();
}
public Book getBookById(Long id) {
return bookRepository.findById(id).orElse(null);
}
public Book saveBook(Book book) {
return bookRepository.save(book);
}
public void deleteBook(Long id) {
bookRepository.deleteById(id);
}
}
6. 控制器
创建 UserController
和 BookController
类。
java
深色版本
package com.example.bookmanagement.controller;
import com.example.bookmanagement.model.User;
import com.example.bookmanagement.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/signup")
public ResponseEntity<?> registerUser(@RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity.ok(savedUser);
}
}
package com.example.bookmanagement.controller;
import com.example.bookmanagement.model.Book;
import com.example.bookmanagement.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping
public List<Book> getAllBooks() {
return bookService.getAllBooks();
}
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable Long id) {
Book book = bookService.getBookById(id);
if (book == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(book);
}
@PostMapping
public ResponseEntity<Book> addBook(@RequestBody Book book) {
Book savedBook = bookService.saveBook(book);
return ResponseEntity.ok(savedBook);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
bookService.deleteBook(id);
return ResponseEntity.noContent().build();
}
}
7. 安全配置
配置 Spring Security 以实现用户认证和授权。
java
深色版本
package com.example.bookmanagement.security;
import com.example.bookmanagement.security.jwt.JwtAuthEntryPoint;
import com.example.bookmanagement.security.jwt.JwtAuthTokenFilter;
import com.example.bookmanagement.security.services.UserDetailsServiceImpl;
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.builders.AuthenticationManagerBuilder;
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 UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthEntryPoint unauthorizedHandler;
@Bean
public JwtAuthTokenFilter authenticationJwtTokenFilter() {
return new JwtAuthTokenFilter();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
8. JWT 认证
实现 JWT 令牌生成和验证。
java
深色版本
package com.example.bookmanagement.security.jwt;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
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.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtils {
private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
@Value("${app.jwtSecret}")
private String jwtSecret;
@Value("${app.jwtExpirationMs}")
private int jwtExpirationMs;
public String generateJwtToken(Authentication authentication) {
User principal = (User) authentication.getPrincipal();
return Jwts.builder()
.setSubject(principal.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)), SignatureAlgorithm.HS256)
.compact();
}
public String getUserNameFromJwtToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)))
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateJwtToken(String authToken) {
try {
Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)))
.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;
}
}
9. 用户详细信息服务
实现 UserDetailsServiceImpl
以加载用户详细信息。
java
深色版本
package com.example.bookmanagement.security.services;
import com.example.bookmanagement.model.User;
import com.example.bookmanagement.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 {
@Autowired
UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
return UserDetailsImpl.build(user);
}
}
10. 资源异常处理
创建自定义异常处理类。
java
深色版本
package com.example.bookmanagement.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
11. 配置文件
在 application.properties
中添加必要的配置。
properties
深色版本
# H2 Database Configuration
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
# JWT Configuration
app.jwtSecret=your_secret_key
app.jwtExpirationMs=86400000 # 24 hours
结论
通过上述步骤,我们构建了一个简单的图书管理系统,涵盖了用户注册、登录、书籍管理和订单管理等功能。这个项目展示了如何使用 Spring Boot 来快速搭建一个功能完备的应用程序。Spring Boot 的自动配置和丰富的生态系统使得开发变得更加高效和便捷。