Java導(dǎo)入Excel到數(shù)據(jù)庫工具——EXCEL-UTIL4J使用示例

2017.9.3 更新v2.1.0: 進(jìn)度監(jiān)控調(diào)整為整個(gè)導(dǎo)入過程的進(jìn)度監(jiān)控迫淹,并且更加精確

前些時(shí)日開發(fā)了一款用Java將Excel導(dǎo)入數(shù)據(jù)庫的工具:EXCEL-UTIL4J源碼和文檔在這里)篮赢,覺得還是寫一個(gè)使用示例的好,主要想用來記錄使用方法镜会。

因?yàn)闀r(shí)間有限,工具只實(shí)現(xiàn)了一對(duì)一關(guān)系數(shù)據(jù)導(dǎo)入,以及只能使用hibernate作為ORM框架進(jìn)行導(dǎo)入,所以本示例將只做一對(duì)一關(guān)系數(shù)據(jù)導(dǎo)入冕碟,并且最大可能的利用到工具的所有功能,使用hibernate進(jìn)行導(dǎo)入匆浙。

示例中只會(huì)簡(jiǎn)單的提示代碼作用安寺,建議先大概瀏覽一下工具文檔,這樣有利于理解示例的代碼吞彤,本示例代碼源碼見 excel-util4j-sample


需求

1. Excel表如下:
Excel表頭
2. 數(shù)據(jù)表結(jié)構(gòu)如下:
表結(jié)構(gòu)
3. 分析
  1. 字段對(duì)應(yīng)
    Excel中的賬號(hào)我衬、密碼在數(shù)據(jù)表excel_util4j_user(下簡(jiǎn)稱user)中,分別對(duì)應(yīng)username饰恕、password挠羔;
    Excel中的姓名性別埋嵌、生日破加、電話买鸽、地址excel_util4j_user_info(下簡(jiǎn)稱info)中篡石,分別對(duì)應(yīng)namegenderbirthday俊庇、phoneaddress禾酱;

  2. 字段約束(下面有建表語句科侈,展示更清晰)

    1. 唯一性
      user表中username以及info表中phone字段為唯一的
    2. 非空
      usernamepassword辅辩、name
    3. 其他
      username最大20字难礼、password6~20字、name最大20字玫锋、phone最大20蛾茉,并且需要驗(yàn)證是否為電話號(hào)碼、address最大50字
  3. 常量值字段
    user表中除了excel中的字段外撩鹿,還有enable字段谦炬,該字段表示是否啟用賬號(hào),值為01节沦,分別表示禁用啟用键思,本例中所有賬戶設(shè)置為1

  4. 其他字段

  • 每個(gè)用戶還有角色,對(duì)應(yīng)的表為excel_util4j_user_role(下簡(jiǎn)稱user_role)表散劫,由于excel-util4j只能導(dǎo)入一對(duì)一關(guān)系的數(shù)據(jù)稚机,所以這里僅僅設(shè)置角色為一個(gè),假設(shè)role_id3

  • 創(chuàng)建時(shí)間字段create_time获搏,該字段不由excel導(dǎo)入赖条,也不是常量字段,而是系統(tǒng)當(dāng)前時(shí)間

  1. 密碼處理
    密碼解析后常熙,需要驗(yàn)證是否為6~20個(gè)字符纬乍,通過驗(yàn)證后需要轉(zhuǎn)換為MD5+Base64加密的格式再存表

下面是建表語句,表結(jié)構(gòu)和約束更清晰的展現(xiàn):

  • user表:
CREATE TABLE excel_util4j_user (
  
  id bigint(20) NOT NULL AUTO_INCREMENT,
  username varchar(20) NOT NULL,
  password varchar(20) NOT NULL,
  create_time datetime DEFAULT NULL,
  enable int(1) NOT NULL,
  
  PRIMARY KEY (id),
  UNIQUE KEY username_unique (username) USING BTREE
);
  • info表:
