Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SpringWebFlux:如果抛出此异常,如何在网页上显示来自自定义异常类的消息?_Java_Spring Boot_Web_Exception_Spring Webflux - Fatal编程技术网

Java SpringWebFlux:如果抛出此异常,如何在网页上显示来自自定义异常类的消息?

Java SpringWebFlux:如果抛出此异常,如何在网页上显示来自自定义异常类的消息?,java,spring-boot,web,exception,spring-webflux,Java,Spring Boot,Web,Exception,Spring Webflux,这是我的模型类的片段,Student: @Table public class Student { @Id private Long id; private String name; private String surname; private Integer age; public Student(String name, String surname, Integer age) { validateInput(na

这是我的模型类的片段,
Student

@Table
public class Student {

    @Id
    private Long id;

    private String name;

    private String surname;

    private Integer age;

    public Student(String name, String surname, Integer age) {

        validateInput(name, surname, age);

        this.name = name;
        this.surname = surname;
        this.age = age;
    }

    private void validateInput(String name, String surname, Integer age) {

        if (name == null || name.isBlank()) throw new InvalidNewStudentNameException(name);

        if (surname == null || surname.isBlank()) throw new InvalidNewStudentSurnameException(surname);

        if (age == null || age < 16) throw new InvalidNewStudentAgeException(age);
    }
}
StudentController
中添加新学生的我的端点:

@GetMapping("/add")
@ResponseBody
public Mono<Long> add(@RequestParam String name, @RequestParam String surname, @RequestParam Integer age) {

    return studentService.add(name, surname, age).map(student -> student.getId());
} 
@ResponseStatus(
  value = HttpStatus.UNPROCESSABLE_ENTITY,
  reason = "Invalid input data for new student.")
@ExceptionHandler(InvalidInputException.class)
public ResponseEntity invalidInputHandler(InvalidInputException e) {
    return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
}
我运行应用程序并尝试通过以下方式添加无效学生(年龄小于16岁的学生):

http://localhost:8080/add/?name=SomeName&surname=SomeSurname&age=14

我确实会抛出自定义异常,但是,该消息仅在我的IDE堆栈跟踪中可见,而在浏览器中不可见。应用程序终止,如果我访问http://localhost:8080/,我会得到带有内部服务器错误(500)的白标签错误页面,或者如果我将
Server.Error.Whitelabel.enabled=false
添加到我的application.properties,则只会得到没有该页面的错误

我尝试了各种方法来处理此异常,以便为用户(浏览器)获取自定义错误消息,但到目前为止没有成功

请帮助我找到一种合适的方法来捕获控制器中的自定义异常,并以这样的方式处理它:它将在客户端浏览器中显示一条关于无效数据的消息

即使是禁用白标签页面和在
src\main\resources\templates
project目录中添加error.html文件这一肮脏且明显错误的解决方法,由于某些原因也不起作用

这是我尝试的一种方法。我更改了我的
StudentController
add()
方法,如下所示:

@GetMapping("/add")
@ResponseBody
public Mono<Long> add(@RequestParam String name, @RequestParam String surname, @RequestParam Integer age) {
    try {
        return studentService.add(name, surname, age).map(student -> student.getId());
    }
    catch (InvalidNewStudentAgeException invNewStudAgeEx) {
        return Mono.error(invNewStudAgeEx);
    }
    catch (InvalidNewStudentNameException invNewStudNameEx) {
        return Mono.error(invNewStudNameEx);
    }
    catch (InvalidNewStudentSurnameException invNewStudSurnameEx) {
        return Mono.error(invNewStudSurnameEx);
    }
}
 @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's age: age should not be empty or less than 16.")
    @ExceptionHandler(InvalidNewStudentAgeException.class)
    public void invalidNewStudentAgeHandler() {

    }

    @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's name: the name should not be empty.")
    @ExceptionHandler(InvalidNewStudentNameException.class)
    public void invalidNewStudentNameHandler() {

    }

    @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's surname: the surname should not be empty.")
    @ExceptionHandler(InvalidNewStudentSurnameException.class)
    public void invalidNewStudentSurnameHandler() {

    }
@GetMapping("/add")
@ResponseBody
public Mono<Long> add(@RequestParam String name, @RequestParam String surname, @RequestParam Integer age) {
    try {
        return studentService.add(name, surname, age).map(student -> student.getId());
    }
    catch (InvalidInputException invalidInputException) {
        return Mono.error(invalidInputException);
    }
}
public class InvalidInputException extends RuntimeException {

    protected HttpStatus httpStatus;

    public InvalidInputException(HttpStatus httpStatus, String message) {

        super(message);

        this.httpStatus = httpStatus;
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }
}

我发现,如果我为无效年龄处理程序更改
HttpStatus
的枚举,然后尝试添加未成年学生,它会根据枚举返回不同的响应代码。因此,它确实捕获了处理程序中的异常,但是我如何获得比500或404这样的数字更多的数据呢?我是否可以让浏览器显示“Invadin student's age…”,而不是只显示
HTTP ERROR 509

由于这个问题,我找到了解决方案:

来自
StudentController
的我的端点的最终
add()
方法如下所示:

@GetMapping("/add")
@ResponseBody
public Mono<Long> add(@RequestParam String name, @RequestParam String surname, @RequestParam Integer age) {
    try {
        return studentService.add(name, surname, age).map(student -> student.getId());
    }
    catch (InvalidNewStudentAgeException invNewStudAgeEx) {
        return Mono.error(invNewStudAgeEx);
    }
    catch (InvalidNewStudentNameException invNewStudNameEx) {
        return Mono.error(invNewStudNameEx);
    }
    catch (InvalidNewStudentSurnameException invNewStudSurnameEx) {
        return Mono.error(invNewStudSurnameEx);
    }
}
 @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's age: age should not be empty or less than 16.")
    @ExceptionHandler(InvalidNewStudentAgeException.class)
    public void invalidNewStudentAgeHandler() {

    }

    @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's name: the name should not be empty.")
    @ExceptionHandler(InvalidNewStudentNameException.class)
    public void invalidNewStudentNameHandler() {

    }

    @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's surname: the surname should not be empty.")
    @ExceptionHandler(InvalidNewStudentSurnameException.class)
    public void invalidNewStudentSurnameHandler() {

    }
@GetMapping("/add")
@ResponseBody
public Mono<Long> add(@RequestParam String name, @RequestParam String surname, @RequestParam Integer age) {
    try {
        return studentService.add(name, surname, age).map(student -> student.getId());
    }
    catch (InvalidInputException invalidInputException) {
        return Mono.error(invalidInputException);
    }
}
public class InvalidInputException extends RuntimeException {

    protected HttpStatus httpStatus;

    public InvalidInputException(HttpStatus httpStatus, String message) {

        super(message);

        this.httpStatus = httpStatus;
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }
}
我为generic
InvalidInputException
添加了一个新类,如下所示:

@GetMapping("/add")
@ResponseBody
public Mono<Long> add(@RequestParam String name, @RequestParam String surname, @RequestParam Integer age) {
    try {
        return studentService.add(name, surname, age).map(student -> student.getId());
    }
    catch (InvalidNewStudentAgeException invNewStudAgeEx) {
        return Mono.error(invNewStudAgeEx);
    }
    catch (InvalidNewStudentNameException invNewStudNameEx) {
        return Mono.error(invNewStudNameEx);
    }
    catch (InvalidNewStudentSurnameException invNewStudSurnameEx) {
        return Mono.error(invNewStudSurnameEx);
    }
}
 @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's age: age should not be empty or less than 16.")
    @ExceptionHandler(InvalidNewStudentAgeException.class)
    public void invalidNewStudentAgeHandler() {

    }

    @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's name: the name should not be empty.")
    @ExceptionHandler(InvalidNewStudentNameException.class)
    public void invalidNewStudentNameHandler() {

    }

    @ResponseStatus(
      value = HttpStatus.BAD_REQUEST,
      reason = "Invalid student's surname: the surname should not be empty.")
    @ExceptionHandler(InvalidNewStudentSurnameException.class)
    public void invalidNewStudentSurnameHandler() {

    }
@GetMapping("/add")
@ResponseBody
public Mono<Long> add(@RequestParam String name, @RequestParam String surname, @RequestParam Integer age) {
    try {
        return studentService.add(name, surname, age).map(student -> student.getId());
    }
    catch (InvalidInputException invalidInputException) {
        return Mono.error(invalidInputException);
    }
}
public class InvalidInputException extends RuntimeException {

    protected HttpStatus httpStatus;

    public InvalidInputException(HttpStatus httpStatus, String message) {

        super(message);

        this.httpStatus = httpStatus;
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }
}
每个无效输入对应一个特定类。下面是这样一个类的示例,
InvalidNewStudentAgeException

public class InvalidNewStudentAgeException extends InvalidInputException {

    public InvalidNewStudentAgeException(HttpStatus httpStatus, Integer age) {
        super(httpStatus, "Could not create a student: student's age, " + age + ", should not be empty or less than 16.");
    }
}
除特定异常构造函数的签名外,其他所有内容都保持不变。异常仍然像以前一样通过调用的私有方法在
Student
类的构造函数中抛出:

public Student(String name, String surname, Integer age) {

    validateInput(name, surname, age);

    this.name = name;
    this.surname = surname;
    this.age = age;
}

private void validateInput(String name, String surname, Integer age) {

    if (name == null || name.isBlank()) throw new InvalidNewStudentNameException(HttpStatus.UNPROCESSABLE_ENTITY, name);

    if (surname == null || surname.isBlank()) throw new InvalidNewStudentSurnameException(HttpStatus.UNPROCESSABLE_ENTITY, surname);

    if (age == null || age < 16) throw new InvalidNewStudentAgeException(HttpStatus.UNPROCESSABLE_ENTITY, age);
}
公立学生(字符串名称、字符串姓氏、整数年龄){
验证输入(姓名、姓氏、年龄);
this.name=名称;
this.姓氏=姓氏;
这个。年龄=年龄;
}
私有void validateInput(字符串名称、字符串姓氏、整数年龄){
if(name==null | | name.isBlank())抛出新的InvalidNewStudentNameException(HttpStatus.UNPROCESSABLE_ENTITY,name);
if(姓氏==null | |姓氏.isBlank())抛出新的InvalidNewStudentNameException(HttpStatus.UNPROCESSABLE_实体,姓氏);
如果(age==null | | age<16)抛出新的InvalidNewStudentAgeException(HttpStatus.UNPROCESSABLE_实体,age);
}
现在一切正常。流程如下:

public class InvalidNewStudentAgeException extends RuntimeException {

    public InvalidNewStudentAgeException(Integer age) {

        super("Could not create a student: student's age, " + age + ", should not be empty or less than 16.");
    }
}
  • 运行应用程序
  • 通过链接添加“无效”学生:http://localhost:8080/add/?name=TestName&surname=TestSurname&age=14
  • 之后,转到localhost:8080并查看来自自定义异常构造函数的纯文本消息
    client.execute
    感觉就像一个阻塞调用。它应该返回一个
    Mono.error
    ,如果出现问题,不会抛出异常。您使用的是什么数据库驱动程序。@ThomasAndolf非常感谢您的反馈!!!虽然这段代码肯定不是没有设计/实现缺陷,但它是可以接受的,并且可以在浏览器中工作。这是我的测试任务。我是春天的新手,网络和网络流量,用谷歌做一切。我需要做的最后一件事就是在浏览器中显示错误消息。如果您能以任何可能的方式提供帮助,我将不胜感激。我编辑了我的问题。我在那里使用了
    Mono.error
    。我使用r2dbc和内存中的H2数据库:
    spring.r2dbc.url=r2dbc:H2:mem:///studentlist;DB_CLOSE_DELAY=-1
    @thomasandelf似乎我找到了解决方案!现在我正在进行最后的重构,然后用解决方案回答我自己的问题。:)在webflux中,我们通常不使用
    try/catch
    。因为当抛出异常时,我们会自动断开反应链,这可能会导致糟糕的性能。相反,我们返回
    Mono.error
    return studentService.add(…)
    不应引发异常,而应在出现错误时,在出错时返回
    Mono.error
    。@ThomasAndolf感谢您的反馈!从积极的方面来看,Java实习生职位的测试任务代码被认为是可以接受的。此测试任务是我第一次面对反应式编程。:)很明显,我是个笨蛋,我的解决方案很糟糕,这并不奇怪。如果您可以详细说明您的评论并发布一个答案,说明我如何在浏览器中获得相同的错误消息,而不在
    add()
    中抛出异常,并使用
    try/catch
    ,我将接受您的答案,而不是我自己的答案,您将获得分数。:)我不能接受任何评论作为回答。:)