POI实现导入Excel

此例为maven项目,实现学生模块列表信息的导入Excel操作。所用框架为SSM框架。
工具类 ImportExcelUtil.java 中均为公用方法,无论任何框架项目都可直接调用类中方法,只需将对应的参数传到方法中即可。
1.jar包
在maven项目中增加如下配置即可。若非maven项目,将jar包下载后导入项目中。

<!-- 支持Excel表格操作 -->
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>3.16</version>
</dependency>
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>3.16</version>
</dependency>

2.JSP 构建一个隐藏文件域,当点击导入时,自动点击弹出选择文件框

<a href="javascript:void(0)" class="easyui-linkbutton" id="importExcel" iconCls="icon-import" plain="true">导入Excel</a>
<%-- 导入Excel start --%>
<input type="file" id="fileElement" name="fileElement" style="filter:alpha(opacity=0);opacity:0;width: 0;height: 0;"/>
<%-- 导入Excel end --%>

3.JS 采用ajaxFileUpload的方式进行上传,需在jsp页面中引入ajaxfileupload.js文件,该文件在百度搜索即可。

/**
 * 页面初始化
 */
$(document).ready(function () {
$("#importExcel").on("click",importExcel); //导入Excel绑定事件
});
/**
 * 导入Excel操作
 * @returns
 */  
function importExcel(){  
    //导入表格url
    var url = "../file/demoStudentFile/importExcel";
    //文件域ID
    var fileId = "fileElement";
    //文件类型名称,用于提示信息
    var fileTypeName = "Excel";
    //文件类型,用于判断文件后缀是否有效
    var fileType = "xls;xlsx";
    //向后台传输的数据,格式为{id:"111"}
    var d = {};
    //调用公用JS文件中的方法
    importUtil(url,d,fileId,fileTypeName,fileType);
}
/**  以下为公用JS中的公用方法,所有导入或上传文件均可直接调用,将文件域ID,文件类型等传递到方法中即可  **/
/**
 * 点击导入或上传按钮,绑定文件域事件,模拟点击,打开文件选择框
 * @param url
 * @param fileId   文件域ID
 * @param fileTypeName  上传的文件类型名称(Word、Excel、PPT...),用于提示信息
 * @param fileType      要求上传的文件类型,各个类型间用英文;隔开 (xls;xlsx),用于判断文件后缀是否有效
 * @returns
 */
function importUtil(url,d,fileId,fileTypeName,fileType){
    //Excel文件域绑定改变事件
    $("#"+fileId).change( function() {
        importFileUtil(url,d,fileId,fileTypeName,fileType);
    });
    $("#"+fileId).trigger("click");
}

/**
 * 传输文件
 * @param url
 * @param fileId   文件域ID
 * @param fileTypeName  上传的文件类型名称(Word、Excel、PPT...),用于提示信息
 * @param fileType      要求上传的文件类型,各个类型间用英文;隔开 (xls;xlsx),用于判断文件后缀是否有效
 * @returns
 */
function importFileUtil(url,d,fileId,fileTypeName,fileType){
    if(checkFileType(fileId,fileTypeName,fileType)){  
       $.ajaxFileUpload({
            url: url, 
            secureuri: false, //是否需要安全协议,一般设置为false
            fileElementId: fileId, //文件上传域的ID
            dataType:"JSON",
            data : d,
            success: function (data, status){ //服务器成功响应处理函数
                var result = $.parseJSON(data);
                $("#"+fileId).val("");
                $.messager.show({ title: '提示', msg: result.msg, timeout: 1000, style: {} });
            },
            error: function (data, status, e){ //服务器响应失败处理函数
                alert("导入失败");
            }
        });
        return false;
    }  
}

/**
 * 校验文件类型
 * @param fileId  文件域ID
 * @param fileTypeName  上传的文件类型名称(Word、Excel、PPT...),用于提示信息
 * @param fileType      要求上传的文件类型,各个类型间用英文;隔开 (xls;xlsx),用于判断文件后缀是否有效
 * @returns
 */  
