一、概述
在工作過程中,都會遇到這樣一個需求,就是將相關的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接口
package com.htf.Interceptor;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
public class XssInterceptor implements HandlerInterceptor {
private static Logger logger = LoggerFactory.getLogger(XssInterceptor.class);
private static Pattern XSS_PATTERN;
// 匹配含有字符:<
public static String regex = ".*<.*";
// 匹配含有字符: alert( )
public static String regex1 = ".*[A|a][L|l][E|e][R|r][T|t]\\s*\\(.*\\).*";
// 匹配含有字符: window.location =
public static String regex2 = ".*[W|w][I|i][N|n][D|d][O|o][W|w]\\.[L|l][O|o][C|c][A|a][T|t][I|i][O|o][N|n]\\s*=.*";
// 匹配含有字符:style = x:expression ( )
public static String regex3 = ".*[S|s][T|t][Y|y][L|l][E|e]\\s*=.*[X|x]:[E|e][X|x].*[P|p][R|r][E|e][S|s]{1,2}[I|i][O|o][N|n]\\s*\\(.*\\).*";
// 匹配含有字符: document.cookie
public static String regex4 = ".*[D|d][O|o][C|c][U|u][M|m][E|e][N|n][T|t]\\.[C|c][O|o]{2}[K|k][I|i][E|e].*";
// 匹配含有字符: eval( )
public static String regex5 = ".*[E|e][V|v][A|a][L|l]\\s*\\(.*\\).*";
// 匹配含有字符: unescape()
public static String regex6 = ".*[U|u][N|n][E|e][S|s][C|c][A|a][P|p][E|e]\\s*\\(.*\\).*";
// 匹配含有字符: execscript( )
public static String regex7 = ".*[E|e][X|x][E|e][C|c][S|s][C|c][R|r][I|i][P|p][T|t]\\s*\\(.*\\).*";
// 匹配含有字符: msgbox( )
public static String regex8 = ".*[M|m][S|s][G|g][B|b][O|o][X|x]\\s*\\(.*\\).*";
// 匹配含有字符: confirm( )
public static String regex9 = ".*[C|c][O|o][N|n][F|f][I|i][R|r][M|m]\\s*\\(.*\\).*";
// 匹配含有字符: prompt( )
public static String regex10 = ".*[P|p][R|r][O|o][M|m][P|p][T|t]\\s*\\(.*\\).*";
// 匹配含有字符: <script> </script>
public static String regex11 = ".*<[S|s][C|c][R|r][I|i][P|p][T|t]>.*";
// 匹配含有字符: <script> </script>
public static String regex12 = ".*<[S|s][C|c][R|r][I|i][P|p][T|t]>.*</[S|s][C|c][R|r][I|i][P|p][T|t]>.*";
// 匹配含有字符: 含有一個符號: 雙引號
public static String regex13 = "[.&[^\"]]*\"[.&[^\"]]*";
// 匹配含有字符: 含有一個符號: 單引號
public static String regex14 = "[.&[^']]*'[.&[^']]*";
// 匹配含有字符: 含有回車換行 和 <script> </script>
public static String regex15 = "[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*<[S|s][C|c][R|r][I|i][P|p][T|t]>.*</[S|s][C|c][R|r][I|i][P|p][T|t]>[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*]";
// 匹配含有字符: <script> </script>
public static String regex16 = ".*<[J|j][A|a][V|v][A|a][S|s][C|c][R|r][I|i][P|p][T|t]>.*</[J|j][A|a][V|v][A|a][S|s][C|c][R|r][I|i][P|p][T|t]>.*";
// 匹配含有字符: 含有回車換行 和 <script> </script>
public static String regex17 = "[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*<[J|j][A|a][V|v][A|a][S|s][C|c][R|r][I|i][P|p][T|t]>.*</[J|j][A|a][V|v][A|a][S|s][C|c][R|r][I|i][P|p][T|t]>[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*]";
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Enumeration<String> params = request.getParameterNames();
StringBuffer str = new StringBuffer();
Map<String, String[]> map = request.getParameterMap();
if (map != null && map.size() != 0) {
Set<String> names = map.keySet();
if (names != null && names.size() != 0) {
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String value = request.getParameter(iterator.next());
str.append(value);
}
}
}
if (Pattern.compile(regex).matcher(str.toString()).matches() || Pattern.compile(regex1).matcher(str.toString()).matches() || Pattern.compile(regex2).matcher(str.toString()).matches() || Pattern.compile(regex3).matcher(str.toString()).matches()
|| Pattern.compile(regex4).matcher(str.toString()).matches() || Pattern.compile(regex5).matcher(str.toString()).matches() || Pattern.compile(regex6).matcher(str.toString()).matches()
|| Pattern.compile(regex7).matcher(str.toString()).matches() || Pattern.compile(regex8).matcher(str.toString()).matches() || Pattern.compile(regex9).matcher(str.toString()).matches() || Pattern.compile(regex10).matcher(str.toString()).matches() || Pattern.compile(regex11).matcher(str.toString()).matches() || Pattern.compile(regex12).matcher(str.toString()).matches() || Pattern.compile(regex13).matcher(str.toString()).matches() || Pattern.compile(regex14).matcher(str.toString()).matches() || Pattern.compile(regex15).matcher(str.toString()).matches() || Pattern.compile(regex16).matcher(str.toString()).matches() || Pattern.compile(regex17).matcher(str.toString()).matches())
{
logger.info("[attack] xss attack");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().print(JSON.toJSONString(AJAXResult.createErrorAjaxResult(AJAXCode.ParamsError), true));
return false;
} else {
return true;
}
}
public static boolean matches(String text) {
if (text == null) {
return false;
}
if (Pattern.compile(regex).matcher(text).matches() || Pattern.compile(regex1).matcher(text).matches() || Pattern.compile(regex2).matcher(text).matches() || Pattern.compile(regex3).matcher(text).matches() || Pattern.compile(regex4).matcher(text).matches() || Pattern.compile(regex5).matcher(text).matches() || Pattern.compile(regex6).matcher(text).matches() || Pattern.compile(regex7).matcher(text).matches() || Pattern.compile(regex8).matcher(text).matches() || Pattern.compile(regex9).matcher(text).matches() || Pattern.compile(regex10).matcher(text).matches() || Pattern.compile(regex11).matcher(text).matches() || Pattern.compile(regex12).matcher(text).matches() || Pattern.compile(regex13).matcher(text).matches() || Pattern.compile(regex14).matcher(text).matches() || Pattern.compile(regex15).matcher(text).matches() || Pattern.compile(regex16).matcher(text).matches() || Pattern.compile(regex17).matcher(text).matches()) {
return true;
}
return false;
}
public static void main(String[] args) {
Pattern pattern = Pattern.compile(regex1);
CharSequence cs = "<Script>alert(\"test)</script>";
System.out.println(pattern.matcher(cs).matches());
}
}