diff --git a/pom.xml b/pom.xml index 9a2fe89..e958e78 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,12 @@ test + + + org.springframework.boot + spring-boot-starter-validation + + org.springframework.boot diff --git a/src/main/java/com/example/demo/controller/UserController.java b/src/main/java/com/example/demo/controller/UserController.java index e8c773f..0434835 100644 --- a/src/main/java/com/example/demo/controller/UserController.java +++ b/src/main/java/com/example/demo/controller/UserController.java @@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; import java.util.List; @RestController @@ -28,12 +29,12 @@ public class UserController { } @PostMapping - public User create(@RequestBody User user) { + public User create(@Valid @RequestBody User user) { return userService.save(user); } @PutMapping("/{id}") - public ResponseEntity update(@PathVariable Long id, @RequestBody User user) { + public ResponseEntity update(@PathVariable Long id, @Valid @RequestBody User user) { return userService.findById(id) .map(existing -> { existing.setName(user.getName()); diff --git a/src/main/java/com/example/demo/entity/User.java b/src/main/java/com/example/demo/entity/User.java index e66dcca..35b66bb 100644 --- a/src/main/java/com/example/demo/entity/User.java +++ b/src/main/java/com/example/demo/entity/User.java @@ -1,6 +1,9 @@ package com.example.demo.entity; import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; @Entity @Table(name = "t_user") @@ -10,12 +13,16 @@ public class User { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotBlank(message = "姓名不能为空") @Column(nullable = false) private String name; + @NotBlank(message = "邮箱不能为空") + @Email(message = "邮箱格式不正确") @Column(nullable = false) private String email; + @Min(value = 0, message = "年龄不能小于0") private Integer age; public User() { diff --git a/src/main/java/com/example/demo/exception/BusinessException.java b/src/main/java/com/example/demo/exception/BusinessException.java new file mode 100644 index 0000000..8a97cee --- /dev/null +++ b/src/main/java/com/example/demo/exception/BusinessException.java @@ -0,0 +1,22 @@ +package com.example.demo.exception; + +/** + * 业务异常 + */ +public class BusinessException extends RuntimeException { + + private final int code; + + public BusinessException(int code, String message) { + super(message); + this.code = code; + } + + public BusinessException(String message) { + this(400, message); + } + + public int getCode() { + return code; + } +} diff --git a/src/main/java/com/example/demo/exception/GlobalExceptionHandler.java b/src/main/java/com/example/demo/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..2166e54 --- /dev/null +++ b/src/main/java/com/example/demo/exception/GlobalExceptionHandler.java @@ -0,0 +1,60 @@ +package com.example.demo.exception; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDateTime; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + /** + * 处理参数校验失败 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidation(MethodArgumentNotValidException ex) { + String message = ex.getBindingResult().getFieldErrors().stream() + .map(FieldError::getDefaultMessage) + .collect(Collectors.joining("; ")); + return buildResponse(HttpStatus.BAD_REQUEST, message); + } + + /** + * 处理业务异常 + */ + @ExceptionHandler(BusinessException.class) + public ResponseEntity> handleBusiness(BusinessException ex) { + log.warn("业务异常: code={}, message={}", ex.getCode(), ex.getMessage()); + return buildResponse(HttpStatus.valueOf(ex.getCode()), ex.getMessage()); + } + + /** + * 处理其他未捕获异常 + */ + @ExceptionHandler(Exception.class) + public ResponseEntity> handleException(Exception ex, HttpServletRequest request) { + log.error("请求 {} {} 发生异常", request.getMethod(), request.getRequestURI(), ex); + return buildResponse(HttpStatus.INTERNAL_SERVER_ERROR, "服务器内部错误"); + } + + private ResponseEntity> buildResponse(HttpStatus status, String message) { + Map body = new LinkedHashMap<>(); + body.put("timestamp", LocalDateTime.now().toString()); + body.put("status", status.value()); + body.put("error", status.getReasonPhrase()); + body.put("message", message); + return ResponseEntity.status(status).body(body); + } +}