关于来自 REST 应用程序的异常的漂亮消息

Pretty message on exceptions from REST app

我的 REST 应用程序有问题。下面是gitlink减轻你的负担:https://github.com/TheNiceGuy123/AstonishingBackEnd

这里也是原始代码:

类 发布顺序:

员工控制器:

package com.example.csmartbackend.controller;

import com.example.csmartbackend.model.Employee;
import com.example.csmartbackend.modeldto.EmployeeDto;
import com.example.csmartbackend.service.EmployeeService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("employee")
@RequiredArgsConstructor
public class EmployeeController
{
    private final EmployeeService employeeService;

    @GetMapping("find/{Cnp}")
    public ResponseEntity<Employee> findByCNP(@PathVariable("Cnp") String Cnp)
    {
        Employee employee = employeeService.findByCnp(Cnp);
        HttpHeaders header = new HttpHeaders();
        header.add("Desc","Getting employee by id.");
        return ResponseEntity.status(HttpStatus.OK).headers(header).body(employee);
    }
}

员工服务:

package com.example.csmartbackend.service;

import com.example.csmartbackend.mapper.EmployeeMapper;
import com.example.csmartbackend.model.Employee;
import com.example.csmartbackend.modeldto.EmployeeDto;
import com.example.csmartbackend.repository.EmployeeRepository;
import exception.general.TargetNotFoundException;
import exception.requestsexceptions.CNPNotFoundException;
import exception.requestsexceptions.EmployeeNotFoundException;
import exception.requestsexceptions.InvalidIdException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
@RequiredArgsConstructor
@Transactional
public class EmployeeService implements EmployeeServiceImpl
{
    private final EmployeeRepository employeeRepository;
    private final ContractService contractService;
    private final AdressService adressService;

    public Employee findByCnp(String Cnp) throws CNPNotFoundException
    {
        Optional<Employee> employeeOptional = Optional.ofNullable(employeeRepository.findByCnp(Cnp));
        if(employeeOptional.isPresent())
            return employeeOptional.get();
        else
            throw new CNPNotFoundException("No employee found.");
    }
}

全局异常处理程序:

package exception.requestsexceptions;

import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
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 java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler
{
    @Override
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported
            (HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Request method not supported.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now());
        return ResponseEntity.status(status).body(apiErrorModel);
    }

    @Override
    protected ResponseEntity<Object> handleHttpMediaTypeNotSupported
            (HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Media method not supported.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now());
        return ResponseEntity.status(status).body(apiErrorModel);
    }

    @Override
    protected ResponseEntity<Object> handleMissingPathVariable
            (MissingPathVariableException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Path variable is missing.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now());
        return ResponseEntity.status(status).body(apiErrorModel);
    }

    @Override
    protected ResponseEntity<Object> handleMissingServletRequestParameter
            (MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Request parameter is missing.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now());
        return ResponseEntity.status(status).body(apiErrorModel);
    }

    @Override
    protected ResponseEntity<Object> handleTypeMismatch
            (TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Mismatch of type.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now());
        return ResponseEntity.status(status).body(apiErrorModel);
    }

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable
            (HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Request body is not readable.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, status, LocalDateTime.now());
        return ResponseEntity.status(status).body(apiErrorModel);
    }

    @ExceptionHandler(EmployeeNotFoundException.class)
    public ResponseEntity<Object> handleEmployeeNotFoundException(EmployeeNotFoundException ex)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Employee not found.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, HttpStatus.BAD_REQUEST, LocalDateTime.now());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(apiErrorModel);
    }

    @ExceptionHandler(CNPNotFoundException.class)
    public ResponseEntity<Object> handleInvalidCNPException(CNPNotFoundException ex)
    {
        String message = ex.getMessage();
        List<String> details = new ArrayList<>();
        details.add("Employee with the given CNP not found.");
        ApiErrorModel apiErrorModel = new ApiErrorModel(message, details, HttpStatus.NOT_FOUND, LocalDateTime.now());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(apiErrorModel);
    }
}

CNPNotFoundException class:

package exception.requestsexceptions;

public class CNPNotFoundException extends RuntimeException
{
    public CNPNotFoundException(String message) { super(message); }
}

ApiErrorModel class:

package exception.requestsexceptions;

import lombok.*;
import org.springframework.http.HttpStatus;

import java.time.LocalDateTime;
import java.util.List;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ApiErrorModel
{
    String message;
    List<String> details;
    HttpStatus status;
    LocalDateTime timestamp;
}

我想像第二张图片中那样向用户提供一些相关信息,但在邮递员中,一切都保持在默认级别以这样调用它,就像我的处理程序代码甚至不存在一样。我是否遗漏了任何逻辑或注释?

This is how it looks on my side

This is how it should look like

感谢您的宝贵时间!

问题是当 class 被注释为 @SpringBootApplication 而没有任何属性时 SpringBoot 仅扫描 class 本身所在的包及其子包。

在您的情况下,这意味着 Spring当您将 GlobalExceptionHandler class 放入 [=13] 时,引导仅查找 com.example.csmartbackend 包下的任何 Spring 组件=]s包。

要修复它,您有两种选择:

  • exception 包放在 com.example.csmartbackend 下,所以它将是 com.example.csmartbackend.exception.requestsexception.GlobalExceptionHandler
  • 告诉 spring 也扫描 exception 包,使用 scanBasePackageClassesscanBasePackages 属性,例如 @SpringBootApplication(scanBasePackageClasses = {CSmartBackEndApplication.class, GlobalExceptionHandler.class})