spring ldap简单的例子(五)
上一篇文章中,我们导入了组织结构,那么这里继续导入人员,让每个人员都回到自己对应的部门下面去,由于上一篇中我们提到了,使用实体不够灵活,而且还有弊端,但是相对来说组织机构的数据量一般不会太多,那么可以使用实体的方式将就一下,人员这里我将使用另一中方式,最后呢达到程序可以通过我们的表格自动判断需要导入的属性,并且自动组装属性和属性值,不用在程序里面写死,当然,遵循守恒定律,我们表格就需要简单加工一下了!(突然觉得肚子饿,稍等片刻,吃个泡面先,貌似下午没有吃饭.....).
去吃泡面了,记录下时间:00:11:44
回来了,继续00:37:20
============================
首先要看一下人员的表格模板,如下图
我这是尽可能的把表格用一张图截取了,主要看第行和第二行,第一行不用我多说,第二行的每一个字段都对应core.schema中对objectclass为person的必选属性+可选属性,必选属性我们必须要添加,可选属性当然就是加不加都可以。我这里就先把我的objectclass为person的schema部分贴一下,里面有好多属性都是我自定义的,这一点要注意,你在写的时候一定要保证这个属性存在。
objectclass ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description $ useremail $ anquanma $ sslvpn $ incontroller $ guid $ employeeId $ employeeCode $ description $ state $ createTime $ userMail $ telephone $ thirdPartyMail $ operationState $ datasources $ employeeTypes $ employeeCard $ employeeSex $ employeeBirthday $ lastModifyTime $ orderCode $ postName $ companyName $ companyNumber $ diyProperties ) )
好,接下来需要添加导入人员的方法了,首先在接口中添加方法的定义,这次我们会用到一个LDAP的简单查询,即通过部门名称获得这个部门的完整DN,所以在这里定义的是两个方法,一个添加和一个查询:
package com.study.dao; import java.util.List; import java.util.Map; public interface CnDAO { /** * 添加人员 * @param map * @param supDn */ public void insertCn(Map<String,String> map,String supDn); /** * 获取父节点Dn * @param string * @return */ public String getOrgBasicDn(String string); /** * 添加人员 * @param map * @param mlist * @param orgBasicDn */ public void importCn(Map<String, String> map, List<String> mlist, String orgBasicDn); }
然后是对应的实现方法:
1 package com.study.dao.impl; 2 3 import java.util.Date; 4 import java.util.List; 5 import java.util.Map; 6 import java.util.UUID; 7 8 import javax.naming.directory.Attributes; 9 import javax.naming.directory.BasicAttribute; 10 import javax.naming.directory.BasicAttributes; 11 import javax.naming.directory.SearchControls; 12 13 import org.apache.log4j.Logger; 14 import org.springframework.ldap.NameAlreadyBoundException; 15 import org.springframework.ldap.core.ContextMapper; 16 import org.springframework.ldap.core.DirContextAdapter; 17 import org.springframework.ldap.core.DistinguishedName; 18 import org.springframework.ldap.core.LdapTemplate; 19 20 import com.study.dao.CnDAO; 21 22 public class CnDAOImpl implements CnDAO { 23 private LdapTemplate ldapTemplate; 24 public void setLdapTemplate(LdapTemplate ldapTemplate){ 25 this.ldapTemplate=ldapTemplate; 26 } 27 Logger logger=Logger.getLogger(CnDAOImpl.class); 28 @Override 29 public void insertCn(Map<String, String> map, String supDn) { 30 Attributes ouAttributes=new BasicAttributes(); 31 BasicAttribute ouBasicAttribute=new BasicAttribute("objectclass"); 32 ouBasicAttribute.add("person"); 33 ouAttributes.put(ouBasicAttribute); 34 for(String str:map.keySet()){ 35 ouAttributes.put(str,map.get(str)); 36 } 37 DistinguishedName newContactDN=new DistinguishedName(supDn); 38 newContactDN.add("cn",map.get("cn")); 39 ldapTemplate.bind(newContactDN,null,ouAttributes); 40 } 41 @Override 42 public String getOrgBasicDn(String dn) { 43 List list= ldapTemplate.search("", dn, SearchControls.SUBTREE_SCOPE,new ContextMapper(){ 44 public Object mapFromContext(Object arg0) { 45 DirContextAdapter context = (DirContextAdapter)arg0; 46 return context.getDn(); 47 } 48 49 }); 50 String bdn=list.toString(); 51 bdn=bdn.substring(1,bdn.length()-1); 52 return bdn; 53 } 54 @Override 55 public void importCn(Map<String, String> map, List<String> list, 56 String orgBasicDn) { 57 Attributes personAttributes=new BasicAttributes(); 58 BasicAttribute personBasicAttribute=new BasicAttribute("objectclass"); 59 personBasicAttribute.add("person"); 60 personAttributes.put(personBasicAttribute); 61 for(int b=0;b<list.size();b++){ 62 personAttributes.put(list.get(b),map.get(list.get(b))); 63 } 64 personAttributes.put("guid",UUID.randomUUID().toString()); 65 personAttributes.put("userPassword","123456"); 66 personAttributes.put("lastModifyTime",new Date(System.currentTimeMillis()).toLocaleString()); 67 DistinguishedName newContactDN=new DistinguishedName(orgBasicDn); 68 newContactDN.add("cn",map.get("cn")); 69 try{ 70 ldapTemplate.bind(newContactDN,null,personAttributes); 71 }catch(NameAlreadyBoundException e){ 72 logger.error("导入失败:"+e.getExplanation()+":"+map.get("cn")); 73 } 74 75 } 76 77 }
这个类中实现的两个方法,一个是getOrgBasicDn(String dn),通过这个方法我们可以查询到传入dn的完整DN值,关于查询的相关内容我后面会单独写文章,查询是个重头戏,我这里只是简单的一个查询,可以看到第50行的地方我对查询获取的数据进行了简单的加工,(就是去掉了list进行toString()后多出来的前后两个方括号,将[ou=aaa]变为ou=aaa)。
在下面的添加方法接收三个参数,第一个是我们自己组装的一个Map,怎样组装map是一个技术活,组装的好了会对以后操作数据很方便;第二个是一个list,里面存了第二列中所有的属性值,在这里遍历这个lis即可以完成对每一条数据的属性添加,我们这里是这样设计的,就是程序在读取表格的时候是从第二行开始读取,将第二行的数据存入一个list,并且第二行中属性的个数也控制着程序将要读取表格中数据的步进值,所以如果这个时候你在下面的数据后面添加备注是不会影响程序读取数据的,因为程序读取多少列数据是与第二行数据的个数有关系的。这个你稍作思考便明白了。
下面就是解析表格并且只执行添加的代码,ImportCnForXls.java
1 package com.study.cn; 2 3 import java.io.FileInputStream; 4 import java.io.InputStream; 5 import java.util.ArrayList; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 10 import org.apache.log4j.Logger; 11 import org.apache.poi.hssf.usermodel.HSSFRow; 12 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 13 import org.apache.poi.ss.usermodel.Cell; 14 import org.apache.poi.ss.usermodel.Row; 15 import org.apache.poi.ss.usermodel.Sheet; 16 import org.springframework.beans.factory.BeanFactory; 17 import org.springframework.beans.factory.xml.XmlBeanFactory; 18 import org.springframework.core.io.ClassPathResource; 19 import org.springframework.core.io.Resource; 20 21 import com.study.dao.CnDAO; 22 23 24 @SuppressWarnings("deprecation") 25 public class ImportCnForXls { 26 Logger logger=Logger.getLogger(ImportCnForXls.class); 27 public void importCnMethod(String src) throws Exception { 28 InputStream ins=new FileInputStream(src); 29 HSSFWorkbook hssfWorkbook=new HSSFWorkbook(ins); 30 hssfWorkbook.setMissingCellPolicy(Row.CREATE_NULL_AS_BLANK); 31 Sheet sheet=hssfWorkbook.getSheetAt(0); 32 33 Map<String,Map<String,String>> maryMap=new HashMap<String,Map<String,String>>(); 34 List<String> ldapList=new ArrayList<String>(); 35 Map<String,String> maryMapOpt=null; 36 for(int a=0;a<sheet.getLastRowNum();a++){ 37 if(a==0)continue; 38 HSSFRow row=(HSSFRow) sheet.getRow(a); 39 if(null!=row){ 40 if(a==1){ 41 for(int b=0;b<row.getLastCellNum();b++){ 42 row.getCell(b).setCellType(Cell.CELL_TYPE_STRING); 43 ldapList.add(row.getCell(b).getStringCellValue()); 44 } 45 continue; 46 } 47 maryMapOpt=new HashMap<String,String>(); 48 for(int c=0;c<sheet.getRow(1).getLastCellNum();c++){ 49 row.getCell(c).setCellType(Cell.CELL_TYPE_STRING); 50 maryMapOpt.put(ldapList.get(c),row.getCell(c).getStringCellValue().length()>0?row.getCell(c).getStringCellValue():" "); 51 } 52 if(maryMap.containsKey(maryMapOpt.get(ldapList.get(4)))){ 53 logger.warn("工号重复:"+maryMapOpt); 54 continue; 55 } 56 maryMap.put(maryMapOpt.get(ldapList.get(4)), maryMapOpt); 57 } 58 } 59 addPerson(maryMap, ldapList); 60 } 61 public void addPerson(Map<String,Map<String,String>> mmap,List<String> mlist){ 62 Resource resource=new ClassPathResource("com/study/cn/ldap-cn.xml"); 63 BeanFactory factory=new XmlBeanFactory(resource); 64 CnDAO ldapContact=(CnDAO) factory.getBean("ldapContext"); 65 StringBuffer sb=new StringBuffer(); 66 for(String mp: mmap.keySet()){ 67 sb.append("(&(ou="); 68 sb.append(mmap.get(mp).get("companyName")); 69 sb.append(")(objectclass=organizationalUnit))"); 70 String orgBasicDn = ldapContact.getOrgBasicDn(sb.toString()); 71 ldapContact.importCn(mmap.get(mp),mlist, orgBasicDn); 72 System.out.println("---"+orgBasicDn); 73 sb.delete(0, sb.length()); 74 } 75 System.out.println(mmap.size()); 76 } 77 public static void main(String[] args) { 78 try { 79 new ImportCnForXls().importCnMethod("user.xls"); 80 } catch (Exception e) { 81 e.printStackTrace(); 82 } 83 } 84 }
执行后大功告成:
对于这段代码我觉得我就不用多做说明了,明眼人一看就知道我做了什么,所以我就不在这里啰嗦了。
看到这里觉得刚开始接触LDAP觉得自己完全搞不懂是怎么回事,因为我们习惯了关系系数据库,对于这样的目录型的不适应,我也是,刚刚开始也是这样,总是问别人也不太好,谁都有自己的事情,公司里用到的都是已经封装好的东西,但是我就是不理解,我就是搞不明白为什么我调用这个方法他就执行添加了,为什么要传递这样 一个参数,他到底做了什么,这些问题我都是必须要搞明白的,因为我无法忍受我调用了一段代码我就稀里糊涂的把程序写出来了,也不是说我钻牛角尖,因为我不知道他做了什么,我就不明白自己为什么要这么做,这几天研究了下,总算是有点眉目了,而且我觉得以前封装的东西我直接就拿过来用,如果有一天哪里出问题了,我觉得我也搞不定,因为我完全不知道是怎么回事。
现在我做的所有功能都是基于我自己定义的一些接口和抽取的一些代码,但是最终还是要回到项目里面的,项目里面已经定义好的东西轻易是不会让你改变的,但是最起码的我知道了这些后会对我更好的完善代码和理解业务有很大的帮助吧。
其实,到现在我才明白,我们项目里有部分使用的是novell.ldap,并不是我这几天搞的spring ldap,这个就让我比较郁闷了,为毛要用两个???
=====================================
1、码字真心累啊,这篇文章写了有将近三个小时了吧,我也是一边做一边写的,再过一遍,熟悉熟悉。
2、困了,看屏幕的字都有点模糊了,再不睡刚刚吃的一桶泡面消化完肚子该饿了。
3、其实我还不困。
==============2014年3月26日17:04:45补充内容=======================
上面的查询写的比较次,各位看倌先凑合着看,专业的查询后续补充。