一步到位!Spring Boot 用户管理系统全流程开发与部署(超详细企业级指南)

本文以「用户管理系统」为实战案例,演示如何从零搭建、部署及测试一个功能完备、架构合理的 Spring Boot 企业级应用,涵盖:多环境配置、实体/DTO/VO 分离、分页 & 动态查询、全局统一异常、日志系统、接口文档、数据库控制台、安全认证、单元测试、集成测试、Docker 化及 CI/CD。


📑 目录

  1. 技术栈与架构
  2. 项目初始化
  3. 多环境配置
  4. 实体/DTO/VO 设计
  5. 数据访问层(Repository)
  6. 业务层(Service)
  7. 控制层(Controller)
  8. 全局异常处理
  9. 日志系统配置
  10. 接口文档(Swagger / OpenAPI)
  11. 数据库控制台(H2)
  12. 安全认证(Spring Security + JWT)
  13. 前端展示(Thymeleaf + Bootstrap)
  14. 单元测试与集成测试
  15. Docker 化部署
  16. CI/CD(GitHub Actions)
  17. 常见问题 & FAQ
  18. 下一步

技术栈与架构

  • 后端框架:Spring Boot 3.x
  • 持久层:Spring Data JPA + Hibernate
  • 数据库:H2(测试),MySQL(生产)
  • 安全:Spring Security + JWT
  • 接口文档:SpringDoc OpenAPI
  • 模板引擎:Thymeleaf
  • 前端样式:Bootstrap 5
  • 日志:SLF4J + Logback
  • 测试:JUnit 5 + Mockito + SpringBootTest
  • 容器化:Docker + Docker Compose
  • CI/CD:GitHub Actions

项目分层架构示意:
在这里插入图片描述

┌─ controller (接口层)
│
├─ service    (服务层, 业务逻辑)
│
├─ repository (数据访问层)
│
├─ entity     (JPA 实体)
│
├─ dto        (数据传输对象)
│
├─ vo         (视图对象)
│
├─ config     (配置类)
│
└─ exception  (全局异常处理)

项目初始化

  1. 前往 Spring Initializr,设置:
    • Project: Maven
    • Language: Java
    • Spring Boot: 3.1+
    • Packaging: Jar
    • Java: 17(或 11)
  2. 添加依赖:
    • Spring Web
    • Spring Data JPA
    • H2 Database
    • MySQL Driver
    • Spring Boot Actuator
    • Spring Security
    • springdoc-openapi-starter-webmvc-ui
    • Lombok
  3. 下载并导入 IDE,开启 Lombok 插件。

多环境配置

使用 application.yml + Profile 切换:

spring:
  profiles:
    active: dev  # 默认开发环境
---
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
---
spring:
  config:
    activate:
      on-profile: prod
  datasource:
    url: jdbc:mysql://localhost:3306/userdb?useSSL=false&serverTimezone=UTC
    username: root
    password: 你的密码
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: validate

启动生产环境:

java -jar user-demo.jar --spring.profiles.active=prod

实体/DTO/VO 设计

Entity: User.java

@Entity
@Table(name = "users")
@Data
@NoArgsConstructor @AllArgsConstructor @Builder
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable=false, unique=true)
    private String username;

    @Column(nullable=false)
    private String email;

    @Column(nullable=false)
    private String password; // 存储加密后密码
}

DTO: UserDTO.java

@Data
public class UserDTO {
    private String username;
    private String email;
}

VO: UserVO.java

@Data
public class UserVO {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createdAt;
}

Mapper: 使用 MapStruct

@Mapper(componentModel = "spring")
public interface UserMapper {
    UserVO toVO(User user);
    User toEntity(UserDTO dto);
}

数据访问层(Repository)

public interface UserRepository extends JpaRepository<User, Long> {
    Page<User> findByUsernameContainsAndEmailContains(String username, String email, Pageable pageable);
    Optional<User> findByUsername(String username);
}

业务层(Service)

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository repo;
    private final PasswordEncoder encoder;
    private final UserMapper mapper;

    @Transactional
    public UserVO createUser(UserDTO dto) {
        if(repo.findByUsername(dto.getUsername()).isPresent()) {
            throw new BusinessException("用户名已存在");
        }
        User entity = mapper.toEntity(dto);
        entity.setPassword(encoder.encode(dto.getPassword()));
        User saved = repo.save(entity);
        return mapper.toVO(saved);
    }

    public Page<UserVO> listUsers(String username, String email, Pageable p) {
        return repo.findByUsernameContainsAndEmailContains(username, email, p)
                   .map(mapper::toVO);
    }
    // 其他更新、删除方法略...
}

