SpringBoot DTO验证

时间:2020-05-17 03:47:01

标签: java spring hibernate spring-boot

我是spring-boot的新手,我正尝试将验证添加到我的DTO类中,如下所示。

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;

}

下面是我用来保存员工的REST端点。

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

    }

我创建如下的Validation类来验证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;

    }
}

预期输出为

{ “ firstName”:“需要雇员的名字”, “ employeeNum”:“ EmployeeNUM是必需的” }

但是当我通过邮递员到达终点时,我只收到400错误的请求。 我的代码有什么问题?如上所述,如何解决并获得预期的输出?

3 个答案:

答案 0 :(得分:1)

尝试像这样扩展ResponseEntityExceptionHandler类:


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

答案 1 :(得分:0)

我使用了下面的类,现在它可以正常工作。

{% extends 'app.html' %}

{% block body %}
    <div>
        <div class="alert alert-info">Transaction / Returning</div>

        <table id="table" class="table table-stripped">
            <thead class="alert-success">
            <tr>
                <th>Student Name</th>
                <th>Book Title</th>
                <th>Book Author</th>
                <th>Status</th>
                <th>Date Returned</th>
                <th>Action</th>
            </tr>
            </thead>
            <tbody>
            {% for borrow in borrows %}
                <tr>
                    <td>{{ borrow.student.all.0.firstname }} {{ borrow.student.all.0.lastname }}</td>
                    <td>{{ borrow.book.all.0.title }}</td>
                    <td>{{ borrow.book.all.0.author }}</td>
                    <td>{{ borrow.status }}</td>
                    <td>{{ borrow.date | date }}</td>
                    <td>
                        {% if borrow.status == "Returned" %}
                            <button disabled="disabled" class="btn btn-primary" type="button" href="#">
                                <span class="glyphicon glyphicon-check"></span> Returned
                            </button>
                        {% else %}
                            <form method="POST" action="">
                                {% csrf_token %}
                                <input type="hidden" name="borrow_id" value="{{ borrow.id }}"/>
                                <button class="btn btn-danger">
                                    <span class="glyphicon glyphicon-unchecked"></span> Return
                                </button>
                            </form>
                        {% endif %}
                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
{% endblock %}

在COntroller中

@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;

    }

}

答案 2 :(得分:0)

@Ehab Qadah的复制答案。

仅修改是在字符串映射而不是字符串映射中提供带有错误原因的错误字段

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