Liferay 6.1 + Spring MVC Portlet 4.0: Friendly URL Mapping - spring

I'm trying to get friendly URL mapping to work for a Spring MVC portlet inside Liferay 6.1 and fail.
My additions to the liferay-portlet-xml are according to the manual and blog examples available and as follows:
<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
<friendly-url-mapping>search</friendly-url-mapping>
<friendly-url-routes>com/.../friendly-url-routes.xml</friendly-url-routes>
with the friendly-url-routes.xml being
<!DOCTYPE routes PUBLIC "-//Liferay//DTD Friendly URL Routes 6.1.0//EN"
"http://www.liferay.com/dtd/liferay-friendly-url-routes_6_1_0.dtd">
<routes>
<route>
<pattern>/{match}</pattern>
<generated-parameter name="foo">{match}</generated-parameter>
</route>
</routes>
My Spring MVC controller goes like
#Controller
#RequestMapping("VIEW")
public class CarModelController {
#ActionMapping
public void action(#RequestParam("foo") final String testParam,
final ActionRequest request, final ActionResponse response) {
this.logger.info("default action");
this.logger.info("testParam = {}", testParam);
}
#RenderMapping
public String render(final RenderRequest request, final RenderResponse response) {
this.logger.info("default render");
return "index";
}
}
If I call my portlet using /baseurl/-/search/bar only the render phase output occurs, the action method isn't called.
If I create a link to this page using
<portlet:actionURL var="lastStepUrl">
<portlet:param name="foo" value="bar" />
</portlet:actionURL>
the URL Liferay generates looks like /baseurl/-/search/bar?p_auth=sometoken&p_p_lifecycle=1. It executes the action phase correctly and I'm also able to call that URL directly. It does, however, include the p_auth and p_p_lifecycle parameters that I want to get rid of.
Any suggestions are welcomed warmly.

I don't know much about Friendly URL in Liferay.
But I believe you can't completely remove p_p_lifecycle from url because.
this parameter tells Liferay which action to perform. This paramater has two values (0 or 1).
0 tells Liferay to just render the portlet,
whereas 1 tells Liferay to call the process Action Method.
Lets say you want to remove from certain action URL then can do it like this
<pattern>"your URL pattern"</pattern>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="javax.portlet.action">"Your action"</implicit-parameter>
As we know 1 for action phase we can hard code and put it into routes.xml file.same way for any render URL we can put 0
To remove p_auth try putting below properties in portal-ext.properties file
portlet.add.default.resource.check.enabled=false
auth.token.check.enabled=false

Related

Login page with Spring

I'm setting up my security support in Spring and I am exploring what it has to offer. While setting up my login URL and view, I needed to register simple controllers for home and login URL. Concretely, code is:
#Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/").setViewName("home");
registry.addViewController("/login");
}
In line registry.addViewController("/").setViewName("home"); it seems that that line simply adds controller for URL "/" and for GET to that URL simply uses view "home" for rendering.
Did I get it right? Main question is about line registry.addViewController("/login");. Here I add controller for "/login" URL.
But how application knows which view to use? When I tried the app it really used "login" view I created.
Well, you are on the right track but not completely. If you are NOT logged in and open the URL "yourdomain.tld/" you will be redirected to the URL "yourdomain.tld/home" which normally could be a login page. (first line). Of course, you need a controller to handle this request and return a proper JSP/JSF page.
Your second line is not needed. The trick is that with such a configuration you can use the URL "yourdoamin.tld/" with a different page for logged in users.
And to answer your main question, you need a controller for every URL or part of the URL you want to use. And within this controller, you can choose the views according to the requested URL.
Example:
#Controller
#RequestMapping(value="/info")
#Scope(value="session")
public class InfoController extends AbstractWebController {
#RequestMapping
public ModelAndView infoPage() {
ModelAndView mav = this.getModelAndView("info/infopage");
return mav;
}
}
This controller is responsible for all URLs starting with "yourdomain.tld/info". And as you can see I have only the URL "yourdomain.tld/info" to return a proper view. In this example I return "infopage.jsp". You can add code to return different views for other pages.

Spring controller, why is the returned view ignored?

So, say I have an existing, working page Display Cashier, which displays information about a cashier in a shop. Now, I add a button to this page that looks like:
Manager
The request-mapping for this URL maps it (successfully) to a controller: HandleGetManager
the HandleGetManager controller looks like this:
#Controller
public class HandleGetManager{
private employeeBO employeeBO; //BO handles all business logic
//spring hooks
public HandleGetManager(){}
public void setemployeeBo(employeeBO employeeBO){
this.employeeBO = employeeBO;
}
//get controller
#RequestMapping(method=RequestMethod.GET)
public String getManager(#RequestParam String cashierId){
Long managerId = employeeBO.getManagerByCashierId(cashierId);
String redirectUrl = "/displayManager.ctl?managerId=" + managerId.toString();
return redirectUrl;
}
}
Here's what happens when I try it:
I hit the new button on the Display Cashier page, I expect the following to happen:
The browser sends a get request to the indicated URL
The spring request-mapping ensures that the flow of control is passed to this class.
the #RequestMapping(method=RequestMethod.GET) piece ensures that this method is evoked
The #RequestParam String cashierId instructs Spring to parse the URL and pass the cashierId value into this method as a parameter.
The EmployeeBo has been injected into the controller via spring.
The Business logic takes place, envoking the BO and the managerId var is populated with the correct value.
The method returns the name of a different view, with a new managerId URL arg appended
Now, up until this point, everything goes to plan. What I expect to happen next is:
the browsers is directed to that URL
whereupon it will send a get request to that url,
the whole process will start again in another controller, with a different URL and a different URL arg.
instead what happens is:
this controller returns the name of a different view
The browser is redirected to a half-right, half wrong URL: handleGetManager.ctl?managerId=12345
The URL argument changes, but the name of the controller does not, despite my explicitly returning it
I get an error
What am I doing wrong? Have I missed something?
Assuming you have a UrlBasedViewResolver in your MVC configuration, the String value you return is a View name. The ViewResolver will take that name and try to resolve a View for it.
What you seem to want to do is to have a 301 response with a redirect. With view names, you do that by specifying a redirect: prefix in your view name. It's described in the documentation, here.
Here's a question/answer explaining all the (default) ways you can perform a redirect:
How can I prevent Spring MVC from doing a redirect?

