SpringMVC+poi 完成Excel操作

SpringMVC完成Excel的导入

摘要:

了解使用POI操作Excel的步骤和流程

学会使用jQuery插件用ajax方式上传Excel

环境搭建

1.SSM环境之 pom文件

		<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>

2.web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd ">

	  <!-- 加载Spring容器监听 -->
	  <listener>    
	        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	  </listener>
	  
	  <!-- 设置Spring容器加载配置文件路径 -->
	  <context-param>    
	      <param-name>contextConfigLocation</param-name>    
	      <param-value>WEB-INF/application/applicationContext-*.xml</param-value>
	  </context-param>
	  
	  <!--配置Springmvc核心控制器-->
	  <servlet>          
	        <servlet-name>springmvc</servlet-name>         
	        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	        <load-on-startup>1</load-on-startup>
	  </servlet>    
	  <!--为DispatcherServlet建立映射 -->      
	  <servlet-mapping>  
	        <servlet-name>springmvc</servlet-name>      
	        <url-pattern>*.do</url-pattern>    
	  </servlet-mapping> 
    <welcome-file-list>
    	<welcome-file>main.jsp</welcome-file>
    </welcome-file-list>  
</web-app>

3.SpringMVC文件上传下载处理器

<bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 默认编码 -->
        <property name="defaultEncoding" value="utf-8" />
        <!-- 文件大小最大值 -->
        <property name="maxUploadSize" value="10485760000" />
        <!-- 内存中的最大值 -->
        <property name="maxInMemorySize" value="40960" />
    </bean>

<!-- 文件上传和下载所依赖的jar包 -->
		<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>

4.Excel表 及 实体类

public class InfoVo {

   private String jtbg;
   private String xm;
   private String hy;
   private String bz;
   
   //get和set方法

前端页面

main.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
    <base href="<%=basePath%>">
    <script type="text/javascript" src="lib/jquery/1.9.1/jquery.js"></script>
    <script type="text/javascript" src="js/jquery-form.js"></script>
    <title>My JSP 'index.jsp' starting page</title>
    <script type="text/javascript">
        //ajax 方式上传文件操作
        $(document).ready(function(){
            $('#btn').click(function(){
                debugger
                if(checkData()){
                    $('#form1').ajaxSubmit({
                        url:'uploadExcel/ajaxUpload.do',
                        dataType: 'text',
                        success: resutlMsg,
                        error: errorMsg
                    });
                    function resutlMsg(msg){
                        debugger
                        alert(msg);
                        $("#upfile").val("");
                    }
                    function errorMsg(){
                        alert("导入excel出错!");
                    }
                }
            });
        });

        //JS校验form表单信息
        function checkData(){
            debugger
            var fileDir = $("#upfile").val();
            var suffix = fileDir.substr(fileDir.lastIndexOf("."));
            if("" == fileDir){
                alert("选择需要导入的Excel文件!");
                return false;
            }
            if(".xls" != suffix && ".xlsx" != suffix ){
                alert("选择Excel格式的文件导入!");
                return false;
            }
            return true;
        }
    </script>
</head>

<body>
<div>1.通过简单的form表单提交方式,进行文件的上</br> 2.通过jquery.form.js插件提供的form表单一步提交功能 </div></br>
<form method="POST"  enctype="multipart/form-data" id="form1" action="uploadExcel/upload.do">
    <table>
        <tr>
            <td>上传文件: </td>
            <td> <input id="upfile" type="file" name="upfile"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交" onclick="return checkData()"></td>
            <td><input type="button" value="ajax方式提交" id="btn" name="btn" ></td>
        </tr>
    </table>
</form>

</body>
</html>

Controller层

获取前端的请求然后调用相应的工具类完成处理

import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.ssm.model.Family;
import com.ssm.service.impl.ImportExcelUtil;

@Controller
@RequestMapping("/jsp/uploadExcel")
public class LeadingExcelController {

@RequestMapping("/form")    
public String form(HttpServletRequest request)throws Exception{
     MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;     
       
     InputStream in =null;  
     List<List<Object>> listob = null;  
     MultipartFile file = multipartRequest.getFile("upfile");  
    
     if(file.isEmpty()){  
         throw new Exception("文件不存在!");  
     }  
     in = file.getInputStream();  
     listob = new ImportExcelUtil().getBankListByExcel(in,file.getOriginalFilename());
     in.close();  
    
     //该处可调用service相应方法进行数据保存到数据库中,现只对数据输出  
     for (int i = 0; i < listob.size(); i++) {  
         List<Object> lo = listob.get(i);  
         Family family = new Family();  
         family.setJtbh(String.valueOf(lo.get(0)));  
         family.setXm(String.valueOf(lo.get(1)));  
         family.setHy(String.valueOf(lo.get(2)));  
         family.setBz(String.valueOf(lo.get(3)));  
           
         System.out.println("打印信息-->"+family.toString());  
     }  


    return null;
}

@RequestMapping(value="/ajax")  
public  void  ajaxUploadExcel(HttpServletRequest request,HttpServletResponse response) throws Exception {  
    MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;    
      
      
    InputStream in =null;  
    List<List<Object>> listob = null;  
    MultipartFile file = multipartRequest.getFile("upfile");  
    if(file.isEmpty()){  
        throw new Exception("文件不存在!");  
    }  
      
    in = file.getInputStream();  
    listob = new ImportExcelUtil().getBankListByExcel(in,file.getOriginalFilename());  
      
  //该处可调用service相应方法进行数据保存到数据库中,现只对数据输出  
    for (int i = 0; i < listob.size(); i++) {  
        List<Object> lo = listob.get(i);  
        Family family = new Family();  
        family.setJtbh(String.valueOf(lo.get(0)));  
        family.setXm(String.valueOf(lo.get(1)));  
        family.setHy(String.valueOf(lo.get(2)));  
        family.setBz(String.valueOf(lo.get(3)));  
          
        System.out.println("打印信息-->"+family.toString());  
    }  
      
    PrintWriter out = null;  
    response.setCharacterEncoding("utf-8");  //防止ajax接受到的中文信息乱码  
    out = response.getWriter();  
    out.print("文件导入成功!");  
    out.flush();  
    out.close();  
} 

}

工具类的实现

import java.io.IOException;  
import java.io.InputStream;  
import java.text.DecimalFormat;  
import java.text.SimpleDateFormat;  
import java.util.ArrayList;  
import java.util.List;  
  
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;  
  
  
public class ImportExcelUtil {  
      
