spring boot实现用户管理服务器

我们来实现一个更贴近实际开发的 用户管理服务器,包含以下功能:

• 数据库交互(使用 JPA + MySQL)

• 完整的 CRUD 接口(RESTful 风格)

• 参数校验与自定义异常处理

• 分层架构(Controller/Service/Repository)

• DTO 数据传输(避免直接暴露实体类)

一、技术栈与依赖

在 Spring Initializr 中额外添加以下依赖:

• Spring Web(Web 服务器基础)

• Spring Data JPA(数据库操作)

• MySQL Driver(数据库驱动)

• Validation(参数校验)

• Lombok(简化实体类代码,需 IDE 安装 Lombok 插件)

二、项目结构(分层架构)
src/main/java/com/example/usermanage/
├── UserManageApplication.java  // 主启动类
├── controller/                 // 控制器层(处理HTTP请求)
│   └── UserController.java
├── service/                    // 服务层(业务逻辑)
│   ├── UserService.java
│   └── impl/UserServiceImpl.java
├── repository/                 // 数据访问层(操作数据库)
│   └── UserRepository.java
├── entity/                     // 数据库实体类
│   └── User.java
├── dto/                        // 数据传输对象(请求/响应)
│   ├── UserRequest.java        // 接收创建/更新用户的请求参数
│   └── UserResponse.java       // 返回用户数据
├── exception/                  // 异常处理
│   ├── UserNotFoundException.java  // 自定义异常
│   ├── GlobalExceptionHandler.java  // 全局异常处理器
│   └── ErrorResponse.java       // 统一错误响应格式
└── config/                     // 配置类
    └── JpaConfig.java          // JPA 配置(可选)
src/main/resources/
├── application.properties  // 全局配置(数据库、端口等)

三、核心代码实现

1. 配置文件(application.properties)
# 服务器端口
server.port=8080

# MySQL 数据库配置(需先在本地创建名为 `usermanage` 的数据库)
spring.datasource.url=jdbc:mysql://localhost:3306/usermanage?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=你的数据库密码
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA 配置
spring.jpa.hibernate.ddl-auto=update  # 自动创建/更新表结构
spring.jpa.show-sql=true              # 打印SQL日志
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.format_sql=true  # 格式化SQL

# 日志级别(可选)
logging.level.org.springframework.web=INFO
logging.level.com.example.usermanage=DEBUG
2. 实体类(User.java)
package com.example.usermanage.entity;

import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import java.time.LocalDateTime;

@Data  // Lombok 注解:自动生成 getter/setter/toString 等
@Entity
@Table(name = "t_user")  // 数据库表名
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)  // 自增主键
    private Long id;

    @Column(unique = true, nullable = false)  // 用户名唯一且非空
    private String username;

    @Column(nullable = false)
    private String email;

    private Integer age;

    @CreationTimestamp  // 自动填充创建时间
    private LocalDateTime createTime;

    @UpdateTimestamp  // 自动填充更新时间
    private LocalDateTime updateTime;
}
3. DTO(数据传输对象)

UserRequest.java(接收请求参数)
package com.example.usermanage.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class UserRequest {
    @NotBlank(message = "用户名不能为空")  // 参数校验:非空
    private String username;

    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")  // 校验邮箱格式
    private String email;

    @Min(value = 0, message = "年龄不能为负数")  // 校验年龄最小值
    private Integer age;
}
UserResponse.java(返回响应数据)
package com.example.usermanage.dto;

import lombok.Data;
import java.time.LocalDateTime;

@Data
public class UserResponse {
    private Long id;
    private String username;
    private String email;
    private Integer age;
    private LocalDateTime createTime;
}
4. 数据访问层(UserRepository.java)
package com.example.usermanage.repository;

import com.example.usermanage.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;

// 继承 JpaRepository 即可获得 CRUD 方法(无需手动实现)
public interface UserRepository extends JpaRepository<User, Long> {
    // 自定义查询:根据用户名查询(用于判断用户名是否已存在)
    Optional<User> findByUsername(String username);
}
5. 服务层(Service)

