Inject Spring defined propery into controller - spring-mvc

I am trying to inject property with value inside my controller by using Spring Framework servlet.xml config file. My controller starts like this
package lv.lu.meetings.portal.mvc.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
import lv.lu.meetings.domain.jpa.User;
import lv.lu.meetings.domain.jpa.meeting.Attendance;
import lv.lu.meetings.domain.jpa.meeting.Invite;
import lv.lu.meetings.domain.jpa.meeting.InviteStatus;
import lv.lu.meetings.domain.jpa.meeting.Meeting;
import lv.lu.meetings.domain.jpa.notification.Notification;
import lv.lu.meetings.domain.redis.Friend;
import lv.lu.meetings.interfaces.service.NotificationService;
import lv.lu.meetings.interfaces.service.UserService;
import lv.lu.meetings.portal.mvc.WebConst;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Controller for displaying application home page.
*
* Supports multiple tab views: Main, Friends, Notifications, Meetings.
*/
#Controller
public class HomePageController {
// limit meeting count
// defined in meetings-servlet.xml
private String limit;
public String getLimit() {
return limit;
}
public void setLimit(String limit) {
this.limit = limit;
}
My meetings-servlet.xml file is like this
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring Web application configuration file -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<!-- Support for component autowiring -->
<context:component-scan base-package="lv.lu.meetings"/>
<!-- URL mapping for annotation-based Spring Web MVC controllers -->
<bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="loginInterceptor"/>
</list>
</property>
</bean>
<!-- Limit output data -->
<bean id="HomePageController" class="lv.lu.meetings.portal.mvc.controller.HomePageController">
<property name="limit" value="10" />
</bean>
I'm getting error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'urlMapping' defined in ServletContext resource [/WEB-INF/meetings-servlet.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot map handler 'HomePageController' to URL path [/home]: There is already handler of type [class lv.lu.meetings.portal.mvc.controller.HomePageController] mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
It's definitely smth easy to configure, but i am new to Java and Spring Framework itself, so help is appreciated. Thanks!

You are currently creating 2 HomePageController beans. One from
<!-- Limit output data -->
<bean id="HomePageController" class="lv.lu.meetings.portal.mvc.controller.HomePageController">
<property name="limit" value="10" />
</bean>
and the other from
<context:component-scan base-package="lv.lu.meetings"/>
and the #Controller annotation on
#Controller
public class HomePageController {
Assuming you have a #RequestMapping handler method in this class, Spring will try to register it twice and fail since you can't have two handlers for the same URL.
Choose one or the other bean. If you want to go the annotation way, you can inject the value directly
#Value("10")
private String limit;
or use a property placeholder.

You can set the property with the #Value annotation reading a value from a property file (or whatever):
#Value("${my.limit}")
private String limit;
You can also exclude the HomePageController from the component scanning:
<context:component-scan base-package="lv.lu.meetings">
<context:exclude-filter type="regex" expression="HomePageController$"/>
</context:component-scan>

Related

Spring MVC implementation of WebApplicationInitializer

I have already learned how to configure Spring MVC app with XML so I decided to go ahead.
I read documentation about WebApplicationInitializer and minimizing of XML in application configuration. But when I completed all preparations of the sample application I encountered with 404 page.
Further I put snippets of my code, please give me advices how to make #-based approach properly.
Config file:
package com.onet.init;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
#Configuration
#ComponentScan("com.onet")
#EnableWebMvc
public class BaseConfig {
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
Initializer:
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class Initializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(BaseConfig.class);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("*.html");
servlet.setLoadOnStartup(1);
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>oneTest</groupId>
<artifactId>oneTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
Controller:
package com.onet.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class HelloController {
#RequestMapping(value="/hello")
public ModelAndView goToHelloWorld() {
return new ModelAndView("hello-world");
}
}
index.jsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Home page</title>
</head>
<body>
<h1>Home page</h1>
<p>This is a home page.</p>
<p>Say Hello</p>
</body>
</html>
So when I click on "Say Hello" link I get 404.
Entire project you can download from my drop-box.
i just checked the project in your dropbox. it seems to me, the structure of the project is wrong. you mixed maven-scructure with eclipse-structure. When you use maven, you put the webcontent in src/main/webapp... not in WebContent like you did. you can take a look here for more details on this topic.
short version:
move the files from WebContent to src/main/webapp and try again.
long version:
if you run mvn package and extract the resulting *.war from /target directory, you will see it lacks the files from WebContent directory. Maven expect those files to be in src/main/webapp. I assume you started by creating a "Dynamic Web Project" in eclipse. Eclipse expect the resources like *.jsp and co. to be located in WebContent, this is why calling index.jsp work. But when it comes to spring it failes, because hello-world.jsp is not located where it should be.
how to fix:
Start with moving the files from WebContent to src/main/webapp. then run mvn eclipse:eclipse -Dwtpversion=2.0. it will generate the configuration for eclipse (.classpath, .project, etc.). Refresh the project in Eclipse. Now it should work.

Spring MVC - Mapping / to a controller

How do I map the '/' request to a controller? The application's context name is reac and I want to bring up the login page when the context is sent to the server. I have REACController like this:
#Controller
public class REACController {
#RequestMapping(value="/", method=RequestMethod.GET)
public String onLaunch() {
return "LoginPage";
}
}
I face the dreaded 404 error for the context, 'resource /reac/ is not available'. What's the right way to handle requests to '/' through a Controller class?
Are you trying to secure the site? In which case you might be better off hooking up Spring Security into the project and have it manage the URL security for you.
But if you really want to map some view to the / then in your application context you can also add something like this
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!--facilitates mapping of Dispatcher Servlet to /-->
<mvc:default-servlet-handler/>
<mvc:view-controller path="/" view-name="login"/>
</beans>
this will forward the / requests to the login view using parameterizable view controller
Still unsure of the reason why you would do something like this as Filter would be a better option even if you were wanting to do login/security check without Security frameworks.
Edit: here is how you can do it through controller itself
#RequestMapping("/")
#Controller
public class MyController {
#RequestMapping()
public String showMeTheLoginPage() {
return "redirect:/login.html";
}
}

Spring MVC 3, Interceptor on all excluding some defined paths

Is it possible to apply an interceptor to all controllers and actions, except some that are defined?
Just to be clear, I am not interested in applying an interceptor on a list of defined ones. I want to define those to exclude.
Thanks!
Since Spring 3.2 they added that feature with the tag
mvc:exclude-mapping
See this example from the Spring documentation:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor" />
</mvc:interceptor>
Here's the link to the doc
For java based configuration, from the docs
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
When configuring an interceptor, you can specify a path pattern. The interceptor will be invoked only for controllers which the path matches the interceptor path pattern.
ref: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-config-interceptor
But as you probably noticed it, the path pattern doesn't support exclusion.
So I think the only way is to code a blacklist of paths inside the interceptor. When the interceptor is invoked, retrieve the HttpServletRequest.getRequestURI() and check if the path is blacklisted or not.
You can build the blacklist inside a #PostConstruct annotated method of the interceptor, and so get the blacklisted path from a property file for instance.

Default formView for SimpleFormController?

Firstly I would like to say that I am quite new to Spring (in particular the MVC framework), and just trying to understand how everything works so please go easy on me.
I'm playing around with a dummy application that I've created, and I've created a simple login form that users can access via the /login.html bean. The bean definition is as follows:
<bean name="/login.html" class="test.controller.LoginController">
<property name="successView" value="list_messages.html" />
<property name="commandClass" value="test.domain.Login" />
<property name="commandName" value="login" />
</bean>
(the Login class is a simple object containing a username and password field with appropriate getters and setters).
The LoginController class does virtually nothing for now:
public class LoginController extends SimpleFormController
{
#Override
protected ModelAndView onSubmit(Object command, BindException errors) throws Exception
{
return new ModelAndView(new RedirectView(getSuccessView()));
}
}
Now I have one view resolver in my bean definition file, which goes as follows:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
To support my Login form I have a login.jsp file in my jsp directory.
My question is as follows: why does accessing /login.html redirect me to login.jsp? I have not specified a formView property for my form, so how does the view resolver know to redirect me to login.jsp?
Thanks in advance for any help!
Joseph.
When you do not specify The logical view name, Spring relies on DefaultRequestToViewNameTranslator, which is installed by default. So if your request is something like
http://127.0.0.1:8080/app/<LOGICAL_NAME_EXTRACTED_BY_VIEW_NAME_TRANSLATOR_GOES_HERE>.html
Have you seen <LOGICAL_NAME_EXTRACTED_BY_VIEW_NAME_TRANSLATOR> ??? So if your request is
http://127.0.0.1:8080/app/login.html
The logical name extracted by ViewNameTranslator is login which is supplied To viewResolver and Translated To
/jsp/login.jsp
Nothing else

spring roo excel view

I am trying to output an Excel file as the view in Spring Roo 1.0.2
What is the quickest way to do this?
(Do I have to add new mapping etc?) At the moment I am using the default Roo AjaxUrlBasedViewResolver.
Thanks
I don't think there's a specific "Roo" way of doing this, but Spring MVC does have an AbstractExcelView class that uses Apache POI and doesn't cause any problems - I think it's the best you can hope for.
First create a view class that extends AbstractExcelView and implements the buildExcelDocument method:
import org.springframework.web.servlet.view.document.AbstractExcelView;
public class XlsView extends AbstractExcelView {
#Override
protected void buildExcelDocument(
Map<String, Object> model, HSSFWorkbook workbook,
HttpServletRequest request, HttpServletResponse response) throws Exception {
//Apache POI code to set up the HSSFWorkbook goes here
response.setHeader("Content-Disposition", "attachment; filename=\"file.xls\"");
}
}
Then add the following to your webmvc-config.xml. I don't think the position matters, but I have it below the section where my TilesConfigurer is listed:
<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/views/views-excel.xml"/>
</bean>
Finally create views-excel.xml with the following in it:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean name="XlsView" class="com.your.package.XlsView"/>
</beans>

Resources