Spring MVC 实例:Excel视图的使用

  对于Excel而言,Spring MVC所推荐的是使用AbstractXlsView,它实现了视图接口,从其命名也可以知道它只是一个抽象类,不能生成实例对象。它自己定义了一个抽象方法——buildExcelDocument要去实现。其他的方法Spring的AbstractXlsView已经实现了,所以对于我们而言完成这个方法便可以使用Excel的视图功能了
  buildExcelDocument方法的主要任务是创建一个Workbook,它要用到POI的API,这需要我们自行下载并导入项目中。这里的参数在代码中也给出了,在Spring MVC中已经对导出Excel进行了很多的封装,所以很多细节我们并不需要关心。

<!-- poi -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>

  假设需要一个导出所有角色信息的功能,但是将来也许还有其他的导出功能。为了方便,先定义一个接口,这个接口主要是让开发者自定义生成Excel的规则,如代码清单15-46所示。
  代码清单15-46:自定义导出接口定义

package com.ssm.chapter15.view;

import org.apache.poi.ss.usermodel.Workbook;

import java.util.Map;

public interface ExcelExportService {

    /***
     * 生成exel文件规则
     * @param model 数据模型
     * @param workbook excel workbook
     */
    public void makeWorkBook(Map<String, Object> model, Workbook workbook);

}

  有了这个接口还需要完成一个可实例化的Excel视图类——ExcelView,对于导出而言还需要一个下载文件名称,所以还会定义一个文件名(fileName)属性,由于该视图不是一个逻辑视图,所以无须视图解析器也可以运行它,其定义如代码清单15-47所示。
  代码清单15-47:定义Excel视图

package com.ssm.chapter15.view;

import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.view.document.AbstractXlsView;

public class ExcelView extends AbstractXlsView {

    //文件名
    private String fileName = null;

    //导出视图自定义接口
    private ExcelExportService excelExpService = null;

    //构造方法1
    public ExcelView(ExcelExportService excelExpService) {
        this.excelExpService = excelExpService;
    }

    //构造方法2
    public ExcelView(String viewName, ExcelExportService excelExpService) {
        this.setBeanName(viewName);
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public ExcelExportService getExcelExpService() {
        return excelExpService;
    }

    public void setExcelExpService(ExcelExportService excelExpService) {
        this.excelExpService = excelExpService;
    }

    @Override
    protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {

        //没有自定义接口
        if (excelExpService == null) {
            throw new RuntimeException("导出服务接口不能为null!!");
        }
        // 文件名不为空,为空则使用请求路径中的字符串作为文件名
        if (!StringUtils.isEmpty(fileName)) {

            //进行字符转换
            String reqCharset = request.getCharacterEncoding();
            reqCharset = reqCharset == null ? "UTF-8" : reqCharset;
            fileName = new String(fileName.getBytes(reqCharset), "ISO8859-1");
            // 设置下面文件名
            response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        }
        // 回调接口方法,使用自定义生成Excel文档
        excelExpService.makeWorkBook(model, workbook);
    }
}

  上面的代码实现了生成Excel的buildExcelDocument方法,这样就完成了一个视图类。回调了自定义的接口方法可以根据需要进行自定义生成Excel的规则,接着我们需要在角色控制器中加入新的方法,来满足导出所有角色的要求,如代码清单15-48所示。

  代码清单15-48:使用ExcelView导出Excel

package com.ssm.chapter15.controller;

import com.ssm.chapter15.pojo.PageParams;
import com.ssm.chapter15.pojo.Role;
import com.ssm.chapter15.pojo.RoleParams;
import com.ssm.chapter15.view.ExcelExportService;
import com.ssm.chapter15.view.ExcelView;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/excel")
public class ExcelController {

    @RequestMapping(value = "/export", method = RequestMethod.GET)
    public ModelAndView export() {
        //模型和视图
        ModelAndView mv = new ModelAndView();
        // Excel视图,并设置自定义导出接口
        ExcelView ev = new ExcelView(exportService());
        //文件名
        ev.setFileName("所有角色.xlsx");
        // // 设置SQL后台参数
        // RoleParams roleParams = new RoleParams();
        // // 限制1万条
        // PageParams page = new PageParams();
        // page.setStart(0);
        // page.setLimit(10000);
        // roleParams.setPageParams(page);
        // 查询
        // List<Role> roleList = roleService.findRoles(roleParams);
        List<Role> roleList = new ArrayList<>();
        roleList.add(new Role(1l, "射手", "远程物理输出"));
        roleList.add(new Role(2l, "法师", "魔法输出"));
        // 加入数据模型
        mv.addObject("roleList", roleList);
        mv.setView(ev);
        return mv;
    }

    @SuppressWarnings({"unchecked"})
    private ExcelExportService exportService() {
        // 使用Lambda表达式自定义导出excel规则
        return (Map<String, Object> model, Workbook workbook) -> {
            // 获取用户列表
            List<Role> roleList = (List<Role>) model.get("roleList");
            // 生成Sheet
            Sheet sheet = workbook.createSheet("所有角色");
            // 加载标题
            Row title = sheet.createRow(0);
            title.createCell(0).setCellValue("编号");
            title.createCell(1).setCellValue("名称");
            title.createCell(2).setCellValue("备注");
            //便利角色列表,生成一行行的数据
            for (int i = 0; i < roleList.size(); i++) {
                Role role = roleList.get(i);
                int rowIdx = i + 1;
                Row row = sheet.createRow(rowIdx);
                row.createCell(0).setCellValue(role.getId());
                row.createCell(1).setCellValue(role.getRoleName());
                row.createCell(2).setCellValue(role.getNote());
            }
        };
    }

}

  这样就能够导出Excel了,ExcelExportService接口的实现使用了Lambda表达式,因此Java版本是8及以上,Java 8以下的版本可以使用匿名类的方法去实现它。这里使用了ExcelExportService接口,就可以在自己的控制器上自定义导出规则,这样就可以根据需要开发了。