CREATE TABLE excel_util4j_user_info (

  id bigint(20) NOT NULL AUTO_INCREMENT,
  user_id bigint(20) NOT NULL,
  name varchar(20) NOT NULL,
  gender int(1) DEFAULT NULL,
  birthday date DEFAULT NULL,
  phone varchar(20) DEFAULT NULL,
  address varchar(50) DEFAULT NULL,

  PRIMARY KEY (id),
  UNIQUE KEY phone_unique (phone) USING BTREE
);
  • user_role表:
CREATE TABLE excel_util4j_user_role (

  id bigint(20) NOT NULL AUTO_INCREMENT,
  user_id bigint(20) NOT NULL,
  role_id int(11) NOT NULL,

  PRIMARY KEY (id)
);

編碼

  1. 源碼下載下來裸卫,然后mvn install -Dmaven.test.skip=true安裝相應(yīng)jar包仿贬,共4個(gè)

  2. 配置POM文件,將包添加到依賴:

    <!-- 讀取excel的包 -->
    <dependency>
        <groupId>online.dinghuiye</groupId>
        <artifactId>poi-kit</artifactId>
        <version>1.0.1</version>
    </dependency>
    
    <!-- excel-util4j-api包 -->
    <dependency>
        <groupId>online.dinghuiye</groupId>
        <artifactId>excelutil-api</artifactId>
        <version>2.1.0</version>
    </dependency>
    
    <!-- excel-util4核心包 -->
    <dependency>
        <groupId>online.dinghuiye</groupId>
        <artifactId>excelutil</artifactId>
        <version>2.1.0</version>
    </dependency>
    
    <!-- ORM實(shí)現(xiàn)包 -->
    <dependency>
        <groupId>online.dinghuiye</groupId>
        <artifactId>persistence-hibernate-impl</artifactId>
        <version>2.1.0</version>
    </dependency>
    
    <!-- 數(shù)據(jù)庫相關(guān)的包墓贿,使用Mysql數(shù)據(jù)庫 -->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.42</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.31</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.11.Final</version>
    </dependency>
    
    <!-- 轉(zhuǎn)換茧泪,驗(yàn)證等包 -->
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.1-b08</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.33</version>
    </dependency>
    
  3. 創(chuàng)建實(shí)體類,用Intellij Idea自動(dòng)生成聋袋,下面列出3個(gè)pojo代碼队伟,關(guān)鍵部分都有注釋。屬性注解參看文檔幽勒。

    值得注意的是:

    • UniqueValidator.class(v2.0.0版本的示例)或UsernameUniqueValidator.classPhoneUniqueValidator.class(v2.1.0版本示例)是自定義的判重驗(yàn)證器嗜侮,并不是使用的hibernate validator的自定義驗(yàn)證,是excel-util4j中實(shí)現(xiàn)的驗(yàn)證器,使用前需要編寫類并實(shí)現(xiàn)online.dinghuiye.api.validation.Validator锈颗,代碼見下文UniqueValidator驗(yàn)證器顷霹,另外兩個(gè)驗(yàn)證器相似

    • password字段從excel導(dǎo)入后,需要先驗(yàn)證長度在6 ~ 20個(gè)字符击吱,然后通過PasswordRepairer進(jìn)行修正淋淀,即將POJO對(duì)象的password屬性值設(shè)置為MD5+Base64加密的字符串。加密后的字符串長度不一定再滿足6 ~ 20個(gè)字符了姨拥,hibernate存表時(shí)還會(huì)再次按照POJO注解進(jìn)行驗(yàn)證绅喉,此時(shí)就可能無法驗(yàn)證通過而報(bào)錯(cuò),所以需要將因?yàn)閷傩孕拚赡苡绊懙降尿?yàn)證的注解加上groups = {Validator.class}參數(shù)叫乌,Validator.classonline.dinghuiye.api.validation.Validator.class

    • createTime字段是系統(tǒng)時(shí)間字段,使用自定義轉(zhuǎn)換器設(shè)值徽缚,使用謙虛編寫類并實(shí)現(xiàn)online.dinghuiye.api.resolution.Convertor接口憨奸,重寫方法返回需要的特定值即可,代碼見下文CurrentTimeConvertor轉(zhuǎn)換器(v2.1.0版本示例)

  • user pojo
package online.dinghuiye.example.entity;

import online.dinghuiye.api.annotation.validate.Validate;
import online.dinghuiye.api.validation.Validator;
import online.dinghuiye.core.annotation.convert.ConstValue;
import online.dinghuiye.core.annotation.convert.ValueConvert;
import online.dinghuiye.core.annotation.excel.SheetTitleName;
import online.dinghuiye.example.convertor.CurrentTimeConvertor;
import online.dinghuiye.example.validator.UsernameUniqueValidator;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.validator.constraints.NotBlank;

import javax.persistence.*;
import javax.validation.Valid;
import javax.validation.constraints.Size;
import java.util.Date;

/**
 * @author Strangeen on 2017/08/27
 *
 * @author Strangeen on 2017/9/3
 * @version 2.1.0
 */
@Entity
@DynamicInsert(true)
@Table(name = "excel_util4j_user")
public class ExcelUtil4JUserEntity {

    @Transient // 不需要執(zhí)行轉(zhuǎn)換和驗(yàn)證凿试,但并不影響hibernate存表的操作
    private Long id;

    @SheetTitleName("賬號(hào)") // excel表字段對(duì)應(yīng)
    @NotBlank
    @Size(max = 20, message = "輸入最大{max}個(gè)字")
    @Validate(validator = UsernameUniqueValidator.class, message = "已被注冊(cè)") // 自定義檢驗(yàn)器排宰,判斷重復(fù)
    private String username;

    @SheetTitleName("密碼")
    // 如果后續(xù)需要repaire的屬性,需要將repaire可能影響的驗(yàn)證加上groups={Validator.class}
    // 否則可能會(huì)導(dǎo)致比如字符串長度改變而無法再存表時(shí)通過hibernate的驗(yàn)證
    @NotBlank
    @Size(max = 20, min = 6, message = "輸入{min}~{max}個(gè)字", groups = {Validator.class})
    private String password;

    @ValueConvert(CurrentTimeConvertor.class) // 自定義轉(zhuǎn)換器那婉,存入當(dāng)前時(shí)間
    private Date createTime;

    @ConstValue("1") // 常量值轉(zhuǎn)換器板甘,導(dǎo)入時(shí)會(huì)被設(shè)置為1
    private Integer enable;

    @Valid // 執(zhí)行hibernate validator支持的對(duì)象屬性檢測(cè),不注釋@Valid則不會(huì)對(duì)info對(duì)象的屬性進(jìn)行檢測(cè)
    private ExcelUtil4JUserInfoEntity info;

    private ExcelUtil4JUserRoleEntity userRole;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Basic
    @Column(name = "username")
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Basic
    @Column(name = "password")
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Basic
    @Column(name = "create_time")
    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Basic
    @Column(name = "enable")
    public Integer getEnable() {
        return enable;
    }

    public void setEnable(Integer enable) {
        this.enable = enable;
    }

    @OneToOne(mappedBy = "user", cascade = {CascadeType.ALL})
    public ExcelUtil4JUserInfoEntity getInfo() {
        return info;
    }

    public void setInfo(ExcelUtil4JUserInfoEntity info) {
        this.info = info;
    }

    // 這里定義為OneToOne并不太合適详炬,只是為了演示
    // 常規(guī)應(yīng)該使用OneToMany盐类,現(xiàn)階段無法實(shí)現(xiàn)OneToMany的導(dǎo)入,就只能使用RowRecordPerPersistentRepairer在存表前進(jìn)行修正了
    @OneToOne(mappedBy = "user", cascade = {CascadeType.ALL})
    public ExcelUtil4JUserRoleEntity getUserRole() {
        return userRole;
    }

    public void setUserRole(ExcelUtil4JUserRoleEntity userRole) {
        this.userRole = userRole;
    }
}
  • info pojo
package online.dinghuiye.example.entity;