    private final static String excel2003L =".xls";    //2003- 版本的excel  
    private final static String excel2007U =".xlsx";   //2007+ 版本的excel  
      
    /** 
     * 描述:获取IO流中的数据,组装成List<List<Object>>对象 
     * @param in,fileName 
     * @return 
     * @throws IOException  
     */  
    public  List<List<Object>> getBankListByExcel(InputStream in,String fileName) throws Exception{  
        List<List<Object>> list = null;  
          
        //创建Excel工作薄  
        Workbook work = this.getWorkbook(in,fileName);  
        if(null == work){  
            throw new Exception("创建Excel工作薄为空!");  
        }  
        Sheet sheet = null;  
        Row row = null;  
        Cell cell = null;  
          
        list = new ArrayList<List<Object>>();  
        //遍历Excel中所有的sheet  
        for (int i = 0; i < work.getNumberOfSheets(); i++) {  
            sheet = work.getSheetAt(i);  
            if(sheet==null){continue;}  
                      /*
                      getFirstRowNum() 能够获取表中第一行的索引 默认从0开始
                      getLastRowNum()

                      */
            //遍历当前sheet中的所有行  
            for (int j = sheet.getFirstRowNum(); j < sheet.getLastRowNum(); j++) {  
                row = sheet.getRow(j);  
                if(row==null||row.getFirstCellNum()==j){continue;}  
                  //当某一行为null或者 为第一行(表头时)时跳过处理
                //遍历所有的列  
                List<Object> li = new ArrayList<Object>();  
                for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {  
                    cell = row.getCell(y);  
                    li.add(this.getCellValue(cell));  
                }  
                list.add(li);  
            }  
        } 
        in.close();  
        return list;  
    }  
      
    /** 
     * 描述:根据文件后缀,自适应上传文件的版本  
     * @param inStr,fileName 
     * @return 
     * @throws Exception 
     */  
    public  Workbook getWorkbook(InputStream inStr,String fileName) throws Exception{  
        Workbook wb = null;  
        String fileType = fileName.substring(fileName.lastIndexOf("."));  
        if(excel2003L.equals(fileType)){  
            wb = new HSSFWorkbook(inStr);  //2003-  
        }else if(excel2007U.equals(fileType)){  
            wb = new XSSFWorkbook(inStr);  //2007+  
        }else{  
            throw new Exception("解析的文件格式有误!");  
        }  
        return wb;  
    }  
  