UserService.java(接口)
package com.example.usermanage.service;

import com.example.usermanage.dto.UserRequest;
import com.example.usermanage.dto.UserResponse;
import java.util.List;

public interface UserService {
    // 创建用户
    UserResponse createUser(UserRequest request);

    // 查询所有用户
    List<UserResponse> getAllUsers();

    // 根据ID查询用户
    UserResponse getUserById(Long id);

    // 更新用户
    UserResponse updateUser(Long id, UserRequest request);

    // 删除用户
    void deleteUser(Long id);
}
UserServiceImpl.java(实现类)
package com.example.usermanage.service.impl;

import com.example.usermanage.dto.UserRequest;
import com.example.usermanage.dto.UserResponse;
import com.example.usermanage.entity.User;
import com.example.usermanage.exception.UserNotFoundException;
import com.example.usermanage.repository.UserRepository;
import com.example.usermanage.service.UserService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor  // Lombok 自动生成构造方法(注入依赖)
public class UserServiceImpl implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
    private final UserRepository userRepository;  // 注入 Repository

    @Override
    public UserResponse createUser(UserRequest request) {
        // 校验用户名是否已存在
        if (userRepository.findByUsername(request.getUsername()).isPresent()) {
            log.error("用户名已存在:{}", request.getUsername());
            throw new IllegalArgumentException("用户名已存在");
        }

        // 转换 DTO 为实体类
        User user = new User();
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setAge(request.getAge());

        // 保存到数据库
        User savedUser = userRepository.save(user);
        log.info("创建用户成功:{}", savedUser.getId());

        // 转换实体类为响应 DTO 并返回
        return convertToResponse(savedUser);
    }

    @Override
    public List<UserResponse> getAllUsers() {
        log.info("查询所有用户");
        return userRepository.findAll().stream()
                .map(this::convertToResponse)
                .collect(Collectors.toList());
    }

    @Override
    public UserResponse getUserById(Long id) {
        log.info("查询用户:{}", id);
        User user = userRepository.findById(id)
                .orElseThrow(() -> new UserNotFoundException("用户不存在:" + id));
        return convertToResponse(user);
    }

    @Override
    public UserResponse updateUser(Long id, UserRequest request) {
        log.info("更新用户:{}", id);
        // 先查询用户是否存在
        User user = userRepository.findById(id)
                .orElseThrow(() -> new UserNotFoundException("用户不存在:" + id));

        // 校验用户名是否被其他用户占用
        if (userRepository.findByUsername(request.getUsername()).isPresent() 
                && !user.getUsername().equals(request.getUsername())) {
            throw new IllegalArgumentException("用户名已存在");
        }

        // 更新字段
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setAge(request.getAge());

        User updatedUser = userRepository.save(user);
        return convertToResponse(updatedUser);
    }

    @Override
    public void deleteUser(Long id) {
        log.info("删除用户:{}", id);
        if (!userRepository.existsById(id)) {
            throw new UserNotFoundException("用户不存在:" + id);
        }
        userRepository.deleteById(id);
    }

    // 实体类转响应 DTO 的工具方法
    private UserResponse convertToResponse(User user) {
        UserResponse response = new UserResponse();
        response.setId(user.getId());
        response.setUsername(user.getUsername());
        response.setEmail(user.getEmail());
        response.setAge(user.getAge());
        response.setCreateTime(user.getCreateTime());
        return response;
    }
}
6. 控制器层(UserController.java)
package com.example.usermanage.controller;

