Spring create a method controller that executes in every page - java

Currently , I am implementing the hreflang meta tag in my site and I am facing a problem , I need to create a method that must be executed in every page (in order to load the hreflangs into the model and pass them to the JSP) of my site and this method must have this parameters HttpServletRequest request, HttpServletResponse response.
I tried with this :
#RequestMapping(value = {"/*"})
public class GLobalPageController {
#ModelAttribute
public void setupHreflangs(Model model, HttpServletRequest request, final HttpServletResponse response) {
//code
}
}
But its not working , any idea about how can I achieve this ?

Related

How to add objects into Model after each request (Spring Boot)

I'm developing a web application with Java and Spring Boot. What I would like to do is to add an object into the Model every time a request is received. Let me explain better what I'm doing and why I need it.
The application is an eCommerce and I need every time a page is loaded the number of items inside the cart and the number of notifications a user has got. These information are displayed inside the menu in all the pages of the web app. Right now I'm requesting these information to through an ajax call after the page has been loaded. I would like to automatically add these information inside the Model and render and return all the pages with them already present without making any further request.
I googled it and I found out that a way to solve this problem is to use an Interceptor.
I implemented it following this tutorial but the only problem is that preHandle, postHandle and afterCompletion get called not only with the page requests but also with other kind of content like images, videos etc.
#Component
public class ProductServiceInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre Handle method is Calling: " + request.getRequestURI());
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Post Handle method is Calling");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {
System.out.println("Request and Response is completed");
}
}
When registering your interceptors in WebMvcConfigurerAdapter, you can also define a path pattern to include or exclude.
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new YourInterceptor()).excludePathPatterns("/path/to/your/static/resources/*");
}
Full example is available here : https://www.concretepage.com/spring/spring-mvc/spring-mvc-handlerinterceptor

How to access a spring-mvc flash redirectAttribute in the filter chain before the DispatcherServlet is invoked?

