Trying to pass view implicitly using mvc:view controller - spring

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.

Related

Command object automatically added to model?

I have a controller method like this:
#RequestMapping("/hello")
public String hello(UserForm user) {
return "hello";
}
It receives some request parameters in the UserForm command object. But I have not written any code to add the object to the Model. Still, in the view hello.jsp, I'm able to access the data, like this:
Hello, ${userForm.name}!
Does it mean that Spring MVC adds command objects to the Model automatically?
You don't need #ModelAttribute just to use a Bean as a parameter.
You'll need to use #ModelAttribute or model.addAttribute() to load default data into your model - for example from a database.
Most of the Spring controllers in the real world accept a lot of different types of parameters - Path variables, URL parameters, request headers, request body and sometimes even the entire HTTP Request object. This provides a flexible mechanism to create APIs. Spring is really good at parsing these parameters in to Java types as long as there is an ObjectMapper (like Jackson) configured to take care of the de-serialization.
The RequestMappingHandlerAdapter makes sure the arguments of the method are resolved from the HttpServletRequest.
Spring model data created prior to (or during) the handler method
execution gets copied to the HttpServletRequest before the next view
is rendered.
By now, Spring has processed the HTTP request and it creates the ModelAndView object from the method’s return value. Also, note that you are not required to return a ModelAndView instance from a controller method. You may return a view name, or a ResponseEntity or a POJO that will be converted to a JSON response etc.
ServletInvocableHandlerMethod invocableMethod
= createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(
this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(
this.returnValueHandlers);
}
The returnValueHandlers object is a composite of HandlerMethodReturnValueHandler objects. There are also a lot of different value handlers that can process the result of your method to create ModelAndViewobject expected by the adapter.
Then, it has to render the HTML page that the user will see in the browser. It does that based on the model and the selected view encapsulated in the ModelAndView object.
Now, at this stage, the view gets access to the userForm (as in your example above) from the request scope.

Best Practice of reading text file in spring mvc

What is the best way to read HTML content from a text file and display the content in JSP? I have placed the text file in the resource folder using spring mvc 3. Normally I do this kind of stuff with Apache commons in struts but believe spring must have provided some utility for this.
I am thinking about reading it in a tag file. What utility should i use for that?
Ignoring the question of why you would want to do this. The return value from a Spring MVC controller method is usually used to resolve a view. The resolved view then becomes the response body. However, you can use the #ResponseBody annotation to make the raw return value the response body.
You can do it in the #RequestMapping method. The Key is the return type ModelAndView.
You read your text file and get the html that you need, after this, adding the html to the model and then return the a new ModelAndView Object.
Here's a sample:
#RequestMapping(value = "siteWithResHtml", method = RequestMethod.GET)
public ModelAndView loadSiteWithResHtml(Model model)
{
String resourceHtml;
// do your stuff for reading file and assign it to the String
model.addAttribute("resource_Html", resourceHtml);
return new ModelAndView("yourJSP", "model", model);
}
and in the jsp you can read the value from the model that you forwarded to the jsp, like this:
<div>${model.resource_Html}</div>
please take notice that the names are match.

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?

Liferay 6.1 + Spring MVC Portlet 4.0: Friendly URL Mapping

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

Spring + Ehcache - can #Cacheable be used to cache the output of a jsp view

Basically, is it possible to do this:
#Cacheable(cacheName="default")
#RequestMapping("getContent/{name}")
public String getContentByNameHandler(#PathVariable String name, Model model) {
ContentService contentService = domainService.getContentService();
model.addAttribute("model",contentService.getContentByName(name));
return RESOURCE_FOLDER + "content";
}
When I try this, the view is cached, but the only the plain content of the jsp is returned from the cache, not the jsp view after the simple jsp view rendering logic has completed. I'm on spring 3.0.7, so still using the ehcache-spring-annotations (http://code.google.com/p/ehcache-spring-annotations)
#Cacheable works by simply forming a key based on all input parameters, and putting the return value under that key.
So it won't store the processed view - it will simply store the view name.
Normally, you'd use browser caching for that instead of server-side caching. And since rendering the view is supposed to be less consuming than generating the content, you'd put #Cacheable on the service method.

Resources