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);
}
}