我有一个简单的Java Spring IO项目,其中一个类应该从csv文件中读取,并且对于每个读取的记录,参数都存储在一个帐户对象列表中。 我使用Force IDE Luna和读取该文件的Class CsvAccountDao与在xml文件的第一个bean中定义的csv文件位于同一个包中。 xml文件也位于同一个包下。这是bean文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
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">
<bean id="accountDao"
class="com.springinpractice.ch01.model.dao.csv.CsvAccountDao">
<property name="csvResource" value="accounts.csv"></property>
</bean>
<bean id="accountService"
class="com.springinpractice.ch01.service.AccountService">
<property name="accountDao" ref="accountDao"</property>
</bean>
</beans>
这里是类文件CscAccountDao:
package com.springinpractice.ch01.model.dao.csv;
import java.io.BufferedReader;
import java.io.FileReader;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.core.io.Resource;
import com.springinpractice.ch01.model.Account;
import com.springinpractice.ch01.model.dao.AccountDao;
public class CsvAccountDao implements AccountDao {
private Resource csvResource;
public CsvAccountDao() {
// TODO Auto-generated constructor stub
}
public void setCsvResource(Resource csvFile){
this.csvResource = csvFile;
}
@Override
public List<Account> findAll() throws Exception {
List<Account> results = new ArrayList<Account>();
DateFormat fmt = new SimpleDateFormat("MMddyyyy");
BufferedReader br = new BufferedReader(
new FileReader(csvResource.getFile()));
String line;
while((line = br.readLine()) != null){
String[] fields = line.split(",");
String accountNo = fields[0];
BigDecimal balance = new BigDecimal(fields[1]);
Date lastPaidOn = fmt.parse(fields[2]);
Account account =
new Account(accountNo, balance, lastPaidOn);
results.add(account);
}
br.close();
return results;
}
}
注意setCsvResource方法将csv文件分配给资源对象的位置是异常问题的开始位置。我在堆栈跟踪中得到一个异常错误:
Jun 20, 2015 7:59:42 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@177e4b0: defining beans [accountDao,accountService]; root of factory hierarchy
Exception in thread "main" java.io.FileNotFoundException: class path resource [accounts.csv] cannot be resolved to URL because it does not exist
问:我是否有必要通过添加完整路径来更新第一个bean使用accounts.csv的XML文件?由于class,xml和csv文件都在同一个包中,我认为我不需要更具体。
答案 0 :(得分:2)
资源加载的一些背景知识。
在Java中,要加载类路径资源,请在具有资源名称的类加载器上调用getResource
或getResourceAsStream
。资源名称为:
资源的名称是'/' - 标识资源的分隔路径名。
所以要从你使用的包中获取资源:
classloader.getResource("org/com/resource.jpg")
java类也有方便的方法从它的类加载器加载资源。如果你使用ClassA.class.getResource("resource.jpg")
,它会将'/' - 加入的ClassA包前缀加到“resource.jpg”并委托给类加载器。如果您的资源字符串以'/'开头,它被解释为绝对路径,则删除起始'/',然后委托给类加载器。
然后我们开始使用accounts.csv
作为要转换为资源的值。 Spring使用DefaultResourceLoader
来查找您的资源。以下是用于查找资源的逻辑:
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
if (location.startsWith("/")) {
return getResourceByPath(location);
}
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// Try to parse the location as a URL...
URL url = new URL(location);
return new UrlResource(url);
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
在你的情况下,它一直落到catch(MalformedURLException ex)
,然后尝试将其作为类路径资源查找。当最终要求ClasspathResource输入URL或输入流时,它会将"account.csv"
传递给类加载器。类加载器在类路径的根目录中查找它。
所以在你的spring xml中你需要告诉它它是什么包。它不会相对于xml。所以将其更改为“/package/account.csv”或“classpath:/package/account.csv”
供参考:我正在寻找Spring 4.0.9.RELEASE和oracle jdk8。