Java基於注解和反射導入導出Excel


代碼地址如下:
http://www.demodashi.com/demo/11995.html

1. 構建項目

使用Spring Boot快速構建一個Web工程,並導入與操作Excel相關的POI包以及一些常用的工具類包,pom文件中添加如下一些依賴:

		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.9</version>
		</dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.google.collections</groupId>
            <artifactId>google-collections</artifactId>
            <version>1.0</version>
        </dependency>

2. 自定義Excel注解

使用注解的形式,自定義一些與操作Excel相關的基本信息,如生成Excel模板時,需要有哪些字段名、字段標題、字段之間的排序、字段中內容的位置、對齊方式等信息。然后通過在JavaBean中的需要的字段對應的getter方法上添加這些注解,就可以將其標記為Excel相關的字段。自定義注解內容主要如下(為了節省篇幅,一下代碼中的注解已刪除,詳細代碼可以看下載附件)

@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelField {

    String value() default "";

    String title();
    
    int type() default 0;

    int align() default 0;

    int sort() default 0;

    String dictType() default "";

    Class<?> fieldType() default Class.class;

    int[] groups() default {};
}

3. 通過反射創建Excel模板

使用反射的方式獲取類的信息、類中方法、屬性,為了創建一個可供用戶填寫的Excel模板,我們需要在模板中定義系統需要收集的數據字段,即在JavaBean中,通過注解定義的相關字段。偽代碼及關鍵代碼如下:


 public ExportExcel(String title, Class<?> cls, int type, int... groups){
        // Get annotation field
        Field[] fs = cls.getDeclaredFields();
        for (Field f : fs){
            //獲取字段上加的@Excel注解
            ExcelField ef = f.getAnnotation(ExcelField.class);
            if (ef != null && (ef.type()==0 || ef.type()==type)){
	            //根據字段注解中配置的groups進行分組
	            //....
                }else{
	            //若無group屬性,則直接將字段和對應的注解加入到一個全局的注解鏈表中,用於之后進行統一的排序
                    annotationList.add(new Object[]{ef, f});
                }
            }
        }
        // Get annotation method
        Method[] ms = cls.getDeclaredMethods();
        for (Method m : ms){
	        //獲取方法上的注解
            ExcelField ef = m.getAnnotation(ExcelField.class);
            if (ef != null && (ef.type()==0 || ef.type()==type)){
	              //操作同對字段的操作
                }else{
                    annotationList.add(new Object[]{ef, m});
                }
            }
        }
        // 對字段進行排序
        Collections.sort(annotationList, new Comparator<Object[]>() {
	         //排序規則
        });
        // Initialize
        List<String> headerList = Lists.newArrayList();
        for (Object[] os : annotationList){
            //獲取注解title屬性值
            String t = ((ExcelField)os[0]).title();
            //將字段名稱保存在一個list中,交給初始化方法使用
            headerList.add(t);
        }
        //初始化操作,創建Excel,設置文件名稱,表格標題,表頭內容及單元格的格式等信息
        initialize(title, headerList);
    }

4. 導入Excel文件

導入Excel文件,意味着需要將一個根據我們生成模板填好的Excel文件導入到系統中。在這個過程中,需要使用一個接口去接收文件,並對文件進行解析。在Excel文件中,每一行都對應着我們定義的一個實體對象,所以解析之后,我們得到的是一個存放着多個對象的List。
在解析文件的過程中,首先需要對文件格式校驗,保證是一個有效的Excel文件,然后循環讀取每一行的數據,並將其賦值給對象。

5. 導出Excel文件

導出Excel的原理同導出模板一樣,只是需要將數據填充到Excel文件中。填充數據過程中,還是需要通過@Excel注解將JavaBean中的字段找出,並將值設置到單元格中

6. 測試

1. 定義實體類並為其中字段方法添加@Excel注解

public class User {
    private String userName;
    private String nickName;
    private Integer age;
    private Date birth;

