spring-ldap学习(二)
来源:互联网 发布:10月经济数据 统计局 编辑:程序博客网 时间:2024/06/09 04:02
上一篇介绍了搭建ldap服务,通过GUI风格的ldapsoft ldap admin tool去连接ldap服务端以及介绍了spring-ldap的增删改查,本文将介绍spring data 式的风格去编码,使代码更加简洁,之前也写过一篇spring data mongodb,点击这里查看 spring data mongodb学习以及为repository提供可扩展的自定义方法
首先我们通过ldapsoft ldap admin tool创建几个目录:
第一步:点击左上角dc=dianrong,dc=com,右键选择New Entry,再选择New Organization Unit,在面板里配置上Departments
第二步:点击创建好的Departments,右键选择New Entry,再选择New Organization Unit,在面板里配置上IT
第三步:点击创建好的IT,右键选择New Entry,再选择New Organization Unit,在面板里配置上PROJECTTHREE
这样目录层次就如下图所示:
同时我们也增加一个ou=Groups,最后目录层次如下
上面这些也是可以在我们代码里面实现:
public void addOrganization(String ou,String parent) {this.getLdapTemplate().bind(this.getDn(ou,parent), null, this.getAttributes(ou,parent)); } private Attributes getAttributes(String ou,String parent){Attributes attrs = new BasicAttributes();Attribute oattr = new BasicAttribute("objectclass");oattr.add("top");oattr.add("OrganizationalUnit");attrs.put(oattr);attrs.put("ou",ou);return attrs; } private Name getDn(String ou ,String parent){Name dn = LdapNameBuilder.newInstance(parent).add("ou", ou).build();return dn; }然后写两个junit加进去就好
@Testpublic void initDepartment() {ApplicationContext ac = getapp();OrganizationRepo org = (OrganizationRepo) ac.getBean("organizationRepo");org.addOrganization("Departments", "");org.addOrganization("Groups", "");}@Testpublic void initUnits() {ApplicationContext ac = getapp();OrganizationRepo org = (OrganizationRepo) ac.getBean("organizationRepo");org.addOrganization("IT","ou=Departments");org.addOrganization("PROJECTTHREE", "ou=IT,ou=Departments");}在我们右边的界面可以看到这些信息,比如:objectClass=top; objectClass=organizationlUnit等等
以上就是初始化的一些配置,为下面介绍spring data ldap做铺垫。
在这里简单说一下objectClass:
LDAP中,一个条目必须包含一个objectClass属性,且需要赋予至少一个值。每一个值将用作一条LDAP条目进行数据存储的模板;模板中包含了一个条目必须被赋值的属性和
可选的属性。
objectClass有着严格的等级之分,最顶层是top和alias。例如,organizationalPerson这个objectClass就隶属于person,而person又隶属于top。
objectClass可分为以下3类:
结构型(Structural):如person和organizationUnit;
辅助型(Auxiliary):如extensibeObject;
抽象型(Abstract):如top,抽象型的objectClass不能直接使用。
在OpenLDAP的schema中定义了很多objectClass,下面列出部分常用的objectClass的名称。
account
alias
dcobject
domain
ipHost
organization
organizationalRole
organizationalUnit
person
organizationalPerson
inetOrgPerson
residentialPerson
posixAccount
posixGroup
不了解这些shcema代码中会可能遇到一些错误,这在后面会介绍。
定义model类(model类里面的注解,在上一篇有介绍可以点击这里查看spring-ldap学习(一):
import org.springframework.ldap.odm.annotations.Attribute;import org.springframework.ldap.odm.annotations.DnAttribute;import org.springframework.ldap.odm.annotations.Entry;import org.springframework.ldap.odm.annotations.Id;import javax.naming.Name;import java.util.HashSet;import java.util.Set;/** * Created by drjr on 5/19/17. */@Entry(objectClasses = {"groupOfNames", "top"}, base = "ou=Groups")public class Group { @Id private Name id; @Attribute(name = "cn") @DnAttribute(value = "cn", index=1) private String name; @Attribute(name = "description") private String description; @Attribute(name = "member") private Set<Name> members = new HashSet<Name>(); public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Set<Name> getMembers() { return members; } public void addMember(Name newMember) { members.add(newMember); } public void removeMember(Name member) { members.remove(member); } public Name getId() { return id; } public void setId(Name id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
import org.springframework.ldap.odm.annotations.Attribute;import org.springframework.ldap.odm.annotations.DnAttribute;import org.springframework.ldap.odm.annotations.Entry;import org.springframework.ldap.odm.annotations.Id;import org.springframework.ldap.odm.annotations.Transient;import org.springframework.ldap.support.LdapUtils;import javax.naming.Name;/** * Created by drjr on 5/19/17. */@Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top"}, base = "ou=Departments")public final class User { @Id private Name id; @Attribute(name = "cn") @DnAttribute(value="cn", index=3) private String fullName; @Attribute(name = "employeeNumber") private int employeeNumber; @Attribute(name = "givenName") private String firstName; @Attribute(name = "sn") private String lastName; @Attribute(name = "title") private String title; @Attribute(name = "mail") private String email; @Attribute(name = "telephoneNumber") private String phone; @DnAttribute(value="ou", index=2) @Transient private String unit; @DnAttribute(value="ou", index=1) @Transient private String department; public String getUnit() { return unit; } public void setUnit(String unit) { this.unit = unit; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } public Name getId() { return id; } public void setId(Name id) { this.id = id; } public void setId(String id) { this.id = LdapUtils.newLdapName(id); } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getEmployeeNumber() { return employeeNumber; } public void setEmployeeNumber(int employeeNumber) { this.employeeNumber = employeeNumber; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; }}定义接口来说明我们要对数据库操作什么
import ldap.domain.User;import org.springframework.ldap.repository.LdapRepository;import java.util.List;/** * Created by drjr on 5/17/17. */public interface UserRepo extends LdapRepository<User> { User findByEmployeeNumber(int employeeNumber); List<User> findByFullNameContains(String name);}
import ldap.domain.Group;import org.springframework.ldap.repository.LdapRepository;/** * Created by drjr on 5/19/17. */public interface GroupRepo extends LdapRepository<Group> { Group findByName(String groupName);}定义对group操作的扩展类:
public interface GroupRepoExtension { List<String> getAllGroupNames(); void create(Group group);}
import ldap.dao.GroupRepoExtension;import ldap.domain.Group;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.ldap.core.AttributesMapper;import org.springframework.ldap.core.LdapTemplate;import org.springframework.ldap.query.LdapQuery;import org.springframework.ldap.support.LdapUtils;import org.springframework.stereotype.Repository;import static org.springframework.ldap.query.LdapQueryBuilder.query;import javax.naming.NamingException;import javax.naming.directory.Attributes;import java.util.List;/** * Created by drjr on 5/19/17. */@Repository("groupRepoExtensionImpl")public class GroupRepoExtensionImpl implements GroupRepoExtension { private static final String ADMIN_USER = "cn=system"; @Autowired private LdapTemplate ldapTemplate; public void setLdapTemplate(LdapTemplate ldapTemplate) { this.ldapTemplate = ldapTemplate; } @Override public List<String> getAllGroupNames() { LdapQuery query = query().attributes("cn") .where("objectclass").is("groupOfNames"); return ldapTemplate.search(query, new AttributesMapper<String>() { @Override public String mapFromAttributes(Attributes attributes) throws NamingException { return (String) attributes.get("cn").get(); } }); } @Override public void create(Group group) { System.out.println("name:" + group.getName()); group.addMember(LdapUtils.newLdapName(ADMIN_USER));//必须要有member成员,默认增加一个系统成员。 ldapTemplate.create(group); }}service层:
import ldap.dao.GroupRepo;import ldap.dao.UserRepo;import ldap.domain.Group;import ldap.domain.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.ldap.support.LdapUtils;import org.springframework.stereotype.Service;import java.util.List;/** * Created by drjr on 5/19/17. */@Service("userService")public class UserService { @Autowired private UserRepo userRepo; public void setUserRepo(UserRepo userRepo) { this.userRepo = userRepo; } @Autowired private GroupRepo groupRepo; public void setGroupRepo(GroupRepo groupRepo) { this.groupRepo = groupRepo; } public Iterable<User> findAll() { return userRepo.findAll(); } public User findUser(String userId) { return userRepo.findOne(LdapUtils.newLdapName(userId)); } public List<User> searchByNameName(String lastName) { return userRepo.findByFullNameContains(lastName); } public User create(User user, String group) { User savesUser = userRepo.save(user); Group grp = groupRepo.findOne(LdapUtils.newLdapName(group)); //根据组名ID查询到该组 grp.addMember(savesUser.getId()); //保存用户到组 groupRepo.save(grp); return savesUser; }}
同时需要在applicationContext.xml配置:<ldap:repositories base-package="ldap.dao" />这样上面的dao层才起作用。
spring-data 的意思是,我们需要在接口里告诉spring你要查询什么一个什么样的查询,它便帮你实现了。我们不用自己再去写查询语句,不用再拼接复杂的查询,比如你根据员工id去查询这个人,如上只要在dao层定义:User findByEmployeeNumber(int employeeNumber); 也可以查询一个人的名字是否包含某个字符串,例如上面:List<User> findByFullNameContains(String name);
下面是我写的测试类:
import ldap.dao.GroupRepoExtension;import ldap.domain.Group;import ldap.domain.User;import ldap.service.UserService;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.concurrent.atomic.AtomicInteger;/** * Created by drjr on 5/19/17. */public class LdapDemoTest {private final AtomicInteger nextEmployeeNumber = new AtomicInteger(10);@Testpublic void initGroup() {ApplicationContext apc = new ClassPathXmlApplicationContext("applicationContext.xml");GroupRepoExtension groupRepo = (GroupRepoExtension) apc.getBean("groupRepoExtensionImpl");Group grp = new Group();grp.setName("ROLE_USER");groupRepo.create(grp);Group grp2 = new Group();grp2.setName("BASIC_USER");groupRepo.create(grp2);}@Testpublic void addUser() {ApplicationContext apc = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = (UserService) apc.getBean("userService");User user = new User();user.setFullName("Tony Born");user.setEmployeeNumber(nextEmployeeNumber.getAndIncrement());user.setFirstName("Tony");user.setLastName("Born");user.setTitle("test");user.setEmail("qq.com");user.setPhone("18888886666");user.setUnit("PROJECTTHREE");user.setDepartment("IT");userService.create(user, "cn=ROLE_USER,ou=Groups");}}依次执行两个test之后,会得到如下图所示的结果。
在右边可以看到cn=ROLE_USER的详细信息,里面有两个member,其中一个就是cn=Tony Born,ou=PROJECTTHREE,ou=IT,ou=Depatments,就是我们添加user的时候加到该组中的。
cn=Tony Born信息如下:
最后再提下这个schema的事情,需要注意一下:
上面的User类Entry定义是这样子:
如果改成如下所示,会报异常,org.springframework.ldap.SchemaViolationException: [LDAP: error code 65 - attribute 'mail' not allowed];
因为mail,employeeNumber,givenName,title,sn这些是没有定义的。而是在objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top"}才有定义,导致违反schema的异常。所以要了解schema之后才能在model里面定义属性,不能随便添加。
解释一下base:如果上述Group类不指定base = "ou=Groups",那么添加的组就会出现在dc=dianrong,dc=com目录下面。
对上面代码进行一些改进:
1)让 GroupRepo同时继承LdapRepository<Group>和GroupRepoExtension
2)在UserServcie,增加一个借口,同时修改测试类:
区别就是用GroupRepo来统一接口编程,不过这时候会报错:Caused by: org.springframework.data.mapping.PropertyReferenceException: No property getAllGroupNames found for type Group!
需要将GroupRepoExtensionImpl修改成GroupRepoImpl这种格式才行。
再次运行代码,还会出错:Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'groupRepoImpl' for bean class [ldap.dao.impl.GroupRepoImpl] conflicts with existing, non-compatible bean definition of same name and class [ldap.dao.impl.GroupRepoImpl]
意思是这个groupRepoImpl的bean已经存在了。
因为在applicationContext.xml文件中配置了,两个扫描包导致的。
所以去掉这个@Repository("groupRepoImpl")就可以了,但是在applicationContext.xml配置bean,是不会出现已经存在的情况,应该是自动被忽略掉。
<bean class="ldap.dao.impl.GroupRepoImpl" />这样子的是会被忽略掉。运行代码,结果如下:
- spring-ldap学习(二)
- spring-ldap学习(一)
- LDAP学习笔记(二)LDAP安装配置
- Spring LDAP学习
- 解读Spring LDAP帮助中的代码案例(二)
- LDAP简介(二)
- Spring-ldap 操作LDAP
- Spring-ldap 操作LDAP
- Spring-ldap 操作LDAP
- Spring-ldap 操作LDAP
- spring-ldap
- Spring Ldap
- Spring LDAP
- Spring + LDAP
- Spring学习(二)
- Spring学习(二)
- Spring学习(二)
- Spring学习(二)
- Excel Sheet Column Number
- Libevent简介与使用
- spring发送邮件demo
- 【LeetCode】Binary Tree Preorder Traversal 解题报告
- 使用英特尔流式SIMD扩展优化动画模型的渲染流水线
- spring-ldap学习(二)
- 调用startActivityForResult,onActivityResult无响应的问题
- System.getProperty("catalina.home")+":"+System.getProperty("catalina.base")
- 上传本地项目到github
- 插入排序
- [ue4]摩尔纹(远处材质闪烁并有纹路)
- atof()和atoi()函数使用问题
- linux修改文件夹-文件目录权限
- MySQL开放3306端口不能访问的问题