Handle url pattern that has user name as part of the url

Suppose I have 3 url patterns that needs to be handled by Spring MVC as follows:
1) www.example.com/login (to login page)
2) www.example.com/home (to my home page)
3) www.example.com/john (to user's home page)
I would like to know what is the best practice way of handling the url pattern that has username as part of the url (real world example is facebook fanpage www.faceboo.com/{fanpage-name})
I have come up with my own solution but not sure if this is the clean way or possible to do it.
In my approach, I need to intercept the request before it being passed to Spring MVC's dispatchservlet, then query the database to convert username to userid and change the request URI to the pattern that Spring MVC can recognize like www.example/user/userId=45.
But I am not sure if this is doable since the ServletAPI does not have the setter method
for requestURI(it does have the getter method for requestURI)
Or if you have a better solution please share with me. Thank in advance :-)
Spring MVC should be able to handle this just fine with PathVariables.
One handler for /login, one handler for /home, and one handler for /{userName}. Within the username handler you can do the lookup to get the user. Something like this:
#RequestMapping(value="/login", method=RequestMethod.GET)
public String getLoginPage() {
// Assuming your view resolver will resolve this to your jsp or whatever view
return "login";
}
#RequestMapping(value="/home", method=RequestMethod.GET)
public String getHomePage() {
return "home";
}
#RequestMapping(value="/{userName}", method=RequestMethod.GET)
public ModelAndView getUserPage( #PathVariable() String userName ) {
// do stuff here to look up the user and populate the model
// return the Model and View with the view pointing to your user page
}

Trying to pass view implicitly using mvc:view controller

I have a Spring configuration file with MANY entries such as the one below.
<mvc:view-controller path="/test/one" view-name="one.xml" />
<mvc:view-controller path="/test/two" view-name="two.xml" />
<mvc:view-controller path="/test/three" view-name="three.xml" />
Now I am integrating controller code and I am trying to avoid having to have a request mapping for every single page. Is there a way for Spring MVC to implicitly find the page with the view as specified in the controllers.xml.
So instead of returning a string as the View. I would like a method where I was returning void or just the model to the page and for it to find the page
#RequestMapping(value = "/test/one", method = RequestMethod.GET)
public String getOne(HttpServletRequest request, Model model) {
// Business Logic
return "one.xml" // would like to be able to return void here or just the mode
}
The idea of mvc:view-controller is precisely to avoid having to implement a controller whan its only job would be to dispatch to a view. Just having this tag in the XML is sufficient. You don't need a controller.
See http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-view-controller
If you have controller logic and thus need a controller, then the mvc:view-controller element should be removed, and be replaced by the actual controller, which dispatches to the appropriate view. You may avoid specifying a view name explicitely here using a RequestToViewNameTranslator, as explained here.

Spring redirect: prefix issue

I have an application which uses Spring 3. I have a view resolver which builds my views based on a String. So in my controllers I have methods like this one.
#RequestMapping(...)
public String method(){
//Some proccessing
return "tiles:tileName"
}
I need to return a RedirectView to solve the duplicate submission due to updating the page in the browser, so I have thought to use Spring redirect: prefix. The problem is that it only redirects when I user a URL alter the prefix (not with a name a resolver can understand). I wanted to do something like this:
#RequestMapping(...)
public String method(){
//Some proccessing
return "redirect:tiles:tileName"
}
Is there any way to use RedirectView with the String (the resolvable view name) I get from the every controller method?
Thanks
the call prefixed by redirect: is a url, which is sent in a standard browser 302 redirect. you can't redirect to a view, because a view isn't a url. instead you'll need a new servelet mapping to a 'success' view and then redirect to that instead
#RequestMapping("processing.htm")
public String method(){
//Some proccessing
return "redirect:success.htm"
}
#RequestMapping("success.htm")
public String method(){
return "tiles:tileName"
}
this case works fine when you just need to show a 'thank you' page, which requires no specific data from the processing stage. however, if your success page needs to show some information from the processing, there are 2 ways to do it.
1) pass the information in the url as a get post ("redirect:success.htm?message=hi"). this is incredibly hackable, and thus highly unrecommended.
2) the better way is to store information in the http session, using #SessionAttributes and #ModelAttribute

Resources