I am starting to use Spring Security. I've always implement my own security. So this is new for me. I've followed few tutorials. I've read even Pro Spring Security Book (unfortunatelly everythink was configured with xml).
I would like to write Rest Api base on Spring and Spring Security. I will have to main routes to my api. First is for anonymous users, and this goes as follow:
http://localhost:8080/cms/services/anonymous/**
The second url route is for authenticated users:
http://localhost:8080/cms/services/authenticated/**
When I hit url like this:
http://localhost:8080/cms/services/authenticated/testService/getInfo
I should get http answer 401 Unauthorized. But in my current project I am getting 200 Ok. What I am doing wrong?
Here is my config:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
#EnableWebMvc
#Configuration
#ComponentScan("pl.korbeldaniel.cms.server")
#Import({ SecurityConfig.class })
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean(name = "messageSource")
public ReloadableResourceBundleMessageSource getMessageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
resource.setBasename("classpath:messages");
resource.setDefaultEncoding("UTF-8");
return resource;
}
#Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
converters.add(new MappingJackson2HttpMessageConverter());
}
}
#Configuration
#ComponentScan("pl.korbeldaniel.cms.server")
#EnableWebSecurity
// #EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableGlobalMethodSecurity(securedEnabled = true)
#PropertySource("classpath:jdbc.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
Environment env;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("temporary").password("temporary").roles("ADMIN").and().withUser("user").password("userPass").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().//
antMatchers("/cms/services/authenticated/**").authenticated().//
antMatchers("/cms/services/anonymous/**").anonymous().and().//
csrf().disable();
}
#Bean
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
}
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- Name the application -->
<display-name>Rest GWT</display-name>
<description>This is web-project for cms</description>
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/action-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>cms.html</welcome-file>
</welcome-file-list>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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">
<!-- Scans the classpath of this application for #Components to deploy as
beans -->
<context:component-scan base-package="pl.korbeldaniel.cms" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<!-- <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /> -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
</list>
</property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- registers all of Spring's standard post-processors for annotation-based configuration -->
<context:annotation-config />
</beans>
Please help.
You should register your SecurityConfig in AbstractAnnotationConfigDispatcherServletInitializer, like following:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Related
I have faced a real proglem and solved it, but couldn't figure out what has been happened.
I defined transactionManager and sessionFactory bean in root context and my dao class with #Transactional methods in dispatcher context. And that's all. When I was trying to use getCurrentSession() in dao, I was getting "could not obtain a current session".
But, as I can remember, dispatcher context is aware about root context and has access to all beans in root context.
Can somebody explain me, why do not transactions open before #Transactional method if transactionManager and sessionFactory were defined in root context and class with #Transactional in child context?
Database config class
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
public LocalSessionFactoryBean sessionFactory() throws IOException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(getDatabaseDataSource());
sessionFactoryBean.setPackagesToScan("com.varguss.domain");
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL57Dialect");
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.connection.useUnicode", "true");
properties.setProperty("hibernate.connection.characterEncoding", "utf8");
properties.setProperty("hibernate.connection.charSet", "utf8");
sessionFactoryBean.setHibernateProperties(properties);
return sessionFactoryBean;
}
#Bean
#Autowired
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
#Bean(name = "dataSource", destroyMethod = "close")
public BasicDataSource getDatabaseDataSource() throws IOException {
BasicDataSource databaseDataSource = new BasicDataSource();
Properties properties = new Properties();
ClassPathResource propertiesFileResource = new ClassPathResource("database.properties");
properties.load(propertiesFileResource.getInputStream());
databaseDataSource.setDriverClassName(properties.getProperty("driverClassName"));
databaseDataSource.setUrl(properties.getProperty("url"));
databaseDataSource.setUsername(properties.getProperty("username"));
databaseDataSource.setPassword(properties.getProperty("password"));
return databaseDataSource;
}
}
DAO class
#Repository
#Transactional
public class DbComputerPartDAO implements ComputerPartDAO {
private SessionFactory sessionFactory;
private Strategy strategy;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
strategy = StrategyFactory.getStrategy(StrategyType.ALL, sessionFactory);
}
#Override
#Transactional(readOnly = true)
public List<ComputerPart> allParts() {
return sessionFactory.getCurrentSession().createQuery("FROM ComputerPart part ORDER BY part.count DESC", ComputerPart.class).getResultList();
}
#Override
#Transactional(readOnly = true)
public ComputerPart part(Long id) {
return sessionFactory.getCurrentSession().find(ComputerPart.class, id);
}
#Override
public void save(String name, boolean isImportant, Long count) {
sessionFactory.getCurrentSession().saveOrUpdate(new ComputerPart(name, isImportant, count));
}
#Override
public void remove(Long id) {
ComputerPart computerPart = part(id);
if (computerPart != null)
sessionFactory.getCurrentSession().delete(computerPart);
}
#Override
#Transactional(readOnly = true)
public List<ComputerPart> byImportance(boolean isImportant) {
return sessionFactory.getCurrentSession().createQuery("FROM ComputerPart part WHERE part.isImportant ORDER BY part.count DESC", ComputerPart.class).getResultList();
}
#Override
public void updateImportance(Long id, boolean isImportant) {
ComputerPart computerPart = part(id);
if (computerPart != null)
computerPart.setImportant(isImportant);
}
#Override
public void updateName(Long id, String name) {
ComputerPart computerPart = part(id);
if (computerPart != null)
computerPart.setName(name);
}
#Override
public void updateCount(Long id, Long count) {
ComputerPart computerPart = part(id);
if (computerPart != null)
computerPart.setCount(count);
}
#Override
#Transactional(readOnly = true)
public List<ComputerPart> page(int pageNumber) {
return strategy.page(pageNumber);
}
#Override
#Transactional(readOnly = true)
public List<ComputerPart> parts() {
return strategy.parts();
}
#Override
#Transactional(readOnly = true)
public Integer lastPageNumber() {
return strategy.lastPageNumber();
}
#Override
#Transactional(readOnly = true)
public List<ComputerPart> search(String partOfName) {
return strategy.search(partOfName);
}
#Override
public void changeStrategy(StrategyType strategyType) {
this.strategy = StrategyFactory.getStrategy(strategyType, sessionFactory);
}
}
Root context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:annotation-config/>
<bean class="com.varguss.config.DatabaseConfig"/>
</beans>
Child context
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-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">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /resources/views/ directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/views/" p:suffix=".jsp" />
<context:component-scan base-package="com.varguss.dao" />
<context:component-scan base-package="com.varguss.controller" />
</beans:beans>
When using hierarchical application context (a parent and child) the child can see the beans from the parent. So it can detect the EntityManagerFactory and the PlatformTransactionManager.
However when using things like AOP that only applies to beans in the same application context as the AOP is defined in. So AOP defined in the parent context only applies to beans in the parent context, not to beans in the child contexts.
So in your case the #EnableTransactionManagement is in the parent context but in there there aren't any beans with #Transactional, those are in the child context. So either create an #Configuration which enables transactions there or use <tx:annotation-driven /> in your XML configuration.
I am at my wits end trying to debug this issue. Basically, I have a mvc application where I have a BusinessManagerImpl class which has 2 DAOs (UserDao and ProductDao) and am using JDBC with a connection pool instead of an ORM. Database is mySQL with InnoDb engine. RestUserController is the calling class of BusinessManagerImpl.
BusinessManagerImpl.addUser() has been annotated with #Transactional annotation. I have also tried annotating #Transactional at the class level but doesn't seem to make a difference. Both DAOs are also annotated as such.
BusinessManagerImpl.addUser() uses UserDao to insert a user but a subsequent call to ProductDao.getAllProducts() throws a RuntimeException on purpose to cause the transaction to rollback. My expectation is that the user should not have been inserted as a RuntimeException has occurred and the transaction would have been rolledback but I have checked my database and the new user is inserted.
I have tried with throwing a checked exception and using the "rollback for" parameter of #Transactional annotation but it doesn't work. I have also tried different values of propagation like Propagation.Required but doesn't seem to have an effect on rolling back the transaction. I have tried searching on stackoverflow and google but came up with nothing that could help. Can someone please shed some light on what I am doing wrong or missing something? Thank you. Below is my setup:
application-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<context:component-scan base-package="someproject" />
<!-- <context:annotation-config /> -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/somedb" />
<property name="username" value="xxx" />
<property name="password" value="yyy" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
BusinessManagerImpl class
#Service
public class BusinessManagerImpl implements BusinessManager{
#Autowired
private UserDao userDao;
#Autowired
private ProductDao productDao;
....
#Override
#Transactional(propagation=Propagation.REQUIRED)
public User addUser(User user) throws Exception {
// TODO Auto-generated method stub
User tempUser = userDao.addUser(user);
productDao.getAllProducts();
return tempUser;
}
UserDaoImpl class
#Service
public class UserDaoImpl implements UserDao {
private DataSource dataSource;
#Autowired
public UserDaoImpl(DataSource dataSource) {
super();
setDataSource(dataSource);
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
private JdbcTemplate getJdbcTemplate(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate;
}
...
#Override
#Transactional(propagation=Propagation.MANDATORY)
public User addUser(final User user) {
KeyHolder holder = new GeneratedKeyHolder();
final String sql = "insert into user (username, password) "
+ " VALUES (?, ?)";
getJdbcTemplate().update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS);
int index = 1;
ps.setString(index++, user.getUsername());
ps.setString(index++, user.getPassword());
return ps;
}
}, holder);
int seq = holder.getKey().intValue();
user.setSeq(seq);
return user;
}
ProductDaoImpl class
#Service
public class ProductDaoImpl implements ProductDao {
private DataSource dataSource;
#Autowired
public ProductDaoImpl(DataSource dataSource) {
super();
setDataSource(dataSource);
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
#Transactional(propagation=Propagation.MANDATORY)
public List<Product> getAllProducts() throws Exception {
if(true)
throw new RuntimeException("on purpose");
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
List<Product> products = jdbcTemplate.query(
"select * from product",
new ProductRowMapper());
return products;
}
RestUserController class
#RestController
public class RestUserController {
private static Logger logger = LoggerFactory.getLogger(RestUserController.class);
#Autowired
private BusinessManager businessManager;
#RequestMapping(value = "/adduser", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> createEmployee(#RequestBody User user)
{
logger.debug("adding user:"+user);
User addedUser=null;
try {
addedUser = businessManager.addUser(user);
return new ResponseEntity(addedUser, HttpStatus.CREATED);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>Spring3 MVC Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>spring-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-web</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
spring-web-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="someproject" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:annotation-driven />
</beans>
I find use of #Service annotation on Dao Implementation class weird. Try replacing them with #Repository and adding rollbackFor = {Exception.class} to all of your transactional annotations.
For your 2 application contexts configs, you have to specify the base-package differently. Do not let the web application context scan DAO package.
I'm making a simple project for school but I'm stuck.
I have a bean FavoriteService that I need to address. However when autowiring the bean in my servlet I keep getting a Null Pointer Exception and I can't figure out why.
FavoriteService
public class FavoriteService {
#Autowired
private Users users;
public boolean checkLogin(String username, String password) {
return users.login(username, password);
}
public void addUser(String rootUsername, String rootPassword, String username, String password)
{
if(rootUsername.equals("root") && rootPassword.equals("rootpasswd")) users.addUser(username, password);
}
public List<String> getFavorites(String username, String password)
{
List<String> favorites;
if(checkLogin(username, password))
{
favorites = users.getFavorites(username);
} else {
favorites = new ArrayList<String>();
}
return favorites;
}
public void addFavorite(String username, String password, String favorite)
{
if(checkLogin(username, password))
{
users.addFavorite(username, favorite);
}
}
public void removeFavorite(String username, String password, String favorite)
{
if(checkLogin(username, password))
{
users.removeFavorite(username, favorite);
}
}
}
Servlet
public class LoginServlet extends HttpServlet {
#Autowired
private FavoriteService favoriteService;
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(favoriteService);
if(favoriteService.checkLogin(username, password))
{
resp.sendRedirect("root.jsp");
} else {
resp.sendRedirect("index.jsp");
}
}
}
springservlet-servlet
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="be.kdg.prog4.tdd"/>
<bean name="userDao" class="be.kdg.prog4.tdd.UserDaoWithMap" scope="singleton" />
<bean name="users" class="be.kdg.prog4.tdd.Users" scope="singleton" />
<bean name="favoriteService" class="be.kdg.prog4.tdd.FavoriteService" scope="singleton" />
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".*"/>
</bean>
</beans>
Web.xml
<web-app schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>TDD oefening</display-name>
<servlet>
<servlet-name>springservlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springservlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>be.kdg.prog4.tdd.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
If you need any more info feel free to ask.
Thanks.
EDIT:
I solved it by doing this in the servlet init
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
}
If you are calling LoginServlet you are not going through Spring. You mapped it directly in your web.xml and your set let container is initializing your class without going through Spring and the autowired does not work. You need the access the server through a mapping of springservlet.
The Servlet is not initialized by Spring and therefore the #Autowired fields are not getting initialized by Spring.
Instead of using #Autowired you can override the Servlet init() method and get the Spring web context and use its getBean method to get your bean.
This is how you can get the Spring context in your init method:
ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
I'm working on an open source projet and i have issues with my application.
When multiple users use the app, one users can get another one's data ( the server response).
my beans are request and session scoped and my controller request scoped.
When starting tomcat, beans are created 3x times.
I've read lot of documentations and try playing with scopes and nothing.
I must be missing something. Thanks for your help.
My controller:.
#Controller
#Scope("request")
public class SpinalToolboxWebController {
#Autowired
private FileOperationsService fileOperationsService;
#Autowired
private ServerResponse serverResponse;
#Autowired
private SoftwareCommunicationService softwareCommunicationService;
#Autowired
private StringBuffer stringBuffer;
#Autowired
private UserEnvironmentService userEnvironmentService;
#RequestMapping(value = "/")
public ModelAndView home(){
System.out.println("Passing throught home controller");
return new ModelAndView(SpinalToolBoxWebConstants.VIEW_HOME, "result", "command submitted : ");
}
#RequestMapping(value="/upload", method = RequestMethod.POST, produces="application/json")
public #ResponseBody
ServerResponse handleUploadedFiles(#RequestParam(value = "file") MultipartFile file,
#RequestParam(value="token") String token)throws IOException {
System.out.println("Passing throught upload controller");
if(!fileOperationsService.isUploadedFileExtensionAllowed(file.getOriginalFilename()))
{
serverResponse.setUndefinedResponse();
return serverResponse;
}
if(fileOperationsService.uploadFile(file, token)){
serverResponse.setResponse(file, softwareCommunicationService.generateRawAndHeader(file));
}
else{
serverResponse.setUndefinedResponse();
}
return serverResponse;
}
}
Here is my java config file:
#Configuration
public class SpinalToolBoxWebConfig {
#Value("${uploadPath}") private String uploadPathFromPropertyFile;
//Resolve view name to jsp
#Bean
ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("WEB-INF/view/");
resolver.setSuffix(".jsp");
/*resolver.setExposeContextBeansAsAttributes(true);
resolver.setExposedContextBeanNames("configProperties");*/
return resolver;
}
#Bean
#Scope("request")
#ScopedProxy
public FileOperationsController fileOperationsController(){
return new FileOperationsController();
}
#Bean
#Scope("request")
#ScopedProxy
public LogController logController() {return new LogController();}
#Bean
#Scope("request")
#ScopedProxy
public ServerResponse serverResponse(){return new ServerResponse();}
#Bean
#Scope("request")
#ScopedProxy
public SoftwareCommunicationController softwareCommunicationController() {return new SoftwareCommunicationController();}
#Bean
#Scope("prototype")
public CommonsMultipartResolver multipartResolver() throws java.io.IOException{
Resource fileSystemResource = new FileSystemResource(uploadPathFromPropertyFile);
System.out.println(uploadPathFromPropertyFile);
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setUploadTempDir(fileSystemResource);
commonsMultipartResolver.setMaxUploadSize(-1); //no limit to file upload size
return commonsMultipartResolver;
}
#Bean
#Scope("request")
#ScopedProxy
public StringBuffer stringBuffer(){ return new StringBuffer();}
#Bean
#Scope("session")
#ScopedProxy
public UserEnvironment userEnvironment(){
return new UserEnvironment();
}
#Bean
#Scope("request")
#ScopedProxy
public UserEnvironmentController userEnvironmentController(){return new UserEnvironmentController(); }
}
Here is my servlet-context.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:properties id="configProperties" location="WEB-INF/config.properties" />
<context:property-placeholder properties-ref="configProperties" />
<context:component-scan base-package="spinalToolBoxWeb"/>
<mvc:annotation-driven/>
<mvc:resources mapping="/resources/**" location="${resources}" />
<mvc:resources mapping="/external/**" location="file:///${uploadPath}" />
</beans>
Here is my web xml file:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>spinalToolBoxServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spinalToolBoxServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spinalToolBoxServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener> </web-app>
My application, which make use of Spring Security, is crashing during the startup. Tracking the execution of the application, I could verify the error is happening in method onStartup from class MainWebAppInitializer:
public class MainWebAppInitializer implements WebApplicationInitializer {
/**
* Register and configure all Servlet container components necessary to power the web application.
*/
#Override
public void onStartup(final ServletContext sc) throws ServletException {
// Create the 'root' Spring application context
final AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.scan("com.spring.web.config");
// Manages the lifecycle of the root application context
sc.addListener(new ContextLoaderListener(root));
// Handles requests into the application
final ServletRegistration.Dynamic appServlet = sc.addServlet("horariolivreapp", new DispatcherServlet(new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
final Set<String> mappingConflicts = appServlet.addMapping("/");
if (!mappingConflicts.isEmpty()) {
throw new IllegalStateException("'appServlet' could not be mapped to '/' due " + "to an existing mapping. This is a known issue under Tomcat versions " + "<= 7.0.14; see https://issues.apache.org/bugzilla/show_bug.cgi?id=51278");
}
}
}
More specificly, the error occurs in the line
appServlet.setLoadOnStartup(1)
where a NullPointerException is triggered. Follow it is my configuration files, for reference:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>HorarioLivre</display-name>
<!-- Spring MVC -->
<servlet>
<servlet-name>horariolivreapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>horariolivreapp</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.spring.web.config</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
horariolivreap-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.horariolivreapp.controller" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
webSecurityConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<http use-expressions="true">
<intercept-url pattern="/login*" access="isAnonymous()" />
<intercept-url pattern="/**" access="isAuthenticated()"/>
<form-login
login-page='/form_login.html'
login-processing-url="/usuario_login.html"
default-target-url="/usuario_start.html"
authentication-failure-url="/form_login"
always-use-default-target="true"/>
<logout logout-success-url="/login.html" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user1" password="user1Pass" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Looking in this files, someone can find the reason for this problem?
UPDATE 1
This is my Controller (DispatcherServlet) class:
package com.horariolivreapp.controller;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.horariolivreapp.core.Sessao;
import com.horariolivreapp.data.UsuarioDAO;
#Controller
public class HorarioLivreController {
private Sessao sessao;
#RequestMapping("/cadastra_evento")
public ModelAndView cadastra_evento() {
return null;
}
#RequestMapping(value="/listagem_evento", method=RequestMethod.GET)
public ModelAndView listagem_evento() {
return null;
}
#RequestMapping("/cadastra_horario")
public ModelAndView cadastra_horario() {
return null;
}
#RequestMapping("/listagem_horario")
public ModelAndView listagem_horario() {
return null;
}
#RequestMapping("/cadastra_usuario")
public ModelAndView cadastra_usuario() {
return null;
}
#RequestMapping("/listagem_usuario")
public ModelAndView listagem_usuario() {
return null;
}
#RequestMapping("/cadastra_tipo")
public ModelAndView cadastra_tipo() {
return null;
}
#RequestMapping("/cadastra_campo")
public ModelAndView cadastra_campo() {
return null;
}
#RequestMapping("/cadastra_autorizacao")
public ModelAndView cadastra_autorizacao() {
return null;
}
#RequestMapping("/usuario_perfil")
public ModelAndView usuario_perfil() {
return null;
}
#RequestMapping("/usuario_config")
public ModelAndView usuario_config() {
return null;
}
#RequestMapping(value="/usuario_login", method=RequestMethod.POST)
public ModelAndView usuario_login(#RequestParam("j_username") String username, #RequestParam("j_password") String password) {
UsuarioDAO usuario = new UsuarioDAO(username, password);
if(usuario.getUsuario() != null) {
this.sessao = new Sessao(usuario.getUsuario());
}
return new ModelAndView("usuario_start","usuario",usuario.getUsuario());
}
#Configuration
#ImportResource({ "classpath:webSecurityConfig.xml" })
public class SecSecurityConfig {
public SecSecurityConfig() {
super();
}
}
}
An NPE at that point means that appServlet is null, which in turn means that sc.addServlet(...) returned null.
The Javadoc for addServlet says this:
"Returns: a ServletRegistration object that may be used to further configure the given servlet, or null if this ServletContext already contains a complete ServletRegistration for a servlet with the given servletName or if the same servlet instance has already been registered with this or another ServletContext in the same container."
Now you are instantiating the Servlet object at that point, so it cannot have previously been registered. But there could be another Servlet with the same name ... and that's the probable immediate cause of the problem.
And in fact, it looks like you have already registered a servlet called "horariolivreapp" by declaring it in the web.xml file.