When I'm looking at Spring FrameWork 3.0 I see the following code example:
#RequestMapping("/index.dlp")
public ModelAndView index(){
logger.info("Return View");
return new ModelAndView("index");
}
This option doesn't work for me. Only when I change the code the following way:
#RequestMapping("/index.dlp")
public ModelAndView index(){
logger.info("Return View");
return new ModelAndView("index.jsp");
}
It works fine. Can anybody tell me why?
View names are resolved into the actual views by ViewResolvers.
To refer JSP pages by short names, you need to supply InternalResourceViewResolver with prefix and suffix. The following configuration maps index to /WEB-INF/jsp/index.jsp:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
See also:
15.5 Resolving views
Related
I try to create pdf view according this tutorial
I have controller:
#Controller
public class UserController {
#Autowired
UserDao userDao;
#RequestMapping(value = "/user_pdf", method = RequestMethod.GET, headers = "Accept=application/pdf")
public ModelAndView usersPdf(#ModelAttribute("model") ModelMap model) {
return new ModelAndView("pdfView", "listBooks", userDao.getAll());
}
}
I have servlet configuration:
<context:component-scan base-package="ua.epam.spring.hometask" />
<context:annotation-config/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<!--<property name="prefix" value="/WEB-INF/ftl"/>-->
<property name="suffix" value=".ftl"/>
</bean>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
</bean>
<bean id="PdfRevenueSummary"
class="ua.epam.spring.hometask.view.UserPdfView">
</bean>
And I have pdf builder:
#Component
public class UserPdfView extends AbstractPdfView {
protected void buildPdfDocument(Map model,
Document document, PdfWriter writer, HttpServletRequest req,
HttpServletResponse resp) throws Exception {
User user = (User) model.get("command");
Paragraph header = new Paragraph(new Chunk("Generate Pdf USing Spring Mvc",FontFactory.getFont(FontFactory.HELVETICA, 30)));
Paragraph by = new Paragraph(new Chunk("Author " + user.getFirstName() + " " + user.getLastName(),FontFactory.getFont(FontFactory.HELVETICA, 20)));
document.add(header);
document.add(by);
}
}
Surely I made appropriate <servlet-mapping> in web.xml
Questions:
How does binding work? From the tutorial I see that there is now linkage from Controller to PDF view
Please, help me to see how to fix my code. I see 404 error code now, and when I remove headers = "Accept=application/pdf" I see it tries to resolve it with FreeMarkerViewResolver
Accept header should be specified by the client (i.e. browser). #RequestMapping annotation should specify corresponding produces attribute to match the request. Basically, the annotation should look like this to match a request with Accept=application/pdf
#RequestMapping(value = "/user_pdf", method = RequestMethod.GET, produces = "application/pdf")
To test that method use something like postman specifying Accept header.
In order to get your pdf view resolved you want to configure a view resolver. In the tutorial it is this part (missing in your snippets):
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>/WEB-INF/spring-pdf-views.xml</value>
</property>
</bean>
This bean declares that you have a /WEB-INF/spring-pdf-views.xml file that contains a configuration for beans responsible for views. However you can configure BeanNameViewResolver to avoid creating additional file (less flexible solution but choice is your):
<bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
Take care to return the exact same view name in controller method as view-bean id (now they are inconsistent). Since
<bean id="PdfRevenueSummary" class="ua.epam.spring.hometask.view.UserPdfView"/>
you are supposed to return
return new ModelAndView("PdfRevenueSummary", "listBooks", userDao.getAll());
Another issue with your example is that probably the bean of UserPdfView class gets instantiated twice: it is declared in xml configuration and maybe picked up by component scan because of #Component annotation.
this is my first post in stackoverflow and also i'm new to spring. this is my question(please don't mind my language)
this is my folder structure of the project in netbeans(i cant post images yet because i have no 10 reputations)
WEB-INF
views
sales
sales_invoice.jsp
sales_order.jsp
sales_order_list.jsp
sales_invoice_list.jsp
purchase
purchase_order.jsp
grn.jsp
accounts
account_list.jsp
web.xml
spring-dispatcher-servlet.xml
I want to invoke jsps inside any directory under view folder using spring i try to do in this way but i was unable to do that under my knowledge. (In the web xml i use InternalViewResolver and also i used annotation to define controllers and requestMappings)
please tell me how to invoke thease jsp using this way or another way because my final project is waiting till your possible responses
Thank You
Here i am assuming that you have created mvc-dispatch-servlate.xml in which you have configuration like this.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
your controller code should be like this if want to access sales > sales_invoice.jsp
#Controller
#RequestMapping("/sales")
public class SalesController{
#RequestMapping(value="/sales-invoice", method = RequestMethod.GET)
public String salesInvoice(ModelMap model) {
model.addAttribute("message", "Hello Spring MVC Framework!");
return "sales/sales_invoice";
}
}
I'm attempting to forward a request received from one Controller to a second Controller using Spring's "forward:" prefix. However, instead of forwarding the request on to the second Controller as I would expect, the request is instead handled by the first Controller over and over again (until I receive a StackOverflowError). This made me think it might be treating the "/app/pong" as a relative path of some sort, but I'm not sure why this would be the case. Am I misunderstanding how "forward:" is supposed to work? Is there something that I'm missing here?
Controllers:
#Controller
public class ControllerOne {
#RequestMapping(value = "/ping", method = RequestMethod.GET)
public String doPing(HttpServletRequest request) {
log.debug("Ping?");
return "forward:/app/pong";
}
}
#Controller
public class ControllerTwo {
#RequestMapping(value = "/pong", method = RequestMethod.GET)
public String doPong(HttpServletRequest request) {
log.debug("Pong!");
return "pong";
}
}
servlet-mapping:
<servlet-mapping>
<servlet-name>test-servlet</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
view resolver:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
I think the problem is about the InternalResourceViewResolver that you configed. Because the inner logic of this viewResolver, it will do a forward automatically, you can config another kinds of viewResolver: UrlBasedViewResolver .
Below is the information I found in official document:
It is also possible to use a special forward: prefix for view names
that are ultimately resolved by UrlBasedViewResolver and subclasses.
This creates an InternalResourceView (which ultimately does a
RequestDispatcher.forward()) around the rest of the view name, which
is considered a URL. Therefore, this prefix is not useful with
InternalResourceViewResolver and InternalResourceView (for JSPs for example). But the prefix can be helpful when you are primarily
using another view technology, but still want to force a forward of a
resource to be handled by the Servlet/JSP engine. (Note that you may
also chain multiple view resolvers, instead.)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I have case insensitive URLS in Spring MVC with annotated mappings
I have Controller having multiple #RequestMapping annotations in it.
#Controller
public class SignUpController {
#RequestMapping("signup")
public String showSignUp() throws Exception {
return "somejsp";
}
#RequestMapping("fullSignup")
public String showFullSignUp() throws Exception {
return "anotherjsp";
}
#RequestMapping("signup/createAccount")
public String createAccount() throws Exception {
return "anyjsp";
}
}
How can I map these #RequestMapping to case insensitive. i.e. if I use "/fullsignup" or "/fullSignup" I should get "anotherjsp". But this is not happening right now. Only "/fullSignup" is working fine.
I've tried extending RequestMappingHandlerMapping but no success. I've also tried AntPathMatcher like the guy mentioned there is another question on this forum but its also not working for #RequestMapping annotation.
Debugging console
Output console when server is up.
I've added two images which shows the problem. I've tried both the solutions mentioned below. The console says that it mapped lowercased URLS but when I request to access a method with lowercase url then it shows that the original map where the values are stored stilled contained MixCase URLS.
One of the approaches in How can I have case insensitive URLS in Spring MVC with annotated mappings works perfectly. I just tried it with combinations of #RequestMapping at the level of controller and request methods and it has worked cleanly, I am just reproducing it here for Spring 3.1.2:
The CaseInsensitivePathMatcher:
import java.util.Map;
import org.springframework.util.AntPathMatcher;
public class CaseInsensitivePathMatcher extends AntPathMatcher {
#Override
protected boolean doMatch(String pattern, String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
return super.doMatch(pattern.toLowerCase(), path.toLowerCase(), fullMatch, uriTemplateVariables);
}
}
Registering this path matcher with Spring MVC, remove the <mvc:annotation-driven/> annotation, and replace with the following, configure appropriately:
<bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"></property>
<property name="validator">
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
</bean>
</property>
</bean>
</property>
<property name="messageConverters">
<list>
<ref bean="byteArrayConverter"/>
<ref bean="jaxbConverter"/>
<ref bean="jsonConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
</list>
</property>
</bean>
<bean name="byteArrayConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean name="jaxbConverter" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean name="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
<bean name="caseInsensitivePathMatcher" class="org.bk.lmt.web.spring.CaseInsensitivePathMatcher"/>
<bean name="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="pathMatcher" ref="caseInsensitivePathMatcher"></property>
</bean>
Or even more easily and cleanly using #Configuration:
#Configuration
#ComponentScan(basePackages="org.bk.webtestuuid")
public class WebConfiguration extends WebMvcConfigurationSupport{
#Bean
public PathMatcher pathMatcher(){
return new CaseInsensitivePathMatcher();
}
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors());
handlerMapping.setPathMatcher(pathMatcher());
return handlerMapping;
}
}
The following simple solution should make #RequestMapping insensitive, whether it annotates a Controller or a method. Biju's solution should work too.
Create this custom HandlerMapping :
public CaseInsensitiveAnnotationHandlerMapping extends DefaultAnnotationHandlerMapping {
#Override
protected Object lookupHandler(String urlPath, HttpServletRequest request)
throws Exception {
return super.lookupHandler(urlPath.toLowerCase(), request);
}
#Override
protected void registerHandler(String urlPath, Object handler)
throws BeansException, IllegalStateException {
super.registerHandler(urlPath.toLowerCase(), handler);
}
}
And add this in your [servlet-name]-servlet.xml :
<bean class="yourpackage.CaseInsensitiveAnnotationHandlerMapping" />
Note: if you don't want two HandlerMapping in your app, you may want to remove <mvc:annotation-driven /> (it instantiates a DefaultAnnotationHandlerMapping).
I'm trying to use MappingJacksonJsonView with Spring 3.0, without success. I don't know what I'm doing wrong, I think the problem is that I don't know how to tell to use the MappingJacksonJsonView to render a request. I tried to use the same name for view name and bean name of MappingJacksonView, but didn't work. I built a sample test application here: https://github.com/stivlo/restjson
In web.xml I've defined ContextLoaderListener and the mapping for dispatcherServlet.
In servlet-context.xml I've added
<mvc:annotation-driven/>
and
<bean name="jsonView"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
In org.obliquid.restjson.web.ToDoList.java I set the logical view name as jsonView.
However, instead of using MappingJacksonJsonView, it looks for a JSP file, according to my JSP mapping.
message /restjson/WEB-INF/jsp/jsonView.jsp
description The requested resource (/restjson/WEB-INF/jsp/jsonView.jsp)
is not available.
What should I change to use MappingJacksonJsonView as a renderer?
UPDATE 1: In following tests I've found that if I add the following to my servlet-context.xml, JSON rendering works, but my other view, rendered as JSP (home) is not working anymore.
<!-- Resolve views based on string names -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
UPDATE 2: I removed the BeanNameViewResolver and changed my ToDoList.java to return directly the Collection to be converted in JSON, instead of ModelAndView, with a #ResponseBody annotation, as follows:
#RequestMapping("/toDoList")
public #ResponseBody List<ToDoItem> test() {
List<ToDoItem> toDoList = new ArrayList<ToDoItem>();
toDoList.add(new ToDoItem(1, "First thing, first"));
toDoList.add(new ToDoItem(1, "After that, do the second task"));
return toDoList;
}
In this way it works. Even though the mapping is even more "magical". It makes me wonder, if a similar renderer exists for XML for instance, how does Spring know which renderer to pick?
Spring will use Accept header sent by the client to return most appropriate view. Here you will find my complete Spring MVC application that returns both JSON and XML.
As you can see, I only needed:
<mvc:annotation-driven />
I also used the same annotations: #RequestMapping to map request to a method and #ResponseBody to tell Spring that what I am returning from the controller is the actual response. It might however need some tweaking/formatting, and here Spring takes care of marshalling your object into most appropriate type like JSON.
You should do it this way:
In your xml file set the following: set
<mvc:annotation-driven />
After it you need to set Jackson serializer:
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
after it you can use it in your Controller:
#RequestMapping(value="/getObjects",method = RequestMethod.POST)
#ResponseBody
public List<MyObject> getCategories(){
List<MyObject> objects = daoService.gettAllObjects();
return objects;
}
Adding the following worked in my case
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0" />
</bean>
So basically we should try to resolve any view as a bean first
you will need to see ContentNegotiatingViewResolver,and set defaultviews property to MappingJacksonJsonView, and #ResponseBody uses HttpMessageConverter to instead of ViewSolver,see the differences between them
http://ufasoli.blogspot.com/2013/08/viewresolver-vs-messageconverter-spring.html