上一篇 [Java] Spring LDAP LDIF Parsing(1) 主要講的是如何 parse ldif 檔。
這篇主要是實作 RecordMapper 的部分。
在上一篇有講到如果要整合 spring batch 的話,我們需實做 RecordMapper 這隻 interface
MappingLdifReader<Entity> mappingLdifReader = new MappingLdifReader<>();
mappingLdifReader.setRecordMapper(new RecordMapper<Entity>(){
@Override
public Entity mapRecord(LdapAttributes attributes) {
// do something you want
Entity entity = new Entity();
entity.setDn(attributes.getName());
return entity;
}
});
mappingLdifReader.setResource(new ClassPathResource("data.ldif"));
mappingLdifReader.open(new ExecutionContext());
try {
Entity entity = mappingLdifReader.read();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mappingLdifReader.close();
其中 Entity 的部份如下:
public class Entity{
private Name dn;
public Name getDn() {
return dn;
}
public void setDn(Name dn) {
this.dn = dn;
}
}
今天我們要轉換的物件假設不是 Entity 這麼簡單,是一個 objectclass 為 inetOrgPerson 的 Person 物件呢?
首先我們的 Person 類別如下:
@Entry(objectClasses = {"top", "inetOrgPerson"})
public class Person extends Person {
@Id
private Name dn;
@Attribute(name="cn")
private String name;
@Attribute(name="sn")
private String lastName;
@Attribute(name="uid")
private String uid;
@Attribute(name="userPassword")
private String password;
@Override
public Name getDn() {
return dn;
}
@Override
public void setDn(Name dn) {
this.dn = dn;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getLastName() {
return lastName;
}
@Override
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String getUid() {
return uid;
}
@Override
public void setUid(String uid) {
this.uid = uid;
}
@Override
public String getPassword() {
return password;
}
@Override
public void setPassword(String password) {
this.password = password;
}
}
這邊我們是利用 Object-Directory Mapping (ODM)。也就是類似 Hibernate 和 JPA 利用 annotations 將 java 物件與資料庫 tables 的 mapping 方式。
那原先的程式碼就會變這樣:
MappingLdifReader<Person> mappingLdifReader = new MappingLdifReader<>();
mappingLdifReader.setRecordMapper(new RecordMapper<Person>(){
@Override
public Person mapRecord(LdapAttributes attributes) {
// 假設我們的 ldif 檔這些 attributes 都有值
Person person = new Person();
person.setDn(attributes.getName());
person.setName((String) attributes.get("cn"));
person.setLastName((String)attributes.get("sn"));
person.setUid((String) attributes.get("uid"));
person.setPassword(DatatypeConverter.printBase64Binary((byte[])
attributes.get(PASSWORD).get()));
return person;
}
});
mappingLdifReader.setResource(new ClassPathResource("data.ldif"));
mappingLdifReader.open(new ExecutionContext());
try {
// 這裡我們就拿到轉換完成的 person 物件了
Person person = mappingLdifReader.read();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mappingLdifReader.close();
其中假設我們的 ldif 檔如下:
uid=1,o=keeplearning,dc=blog
objectclass: organizationalPerson
objectclass: person
objectclass: inetOrgPerson
objectclass: top
cn: Dennis
sn: Shen
uid: 1
userPassword:: 12345
當初一直不知道為什麼讀進來的 password 有問題,後來看 source code,之後發現是有經過 base64(base64 並不是壓縮也不是加密)的轉換。
其實 userPassword: 12345
這樣的話,讀進來的就會是 String。因為 LdapAttributes
這隻在 toString 時有特別處理 ::
。
另外有點要注意的就是:如果是利用 ApacheDS(其他的我沒試過) 將 ldif 檔案匯出來的,這時的 password 是有經過加密的,這時就無法將他轉回原先字串了。