Search code examples
javaspringspring-mvcservlet-filterstransactional

how can i use @Transactional and sessionFactory bean in servlet filter with spring


web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  <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.phoenix.config.ApplicationConfig</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>
        org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </init-param>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.phoenix.config.MvcConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <filter>
    <filter-name>authenticationFilter</filter-name>
    <filter-class>
    com.phoenix.authentication.AuthenticationFilter
    </filter-class>
  </filter>
  <filter>
    <filter-name>authorizationFilter</filter-name>
    <filter-class>
    com.phoenix.authentication.AuthorizationFilter
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>authenticationFilter</filter-name>
    <url-pattern>/login/*</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>authorizationFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/ErrorHandler</location>
  </error-page>

  <servlet>
    <servlet-name>PhoenixExceptionHandler</servlet-name>
    <servlet-class>com.phoenix.authentication.PhoenixExceptionHandler</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>PhoenixExceptionHandler</servlet-name>
    <url-pattern>/ErrorHandler</url-pattern>
  </servlet-mapping>
</web-app>

context configuration class:

package com.phoenix.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.phoenix" })
@PropertySource(value = { "classpath:hibernate.properties" })
public class ApplicationConfig {

    @Autowired
    private Environment environment;

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan("com.phoenix.data.entity");
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        return properties;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(s);
        return txManager;
    }
    @Bean
    public HttpHeaders responseHeader(){
    HttpHeaders responseTypeHeader = new HttpHeaders();
    responseTypeHeader.add("Content-Type", "application/json; charset=utf-8");
    return responseTypeHeader;
    }
}

dispatcher configuration class:

package com.phoenix.config;

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.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.phoenix")
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
        .addResourceLocations("/WEB-INF/resources/");
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        registry.viewResolver(viewResolver);
    }


}

filter class:

    package com.phoenix.authentication;

import java.io.IOException;
import java.util.List;

import javax.persistence.Query;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.phoenix.data.entity.UserInfo;


public class AuthenticationFilter implements Filter {

    @Autowired
    SessionFactory sessionFactory;



    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    if(httpRequest.getParameter("username") != null 
            && httpRequest.getParameter("password") != null)
    {
        String username = httpRequest.getParameter("username");
        String password = httpRequest.getParameter("password");
        boolean rememberMe = false;
        if(httpRequest.getParameter("rememberMe")!= null)
            rememberMe = httpRequest.getParameter("rememberMe").equals("on");

        UserInfo user = getUserInfo(username, password);
         System.out.print(user+"\n"+rememberMe);

    }
    chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

    public UserInfo getUserInfo(String username, String password)
    {
        UserInfo user=null;
        Session session=sessionFactory.getCurrentSession();
        Query query = session.createQuery("FROM UserInfo WHERE"
                + " UserInfo.username = :xusername AND UserInfo.password = :xpassword");
        query.setParameter("xusername",username);
        query.setParameter("xpassword",password);
        List list=query.getResultList();
        if (list.size()>0)
            user=(UserInfo)list.get(0);
        return user;
    }

}

exception :

Aug 13, 2016 5:02:39 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/phoenix] threw exception
java.lang.NullPointerException
    at com.phoenix.authentication.AuthenticationFilter.getUserInfo(AuthenticationFilter.java:65)
    at com.phoenix.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:50)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

I did a little search and The solution org.springframework.web.filter.DelegatingFilterProxy came. But this solution is a little vague to me. I am grateful if explain.


Solution

  • You can't use @Autowired in your AuthenticationFilter because it is not instantiated in Spring Container. It is instantiated in the Web Application Container so sessionFactory will always be null thus the NullPointerException.

    But you can get the WebApplicationContext inside of a Filter by using WebApplicationContextUtils.getRequiredWebApplicationContext which is provided by Spring.

    So with the modified AuthenticationFilter.init method as below, your filter should work.

    public class AuthenticationFilter implements Filter {
    
        SessionFactory sessionFactory;   
    
        @Override
        public void destroy() {
            this.sessionFactory.close();
            this.sessionFactory = null;    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if(httpRequest.getParameter("username") != null 
                && httpRequest.getParameter("password") != null)
        {
            String username = httpRequest.getParameter("username");
            String password = httpRequest.getParameter("password");
            boolean rememberMe = false;
            if(httpRequest.getParameter("rememberMe")!= null)
                rememberMe = httpRequest.getParameter("rememberMe").equals("on");
    
            UserInfo user = getUserInfo(username, password);
             System.out.print(user+"\n"+rememberMe);
    
        }
        chain.doFilter(request, response);
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
            this.sessionFactory = ctx.getBean(SessionFactory.class);
        }
    
        public UserInfo getUserInfo(String username, String password)
        {
            UserInfo user=null;
            Session session=sessionFactory.getCurrentSession();
            Query query = session.createQuery("FROM UserInfo WHERE"
                    + " UserInfo.username = :xusername AND UserInfo.password = :xpassword");
            query.setParameter("xusername",username);
            query.setParameter("xpassword",password);
            List list=query.getResultList();
            if (list.size()>0)
                user=(UserInfo)list.get(0);
            return user;
        }
    
    }