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表如下:
2. 數(shù)據(jù)表結(jié)構(gòu)如下:
3. 分析
字段對(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)name
、gender
、birthday
俊庇、phone
、address
禾酱;-
字段約束(下面有建表語句科侈,展示更清晰)
- 唯一性
user
表中username
以及info
表中phone
字段為唯一的 - 非空
username
、password
辅辩、name
- 其他
username
最大20字难礼、password
6~20字、name
最大20字玫锋、phone
最大20蛾茉,并且需要驗(yàn)證是否為電話號(hào)碼、address
最大50字
- 唯一性
常量值字段
user
表中除了excel中的字段外撩鹿,還有enable
字段谦炬,該字段表示是否啟用賬號(hào),值為0
或1
节沦,分別表示禁用
或啟用
键思,本例中所有賬戶設(shè)置為1
其他字段
每個(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_id
為3
創(chuàng)建時(shí)間字段
create_time
获搏,該字段不由excel導(dǎo)入赖条,也不是常量字段,而是系統(tǒng)當(dāng)前時(shí)間
-
密碼處理
密碼解析后常熙,需要驗(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)
);
編碼
源碼下載下來裸卫,然后
mvn install -Dmaven.test.skip=true
安裝相應(yīng)jar包仿贬,共4個(gè)-
配置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>
-
創(chuàng)建實(shí)體類,用
Intellij Idea
自動(dòng)生成聋袋,下面列出3個(gè)pojo代碼队伟,關(guān)鍵部分都有注釋。屬性注解參看文檔幽勒。值得注意的是:
UniqueValidator.class
(v2.0.0版本的示例)或UsernameUniqueValidator.class
和PhoneUniqueValidator.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.class
是online.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;
}
}
- 編寫
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();
}
}
- 編寫
UniqueValidator驗(yàn)證器
代碼(UsernameUniqueValidator
和PhoneUniqueValidator
驗(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;
}
}
- 編寫
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);
}
}
}
- 編寫入口代碼:
配置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