Java生成导出Excel并下载_Java Web上传并解析Excel表格
2015-09-29 09:49:16  By: dwtedx

在软件开发过程中难免需要批量上传与下载、生成报表保存也是常有之事、最近在公司项目开发用到了Excel模版下载、Excel生成、圆满完成、对这一知识点进行整理、资源共享、有不足之处还望批评指正、文章结尾提供了所需jar包的下载、方便大伙使用、下面言归正传


一、Excel的下载

1、Action中、添加响应事件、通过getRealPath获得工程路径、与jsp中获得request.getContextPath()效果相同、fileName为要下载的文件名、经过拼接filePath是xls文件的绝对路径、调用工具类DownLoadUtil中的downLoadUtil方法

public ActionForward downLoadExcelModel(ActionMapping actionMapping,
    ActionForm actionForm, HttpServletRequest request,
    HttpServletResponse response) throws Exception {
    String path = request.getSession().getServletContext().getRealPath("/resources");
    String fileName = "成员模版.xls";
    String filePath = path   "\"   fileName;
    DownLoadUtil.downLoadFile(filePath, response, fileName, "xls");
    return null;
}


2、工具类DownLoadUtil中

public static boolean downLoadFile(String filePath,
    HttpServletResponse response, String fileName, String fileType)
    throws Exception {
    File file = new File(filePath);//根据文件路径获得File文件
    //设置文件类型(这样设置就不止是下Excel文件了,一举多得)
    if("pdf".equals(fileType)){
       response.setContentType("application/pdf;charset=GBK");
    }else if("xls".equals(fileType)){
       response.setContentType("application/msexcel;charset=GBK");
    }else if("doc".equals(fileType)){
       response.setContentType("application/msword;charset=GBK");
    }
    //文件名
    response.setHeader("Content-Disposition", "attachment;filename=""
          new String(fileName.getBytes(), "ISO8859-1")   """);
    response.setContentLength((int) file.length());
    byte[] buffer = new byte[4096];// 缓冲区
    BufferedOutputStream output = null;
    BufferedInputStream input = null;
    try {
        output = new BufferedOutputStream(response.getOutputStream());
        input = new BufferedInputStream(new FileInputStream(file));
        int n = -1;
        //遍历,开始下载
        while ((n = input.read(buffer, 0, 4096)) > -1) {
            output.write(buffer, 0, n);
        }
        output.flush();   //不可少
        response.flushBuffer();//不可少
    } catch (Exception e) {
        //异常自己捕捉       
    } finally {
        //关闭流,不可少
        if (input != null)
            input.close();
        if (output != null)
           output.close();
    }
    return false;
}

这样、就可以完成文件的下载、java程序将文件以流的形式、保存到客户本机


二、Excel的上传与解析(此处方面起见、Excel为N行两列,以为手机号,另一为短号)

对于数据批量上传、就涉及到文件的上传与数据的解析功能、此处运用了第三方jar包、方便快捷、对于文件上传、用到了

commons-fileupload-1.1.1.jar与commons-io-1.1.jar、代码中并没有导入common-io包中的内容、而fielupload包的上传依赖于common-io

所以两者皆不可少、而对于Excel的解析、此处用到了jxl-2.6.jar、下面通过代码对各步骤进行解析

1、jsp文件

对于文件的上传、强烈推荐使用form表单、并设置enctype="multipart/form-data" method="post"、action为处理文件的路径

<form action="/file.action" enctype="multipart/form-data" method="post">
    <input name="file" type="file">
    <input type="button" value="提交">
</form>


2、js文件

通过js文件对上传的文件进行初识的格式验证、判断是否为空以及格式是否正确、正确的话提交表单、由后台对上传的文件处理、此处用的是jQuery、需要导入jquery-***.js,此处使用的是jquery-1.4.2.min.js(最后提供下载地址)

function submitExcel(){
    var excelFile = $("#excelFile").val();
    if(excelFile==´´) {
        alert("请选择需上传的文件!");
        return false;
    }
    if(excelFile.indexOf(´.xls´)==-1){
        alert("文件格式不正确,请选择正确的Excel文件(后缀名.xls)!");
        return false;
    }
    $("#fileUpload").submit();
}


3、Action中

使用common-fileupload包中的类FileItemFactory、ServletFileUpload对请求进行处理、如果是文件、用工具累ExcelUtil处理、不是文件、此处未处理

不过以后开发可以根据需要处理、此处不纍述。(因为如果Excel中如果存在错误记录、还需供用户下载、所以若有错误信息、暂保存在session中、待用户下载后可清空此session)

public ActionForward exportMemberExcel(ActionMapping actionMapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    int maxPostSize = 1000 * 1024 * 1024;
    FileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
    servletFileUpload.setSizeMax(maxPostSize);
    try {
        List fileItems = servletFileUpload.parseRequest(request);
        Iterator iter = fileItems.iterator();
        while (iter.hasNext()) {
            FileItem item = (FileItem) iter.next();
            if (!item.isFormField()) {// 是文件
                Map map = ExcelUtil.excel2PhoneList(item.getInputStream());
                String[][] error = (String[][]) map.get("error");

                if (error.length != 0) {
                    // 如果存在错误,存入内存,供用户保存
                    request.setAttribute("errorFlag", "ture");
                    request.getSession().setAttribute("exportMap", map);
                } else {
                    request.setAttribute("errorFalg", "false");
                    // 获取正确的值填写json
                    String phoneJson = JsonUtil.phoneArray2Json((String[][]) map.get("current"));
                    request.setAttribute("phoneJson", phoneJson);
                }
            } else { // 不是文件,此处不处理,对于text,password等文本框可在此处理
                logger.error("wrong file");
            }
        }
    } catch (Exception e) {
        logger.error("invoke fileUpload error.", e);
    }
    return actionMapping.findForward("queryAccounts");
}


4、工具类ExcelUtil

主要借助jxl包对Excel文件进行解析、获取正确信息以及错误信息、供用户取舍

public static Map excel2PhoneList(InputStream inputStream) throws Exception {
    Map map = new HashMap();
    Workbook workbook = Workbook.getWorkbook(inputStream); // 处理输入流
    Sheet sheet = workbook.getSheet(0);// 获取第一个sheet
    int rows = sheet.getRows(); // 获取总行号
    String[][] curArr = new String[rows][2]; // 存放正确心细
    String[][] errorArr = new String[rows * 2][4]; // 存放错误信息
    int curLines = 0;
    int errorLines = 0;
    for (int i = 1; i < rows; i  ) {// 遍历行获得每行信息
        String phone = sheet.getCell(0, i).getContents();// 获得第i行第1列信息
        String shortNum = sheet.getCell(1, i).getContents();// 短号
        StringBuffer errorMsg = new StringBuffer();
        if (!isRowEmpty(sheet, i)) { // 此行不为空
            // 对此行信息进行正误判断
        }
    } // 行
        // 正误信息存入map,保存
    map.put("current", current);
    map.put("error", error);
    return map;
}

private static boolean isRowEmpty(Sheet sheet, int i) {
    String phone = sheet.getCell(0, i).getContents();// 集团编号
    String shortNum = sheet.getCell(1, i).getContents();// 集团名称
    if (isEmpty(phone) && isEmpty(shortNum))
        return true;
    return false;
}


返回值由Action处理、此处为止、Excel的解析就完成了


三、生成Excel

上文中说到如果存在错误信息、可供用户下载、错误信息存在Session中、下载就需要利用Session中的数据生成Excel文档、供用户保存

1、Action中

Action从Session中获取保存的对象、调用工具类保存、然后删除Session中的内容

public ActionForward downErrorExcel(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception {
    Map map = (Map) request.getSession().getAttribute("exportMap");
    ExcelUtil.createExcel(response, map);
    request.getSession.removeAttribure("exportMap");
    return null;
}


2、工具类ExcelUtil中

public static boolean createExcel(HttpServletResponse response, Map map) {
    WritableWorkbook wbook = null;
    WritableSheet sheet = null;
    OutputStream os = null;
    try {
        response.reset();
        // 生成文件名
        response.setHeader("Content-disposition",
                "attachment; filename="   new String("错误信息".getBytes("GB2312"), "ISO8859-1")   ".xls");
        response.setContentType("application/msexcel");
        os = response.getOutputStream();
        wbook = Workbook.createWorkbook(os);
        sheet = wbook.createSheet("信息", 0);
        int row = 0;
        // 填写表头
        setSheetTitle(sheet, row);
        // 遍历map,填充数据
        setSheetData(sheet, map, row);
        wbook.write();
        os.flush();
    } catch (Exception e) {
        // 自己处理
    } finally {
        try {// 切记,此处一定要关闭流,否则你会下载一个空文件
            if (wbook != null)
                wbook.close();
            if (os != null)
                os.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (WriteException e) {
            e.printStackTrace();
        }
    }
    return false;
}

private static void setSheetTitle(WritableSheet sheet, int row) throws RowsExceededException, WriteException {
    // 设置excel标题格式
    WritableFont wfont = new WritableFont(WritableFont.ARIAL, 12, WritableFont.BOLD, false,
            UnderlineStyle.NO_UNDERLINE, Colour.BLACK);
    WritableCellFormat wcfFC = new WritableCellFormat(wfont);
    // 设置每一列宽度
    sheet.setColumnView(0, 13);
    sheet.setColumnView(1, 13);
    sheet.setColumnView(2, 13);
    sheet.setColumnView(3, 50);
    // 填写第一行提示信息
    sheet.addCell(new Label(0, row, "手机号码", wcfFC));
    sheet.addCell(new Label(1, row, "短号", wcfFC));
    sheet.addCell(new Label(2, row, "原错误行号", wcfFC));
    sheet.addCell(new Label(3, row, "错误原因", wcfFC));
}

private static void setSheetData(WritableSheet sheet, Map map, int row)
        throws RowsExceededException, WriteException {
    WritableFont wfont = new WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false,
            UnderlineStyle.NO_UNDERLINE, Colour.RED);
    WritableCellFormat wcfFC = new WritableCellFormat(wfont);
    // 从map中获取数据
    String[][] error = (String[][]) map.get("error");
    // 遍历并填充
    for (int i = 0; i < error.length; i  ) {
        row  ;
        sheet.addCell(new Label(0, row, error[i][0]));
        sheet.addCell(new Label(1, row, error[i][1]));
        sheet.addCell(new Label(2, row, error[i][2]));
        sheet.addCell(new Label(3, row, error[i][3], wcfFC));
    }
}


Excel文件生成之后、由response传给客户、客户选择路径、就可以下载了、至此、完成了Excel文件下载、解析、和生成的工作、大功一件、希望有所启发

另外、补充一下、火狐fireFox在上传文件时、服务器端并不能获取客户端存取文件的绝对路径、而只是一个文件名、ie8以及低版本上传文件时、服务器可以获得绝对路径、这是火狐的安全机制决定的、所以试图根据上传的文件路径、对文件修改然后保存到原文件

这种是不可取的、一者是因为火狐下获取不到文件路径、二者即使服务器在ie下获得了文件的绝对路径、在创建并修改文件时也只是生成在服务器端、并不能修改客户端的文件、只是提醒下、网上有解决方法、可以自行查阅


最后给贴上Demo的源代码、希望对大家有用、有兴趣的哥们可以下载看看

源代码下载链接: http://dwtedx.com/download.html?bdkey=s/1mgMpkOK 密码: fc7t

若资源对你有帮助、浏览后有很大收获、不妨小额打赏我一下、你的鼓励是维持我不断写博客最大动力

想获取DD博客最新代码、你可以扫描下方的二维码、关注DD博客微信公众号(ddblogs)

或者你也可以关注我的新浪微博、了解DD博客的最新动态:DD博客官方微博(dwtedx的微博)

如对资源有任何疑问或觉得仍然有很大的改善空间、可以对该博文进行评论、希望不吝赐教

为保证及时回复、可以使用博客留言板给我留言: DD博客留言板(dwtedx的留言板)

感谢你的访问、祝你生活愉快、工作顺心、欢迎常来逛逛


快速评论


技术评论

  • 该技术还没有评论、赶快抢沙发吧...
DD记账
top
+