function checkFileType(fileId,fileTypeName,fileType){  
   var fileDir = $("#"+fileId).val();  
   if("" == fileDir){  
       ts("请选择有效的"+fileTypeName+"文件!");  
       return false;  
   }  
   var suffix = fileDir.substr(fileDir.lastIndexOf(".")+1);  
   var fileTypes = fileType.split(";");
   if(fileTypes.indexOf(suffix)==-1){
       ts("请选择有效的"+fileTypeName+"文件!"); 
       return false;  
   }
   return true;  
} 

4.实体类 DemoStudent.java

package com.project.entity.demo;

import com.project.entity.BaseEntity;

/**
* @author hmz 2017年12月25日 下午5:05:03 学生实体类
*/
@SuppressWarnings("serial")
public class DemoStudent extends BaseEntity {
   private String stuId;// 学生id
   private String name;// 学生姓名
   private String sex;// 学生性别
   private String phone;// 学生电话
   private String address;// 学生地址
   private String message;// 学生自我评价
   private String fkFileId;// 附件ID
   private String fkFileName;// 附件名称

   public String getStuId() {
       return stuId;
   }
   public void setStuId(String stuId) {
       this.stuId = stuId;
   }
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }
   public String getSex() {
       return sex;
   }
   public void setSex(String sex) {
       this.sex = sex;
   }
   public String getPhone() {
       return phone;
   }
   public void setPhone(String phone) {
       this.phone = phone;
   }
   public String getAddress() {
       return address;
   }
   public void setAddress(String address) {
       this.address = address;
   }
   public String getMessage() {
       return message;
   }
   public void setMessage(String message) {
       this.message = message;
   }
   public String getFkFileId() {
       return fkFileId;
   }
   public void setFkFileId(String fkFileId) {
       this.fkFileId = fkFileId;
   }
   public String getFkFileName() {
       return fkFileName;
   }
   public void setFkFileName(String fkFileName) {
       this.fkFileName = fkFileName;
   }
}

5.Controller层 DemoStudentFileController.java 主要用于获取文件并调用Service中方法

package com.project.controller.demo;

import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.project.entity.demo.DemoStudent;
import com.project.service.demo.DemoStudentService;
import com.project.util.cipher.CipherTransport;

/**
 * @ClassName: DemoStudentFileController
    * @Description: TODO
    * @author: HeMengZhu
 * @date: 2018年2月28日 下午3:49:22
 */
@Controller
@CipherTransport
@RequestMapping("/file/demoStudentFile")
public class DemoStudentFileController {
        @Autowired
        private DemoStudentService demoStudentService;

    /**
     * 导入Excel
     * @Title: importExcel
     * @Description: TODO
     * @param file 导入文件 其中@RequestParam("importExcelFile")要与文件域ID一致
     * @param response
     * @throws IOException
     * @return: ResBody<String>
     */
    @ResponseBody
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public void importExcel(@RequestParam("fileElement") MultipartFile file, HttpServletResponse response) throws IOException {
        JSONObject obj = demoStudentService.importExcel(file);
        response.getWriter().print(obj.toString());
    }
}

6.Service层 DemoStudentService.java 主要处理业务逻辑并访问公用方法获取Excel中的数据并做业务处理(此例只将表格中的数据一行一行打印出来,并未做业务处理,所以数据库层代码在此不做展现。需要注意的是,导入操作时需对每一个单元格数据进行验证,包括长度、非空以及与自己业务规则逻辑的验证,且与前台页面上的新增验证理论上应保持一致。)

package com.project.service.demo;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.engine.impl.util.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.project.entity.demo.DemoStudent;
import com.project.mapper.demo.DemoStudentMapper;
import com.project.util.ConstUtil;
import com.project.util.file.ExportExcelUtil;
import com.project.util.file.FileConstUtil;
import com.project.util.file.FileValidateUtil;
import com.project.util.file.ImportExcelUtil;

/**
 * @ClassName: DemoStudentService
 * @Description: TODO
 * @author: HeMengZhu
 * @date: 2018年2月28日 下午3:52:03
 */
@Service
public class DemoStudentService {
    @Autowired
    private DemoStudentMapper demoStudentMapper;
    @Autowired
    private DemoFileService demoFileService;

    /**
     * 导入Excel
     * @Title: importExcel
     * @Description: TODO
     * @param file
     * @param response
     * @return
     * @throws IOException
     * @return: boolean
     */
    @Transactional
    public JSONObject importExcel(MultipartFile file) throws IOException {
        JSONObject obj = new JSONObject();
        InputStream in = null;
        // 定义listob存储表格数据
        List<List<Object>> listob = null;
        try {
            // 判断文件是否存在
            if (file.isEmpty()) {
                obj.put("msg", FileConstUtil.ExcelMessage.FILE_EXISTS);
                // throw new Exception("文件不存在!");
            } else if (!FileConstUtil.ExcelMessage.EXTS.contains(file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1))) {
                // 判断文件类型是否正确
                obj.put("msg", FileConstUtil.ExcelMessage.FILE_EXT_ERROR);
            } else {
                in = file.getInputStream();
                // 获取表格数据
                listob = new ImportExcelUtil().getBankListByExcel(in, file.getOriginalFilename());
                // 该处可调用service相应方法进行数据保存到数据库中,现只对数据输出
                for (int i = 0; i < listob.size(); i++) {
                    List<Object> lo = listob.get(i);
                    DemoStudent stu = new DemoStudent();
                    stu.setId(UUID.randomUUID().toString());
                    stu.setName(String.valueOf(lo.get(1)));
                    stu.setSex(String.valueOf(lo.get(2)));
                    stu.setPhone(String.valueOf(lo.get(3)));
                    System.out.println("打印信息-->id:" + stu.getId() + "  名称:" + stu.getName());
                }
                obj.put("msg", FileConstUtil.ExcelMessage.SUCCESS_MESSAGE);
            }
        } catch (Exception e) {
            e.printStackTrace();
            obj.put("msg", FileConstUtil.ExcelMessage.ERROR_MESSAGE);
        }
        return obj;
    }
}

7.常量类 FileConstUtil.java 主要定义导入表格中的一些常量,比如文件类型、提示信息等等

package com.project.util.file;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @ClassName: FileConstUtil
 * @Description: TODO文件信息常量类
 * @author: HeMengZhu
 * @date: 2018年2月28日 下午4:23:43
 */
public class FileConstUtil {
    /**
     * 导入表格信息
     * @ClassName: ExcelMessage
     * @Description: TODO
     * @author: HeMengZhu
     * @date: 2018年3月1日 下午3:03:32
     */
    public static class ExcelMessage {
        /**
         * 文件不存在提示信息
         */
        public static final String FILE_EXISTS = "文件不存在";
        /**
         * 导入表格后缀格式
         */
        public static final List<String> EXTS = Arrays.asList("xls", "xlsx");
        /**
         * 文件类型不正确提示信息
         */
        public static final String FILE_EXT_ERROR = "请选择正确的文件";
        /**
         * 导入成功提示信息
         */
        public static final String SUCCESS_MESSAGE = "导入成功";
        /**
         * 导入失败提示信息
         */
        public static final String ERROR_MESSAGE = "导入失败";
    }
}

8.工具类 ImportExcelUtil.java 主要为读取Excel表格中的数据等操作

package com.project.util.file;

import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

/**
 * 导入Excel文件工具Service
 * @author HMZ
 * @version 2017年10月8日下午1:02:23
 */
@Service
public class ImportExcelUtil {
    private final static String excel2003L = ".xls"; // 2003- 版本的excel
    private final static String excel2007U = ".xlsx"; // 2007+ 版本的excel

    /**
     * 描述:获取IO流中的数据,组装成List<List<Object>>对象
     * @param in,fileName
     * @return
     * @throws IOException
     */
    public List<List<Object>> getBankListByExcel(InputStream in, String fileName) throws Exception {
        List<List<Object>> list = null;
        // 创建Excel工作薄
        Workbook work = this.getWorkbook(in, fileName);
        if (null == work) {
            throw new Exception("创建Excel工作薄为空!");
        }
        Sheet sheet = null;
        Row row = null;
        Cell cell = null;
        int maxRowNum;
        list = new ArrayList<List<Object>>();
        // 遍历Excel中所有的sheet
        for (int i = 0; i < work.getNumberOfSheets(); i++) {
            sheet = work.getSheetAt(i);
            if (sheet == null) {
                continue;
            }
            // 遍历当前sheet中的所有行
            for (int j = sheet.getFirstRowNum(); j < sheet.getLastRowNum() + 1; j++) {
                row = sheet.getRow(j);
                maxRowNum = sheet.getRow(0).getLastCellNum();
                if (row == null || row.getFirstCellNum() == j) {
                    continue;
                }
                // 遍历所有的列
                List<Object> li = new ArrayList<Object>();
                for (int y = 0; y < maxRowNum; y++) {
                    cell = row.getCell(y);
                    li.add(cell);
                }
                /*
                 * for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) { cell = row.getCell(y); li.add(this.getCellValue(cell)); }
                 */
                if (li.size() > 0) {
                    list.add(li);
                }
            }
        }
        work.close();
        return list;
    }
    /**
     * 描述:根据文件后缀,自适应上传文件的版本
     * @param inStr,fileName
     * @return
     * @throws Exception
     */
    public Workbook getWorkbook(InputStream inStr, String fileName) throws Exception {
        Workbook wb = null;
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        if (excel2003L.equals(fileType)) {
            wb = new HSSFWorkbook(inStr); // 2003-
        } else if (excel2007U.equals(fileType)) {
            wb = new XSSFWorkbook(inStr); // 2007+
        } else {
            throw new Exception("解析的文件格式有误!");
        }
        return wb;
    }
    /**
     * 描述:对表格中数值进行格式化
     * @param cell
     * @return
     */
    public Object getCellValue(Cell cell) {
        Object value = null;
        DecimalFormat df = new DecimalFormat("0"); // 格式化number String字符
        SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd"); // 日期格式化
        DecimalFormat df2 = new DecimalFormat("0.00"); // 格式化数字
        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_STRING:
                value = cell.getRichStringCellValue().getString();
                break;
            case Cell.CELL_TYPE_NUMERIC:
                if ("General".equals(cell.getCellStyle().getDataFormatString())) {
                    value = df.format(cell.getNumericCellValue());
                } else if ("m/d/yy".equals(cell.getCellStyle().getDataFormatString())) {
                    value = sdf.format(cell.getDateCellValue());
                } else {
                    value = df2.format(cell.getNumericCellValue());
                }
                break;
            case Cell.CELL_TYPE_BOOLEAN:
                value = cell.getBooleanCellValue();
                break;
            case Cell.CELL_TYPE_BLANK:
                value = "";
                break;
            default:
                break;
        }
        return value;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,825评论 25 707
  • 对 我说我不难过 我说我不介意 我说我没感觉 我说我不难过
    哦嘛咪呗呗哄阅读 130评论 0 0
  • 你所紧紧维护的,真的是让你感到安全的吗? 2017年8月15日星期二凌晨 心安:安全感,真的安全吗? 这是一期的圆...
    先秦啊阅读 841评论 3 16
  • 512地震的纪念日刚刚过去,我们还有多少人真正记得那场灾难?2008年的那场灾难夺去了太多人的生命,在狂暴的大自然...
    明媚月光阅读 570评论 4 5