    @NotNull(message = "User Name 不能為空")
    @ExcelField(title="User Name", align=2, sort=1)
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @ExcelField(title="Nick Name", align=2, sort=2)
    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    @ExcelField(title="Age", align=2, sort=3)
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @JsonFormat(pattern = "mm/dd/YYYY")
    @NotNull(message="Birth Day不能為空")
    @ExcelField(title="Birth Day", align=2, sort=4)
    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }
}

2. 定義接口方法
1. 下載輸入數據的模板
    @RequestMapping("import/template")
    public void importFileTemplate(HttpServletResponse response){
        try {
            //定義文件名稱
            String fileName = "User_Data_import_template.xlsx";
            List<User> list = Lists.newArrayList();
            new ExportExcel("User Data", User.class, 1).setDataList(list).write(response, fileName).dispose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
2. 導入Excel文件到系統
  @RequestMapping(value = "import",method = RequestMethod.POST)
    public void importFile(MultipartFile multipartFile){
        try {
            int successNum = 0;
            int failureNum = 0;
            StringBuilder failureMsg = new StringBuilder();
            ImportExcel ei = new ImportExcel(multipartFile, 1, 0);
            List<User> list = ei.getDataList(User.class);
            for (User user : list){
                try{
                    //to do: 保存/處理數據
                    //userService.save(user);
                    logger.info(user.toString());
                    successNum++;
                }catch(ConstraintViolationException ex){
                    failureNum++;
                }catch (Exception ex) {
                    failureNum++;
                }
            }
            if (failureNum>0){
                failureMsg.insert(0, ", Failures: "+failureNum);
            }
            logger.info("Had Operation "+successNum+" Data;"+" "+"Failure "+failureNum);
        } catch (Exception e) {
            logger.error("導入失敗",e);
        }
    }
3. 導出Excel文件
 @RequestMapping("export")
    public void export(HttpServletResponse response){
        try {
            String fileName = "User Data"+ DateUtils.getDate("yyyyMMddHHmmss")+".xlsx";
            List<User> users=new ArrayList<>();
            User user1=new User();
            user1.setUserName("小明");
            user1.setNickName("豬小明");
            user1.setAge(20);
            user1.setBirth(DateUtils.parseDate("1992-10-10"));
            users.add(user1);
            User user2=new User();
            user2.setUserName("小紅");
            user2.setNickName("小小紅");
            user2.setAge(18);
            user2.setBirth(DateUtils.parseDate("1998-11-09"));
            users.add(user2);
            new ExportExcel("Test Over View Define", User.class,2).setDataList(users).write(response, fileName).dispose();
        } catch (Exception e) {
        }
    }
3. 演示

端口號可以自己通過在application.properties文件中,添加server.port=8000進行定義

通過瀏覽器訪問接口http://localhost:8000/user/import/template,下載模板:

編輯Excel文件,並通過接口測試工具Postman訪問接口localhost:8000/user/import

接口測試工具中,上傳文件,並訪問:

上傳之后,通過日志輸出文件解析的結果:

2017-11-24 19:56:15.186  INFO 37428 --- [nio-8000-exec-5] com.shexd.Controller.UserController      : User{userName='小明', nickName='豬小明', age=18, birth=1992-10-09}
2017-11-24 19:56:15.187  INFO 37428 --- [nio-8000-exec-5] com.shexd.Controller.UserController      : User{userName='蘑菇頭', nickName='小蘑菇', age=21, birth=1996-09-25}
2017-11-24 19:56:15.187  INFO 37428 --- [nio-8000-exec-5] com.shexd.Controller.UserController      : Had Operation 2 Data; Failure 0

訪問接口http://localhost:8000/user/export,從系統導出Excel文件

7. 項目目錄結構

8. 小結

本文簡單介紹了利用Java注解和反射對Excel進行操作的基本原理,並實例進行詳細說明。

Java基於注解和反射導入導出Excel

代碼地址如下:
http://www.demodashi.com/demo/11995.html

注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM