一、概述
在工作过程中,都会遇到这样一个需求,就是将相关的Excel中的数据导入数据库,这里写成通用的导入Excel的工具。
二、项目实现
1、构建pom.xml
我的工程是利用Maven来构建的,这里仅给出最核心的包
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.11-beta2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.11-beta2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.11-beta2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-excelant</artifactId>
<version>3.11-beta2</version>
</dependency>
<!-- excel上传用 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
导入之前需要先下载要导入的Excel模板,把数据填写到Excel,然后在导入到数据库中
2.下载Excelm模板通用工具类
/**
*
* 2003导出下载Excel模板
* @param fileName 文件名
* @param titles 导出excel标题
* @param hashMapKeys 导出excel显示的列头(对应pojo里面的属性)
* @Description: 2003版本最大支持65536行
*/
public static void exportExcelTemplate(String fileName, String[] titles, String[] hashMapKeys,HttpServletResponse response) throws IOException{
// 1.创建工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
// 2.在workbook中添加一个sheet,对应Excel文件中的fileName
HSSFSheet sheet = workbook.createSheet(fileName);
// 样式1:定义列宽
for (int i = 0; i < 100; i++) {
sheet.setColumnWidth(i, 6000);
}
//基础样式
HSSFCellStyle baseStyle = workbook.createCellStyle();
//设置单元格居中
baseStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中
baseStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中
//设置边框
baseStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
baseStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); //左边框
baseStyle.setBorderTop(HSSFColor.BLACK.index); //上边框
baseStyle.setBorderRight(HSSFColor.WHITE.index); //右边框
//设置自动换行
baseStyle.setWrapText(true);
//样式2:定义第一行单元格样式
HSSFCellStyle cellStyle = workbook.createCellStyle();
//设置字体
HSSFFont font = workbook.createFont();
font.setFontName("宋体");
font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
// 字体大小
font.setFontHeightInPoints((short) 12);
cellStyle.setFont(font);
//设置单元格居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
//样式3:定义标题单元格样式
HSSFCellStyle cellStyle1 = workbook.createCellStyle();
cellStyle1.cloneStyleFrom(baseStyle);
//设置字体
HSSFFont font1 = workbook.createFont();
font1.setFontName("楷体");
font1.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
font1.setFontHeightInPoints((short) 12);// 字体大小
font1.setColor(HSSFColor.RED.index);//设置红色
cellStyle1.setFont(font1);
//设置背景色
cellStyle1.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
cellStyle1.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
//样式4:定义内容栏单元格样式
HSSFCellStyle cellStyle2 = workbook.createCellStyle();
cellStyle2.cloneStyleFrom(baseStyle);
//设置字体
HSSFFont font2 = workbook.createFont();
font2.setFontName("宋体");
font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
// 字体大小
font2.setFontHeightInPoints((short) 12);
cellStyle2.setFont(font2);
//设置单元格居左和居上
HSSFDataFormat format=workbook.createDataFormat();
cellStyle2.setDataFormat(format.getFormat("@"));
//样式5:定义尾部栏注释单元格样式
HSSFCellStyle cellStyle3 = workbook.createCellStyle();
HSSFFont font3 = workbook.createFont();
font3.setFontName("楷体");
font3.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
font3.setFontHeightInPoints((short) 12);// 字体大小
font3.setColor(HSSFColor.RED.index);//设置红色
cellStyle3.setFont(font3);
//样式6:合并第一行单元格
// Region region1 = new Region(0, (short) 0, 0, (short) (titles.length - 1));
// sheet.addMergedRegion(region1);
//2.创建顶行
HSSFRow rowhead = sheet.createRow(0);
rowhead.setHeight((short) 700);
HSSFCell cellhead = rowhead.createCell(0);
cellhead.setCellValue(fileName.substring(0, fileName.lastIndexOf(".")));
cellhead.setCellStyle(cellStyle);
//3.创建标题行
HSSFRow row = sheet.createRow(0);
// row.setHeight((short) 550);
for (int i = 0; i < titles.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellValue(titles[i]);
cell.setCellStyle(cellStyle1);
}
//4.创建key行
HSSFRow rowi=sheet.createRow(2);
for (int i = 0; i < hashMapKeys.length; i++) {
HSSFCell cell = rowi.createCell(i);
cell.setCellValue(hashMapKeys[i]);
cell.setCellStyle(cellStyle1);
}
HSSFRow row3=sheet.createRow(3);
for (int i = 0; i < hashMapKeys.length; i++) {
HSSFCell cell = row3.createCell(i);
cell.setCellStyle(cellStyle2);
}
//6.输出到Excel表格
//设置响应头
if (fileName.endsWith("xlsx")) {
// response.setContentType("application/vnd.ms-excel");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
} else {
response.setContentType("application/vnd.ms-excel");
}
response.setHeader("Content-disposition", "attachment; fileName=" + URLEncoder.encode(fileName, "UTF-8"));
OutputStream out = response.getOutputStream();
workbook.write(out);
// out.flush();
// out.close();
}
3.下载Excel模板Controller
import com.htf.utils.ExcelUtils;
import com.htf.utils.ImportExcelUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
@Controller
public class ExportExcelController {
public static final String[] KEYS = {"id", "name", "age"};
/**
* @param : [map, response]
* @return : void
* @date : 2018/10/27 16:08
* @exception:
* @Description: 下载excel2003模板测试
*/
@RequestMapping("/downloadTemplate.do")
public void downTemplate(@RequestParam HashMap<String, Object> map, HttpServletResponse response) {
List<Map> list = new ArrayList<>();
//必填字段
String[] key = ExportExcelController.KEYS;
String[] titles = new String[]{"名称", "性别", "年龄", "学校", "班级"};
String fileName = "报表.xls";
try {
ExcelUtils.exportExcelTemplate(fileName, key, titles, response);
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
4.测试下载Excel模板
模板内容如下图
5.导入Excel工具类
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ImportExcelUtils {
/**
* 导入excel
* @param : file 文件
* @param : startRow 起始行
* @param : startColumn 起始列
* @param : endRow
* @param : endColumn
* @return : java.util.List<java.lang.String[]>
* @date : 2018/10/27 16:15
* @exception:
* @Description: 解析excel表XSSF List<String[]>,适用于2007挤以上版本的excel,后缀名为.xlsx或.xls文件
* 默认解析工作簿中的第一张表,如果endRow=-1则默认解析最后一行,如果endColumn=-1则默认解析到startRow行的最后一列,后面的空行也会解析
* 输入的4个参数第几行和第几列都是从1算起,都是字面上的行或列,解析excel时会将所以单元格的类型转化为String类型,没有值的单元格默认值为"",
* 没有任何值的空行会跳过处理
*/
public static List<String[]> importExcel(File file, int startRow, int startColumn, int endRow, int endColumn) throws Exception {
try {
//导入excel文件,获取工作簿
Workbook workbook = WorkbookFactory.create(file);
//获取excel工作表对象,默认去第一个
Sheet sheet = workbook.getSheetAt(0);
//设置默认值,行数从0算起的,列数从1算起的
if (endRow == -1) endRow = sheet.getLastRowNum() + 1;
if (endColumn == -1) endColumn = sheet.getRow(startRow - 1).getLastCellNum();
//定义集合
List<String[]> list = new ArrayList<>();
//给集合中添加数据
for (int i = startRow - 1; i < endRow; i++) {
Row r = sheet.getRow(i);
if (null == r) continue;
String[] strArr = new String[endColumn - startColumn + 1];
for (int j = startColumn - 1; j < endColumn; j++) {
//转化单元格的类型为String类型
if (null != r.getCell(j)) {
r.getCell(j).setCellType(Cell.CELL_TYPE_STRING);
strArr[j] = r.getCell(j).getStringCellValue();
continue;
}
strArr[j] = "";
}
list.add(strArr);
}
return list;
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
6.导入Excel Controller代码
import com.htf.service.ExportExcelService;
import com.htf.utils.ExcelUtils;
import com.htf.utils.ImportExcelUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @Auther: admin
* @Date: 2018/10/1 21:18
* @Description:上传Excel
*/
@Controller
public class ExportExcelController {
/**
* @date : 2018/10/28 11:22
* @param : [request, file, response]
* @return : java.lang.String
* @exception:
* @Description: 导入Excel
*
*/
@RequestMapping("/importExcel.do")
public String importExcel(HttpServletRequest request, @RequestParam("file") CommonsMultipartFile file, HttpServletResponse response) {
StringBuffer buffer = new StringBuffer();
//根据指定类的相对路径来查找
Resource resource = new ClassPathResource("../exportTemplate", this.getClass());
String name = file.getOriginalFilename();
//只能上传.xls后缀的文件
if (!name.endsWith(".xls") && !name.endsWith(".xlsx")) {
buffer.append("必须使用下载模板上传");
}
try {
if (!resource.exists()) {
resource.getFile().mkdir();
}
File fileExcel = new File(resource.getFile().getPath() + "/" + name);
file.getFileItem().write(fileExcel);
//解析文件
List<String[]> list = ImportExcelUtils.importExcel(fileExcel, 1, 1, -1, -1);
//定义信息结果字符串
//定义上传成功计数器
int count = 0;
//对解析的模板进行校验
//1.校验模板是否正确
if (!("类型".equals(list.get(0)[0]) && "数据".equals(list.get(0)[1]))) {
buffer.append("您的模板不正确,第一行第一格必须是类型,第二行第二格必须是数据!!!");
}
//校验是否为XSS代码
// for (int i = 1; i < list.size(); i++) {
// if (XssInterceptor.matches(list.get(i)[1])) {
// buffer.append("该模板里存在恶意代码,请检查后重新上传");
// }
// }
if (list.size() == 0) {
buffer.append("模板数据为空");
}
for (int i = 1; i < list.size(); i++) {
//校验为空的单元格
if (StringUtils.isBlank(list.get(i)[0]) || StringUtils.isBlank(list.get(i)[1])) {
buffer.append("第" + (i + 1) + "行数据为空,不能正确导入");
continue;
}
//2.校验单元格长度大于100字符
if (list.get(i)[1].length() >= 100) {
buffer.append("第" + (i + 1) + "行导入的字符数超过100字,不能正确导入");
continue;
}
//4.校验数据是否重复
HashMap map = new HashMap();
map.put("id", list.get(i)[0]);
map.put("name", list.get(i)[1]);
continue;
}
//5存入数据库
HashMap hashMap = new HashMap();
hashMap.put("id", "");
//存入数据库,调用service里面的方法插入,(传入参数是hashMap)
// excelService.insert(hashMap);
if (count == 0) {
buffer.append("模板数据全部为已导入的重复数据!");
} else {
buffer.append("共存入" + count + "条数据!");
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return "xxx页面";
}
}
7.校验是否为XSS,需要实现 HandlerInterceptor接口