How do I get the rest path in a HandlerInterceptorAdapter without resolved path variables - spring

I have a problem with my RestController interceptor.
My goal is to get the RestController path in a HandlerInterceptorAdapter and then use it to create metrics.
Via the interface HttpServletRequest I have access to the path, but it is resolved there.
Example of what I would like to get in my interceptor:
GET: object/123 // wrong
GET object/{id} // right
Is there any way to get the path without resolved variables?
Here is my implementation:
RestController:
#RestController
public class ObjectController
{
#GetMapping("object/{id}")
public String getObjectById(#PathVariable String id)
{
return id;
}
}
Config:
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter
{
#Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(new RequestInterceptor());
}
}
Interceptor:
public class RequestInterceptor extends HandlerInterceptorAdapter
{
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception
{
System.out.println(request.getRequestURI());
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
#Nullable ModelAndView modelAndView) throws Exception
{
System.out.println(request.getRequestURI());
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
#Nullable Exception ex) throws Exception
{
System.out.println(request.getRequestURI());
}
}

Related

i am trying to add interceptors to spring project,my prehandle method is not getting called

I want my prehandle method to be called.On debugging i see the control going inside ProductServiceInterceptor class but none of the methods inside are getting called
#EnableWebMvc
#Configuration
public class ProductServiceInterceptorAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new productServiceInterceptor()).addPathPatterns("/home/*"));
}
}
#Component
public class ProductServiceInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
#Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception exception) throws Exception {}
}

Spring Boot - Pass Exception object from ResponseEntityExceptionHandler to HandlerInterceptor?

I am working on Spring Boot Example and implemented GlobalExceptionHandler and trying to print all error messages in JSON - it's my custom method.
Also, I have ExceptionHandler there I am catching all the Exception. But is there any way to pass the exception object from ResponseEntityExceptionHandler to HandlerInterceptor?
HandlerInterceptor:
#Slf4j
public class GlobalExceptionHandler implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
............
.............
..............
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
ServletRequestAttributes attributes = (ServletRequestAttributes) request.getAttribute(REQUEST_ATTRIBUTES);
ServletRequestAttributes threadAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
............
.............
..............
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
if(ex != null) {
printJsonReq(request, response);
}
}
}
ExceptionHandler:
#ControllerAdvice
#Slf4j
public class ExceptionHandler extends ResponseEntityExceptionHandler{
#ExceptionHandler({ResponseStatusException.class})
protected ResponseEntity<Object> handleResStatusException(Exception e, WebRequest request, HttpServletRequest httpRequest) {
ResponseStatusException be = (ResponseStatusException) e;
ErrorResource error = ErrorResource.builder().code(AppConst.BAD_REQUEST)
.message(ExceptionUtils.getDetails(e.getCause())).build();
return handleExceptionInternal(e, error, getHeaders(), HttpStatus.BAD_REQUEST, request);
}
.........
..........
.........
}
You can set it as a request attribute in ExceptionHandler class (if you need it just to be sure you are going print log then instead of passing Exception object you can pass boolean param to not load your request object)
request.setAttribute("exception", e);
And use it in your HandlerInterceptor as
if(ex != null || request.getAttribute("exception") != null) {
printJsonReq(request, response);
}
You can configure the interceptors using WebMvcConfigurerAdapter
17.15.3 Configuring Interceptors
You can configure HandlerInterceptors or WebRequestInterceptors to be applied to all incoming requests or restricted to specific URL path patterns.
An example of registering interceptors in Java:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new GlobalExceptionHandler());
}
}

Why does the spring boot controller not invoked after calling request.getReader in preHandle

I am implementing an interceptor for logging purposes. I know once i called the getReader method on HttpServletRequest will loose the body data, but i was experimenting. So i ran the below code, and realized the controller is never invoked (Debug point is not activated) and there was no errors.
#Component
public class IncomingRequestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestPayload = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(requestPayload);
return super.preHandle(request, response, handler);
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
super.afterCompletion(request, response, handler, ex);
}
}
And the controller
#PostMapping("/test")
public String test(#Valid #RequestBody CredentialsVo credentials) {
credentials.getUsername();
.............
return "test";
}
Filter Registration
#Configuration
public class MyConfig implements WebMvcConfigurer {
#Autowired
IncomingRequestInterceptor incomingRequestInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(incomingRequestInterceptor)
.addPathPatterns("/**");
}
}
if i do not call getReader() method, the controller is invoked. I was actually expecting the controller is called but i would get a null pointer or something like that.
Could anyone tell me how spring acts in this scenario ?

Do we have provision for interceptor chaining in Spring?

Let's say we have two interceptors "LogInterceptor" and "AuthInterceptor".
The first interceptor logs the incoming request and the second one authenticate it.
Aim: Chain LogIntercptor and AuthInterceptor. First I want the logInterceptor be called and after that AuthInterceptor should be executed.
Note: I know about "redirect" and returning false (Please don't suggest the one)
---------------------Log Interceptor---------------------------------------
//First Inteceptor
#Component
public class LogInterceptor extends HandlerInterceptorAdapter
{
private final Logger Logger =
LoggerFactory.getLogger(this.getClass());
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//take action base on incoming IP
long startTime = System.currentTimeMillis();
request.setAttribute("startTime",startTime);
if(request.getRemoteAddr().startsWith("192"))
{
response.sendRedirect("/auth-failed"); //redirect to default
return false;
}
return true;
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler, #Nullable ModelAndView
modelAndView) throws Exception
{
}
#Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, #Nullable Exception
ex) throws Exception
{
}
}
//Second interceptor "Code is however not complete, I am just seeeking how this can be achieved."
class AuthInterceptor
{
}
You just need to make sure the Interceptor are added in your desired orders when configuring InterceptorRegistry:
#EnableWebMvc
#Configuration
public class WebConfig implements WebMvcConfigurer{
#Autowired
private LogInterceptor logInterceptor;
#Autowired
private AuthInterceptor authInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor);
registry.addInterceptor(authInterceptor);
}
}
In case you have multiple WebMvcConfigurer , you can simply use #Order to control which the execution order of WebMvcConfigurer (lower value has higher priority):
#EnableWebMvc
#Configuration
#Order(1)
public class FooWebConfig implements WebMvcConfigurer{
}
#EnableWebMvc
#Configuration
#Order(2)
public class BarWebConfig implements WebMvcConfigurer{
}

I'm looking for the way to handle pre & post processing of Controller in Spring Boot + thymeleaf

I have been looking for the way to handle pre & post processing of controller.
I want to add a procedure for every request & response.
For example:
Checking every requested header or adding hidden field include hash code in every form tags we response.
If there is sample, or any idea,give me please.
Thanks for advice.
I was able to find the result from this page.
http://www.concretepage.com/spring/spring-mvc/spring-handlerinterceptor-annotation-example-webmvcconfigureradapter
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new ControllerHandler());
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
}
}
public class ControllerHandler implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("---Before Method Execution---");
return true;
}
#Override
public void postHandle( HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---method executed---");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("---Request Completed---");
}
}
I found another way to do,using #ControllerAdvice.
This annotaion seems to focus Error Handling.
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html1
#ControllerAdvice
public class ExceptionControllerAdvice {
#InitBinder
public void initBinder(WebDataBinder binder) {
System.out.println("controller advice: init binder");
}
#ExceptionHandler(Exception.class)
public String exception(Exception e) {
System.out.println("controller advice: exception Handler");
System.out.println(e.getMessage());
return "error";
}
#ModelAttribute
public void modelAttribute(){
System.out.println("controller advice:model Attribute");
}
}

Resources