spring mvc 使用注解实现excle导出 最佳实践


最近项目中遇到需要excle导出的需求,百度搜索关键词,excle和spring mvc出来的结果都是代码及其长,并且还是直接设置response的原始方法

不得不说国内的程序员大都只追求能够勉强实现功能,很少想到优雅,我在bing上搜索(没有vpn哭)同样关键词,结果至少是返回modelandview对象,但是需要自己实现视图的基础上,还要实现视图解析器

话不多说,上正菜:

本文使用注解和自定义视图的方式实现excle导出功能,不需要实现自定义视图解析器,只要用默认视图解析器InternalResourceViewResolver就可以,

现在网上还没有看到使用注解来简化excle导出的文章,本文算是首创,是我目前水平下想到的最好的实现方式,希望大家可以多多指教

本文是在使用Spring MVC和Poi的前提

 

  1. 先定义注解,大部分注释内容我直接放在代码中
1 @Target(ElementType.FIELD)//标注用来注解field类型
2 @Retention(RetentionPolicy.RUNTIME)//标注运行时注解
3 public @interface Export {
4     //不设置default表示必填
5     String title();//title表示导出时的标题
6     int index();//inde表示导出时改字段的列号
7 
8     Class format() default String.class;//默认使用String.class只是标注,自定义的不可能是String.class
9 }

其中 :title表示导出时的标题,inde表示导出时改字段的列号,format用于格式化一些字段,由于是非必填项,所以要指定默认值,我这里指定了String.class。

    

  2.自定义一个需要导出的model类,也就是bean类,在需要导出的字段上加入注解

public class Company extends BaseModel{


    @Export(title = "企业名称",index = 1)
    private String name;

    @Export(title = "统一社会信用代码",index = 2)
    private String uniformSocialCreditCode;

    //1:规模以上;0:规模以下
    @Export(title = "规模",index = 3,format = Scale.class)
    private Byte scale;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUniformSocialCreditCode() {
        return uniformSocialCreditCode;
    }

    public void setUniformSocialCreditCode(String uniformSocialCreditCode) {
        this.uniformSocialCreditCode = uniformSocialCreditCode;
    }

    public Byte getScale() {
        return scale;
    }

    public void setScale(Byte scale) {
        this.scale = scale;
    }
}

  解析注解需要用到反射

  

//生成标题列,生成内容列是一样的,只是多出一个解析字段值
private
void generateHead(Field[] fields) { currentSheetHeadRow = currentSheet.createRow(0); //这里我学习lambda表达式,读者也可以直接用for循环 Arrays.stream(fields)
          .filter(field -> field.isAnnotationPresent(Export.class))//找出有Export注解的field,也就是需要导出的字段
          .forEach((field)
-> { String title = field.getAnnotation(Export.class).title(); int index = field.getAnnotation(Export.class).index(); createHeadTitle(title, index); }); } //指定的index位置加入标题 private void createHeadTitle(String name, int index) { Cell c1 = currentSheetHeadRow.createCell(index); c1.setCellValue(name); }

 

  3.我的例子中有一个需要规模字段,它是比较典型的一类,就是导出的时候与实际的值并不相同,需要转换,此时定义一个枚举类最为合适,这里只是供大家参考

  我的Scale枚举类,用来解析字段值,

public enum Scale {

    ABOVE("规模以上",1),BLOW("规模以下",0),NULL("",-1);

    private String name;
    private Integer index;

    Scale(String name, Integer index) {
        this.name = name;
        this.index = index;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getIndex() {
        return index;
    }

    public void setIndex(Integer index) {
        this.index = index;
    }
}

    此时导出功能的基本的注解部分已经实现

 

 接下来自定义一个exle的视图,到时候在Controller中返回modelAndView的时候加入这个视图类即可

  

/**
*
AbstractXlsxView是Spring内置的类是2007版之后的excle版本
*如果你想要2003版本,这里只需要继承AbstractXlsView即可,其他不需要任何改动
*/
public class ExcleView extends AbstractXlsxView{ 
  //导出文件名
private String fileName; public ExcleView(String excleName){ super(); this.fileName = excleName; } @Override protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { List<BaseModel> list = (List<BaseModel>)model.get("list"); Sheet currentSheet = workbook.createSheet(); for (BaseModel baseModel : list) { //....省略具体代码
       //可以循环的添加cell } String name
= URLEncoder.encode(fileName+".xlsx", "UTF-8"); response.setHeader("Content-Disposition", "attachment; filename="+name); } }

  Controller中的方法示例

  

public ModelAndView exportExcel(@ModelAttribute CompanyBasic model) throws IOException{
        List<Company> list = new ArrayList<>();
       //示例创建一个list列表
        for (int i = 0; i <3 ; i++) {
            Company company = new Company();
            company.setName("a");
            company.setUniformSocialCreditCode("124521");
            company.setScale((byte)1);
            list.add(company);
        }

     //将list放入Map类型的对象中,即可 Map
<String, Object> map = new HashMap<>(); map.put("list",list); return new ModelAndView(new ExcleView("企业列表"),map); }

只要返回的时候   return new ModelAndView(new ExcleView("企业列表"),map); 其中企业列表是导出的文件名

自此,以后再有其他需要导出的类,只要在对应的字段加上titie和index注解,在对应Controller中,查询中list,再new ExcleVIew(filename)的时候传入文件名即可

大功告成

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM