Spring Boot是Java生态中最流行的微服务框架,掌握Spring Boot是Java后端开发的核心技能。本文将深入剖析Spring Boot的核心特性和最佳实践,助你快速构建企业级应用。
一、Spring Boot简介
1.1 什么是Spring Boot?
关键点: Spring Boot是基于Spring框架的快速开发脚手架,简化了Spring应用的配置和部署。
传统Spring vs Spring Boot:
xml
<!-- ❌ 传统Spring:繁琐的XML配置 -->
<!-- applicationContext.xml -->
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 更多配置... -->
</beans>
java
// ✅ Spring Boot:约定优于配置,零XML
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
Spring Boot优势:
- 零XML配置,使用注解和自动配置
- 内嵌Tomcat,无需部署WAR包
- 提供starter依赖,简化Maven配置
- 生产级监控和健康检查
- 快速开发,提高效率
二、快速入门
2.1 创建第一个Spring Boot项目
xml
<!-- pom.xml -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<dependencies>
<!-- Web starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
java
// 主启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// Controller
@RestController
@RequestMapping("/api")
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
User user = new User();
user.setId(id);
user.setName("张三");
user.setAge(25);
return user;
}
@PostMapping("/user")
public User createUser(@RequestBody User user) {
System.out.println("创建用户:" + user);
return user;
}
}
// 实体类
@Data
public class User {
private Long id;
private String name;
private Integer age;
}
2.2 配置文件
yaml
# application.yml
server:
port: 8080
servlet:
context-path: /api
spring:
application:
name: demo-service
# 数据源配置
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# JPA配置
jpa:
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
# Redis配置
redis:
host: localhost
port: 6379
password:
database: 0
# 日志配置
logging:
level:
root: INFO
com.example: DEBUG
file:
name: logs/application.log
三、核心注解详解
3.1 常用注解
java
// @SpringBootApplication:组合注解
@SpringBootApplication
// 等价于:
// @SpringBootConfiguration
// @EnableAutoConfiguration
// @ComponentScan
public class Application {
}
// @RestController:组合注解
@RestController
// 等价于:
// @Controller + @ResponseBody
public class UserController {
}
// @RequestMapping:请求映射
@RestController
@RequestMapping("/api/users")
public class UserController {
// GET请求
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getById(id);
}
// POST请求
@PostMapping
public User createUser(@RequestBody User user) {
return userService.save(user);
}
// PUT请求
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.update(user);
}
// DELETE请求
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteById(id);
}
}
// @Autowired:依赖注入
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 推荐:构造器注入
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
// @Value:读取配置
@Component
public class AppConfig {
@Value("${app.name}")
private String appName;
@Value("${app.version:1.0}") // 默认值
private String version;
}
// @ConfigurationProperties:批量读取配置
@Component
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
private String name;
private String version;
private Database database;
@Data
public static class Database {
private String url;
private String username;
private String password;
}
}
3.2 条件注解
java
// 根据条件创建Bean
@Configuration
public class DataSourceConfig {
// 当存在某个类时
@Bean
@ConditionalOnClass(DataSource.class)
public DataSource dataSource() {
return new HikariDataSource();
}
// 当不存在某个Bean时
@Bean
@ConditionalOnMissingBean
public UserService userService() {
return new UserServiceImpl();
}
// 当配置属性存在时
@Bean
@ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
四、数据访问层
4.1 Spring Data JPA
java
// 实体类
@Entity
@Table(name = "users")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String username;
@Column(nullable = false)
private String password;
@Column(length = 100)
private String email;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
@PrePersist
public void prePersist() {
this.createTime = LocalDateTime.now();
this.updateTime = LocalDateTime.now();
}
@PreUpdate
public void preUpdate() {
this.updateTime = LocalDateTime.now();
}
}
// Repository接口
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名查询
User findByUsername(String username);
List<User> findByEmailContaining(String email);
// @Query注解
@Query("SELECT u FROM User u WHERE u.username = ?1 AND u.email = ?2")
User findByUsernameAndEmail(String username, String email);
// 原生SQL
@Query(value = "SELECT * FROM users WHERE username LIKE %?1%", nativeQuery = true)
List<User> searchByUsername(String username);
// 分页查询
Page<User> findByEmailContaining(String email, Pageable pageable);
}
// Service层
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User save(User user) {
return userRepository.save(user);
}
public User getById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("用户不存在"));
}
public Page<User> getUsers(int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("createTime").descending());
return userRepository.findAll(pageable);
}
public void deleteById(Long id) {
userRepository.deleteById(id);
}
}
4.2 MyBatis
xml
<!-- pom.xml -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
java
// Mapper接口
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User findById(Long id);
@Insert("INSERT INTO users(username, password, email) VALUES(#{username}, #{password}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
@Update("UPDATE users SET username=#{username}, email=#{email} WHERE id=#{id}")
int update(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteById(Long id);
// 使用XML映射
List<User> findByCondition(UserQuery query);
}
xml
<!-- UserMapper.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<select id="findByCondition" resultType="com.example.entity.User">
SELECT * FROM users
<where>
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%')
</if>
<if test="email != null and email != ''">
AND email = #{email}
</if>
</where>
ORDER BY create_time DESC
</select>
</mapper>
五、统一异常处理
java
// 自定义异常
public class BusinessException extends RuntimeException {
private Integer code;
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
public Integer getCode() {
return code;
}
}
// 统一响应格式
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
public static <T> Result<T> error(Integer code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
return result;
}
}
// 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusinessException(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<?> handleValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
String message = bindingResult.getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.error(400, message);
}
// 处理其他异常
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e) {
e.printStackTrace();
return Result.error(500, "系统错误:" + e.getMessage());
}
}
// Controller使用
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public Result<User> getUser(@PathVariable Long id) {
User user = userService.getById(id);
if (user == null) {
throw new BusinessException(404, "用户不存在");
}
return Result.success(user);
}
}
六、参数校验
java
// 实体类添加校验注解
@Data
public class UserDTO {
@NotNull(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
private String username;
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$",
message = "密码必须包含大小写字母和数字,至少8位")
private String password;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 18, message = "年龄必须大于18岁")
@Max(value = 100, message = "年龄必须小于100岁")
private Integer age;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
}
// Controller使用@Valid触发校验
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public Result<User> createUser(@Valid @RequestBody UserDTO userDTO) {
// 校验通过才会执行到这里
User user = userService.create(userDTO);
return Result.success(user);
}
}
// 自定义校验注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
String message() default "身份证号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
// 校验器实现
public class IdCardValidator implements ConstraintValidator<IdCard, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isEmpty()) {
return true;
}
// 身份证号校验逻辑
return value.matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$");
}
}
七、拦截器与过滤器
7.1 拦截器
java
// 自定义拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || token.isEmpty()) {
response.setStatus(401);
response.getWriter().write("未登录");
return false;
}
// 验证token
if (!validateToken(token)) {
response.setStatus(401);
response.getWriter().write("token无效");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 请求处理后,视图渲染前
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
// 视图渲染后
}
private boolean validateToken(String token) {
// token验证逻辑
return true;
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**") // 拦截路径
.excludePathPatterns("/api/login", "/api/register"); // 排除路径
}
}
7.2 过滤器
java
// 自定义过滤器
@Component
@Order(1) // 执行顺序
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LogFilter初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
long start = System.currentTimeMillis();
System.out.println("请求开始:" + req.getRequestURI());
chain.doFilter(request, response); // 继续执行
long end = System.currentTimeMillis();
System.out.println("请求结束,耗时:" + (end - start) + "ms");
}
@Override
public void destroy() {
System.out.println("LogFilter销毁");
}
}
过滤器 vs 拦截器:
| 特性 | 过滤器 | 拦截器 |
|---|---|---|
| 规范 | Servlet规范 | Spring规范 |
| 执行时机 | 请求进入容器 | 请求进入Controller |
| 依赖注入 | 不支持 | 支持 |
| 使用场景 | 编码、跨域 | 权限、日志 |
八、实战案例:RESTful API
java
// 用户管理完整示例
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
// 分页查询
@GetMapping
public Result<Page<User>> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String keyword) {
Page<User> users = userService.getUsers(page, size, keyword);
return Result.success(users);
}
// 根据ID查询
@GetMapping("/{id}")
public Result<User> getUser(@PathVariable Long id) {
User user = userService.getById(id);
return Result.success(user);
}
// 创建用户
@PostMapping
public Result<User> createUser(@Valid @RequestBody UserDTO userDTO) {
User user = userService.create(userDTO);
return Result.success(user);
}
// 更新用户
@PutMapping("/{id}")
public Result<User> updateUser(@PathVariable Long id,
@Valid @RequestBody UserDTO userDTO) {
User user = userService.update(id, userDTO);
return Result.success(user);
}
// 删除用户
@DeleteMapping("/{id}")
public Result<Void> deleteUser(@PathVariable Long id) {
userService.deleteById(id);
return Result.success(null);
}
// 批量删除
@DeleteMapping
public Result<Void> batchDelete(@RequestBody List<Long> ids) {
userService.batchDelete(ids);
return Result.success(null);
}
}
// Service层
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository,
PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public Page<User> getUsers(int page, int size, String keyword) {
Pageable pageable = PageRequest.of(page, size,
Sort.by("createTime").descending());
if (keyword != null && !keyword.isEmpty()) {
return userRepository.findByUsernameContaining(keyword, pageable);
}
return userRepository.findAll(pageable);
}
public User getById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new BusinessException(404, "用户不存在"));
}
public User create(UserDTO userDTO) {
// 检查用户名是否存在
if (userRepository.findByUsername(userDTO.getUsername()) != null) {
throw new BusinessException(400, "用户名已存在");
}
User user = new User();
BeanUtils.copyProperties(userDTO, user);
user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
return userRepository.save(user);
}
public User update(Long id, UserDTO userDTO) {
User user = getById(id);
BeanUtils.copyProperties(userDTO, user, "id", "password");
return userRepository.save(user);
}
public void deleteById(Long id) {
if (!userRepository.existsById(id)) {
throw new BusinessException(404, "用户不存在");
}
userRepository.deleteById(id);
}
public void batchDelete(List<Long> ids) {
userRepository.deleteAllById(ids);
}
}
九、总结
Spring Boot微服务开发的核心要点:
- 快速开发 - 约定优于配置,零XML
- 数据访问 - JPA或MyBatis,选择合适的ORM
- 异常处理 - 统一异常处理,规范响应格式
- 参数校验 - 使用JSR303校验,保证数据安全
- 拦截器 - 权限控制、日志记录
最佳实践:
- 使用构造器注入代替@Autowired
- 合理使用事务注解@Transactional
- 统一响应格式和异常处理
- 使用DTO传输数据,避免直接暴露实体
- 合理使用缓存提升性能
相关资源
💡 小贴士: Spring Boot简化了开发,但理解Spring核心原理同样重要!
关注我,获取更多Spring Boot干货! ☕