spring boot + vue 使用poi实现Excel导出功能(包括Excel样式调整,以及前后端代码)

本文详细介绍使用Apache POI库在Java后端生成Excel文件,并结合Vue与axios实现在前端下载的功能。涵盖pom.xml依赖配置、代码流程、工具类详解、基于Vue的文件下载方法及效果展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可以直接复制拿来用哟。(#^.^#)

目录

一、pom.xml依赖

二、代码大致流程是这样的

三、后端工具类

四、基于vue,使用axios调用后端接口,实现下载文件的方法

五、看效果


一、pom.xml依赖

		<!--poi文档处理-->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.17</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.17</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>3.17</version>
		</dependency>

二、代码大致流程是这样的

  1. 创建Excle文件对象
  2. 根据创建的Excle文件对象创建Sheet页
  3. 在根据sheet页设置里面的内容
  4. 把文件流对象通过HttpServletResponse返回
  5. 前端模拟a标签,获取流数据,达到下载文件功能。

三、后端工具类

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.CellStyle;

import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;


/**
 * @program: zy
 * @description: Excel工具类
 * @author: zhang yi
 * @create: 2020-08-28 11:08
 */
public class ExcelUtil {

    /**
     * Excel表格导出模板类
     * @param response response对象,返回的是流数据
     * @param list 数据源对象,这里就是最后的列表
     * @param filename 自己定义的文件名。(前后端分离时,无法返回正确的文件名,这里的文件名一般是前端写好传递过来的)
     * @throws IOException
     */
    public static void exportExcelUtil(HttpServletResponse response, List<LinkedHashMap<String,Object>> list, String filename) throws IOException {
        /**创建Excel文件*/
        HSSFWorkbook  sxssfWorkbook = new HSSFWorkbook ();

        /**创建sheet页*/
        HSSFSheet sheet = sxssfWorkbook.createSheet(filename);
        /**设置每一列单元格的宽度,因为一个单元格宽度定了,那么下面多有的单元格高度都确定了,所以这个方法是sheet的*/
        int z=0;
        sheet.setColumnWidth((short)z++, 10*256);//第一列
        sheet.setColumnWidth((short)z++, 12*256);//第二列
        sheet.setColumnWidth((short)z++, 10*256);//第三列
        sheet.setColumnWidth((short)z++, 13*256);//第四列
   

        /**有得时候你想设置统一单元格的高度,就用这个方法*/
//      sheet.setDefaultRowHeight((short)400);    
        
        /**自适应列宽(不合适。数据量大会卡,1000条2分钟)*/
//      sheet.autoSizeColumn(1, true);//设置第一列单元格宽度自适应

        
        /**设置样式,独立的一个CellStyle对象,在后面可以把这个CellStyle对象添加到单元格中,就实现了单元格样式*/
        CellStyle style = sxssfWorkbook.createCellStyle();//创建CellStyle对象
        style.setAlignment(HorizontalAlignment.CENTER);//水平居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
        
        /**字体样式*/
        HSSFFont font = sxssfWorkbook.createFont();//内容样式
        font.setFontHeightInPoints((short)15);//字体大小
        font.setFontName("Courier New");//字体
//        font.setItalic(true);//是否倾斜
        font.setBold(true);//是否加粗
        /**将字体样式加入CellStyle对象中*/
        style.setFont(font);


        /**样式2(按照同样的方法,可以设置多个CellStyle样式对象,这样你哪里需要用到这个样式,就直接添加进来。这些样式可以封装起来,便于单独调用)*/
        CellStyle style2 = sxssfWorkbook.createCellStyle();
//        style2.setAlignment(HorizontalAlignment.CENTER);//水平居中
//        style2.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
        /**字体样式*/
        HSSFFont font2 = sxssfWorkbook.createFont();//内容样式
        font2.setColor(HSSFFont.COLOR_RED);
        font2.setBold(false);//是否加粗
        /**将字体样式加入Style中*/
        style2.setFont(font2);


        /**合并单元格,四个参数依次为:起始行,终止行,起始列,终止列*/
        CellRangeAddress region1 = new CellRangeAddress(0, 1, (short) 0, (short) 8);
        /**把合并后的单元格添加进sheet对象*/
        sheet.addMergedRegion(region1);

        /**创建 行 对象*/
        HSSFRow headTitle = sheet.createRow(0);//起始行数为0
        headTitle.setHeightInPoints(25);//高度
        /**创建 列 对象*/
        HSSFCell cell = headTitle.createCell(0);//起始列数为0
        /**设置单元格的内容*/
        cell.setCellValue(filename);
        /**设置设置样式*/
        cell.setCellStyle(style);


        String[] head={"标题1","标题2","标题3","标题4","标题5"};//标题集合
        /**继续创建 行 对象*/
        HSSFRow headRow = sheet.createRow(2);//起始行数为2,因为之前我们合并单元格占用了2行,所以这里从第三行开始,索引就是2
        /**继续创建 列 对象*/
        for (int i = 0; i < head.length; i++) {
            headRow.createCell(i).setCellValue(head[i]);//把标题添加到列里面
        }
        

        /**前面的标题渲染好了后,这里就开始渲染实际数据了,数据一般放在List集合中,进行遍历渲染*/
        for (LinkedHashMap<String, Object> a : list) {
            int j=0;
            /**创建 行 对象*/
            HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum() + 1);//起始位置就是当前sheet最后一行+1开始
            /**根据行对象,创建列对象*/
            HSSFCell cell1 = dataRow.createCell(j++);
            cell1.setCellValue("我是内容1");
            cell1.setCellStyle(style2);//把之前创建的样式对象CellStyle添加到这个单元格中,这样单元格就有了样式

            dataRow.createCell(j++).setCellValue("我是内容1");
            dataRow.createCell(j++).setCellValue("我是内容1");
            dataRow.createCell(j++).setCellValue("我是内容1");
            dataRow.createCell(j++).setCellValue("我是内容1");
        }


        /****************Excle表格渲染完成后,开始返回流数据*****************/
        /**设置头信息*/
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/vnd.ms-excel");
        /**一定要设置成xlsx格式*/
        response.setHeader("Content-disposition", "attachment;filename=" + filename);
        /**创建一个输出流*/
        ServletOutputStream outputStream = response.getOutputStream();
        /**写入数据*/
        sxssfWorkbook.write(outputStream);
        /**关闭流*/
        outputStream.close();
        sxssfWorkbook.close();
        System.out.println("导出完成");
    }
}

 注意:spring mvc中的注解必须是@Controller,不能添加@ResponseBody。因为这里返回的是流,而不是JSON

