简体   繁体   English

SpringBoot DTO 验证

[英]SpringBoot DTO Validation

I am new to spring-boot I'm trying to add validation to my DTO class like below.我是 spring-boot 的新手,我正在尝试向我的 DTO class 添加验证,如下所示。

import javax.validation.constraints.NotBlank;

@Getter
@Setter
public class EmployeeDto {
    private Long id;

    @NotBlank(message = "Employee first name is required")
    private String firstName;

    private String lastName;

    @NotBlank(message = "EmployeeNUM  is required")
    private String employeeNum;

}

Below is my REST endpoint to save employee.下面是我的 REST 端点来保存员工。

import javax.validation.Valid;
 @PostMapping("/employee")
    public ResponseEntity<?> addEmployee(@Valid @RequestBody EmployeeDto employeeDto) throws ClassNotFoundException {
        return   ResponseEntity.ok(employeeService.saveEmployee(deptId,employeeDto));

    }

I create a Validation class like below to validate the DTO fields.我创建了一个如下所示的验证 class 来验证 DTO 字段。

@ControllerAdvice
@RestController
public class Validation {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, String> handleValidationExceptions(
            MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        return errors;

    }
}

expected output is预计 output 是

{ "firstName":"Employee first name is required", "employeeNum":"EmployeeNUM is required" } { "firstName":"员工名字是必填项", "employeeNum":"EmployeeNUM 是必填项" }

But I'm getting only the 400 bad request when hit the endpoint through postman.但是当通过 postman 到达端点时,我只收到 400 错误请求。 What is the issue with my code?我的代码有什么问题? How to fix and get the expected output as mentioned above?如上所述,如何修复并获得预期的 output?

Try to extend the ResponseEntityExceptionHandler class like this:尝试像这样扩展ResponseEntityExceptionHandler class:


import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.validation.ConstraintViolationException;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * * Handle all exceptions and java bean validation errors for all endpoints income data that use the @Valid annotation
 *
 * @author Ehab Qadah
 */
@ControllerAdvice
public class GeneralExceptionHandler extends ResponseEntityExceptionHandler {


    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception, HttpHeaders headers,
                                                                  HttpStatus status, WebRequest request) {
        List<String> validationErrors = exception.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.toList());
        return getExceptionResponseEntity(HttpStatus.BAD_REQUEST, request, validationErrors);
    }


    @ExceptionHandler({ConstraintViolationException.class})
    public ResponseEntity<Object> handleConstraintViolation(
            ConstraintViolationException exception, WebRequest request) {
        List<String> validationErrors = exception.getConstraintViolations().stream().
                map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
                .collect(Collectors.toList());
        return getExceptionResponseEntity(HttpStatus.BAD_REQUEST, request, validationErrors);
    }

    private ResponseEntity<Object> getExceptionResponseEntity(final HttpStatus status, WebRequest request, List<String> errors) {
        final Map<String, Object> body = new LinkedHashMap<>();
        final String errorsMessage = CollectionUtils.isNotEmpty(errors) ? errors.stream().filter(StringUtils::isNotEmpty).collect(Collectors.joining(",")):status.getReasonPhrase();
        final String path = request.getDescription(false);
        body.put("TIMESTAMP", Instant.now());
        body.put("STATUS", status.value());
        body.put("ERRORS", errorsMessage);
        body.put("PATH", path);
        body.put("MESSAGE", status.getReasonPhrase());
        return new ResponseEntity<>(body, status);
    }
}

Copied answer of @Ehab Qadah. @Ehab Qadah 的复制答案。

Only modification is giving error fields with reason in a map of string, instead of a string唯一的修改是在字符串的 map 中给出错误字段,而不是字符串

    @ExceptionHandler({ConstraintViolationException.class})
public ResponseEntity<Object> handleConstraintViolation(
        ConstraintViolationException exception, WebRequest request) {
        
    Map<String, String> fieldErrors = ex.getConstraintViolations().stream()
            .collect(Collectors.toMap(cv -> cv.getPropertyPath().toString(), ConstraintViolation::getMessage));
        
    return getExceptionResponseEntity(HttpStatus.BAD_REQUEST, request, fieldErrors);
}

private ResponseEntity<Object> getExceptionResponseEntity(final HttpStatus status, WebRequest request, List<String> errors) {
    final Map<String, Object> body = new LinkedHashMap<>();
    final String errorsMessage = CollectionUtils.isNotEmpty(errors) ? errors.stream().filter(StringUtils::isNotEmpty).collect(Collectors.joining(",")):status.getReasonPhrase();
    final String path = request.getDescription(false);
    body.put("TIMESTAMP", Instant.now());
    body.put("STATUS", status.value());
    body.put("ERRORS", errorsMessage);
    body.put("PATH", path);
    body.put("MESSAGE", status.getReasonPhrase());
    return new ResponseEntity<>(body, status);
}   

I used the below class and now it's working correctly.我使用了下面的 class 现在它工作正常。

@Service
public class MapValidationErrorService {
    public ResponseEntity<?> MapValidationService(BindingResult result){

        if(result.hasErrors()){
            Map<String, String> errorMap = new HashMap<>();

            for(FieldError error: result.getFieldErrors()){
                errorMap.put(error.getField(), error.getDefaultMessage());
            }
            return new ResponseEntity<Map<String, String>>(errorMap, HttpStatus.BAD_REQUEST);
        }

        return null;

    }

}

In COntroller在 COntroller

 @Autowired
    private MapValidationErrorService mapValidationErrorService;

    @PostMapping("/employee/{deptId}")
    public ResponseEntity<?> addEmployee(@PathVariable(name = "deptId") String deptId,@Valid @RequestBody EmployeeDto employeeDto, BindingResult result) throws ClassNotFoundException {
        ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
        if(errorMap != null)return errorMap;
        return   ResponseEntity.ok(employeeService.saveEmployee(deptId,employeeDto));

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM