Spring - 通过异常处理程序拦截来自另一个 bean 的响应
Spring - Intercept response from another bean by exception handler
我有两个 @RestController
-(A 和 B)并注册了 ResponseEntityExceptionHandler
。是否有可能(以及如何做)从 A
调用并在应用异常处理程序后从 B
获得响应?
示例:
- 用户休息电话
A
A
用 getPerson
调用 B
B
抛出异常 NotFound
NotFound
由异常处理程序处理,转换 ResponseEntity
并放入 400 status
B
终于 return 异常 ResponseEntity
A
从 B
获得 400 状态
A
可以获得这个 400 并用它做点什么
简单 @Autowired
不起作用。
片段:
答:
@RestController
@RequestMapping("/v1")
public class A {
private final B b;
@Autowired
public A(B b) {
this.b = b;
}
@PostMapping(
value = "persons",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<List<StatusResponse<Person>>> addPersons(final List<Person> persons) {
final List<StatusResponse<Person>> multiResponse = new ArrayList<>();
for(final Person p: persons) {
final ResponseEntity<Person> response = b.addPerson(person);
multiResponse.add(new StatusResponse<>(
response.getStatusCode(), response.getMessage(), response.getBody()
));
}
return ResponseEntity.status(HttpStatus.MULTI_STATUS).body(multiResponse);
}
}
乙:
@RestController
@RequestMapping("/v1")
public class B {
@PostMapping(
value = "person",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<Person> addPerson(final Person person) {
accessService.checkAccess();
return ResponseEntity.status(201).body(
logicService.addPerson(person)
);
}
}
处理程序
@ControllerAdvice
public final class MyExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(MyException.class)
protected ResponseEntity<Object> handleApiException(final MyException exception, final WebRequest webRequest) {
//logic
return afterLogic;
}
}
forward 类似于重定向,但完全发生在服务器端; Servlet 容器将相同的请求转发到目标 URL; URL 在浏览器中不会改变。
在 spring 你可以这样做,你可以传递属性 :
@Controller
@RequestMapping("/")
public class YourController {
@GetMapping("/forward")
public ModelAndView redirectWithUsingForwardPrefix(ModelMap model) {
model.addAttribute("attribute", "forward");
return new ModelAndView("forward:/redirectedUrl", model);
}
}
无法将控制权从处理完其方法后调用的异常处理程序返回给控制器。您当前的流程如下所示call A.addPersons
-> invoke B.addPerson
-> B throws exception
-> exception is propagate to A controller
并在处理控制器方法(不是状态为 400 的 ResponseEntity)后保存为 dispatchException 以在 DispatcherServlet 中进一步处理 -> 使用 MyExceptionHandler 处理异常。从这个地方你不能回到控制器。
我不确定你想用控制器中的这个异常做什么,但解决方案可能如下所示:
@RestController
@RequestMapping("/resources")
public class AController {
private BService service;
@Autowired
public AController(BService service) {
this.service = service;
}
@RequestMapping("/test")
public ResponseEntity<String> test() {
ResponseEntity<String> result = service.test();
if (result.hasBody()) {
//doSomething
}
return result; //or list like you did
}
}
@Service
public class BService {
public ResponseEntity<String> test() {
try {
return ResponseEntity.status(201).body(getResponse()); //this always throws exception. It's just for purpose of example
} catch (CustomException ex) {
return ResponseEntity.status(400).build();
}
}
private String getResponse() {
throw new CustomException("Not OK!");
}
}
我有两个 @RestController
-(A 和 B)并注册了 ResponseEntityExceptionHandler
。是否有可能(以及如何做)从 A
调用并在应用异常处理程序后从 B
获得响应?
示例:
- 用户休息电话
A
A
用getPerson
调用 B
抛出异常NotFound
NotFound
由异常处理程序处理,转换ResponseEntity
并放入 400 statusB
终于 return 异常ResponseEntity
A
从B
获得 400 状态
A
可以获得这个 400 并用它做点什么
B
简单 @Autowired
不起作用。
片段:
答:
@RestController
@RequestMapping("/v1")
public class A {
private final B b;
@Autowired
public A(B b) {
this.b = b;
}
@PostMapping(
value = "persons",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<List<StatusResponse<Person>>> addPersons(final List<Person> persons) {
final List<StatusResponse<Person>> multiResponse = new ArrayList<>();
for(final Person p: persons) {
final ResponseEntity<Person> response = b.addPerson(person);
multiResponse.add(new StatusResponse<>(
response.getStatusCode(), response.getMessage(), response.getBody()
));
}
return ResponseEntity.status(HttpStatus.MULTI_STATUS).body(multiResponse);
}
}
乙:
@RestController
@RequestMapping("/v1")
public class B {
@PostMapping(
value = "person",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<Person> addPerson(final Person person) {
accessService.checkAccess();
return ResponseEntity.status(201).body(
logicService.addPerson(person)
);
}
}
处理程序
@ControllerAdvice
public final class MyExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(MyException.class)
protected ResponseEntity<Object> handleApiException(final MyException exception, final WebRequest webRequest) {
//logic
return afterLogic;
}
}
forward 类似于重定向,但完全发生在服务器端; Servlet 容器将相同的请求转发到目标 URL; URL 在浏览器中不会改变。 在 spring 你可以这样做,你可以传递属性 :
@Controller
@RequestMapping("/")
public class YourController {
@GetMapping("/forward")
public ModelAndView redirectWithUsingForwardPrefix(ModelMap model) {
model.addAttribute("attribute", "forward");
return new ModelAndView("forward:/redirectedUrl", model);
}
}
无法将控制权从处理完其方法后调用的异常处理程序返回给控制器。您当前的流程如下所示call A.addPersons
-> invoke B.addPerson
-> B throws exception
-> exception is propagate to A controller
并在处理控制器方法(不是状态为 400 的 ResponseEntity)后保存为 dispatchException 以在 DispatcherServlet 中进一步处理 -> 使用 MyExceptionHandler 处理异常。从这个地方你不能回到控制器。
我不确定你想用控制器中的这个异常做什么,但解决方案可能如下所示:
@RestController
@RequestMapping("/resources")
public class AController {
private BService service;
@Autowired
public AController(BService service) {
this.service = service;
}
@RequestMapping("/test")
public ResponseEntity<String> test() {
ResponseEntity<String> result = service.test();
if (result.hasBody()) {
//doSomething
}
return result; //or list like you did
}
}
@Service
public class BService {
public ResponseEntity<String> test() {
try {
return ResponseEntity.status(201).body(getResponse()); //this always throws exception. It's just for purpose of example
} catch (CustomException ex) {
return ResponseEntity.status(400).build();
}
}
private String getResponse() {
throw new CustomException("Not OK!");
}
}