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