0

我正在为我创建的数据库编写一个小的 Web 界面。数据库访问是通过 Hibernate 完成的,但它也使用 Spring 来注入 DAO 的实例(这反过来又注入了 SessionFactory)。我在嵌入式 Jetty 服务器上测试 Web 界面。独立使用时一切正常:我可以从数据库项目中获取数据库中的内容,我可以在 Jetty 服务器上使用 Wicket 运行网页,我什至设法让 Spring 为 WicketTester 工作,这有点痛苦在屁股。但是现在当我尝试从数据库中获取某些内容时(通过单击网页上的某个按钮),我收到一条错误消息:

java.lang.NullPointerException
     at nl.ru.cmbi.pdbeter.core.controller.DAO.GenericDAO.getCurrentSession(GenericDAO.java:37)

不知何故,应该在 DAO 中注入的 sessionFactory 没有被注入。我在 Wicket 模块的 applicationContext.xml 中定义了 DAO bean,但我认为只要它看到 SessionFactory 的 @Autowired,它就会在该项目的 spring.xml 文件中查找,但显然不是。我将在下面放置一些代码来展示各个部分的工作情况。

检票应用:

@Service
public class WicketApplication extends WebApplication {
    @SpringBean
    private IPDBEntryDAO    pdbEntryDAO;

    public IPDBEntryDAO getPdbEntryDAO() {
        return pdbEntryDAO;
    }

    public void setPdbEntryDAO(IPDBEntryDAO pdbEntryDAO) {
        this.pdbEntryDAO = pdbEntryDAO;
    }

    /**
     * @see org.apache.wicket.Application#getHomePage()
     */
    @Override
    public Class<HomePage> getHomePage() {
        return HomePage.class;
    }

    /**
     * @see org.apache.wicket.Application#init()
     */
    @Override
    public void init() {
        super.init();

        new ClassPathXmlApplicationContext("applicationContext.xml").getAutowireCapableBeanFactory().autowireBean(this);
    }

    public void setupInjector() {
        getComponentInstantiationListeners().add(new SpringComponentInjector(this));
    }
}

启动嵌入式 Jetty 服务器的类(复制自 Wicket 快速入门):

public class Start {
    public static void main(String[] args) throws Exception {
        int timeout = (int) Duration.ONE_HOUR.getMilliseconds();

        Server server = new Server();
        SocketConnector connector = new SocketConnector();

        // Set some timeout options to make debugging easier.
        connector.setMaxIdleTime(timeout);
        connector.setSoLingerTime(-1);
        connector.setPort(8080);
        server.addConnector(connector);

        // check if a keystore for a SSL certificate is available, and
        // if so, start a SSL connector on port 8443. By default, the
        // quickstart comes with a Apache Wicket Quickstart Certificate
        // that expires about half way september 2021. Do not use this
        // certificate anywhere important as the passwords are available
        // in the source.

        Resource keystore = Resource.newClassPathResource("/keystore");
        if (keystore != null && keystore.exists()) {
            connector.setConfidentialPort(8443);

            SslContextFactory factory = new SslContextFactory();
            factory.setKeyStoreResource(keystore);
            factory.setKeyStorePassword("wicket");
            factory.setTrustStoreResource(keystore);
            factory.setKeyManagerPassword("wicket");
            SslSocketConnector sslConnector = new SslSocketConnector(factory);
            sslConnector.setMaxIdleTime(timeout);
            sslConnector.setPort(8443);
            sslConnector.setAcceptors(4);
            server.addConnector(sslConnector);

            System.out.println("SSL access to the quickstart has been enabled on port 8443");
            System.out.println("You can access the application using SSL on https://localhost:8443");
            System.out.println();
        }

        WebAppContext bb = new WebAppContext();
        bb.setServer(server);
        bb.setContextPath("/");
        bb.setWar("src/main/webapp");

        // START JMX SERVER
        // MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
        // MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer);
        // server.getContainer().addEventListener(mBeanContainer);
        // mBeanContainer.start();

        server.setHandler(bb);

        try {
            System.out.println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP");
            server.start();
            System.in.read();
            System.out.println(">>> STOPPING EMBEDDED JETTY SERVER");
            server.stop();
            server.join();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

web.xml 文件:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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"
    version="2.5">

    <display-name>web-interface</display-name>

    <!--
        There are three means to configure Wickets configuration mode and they 
        are tested in the order given.

        1) A system property: -Dwicket.configuration 
        2) servlet specific <init-param> 
        3) context specific <context-param>

        The value might be either "development" (reloading when templates change) or 
        "deployment". If no configuration is found, "development" is the default. -->

    <filter>
        <filter-name>wicket.web-interface</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationClassName</param-name>
            <param-value>nl.ru.cmbi.pdbeter.WicketApplication</param-value>
        </init-param>
        <init-param>
            <param-name>applicationFactoryClassName</param-name>
            <param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
        </init-param>
        <init-param>
            <param-name>applicationBean</param-name>
            <param-value>wicketApplication</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>wicket.web-interface</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- The SpringWebApplicationFactory will need access to a Spring Application context, configured like this... -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

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

applicationContext.xml 文件:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
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/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <!--
    <context:component-scan base-package="nl.ru.cmbi.pdbeter" />
    -->

    <!-- setup wicket application -->
    <bean id="wicketApplication" class="nl.ru.cmbi.pdbeter.WicketApplication">
        <property name="pdbEntryDAO" ref="pdbEntryDAO"/>
    </bean>

    <bean id="pdbEntryDAO" class="nl.ru.cmbi.pdbeter.core.controller.DAO.PDBEntryDAO" />
</beans>

来自数据库模块的 DAO 类的一部分:

public class GenericDAO<I> implements IGenericDAO<I> {
    private Class<I>        persistentClass;

    @Autowired
    private SessionFactory  sessionFactory;

    @SuppressWarnings("unchecked")
    public GenericDAO() {
        persistentClass = (Class<I>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }


    protected Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

数据库模块使用的spring.xml文件:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:task="http://www.springframework.org/schema/task"
    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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">


    <context:component-scan base-package="nl.ru.cmbi.pdbeter" />

    <!-- Transaction Manager -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven />

    <!-- Session Factory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="configLocation" value="hibernate.cfg.xml" />
        <property name="packagesToScan" value="nl.ru.cmbi.pdbeter.core.model.domain" />
    </bean>
</beans>

很抱歉发布了这么多代码,但我想如果我不这样做,我可能会泄露重要的东西。

有谁知道如何确保 Wicket 模块和数据库模块的所有内容都被注入?

4

0 回答 0