1、搭建ldap服务,我用的系统是Ubuntu14.04,具体可以参考这篇文章:ubuntu14.04搭建ldap服务,按照步骤来没什么问题。
安装之后访问地址为:http://10.8.12.147/phpldapadmin/
name: cn=admin,dc=dianrong,dc=com
password: 123456
2、安装ldapsoft ldap admin tool,官网下载地址:http://www.ldapsoft.com/download.html
点击新建连接(New Connection),按照以下配置:
第一次进来,只会有下图的cn=admin
3、利用spring-ldap实现增删改查(没有使用注解)
model类:
/**
* Created by drjr on 5/17/17.
*/
public class User {
private String fullName;
private String lastName;
private String description;
private String country;
private String company;
private String phone;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
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 getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
定义操作ldap的接口类:
public interface UserDao {
void create(User user);
void update(User user);
void delete(String fullName);
List<String> getAllUserNames();
List<User> findAll();
User findByPrimaryKey(String fullname);
}
接口实现类:
public class UserDaoImpl implements UserDao {
private LdapTemplate ldapTemplate;
@Override
public void create(User user) {
Name dn = buildDn(user.getFullName()); // 生成条目唯一标识,有点类似mysql的主键ID
DirContextAdapter context = new DirContextAdapter(dn); // 根据体用提供的dn构建适配器对象
mapToContext(user, context); // 给适配器对象设置属性值
ldapTemplate.bind(dn, context, null); // 插入数据
}
@Override
public void update(User user) {
Name dn = buildDn(user.getFullName());
DirContextAdapter context = (DirContextAdapter) ldapTemplate.lookup(dn);
mapToContext(user, context);
ldapTemplate.modifyAttributes(dn, context.getModificationItems());
}
@Override
public void delete(String fullName) {
ldapTemplate.unbind(buildDn(fullName));
}
@Override
public List<String> getAllUserNames() {
return ldapTemplate.search(query()
.attributes("cn")
.where("objectclass").is("person"),
new AttributesMapper<String>() {
@Override
public String mapFromAttributes(Attributes attributes) throws NamingException {
return attributes.get("cn").get().toString();
}
});
}
@Override
public List<User> findAll() {
return ldapTemplate.search(query()
.where("objectclass").is("person"),
USER_CONTEXT_MAPPER);
}
@Override
public User findByPrimaryKey(String fullname) {
LdapName dn = buildDn(fullname);
return ldapTemplate.lookup(dn, USER_CONTEXT_MAPPER);
}
private LdapName buildDn(String fullName) {
return LdapNameBuilder.newInstance()
.add("cn", fullName)
.build();
}
private void mapToContext(User user, DirContextAdapter context) {
context.setAttributeValues("objectclass", new String[] { "top", "person" });
context.setAttributeValue("cn", user.getFullName());
context.setAttributeValue("sn", user.getLastName());
context.setAttributeValue("description", user.getDescription());
context.setAttributeValue("telephoneNumber", user.getPhone());
}
private final static ContextMapper<User> USER_CONTEXT_MAPPER = new AbstractContextMapper<User>() {
@Override
public User doMapFromContext(DirContextOperations context) {
User user = new User();
user.setFullName(context.getStringAttribute("cn"));
user.setLastName(context.getStringAttribute("sn"));
user.setDescription(context.getStringAttribute("description"));
user.setPhone(context.getStringAttribute("telephoneNumber"));
return user;
}
};
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
public LdapTemplate getLdapTemplate() {
return ldapTemplate;
}
}
前端入口controller层:
@Controller
@RequestMapping(value = "users")
public class TestSpringLdapController {
@Autowired
private UserDao userDao;
@RequestMapping("/addUser")
public String addUser() {
User user = getUser();
userDao.create(user);
return "success";
}
@RequestMapping("/showUser")
@ResponseBody
public ModelMap showUser(@RequestParam(value = "fullName", required = true) String fullName) {
User user = userDao.findByPrimaryKey(fullName);
return new ModelMap("user", user);
}
@RequestMapping("/updatePhoneNumber")
public String updatePhoneNumber(@RequestParam(value = "fullName", required = true) String fullName) {
User user = userDao.findByPrimaryKey(fullName);
user.setPhone(StringUtils.join(new String[] { user.getPhone(), "0" }));
userDao.update(user);
return "success";
}
@RequestMapping("/removeUser")
public String removePerson(@RequestParam(value = "fullName", required = true) String fullName) {
userDao.delete(fullName);
return "success";
}
@RequestMapping("/getAll")
@ResponseBody
public String getAll() throws IOException {
ObjectMapper mapper = getDefaultObjectMapper();
List<User> users = userDao.findAll();
return mapper.writeValueAsString(users);
}
@RequestMapping("/getAllName")
@ResponseBody
public String getAllName() throws IOException {
ObjectMapper mapper = getDefaultObjectMapper();
List<String> userNames = userDao.getAllUserNames();
return mapper.writeValueAsString(userNames);
}
private User getUser() {
User user = new User();
user.setFullName("curry");
user.setLastName("stephone");
user.setCompany("company1");
user.setCountry("Sweden");
user.setDescription("Test user");
return user;
}
public static ObjectMapper getDefaultObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_EMPTY);
//设置将MAP转换为JSON时候只转换值不等于NULL的
mapper.configure(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES, false);
//mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//设置有属性不能映射成PO时不报错
mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
return mapper;
}
}
用的是gradle构建,所以build.gradle配置如下:
group 'dianrongDenghb'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'war'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
repositories {
jcenter()
maven {
url 'https://repo.spring.io/libs-milestone'
}
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile group: 'org.springframework.ldap', name: 'spring-ldap-core', version: '2.1.0.RELEASE'
compile group: 'org.springframework.ldap', name: 'spring-ldap-test', version: '2.1.0.RELEASE'
compile group: 'org.springframework', name: 'spring-context', version: '4.2.4.RELEASE'
compile group: 'org.springframework', name: 'spring-webmvc', version: '4.2.4.RELEASE'
compile group: 'org.springframework', name: 'spring-web', version: '4.2.4.RELEASE'
compile group: 'org.springframework', name: 'spring-beans', version: '4.2.4.RELEASE'
compile 'org.springframework:spring-core:4.2.4.RELEASE'
compile group: 'org.springframework.data', name: 'spring-data-commons', version: '1.11.4.RELEASE'
compile group: 'javax.servlet', name: 'jstl', version: '1.2'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.4.3'
compile group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version: '1.9.13'
compile group: 'org.codehaus.jackson', name: 'jackson-core-asl', version: '1.9.13'
providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
数据源的相关配置放在:ldap.properties
sample.ldap.url=ldap://10.8.12.147:389
sample.ldap.userDn=cn=admin,dc=dianrong,dc=com
sample.ldap.password=123456
sample.ldap.base=dc=dianrong,dc=com
sample.ldap.clean=true
在applicationContext.xml读取数据源配置文件,生成ldapTemplate
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ldap="http://www.springframework.org/schema/ldap"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap.xsd">
<context:property-placeholder location="classpath:/ldap.properties" />
<ldap:context-source id="contextSource"
password="${sample.ldap.password}"
url="${sample.ldap.url}"
username="${sample.ldap.userDn}"
base="${sample.ldap.base}" />
<ldap:ldap-template id="ldapTemplate" context-source-ref="contextSource"/>
<bean id="personDao" class="ldap.dao.odm.PersonDaoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
<bean id="userDao" class="ldap.dao.UserDaoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
</beans>
springmvc配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="ldap.web" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="Tiink-preview" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>Spring LDAP Basic Example</display-name>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>basic</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/basic-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>basic</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
到此结束,下面介绍通过注解的方式,实现对象和目录映射功能,简化代码。
model类这样写:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.ldap.odm.annotations.*;
import javax.naming.Name;
/**
* Created by drjr on 5/16/17.
*/
@Entry(objectClasses = {"person", "top"})
@JsonIgnoreProperties(value = {"dn"})
public class Person {
@Id
private Name dn;
@Attribute(name = "cn")
@DnAttribute(value = "cn", index = 0)
private String fullName;
@Attribute(name = "sn")
private String lastName;
@Attribute(name = "description")
private String description;
@Transient
private String country;
@Transient
private String company;
@Attribute(name = "telephoneNumber")
private String phone;
public Name getDn() {
return dn;
}
public void setDn(Name dn) {
this.dn = dn;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
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 getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
@JsonIgnoreProperties此注解是类注解,作用是json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响。不用此注解,会报json转换的异常。
@Id表明实体类DN ,这个属性必须是javax.naming.Name类型,有点类似数据库表中的主键意思
@Attribute表示目录属性映射到对象类字段,表示这是objectClass的一个属性
@Dnattribute标注的属性都是属于自动构建DN时的一部分
@Entry注解表明这是一个ldap的实体映射类
接口实现类(增删改查和上面的实现类对比省掉一些代码,更加简洁,不需要手动去映射字段了):
import ldap.dao.PersonDao;
import ldap.domain.Person;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.support.LdapNameBuilder;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import java.util.List;
import static org.springframework.ldap.query.LdapQueryBuilder.query;
/**
* Created by drjr on 5/16/17.
*/
public class PersonDaoImpl implements PersonDao {
private LdapTemplate ldapTemplate;
@Override
public void create(Person person) {
ldapTemplate.create(person);
}
@Override
public void update(Person person) {
ldapTemplate.update(person);
}
@Override
public void delete(Person person) {
ldapTemplate.delete(ldapTemplate.findByDn(buildDn(person.getFullName()), Person.class));
}
@Override
public List<String> getAllPersonNames() {
return ldapTemplate.search(query()
.attributes("cn")
.where("objectclass").is("person"),
new AttributesMapper<String>() {
public String mapFromAttributes(Attributes attrs) throws NamingException {
return attrs.get("cn").get().toString();
}
});
}
@Override
public List<Person> findAll() {
return ldapTemplate.findAll(Person.class);
}
@Override
public Person findByPrimaryKey(String fullname) {
LdapName dn = buildDn(fullname);
Person person = ldapTemplate.findByDn(dn, Person.class);
return person;
}
private LdapName buildDn(String fullName) {
return LdapNameBuilder.newInstance()
.add("cn", fullName)
.build();
}
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
}