四、基于vue,使用axios调用后端接口,实现下载文件的方法

      /**
       * 导出Excle通用
       * @param filename 文件名,前后端分离后,后端返回的是流数据,文件名会失效,所以需要前端指定
       * @param res 后端返回的流数据,直接把axios返回的流数据塞进来
       */
      exportExcel(filename,res){
        const link = document.createElement('a');
        let blob = new Blob([res.data], {type: 'application/vnd.ms-excel'});
        link.style.display = 'none';
        link.href = URL.createObjectURL(blob);
        let num = '';
        for (let i = 0; i < 10; i++) {
          num += Math.ceil(Math.random() * 10)
        }
        link.setAttribute('download', filename + '.xls');
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link)
      }

axios修改(还需要在响应拦截那里修改): 

const config = {responseType: 'blob'};//这一步关键
return new Promise((resolve, reject) => {
      axios.post(url, params, config).then(res => {
        if (res !== `failed`) {
          resolve(res)
        } else {
          reject(res)
        }
      }).catch(err => {
        if (throws_exception) {
          reject(err)
        }
      })
    })
    if (res.status === 200) {
        //这一步关键
      if (res.data instanceof Blob) {
        return Promise.resolve(res.data)
      }
      if (!res.data.result) {
        return Promise.resolve('failed')
      } else {
        return Promise.resolve(res.data.data)
      }
    }

 

五、看效果

当通过后端调用工具类后,会返回一个文件流输入,如下

