【Spring Boot微服务开发实战:从入门到企业级应用】

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微服务开发的核心要点:

  1. 快速开发 - 约定优于配置,零XML
  2. 数据访问 - JPA或MyBatis,选择合适的ORM
  3. 异常处理 - 统一异常处理,规范响应格式
  4. 参数校验 - 使用JSR303校验,保证数据安全
  5. 拦截器 - 权限控制、日志记录

最佳实践:

  • 使用构造器注入代替@Autowired
  • 合理使用事务注解@Transactional
  • 统一响应格式和异常处理
  • 使用DTO传输数据,避免直接暴露实体
  • 合理使用缓存提升性能

相关资源


💡 小贴士: Spring Boot简化了开发,但理解Spring核心原理同样重要!

关注我,获取更多Spring Boot干货!

相关推荐
刺客-Andy2 小时前
js高频面试题 50道及答案
开发语言·javascript·ecmascript
徐老总2 小时前
手机号脱敏处理(Python/Scala 双版本实现)
java
夏幻灵2 小时前
指针在 C++ 中最核心、最实用的两个作用:“避免大数据的复制” 和 “共享”。
开发语言·c++
夏末4722 小时前
面试必问!多线程操作集合避坑指南:用synchronized搞定线程安全
java
CC.GG2 小时前
【C++】STL----封装红黑树实现map和set
android·java·c++
loosenivy2 小时前
IP风险画像识别和IP风险预警接口
java·ip查询·ip风险画像识别·ip预警查询·ip画像
ghie90902 小时前
MATLAB 高速公路裂缝检测
开发语言·matlab
Yyyyy123jsjs2 小时前
Python 如何做量化交易?从行情获取开始
开发语言·python