利用POI實現電子表格匯出/匯入操作
阿新 • • 發佈:2020-12-24
利用POI實現電子表格匯出/匯入操作
1. 需要的依賴
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency>
2. 工具類
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /** * Created with IntelliJ IDEA. * User: 楓葉 * Date: 2020/12/22 * Description: excel讀寫工具類,需要poi-4.0.1.jar、poi-ooxml-4.0.1.jar、poi-ooxml-schemas-4.0.1.jar、xmlbeans-3.0.2.jar四個核心jar包 * 還需要commons-collections4-4.2.jar和commons-compress-1.18.jar兩個輔助包 * Version: V1.0 */ @SuppressWarnings("all") public class POIUtil { /** * 根據fileType不同讀取excel檔案 * * @param path 請求硬碟物理路徑中的一個excel檔案可以是xls,也可以是xlsx檔案 * @return 返回資料列表 */ public static List<List<String>> readExcelForPOI(InputStream ins, String fileType) throws IOException { List<List<String>> lists = new ArrayList<>(); Workbook wb = null; if ("xls".equals(fileType)) { // 判斷是2003版本還是2007之後的版本,xls為2003版本,xlsx為2007版本 wb = new HSSFWorkbook(ins); // HSSFWorkbook型別對應2003版本 } else if ("xlsx".equals(fileType)) { wb = new XSSFWorkbook(ins); // XSSFWorkbook型別對應2007之後版本 } else { return null; } Sheet sheet = wb.getSheetAt(0); //假設讀取第一個工作頁sheet,index預設從0開始,如果存在多個sheet,那麼需要迴圈Sheet判斷 for (Row row : sheet) { //迴圈讀取第一個工作頁中的每一行記錄 ArrayList<String> list = new ArrayList<>(); for (Cell cell : row) { // 迴圈讀取一行中的每一列資料 cell.setCellType(CellType.STRING); // 根據不同型別轉化成字串 list.add(cell.getStringCellValue()); // 獲取當前列中的資料 } lists.add(list); } return lists; } public static List<List<String>> readExcelForPOI(String path) { String fileType = path.substring(path.lastIndexOf(".") + 1); // 獲取檔案的字尾名 List<List<String>> lists = null; // 裡面的list代表每一行資料,外面list代表所有行資料,實際專案中,需要把excel中的每一行資料做成POJO物件處理 InputStream is = null; // 生成輸入流 try { lists = readExcelForPOI(is, fileType); } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } } return lists; } /** * 建立Excel.xls 返回一個Workbook物件,外部呼叫方式:首先建立一個OutputStream物件,然後通過workbook.write(out);完成輸出 * * @param lists 需要寫入excel的資料 * @param name 檔名 * @return 返回一個excel poi Workbook物件,如果沒有解析成功,或者沒有傳入資料列表,則會返回null * @throws IOException 如果IO失敗會丟擲異常 */ public static Workbook creatExcelForPOI(List<List<String>> lists, String name) throws IOException { /* 操作excel五個核心 1.Font字型 2.CellStyle樣式單 3.Sheet頁 4.Row行 5.Cell列 企業使用的是DOM4J、SAX完成xml解析,POI完成excel解析 DOM4J:(50M大小以下)解析機制,首先完整讀取xml,把xml所有的內容放入了電腦記憶體中,操作效能極高,而且在使用讀取規則更方便 SAX:解析機制,基於xml每一個節點位置來迴圈讀取載入 POI:解析機制,類似於SAX,並且可以和DOM4J、SAX結合完成讀寫操作 */ Workbook wb = new HSSFWorkbook(); // 建立2003 excel物件 HSSFWorkbook型別對應2003版本 XSSFWorkbook型別對應2007之後版本 Sheet sheet = wb.createSheet(name); // 建立第一個sheet(頁),並命名,注意這裡只建立一頁,如果業務需求,可以新增多頁 Font f = wb.createFont(); // 建立字型 f.setFontHeightInPoints((short) 10); // 建立字型樣式:字型大小 f.setColor(IndexedColors.BLACK.getIndex()); // 建立字型樣式:字型型別(這裡設定的是黑體) f.setBold(true); // 建立字型樣式:粗體 CellStyle cs = wb.createCellStyle(); // 建立單元格每列格式物件 cs.setFont(f); // 把字型樣式儲存到樣式單中 cs.setBorderLeft(BorderStyle.THIN); // 設定具有邊框的效果:左邊框 cs.setBorderRight(BorderStyle.THIN); // 設定具有邊框的效果:右邊框 cs.setBorderTop(BorderStyle.THIN); // 設定具有邊框的效果:上邊框 cs.setBorderBottom(BorderStyle.THIN); // 設定具有邊框的效果:下邊框 cs.setAlignment(HorizontalAlignment.CENTER); // 設定文字居中的效果 if (lists == null || lists.size() == 0) { // 如果沒有傳遞資料列表,則直接返回null return null; } for (int i = 0; i < lists.size(); i++) { // 設定每行每列的值 Row 行,Cell 方格 , Row 和 Cell 都是從0開始計數的 Row row01 = sheet.createRow(i); // 在當前sheet頁上建立一個新行 List<String> listInner = lists.get(i); for (int j = 0; j < listInner.size(); j++) { sheet.setColumnWidth(j, 256 * 35); // 設定列寬。第一個引數表示要為第幾列,第二個引數表示列的寬度,值為畫素值。 Cell cell01 = row01.createCell(j); // 在row行上建立一列 cell01.setCellValue(listInner.get(j)); // 在此列上寫入資料 cell01.setCellStyle(cs); // 在此列上新增樣式 } } return wb; } }
3. 匯出資料庫中的記錄
這裡使用servlet演示,ssm和boot需將程式碼遷移到controller中
/** * @author 楓葉 * @version 1.0 * @date 2020/12/23 */ @WebServlet(value = { "/download/yongHuList" }, name = "download") public class DownLoadServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { YongHuService yongHuService = new YongHuServiceImpl(); //獲取使用者列表 List<YongHu> yongHuList = yongHuService.selectYhList(); List<List<String>> rowList = new ArrayList<>(yongHuList.size()+1); List<String> title = new ArrayList<>(1); title.add("使用者名稱"); title.add("密碼"); title.add("是否鎖定"); title.add("部門"); title.add("許可權"); rowList.add(title); yongHuList.forEach(yongHu -> { List<String> row = new ArrayList<>(5); row.add(yongHu.getYongHuMing()); row.add(yongHu.getMiMa()); row.add(yongHu.getSuoDing() == 0 ? "否" : "是"); row.add(yongHu.getBuMen().getBmMing()); row.add(yongHu.getQuanXian().getQuanXianMing()); rowList.add(row); }); Workbook workbook = POIUtil.creatExcelForPOI(rowList, "使用者"); if (workbook != null) { resp.setCharacterEncoding("UTF-8"); resp.setHeader("Content-Disposition", "attachment; filename=" + System.currentTimeMillis() + ".xls"); //獲取響應報文輸出流物件 ServletOutputStream out = resp.getOutputStream(); //輸出 workbook.write(out); out.flush(); out.close(); } else { resp.setContentType("text/html;charset=utf-8"); resp.getWriter().println(DataResponse.error("系統錯誤,或excel檔案格式錯誤。")); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4. 上傳excel檔案並解析資料存到資料庫
/**
* @author 楓葉
* @version 1.0
* @date 2020/12/23
*/
@WebServlet(value = {
"/upload/yongHuList"
},
name = "upload")
public class UpLoadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
YongHuService yongHuService = new YongHuServiceImpl();
BuMenService buMenService = new BuMenServiceImpl();
QuanXianService quanXianService = new QuanXianServiceImpl();
List<BuMen> buMenList = buMenService.chaXunBuMenList();
List<QuanXian> quanXianList = quanXianService.selectQuanXianList();
// 設定請求物件語言編碼為UTF-8
req.setCharacterEncoding("UTF-8");
//固定寫法
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if (isMultipart) {
// 建立工廠(這裡用的是工廠模式)
DiskFileItemFactory factory = new DiskFileItemFactory();
// 獲取ServletContext
ServletContext servletContext = req.getSession().getServletContext();
// 獲取從ServletContext中得到上傳來的資料,fileupload固定的引數:javax.servlet.context.tempdir
File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
// fileupload封裝上傳來的檔案的各種屬性(上傳來的檔案的大小、檔名等)
factory.setRepository(repository);
// fileupload生成對應的資料引數物件
ServletFileUpload upload = new ServletFileUpload(factory);
// 把request轉成fileupload中FileItem的例項
List<FileItem> items = upload.parseRequest(req);
System.out.println(items);
FileItem item = items.get(0);
String fieldName = item.getName();
System.out.println("檔案:"+fieldName+"讀取成功");
int lastIndex = fieldName.lastIndexOf(".");
String houZhui = fieldName.substring(lastIndex + 1);
System.out.println(houZhui);
if (!("xls".equals(houZhui) || "xlsx".equals(houZhui))) {
resp.getWriter().println(DataResponse.error("只能傳Excel檔案"));
return;
}
InputStream fis = item.getInputStream();
List<List<String>> lists = POIUtil.readExcelForPOI(fis, houZhui);
if (lists == null || lists.size() == 0) {
resp.getWriter().println(DataResponse.error("檔案中沒有資料。"));
return;
}
List<YongHu> yongHuList = new ArrayList<>(lists.size() - 1);
for (int i = 1; i < lists.size(); i++) {
YongHu yongHu = new YongHu();
List<String> row = lists.get(i);
String col1 = row.get(0);
String col2 = row.get(1);
String col3 = row.get(2);
String col4 = row.get(3);
String col5 = row.get(4);
yongHu.setYongHuMing(col1);
yongHu.setMiMa(col2);
short suoDing = (short) ("是".equals(col3) ? 1 : 0);
yongHu.setSuoDing(suoDing);
//將部門名對映成部門id
int bmId = 0;
for (BuMen buMen : buMenList) {
if (buMen.getBmMing().equals(col5)) {
bmId = buMen.getBid();
break;
}
}
yongHu.setBmId(bmId);
//將許可權名對映成許可權id
int qxId = 0;
for (QuanXian quanXian : quanXianList) {
if (quanXian.getQuanXianMing().equals(col5)){
qxId=quanXian.getQxId();
break;
}
}
yongHu.setQxId(qxId);
yongHuList.add(yongHu);
}
//資料存入資料庫
if (yongHuService.addYhList(yongHuList)) {
resp.getWriter().println(DataResponse.ok("成功匯入" + yongHuList.size() + "條資料"));
return;
}
resp.getWriter().println(DataResponse.error("匯入失敗,請嚴格按照檔案模板的格式寫入EXCEL。"));
}
}
}
5. 上面用到的返回封裝類DataResponse如下
public class DataResponse{
private final Map<String,Object> result;
@Override
public String toString() {
//這裡也用到了fastJSON並且設定了日期的格式化格式
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd hh:mm:ss";
return JSON.toJSONString(result,SerializerFeature.WriteDateUseDateFormat);
}
public DataResponse(Integer code,String msg,Object data){
result = new HashMap<>();
result.put("code",code);
result.put("msg",msg);
result.put("data",data);
}
public DataResponse(Integer code,String msg){
this(code,msg,null);
}
public DataResponse() {
result=new HashMap<>();
}
public DataResponse put(String key,Object value){
result.put(key,value);
return this;
}
public static DataResponse ok(){
return new DataResponse(200,"成功!");
}
public static DataResponse ok(String msg){
return new DataResponse(200,msg);
}
public static DataResponse ok(int code,String msg){
return new DataResponse(code,msg);
}
public static DataResponse ok(String msg,Object data){
return new DataResponse(200,msg,data);
}
public static DataResponse ok(int code,String msg,Object data){
return new DataResponse(200,msg,data);
}
public static DataResponse error(){
return new DataResponse(500,"伺服器錯誤,操作失敗!");
}
public static DataResponse error(String msg){
return new DataResponse(500,msg);
}
public static DataResponse error(int code,String msg){
return new DataResponse(code,msg);
}
public Object get(String key){
return result.get(key);
}
public Object getData(){
return result.get("data");
}
public void setCode(int code) {
result.put("code",code);
}
public void setMsg(String msg) {
result.put("msg",msg);
}
public void setData(Object data) {
result.put("data",data);
}
}