import online.dinghuiye.api.annotation.validate.Validate;
import online.dinghuiye.core.annotation.convert.BlankToNull;
import online.dinghuiye.core.annotation.convert.DateFormat;
import online.dinghuiye.core.annotation.convert.ValueMap;
import online.dinghuiye.core.annotation.excel.SheetTitleName;
import online.dinghuiye.example.validator.PhoneUniqueValidator;
import org.hibernate.validator.constraints.NotBlank;

import javax.persistence.*;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.util.Date;

/**
 * @author Strangeen on 2017/08/27
 *
 * @author Strangeen on 2017/9/3
 * @version 2.1.0
 */
@Entity
@Table(name = "excel_util4j_user_info")
public class ExcelUtil4JUserInfoEntity {

    @Transient
    private Long id;

    @OneToOne // 必須使用hibernate的雙向綁定呛谜,否則無法生成hibernate的POJO對(duì)象
    @JoinColumn(name = "user_id")
    private ExcelUtil4JUserEntity user;

    @SheetTitleName("姓名")
    @NotBlank
    @Size(max = 20, message = "輸入最大{max}個(gè)字")
    private String name;

    @SheetTitleName("性別")
    @ValueMap("{'男':1,'女':0}") // Map值轉(zhuǎn)換器在跳,將excel的只按照Map映射進(jìn)行轉(zhuǎn)換
    private Integer gender;

    @SheetTitleName("生日")
    @BlankToNull // 空串轉(zhuǎn)NULL轉(zhuǎn)換器,防止生日字段為空串轉(zhuǎn)換為Date時(shí)報(bào)錯(cuò)
    @DateFormat("yyyy-MM-dd") // 時(shí)間格式轉(zhuǎn)換器隐岛,將時(shí)間轉(zhuǎn)換為指定格式猫妙,如果單元格為“文本”就會(huì)使用
    private Date birthday;

    @SheetTitleName("電話")
    // hibernate validator的正則驗(yàn)證,這里大概寫一個(gè)電話的驗(yàn)證正則
    @Pattern(regexp = "(^(\\+|0)[0-9]{2}[0-9]{11}$)|(^[0-9]{11}$)", message = "填寫不正確")
    @Validate(validator = PhoneUniqueValidator.class, message = "已被注冊(cè)")
    private String phone;

    @SheetTitleName("地址")
    @Size(max = 50, message = "輸入最大{max}個(gè)字")
    private String address;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Basic
    @Column(name = "name")
    public String getName() {
        return name;
    }

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

    @Basic
    @Column(name = "gender")
    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    @Basic
    @Column(name = "birthday")
    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Basic
    @Column(name = "phone")
    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Basic
    @Column(name = "address")
    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @OneToOne
    @JoinColumn(name = "user_id")
    public ExcelUtil4JUserEntity getUser() {
        return user;
    }

    public void setUser(ExcelUtil4JUserEntity user) {
        this.user = user;
    }
}
  • user_role pojo
package online.dinghuiye.example.entity;

import online.dinghuiye.core.annotation.convert.ConstValue;
import online.dinghuiye.core.annotation.excel.Transient;

import javax.persistence.*;

/**
 * @author Strangeen on 2017/08/27
 */
@Entity
@Table(name = "excel_util4j_user_role")
public class ExcelUtil4JUserRoleEntity {

    @Transient
    private Long id;

    private ExcelUtil4JUserEntity user;

    @ConstValue("3") // 導(dǎo)入的用戶角色均為3
    private Integer roleId;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @OneToOne
    @JoinColumn(name = "user_id")
    public ExcelUtil4JUserEntity getUser() {
        return user;
    }

    public void setUser(ExcelUtil4JUserEntity user) {
        this.user = user;
    }

    @Basic
    @Column(name = "role_id")
    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }
}
  1. 編寫CurrentTimeConvertor轉(zhuǎn)換器代碼:
    自定義轉(zhuǎn)換器需要實(shí)現(xiàn)online.dinghuiye.api.resolution.Convertor
package online.dinghuiye.example.convertor;

import online.dinghuiye.api.resolution.Convertor;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;

