项目需要,要实现一个导入导出excel的功能,于是,任务驱动着我学习到了POI和JXL这2个java操作Excel的插件。

一、POI和JXL介绍

1、POI:是对所有office资源进行读写的一套工具包、属于apache开源组织。

poi操作excel:

poi是把整个文件的属性都封装在HSSFWorkbook 中;

通过HSSFWorkbook来操作单个工作薄。然后通过工作薄来操作行;

在通过行来操控单元格。这样一级一级的分拆下来;

HSSFWorkbook---->HSSFSheet----->HSSFRow---->HSSFCell;

由于是基于HSSFWorkbook对象一步步创建起来的。所以不用把创建好的单元格添加进这个对象中、

如果需要对部分表格进行设置样式什么的。就可以创立HSSFCellStyle对象来进行设定样式;

2、JXL:只能对excel进行操作的一套工具包。

jxl是把整个文件封装在Workbook相关对象中;

通过Workbook去创建sheet工作薄;但是和poi不一样的地方是

jxl是通过向sheet中使用label(单元格)来进行读取写入;

Workbook----->sheet------>label ;

jxl是先创建一个工作区域、然后区创立单元格、单元格包含这个单元格的位置、内容等信息;然后把这个单元格加入工作区;

二、实例操作

1、用POI方式实现导出数据到excel功能

实现思路:当一点击导出按钮就跳转到指定的action去执行对应方法,先调用dao对数据库数据进行查询,根据dao层的方法返回一个集合对象,然后把这个集合对象的数据交互给POI去动态生成单元格并设置进去。项目后端我用的是ssh框架搭建项目,所以逻辑代码我写在action类中。直接看以下代码示例

前端jsp页面按钮部分

导出

交换生实体类

package com.international.model;

import java.util.Date;

import cn.afterturn.easypoi.excel.annotation.Excel;

import cn.afterturn.easypoi.excel.annotation.ExcelTarget;

public class ExchangeStudent {

//此表按照单表来操作,只用作记录

private int id;

private String studentNo;

private String studentName;

private String sex;

private String major;

private String className;

private Date startTime;

private Date endTime;

private String exchangeCollege;

private String reserves1;

private String reserves2;

private String reserves3;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getStudentNo() {

return studentNo;

}

public void setStudentNo(String studentNo) {

this.studentNo = studentNo;

}

public String getStudentName() {

return studentName;

}

public void setStudentName(String studentName) {

this.studentName = studentName;

}

public String getSex() {

return sex;

}

public void setSex(String sex) {

this.sex = sex;

}

public String getMajor() {

return major;

}

public void setMajor(String major) {

this.major = major;

}

public String getClassName() {

return className;

}

public void setClassName(String className) {

this.className = className;

}

public Date getStartTime() {

return startTime;

}

public void setStartTime(Date startTime) {

this.startTime = startTime;

}

public Date getEndTime() {

return endTime;

}

public void setEndTime(Date endTime) {

this.endTime = endTime;

}

public String getExchangeCollege() {

return exchangeCollege;

}

public void setExchangeCollege(String exchangeCollege) {

this.exchangeCollege = exchangeCollege;

}

public String getReserves1() {

return reserves1;

}

public void setReserves1(String reserves1) {

this.reserves1 = reserves1;

}

public String getReserves2() {

return reserves2;

}

public void setReserves2(String reserves2) {

this.reserves2 = reserves2;

}

public String getReserves3() {

return reserves3;

}

public void setReserves3(String reserves3) {

this.reserves3 = reserves3;

}

}

后端action类内的业务方法代码

//导出交换生

