目前我正在尝试为我工作的学校项目设置Spring MVC Controller测试。通常我在像Laravel这样的php和框架中编程,所以这对我来说很新。问题是我无法弄清楚如何解决在加载ApplicationContext时不断弹出的问题。任何帮助表示赞赏。
更新
我现在告诉我,测试用例不能在我的应用服务器中使用jndi ref。所以这个引用在测试用例上会失败,它在启动应用程序时运行良好。现在我创建了一个名为servlet-test.xml (listed below)
的第二个文件,该文件在端口3306上使用对数据库的引用。我只在测试时使用此文件而不是在启动应用程序时。但是当我使用这种方法时,我得到Following error: Error creating bean with name 'productController': Injection of autowired dependencies failed
。欢迎任何帮助,因为我正努力为我的学校项目设置MVC控制器测试。我一直在工作的其他学生也遇到了同样的问题,所以我也可以帮助他们。
我怀疑问题如下,但我不确定如何解决这个问题。
Error creating bean with name 'myDataSource' defined in URL
[file:web/WEB-INF/servlet.xml]: Invocation of init method failed;
nested exception is javax.naming.NamingException: Lookup failed for
'java:app/fotoproducent' ...
错误堆栈跟踪
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in URL [file:web/WEB-INF/servlet.xml]: Cannot resolve reference to bean 'myDataSource' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDataSource' defined in URL [file:web/WEB-INF/servlet.xml]: Invocation of init method failed; nested exception is javax.naming.NamingException: Lookup failed for 'java:app/fotoproducent' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl} [Root exception is javax.naming.NamingException: Invocation exception: Got null ComponentInvocation ]
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1456)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:973)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:750)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:121)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:250)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
控制器测试我试图运行:
ProductController测试
package controller.tests.config;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:web/WEB-INF/servlet-test.xml", "file:web/WEB-INF/dispatcher-servlet.xml"})
public class ProductControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
@Test
public void testProductAction() throws Exception {
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
ResultMatcher msg = MockMvcResultMatchers.model()
.attribute("msg", "Spring quick start!!");
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/product");
this.mockMvc.perform(builder)
.andExpect(ok)
.andExpect(msg);
}
}
servlet.xml / applicationContext.xml文件
<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:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- module/package declarations -->
<context:component-scan base-package="Application" />
<context:component-scan base-package="Authentication" />
<context:component-scan base-package="Photo" />
<context:component-scan base-package="Product" />
<context:component-scan base-package="Organisation" />
<context:component-scan base-package="Login" />
<context:component-scan base-package="UI" />
<context:component-scan base-package="I18n" />
<context:component-scan base-package="Internationalization" />
<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>
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
<property name="jndiName" value="java:app/fotoproducent" />
<property name="resourceRef" value="true" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="*" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<mvc:resources mapping="/static/**" location="/static/"/>
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:default-servlet-handler/>
<mvc:annotation-driven />
</beans>
分派器-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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMap ping"/>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="index.html">indexController</prop>
<prop key="test.html">testController</prop>
</props>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp" />
<!--
The index controller.
-->
<bean name="indexController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="index" />
<!--
The test controller.
-->
<bean name="testController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="test" />
</beans>
更新1:&#34;数据源配置&#34;
这显示了数据源的配置方式。
的glassfish-resources.xml中
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="mysql_fotoproducent_rootPool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
<property name="serverName" value="localhost"/>
<property name="portNumber" value="3306"/>
<property name="databaseName" value="fotoproducent"/>
<property name="User" value="root"/>
<property name="Password" value="password"/>
<property name="URL" value="jdbc:mysql://localhost:3306/fotoproducent?zeroDateTimeBehavior=convertToNull"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</jdbc-connection-pool>
<jdbc-resource enabled="true" jndi-name="app/fotoproducent" object-type="user" pool-name="mysql_fotoproducent_rootPool"/>
</resources>
更新2:其他Bean配置文件(servlet-test.xml)
这导致bean未加载。以下错误:使用名称&#39; productController创建bean时出错&#39;:注入自动连接的依赖项失败
<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:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config/>
<mvc:annotation-driven />
<!-- module/package declarations -->
<context:component-scan base-package="Application" />
<context:component-scan base-package="Authentication" />
<context:component-scan base-package="Photo" />
<context:component-scan base-package="Product" />
<context:component-scan base-package="Organisation" />
<context:component-scan base-package="Login" />
<context:component-scan base-package="UI" />
<context:component-scan base-package="I18n" />
<context:component-scan base-package="Internationalization" />
<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>
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/fotoproducent?zeroDateTimeBehavior=convertToNull" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="*" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<mvc:resources mapping="/static/**" location="/static/"/>
<mvc:resources mapping="/resources/**" location="/resources/" />
</beans>
更新3:问题解决的附加代码
产品控制器
package Product.Controller;
import Product.Sevice.ProductService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/product")
public class ProductController {
@Autowired
protected ProductService service;
@RequestMapping(value = "", method = RequestMethod.GET)
public String productAction(ModelMap model)
{
model.put("productList", this.service.findAll());
return "product/overview";
}
}
产品服务
package Product.Sevice;
import Product.Entity.Product;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
@PersistenceContext
private EntityManager em;
@Transactional
public void insert(Product product)
{
// insert into database
// persist function is for NEW entities in database
this.em.persist(product);
}
@Transactional
public Product get(Integer id)
{
// this gets the entity from the database and returns it
return this.em.find(Product.class, (long) id);
}
@Transactional
public Product update(Product product)
{
// this updates the ExampleEntity in within the database
return this.em.merge(product);
}
@Transactional
public void remove(Integer id)
{
Product product = this.em.find(Product.class, (long) id);
product.delete();
// this updates the product in within the database
this.update(product);
}
@Transactional
public List<Product> findAll()
{
Query q = this.em.createNamedQuery("product.namedquery", Product.class);
return q.getResultList();
}
}
答案 0 :(得分:1)
根据应用程序上下文初始化时的堆栈跟踪,它仍然尝试加载错误的配置文件(servlet.xml),但是应该加载servlet-test.xml。请尝试使用root(src)文件夹中的路径更改配置位置,例如:
@ContextConfiguration({"file:src/main/web/WEB-INF/servlet-test.xml", "file:src/main/web/WEB-INF/dispatcher-servlet.xml"})
P.S此外,您可以尝试将测试配置(servlet-test.xml)移动到src / test / resources并从类路径加载它:“classpath:servlet-test.xml”。您还可以在stackoverflow上查看此线程:Spring @ContextConfiguration how to put the right location for the xml以扩展对类似问题的讨论。
答案 1 :(得分:0)
您收到一条错误消息,指出Spring IOC容器无法创建并实例化entityManagerFactory
bean。为什么?
您的错误异常提到的另一件事。它没有这样做,因为它无法实例化myDataSource
bean。为什么呢?
根据您的错误消息:
Lookup failed for 'java:app/fotoproducent'
这意味着当IOC Spring容器尝试创建myDataSource
bean时,它无法执行此操作,因为它无法将jndiName设置为值java:app/fotoproducent
而不是使用它:
<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
<property name="jndiName" value="java:app/fotoproducent" />
<property name="resourceRef" value="true" />
</bean>
将其替换为:
<bean id="myDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="your_driver_class_name" />
<property name="url" value="url_to_your_db" />
<property name="username" value="user_name_to_db" />
<property name="password" value="password_to_db" />
</bean>
我的建议是创建一个像上面的Spring文档中提到的标准数据源。
现在不要忘记替换驱动程序类名,网址,用户名和密码的值。
以下是Spring文档中有关如何定义使用Hibernate ORM的数据源的示例:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#orm-hibernate