/**
 * 當(dāng)前時(shí)間轉(zhuǎn)換器聚凹,該轉(zhuǎn)換器為自定義轉(zhuǎn)換器割坠,用于適應(yīng)字段為當(dāng)前時(shí)間的情況
 * 自定義轉(zhuǎn)換器需要實(shí)現(xiàn)online.dinghuiye.api.resolution.Convertor
 *
 * @author Strangeen on 2017/09/04
 * @version 2.1.0
 */
public class CurrentTimeConvertor implements Convertor {

    // convet方法參數(shù)會(huì)傳入所有可能用到的值
    // obj 需要轉(zhuǎn)換的值
    // field pojo屬性字段
    // excelRecordMap excel數(shù)據(jù)map<表頭名稱, 單元格值>
    @Override
    public Object convert(Object obj, Field field, Map<String, Object> excelRecordMap) {

        // 返回當(dāng)前時(shí)間即可,自定義轉(zhuǎn)換器也可以用于其他特定值得轉(zhuǎn)換
        return new Date();
    }
}
  1. 編寫UniqueValidator驗(yàn)證器代碼(UsernameUniqueValidatorPhoneUniqueValidator驗(yàn)證器代碼略妒牙,請(qǐng)查看示例代碼v2.1.0版本):
    自定義判重驗(yàn)證器需要實(shí)現(xiàn)online.dinghuiye.api.validation.Validator
package online.dinghuiye.example.validator;

import online.dinghuiye.api.validation.Validator;
import online.dinghuiye.example.util.SessionFactoryUtil;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 判重Validator
 *
 * @author Strangeen on 2017/08/16
 */
public class UniqueValidator implements Validator {

    /*
    實(shí)現(xiàn)原理是將數(shù)據(jù)庫中唯一值全部讀取出來緩存到cache中彼哼,
    然后將導(dǎo)入的只和cache比對(duì),如果重復(fù)則返回false单旁,如果不重復(fù)則加入到cache沪羔,返回true

    這樣做可以提高檢驗(yàn)效率,但是必須要考慮并發(fā)問題
     */

    private static Set<Object> usernameCache = new HashSet<>();
    private static Set<Object> phoneCache = new HashSet<>();

    public UniqueValidator() {
        // 設(shè)置username的cache
        setCache(usernameCache, "excel_util4j_user", "username");
        // 設(shè)置phone的cache
        setCache(phoneCache, "excel_util4j_user_info", "phone");
    }

    public static void setCache(Set<Object> cache, String tableName, String columnName) {
        SessionFactory factory = SessionFactoryUtil.getSessionFactory();
        Session session = factory.openSession();
        SQLQuery query = session.createSQLQuery("select " + columnName + " from " + tableName);
        List<Object> list = query.list();
        for (Object obj : list) {
            cache.add(obj);
        }
        session.close();
    }

    @Override
    public <User> boolean validate(Object fieldValue, Field field, User obj) {

        // 判斷是username還是phone,這里只是演示蔫饰,所以將cache寫在一起琅豆,常規(guī)思路應(yīng)該是分開的2個(gè)類
        if ("username".equals(field.getName())) {
            if (usernameCache.contains(fieldValue)) return false;
            usernameCache.add(fieldValue);
            return true;
        } else if ("phone".equals(field.getName())) {
            if (phoneCache.contains(fieldValue)) return false;
            phoneCache.add(fieldValue);
            return true;
        }

        // 其他字段不用檢測(cè),直接返回true
        return true;
    }
}
  1. 編寫PasswordRepairer修正器代碼:
    在存表前將密碼設(shè)置為密碼明文的加密字符串篓吁,MD5Util的代碼略
package online.dinghuiye.example.repairer;

import online.dinghuiye.api.entity.Process;
import online.dinghuiye.api.entity.ResultStatus;
import online.dinghuiye.api.entity.RowRecord;
import online.dinghuiye.api.persistence.RowRecordPerPersistentRepairer;
import online.dinghuiye.example.entity.ExcelUtil4JUserEntity;
import online.dinghuiye.example.util.MD5Util;

import java.util.List;

/**
 * 對(duì)密碼進(jìn)行MD5加密處理
 * 由于密碼需要驗(yàn)證長度茫因,所以不能在驗(yàn)證前就MD5加密,否則驗(yàn)證是不正確的
 * 所以需要在存表前進(jìn)行修正
 *
 * 通過實(shí)現(xiàn)RowRecordPerPersistentRepairer可以獲得hibernate的POJO對(duì)象杖剪,從而進(jìn)行修正
 *
 * v2.1.0 進(jìn)度監(jiān)控更佳精確冻押,接口提供了進(jìn)度對(duì)象
 *        如果遍歷了List<RowRecord> list,可以對(duì)每一次循環(huán)執(zhí)行process.updateProcess(1)
          需要注意的是盛嘿,使用前必須判斷`process`是否為`null`洛巢,如果入口方法出傳入的`ProcessObserver`為`null`,那么`process`就會(huì)為`null`
 *        如果沒有遍歷或者不執(zhí)行上述方法次兆,當(dāng)repairer執(zhí)行完畢稿茉,程序會(huì)自動(dòng)修正進(jìn)度,
 *           進(jìn)度展示效果會(huì)立即變更到repairer方法執(zhí)行完畢的進(jìn)度狀態(tài)
 *
 * @author Strangeen on 2017/9/3
 * @version 2.1.0
 */
public class PasswordRepairer implements RowRecordPerPersistentRepairer {

    @Override
    public void repaire(List<RowRecord> list, Process process) {
        for (RowRecord rr : list) {
            if (rr.getResult().getResult() != ResultStatus.SUCCESS) continue;
            ExcelUtil4JUserEntity obj =
                    (ExcelUtil4JUserEntity) rr.getPojoRecordMap().get(ExcelUtil4JUserEntity.class);
            obj.setPassword(MD5Util.encode(obj.getPassword()));

            // 精確的進(jìn)度展示芥炭,可以操作process對(duì)象
            if (process != null)
                process.updateProcess(1);
        }
    }
}
  1. 編寫入口代碼:
    配置SessionFactory的代碼略漓库,可以使用多種方式配置,如Spring等
package online.dinghuiye.example;

import online.dinghuiye.api.entity.Process;
import online.dinghuiye.api.entity.ResultStatus;
import online.dinghuiye.api.entity.RowRecord;
import online.dinghuiye.api.entity.TransactionMode;
import online.dinghuiye.core.ImportHandler;
import online.dinghuiye.core.persistence.RowRecordPersistencorHibernateImpl;
import online.dinghuiye.core.resolution.torowrecord.RowRecordHandlerImpl;
import online.dinghuiye.core.validation.RowRecordValidatorImpl;
import online.dinghuiye.example.entity.ExcelUtil4JUserEntity;
import online.dinghuiye.example.repairer.PasswordRepairer;
import online.dinghuiye.example.util.SessionFactoryUtil;
import online.dinghuiye.excel.ExcelFactory;
import org.hibernate.SessionFactory;

import java.io.File;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

/**
 * @author Strangeen on 2017/08/30
 *
 * @author Strangeen on 2017/9/3
 * @version 2.1.0
 */
public class ExcelImportor {

    public static void main(String[] args) {

        SessionFactory factory = null;
        try {

            // 獲取SessionFactory
            factory = SessionFactoryUtil.getSessionFactory();
            // 設(shè)置mode:SINGLETON為單條存儲(chǔ)事務(wù)园蝠,MULTIPLE為整體事務(wù)渺蒿,詳見文檔
            TransactionMode mode = TransactionMode.SINGLETON;

            // 創(chuàng)建導(dǎo)入器handler
            ImportHandler handler = new ImportHandler();
            handler.setHandler(new RowRecordHandlerImpl()); // 一對(duì)一關(guān)系解析器
            handler.setValidator(new RowRecordValidatorImpl()); // 驗(yàn)證器
            handler.setPersistencor(new RowRecordPersistencorHibernateImpl(factory)); // 持久化器hibernate實(shí)現(xiàn)
            handler.setRepairer(new PasswordRepairer()); // 密碼存儲(chǔ)修正器
            handler.setMode(mode);

            // 執(zhí)行excel導(dǎo)入
            List<RowRecord> resultList = handler.importExcel(
                    ExcelFactory.newExcel(new File("D:/test_template.xlsx")), // 創(chuàng)建AbstractExcel對(duì)象讀取excle
                    0, // 讀取sheet序號(hào)為0的sheet
                    new Observer() {
                        @Override
                        public void update(Observable o, Object arg) {
                            // 創(chuàng)建導(dǎo)入進(jìn)度觀察者,arg為導(dǎo)入進(jìn)度百分?jǐn)?shù)(沒有%)
                            Process process = (Process) arg;
                            System.out.println("進(jìn)度:" + process.getProcess() + "彪薛,當(dāng)前階段:" + process.getNode());
                        }
                    },
                    ExcelUtil4JUserEntity.class); // 傳入POJO

            // 打印結(jié)果茂装,如果有錯(cuò)誤可以在resultList中得到
            int successCount = 0;
            int errorCount = 0;
            for (RowRecord rr : resultList) {
                if (rr.getResult().getResult() != ResultStatus.SUCCESS) { // 導(dǎo)入不成功
                    System.out.println(rr.getRowNo() + "行 - " + rr.getResult().getMsg()); // 打印行號(hào)和錯(cuò)誤信息
                    errorCount ++; // 記錄錯(cuò)誤數(shù)
                } else
                    successCount ++; // 記錄成功數(shù)
            }
            // 注意:MULTIPLE為整體事務(wù),successCount依然可能不為0陪汽,僅作為標(biāo)識(shí)训唱,實(shí)際上沒有任何數(shù)據(jù)存入數(shù)據(jù)庫的
            System.out.println("success " + successCount + ", error " + errorCount);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            SessionFactoryUtil.closeSessionFactory(factory);
        }
    }
}

至此,代碼全部編寫完畢挚冤,執(zhí)行導(dǎo)入后况增,控制臺(tái)打印出來的內(nèi)容類似如下(我導(dǎo)入了10條數(shù)據(jù),有6條存在問題训挡,使用SINGLETON事務(wù)形式):

