Skip to content

Spring Boot

这一页以 Controller / Service / 异常处理 / 返回体 为主,尽量做到复制后只改业务名。

统一返回体模板

java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
    private Integer code;
    private String message;
    private T data;

    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(0, "success", data);
    }

    public static <T> ApiResponse<T> success() {
        return success(null);
    }

    public static <T> ApiResponse<T> fail(Integer code, String message) {
        return new ApiResponse<>(code, message, null);
    }
}

业务异常和全局异常模板

java
@Getter
public class BizException extends RuntimeException {
    private final Integer code;

    public BizException(Integer code, String message) {
        super(message);
        this.code = code;
    }
}

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BizException.class)
    public ApiResponse<Void> handleBizException(BizException e) {
        return ApiResponse.fail(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<Void> handleMethodArgumentNotValid(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
            .findFirst()
            .map(FieldError::getDefaultMessage)
            .orElse("参数校验失败");
        return ApiResponse.fail(400, message);
    }

    @ExceptionHandler(Exception.class)
    public ApiResponse<Void> handleException(Exception e) {
        log.error("system error", e);
        return ApiResponse.fail(500, "系统异常");
    }
}

请求对象模板

java
@Data
public class UserCreateRequest {
    @NotBlank(message = "用户编号不能为空")
    private String userNo;

    @NotBlank(message = "用户名不能为空")
    private String userName;

    @Pattern(regexp = "^1\\d{10}$", message = "手机号格式不正确")
    private String mobile;
}

@Data
public class UserQueryRequest extends PageQuery {
    private Long id;
    private String userName;
    private Integer status;
    private LocalDateTime beginTime;
    private LocalDateTime endTime;
}

Controller 模板

java
@Validated
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @GetMapping("/{id}")
    public ApiResponse<UserVO> getById(@PathVariable Long id) {
        return ApiResponse.success(userService.getById(id));
    }

    @GetMapping("/page")
    public ApiResponse<PageResult<UserVO>> page(@Valid UserQueryRequest request) {
        return ApiResponse.success(userService.page(request));
    }

    @PostMapping
    public ApiResponse<Long> create(@RequestBody @Valid UserCreateRequest request) {
        return ApiResponse.success(userService.create(request));
    }

    @PutMapping("/{id}")
    public ApiResponse<Void> update(@PathVariable Long id, @RequestBody @Valid UserCreateRequest request) {
        userService.update(id, request);
        return ApiResponse.success();
    }
}

Service 模板

java
public interface UserService {
    UserVO getById(Long id);

    PageResult<UserVO> page(UserQueryRequest request);

    Long create(UserCreateRequest request);

    void update(Long id, UserCreateRequest request);
}

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserAccountMapper userAccountMapper;

    @Override
    public UserVO getById(Long id) {
        UserAccountDO entity = userAccountMapper.selectById(id);
        if (entity == null) {
            throw new BizException(404, "用户不存在");
        }
        return toVO(entity);
    }

    @Override
    public PageResult<UserVO> page(UserQueryRequest request) {
        UserAccountQuery query = toQuery(request);
        Long total = userAccountMapper.countByQuery(query);
        if (total == null || total == 0) {
            return PageResult.empty();
        }

        List<UserVO> list = userAccountMapper.selectByQuery(query).stream()
            .map(this::toVO)
            .collect(Collectors.toList());
        return PageResult.of(total, list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(UserCreateRequest request) {
        if (userAccountMapper.existsByUserNo(request.getUserNo())) {
            throw new BizException(400, "用户编号已存在");
        }

        UserAccountDO entity = new UserAccountDO();
        entity.setUserNo(request.getUserNo());
        entity.setUserName(request.getUserName());
        entity.setMobile(request.getMobile());
        entity.setStatus(1);
        userAccountMapper.insertSelective(entity);
        return entity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Long id, UserCreateRequest request) {
        UserAccountDO entity = new UserAccountDO();
        entity.setId(id);
        entity.setUserName(request.getUserName());
        entity.setMobile(request.getMobile());

        int rows = userAccountMapper.updateSelective(entity);
        if (rows <= 0) {
            throw new BizException(404, "更新失败,记录不存在");
        }
    }

    private UserVO toVO(UserAccountDO entity) {
        UserVO vo = new UserVO();
        vo.setId(entity.getId());
        vo.setUserNo(entity.getUserNo());
        vo.setUserName(entity.getUserName());
        vo.setMobile(entity.getMobile());
        vo.setStatus(entity.getStatus());
        return vo;
    }

    private UserAccountQuery toQuery(UserQueryRequest request) {
        UserAccountQuery query = new UserAccountQuery();
        BeanUtils.copyProperties(request, query);
        return query;
    }
}

统一日志模板

java
@Slf4j
@Component
public class RequestLogFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(
        HttpServletRequest request,
        HttpServletResponse response,
        FilterChain filterChain
    ) throws ServletException, IOException {
        long start = System.currentTimeMillis();
        try {
            filterChain.doFilter(request, response);
        } finally {
            log.info(
                "method={}, uri={}, status={}, cost={}ms",
                request.getMethod(),
                request.getRequestURI(),
                response.getStatus(),
                System.currentTimeMillis() - start
            );
        }
    }
}

RestTemplate 调用模板

java
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
            .setConnectTimeout(Duration.ofSeconds(2))
            .setReadTimeout(Duration.ofSeconds(5))
            .build();
    }
}

@Service
@RequiredArgsConstructor
public class RemoteUserService {

    private final RestTemplate restTemplate;

    public UserDTO getUser(Long userId) {
        String url = "http://user-service/api/users/{id}";
        return restTemplate.getForObject(url, UserDTO.class, userId);
    }
}
最近更新