java实现导入导出excel数据

项目需要,要实现一个导入导出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框架



            

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; i0){
                        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包,否则是空谈。

  • 1、关于poi3.17版本设置单元格样式居中字段
  • 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天时间,第一次接触,期间遇到各种诡异问题,现在总算是实现了,代码路上,不放弃才能熬到最后。

四、参考文章

1、java通过jxl导入导出excel
2、poi和jxl操作office

你可能感兴趣的:(java实现导入导出excel数据)