上一篇博客中给大家讲解了maven工具的安装和配置,下面我们就来使用maven来构建一个项目,首先来说一下我们的项目功能,这次我们要做的功能是将excel格式的数据表格中的数据导入到数据库中,使用的技术主要就是前面给大家讲解的Spring框架,同时还有一个操作excel表格的工具包poi,poi也是apache的一个项目,该项目主要是为Java提供操作微软的office文件的一套解决方案,也就是说poi框架的功能不光是操作excel,包括word和PowerPoint等等office办公常用格式的文件。好了,我们先来看看怎么使用poi来操作excel。
再啰嗦一句,不管我们学习什么技术,最好的办法就是阅读官方提供的文档,既然我们要学习poi的是使用那么我们首先就是去看看他的官网了,好了,打开http://poi.apache.org/,我们来到poi官网:
我们选择javadocs,可以看到不同版本的文档信息,这里我们选择最新的4.0版本,查看官网的在线文档,
进入文档后如下图所示:
和我们的JavaAPI文档类似,这里我们可以看到poi框架的全部的api的是使用方法, 这里我们主要关注操作excel的方法,首先打开org.apache.poi.hssf.usemodel这个包。找到HSSFWorkBook这个类,这个类的作用就是创建一个工作表对象,也就是对应于excel中的一个sheet,HSSFCell这个类的作用是创建一个单元格,如下图所示:
找到了这三个类我们就可以完成一个操作excel文件的基本的程序了。下面就来看看具体的用法,
首先打开eclipse ,创建一个maven工程,如下图所示:
这里我们需要将Create a simple project 勾选上,这个选项的作用是快速的创建一个简单的maven项目,不需要选择原型模板,这样的好处就是可以快速的创建项目。接着选择next
第一个Group Id 意思是组织的id,也就是对应于公司域名,也就是项目里边的一级包名,第二个Artifact Id 对应于项目名,这两个id在maven项目里边称为坐标,当我们发布项目的时候,就会将这两个值作为我们项目的唯一标识,相当于地址。选择finish
打开我们创建好的项目,项目结构如上图所示,其中我们的代码是写在Java目录下,配置文件放在resources目录下,测试的代码放在test目录下。这里需要介绍一下的是pom.xml这个文件,这个文件就是maven工程里边的管理依赖用的以及管理各种插件,首先我们打开该文件,
其中dependences标签就是用来管理依赖的,所谓的依赖就是指的这个项目依赖于那些jar包,大家应该都知道一个项目会依赖很多jar包,如果把所有的jar包都导入项目里,那么项目就显得很笨重,所以我们就需要maven来管理这些jar包,首先大家在pom.xml文件中添加dependences标签,并且在该标签中添加以下的依赖,
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.0</version>
</dependency>
这就是poi工具的依赖,从上边的依赖中可以看到poi 是apache的一个项目,因此他的groupId也就是组织id就是apache的poi项目的域名 org.apache.poi,artifactId对应的项目名就是poi,version就不用说了,指的是版本号, 好了,这个步骤叫做导入依赖的坐标。导入之后我们打开项目,创建包结构如下图所示:
其中bean包下是User是实体类,用来封装数据的。controller层中的是试图层,这里只是模拟一下正规的项目结构,在下一篇博客中将会把这个项目改造成使用spring框架来构建。service包下放的是service接口和实现类,utils包下放的是项目需要使用到的工具类,好了,一个传统的单体应用的项目结构一般就是这样了。你可能注意到了Maven Dependencies这个包,其实这个包下就是我们刚刚导入的poi依赖,打开这个包我们可以发现里边存放的是jar包。
我们在pom.xml文件中导入我们需要使用的jar包的坐标,maven就会帮助我们下载该坐标对应的jar包,存放在我们本地磁盘上的一个路径,这个路径在maven的安装目录中的 conf文件夹下的setting.xml文件中配置,具体的路径如下图所示:
由于该文件中有示例这里便不再演示。好了,项目的环境准备到此结束。下面就进入了具体的编码了。
首先我们需要编写实体类User的代码,该类主要模拟一下一个用户,我们在程序里为该用户封装数据,然后写入到本地的excel文件中。 User类中的代码如下图所示:
public class User {
private Long id;
private String userName;
private String password;
private String sign;
private Date birthDay;
private Integer age;
private Double salary;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(Long id, String userName, String password, String sign, Date birthDay, Integer age, Double salary) {
super();
this.id = id;
this.userName = userName;
this.password = password;
this.sign = sign;
this.birthDay = birthDay;
this.age = age;
this.salary = salary;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", sign=" + sign + ", birthDay="
+ birthDay + ", age=" + age + ", salary=" + salary + "]";
}
}
这里为了给大家演示不同的数据类型的处理,分别使用了Long、Integer、String、Date类型的数据,这些数据一般是最常见的,好了,我们有了User类之后我们就要分装数据进去了,首先我们来service接口中,在该接口中添加一个方法,该接口中的方法如下所示:
import java.util.List;
import com.wcan.poi.bean.User;
public interface UserService {
public List<User> add();
}
这个方法就是用来添加数据的,接下来我们需要将该方法实现,代码如下:
public class UserServiceImpl implements UserService{
/**
* 添加用户
*
*/
@Override
public List<User> add() {
// TODO Auto-generated method stub
List<User> list = new ArrayList<User>();
for(int i=0;i<100;i++) {
User user = new User();
user.setId(Long.valueOf(i));
user.setUserName(Integer.valueOf(i+(i+1)*99).toString());
user.setPassword(UUID.randomUUID().toString().substring(0, 5));
user.setSign("我是第"+i+"个用户,我很高兴!");
user.setBirthDay(new Date());
user.setAge((i+1)*10+i);
user.setSalary(Double.valueOf((i+1)*500));
list.add(user);
}
return list;
}
}
这里我们使用循环,快速的生成100条数据,用户id就是循环的次数,userName我们通过处理每次循环的次数来生成,这里只是为了快速的演示效果,如果你有更好的办法也可以。密码我们采用UUID来生成,截取 前面5位。剩下的只是为了演示效果,就不解释了。当我们生成完了这些数据后就将这些数据封装进User对象。封装完了就把该对象放入list集合中。返回这个list集合。
好了,这里我们来到controller层,创建UserController层的代码如下:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.junit.Test;
import com.wcan.poi.bean.User;
import com.wcan.poi.service.UserService;
import com.wcan.poi.service.UserServiceImpl;
import com.wcan.poi.utils.PoiUtils;
public class UserController {
private UserService userService;
@Test
public void creatExcel() {
userService = new UserServiceImpl();
List<User> list = userService.add();
HSSFWorkbook workBook = PoiUtils.getWorkBook(list);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(new File("E://demo.xls"));
workBook.write(fileOutputStream);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Test
public void readExcel() {
String filePath = "E://demo.xls";
List<User> readExcel = PoiUtils.readExcel(filePath);
for (User user : readExcel) {
System.out.println(user);
}
}
}
z在这个controller中有两个方法每一个是将对象中的数据写入excel文件,一个是将excel文件中的数据读取出来,并且存入到对象之中。好了现在就来讲解怎么实现excel文件的读写了。
这里我们来到PoiUtils类中,这个类就是我们这个项目的工具类,这里我将实现excel文件的读写功能都封装在这个类种,该类的代码如下所示:
/**
* 工具类
*
* @author wcan
* @date 2018-11-10
*
*/
public class PoiUtils {
/**
*
* 读取文件
*
*/
public static List<User> readExcel(String filePath) {
//创建集合存放数据
List<User> list = new ArrayList<User>();
POIFSFileSystem fs = null;
try {
fs=new POIFSFileSystem(new FileInputStream(filePath));
HSSFWorkbook wb = new HSSFWorkbook(fs);
//读取第第张表格
HSSFSheet sheet = wb.getSheetAt(0);
//获取行
for(int i= 1;i<sheet.getLastRowNum();i++) {
HSSFRow row = sheet.getRow(i);
String[] str = new String[row.getLastCellNum()];
for (int j=0;j<=row.getLastCellNum();j++) {
str[j]=row.getCell(j).toString();
}
User user = new User();
user.setId(Long.valueOf(str[0]));
user.setUserName(str[1]);
user.setPassword(str[2]);
user.setBirthDay(PoiUtils.stringToDate(str[3]));
user.setSign(str[4]);
user.setAge(Integer.valueOf(str[5]));
user.setSalary(Double.valueOf(str[6]));
list.add(user);
// System.out.println("添加了第: "+i+" 个对象");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
fs.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("返回了一个存放了 "+list.size()+" 个对象的集合");
return list;
}
/**
* 将对象中封装的数据存放到HSSFWorkbook对象中
*
* @param list
* @return workbook
*/
public static HSSFWorkbook getWorkBook(List<User> list) {
for (User user : list) {
System.out.println(user);
}
// 创建工作表对象
HSSFWorkbook workbook = new HSSFWorkbook();
// 在对象中创建一个表
HSSFSheet sheet = workbook.createSheet("sheet0");
// 获取表头
String[] header = PoiUtils.getTabHeader();
for (int i = 0; i < list.size() + 1; i++) {
// 创建第i行
HSSFRow row = sheet.createRow(i);
// 设置表头
if (i == 0) {
for (int j = 0; j < header.length; j++) {
row.createCell(j).setCellValue(header[j]);
}
}
// 将内容写入excel表格
else {
// 获取对象属性值
String[] userMsg = getUserMsg(list.get(i - 1));
for (int j = 0; j < userMsg.length; j++) {
row.createCell(j).setCellValue(userMsg[j]);
}
}
}
return workbook;
}
/**
* 将对象属性值存入到string数组中
*
* @param user
* @return
*/
public static String[] getUserMsg(User user) {
String[] usersMsg = {
user.getId() != null ? user.getId().toString() : null, user.getUserName(), user.getPassword(),
PoiUtils.dateToString(user.getBirthDay()), user.getSign(), user.getAge().toString(),
user.getSalary().toString()
};
return usersMsg;
}
/**
* 提供表头
*
* @return
*/
public static String[] getTabHeader() {
String[] tabHeader = { "用户ID", "用户名", "密码", "个性签名", "生日", "年龄", "工资" };
return tabHeader;
}
/**
* 将日期类型的数据转成字符串
*
* @param date
* @return date
*/
public static String dateToString(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
/**
* 将字符串类型的数据转成日期
*
* @param date
* @return date
*/
public static Date stringToDate(String str) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sdf.parse(str);
} catch (Exception e) {
// TODO Auto-generated catch block
throw new RuntimeException("转换失败");
}
}
}
给大家解释一下,由于数据类型的不同,这里可以将所有的数据都转换成字符串,放在一个字符串数组中,饭后遍历该字符串数组,将值一次放入到表格中,最终表格中的数据都是以字符串的形式写入到excel 文件中。需要注意的是Date类型的数据转成字符串的时候需要日期格式化的一个工具类,在构造器中指定要转换的格式即可。
同理,读取excel文件的中的数据存入到对象中的时候我们读取出来的数据也是字符串类型的,因此也需要处理。其实poi中有自带的数据处理的功能,但是我个人觉得来麻烦了,每次用的时候都要加入判断的方法,严重的影响了程序的执行效率。所以这里采用了统一转换的方式来进行处理。
好了,我们回到controller层,测试一下creatExcel这个方法,结果如下图所示:
可以看到,我们成功的将数据封装到了对象中,同时我们打开D盘,就可以发现在D盘下已经生成了一个demo.xls的文件。打开该文件,如下所示:
好了,使用poi生成excel文件的的功能 实现了,接下来我们来读取这个生成的excel文件。运行readExcel方法,结果如下图所示:
好了,这次的poi使用的教程就到此为止了,后面的要做的项目就是把数据知道导入到数据库中,也就是后台的上传excel文件,然后解析excel文件,经该文件的数据导入到数据库中,同时还要不实现将数据库中的数据写入到excel文件中,并且从服务器上下载下来。好了,今天就到这里了,希望这篇博客对大家有帮助。