利用Apache POI实现的功能小应用-实现excel数据的对比和导出
最近遇到一个简单的应用场景,需要写一个简单的小桌面应用的插件,对于一个长久没有用过Swing的web程序员来说,一时间还真是有点手足无措啊,但是没办法也还是硬着头皮花了半天时间给啃下来了,下面简单说下应用场景和简单实现步骤:
场景:一个刚起步的电商公司,由于是轻资产运行,所以对于商品的进出库没有严格的管理,需要发货的时候就去渠道商拿货发货,对退回的货物则直接进入仓库没做统计和处理,就这样不知不觉间仓库的积压货品已经有很多了,继续持续下去可能会影响公司资金的正常流转,所以需要处理的问题就是统计库存中的货品,然后在需要到渠道商拿货的时候看看现在仓库里有没有货品,如果有部分货品则可以减少渠道商直接进货的数目,这样可以持续将仓库的货品盘活从而减轻资金流转中的问题!
解决方案:我这里给出的解决方案其实也不算是解决方案吧,真是一个简单的桌面插件(不得已而为之),首先是让仓库统计现存仓库货品总数行程excel表格,然后采用Apache POI对仓库库存以及订单货品进行对比,从而产生进货清单、仓库出货清单以及仓库剩余货品清单!这里使用到的技术有Apache POI和Swing,其实前面我也有一篇文章写到Apache POI在web应用中的使用【利用Apache POI导出数据到Excel实现】
由于时间的限制和功能的不多但是又要给用户呈现一个简单的可操作的界面,对于一个Java程序员来说想到的第一想法就是采用web去做,但是采用web的话我们后期运行需要长久使用一台web服务器,所以经过纠结之后狠心下来采用Swing来实现,然后由于我们在库存方擅长使用的工具是excel,所以在这里我们也就没有数据库了,操作的就是我们的excel,按照之前的经验想要操作excel那就直接用Apache POI吧,这是我毫无悬念的一个想法,但是在使用过程中破会发现一些问题,例如在excel 2003和excel 2007做同一代码处理的时候回出现错误问题,所以在这里我写了一个简单的同一处理的工具类用于读取指定路径下的excel数据,简单代码如下:
package com.weidian.whareHouse; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFCell; 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; /** * ClassName: ImportExecl * * @Description: excel操作 * @author dapengniao * @date 2016年4月23日 下午1:50:47 */ public class ImportExecl { /** 总行数 */ private int totalRows = 0; /** 总列数 */ private int totalCells = 0; /** 错误信息 */ private String errorInfo; /** 构造方法 */ public ImportExecl() { } /** * @Description: 得到总行数 * @param @return * @author dapengniao * @date 2016年4月23日 下午1:51:45 */ public int getTotalRows() { return totalRows; } /** * @Description: 得到总列数 * @param @return * @author dapengniao * @date 2016年4月23日 下午1:52:17 */ public int getTotalCells() { return totalCells; } /** * @Description: 得到错误信息 * @param @return * @author dapengniao * @date 2016年4月23日 下午1:52:34 */ public String getErrorInfo() { return errorInfo; } /** * @Description: 验证excel文件 * @param @param filePath * @param @return * @author dapengniao * @date 2016年4月23日 下午1:53:27 */ public boolean validateExcel(String filePath) { /** 检查文件名是否为空或者是否是Excel格式的文件 */ if (filePath == null || !(WDWUtil.isExcel2003(filePath) || WDWUtil .isExcel2007(filePath))) { errorInfo = "文件名不是excel格式"; return false; } /** 检查文件是否存在 */ File file = new File(filePath); if (file == null || !file.exists()) { errorInfo = "文件不存在"; return false; } return true; } /** * @Description: 根据文件名读取excel文件 * @param @param filePath * @param @return * @author dapengniao * @date 2016年4月23日 下午1:54:38 */ public List<List<String>> read(String filePath) { List<List<String>> dataLst = new ArrayList<List<String>>(); InputStream is = null; try { /** 验证文件是否合法 */ if (!validateExcel(filePath)) { System.out.println(errorInfo); return null; } /** 判断文件的类型,是2003还是2007 */ boolean isExcel2003 = true; if (WDWUtil.isExcel2007(filePath)) { isExcel2003 = false; } /** 调用本类提供的根据流读取的方法 */ File file = new File(filePath); is = new FileInputStream(file); dataLst = read(is, isExcel2003); is.close(); } catch (Exception ex) { } finally { if (is != null) { try { is.close(); } catch (IOException e) { is = null; } } } /** 返回最后读取的结果 */ return dataLst; } /** * @Description: 根据流读取Excel文件 * @param @param inputStream * @param @param isExcel2003 * @param @return * @author dapengniao * @date 2016年4月23日 下午1:55:41 */ public List<List<String>> read(InputStream inputStream, boolean isExcel2003) { List<List<String>> dataLst = null; try { /** 根据版本选择创建Workbook的方式 */ Workbook wb = null; if (isExcel2003) { wb = new HSSFWorkbook(inputStream); } else { wb = new XSSFWorkbook(inputStream); } dataLst = read(wb); } catch (IOException e) { } return dataLst; } /** * @Description: 读取数据 * @param @param wb * @param @return * @author dapengniao * @date 2016年4月23日 下午1:56:19 */ private List<List<String>> read(Workbook wb) { List<List<String>> dataLst = new ArrayList<List<String>>(); /** 得到第一个shell */ Sheet sheet = wb.getSheetAt(0); /** 得到Excel的行数 */ this.totalRows = sheet.getPhysicalNumberOfRows(); /** 得到Excel的列数 */ if (this.totalRows >= 1 && sheet.getRow(0) != null) { this.totalCells = sheet.getRow(0).getPhysicalNumberOfCells(); } /** 循环Excel的行 */ for (int r = 0; r < this.totalRows; r++) { Row row = sheet.getRow(r); if (row == null) { continue; } List<String> rowLst = new ArrayList<String>(); /** 循环Excel的列 */ for (int c = 0; c < this.getTotalCells(); c++) { Cell cell = row.getCell(c); String cellValue = ""; if (null != cell) { // 以下是判断数据的类型 switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_NUMERIC: // 数字 cellValue = cell.getNumericCellValue() + ""; break; case HSSFCell.CELL_TYPE_STRING: // 字符串 cellValue = cell.getStringCellValue(); break; case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean cellValue = cell.getBooleanCellValue() + ""; break; case HSSFCell.CELL_TYPE_FORMULA: // 公式 cellValue = cell.getCellFormula() + ""; break; case HSSFCell.CELL_TYPE_BLANK: // 空值 cellValue = ""; break; case HSSFCell.CELL_TYPE_ERROR: // 故障 cellValue = "非法字符"; break; default: cellValue = "未知类型"; break; } } rowLst.add(cellValue); } /** 保存第r行的第c列 */ dataLst.add(rowLst); } return dataLst; } /** * @Description: main测试方法 * @param @param args * @param @throws Exception * @author dapengniao * @date 2016年4月23日 下午1:57:23 */ public static void main(String[] args) throws Exception { ImportExecl poi = new ImportExecl(); List<List<String>> list = poi.read("C:/weidian/wh.xlsx"); if (list != null) { for (int i = 0; i < list.size(); i++) { System.out.print("第" + (i) + "行"); List<String> cellList = list.get(i); for (int j = 0; j < cellList.size(); j++) { // System.out.print(" 第" + (j + 1) + "列值:"); System.out.print(" " + cellList.get(j)); } System.out.println(); } } } } /** * ClassName: WDWUtil * * @Description: 工具类 * @author dapengniao * @date 2016年4月23日 下午1:58:25 */ class WDWUtil { /** * @Description: 是否是2003的excel,返回true是2003 * @param @param filePath * @param @return * @author dapengniao * @date 2016年4月23日 下午1:58:44 */ public static boolean isExcel2003(String filePath) { return filePath.matches("^.+\\.(?i)(xls)$"); } /** * @Description: 是否是2007的excel,返回true是2007 * @param @param filePath * @param @return * @author dapengniao * @date 2016年4月23日 下午1:59:02 */ public static boolean isExcel2007(String filePath) { return filePath.matches("^.+\\.(?i)(xlsx)$"); } }
到这里我们对于使用Apache POI读取excel就可以完成了,但是前面我们有说到的就是我们的界面展示使用的是Swing,简单界面如下:
在这个界面中我们可以看到使用的组件仅有容器【JFrame】、菜单【JMenuBar】和按钮【JButton】,然后就是对他们做事件的监听事件,简单代码如下:
package com.weidian.whareHouse; import java.awt.GridLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.FileOutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; 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.hssf.usermodel.HSSFWorkbook; /** * ClassName: 仓库插件的主界面! * * @Description: TODO * @author dapengniao * @date 2016年4月23日 下午2:42:40 */ public class MainFrame extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; private JMenuBar menuBar; public JPanel jPanel; public JButton whbutton, yzbutton; public static String whsrc, yzsrc,outsrc; public int whoutnum=1,jhnum=1; public JButton button; public MainFrame() { super(); this.setSize(800, 300); jPanel = new JPanel(new GridLayout(3, 1)); whbutton = new JButton("请选择仓库库存表格!"); yzbutton = new JButton("请选订单文件!"); button = new JButton("导出货单"); jPanel.add(whbutton); jPanel.add(yzbutton); whbutton.addActionListener(this); whbutton.setActionCommand("1"); yzbutton.addActionListener(this); yzbutton.setActionCommand("2"); jPanel.add(button); button.addActionListener(this); button.setActionCommand("4"); add(jPanel); this.setJMenuBar(this.getMenu());// 添加菜单 this.setTitle("仓库工具!---by 大鹏鸟");// 设置窗口标题 } /** * 菜单的级别JMenuBar->JMenu->JMenuItem 三级都是1:n的关系 最后添加菜单用的SetJMenuBar方法 * * @return 建立好的菜单 */ private JMenuBar getMenu() { if (menuBar == null) { menuBar = new JMenuBar(); JMenu m1 = new JMenu(); m1.setText("文件"); JMenu m2 = new JMenu(); m2.setText("帮助"); JMenuItem item11 = new JMenuItem(); item11.setText("选择仓库库存表格"); JMenuItem item12 = new JMenuItem(); item12.setText("选择订单表格"); JMenuItem item22 = new JMenuItem(); item22.setText("退出!"); m1.add(item11); m1.add(item12); item11.addActionListener(this); item11.setActionCommand("1"); item12.addActionListener(this); item12.setActionCommand("2"); m2.add(item22); item22.addActionListener(this); item22.setActionCommand("3"); menuBar.add(m1); menuBar.add(m2); } return menuBar; } public static void main(String[] args) throws Exception { MainFrame frame1 = new MainFrame(); frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 一定要设置关闭 frame1.setVisible(true); // 设置可见性 } @Override // 事件处理 public void actionPerformed(ActionEvent e) { switch (e.getActionCommand().charAt(0)) { case '1': try{ // item11 的事件 JFileChooser fd = new JFileChooser(); fd.showOpenDialog(null); String whpath = fd.getSelectedFile().getPath(); if (whpath.length() > 0) { whbutton.setText("仓库库存表格文件目录:" + whpath); whsrc = whpath; } }catch(Exception eone){ JOptionPane.showMessageDialog(null, "请重新选择仓库表格目录!", "提示框!",JOptionPane.INFORMATION_MESSAGE); // System.exit(0); } break; case '2': try{ // item12 的事件 JFileChooser fdtwo = new JFileChooser(); fdtwo.showOpenDialog(null); String yzpath = fdtwo.getSelectedFile().getPath(); outsrc=fdtwo.getSelectedFile().getParent(); if (yzpath.length() > 0) { yzbutton.setText("订单源文件目录:" + yzpath); yzsrc = yzpath; } }catch(Exception etwo){ JOptionPane.showMessageDialog(null, "请重新选择订单表格目录!", "提示框!",JOptionPane.INFORMATION_MESSAGE); } break; case '3': System.exit(0); break; case '4': try { // whsrc="C:/weidian/wh.xlsx"; ImportExecl poi = new ImportExecl(); List<List<String>> whlist = poi.read(whsrc); Map<Integer, Object> whlistone = new HashMap<>(); Map<Integer, Object> whlisttwo = new HashMap<>(); Map<Integer, Object> whlistthree = new HashMap<>(); Map<Integer, Object> whlistfour = new HashMap<>(); Map<Integer, Object> whlistfive = new HashMap<>(); if (whlist != null) { for (int i = 1; i < whlist.size(); i++) { System.out.print("仓库==========第" + (i) + "行"); List<String> cellList = whlist.get(i); // for (int j = 0; j < cellList.size(); j++) { // System.out.print(" " + cellList.get(j)); // } whlistone.put(i,cellList.get(0)); whlisttwo.put(i,cellList.get(1)); whlistthree.put(i,cellList.get(2)); whlistfour.put(i,cellList.get(3)); whlistfive.put(i,cellList.get(4)); System.out.println(); } } else { System.out.println("仓库表格是空的!"); } Map<Integer, Object> yzlistone = new HashMap<>(); Map<Integer, Object> yzlisttwo =new HashMap<>(); Map<Integer, Object> yzlistthree = new HashMap<>(); Map<Integer, Object> yzlistfour = new HashMap<>(); // yzsrc="C:/weidian/yz.xlsx"; List<List<String>> yzlist = poi.read(yzsrc); if (yzlist != null) { for (int i = 1; i < yzlist.size(); i++) { System.out.print("有赞=======第" + (i) + "行"); List<String> cellList = yzlist.get(i); // for (int j = 0; j < cellList.size(); j++) { // System.out.print(" " + cellList.get(j)); // } yzlistone.put(i,cellList.get(0)); yzlisttwo.put(i,cellList.get(1)); yzlistthree.put(i,cellList.get(2)); yzlistfour.put(i,cellList.get(3)); System.out.println(); } } else { System.out.println("订单表格是空的!"); } //仓库剩余库存 // 第一步,创建一个webbook,对应一个Excel文件 HSSFWorkbook whwb = new HSSFWorkbook(); // 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet HSSFSheet whsheet = whwb.createSheet("仓库剩余库存"); // 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short HSSFRow whrow = whsheet.createRow((int) 0); // 第四步,创建单元格,并设置值表头 设置表头居中 HSSFCellStyle whstyle = whwb.createCellStyle(); whstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式 HSSFCell whcell = whrow.createCell((short) 0); whcell.setCellStyle(whstyle); whcell.setCellValue("商家编码(商品)"); whcell = whrow.createCell((short) 1); whcell.setCellStyle(whstyle); whcell.setCellValue("商家编码(SKU)"); whcell = whrow.createCell((short) 2); whcell.setCellStyle(whstyle); whcell.setCellValue("颜色"); whcell = whrow.createCell((short) 3); whcell.setCellStyle(whstyle); whcell.setCellValue("尺码"); whcell = whrow.createCell((short) 4); whcell.setCellStyle(whstyle); whcell.setCellValue("件数"); //仓库出货表格 HSSFWorkbook whoutwb = new HSSFWorkbook(); HSSFSheet whoutsheet = whoutwb.createSheet("仓库出货表格"); HSSFRow whoutrow = whoutsheet.createRow((int) 0); HSSFCellStyle whoutstyle = whoutwb.createCellStyle(); whoutstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式 HSSFCell whoutcell = whoutrow.createCell((short) 0); whoutcell.setCellStyle(whoutstyle); whoutcell.setCellValue("商家编码(商品)"); whoutcell = whoutrow.createCell((short) 1); whoutcell.setCellStyle(whoutstyle); whoutcell.setCellValue("商家编码(SKU)"); whoutcell = whoutrow.createCell((short) 2); whoutcell.setCellStyle(whoutstyle); whoutcell.setCellValue("尺码型号"); whoutcell = whoutrow.createCell((short) 3); whoutcell.setCellStyle(whoutstyle); whoutcell.setCellValue("件数"); //市场进货表格 HSSFWorkbook jhwb = new HSSFWorkbook(); HSSFSheet jhsheet = jhwb.createSheet("市场进货表格"); HSSFRow jhrow = jhsheet.createRow((int) 0); HSSFCellStyle jhstyle = jhwb.createCellStyle(); jhstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式 HSSFCell jhcell = jhrow.createCell((short) 0); jhcell.setCellStyle(jhstyle); jhcell.setCellValue("商家编码(商品)"); jhcell = jhrow.createCell((short) 1); jhcell.setCellStyle(jhstyle); jhcell.setCellValue("商家编码(SKU)"); jhcell = jhrow.createCell((short) 2); jhcell.setCellStyle(jhstyle); jhcell.setCellValue("尺码型号"); jhcell = jhrow.createCell((short) 3); jhcell.setCellStyle(jhstyle); jhcell.setCellValue("件数"); for(int n=1;n<=yzlistone.size();n++){ //有赞订单 System.out.println(); System.out.println("有赞============"+yzlistone.size()+"=================="+n); String yzname=yzlistone.get(n).toString(); String yzsku=yzlisttwo.get(n).toString(); String yzstyle=yzlistthree.get(n).toString(); double yznum=Double.parseDouble(yzlistfour.get(n).toString()); //有赞订单数 String yzindex=yzname+yzsku+yzstyle; System.out.println("yzindex====="+yzindex); for(int m=1;m<=whlistone.size();m++){ System.out.println("仓库==============="+whlistone.size()+"==============="+m); //仓库库存 String whname=whlistone.get(m).toString(); String whsku=whlisttwo.get(m).toString(); String whcolor=whlistthree.get(m).toString(); String whsize=whlistfour.get(m).toString(); String whindex=whname+whsku+whcolor+whsize; double whnum=Double.parseDouble(whlistfive.get(m).toString());//仓库数 System.out.println("whindex====="+whindex); if(yzindex.equals(whindex)){ //仓库中存在订单列表中的货 if(whnum==yznum){//仓库中的值刚好等于有赞订单数 // 出库数 break; }else if(whnum>yznum){ //仓库数大于订单数 // 出库数 break; }else if(whnum<yznum){//仓库数小于订单数 需进货 //出货数 //进货数 break; } }else if(m==whlistone.size()){//仓库中没货 全部进货 } } } for(int k=1;k<=whlistone.size();k++){ //仓库残留数 } FileOutputStream whfileOut = new FileOutputStream(outsrc+"/剩余仓库.xlsx"); whwb.write(whfileOut); whfileOut.close(); FileOutputStream whoutfileOut = new FileOutputStream(outsrc+"/仓库出货.xlsx"); whoutwb.write(whoutfileOut); whoutfileOut.close(); FileOutputStream jhfileOut = new FileOutputStream(outsrc+"/进货.xlsx"); jhwb.write(jhfileOut); jhfileOut.close(); whoutnum=1; jhnum=1; Toolkit.getDefaultToolkit().beep(); JOptionPane.showMessageDialog(null, "数据导出成功!", "提示框!",JOptionPane.INFORMATION_MESSAGE); } catch (Exception es) { System.out.println(es.getLocalizedMessage()); JOptionPane.showMessageDialog(null, "数据导出失败,即将退出重新操作!", "提示框!",JOptionPane.INFORMATION_MESSAGE); System.exit(0); } break; } } }
在上面的代码中我们最后将文件存储在初始源文件的目录结构下,其实整个代码的实现就基本就是这些了,写这篇文章的主要目的还是记录下这半天的工作成果吧,也方便后面遇到相似的需求的时候可以查找记录提供资料参考,感谢你的翻阅,如有疑问可以留言讨论!
文章评论