I have the following controller:
#Controller
#RequestMapping("/my-account")
public class AccountController {
#RequestMapping(value = "/foo/post",
method = RequestMethod.POST)
public String doPost(final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("flashAttribute", "flashAttributeValue");
return "redirect:/my-account/foo/get";
}
#RequestMapping(value = "/foo/get",
method = RequestMethod.GET)
public void doGet(final HttpServletRequest request, final Model model) {
System.out.println("in request: " + RequestContextUtils.getInputFlashMap(request).get("flashAttribute"));
System.out.println("in model: " + model.asMap().get("flashAttribute"));
}
}
I would also like to access the flash attribute flashAttribute during the invocation of a filter in the filter chain that finally invokes springs default DispatcherServlet which in turn invokes AccountController.
public class FlashAttributeBasedFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
throws ServletException, IOException {
String flashAttribute = // how to access the redirectAttribute flashAttribute here?
// do something with flashAttribute ...
filterChain.doFilter(request, response);
}
The DispatcherServlet uses a org.springframework.web.servlet.FlashMapManager that handles these flash attributes, but it doesn't provide read-only access so I think I would be messing something up if I would use it in the filter. And also the FlashMapManager instance is kept in the dispatcher servlet privately.
Does anybody have an idea how I can make the redirect attribute accessible in the filter chain for the GET request succeeding the POST?
Considering that all these methods return null into my filter (I don't understand why):
RequestContextUtils.getFlashMapManager(httpRequest)
RequestContextUtils.getInputFlashMap(httpRequest)
RequestContextUtils.getOutputFlashMap(httpRequest)
I used a drastic solution: read directly the into the session (where flash attributes are stored).
CopyOnWriteArrayList<FlashMap> what = (CopyOnWriteArrayList<FlashMap>) httpRequest.getSession().getAttribute("org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS");
if (what != null) {
FlashMap flashMap = what.get(0);
[read flashMap as you read a HashMap]
}
I know, this code is super ugly but at the moment I don't find another solution.
Had the same problem, following works for me.
FlashMap flashMap = new SessionFlashMapManager().retrieveAndUpdate(request, null);
flashMap.get("parameter");

call servlet method name display(HttpServletRequest request, HttpServletResponse response) from another servlet

I am developing a shopping cart using servlets, have two servlets :
1. ShopingCart.java
2. TotalAmount.java
In ShopingCart.java i have created sessions and synchronise them using
synchronized(session) // lock session protect this from multiple threads
{
TotalAmount cart = (TotalAmount)session.getAttribute("Cart");
if(cart == null) // new sesssion, just create a cart
{
cart = new TotalAmount();
session.setAttribute("Cart", cart);
}
// I have to call cart.display();
and my display method in TotalAmount.java contains (request,response) as parameters.
so, how can i pass the request and response to display method?
yes, i need request and response parameters in display method to save some variable data in session in TotalAmount.java
Please Help..
I can pass the request and response to display method of TotalAmount.java by calling
Display(request,response);
As I already have the object of TotalAmount in ShopingCart.java
As per Java EE specification, servlet are independents and the only official way to interact with one is via their service(ServletRequest req, ServletResponse res) or doXXX method.
If you want to call a specific method of another servlet you have 2 broad solutions :
make the objects know each other by dependancy injection (Java EE CDI, Spring framework, etc.) - clean and neat provided you have one DI mechanism
manually register them via static method - say you want to access Servlet2 from Servlet1
class Servlet1 implement HttpServlet {
private static Servlet2 servlet2 = null;
public static void setServlet2(Servlet2 servlet2) {
this.servlet2 = servlet2;
}
// ... other code
servlet2.display(...);
// ...
}
class Servlet2 implements HttpServlet {
#Override
public void init(ServletConfig config) {
Servlet1.setServlet2(this);
// ... other init code eventually
}
// ...
}
It should work but is not very nice because of the static misuse.
forward to the other servlet and pass a request attribute to indicate that a special action is requested (assuming Servlet2 is named "Servlet2" in web.xml)
in Servlet1 :
request.setAttribute("DISPLAY", true);
request.getServletContext().getNamedDispatcher("Servlet2").forward(req, resp);
in Servlet2 :
public void service(ServletRequest req, ServletResponse resp) {
if (req.getAttribute("DISPLAY") != null) {
display(req, resp);
}
else {
super.service(req, resp); // or directly your code
}
}
Still a nice solution because attribute will not be set in a direct call (of course, you can use req.getRequestDispatcher("/Servlet2URL") instead of getServletContext().getNamedDispatcher("Servlet2"))

How can I run common code for most requests in my Spring MVC Web App?

i.e.
I have various URLs mapped using Spring MVC RequestMapping
#RequestMapping(value = "/mystuff", method = RequestMethod.GET)
#RequestMapping(value = "/mystuff/dsf", method = RequestMethod.GET)
#RequestMapping(value = "/mystuff/eee", method = RequestMethod.GET)
etc
I want to run some common action before about 90% of my requests. These are across several controllers.
Is there anyway to do that without delving into AOP? And if I have to use aspects, any guidance on how to do this?!
Thanks!
More info:
It is to run some app specific security - we are chained to a parent security set up, which we need to read and call into, and then need to access a cookie prior to some most of ours calls, but not all.
You can use an Interceptor:
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping
Interceptor is the solution. It has methods preHandler and postHandler, which will be called before and after each request respectively. You can hook into each HTTPServletRequest object and also by pass few by digging it.
here is a sample code:
#Component
public class AuthCodeInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// set few parameters to handle ajax request from different host
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.addHeader("Access-Control-Max-Age", "1000");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Cache-Control", "private");
String reqUri = request.getRequestURI();
String serviceName = reqUri.substring(reqUri.lastIndexOf("/") + 1,
reqUri.length());
if (serviceName.equals("SOMETHING")) {
}
return super.preHandle(request, response, handler);
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
}
The HandlerInterceptor.preHandle() method gives you access to the request and response and also the target handler. In Spring 3.1 that will be of type HandlerMethod, which gives you access to the target controller class and method. If it helps you can try excluding entire controller classes by type name, which would be strongly typed and without specifying explicit URLs.
Another option would be created an interceptor mapped to a set of URL patterns. See the section on configuring Spring MVC in the reference documentation.

Avoiding the endless loop in JSP servlet mapping

I've got this issue, recently I read about the REST arquitecture and it makes a perfect sense, so I'd like to achieve a RESTful web application.
Now, I'm following the Front Controller pattern that means that all of the URL mappings go to the controller.java servlet, I map the by specific URLs, not by using the /* wildcard,
the controller implements the four HTTP methods POST,GET,PUT,DELETE, each method calls the controllers service method and there I determine based on the HttpServletRequest and pathInfo the action to execute.
Controller.java
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
IAction action;
View view;
try {
action = ActionFactory.produceAction(req);
view = action.execute(req, resp);
switch (view.getDispatchMethod()) {
case REDIRECT:
resp.sendRedirect(resp.encodeURL(view.getResource()));
break;
case FORWARD:
req.getRequestDispatcher(view.getResource()).forward(req, resp);
break;
case INCLUDE:
req.getRequestDispatcher(view.getResource()).include(req,resp);
break;
default:
}
} catch (ActionFailedException uae) {
req.setAttribute("ActionName", "Action");
req.setAttribute("FailCause", uae.getMessage());
req.getRequestDispatcher(VIEW_FAIL.getResource()).forward(req, resp);
}
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
I've run into a particular issue when loading a specific order by the URI /orders/*, it is mapped to the controller servlet, the the action is executed and I load the appropriate order the action returns a View.java class
//ommited accessors and mutators for brevety.
public class View {
public enum DispatchMethod {
INCLUDE, FORWARD, REDIRECT
}
private DispatchMethod dispatchMethod;
private String resource;
public View(DispatchMethod dispatchMethod, String resource) {
this.dispatchMethod = dispatchMethod;
this.resource = resource;
}
}
Then the request is dispatched according to the getDispatchMethod() of the returned view.
Now, here is where the loop gets triggered, I use the following URL, myapp/orders/78965 /orders/* gets mapped to controller.java the appropriate action is executed and the correct order is found by the pathInfo() the returned view is new View(View.DispatchMethod.FORWARD,"order_details.jsp") the problem is that with the three available dispatch methods REDIRECT,FORWARD and INCLUDE a request is re-triggered on the URL and so on and on and on I never reach the order_details.jsp that renders the data.
So, how would you avoid the looping, as I'd like to preserve the URI displaying the order number I use the forward method, also, I'd like to do it using servlets, I've heard of the UrlRewriteFilter maybe in the future, but right now, how would it be done using "Plain Vanilla" since I'm using the Front Controller pattern, will it be necessary to add an additional servlet in the /orders/ URI ?
Any help or insights is truly appreciated.
EDIT 1:
Pasted the source code of the controller, a very basic one, I have my suspicions that the way the service method calls all of the overriden do[Method] of the servlet is triggering the loop and that it may be solved by splittig them.
Implementing a RESTful HTTP interface in Java is a lot easier using a JAX-RS implementation like RESTEasy or Jersey.
Using a Front Controller to dispatch requests to the right resource is a good approach, it's exactly the approach taken by these JAX-RS frameworks. I fear you may be re-inventing the wheel here by writing a bespoke URL parsing and dispatching mechanism when this can be taken off-the-shelf.
JAX-RS is a lightweight way to expose resources. By using a couple of simple annotations you can expose a REST interface without any plumbing required. For example:
public class Order {
#GET
#Path("/orders/{orderId}")
#Produces("text/html")
public void getOrder(#Context HttpServletResponse response,
#Context HttpServletRequest request,
#PathParam("orderId") String orderId) throws ServletException, IOException {
// ... create view and add to request here
request.getRequestDispatcher("orders.jsp").forward(request, response);
}
}
You can see how simple it is to attach this class to a URL path (using the #Path annotation), and how easily you can parse values from the URL using #PathParam. Since you get all the plumbing/dispatching/parsing off-the-shelf, you can concentrate on the bits of your app that are specific to your domain (such as what an order contains).

Categories

Resources