前端通过axios调用接口,获取到流数据后,塞入到工具类中的变量里。就可以下载文件啦。

具体效果参考如下:

好的,关于您的问题,以下是前后端详细的步骤和代码前端代码使用Vue和ElementUI实现 1. 首先在Vue组件中定义你的表格,要注意的是要使用el-table-column组件定义每一列的数据和显示方式,其中prop属性表示对应的数据字段,label属性表示列名,使用v-model绑定selection数组来记录选中的行: ```html <el-table :data="tableData" v-loading="tableLoading" @selection-change="handleSelectionChange" @sort-change="handleSortChange" style="width: 100%"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column :prop="'id'" label="ID" sortable="custom" width="80"></el-table-column> <el-table-column :prop="'name'" label="姓名" sortable="custom" width="100"></el-table-column> <el-table-column :prop="'age'" label="年龄" sortable="custom" width="80"></el-table-column> <el-table-column :prop="'gender'" label="性别" sortable="custom" width="80"> <template slot-scope="scope"> <span>{{scope.row.gender == 1 ? '男' : '女'}}</span> </template> </el-table-column> <el-table-column :prop="'address'" label="地址"></el-table-column> </el-table> ``` 2. 在模板中添加一个按钮,点击后调用导出方法: ```html <el-button type="primary" @click="handleExport">导出</el-button> ``` 3. 在Vue实例中定义导出方法,首先获取选中行的id数组(selection),然后使用axios发送POST请求到后端,传递ids参数作为选中行id数组,以及fields参数作为要导出的字段数组。注意在请求头中设置Content-Type为application/json,以及Response-Type为arraybuffer,以便正常接收Excel文件流: ```javascript handleExport() { var ids = this.selection.map(item => item.id) var fields = ['id', 'name', 'age', 'gender', 'address'] axios({ method: 'post', url: '/export', data: { ids: ids, fields: fields }, responseType: 'arraybuffer', headers: { 'Content-Type': 'application/json' } }).then(response => { const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' }) const fileName = 'export.xlsx' FileSaver.saveAs(blob, fileName) }).catch(e => { this.$message.error('导出失败') }) } ``` 后端代码使用Spring Boot和Mybatis-Plus实现 1. 首先创建一个实体类,表示数据库中的一行记录,使用Mybatis-Plus的@TableField注解表示对应的字段,以及@TableId注解表示主键: ```java import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class User { @TableId(value = "id", type = IdType.AUTO) private Integer id; @TableField("name") private String name; @TableField("age") private Integer age; @TableField("gender") private Integer gender; @TableField("address") private String address; } ``` 2. 创建一个Mapper接口,继承Mybatis-Plus的BaseMapper接口,用于对User表进行操作,其中的selectExportList方法返回要导出的数据列表,使用@Param注解传递ids和fields参数: ```java import org.apache.ibatis.annotations.Param; import java.util.List; public interface UserMapper extends BaseMapper<User> { List<User> selectExportList(@Param("ids") List<Integer> ids, @Param("fields") List<String> fields); } ``` 3. 创建一个Controller类,用于处理导出请求,使用@RequestBody接收前端传递过来的ids和fields参数,然后调用UserMapper的selectExportList方法获取要导出的数据列表,最后使用EasyPoi进行Excel导出: ```java import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; @RestController public class ExportController { @Autowired private UserMapper userMapper; @RequestMapping("/export") public void export(@RequestBody ExportRequest request, HttpServletResponse response) throws IOException { List<User> userList = userMapper.selectExportList(request.getIds(), request.getFields()); ExportParams params = new ExportParams(null, "用户信息", ExcelType.XSSF); Workbook workbook = ExcelExportUtil.exportExcel(params, User.class, userList); String fileName = "export.xlsx"; response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); workbook.write(response.getOutputStream()); workbook.close(); } } class ExportRequest { private List<Integer> ids; private List<String> fields; // getter, setter, toString省略 } ``` 至此,您可以开始使用以上代码实现您的需求了,希望能对您有所帮助。
评论 71
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值