简体   繁体   中英

Spring - Intercept response from another bean by exception handler

I have two @RestController s - (A and B) and registered ResponseEntityExceptionHandler . Is it possible (and how to do it) to call from A and get a response from B after the exception handler is applied?

Example:

  1. User rest call A
  2. A calls B with getPerson
  3. B throws exception NotFound
  4. NotFound is handled by an exception handler, transforming ResponseEntity and put 400 status
  5. B finally return exception ResponseEntity
  6. A gets 400 status from B
  7. A can get this 400 and do something with it

Simple @Autowired is not working.

Snippet:

A:

@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);
    }

}

B:

@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)
        );
    }

}

Handler

@ControllerAdvice
public final class MyExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MyException.class)
    protected ResponseEntity<Object> handleApiException(final MyException exception, final WebRequest webRequest) {
        //logic
        return afterLogic;
    }

}

forward is like to redirect but happens entirely on a server side; the Servlet container forwards the same request to the target URL; the URL won't change in the browser. in spring you can do it like this, and you can pass attribute :

@Controller
@RequestMapping("/")
public class YourController {

    @GetMapping("/forward")
    public ModelAndView redirectWithUsingForwardPrefix(ModelMap model) {
        model.addAttribute("attribute", "forward");
        return new ModelAndView("forward:/redirectedUrl", model);
    }
}

It is not possible to get control back to controller from exception handler which is invoke after handling its method. Your current flow looks like this call A.addPersons -> invoke B.addPerson -> B throws exception -> exception is propagate to A controller and it's save as dispatchException to futher processing in DispatcherServlet after handling controller method (not ResponseEntity with status 400) -> exception is handled with MyExceptionHandler. From this place you cannot back to controller.

I'm not sure what you want to do it with this exception in controller but solution may look like this:

@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!");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM