批量导入使用的场景挺多的,自己毕设也涉及到了,做个记录。
导包在上一篇里已经提到了,这里就略过,重点记录一下实现的过程。
JSP 界面
这个部分和上传 word 的一样,就是一个 form
<form class="form-horizontal" id="fm_batchImport" method="post" enctype="multipart/form-data">
<input id="batchImport" name="enclosure" type="file"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel">
<a href="studentTemplate">模板下载</a>
<button type="button" onClick="saveBatchImport()">提交</button>
</form>
还是和 word 一样,这里稍微做一个 accept 的验证,其实然并卵,后台还是需要判断。然后还是采用的 Ajax 上传,弄成 formData。
Controller
两个方法,一个是作为导入,一个响应下载导入模板。
//批量导入学生信息
@RequestMapping(value="/batchImport",method=RequestMethod.POST)
@ResponseBody
public Integer batchImport(@ModelAttribute MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception {
int result = studentService.batchImportByAdmin(file, request, response);
return result;
}
//模板下载
@RequestMapping("/studentTemplate")
@ResponseBody
public void studentTemplate(HttpServletRequest request, HttpServletResponse response) {
// excel标题
String[] title = { "学历名称", "专业名称", "学生姓名", "入学时间(yyyy-MM-dd)" };
// excel文件名
String fileName = "批量导入学生信息模板" + System.currentTimeMillis() + ".xls";
// sheet名
String sheetName = "学生模板";
String[][] content = new String[0][title.length];
//创建HSSFWorkbook
HSSFWorkbook wb = ExcelUtil.getHSSFWorkbook(sheetName, title, content, null);
// 响应到客户端
try {
this.setResponseHeader(response, fileName);
OutputStream os = response.getOutputStream();
wb.write(os);
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void setResponseHeader(HttpServletResponse response, String fileName) {
try {
try {
fileName = new String(fileName.getBytes(), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setContentType("application/octet-stream;charset=ISO-8859-1");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
} catch (Exception ex) {
ex.printStackTrace();
}
}
用到一个工具类 ExcelUtil
package com.shms.util;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
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.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
public class ExcelUtil {
private final static String EXCEL2003L = ".xls"; // 2003- 版本的excel
private final static String EXCEL2007U = ".xlsx"; // 2007+ 版本的excel
/**
* 导出Excel
*
* @param sheetName sheet名称
* @param title 标题
* @param values 内容
* @param wb HSSFWorkbook对象
* @return
*/
public static HSSFWorkbook getHSSFWorkbook(String sheetName, String[] title, String[][] values, HSSFWorkbook wb) {
// 第一步,创建一个HSSFWorkbook,对应一个Excel文件
if (wb == null) {
wb = new HSSFWorkbook();
}
// 第二步,在workbook中添加一个sheet,对应Excel文件中的sheet
HSSFSheet sheet = wb.createSheet(sheetName);
// 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
HSSFRow row = sheet.createRow(0);
// 第四步,创建单元格,并设置表头 设置表头居中
HSSFCellStyle style = wb.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式
// 声明列对象
HSSFCell cell = null;
// 创建标题
for (int i = 0; i < title.length; i++) {
cell = row.createCell(i);
cell.setCellValue(title[i]);
cell.setCellStyle(style);
}
// 创建内容
for (int i = 0; i < values.length; i++) {
row = sheet.createRow(i + 1);
for (int j = 0; j < values[i].length; j++) {
// 将内容按顺序赋给对应的列对象
row.createCell(j).setCellValue(values[i][j]);
}
}
return wb;
}
/**
* 导入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; // Sheet页数
Row row = null; // 行数
Cell cell = null; // 列数
list = new ArrayList<List<Object>>();
// 遍历Excel中所有的sheet
// 将最大的列数记录下来
int lastCellNum = 0;
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(); j++) {
row = sheet.getRow(j);
if (row == null || row.getFirstCellNum() == j) {
continue;
}
// 遍历所有的列
List<Object> li = new ArrayList<Object>();
// 比较当前行的列数跟表的最大的列数
if (j == sheet.getFirstRowNum()) {
// 将第一行的列数设为最大
lastCellNum = row.getLastCellNum();
} else {
lastCellNum = lastCellNum > row.getLastCellNum() ? lastCellNum : row.getLastCellNum();
}
for (int y = row.getFirstCellNum(); y < lastCellNum; y++) {
cell = row.getCell(y);
li.add(this.getValue(cell));
}
list.add(li);
}
}
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
*/
// 解决excel类型问题,获得数值
public String getValue(Cell cell) {
String value = "";
if (null == cell) {
return value;
}
switch (cell.getCellType()) {
// 数值型
case NUMERIC:
if (HSSFDateUtil.isCellDateFormatted(cell)) {
// 如果是date类型则 ,获取该cell的date值
Date date = HSSFDateUtil.getJavaDate(cell.getNumericCellValue());
// 根据自己的实际情况,excel表中的时间格式是yyyy-MM-dd HH:mm:ss还是yyyy-MM-dd,或者其他类型
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
// 由于方法的返回值类型为String,这里将Date类型转为String,便于统一返回数据
value = format.format(date);
} else {// 纯数字
BigDecimal big = new BigDecimal(cell.getNumericCellValue());
value = big.toString();
// 解决1234.0 去掉后面的.0
if (null != value && !"".equals(value.trim())) {
String[] item = value.split("[.]");
if (1 < item.length && "0".equals(item[1])) {
value = item[0];
}
}
}
break;
// 字符串类型
case STRING:
value = cell.getStringCellValue().toString();
break;
// 公式类型
case FORMULA:
// 读公式计算值
value = String.valueOf(cell.getNumericCellValue());
if (value.equals("NaN")) {// 如果获取的数据值为非法值,则转换为获取字符串
value = cell.getStringCellValue().toString();
}
break;
// 布尔类型
case BOOLEAN:
value = " " + cell.getBooleanCellValue();
break;
default:
value = cell.getStringCellValue().toString();
}
if ("null".endsWith(value.trim())) {
value = "";
}
return value;
}
}
在工具类中,有一点需要注意,cell.getCellType()的枚举书写,在 4.x 以前,是 Cell.CELL_TYPE_STRING
这种形式,在 4.0.改成了 CellType.STRING
,在最新版中,变成了 STRING
。
其实模板下载,也可以作为后台数据导出 Excel,只需要下载模板里边稍微改一下就行。比如导出成绩表
String[][] content = new String[scoreList.size()][title.length]
for (int i = 0; i < scoreList.size(); i++) {
ScoreWrapper score = scoreList.get(i);
content[i][0] = score.getcId();
content[i][1] = score.getcName();
content[i][2] = score.gettId();
content[i][3] = score.gettName();
content[i][4] = score.getsId();
content[i][5] = score.getsName();
content[i][6] = score.getAvgSubScore().toString();
}
这样,也就把导出的功能完成了。
Service
具体的逻辑处理部分,读取表格数据。
@Override
public Integer batchImportByAdmin(MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception{
if (file.isEmpty()) {
try {
throw new Exception("文件不存在!");
} catch (Exception e) {
e.printStackTrace();
}
}
//这里可以使用String originalFilename = file.getOriginalFilename();
//originalFilename.endsWith(".xls") || originalFilename.endsWith(".xlsx")
//做一个后缀名的判断,从而限制前端的文件格式
InputStream in = null;
try {
in = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
List<List<Object>> listob = null;
try {
listob = new ExcelUtil().getBankListByExcel(in,file.getOriginalFilename());
} catch (Exception e) {
e.printStackTrace();
}
// 该处可调用mapper相应方法进行数据保存到数据库中
for (int i = 0; i < listob.size(); i++) {
List<Object> lo = listob.get(i);
Student student = new Student();
//这里可以做一些数据库查询操作等等..
//这里的lo集合就是Excel表对应的列的数据(第一行默认是表头,不读取)
String.valueOf(lo.get(0));//表示第i行第一列的数据,以此类推...
//把数据塞入student对象,调用mapper方法进行存储
student.setXXX();
studentMapper.insertSelective(student);
}
return ...;
}
这样就完成了 Excel 的批量导入导出功能。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于