    /** 
     * 描述:对表格中数值进行格式化 
     * @param cell 
     * @return 
     */  
    public  Object getCellValue(Cell cell){  
        Object value = null;  
        DecimalFormat df = new DecimalFormat("0");  //格式化number String字符  
        SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd");  //日期格式化  
        DecimalFormat df2 = new DecimalFormat("0.00");  //格式化数字  
          
        switch (cell.getCellType()) {  
        case Cell.CELL_TYPE_STRING:  
            value = cell.getRichStringCellValue().getString();  
            break;  
        case Cell.CELL_TYPE_NUMERIC:  
            if("General".equals(cell.getCellStyle().getDataFormatString())){  
                value = df.format(cell.getNumericCellValue());  
            }else if("m/d/yy".equals(cell.getCellStyle().getDataFormatString())){  
                value = sdf.format(cell.getDateCellValue());  
            }else{  
                value = df2.format(cell.getNumericCellValue());  
            }  
            break;  
        case Cell.CELL_TYPE_BOOLEAN:  
            value = cell.getBooleanCellValue();  
            break;  
        case Cell.CELL_TYPE_BLANK:  
            value = "";  
            break;  
        default:  
            break;  
        }  
        return value;  
    }  
}

最终效果

SpringMVC完成导出Excel

首先说明。我这里用的是Apache的POI项目,它是目前比较成熟的HSSF接口,用来处理Excel对象。其实POI不仅仅只能处理excel,它还可以处理word、PowerPoint、Visio、甚至Outlook。

一.首先介绍利用POI如何生成Excel

首先在生成Excel前,我们需要理解一下Excel文件的组织形式。在POI中,是这样理解的:一个Excel文件对应一个workbook,一个workerbook是有若干个sheet组成的。一个sheet有多个row,一个row一般存在多个cell。

对于上面的四个名词我们可以在下图理解:

对于生成Excel,POI提供了如下几个基本对象:

HSSFWorkbook excel 的文档对象

HSSFSheet excel 的表单

HSSFRow excel 的行

HSSFCell excel 的格子单元

从上面的图片和Excel的组织结构,我们就可以明白创建Excel的步骤。

​ 1、生成文档对象HSSHWorkbook。

​ 2、通过HSSFWorkbook生成表单HSSFSheet。

​ 3、通过HSSFSheet生成行HSSFRow

​ 4、通过HSSFRow生成单元格HSSFCell。

环境搭建

1.导入jar包依赖

 	 <dependency>
       <groupId>org.apache.poi</groupId>
       <artifactId>poi-ooxml</artifactId>
          <version>3.9</version>
     </dependency> 

2.创建Model对象

public class Person {

    private String id;
    private String name;
    private String password;
    private String age;
    
