I'm using HandlerInterceptor to trigger all the events/actions happens in my applications and save it to audit table. In table I'm saving the information like servername, session, parameters etc..
So using HandlerInterceptor how can I read all those parameters values and the pathvariable values what I'm passing in my controller.
Here is my code :
public class AuditInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
LOG.debug("URL path"+request.getRequestURI());
return true;
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
LOG.debug("URL PATH :"+request.getRequestURI());
}
}
My controller class enter code here::
public class ABCDController {
#RequestMapping(value="categories",method=RequestMethod.GET)
#ResponseBody
public List<Category> getCategoryList(#RequestParam String divisions){
return service.getCategoryList(divisions);
}
}
So how can I read the parameter name and values using HandlerInterceptor's HttpServletRequest request object.
The Servlet API provides a way to read the Request Parameters. For example,
ServletRequest.getParameterMap() returns a map of key-values of the request parameters.
However, for Path variables and values, I don't know if Spring MVC offers a simplified way of doing it, but using Servlet API again, you can read the URI using HttpServletRequest.getRequestURI(). You'll have to have your own logic to split it up into appropriate Path parameters.
You should be able to get the variables and its values as a map using the following,
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
final Map<String, String> variableValueMap = (Map<String, String>) request
.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
variableValueMap.forEach((k,v)->System.out.println("Key:"+k+"->"+"Value : "+v));
return true;
}
Related
I have a question with Spring MVC RequestMapping annotation. need your help.
I have created one IPSLcontroller and i want that IPSLcontroller to handle all request url.i have created two method in this controller.
1)handleLogoutRequest :- this method should invoke on below url.
2)handleRequest :- this method should invoke on all request url otherthan logout.
http://localhost:9086/webapp/login
or
http://localhost:9086/webapp/add
or
http://localhost:9086/webapp/remove
here is my sample code. but it's not working as expected.
#Controller
public class IPSLController {
#RequestMapping(value={"/logout/*"},method = RequestMethod.POST)
protected void handleLogoutRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController logout request.......................................");
}
#RequestMapping(method = RequestMethod.POST,value={"/*"})
protected void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController all request Post.......................................");
}
}
You should use a general Prefix for every controller you use, so you can differ between them better. Also you donĀ“t need any "/" for calls like this.
#Controller
#RequestMapping("ispl")
public class IPSLController {
#RequestMapping(value={"logout"},method = RequestMethod.POST)
protected void handleLogoutRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController logout request.......................................");
}
#RequestMapping(method = RequestMethod.POST,value={"hello"})
protected void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController all request Post.......................................");
}
}
If you now want to call them over a ServletRequest or with a restService or something similar you should declare them like this
#GET
#Path("ispl/logout")
public void Method (HttpServletResponse ...)
Well it is working the way it should. You have a mapping for /* and for /logout/*. So when you post to /logout it invokes the method for /*. I suspect that if you post to /logout/something it would invoke your logout handler.
If you want it to work, you cannot have a wildcard mapping for the second method. At least use /something/* so that spring can make a correct decision on mappings.
What is the purpose of wrapping an HttpServletRequest using an HttpServletRequestWrapper ? What benefits do we gain from doing this ?
HttpServletRequest is an interface for a HTTP specific servlet request. Typically you get instances of this interface in servlet filters or servlets.
Sometimes you want to adjust the original request at some point. With a HttpServletRequestWrapper you can wrap the original request and overwrite some methods so that it behaves slightly different.
Example:
You have a bunch of servlets and JSPs which expect some request parameters in a certain format. E.g. dates in format yyyy-MM-dd.
Now it is required to support the dates also in a different format, like dd.MM.yyyy with the same functionality. Assuming there is no central string to date function (it's an inherited legacy application), you have to find all places in the servlets and JSPs.
As an alternative you can implement a servlet filter. You map the filter so that all requests to your servlets and JSPs will go through this filter.
The filter's purpose is to check the date parameters' format and reformat them to the old format if necessary. The servlets and JSPs get the date fields always in the expected old format. No need to change them.
This is the skeleton of your filter:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest adjustedRequest = adjustParamDates((HttpServletRequest) request);
chain.doFilter(adjustedRequest, response);
}
We take the original request and in method adjustParamDates() we manipulate the request and pass it down the filter chain.
Now, how would we implement adjustParamDates()?
private HttpServletRequest adjustParamDates(HttpServletRequest req) {
// ???
}
We need a new instance of interface HttpServletRequest which behaves exactly like the original instance req. But the four methods getParameter(), getParameterMap(), getParameterNames(), getParameterValues() shouldn't work on the original parameters but on the adjusted parameter set. All other methods of interface HttpServletRequest should behave like the original methods.
So we can do something like that. We create an instance of HttpServletRequest and implement all methods. Most method implementations are very simple by calling the corresponding method of the original request instance:
private HttpServletRequest adjustParamDates(final HttpServletRequest req) {
final Map<String, String[]> adjustedParams = reformatDates(req.getParameterMap());
return new HttpServletRequest() {
public boolean authenticate(HttpServletResponse response) {
return req.authenticate(response);
}
public String changeSessionId() {
return req.changeSessionId();
}
public String getContextPath() {
return req.getContextPath();
}
// Implement >50 other wrapper methods
// ...
// Now the methods with different behaviour:
public String getParameter(String name) {
return adjustedParams.get(name) == null ? null : adjustedParams.get(name)[0];
}
public Map<String, String[]> getParameterMap() {
return adjustedParams;
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(adjustedParams.keySet());
}
public String[] getParameterValues(String name) {
return adjustedParams.get(name);
}
});
}
There are more than 50 methods to implement. Most of them are only wrapper implementations to the original request. We need only four custom implementations. But we have to write down all these methods.
So here comes the class HttpServletRequestWrapper into account. This is a default wrapper implementation which takes the original request instance and implements all methods of interface HttpServletRequest as simple wrapper methods calling the corresponding method of the original request, just as we did above.
By subclassing HttpServletRequestWrapper we only have to overwrite the four param methods with custom behaviour.
private HttpServletRequest adjustParamDates(final HttpServletRequest req) {
final Map<String, String[]> adjustedParams = reformatDates(req.getParameterMap());
return new HttpServletRequestWrapper(req) {
public String getParameter(String name) {
return adjustedParams.get(name) == null ? null : adjustedParams.get(name)[0];
}
public Map<String, String[]> getParameterMap() {
return adjustedParams;
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(adjustedParams.keySet());
}
public String[] getParameterValues(String name) {
return adjustedParams.get(name);
}
});
}
I've setup a Spring HandlerInterceptor to add an attribute to the HttpServletRequest to be able to read it from the Controller, sadly this does not seem to work which seems strange to me. Am I doing things wrong? Any idea how to transmit the data from the Interceptor to the Controller?
Here is the simplified code of the two impacted classes
public class RequestInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
request.setAttribute("my-role", "superman");
}
[...]
}
#RestController
#RequestMapping("Test")
public class TestController {
public final Logger logger = LoggerFactory.getLogger(getClass());
#RequestMapping(value = "something")
public void something(HttpServletRequest request) {
logger.info(request.getAttribute("my-role"));
}
[...]
}
The request.getAttribute("my-role") returns null... but does return the excepted value if I read it in the postHandle of the HandlerInterceptor, I feel like I'm missing something...
EDIT : I found out that going thru the session with "request.getSession().setAttribute" works as a charm, still i do not understand why the request itself does not work in this use case.
Can you try with session instead of request like below.
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
...
HttpSession session = request.getSession();
session.setAttribute("attributeName", objectYouWantToPassToHandler);
....
}
In your handler handleRequest method:
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
....
HttpSession session = request.getSession();
objectYouWantToPassToHandler objectYouWantToPassToHandler = session.getAttribute("attributeName");
....
}
I have a MultiActionController with an action that I would only like to be reachable if the POST method is used.
public class MyController extends MultiActionController {
public ModelAndView myAction(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
// I don't want to hit this code unless POST was used
}
}
Is there a way to achieve this through annotations or am I stuck checking request.getMethod() ?
Use:
#RequestMapping(value={"action1","action2","action3"},
method = RequestMethod.POST)
I am trying to convert controllers from the old inheritance framework to the new annotations.
Here's an existing controller:
public class SelectedTabController extends AbstractController {
private TabSelectionHelper tabSelectionHelper;
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
String param = request.getParameter("selectedTab");
if (param != null)
tabSelectionHelper.setSelectedTabTo(param);
return null;
}
public void setTabSelectionHelper(TabSelectionHelper tabSelectionHelper) {
this.tabSelectionHelper = tabSelectionHelper;
}
And after conversion I have this:
#Controller
public class SelectedTabController {
private TabSelectionHelper tabSelectionHelper;
#Autowired
public SelectedTabController(#Qualifier(value = "tabSelectionHelper") TabSelectionHelper tabSelectionHelper) {
this.tabSelectionHelper = tabSelectionHelper;
}
#RequestMapping("/selectedTab")
public void selectTab(String selectedTab, HttpServletResponse response) throws Exception {
//String param = request.getParameter("selectedTab");
if (selectedTab != null)
tabSelectionHelper.setSelectedTabTo(selectedTab);
}
}
This works but there is a (redundant) HttpServletResponse object in the selectTab paramter list. If I remove it, then the JQuery call says the server returns 500 and the call fails.
Any help?
The stacktrace shows:
javax.servlet.ServletException: Could not resolve view with name 'selectedTab' in servlet with name 'prodman'
So it is trying to find a view and failing. However, there is NO view to display as its a backend callby JQuery.
I guess by declaring the response object, Spring thinks I will write the response.
How can I prevent Spring from trying to resolve a view?
When you use void as your return type Spring will by default try to determine the view name from your method name, unless it thinks you're directly writing the response (which it does when you have a HttpServletResponse as a parameter). Have a look at section 15.3.2.3 of the Spring 3 docs.
You might want to try changing the return type to ModelAndView and return null and see what happens (I'm not certain you can get away with a null view with #RequestMapping as it's not something that I have ever tried)