import com.example.usermanage.dto.UserRequest;
import com.example.usermanage.dto.UserResponse;
import com.example.usermanage.service.UserService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/users")  // 基础路径
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    // 创建用户(POST 请求)
    @PostMapping
    public ResponseEntity<UserResponse> createUser(@Valid @RequestBody UserRequest request) {
        return new ResponseEntity<>(userService.createUser(request), HttpStatus.CREATED);
    }

    // 查询所有用户(GET 请求)
    @GetMapping
    public ResponseEntity<List<UserResponse>> getAllUsers() {
        return ResponseEntity.ok(userService.getAllUsers());
    }

    // 查询单个用户(GET 请求,路径带参数)
    @GetMapping("/{id}")
    public ResponseEntity<UserResponse> getUserById(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }

    // 更新用户(PUT 请求)
    @PutMapping("/{id}")
    public ResponseEntity<UserResponse> updateUser(
            @PathVariable Long id, 
            @Valid @RequestBody UserRequest request
    ) {
        return ResponseEntity.ok(userService.updateUser(id, request));
    }

    // 删除用户(DELETE 请求)
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();  // 返回 204 无内容
    }
}
7. 异常处理

自定义异常(UserNotFoundException.java)
package com.example.usermanage.exception;

// 当查询的用户不存在时抛出
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
}
统一错误响应格式(ErrorResponse.java)
package com.example.usermanage.exception;

import lombok.Data;
import java.time.LocalDateTime;

@Data
public class ErrorResponse {
    private int status;  // 状态码
    private String message;  // 错误信息
    private LocalDateTime timestamp;  // 时间戳

    public ErrorResponse(int status, String message) {
        this.status = status;
        this.message = message;
        this.timestamp = LocalDateTime.now();
    }
}
全局异常处理器(GlobalExceptionHandler.java)
package com.example.usermanage.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice  // 全局异常处理
public class GlobalExceptionHandler {

    // 处理用户不存在异常
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException e) {
        ErrorResponse error = new ErrorResponse(
                HttpStatus.NOT_FOUND.value(),  // 404 状态码
                e.getMessage()
        );
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }

    // 处理参数校验异常(如邮箱格式错误、用户名为空)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationExceptions(MethodArgumentNotValidException e) {
        // 获取第一个校验失败的消息
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        ErrorResponse error = new ErrorResponse(
                HttpStatus.BAD_REQUEST.value(),  // 400 状态码
                message
        );
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }

    // 处理其他业务异常(如用户名已存在)
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e) {
        ErrorResponse error = new ErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                e.getMessage()
        );
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }
}
四、启动与测试

1. 准备工作

• 本地安装 MySQL,创建数据库 usermanage(命令:CREATE DATABASE usermanage;)

• 修改 application.properties 中的 MySQL 用户名和密码为你的本地配置

2. 启动服务器

运行 UserManageApplication.java 主类,控制台显示 Started UserManageApplication 表示启动成功。

3. 测试接口(用 Postman 或 curl)
接口功能 请求方式 地址 请求体示例(JSON) 
创建用户 POST http://localhost:8080/api/users {"username":"zhangsan","email":"zhangsan@test.com","age":20} 
查询所有用户 GET http://localhost:8080/api/users 无 
查询单个用户 GET http://localhost:8080/api/users/1 无(1 为用户 ID) 
更新用户 PUT http://localhost:8080/api/users/1 {"username":"zhangsan2","email":"new@test.com","age":21} 
删除用户 DELETE http://localhost:8080/api/users/1 无 

五、关键扩展点说明

1. 数据库替换:若要使用 MySQL 以外的数据库(如 PostgreSQL),只需修改 application.properties 中的驱动和连接地址,并添加对应依赖。

2. 分页查询:在 UserRepository 中添加 Page<User> findAll(Pageable pageable);,Service 和 Controller 层接收 page 和 size 参数即可实现分页。

3. 认证授权:集成 Spring Security 可添加登录验证、角色权限控制。

4. 日志增强:可通过 logback-spring.xml 配置日志输出格式、文件存储等。

这个例子涵盖了实际开发中的核心流程,包括分层架构、数据校验、异常处理、数据库交互等,你可以基于此进一步扩展功能(如添加缓存、异步任务等)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

globaldeepthinker

能为我买一杯咖啡吗谢谢你的帮助

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

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

打赏作者

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

抵扣说明:

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

余额充值