控制层(Controller)

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService svc;

    @PostMapping
    public ResponseEntity<UserVO> create(@Valid @RequestBody UserDTO dto) {
        UserVO vo = svc.createUser(dto);
        return ResponseEntity.status(HttpStatus.CREATED).body(vo);
    }

    @GetMapping
    public Page<UserVO> search(
        @RequestParam(defaultValue="") String username,
        @RequestParam(defaultValue="") String email,
        @RequestParam(defaultValue="0") int page,
        @RequestParam(defaultValue="10") int size
    ) {
        Pageable p = PageRequest.of(page, size);
        return svc.listUsers(username, email, p);
    }
}

请求示例(curl):

curl -X POST http://localhost:8080/api/users   -H "Content-Type: application/json"   -d '{"username":"alice","email":"alice@example.com","password":"123456"}'

全局异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<?> handleBiz(BusinessException ex) {
        return ResponseEntity.badRequest()
            .body(Map.of("error", ex.getMessage()));
    }
    @ExceptionHandler(Exception.class)
    public ResponseEntity<?> handleSys(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(Map.of("error", "系统异常,请联系管理员"));
    }
}

日志系统配置

logback-spring.xml

<configuration>
  <springProfile name="dev">
    <logger name="com.example" level="DEBUG"/>
  </springProfile>
  <springProfile name="prod">
    <logger name="com.example" level="INFO"/>
  </springProfile>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
  <root level="INFO">
    <appender-ref ref="STDOUT"/>
  </root>
</configuration>

接口文档(Swagger / OpenAPI)

在这里插入图片描述

springdoc:
  api-docs:
    path: /v3/api-docs
  swagger-ui:
    path: /swagger-ui.html

访问:http://localhost:8080/swagger-ui.html


数据库控制台 (H2)

在这里插入图片描述

application.yml 启用:

spring:
  h2:
    console:
      enabled: true
      path: /h2-console

访问:http://localhost:8080/h2-console (JDBC URL: jdbc:h2:mem:testdb


安全认证(Spring Security + JWT)

省略 JWT 生成和过滤器配置代码示例,核心思路:

  1. 用户登录 /api/auth/login 返回 JWT
  2. 全局过滤器校验 Token
  3. 保护 /api/users/** 接口

前端展示(Thymeleaf + Bootstrap)

在这里插入图片描述

  • 模板目录:src/main/resources/templates
  • 静态资源:src/main/resources/static

示例模板 index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>...</head>
<body>
  <div class="container">
    <h1>用户列表</h1>
    <table class="table">...</table>
  </div>
</body>
</html>

单元测试 & 集成测试

单元测试:UserServiceTest.java

@SpringBootTest
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    @Mock UserRepository repo;
    @InjectMocks UserService svc;
    @Test void shouldCreateUser() {
        UserDTO dto = new UserDTO("bob","bob@example.com","pwd");
        when(repo.findByUsername("bob")).thenReturn(Optional.empty());
        when(repo.save(any())).thenAnswer(i -> i.getArgument(0));
        UserVO vo = svc.createUser(dto);
        assertEquals("bob", vo.getUsername());
    }
}

集成测试:UserControllerIT.java

在这里插入图片描述

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class UserControllerIT {
    @Autowired MockMvc mvc;
    @Test void getUsers() throws Exception {
        mvc.perform(get("/api/users"))
           .andExpect(status().isOk())
           .andExpect(jsonPath("$.content").isArray());
    }
}

Docker 化部署

Dockerfile

FROM eclipse-temurin:17-jdk-alpine
WORKDIR /app
COPY target/user-demo.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]

docker-compose.yml

version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      SPRING_PROFILES_ACTIVE: prod
    depends_on:
      - db
  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: userdb
      MYSQL_ROOT_PASSWORD: root
    ports:
      - "3306:3306"

CI/CD (GitHub Actions)

.github/workflows/ci.yml 示例:

name: Java CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
      - name: Build with Maven
        run: mvn clean package -DskipTests
      - name: Run tests
        run: mvn test
      - name: Build Docker image
        run: docker build -t user-demo .

常见问题 & FAQ

  1. 如何加密密码? 使用 BCryptPasswordEncoder
  2. Actuator 如何细粒度管理? 修改 management.endpoints.web.exposure.include/exclude
  3. 如何切换日志级别? 修改 logback-spring.xml 或动态日志端点。

下一步

  • 接入 Redis 缓存,加速查询
  • 整合消息队列(RabbitMQ / Kafka)
  • 微服务拆分:Spring Cloud Gateway + Consul / Eureka
  • 前后端分离:React / Vue + Rest API

⭐️ 如果觉得有帮助,欢迎点赞、收藏并分享给更多人

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeepTechTalk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值