错误响应未显示在 Spring Boot 应用程序上

问题描述 投票:0回答:1

我试图运行 Spring Boot 应用程序来添加 Ornament,并且尝试使用 Insomnia 上的 REST API 来测试错误以获得响应,例如将错误的验证(如整数变量中的字符串输入)放在一起,但它无法显示 500 Internal发生服务器错误。我尽了一切努力,但到目前为止还无法解决这个问题。谁能帮我解决这个问题吗?谢谢

package com.example.demo.controller;

import java.util.Random;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.model.Ornament;
import com.example.demo.services.OrnamentService;

import jakarta.validation.Valid;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
public class OrnamentController {
    
    @Autowired
    private OrnamentService ornamentService;

    public OrnamentController(OrnamentService ornamentService) {
        this.ornamentService = ornamentService;
    }
    
    @GetMapping("/listAllOrnaments")
    public Flux<Ornament> listAllOrnaments() {
        
        Flux<Ornament> randomOrnaments = Flux.fromStream(
                new Random()
                        .ints(10) 
                        .mapToObj(i -> generateRandomOrnament())
        );
        return randomOrnaments;
    }
    
    private Ornament generateRandomOrnament() {
        Random random = new Random();
        
        String name = "Ornament " + random.nextInt(1000);
        double priceMin = ornamentService.getRandomPrice();
        double priceMax = priceMin + random.nextDouble() * 100; 
        double priceMedian = (priceMin + priceMax) / 2;
        
        return new Ornament(name, 0, 0, priceMin, priceMax, priceMedian, "");
    }

    @PostMapping("/addOrnament")
    public Mono<ResponseEntity<String>> addOrnament(@Valid @RequestBody Ornament ornament, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String errorMessage = bindingResult.getFieldErrors().stream()
                    .map(error -> {
                        String fieldName = error.getField();
                        String errorMsg = error.getDefaultMessage(); 
                        if (fieldName.equals("price") && errorMsg.contains("NumberFormatException")) {
                            return "Price should be a number.";
                        }
                        return "Validation error: Field '" + fieldName + "' " + errorMsg;
                    })
                    .collect(Collectors.joining(", "));
            return Mono.just(ResponseEntity.badRequest().body("Validation error: " + errorMessage));
        }
        
        return ornamentService.addOrnament(ornament)
                .thenReturn(ResponseEntity.ok("Ornament added successfully"))
                .onErrorResume(ex -> Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage())));
    }
    
    @GetMapping("/error")
    public ResponseEntity<String> handleErrors() {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred.");
    }
}

装饰控制器

package com.example.demo.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(S3ServiceException.class)
    public ResponseEntity<String> handleS3ServiceException(S3ServiceException ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
    }
    
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<String> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
        String errorMessage;
        switch (ex.getName()) {
            case "weight":
            case "diamondCarat":
            case "priceMin":
            case "priceMax":
            case "priceMedian":
                errorMessage = "Validation error: Field '" + ex.getName() + "' should be a number.";
                break;
            default:
                errorMessage = "Validation error: Field '" + ex.getName() + "' has invalid type.";
        }
        return ResponseEntity.badRequest().body(errorMessage);
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal server error occurred.");
    }
}

全局异常处理程序

package com.example.demo.model;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import reactor.core.publisher.Mono;

@Data
public class Ornament {
    
    @NotNull
    private String name;
    @Min(0)
    private double weight;
    @Min(0)
    private double diamondCarat;
    @Min(0)
    private double priceMin;
    @Max(10)
    private double priceMax;
    @Min(0)
    private double priceMedian;
    private String currency;
    
    public Ornament(String name, double weight, double diamondCarat, double priceMin, double priceMax, double priceMedian, String currency) {
        this.name = name;
        this.weight = weight;
        this.diamondCarat = diamondCarat;
        this.priceMin = priceMin;
        this.priceMax = priceMax;
        this.priceMedian = priceMedian;
        this.currency = currency;
    }
    
    public Mono<Ornament> toMono() {
        return Mono.just(this);
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public double getWeight() {
        return weight;
    }
    
    public void setWeight(double weight) {
        this.weight = weight;
    }
    
    public double getDiamondCarat() {
        return diamondCarat;
    }
    
    public void setDiamondCarat(double diamondCarat) {
        this.diamondCarat = diamondCarat;
    }
    
    public double getPriceMin() {
        return priceMin;
    }
    
    public void setPriceMin(double priceMin) {
        this.priceMin = priceMin;
    }
    
    public double getPriceMax() {
        return priceMax;
    }
    
    public void setPriceMax(double priceMax) {
        this.priceMax = priceMax;
    }
    
    public double getPriceMedian() {
        return priceMedian;
    }
    
    public void setPriceMedian(double priceMedian) {
        this.priceMedian = priceMedian;
    }
    
    public String getCurrency() {
        return currency;
    }
    
    public void setCurrency(String currency) {
        this.currency = currency;
    }
}

装饰品

package com.example.demo.services;

import java.util.Random;

import org.springframework.stereotype.Service;

import com.example.demo.model.Ornament;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
public class OrnamentService {
    
    private final Random random = new Random();
    
    public Flux<Ornament> listAllOrnaments() {
        
        return Flux.just(new Ornament("Ornament 1", 0, 0, 0, 0, 0, ""),
                new Ornament("Ornament 2", 0, 0, 0, 0, 0, ""),
                new Ornament("Ornament 3", 0, 0, 0, 0, 0, ""));
    }

    public Mono<Ornament> addOrnament(Ornament ornament) {
        
        return Mono.just(ornament);
    }
    
    public double getRandomPrice() {
        
        return 1 + (100 - 1) * random.nextDouble();
    }
}

饰品服务

{
    "name": "Ornament 100",
    "weight": "twenty",
    "diamondCarat": 10,
    "priceMin": 20,
    "priceMax": 10,
    "priceMedian": 20,
    "currency": null
}

REST API JSON 测试

java spring-boot rest java-17 jakarta-validation
1个回答
0
投票

如果您打算从您的

@ControllerAdvice
转发验证错误,请尝试 覆盖下面共享的
handleMethodArgumentNotValid
的实现。自过去以来,当我们尝试类似的事情时,这对我们来说一直有效:

@Override // instead of  @ExceptionHandler(MethodArgumentNotValidException.class), to avoid ambiguity from parent
protected ResponseEntity<Object> handleMethodArgumentNotValid(
        MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
    String errorMessage;
    switch (ex.getName()) {
        case "weight":
        case "diamondCarat":
        case "priceMin":
        case "priceMax":
        case "priceMedian":
            errorMessage = "Validation error: Field '" + ex.getName() + "' should be a number.";
            break;
        default:
            errorMessage = "Validation error: Field '" + ex.getName() + "' has invalid type.";
    }
    return ResponseEntity.badRequest().body(errorMessage);
}
© www.soinside.com 2019 - 2024. All rights reserved.