public String exportExchangeSudent() throws Exception{

//获取交换生对象

List studentList = esd.queryInterStudents("");

String []tableHeader={"学号","姓名","性别","班级","专业","交换开始时间","交换结束时间","交换的院校"};

short cellNumber=(short)tableHeader.length;//表的列数

workbook = new HSSFWorkbook(); //创建一个Excel

style = workbook.createCellStyle(); //设置表头的类型

style.setAlignment(HorizontalAlignment.CENTER);

style1 = workbook.createCellStyle(); //设置数据类型

style1.setAlignment(HorizontalAlignment.CENTER);

HSSFFont font = workbook.createFont(); //设置字体

HSSFSheet sheet = workbook.createSheet("sheet1"); //创建一个sheet

HSSFHeader header = sheet.getHeader();//设置sheet的头

try {

//根据是否取出数据,设置header信息

if(studentList.size() < 1 ){

header.setCenter("查无资料");

}else{

header.setCenter("交换生表");

row = sheet.createRow(0);

row.setHeight((short)400);

//表头

for(int k = 0;k < cellNumber;k++){

cell = row.createCell((short) k);//创建第0行第k列

cell.setCellValue(tableHeader[k]);//设置第0行第k列的值

sheet.setColumnWidth((short)k,(short)8000);//设置列的宽度

font.setColor(HSSFFont.COLOR_NORMAL); // 设置单元格字体的颜色.

font.setFontHeight((short)350); //设置单元字体高度

style1.setFont(font);//设置字体风格

cell.setCellStyle(style1);

}

// 给Excel填充数据

for(int i = 0 ;i < studentList.size() ;i++){

//获取InternationalStudent对象

ExchangeStudent student1 = (ExchangeStudent)studentList.get(i);

row = sheet.createRow((short) (i + 1));//创建第i+1行

row.setHeight((short)400);//设置行高

if(student1.getStudentNo() != null){

cell = row.createCell((short) 0);//创建第i+1行第0列

cell.setCellValue(student1.getStudentNo());//设置第i+1行第0列的值

cell.setCellStyle(style);//设置风格

}

if(student1.getStudentName() != null){

cell = row.createCell((short) 1); //创建第i+1行第1列

cell.setCellValue(student1.getStudentName());//设置第i+1行第1列的值

cell.setCellStyle(style); //设置风格

}

if(student1.getSex() != null){

cell = row.createCell((short) 2);

cell.setCellValue(student1.getSex());

cell.setCellStyle(style);

}

if(student1.getClassName()!= null){

cell = row.createCell((short) 3);

cell.setCellValue(student1.getClassName());

cell.setCellStyle(style);

}

if(student1.getMajor()!= null){

cell = row.createCell((short) 4);

cell.setCellValue(student1.getMajor());

cell.setCellStyle(style);

}

if(student1.getStartTime() != null){

cell = row.createCell((short) 5);

cell.setCellValue(student1.getStartTime().toString().substring(0,10));

cell.setCellStyle(style);

}

if(student1.getEndTime() != null){

cell = row.createCell((short) 6);

cell.setCellValue(student1.getEndTime().toString().substring(0,10));

cell.setCellStyle(style);

}

if(student1.getExchangeCollege() != null){

cell = row.createCell((short) 7);

cell.setCellValue(student1.getExchangeCollege());

cell.setCellStyle(style);

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

outputSetting("交换生表.xls");

return null;

}

//固定配置

public void outputSetting(String fileName) {

HttpServletResponse response = null;//创建一个HttpServletResponse对象

OutputStream out = null;//创建一个输出流对象

try {

response = ServletActionContext.getResponse();//初始化HttpServletResponse对象

out = response.getOutputStream();// 得到输出流

response.setHeader("Content-disposition","attachment; filename="+new String(fileName.getBytes(),"ISO-8859-1"));//filename是下载的xls的名

response.setContentType("application/msexcel;charset=UTF-8");//设置类型

response.setHeader("Pragma","No-cache");//设置头

response.setHeader("Cache-Control","no-cache");//设置头

response.setDateHeader("Expires", 0);//设置日期头

workbook.write(out);

out.flush();

workbook.write(out);

} catch (IOException e) {

e.printStackTrace();

}finally{

try{

if(out!=null){

out.close();

}

}catch(IOException e){

e.printStackTrace();

}

}

}

一些关于ssh框架的配置代码

//struts.xml文件

//applicationContext-actions.xml

编写完以上代码,通过poi方式导出excel数据就实现了,主要关注action类那部分代码。

2、用JXL方式实现导入excel数据功能

实现思路:前端界面按下导入按钮,弹出个模态框,提示选择导入excel文件,其实导入功能是先上传文件到服务器指定路径,然后通过JXL去读取上传的excel数据,然后装进集合对象里,最后再循环的把集合对象里的数据遍历插入到数据库中,相当于遍历调用添加交换生的方法。直接看下面贴出来的代码。

前端jsp页面关键代码,有用到bootstrap框架

  • 搜索

    添加

    显示全部

    导出

    导入

    下载Excel模板

×

导入交换生EXCEL表

导入前请先下载交换生Excel表模板,按规范导入

关闭

提交

js代码实现跳转action

//导入excel文件

function importExcel(){

var formData = new FormData($("#studentExcel")[0]); // 要求使用的html对象

//console.log(formData);

$.ajax(

{

type:"post",

url:"http://localhost:8080/InternationalSys/background/importExcelAction!importExStudentExcel",

//注:如果没有文件,只是简单的表单数据则可以使用 $('#formid').serialize();

data:formData,

dataType:"json",

async:false,

contentType: false,

processData: false,

success: function(data){

if(data!=null && data!=""){

alert(data);

}

}

}

);

}

后端action类内的逻辑方法代码

package com.international.common;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import org.apache.commons.io.FileUtils;

import org.apache.commons.lang.StringUtils;

import jxl.*;

import org.apache.struts2.ServletActionContext;

import com.international.dao.ExchangeStuDao;

import com.international.model.ExchangeStudent;

import com.opensymphony.xwork2.ActionSupport;

import jxl.read.biff.BiffException;

import jxl.write.DateTime;

public class ImportExcelAction extends ActionSupport{

private String uploadFileName;

private File upload;

private String savePath;

private List exStudentList = new ArrayList();

private ExchangeStuDao esd;

public ExchangeStuDao getEsd() {

return esd;

}

public void setEsd(ExchangeStuDao esd) {

this.esd = esd;

}

public String getUploadFileName() {

return uploadFileName;

}

public void setUploadFileName(String uploadFileName) {

this.uploadFileName = uploadFileName;

}

public File getUpload() {

return upload;

}

public void setUpload(File upload) {

this.upload = upload;

}

public String getSavePath() {

return savePath;

}

public void setSavePath(String savePath) {

this.savePath = savePath;

}

public List getExStudentList() {

return exStudentList;

}

public void setExStudentList(List exStudentList) {

this.exStudentList = exStudentList;

}

//导入excel数据到交换生表

@SuppressWarnings("static-access")

public void importExStudentExcel() throws IOException{

System.out.println("excel的值为:"+ uploadFileName);

String message="";

String path=null;

Workbook book = null; //jxl工作簿

InputStream fileIn = null;

if(uploadFileName!=null && !uploadFileName.equals("")){

//拦截仅允许上传文件类型

if(uploadFileName.substring(uploadFileName.lastIndexOf(".")).equals(".xls")) {

//获取需要上传文件的文件路径

path=ServletActionContext.getServletContext().getRealPath(this.getSavePath()+ "\\" +this.uploadFileName);

System.out.println("上传Excel的路径:"+path);

//判断文件是否上传,如果上传的话将会创建该目录

File target= new File(path); // 定义目标文件对象

try {

FileUtils.copyFile(upload, target);

} catch (Exception e) {

e.printStackTrace();

}

// 删除临时文件

upload.delete();

int sum=0;//计算导入成功的条数

try {

System.out.println("上传路径:"+path);

fileIn = new FileInputStream(path);

//根据指定的文件输入流导入Excel从而产生Workbook对象

System.out.println("输入流:"+fileIn);

//获取Excel对象

try {

book = book.getWorkbook(new File(path));

} catch (BiffException e1) {

// TODO 自动生成的 catch 块

e1.printStackTrace();

}

//获取Excel的第一个sheet表

Sheet sheet = (Sheet) book.getSheet(0);

System.out.println("获取到的Excel数据:"+ sheet);

System.out.println("行数:"+sheet.getRows());

System.out.println("列数:"+sheet.getColumns());

//对Sheet中的每一行进行迭代

for (int i = 1; i < sheet.getRows(); i++) {

//创建实体类

ExchangeStudent exStudent = new ExchangeStudent();

// 获取第一列第二行单元格对象

exStudent.setStudentNo(sheet.getCell(0, i).getContents());

exStudent.setStudentName(sheet.getCell(1, i).getContents());

exStudent.setSex(sheet.getCell(2, i).getContents());

exStudent.setClassName(sheet.getCell(3, i).getContents());

exStudent.setMajor(sheet.getCell(4, i).getContents());

Date sTime = null;

//日期格式处理方式:

if(sheet.getCell(5, i).getType() == CellType.DATE){

DateCell dc = (DateCell)sheet.getCell(5, i);

sTime = dc.getDate(); //获取单元格的date类型

}

exStudent.setStartTime(sTime);

Date eTime = null;

//日期格式处理方式:

if(sheet.getCell(6, i).getType() == CellType.DATE){

DateCell dc = (DateCell)sheet.getCell(6, i);

eTime = dc.getDate(); //获取单元格的date类型

}

exStudent.setEndTime(eTime);

exStudent.setExchangeCollege(sheet.getCell(7, i).getContents());

//不是空对象才加入集合中

if(exStudent!=null) {

exStudentList.add(exStudent);

}

}

System.out.println(exStudentList);

for(int i=0; i

if(!esd.queryStudentNo(exStudentList.get(i).getStudentNo())) {

if(esd.addExStudent(exStudentList.get(i))){

sum++;

}

}else {

message = "此条学生记录已存在";

System.out.println("此条学生记录已存在");

continue;

}

}

System.out.println("导入的学生人数:"+sum);

if(sum>0){

System.out.println("导入成功");

message="导入成功";

}else{

System.out.println("导入失败");

message="导入失败";

}

fileIn.close();

} catch (IOException ex) {

ex.printStackTrace();

}

}else {

System.out.println("上传的只能是后缀为.xls的Excel文件");

message = "上传的只能是后缀为.xls的Excel文件";

}

}else{

message="请先上传交换生信息的Excel文件";

System.out.println("请先上传交换生信息的Excel文件");

}

ajaxAction.toJson(ServletActionContext.getResponse(),message);

}

}

dao层的代码

//根据学号查询数据库是否有这个交换生

public boolean queryStudentNo(String stuNo) {

Session session = null;

try {

session = sessionFactory.openSession();

String hql = "from ExchangeStudent where studentNo="+stuNo;

Query query = session.createQuery(hql);

List list = query.list();

if(list.size()>0) {

return true;

}else {

return false;

}

}catch (Exception e) {

e.printStackTrace();

return false;

}finally {

session.close();

}

}

//添加交换生信息

public boolean addExStudent(ExchangeStudent exchangeStudent) {

Session session = null;

try{

session = sessionFactory.openSession();

Transaction tran = session.beginTransaction();

session.save(exchangeStudent);

tran.commit();

return true;

}catch(Exception e){

e.printStackTrace();

return false;

}finally{

session.close();

}

}

一些ssh的配置文件

//applicationContext-actions.xml

//struts.xml

/upload

根据以上的代码,通过jxl方法的导入功能也实现了,主要关注action类的那部分代码。

图片.png

三、期间遭遇问题(PS:我认为这才是我写这篇文章的初心和这篇文章的重点,差不多的功能对于每个人都可能出现许多不同的问题,我们要学会自己解决问题,我把这分享出来。)

注意:以上导入导出的实例代码要成功,都得基于导入相应的POI和JXL的jar包,否则是空谈。

2、报错:Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: 违反了 UNIQUE KEY 约束“UQ__Exchange__4D119D59097C43E3”。不能在对象“dbo.ExchangeStudent”中插入重复键。重复键值为 ()。

问题原因:因为我数据库表中studentNo这个字段设置了唯一性约束,所以当excel插入的时候,数据库里面已经存在了该条记录,所以不让插入。

解决方案:我在dao层里加入一个方法,就是上面的queryByStudentNo()方法,用来根据excel表里的学号数据去数据库查询有无这个学生,有的话就不插入了,继续下一次循环。

3、导入excel表中的日期数据报错:java.text.ParseException: Unparseable date: "" 解决参考这里

//思路是借用下面这一段的,我自己写的在上面实例代码。

DateTime accessTime = null;

//日期格式处理方式:

if(sheet.getCell(2, j).getType() == CellType.DATE){

DateCell dc = (DateCell)sheet.getCell(2, j);

Date date = dc.getDate(); //获取单元格的date类型

accessTime = new DateTime(date);

}

4、JXL读取Excel文件,调用sheet.getRows()竟然返回多余的行数。这个有点玄学,明明excel数据有3行数据而已,在程序获取的时候竟然显示有33行数据,最后还是莫名其妙的就恢复正常了。

5、报错:jxl读取excel文件异常,Unable to recognize OLE stream。这是jxl导入excel数据只支持后缀为.xls文件的问题。解决方案这里

6、ssh上传文件到服务器隔一会文件会自动删除。解决方案这里

7、导入时遇到多表关联的数据,比如我在导入国际班学生的excel数据时,excel表里有班级的字段,报错:org.hibernate.TransientObjectException: object references an unsaved tran。经排查,问题代码锁定在下图这块。

图片.png参考了这篇文章,虽然不报错了,导入成功,但是并没有真正解决我的需求,因为这篇文章是级联保存主从表,即主表和从表都插入了数据,但我的需求是数据库里国际班学生表关联班级表,在批量插入国际班学生的信息时班级表不能保存,于是我这又真不知怎么办了,但我要让苍天知道我不认输,一点点思考排查。。。慢慢地,我逐渐了解到事情的本质,我这段代码问题出在我是新创建了一个班级对象,所以刚开始导入国际班学生信息时才会提示班级主表的信息没保存,于是我想到,那我不新创建班级对象,我直接去数据库里查这个班级对象,在设值进去国际班学生对象的属性里不就搞定了!最后代码就变成了这样,问题解决。

图片.png

总结:这2功能我花了2天时间,第一次接触,期间遇到各种诡异问题,现在总算是实现了,代码路上,不放弃才能熬到最后。

四、参考文章

java excel data 导入数据_java实现导入导出excel数据相关推荐

  1. java控制台输出五行字符串_java五行代码导出Excel

    已经写过两种Excel导出插件了.今天再安利一个极简的导出Excel的框架,导出无特殊格式要求的Excel,只需五行代码: 先看代码 再看效果 EasyExcel 本案例用到的框架是阿里推出的Easy ...

  2. java导出excel 打不开_java – 无法使用AbstractExcelView导出Excel工作表

    这是我的ExcelController.java public ModelAndView generateExcel(HttpServletRequest request, HttpServletRe ...

  3. java poi excel 单元格样式_java poi批量导出excel 设置单元格样式

    POI中可能会用到一些需要设置EXCEL单元格格式的操作小结: 先获取工作薄对象: HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb ...

  4. springboot整合poi读取数据库数据和图片动态导出excel

    springboot整合poi读取数据库数据和图片动态导出excel 第一次操作 话不多说就直接上代码 实现代码 需要的依赖 <dependency><groupId>org. ...

  5. java中excel导入图片_java POI实现向Excel中插入图片

    做Web开发免不了要与Excel打交道.今天老大给我一个任务-导出Excel.开始想的还是蛮简单的,无非就是查找,构建Excel,response下载即可.但是有一点不同,就是要加入图片,就是这个加入 ...

  6. java excel row遍历空_Java poi读取,写入Excel,处理row和cell可能为空的情况

    首先需要导入包 import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.NP ...

  7. java excel 导出图片_JAVA 使用 POI 导出 EXCEL 自定义背景颜色

    开发中常用表格导入和导出 Excel 是常见的功能. 在这里分享下使用 POI 导出表格的简单实现,也是为大家提供个思路吧,抛砖引玉,话不多说直接上代码. 1.项目引入 maven 依赖 <!- ...

  8. java 列表数据List通过模板导出excel表和word表

    1.maven需要的jar包 <!-- exl导出 --> <dependency><groupId>net.sf.jxls</groupId>< ...

  9. 使用HSSFWorkbook并简单对数据分批查询完成导出excel功能(java实现)

    ##需求及思路详解 根据产品及需求,我们需要实现对采购品各分类下的采购品进行导出功能. (可能会出现的问题):①因为要对采购品各分类下采购品进行导出excel文件的功能,所以要考虑到根目录及子目录下采 ...

最新文章

  1. Xcode 5.0.1安装插件:规范注释生成器VVDocumenter + OSX 10.9.2
  2. 高中毕业就想转行当 Coder,程序员的学历真的不重要么?
  3. 【转】adobe acrobat pro修改pdf文字
  4. Python文件读写、StringIO和BytesIO
  5. 洛谷——P1042 乒乓球
  6. 6月30日云栖精选夜读:程序员技术与文艺的PK_来首届阿里巴巴研发效能嘉年华...
  7. 华为认证hcia含金量_【华为认证】HCIA-DATACOM史上最全精选题库(附答案解析)...
  8. 通过cmd修改注册表并设置cmd窗口的大小
  9. oracle 10g 下载方法
  10. Oracle查看IP操作,Oracle VM VirtualBox虚拟机ip addr命令查看ip不显示以及静态IP设置
  11. 帆软大数据自定义分页
  12. 微信小程序:二维码DIY背景美化生成器
  13. JS将秒数换算成时分秒 以及转化为年月日 时分秒
  14. python中的int()_python中的int函数如何使用?
  15. 安卓打包出现“app:processReleaseManifest“问题的一种解决方案
  16. linux中匿名用户怎么登陆_linux 匿名登陆
  17. Linux export 命令及如何删除export设置的环境变量
  18. 快手直播弹幕数据采集
  19. 「图学习推荐系统」最新2022综述
  20. RK3568 ov5695摄像头

热门文章

  1. optee的异常向量表-(irq,fiq,svc...)
  2. [私]-图片backup
  3. 基于策略的一种高效内存池的实现
  4. 升级python版本_升级python版本和环境
  5. [INSHack2018]Tricky-Part1
  6. 1.2 Collection接口
  7. ACM入门之【KMP】
  8. 项目: 用C语言写一个音乐播放器
  9. 深度优先搜索(DFS)相关习题
  10. MySQL中的数据分组