進(jìn)度:2.5澳骤,當(dāng)前階段:RESOLUTION
進(jìn)度:5.0,當(dāng)前階段:RESOLUTION
進(jìn)度:7.5澜薄,當(dāng)前階段:RESOLUTION
進(jìn)度:10.0为肮,當(dāng)前階段:RESOLUTION
進(jìn)度:12.5,當(dāng)前階段:RESOLUTION
進(jìn)度:15.0肤京,當(dāng)前階段:RESOLUTION
進(jìn)度:17.5颊艳,當(dāng)前階段:RESOLUTION
進(jìn)度:20.0茅特,當(dāng)前階段:RESOLUTION
進(jìn)度:22.5,當(dāng)前階段:RESOLUTION
進(jìn)度:25.0棋枕,當(dāng)前階段:RESOLUTION
進(jìn)度:27.500000000000004白修,當(dāng)前階段:VALIDATION
進(jìn)度:30.0,當(dāng)前階段:VALIDATION
進(jìn)度:32.5重斑,當(dāng)前階段:VALIDATION
進(jìn)度:35.0兵睛,當(dāng)前階段:VALIDATION
進(jìn)度:37.5,當(dāng)前階段:VALIDATION
進(jìn)度:40.0窥浪,當(dāng)前階段:VALIDATION
進(jìn)度:42.5祖很,當(dāng)前階段:VALIDATION
進(jìn)度:45.0,當(dāng)前階段:VALIDATION
進(jìn)度:47.5漾脂,當(dāng)前階段:VALIDATION
進(jìn)度:50.0假颇,當(dāng)前階段:VALIDATION
進(jìn)度:52.5,當(dāng)前階段:REPAIRATION
進(jìn)度:55.00000000000001符相,當(dāng)前階段:REPAIRATION
進(jìn)度:57.49999999999999拆融,當(dāng)前階段:REPAIRATION
進(jìn)度:60.0,當(dāng)前階段:REPAIRATION
進(jìn)度:77.5啊终,當(dāng)前階段:PERSISTENCE
進(jìn)度:80.0,當(dāng)前階段:PERSISTENCE
進(jìn)度:82.5傲须,當(dāng)前階段:PERSISTENCE
進(jìn)度:85.0蓝牲,當(dāng)前階段:PERSISTENCE
進(jìn)度:87.5,當(dāng)前階段:PERSISTENCE
進(jìn)度:90.0泰讽,當(dāng)前階段:PERSISTENCE
進(jìn)度:92.5例衍,當(dāng)前階段:PERSISTENCE
進(jìn)度:95.0,當(dāng)前階段:PERSISTENCE
進(jìn)度:97.5已卸,當(dāng)前階段:PERSISTENCE
進(jìn)度:100.0佛玄,當(dāng)前階段:PERSISTENCE
4行 - 賬號(hào)不能為空;密碼輸入6~20個(gè)字;姓名不能為空;電話填寫不正確;地址輸入最大50個(gè)字;
5行 - 電話填寫不正確;
7行 - 電話已被注冊(cè);賬號(hào)已被注冊(cè);
8行 - 姓名不能為空;賬號(hào)不能為空;
10行 - 密碼不能為空;
11行 - 姓名不能為空;
success 4, error 6
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市累澡,隨后出現(xiàn)的幾起案子梦抢,更是在濱河造成了極大的恐慌,老刑警劉巖愧哟,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奥吩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蕊梧,警方通過查閱死者的電腦和手機(jī)霞赫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肥矢,“玉大人端衰,你說我怎么就攤上這事。” “怎么了旅东?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵灭抑,是天一觀的道長。 經(jīng)常有香客問我玉锌,道長名挥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任主守,我火速辦了婚禮禀倔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘参淫。我一直安慰自己救湖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布涎才。 她就那樣靜靜地躺著鞋既,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耍铜。 梳的紋絲不亂的頭發(fā)上邑闺,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音棕兼,去河邊找鬼陡舅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛伴挚,可吹牛的內(nèi)容都是我干的靶衍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼茎芋,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼颅眶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起田弥,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤涛酗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后皱蹦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煤杀,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年沪哺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沈自。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辜妓,死狀恐怖枯途,靈堂內(nèi)的尸體忽然破棺而出忌怎,到底是詐尸還是另有隱情,我是刑警寧澤酪夷,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布榴啸,位于F島的核電站,受9級(jí)特大地震影響晚岭,放射性物質(zhì)發(fā)生泄漏鸥印。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一坦报、第九天 我趴在偏房一處隱蔽的房頂上張望库说。 院中可真熱鬧,春花似錦片择、人聲如沸潜的。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啰挪。三九已至,卻和暖如春嘲叔,著一層夾襖步出監(jiān)牢的瞬間亡呵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工硫戈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留政己,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓掏愁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卵牍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子果港,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)糊昙,斷路器辛掠,智...
    卡卡羅2017閱讀 134,693評(píng)論 18 139
  • 說幾句:這幾天在忙春招的東西,看了很多東西释牺,但是都沒有總結(jié)萝衩,感覺很急躁。年輕人没咙,從小聽到大的一句話就是戒驕戒躁猩谊,然...
    l_sivan閱讀 731評(píng)論 0 1
  • spring官方文檔:http://docs.spring.io/spring/docs/current/spri...
    牛馬風(fēng)情閱讀 1,689評(píng)論 0 3
  • 一牌捷、配置maven的pom.xml加載jar包 為了后續(xù)開發(fā)的方便墙牌,將SSM框架所有需要的jar包一并加載進(jìn)來 p...
    docki閱讀 2,257評(píng)論 1 23
  • 原文鏈接:http://www.dropwizard.io/1.2.0/docs/getting-started....
    Lance_Xu閱讀 911評(píng)論 0 0