Spring ldap ODM

Spring ldap ODM

上文讲述了Spring-ldap基本操作,通过定义LdapTemplate这个bean到IOC容器,使用时注入LdapTemplate即可完成对LDAP目录树的CRUD及筛选、过滤等。

  • 但是对于筛选查询出来的内容,JNDI是封装在Attributes中,尽管spring-ldap提供了AttributesMapper接口,让你自己去实现具体的从Attributes转成Java对象的逻辑,但是随着业务变化,对于不同的查询列,转化逻辑必须重新写。

  • 那有没有办法,让查询出来的内容,自动转成我们想要Java对象呢,就像关系型数据库ORM,把从MySQL数据库查询的结果集,自动完成和实体类的映射,执行查询时,直接得到对象列表。

  • spring-ldap同样提供相应的支持(从spring-ldap 2.x版本开始),ODM (Object-Directory Mapping)对象目录映射。不同于MySQL数据库的是,LDAP是目录树,是树结构的数据库。

spring-ldap该框架通过提供和ORM中相似的机制对LDAP相关操作进行封装,主要包括:
1、类比SessionFactory的LdapContextSource;
2、类比HibernateTemplate等的LdapTemplate;
3、伪事务支持,能否与tx框架的TransactionManager混用未知;
4、类比JPA的使用@Entry、@Attribute、@Id标注的注解。

ORM框架,例如Hibernate 或者JPA,使得我们可以使用注解,映射一张表到一个Java实体。Spring-ldap提供相似的功能以完成对LDAP目录树的操作,LdapOperations接口提供了很多类似的方法:

 T findByDn(Name dn, Class clazz)

 T findOne(LdapQuery query, Class clazz)

 List find(LdapQuery query, Class clazz)

 List findAll(Class clazz)

 List findAll(Name base, SearchControls searchControls, Class clazz)

 List findAll(Name base, Filter filter, SearchControls searchControls, Class clazz)

void create(Object entry)
void update(Object entry)
void delete(Object entry)

LdapTemplate实现了该接口,这些方法均可在完成LdapTemplate bean定义后,注入使用。首先按完成基本工程搭建http://www.jianshu.com/p/3aeb49a9befd

ODM注解

需要完成映射的实体类需要使用注释。由org.springframework.ldap.odm.annotations package提供。

  • @Entry - 用于标注实体类(required)
  • @Id - 指明实体DN; 是javax.naming.Name类型(required)
  • @Attribute - 标识实体类需要映射的字段
  • @DnAttribute -
  • @Transient - 标识实体类不需要映射的字段
示例:
@Entry(objectClasses = { "person", "top" }, base="ou=someOu")
public class Person {
   @Id
   private Name dn;

   @Attribute(name="cn")
   @DnAttribute(value="cn", index=1)
   private String fullName;

   // No @Attribute annotation means this will be bound to the LDAP attribute
   // with the same value
   private String description;

   @DnAttribute(value="ou", index=0)
   @Transient
   private String company;

   @Transient
   private String someUnmappedField;
}

@Entry标记,其中的objectClasses定义必须与objectClass完全一致,并且可以指定多个值。在新建和查询object时,ODM会根据此标记进行匹配,无需再指定objectClass。

每个entry必须指定@Id字段,类型为javax.naming.Name,其实就是DN。但是若在LdapContextSource中指定了base,则DN将会按照base截取相对路径。比如,DN为cn=user,ou=users,dc=jayxu,dc=com,base为dc=jayxu,dc=com,则取出的user对象DN为cn=user,ou=users。

对于不需要与LDAP进行映射的字段使用@Transient进行标记

ODM操作

    /**
     * 按部门编号 o 查询部门
     */
    @Test
    public void findOne(){
        LdapQuery ldapQuery = query().where("o").is("039cb846de0e40e08901e85293f642bf");
        LdapDept dept = ldapTemplate.findOne(ldapQuery, LdapDept.class);
        System.out.println(dept);
    }

    /**
     * 按条件过滤部门
     */
    @Test
    public void filter(){
        LdapQueryBuilder ldapQueryBuilder = query();
        Filter filter = new GreaterThanOrEqualsFilter("modifyTimestamp",timestamp);
        ldapQueryBuilder.filter(filter);
        List depts = ldapTemplate.find(ldapQueryBuilder, LdapDept.class);
        for (LdapDept dept: depts ) {
            System.out.println(dept);
        }
    }

    /**
     * 查询所有部门
     * 类型和base,由LdapDept上的@Entry指定
     */
    @Test
    public void getAllDepts(){
        List depts = ldapTemplate.findAll(LdapDept.class);
        for (LdapDept dept: depts ) {
            System.out.println(dept);
        }
    }

其中LdapDept是自定义实体类,按照Entry、@Attribute、@Id注解的约定标注好即可。

使用org.springframework.ldap.pool.factory.PoolingContextSource引入连接池

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.pool.factory.PoolingContextSource;
import org.springframework.ldap.pool.validation.DefaultDirContextValidator;
import org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy;

import java.util.HashMap;
import java.util.Map;

/**
 * LDAP 的自动配置类
 *
 * 完成连接LDAP 及LdapTemplate 的定义
 */
@ConfigurationProperties(prefix = "ldap")
@PropertySource("classpath:/application.yml")
@Configuration
public class LdapConfiguration {

    private LdapTemplate ldapTemplate;

    @Value("${maxActive}")
    private int maxActive;

    @Value(value = "${maxTotal}")
    private int maxTotal;

    @Value(value = "${maxIdle}")
    private int maxIdle;

    @Value(value = "${minIdle}")
    private int minIdle;

    @Value(value = "${maxWait}")
    private int maxWait;

    @Value(value = "${url}")
    private String LDAP_URL;

    @Value(value = "${base}")
    private String BASE_DC;

    @Value(value = "${dbusername}")
    private String USER_NAME;

    @Value(value = "${password}")
    private String PASS_WORD;

    @Bean
    public LdapContextSource contextSource() {
        LdapContextSource contextSource = new LdapContextSource();
        Map config = new HashMap();

        contextSource.setUrl(LDAP_URL);
        contextSource.setBase(BASE_DC);
        contextSource.setUserDn(USER_NAME);
        contextSource.setPassword(PASS_WORD);

        //  解决 乱码 的关键一句
        config.put("java.naming.ldap.attributes.binary", "objectGUID");

        //当需要连接时,池是否一定创建新连接
        contextSource.setPooled(true);
        contextSource.setBaseEnvironmentProperties(config);
        return contextSource;
    }

    /**
     * LDAP pool 配置
     * @return
     */
    @Bean
    public ContextSource poolingLdapContextSource() {
        PoolingContextSource poolingContextSource = new PoolingContextSource();
        poolingContextSource.setDirContextValidator(new DefaultDirContextValidator());
        poolingContextSource.setContextSource(contextSource());
        poolingContextSource.setTestOnBorrow(true);//在从对象池获取对象时是否检测对象有效
        poolingContextSource.setTestWhileIdle(true);//在检测空闲对象线程检测到对象不需要移除时,是否检测对象的有效性

        poolingContextSource.setMaxActive(maxActive <= 0 ? 20:maxActive);
        poolingContextSource.setMaxTotal(maxTotal <= 0 ? 40:maxTotal);
        poolingContextSource.setMaxIdle(maxIdle <= 0 ? 5:maxIdle);
        poolingContextSource.setMinIdle(minIdle <= 0 ? 5:minIdle);
        poolingContextSource.setMaxWait(maxWait <= 0 ? 5:maxWait);

        TransactionAwareContextSourceProxy proxy = new TransactionAwareContextSourceProxy(poolingContextSource);
        return proxy;
    }

    @Bean
    public LdapTemplate ldapTemplate() {
        if (null == ldapTemplate)
            ldapTemplate = new LdapTemplate(poolingLdapContextSource());
        return ldapTemplate;
    }
}

ODM官方文档
https://docs.spring.io/spring-ldap/docs/2.3.2.RELEASE/reference/#odm

你可能感兴趣的:(Spring ldap ODM)