We are trying to have a spring MVC Controller that works as a portlet and a servlet, in order to be deployed in a Liferay context or as a standalone version. But it seems that the we have a conflict if we decide to have multiple RequestMappings on the method level (as opposed to having just 1 mapping on the level of the controller). we get the error shown below.
Note that if we decide to just have a requestMapping on the level of the controller that hosts a servlet mapping and a portlet mapping, it works.
#RequestMapping({"view", "/"})
The controller that does not work:
#Controller("controller")
#RequestMapping("VIEW")
public class MyController {
#RenderMapping
public ModelAndView doView(RenderRequest request, RenderResponse response) throws Exception {
HttpServletRequest portletHttpReq = PortalUtil.getHttpServletRequest(request);
HttpServletResponse portletHttpResp = PortalUtil.getHttpServletResponse(response);
return doView(portletHttpReq, portletHttpResp);
}
#RequestMapping(value="/home")
protected ModelAndView doView(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
// do something
return new ModelAndView("view");
}
}
The resulting error:
[...]
Caused by: java.lang.IllegalStateException: Mode mappings conflict between method and type level: [/home] versus [view]
Do you have any suggestions on how we could implement such thing? What we would really like to avoid is having to maintain 2 controllers for every portlet/servlet.
Thank you.
I don't really think this is a good idea... the #RequestMapping annotation on the class level is going to cause problems for sure, simply because Spring portlet MVC expects the portlet mode, while Spring Web MVC expects a root URL.
Also, your code doesn't seem to be correct either, since ModelAndView exists in both the portlet MVC as the web MVC part of the Spring framework, and since you cannot import both, you'll have to specify the full package for one of them, and since you're not doing that either, your code is just wrong.
Except the technical issues, both portlets and servlet have different terminology and point of views. These are some key questions that pop up with me if I hear this:
What are you going to do about the different phases (ACTION and RENDER)
What about the the different portlet modes (VIEW, EDIT, HELP, ...)
What are you going to do about the specific portlet features (PortletSession, PortletPreferences, ...)
How are you going to handle the different kind of requests (ResourceRequest, ActionRequest, RenderRequest, PortletRequst, EventRequest vs HttpServletRequest)
How are you going to handle security? The portal container provides authentication for you, a standalone web application does not.
And these are just questions from a portlet mindset, I'm pretty sure there are also technical issues if you look at it from the web application point of view.
It makes much more sense to divide your code into a view layer and business logic. Put the business logic in a separate package or separate services, and build a separate portlet- and standalone application, using the same/shared business logic.
Related
I would like to set a breakpoint for debugging purpose. I call a rest api from Postman and I would like to check the very first point where the java application gets the call. Is there a listener? Where to set the breakpoint?
I guess the DispatcherServlet is what you are looking for. There is a lot of other stuff running before e.g. the servlet container and potential servlet filter, but the DispatcherServlet is a good starting point for debugging Spring MVC issues.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception
The documentation is also quite good: https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-servlet
For Spring MVC Webflux applications have a look at DispatcherHandler and set a breakpoint in public Mono<Void> handle(ServerWebExchange exchange).
It seems like I can do everything that the Controller class do inside Spring Web-Flow, for example decision making and switching from page to page. To my understanding, its the C inside the MVC model. Am I correct about this?
So my question is, is there any advantage to still include a Controller class when using Spring Web-Flow?
If you need access to the request and response, an appropriate design might still include a controller while also having a flow.xml. For example, if you had this code:
HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getNativeRequest();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getNativeResponse();
It's more intelligible to put that in a controller rather than a service.
Also, if you want to register a custom editor, it might make sense to have the controller have this logic in the initBinder() method.
Spring Web Flow uses the Spring MVC framework. The DispatcherServlet handles the request. A FlowHandlerMapping is used to map the request to a particular Web Flow.
Web Flow is to solve the problem involved with controller logic that spans multiple-page navigation (a pageflow, or wizard).
Web Flow can eliminate the need for specialized controller classes to accomplish following a path of page transitions/form updates along a predefined workflow. If you don't need to do this, you can save yourself a lot of configuration/complexity just by using MVC.
I came across authentication code in my company's java code. The application is a set of several REST services built on Spring MVC. There is a method that gets called in one of the authentication services on the HttpServletRequest object called getHeader(). And the method retrieves an AuthId. Why would they use HttpServletRequest in a spring MVC application? What are the benefits of using this servlet type code in the spring app? What would this method do? Any alternatives?
Spring MVC provides a lot of fabulous abstractions on top of HttpServletRequest, so you can avoid its low-level implementation details. You rarely need to access it directly.
For example, you could get a header value like Content-Type like this:
#GET
#Path("/myService")
public Response doSomething(#HeaderParam("Content-Type") String contentType) {
...
}
But there are times when you do need to access the HttpServletRequest directly--usually when you are using another API that demands it. If you are using some other library with a method you need that takes HttpServletRequest, then you got to grab it from Spring MVC directly.
For example, check out this method in this random UrlUtil class:
public static String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
//Get a path segment
}
You have no choice but to grab HttpServletRequest from Spring MVC.
Spring MVC is built on the Servlet API. Anything you could do with a Servlet, you can therefore do with Spring MVC. What the Spring MVC framework provides is a wrapper to code a web application in a specific architectural style. This wrapper adds behavior and some times simplifies tasks.
Why would they use HttpServletRequest in a spring MVC application?
In this case, because it is the most direct way to get the header.
What are the benefits of using this servlet type code in the spring
app?
Spring doesn't have to wrap anything. You get it directly from the source.
What would this method do?
Read the javadoc.
Any alternatives?
In a #Controller class' handler method, you can declare a parameter annotated with #RequestHeader and have Spring pass an argument that it retrieves from the HttpServletRequest headers.
This is, by default, restricted to #Controller methods annotated with #RequestMapping. If your service class is a HandlerInterceptor, Filter, or other type of class and simply has a reference to the HttpServletRequest object, there is nothing more you can do than retrieve it directly with getHeader(String).
Here is an alternative : Spring MVC define the parameter annotation #RequestHeader to read httpServletRequest headers :
#RequestMapping(...)
public #ResponseBody String myMethod(#RequestHeader String AuthId){
//the value of the parameter AuthId is the value of request header named AuthId
...
}
I'm working on an web application and have a problem of session storage.
The application is deployed to a cluster, and we place an apache http server to handle load-balancing. So each request may be handled by different node in the cluster. We set out to use Redis(master/slave) as a shared session storage.
My question is how to plug it to Spring mvc, so we can use redis and don't need change our application code.
I find a solution on the internet which uses Filter and HttpServletRequestWrapper:
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
//get sessionId from cookie or generate one if not found
filterChain.doFilter(new CustomHttpServletRequestWrapper(sid, request),
servletResponse);
}
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
String sid = "";
public HttpServletRequestWrapper(String sid, HttpServletRequest arg0) {
super(arg0);
this.sid = sid;
}
public HttpSession getSession(boolean create) {
return new HttpSessionSidWrapper(this.sid, super.getSession(create));
}
public HttpSession getSession() {
return new HttpSessionSidWrapper(this.sid, super.getSession());
}
}
I wonder whether I can find an equivalent in spring mvc?
The first one came to my mind is HandlerInterceptor. But not like filter's api, HanlderIntercepor does not handle the chain, so there is no way to pass a custom request to the next interceptor.
Any idea is appreciate, thanks in advance.
UPDATE:
I found two strategy on this topic:
The first one is extending your web container(such as Tomcat) and There is some mature open source project focused on it already.
The second one is use filter + wrapper. This stratey is web container agnositic.
Personally I prefer the first one because it's transparent to the developers. Let's say we use Weblogic in test/production evironment and we use embedded jetty for development because it's faster and requires less resources. In this situation, developer doesn't have to setup a session storage for development. On the other hand, however, every developer need to setup a session storage of his/her own if we adopt the second strategy. The alternative solution is provide a shared session storage for development environment or some configurations to swtich the sesson storage strategy(built-in for development, shared for test/production). I think it's easier to perform dependency(configuration) injection via spring than that via raw servlet filter and hence raise this question.
Does anyone know is there an out-of-box implementation of the first strategy for Weblogic by the way?
I don't know about WebLogic session storage configuration options, but I can comment on the filter based strategy.
You can implement the filter to be aware of its environment. You can add configuration for the development, which will say "don't wrap request" and enable wrapping only in production (or test) environment.
You can implement your filter to be Spring application context aware (check WebApplicationContextUtils) or even being managed by Spring's application context (via DelegatingFilterProxy). Then you will be able to pull out configuration values or use Spring profiles to set up the filter manually.
Good day!
I am planning to do a simple CRUD application. I am planning to make my add, edit, delete and view handled by one controller. Something like this:
#WebServlet(name="ControllerServlet",
urlPatterns = {"/add","/edit","/delete","/view"}
then just use this code in my controller:
String userPath = request.getServletPath();
if (userPath.equals("/add")) {
}
But I am not sure if this is a common practice. Anyway, I am wondering what is the best practice for this? What are the pros and cons of doing this instead of separating each controller?
Thank you in advance.
Frankly, the common practice is to adopt a MVC framework. Java EE 6 offers JSF 2.0 out the box as a component based MVC framework. CRUD is possible with a single bean and a single view. You can find a basic example in this answer. The sole controller is provided by JSF itself, the FacesServlet. Other MVC frameworks follows less or more the same ideology.
If you don't want to adopt a MVC framework because you would like to learn JSP/Servlets first and/or your project won't go beyond a CRUD form, then it is hard to point out the "right" approach. At least, the use of multiple URL patterns and if/else statements is a poor sign. You have basically 2 options.
Just use 4 separate servlets. With Servlet 3.0 you don't need to fiddle with web.xml anymore and it's really easy to add another servlet class. Each servlet class functions as an "action" class and each one has a clear responsibility.
Use a single servlet, but don't use multiple URL patterns and don't use if/else blocks to determine the actions. Map it on a single URL pattern such as /action/* or *.do so that you can invoke it by URLs like action/create, action/read, etc or by create.do, read.do, etc. Then create an interface like follows
public interface Action {
void execute(HttpServletRequest request, HttpServletResponse response);
}
Implement all actions based on this interface, CreateAction, ReadAction, etc and have in your servlet a Map<String, Action> which you fill as follows during init() method:
actions.put("create", new CreateAction());
actions.put("read", new ReadAction());
// ...
And invoke it as follows (assuming an URL pattern of /action/* is been used)
actions.get(request.getPathInfo().substring(1)).execute(request, response);
That's also how the average MVC framework works deep under the covers.
See also:
Design patterns web based applications
Have you considered doing this as a RESTful service using a JAX-RS framework (like Jersey)? Then you leverage URIs and the HTTP operations: PUT, GET, POST, DELETE for CRUD:
http://bdoughan.blogspot.com/2010/08/creating-restful-web-service-part-45.html
For example:
GET http://www.example.com/customer/1
reads customer with id=1
DELETE http://www.example.com/customer/1
deletes customer with id=1