    //get和set方法

前端页面

下载界面 exportexcel.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>

<!-- 正常数据导出肯定要传入参数,我这里没有用ajax传参,简单用链接传参 -->
<script type="text/javascript">
function download(){
     var url="download_excel?id=10&name=张三";
     window.open(url);  //window.locatin.href
}
</script>
<body>
<form action="">
<input type="button" value="报表导出" onclick="download()"/>
</form>
</body>
</html>

Controller层

ExcleController.java

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.ssm.service.impl.ExcleImpl;

@Controller
public class ExcleController {
    //这里直接new了
    ExcleImpl  excleImpl=new ExcleImpl();
    
@RequestMapping(value="/jsp/download_excel")    

//获取url链接上的参数
public @ResponseBody String dowm(HttpServletResponse response,@RequestParam("id") String id,@RequestParam("name") String name){
     response.setContentType("application/binary;charset=UTF-8");
              try{
                  ServletOutputStream out=response.getOutputStream();
                  try {
                      //设置文件头:最后一个参数是设置下载文件名(这里我们叫:张三.xls)
                      response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(name+".xls", "UTF-8"));
                  } catch (UnsupportedEncodingException e1) {
                      e1.printStackTrace();
                  }
               
                  String[] titles = { "用户id", "用户姓名", "用户密码", "用户年龄" }; 
                  excleImpl.export(titles, out);      
                  return "success";
              } catch(Exception e){
                  e.printStackTrace();
                  return "导出信息失败";
              }
          }
}

工具类实现

ExcleImpl 报表导出实现层

import java.util.ArrayList;

import javax.servlet.ServletOutputStream;

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;

import com.ssm.model.Person;

public class ExcleImpl {

public void export(String[] titles, ServletOutputStream out) throws Exception{
    try{
                     // 第一步,创建一个workbook,对应一个Excel文件
                     HSSFWorkbook workbook = new HSSFWorkbook();
                     
                     // 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet
                     HSSFSheet hssfSheet = workbook.createSheet("sheet1");
                     
                     // 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
                     
                     HSSFRow row = hssfSheet.createRow(0);
                    // 第四步,创建单元格,并设置值表头 设置表头居中
                     HSSFCellStyle hssfCellStyle = workbook.createCellStyle();
                     
                     //居中样式
                     hssfCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
         
                     HSSFCell hssfCell = null;
                     for (int i = 0; i < titles.length; i++) {
                         hssfCell = row.createCell(i);//列索引从0开始
                         hssfCell.setCellValue(titles[i]);//列名1
                         hssfCell.setCellStyle(hssfCellStyle);//列居中显示                
                     }
                     
                     // 第五步,写入实体数据 
                      Person  person1=new Person("1","张三","123","26");
                      Person  person2=new Person("2","李四","123","18");
                      Person  person3=new Person("3","王五","123","77");
                      Person  person4=new Person("4","徐小筱","123","1");
                      
                      //这里我把list当做数据库啦
                      ArrayList<Person>  list=new ArrayList<Person>();
                      list.add(person1);
                      list.add(person2);
                      list.add(person3);
                      list.add(person4);
                     
                         for (int i = 0; i < list.size(); i++) {
                             row = hssfSheet.createRow(i+1);                
                             Person person = list.get(i);
                             
                             // 第六步,创建单元格,并设置值
                             String  id = null;
                             if(person.getId() != null){
                                     id = person.getId();
                             }
                            row.createCell(0).setCellValue(id);
                             String name = "";
                             if(person.getName() != null){
                                 name = person.getName();
                             }
                            row.createCell(1).setCellValue(name);
                             String password = "";
                             if(person.getPassword() != null){
                                 password = person.getPassword();
                             }
                             row.createCell(2).setCellValue(password);
                             String age=null;
                             if(person.getAge() !=null){
                                 age = person.getAge();
                             }
                             row.createCell(3).setCellValue(age);
                         }
    
                     // 第七步,将文件输出到客户端浏览器
                     try {
                         workbook.write(out);
                         out.flush();
                        out.close();
         
                     } catch (Exception e) {
                         e.printStackTrace();
                     }
                 }catch(Exception e){
                     e.printStackTrace();
                    throw new Exception("导出信息失败!");
                    
                    }
                 }        
}

最终效果

当点击按钮后,浏览器就会弹出一个下载文件框,确定后就能够下载

使用地址重定向 window.location.href要注意的是

传一个很大数据到后台(window.location.href= actionUrl + "?" + data;),就会出问题了,当然,当数据量不大的时候,使用这种方式是极好的。导致这个问题的原因是各种浏览器对URL解析的长度限制是不同的。

  • Microsoft Internet Explorer (Browser):IE浏览器对URL的最大限制为2083个字符,如果超过这个数字,提交按钮没有任何反应。
  • Firefox (Browser):对于Firefox浏览器URL的长度限制为65,536个字符
  • Safari (Browser):URL最大长度限制为 80,000个字符。
  • Opera (Browser):URL最大长度限制为190,000个字符。
  • Google (chrome):url最大长度限制为8182个字符

解决办法 ----使用隐藏form

<a href="javascript:void(0)" onclick="exportExcel()">导出1</a>

// 导出,使用这种方式 可以,使用 ajax请求不可以 导出excel
function exportExcel(){
     var form = $("<form>");  //使用jQuery创建一个<form>表单对象
     form.attr('style', 'display:none');  // 添加样式属性
     form.attr('target', '');
     form.attr('method', 'post');
     form.attr('action', '${pageContext.request.contextPath}/user/export');

     var input1 = $('<input>');  //使用jQuery创建一个<input>对象
     input1.attr('type', 'hidden');
     input1.attr('name', 'item');
     input1.attr('value', 'test');      
    /* JSON.stringify($.serializeObject($('#searchForm'))) */

     $('body').append(form);  //将<form>表单追加到body中
     form.append(input1);   //将<input>追加到<form>中
     
     form.submit();
     form.remove();    
}

使用ajax实现导出Excel

Ajax不能完成导出Excel报表

因为导出excel,实际上是文件下载,后台需要往前端(浏览器)写文件流的。而Ajax请求获取数据都是“字符串”,整个交互传输用的都是字符串数据,它没法解析后台返回的文件流,但浏览器可以。

方案一:

我们可以使用ajax拿到服务端返回的 数据下载流 然后借助 Blob 对象,在动态创建一个链接

实现步骤:

1.ajax请求使用axios库完成,axios的responseType需要设置成 Blob ,默认是json

2.创建 Blob 对象

3.创建 a 标签

4.触发下载动作

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax 文件导出</title>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<button type="button" onclick="exportExcel()">导出</button>

<script type="text/javascript">
    function exportExcel() {
        axios({
            method: 'POST',
            url: "http://localhost:8080/export",
            timeout: 5000,
            responseType: 'blob'
        }).then(function (res) {
            var data = res.data;
            var blob = new Blob([data], {type: 'application/octet-stream'});
            var url = URL.createObjectURL(blob);
            var exportLink = document.createElement('a');
            exportLink.setAttribute("download","ajax文件下载.xlsx");
            exportLink.href = url;
            document.body.appendChild(exportLink);
            exportLink.click();
        })
    }
</script>
</body>
</html>html

后台代码

package com.huan.study.ajax.download;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import com.google.common.collect.Lists;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author huan.fu 2020-06-25 - 13:05
 */
@RestController
@CrossOrigin("*")
public class ExcelDownloadController {

