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;
}
}
我为genericInvalidInputException
添加了一个新类,如下所示:
@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.");
}
}
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
,我将接受您的答案,而不是我自己的答案,您将获得分数。:)我不能接受任何评论作为回答。:)