    private static final List<User> USERS = Lists.newArrayList(
            User.builder().age(20).name("张三").build(),
            User.builder().age(18).name("李四").build(),
            User.builder().age(25).name("王五").build()
    );

    @PostMapping("export")
    public void export(HttpServletResponse response) throws IOException {
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=export.xlsx");
        ExportParams exportParams = new ExportParams("学生信息", "导出测试", ExcelType.XSSF);
        ExcelExportUtil.exportExcel(exportParams, User.class, new ArrayList<>(USERS)).write(response.getOutputStream());
    }
}

方案二:

下面是解释:

xhr.responseType = "arraybuffer";
这段代码不加会导致导出的excel出现乱码问题。

xhr.onload内操作如下:使用Blob的构造函数并将取得的response数据作为Blob实例对象的第一个参数,接着这第二个参数type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"可以把表格格式保存为xlsx模式,还有一种是"application/vnd.ms-excel"老版本的用法不需要使用。
由于返回的response数据是二进制流数据所以需借助Blob对象将其转化。另外可能还有其他js插件可以转化这里就不做演示了。

然后创建下载地址以供下载。

最后在页面新增临时a标签点击下载之后remove移除这个dom即可

另外的代码就是增加请求头等需与后端沟通好的信息了
后端需要规定参数的话params里再加就好了,这边传了个空对象。

方案三:

后端代码

List<Custom> excelList = new ArrayList<>();

// excel总体设置
ExportParams exportParams = new ExportParams();
// 指定sheet名字
exportParams.setSheetName("test");
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, Custom.class, excelList);

response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("test", "utf-8") + ".xls");
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.flush();
outputStream.close();

前端代码 -- 使用Jquery的Ajax

var queryParams = {"test":"xxx"};
var url = "xxx";
$.ajax({
	type : "POST", //提交方式
    url : url,//路径
    contentType: "application/json",
    data: JSON.stringify(queryParams),
    beforeSend: function (request) {
    	request.setRequestHeader("Authorization", "xxx");
	},
	success : function(result) {
		const blob = new Blob([result], {type:"application/vnd.ms-excel"});
		if(blob.size < 1) {
			alert('导出失败,导出的内容为空!');
			return;
		}
		if(window.navigator.msSaveOrOpenBlob) {
			navigator.msSaveOrOpenBlob(blob, 'test.xls');
		} else {
			const aLink = document.createElement('a');
            aLink.style.display = 'none';
            aLink.href = window.URL.createObjectURL(blob);
            aLink.download = 'test.xls';
            document.body.appendChild(aLink);
            aLink.click();
            document.body.removeChild(aLink);
		}
	}
});

测试结果

excel能正常导出,但下载下来的excel全是乱码。经过各种找答案,整理了一下可能是以下原因导致:

1、后端未设置字符集,或者在spring框架的过滤器中统一设置了字符集;
2、前端页面未设置字符集编码;
3、需要在ajax中添加 request.responseType = “arraybuffer”;

经过不断测试,我的应该是第三点导致。但在jquery ajax 中添加后仍然不起作用,乱码问题始终无法解决

第二版:前端,使用原生的ajax。后端未变动。

var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("POST", url, true);
xhr.onload = function () {
	const blob = new Blob([this.response], {type:"application/vnd.ms-excel"});
	if(blob.size < 1) {
        alert('导出失败,导出的内容为空!');
        return;
	}
    if(window.navigator.msSaveOrOpenBlob) {
    	navigator.msSaveOrOpenBlob(blob, 'test.xls')
    } else {
        const aLink = document.createElement('a');
        aLink.style.display = 'none';
        aLink.href = window.URL.createObjectURL(blob);
        aLink.download = 'testxls';
        document.body.appendChild(aLink);
        aLink.click();
        document.body.removeChild(aLink);
        return;
	}
}
xhr.setRequestHeader("Authorization", "xxx");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify(queryParams));
原文地址:https://www.cnblogs.com/Qvolcano-blog/p/14422982.html