首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring LdapTemplate 讀取組織架構 + FreeMarker 生成靜態通訊錄

     編輯:Java 相關知識

業務場景

郵件系統通訊錄需按拼音首字母分級目錄存儲(一級目錄首字母、二級前兩字母…),每級目錄包含 result.php 列出該分組人員。手動維護成本極高,需自動化生成。

技術棧

  • Spring LDAP 1.3.1 (LdapTemplate)
  • FreeMarker 2.3.x
  • 正則表達式解析 DN 獲取組織路徑

LdapTemplate 配置與查詢

Spring Bean 定義

<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
    <property name="url" value="ldap://192.168.101.179:389"/>
    <property name="base" value=""/>
    <property name="userDn" value="cn=platoptuser,ou=內置帳號,ou=系統,o=北京XX局"/>
    <property name="password" value="111111"/>
</bean>

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
    <constructor-arg ref="contextSource"/>
</bean>

核心查詢邏輯:ContextMapper 解析 DN

public List<Person> getAllPersonNames() {
    String dnRegex = "ou=([^,]*)?"; // 匹配 ou=組織名
    Pattern pattern = Pattern.compile(dnRegex, Pattern.DOTALL | Pattern.CASE_INSENSITIVE);

    return ldapTemplate.search(
        "o=北京XX局",
        "(objectClass=Person)",
        (ContextMapper<Person>) ctx -> {
            DirContextAdapter adapter = (DirContextAdapter) ctx;
            Attributes attrs = adapter.getAttributes();
            Person person = new Person();

            // 基礎屬性
            person.setFullName(getStringAttr(attrs, "cn"));
            person.setMail(getStringAttr(attrs, "mail"));
            person.setTitle(getStringAttr(attrs, "title"));

            // 關鍵:從 DN 解析組織路徑
            Name dn = adapter.getDn();
            String orgPath = "";
            if (dn != null) {
                Matcher m = pattern.matcher(dn.toString());
                while (m.find()) {
                    orgPath += m.group(1) + "/";
                }
            }
            person.setOrg(orgPath.isEmpty() ? "" : orgPath.substring(0, orgPath.length() - 1));
            return person;
        }
    );
}

private String getStringAttr(Attributes attrs, String key) {
    try {
        Attribute attr = attrs.get(key);
        return attr == null ? "" : attr.get().toString();
    } catch (NamingException e) {
        return "";
    }
}

FreeMarker 模板生成靜態頁面

模板文件 result.ftl

<?xml version="1.0" encoding="GBK"?>
<ul>
<#list persons as p>
    <li>${p.fullName} - ${p.mail} - ${p.title} - ${p.org}</li>
</#list>
</ul>

Java 生成代碼(關鍵:ClassTemplateLoader 解決 JAR 包路徑問題)

public class LdapDirectoryGenerator {
    private Configuration cfg;

    public void init() {
        cfg = new Configuration(Configuration.VERSION_2_3_31);
        // 關鍵點:打包成 JAR 後需用 ClassTemplateLoader 載入模板
        cfg.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/ftl"));
    }

    public void generate(List<Person> persons, String outputPath) throws Exception {
        Map<String, Object> root = new HashMap<>();
        root.put("persons", persons);

        Template template = cfg.getTemplate("result.ftl");
        try (Writer out = new OutputStreamWriter(new FileOutputStream(outputPath), "GBK")) {
            template.process(root, out);
        }
    }

    public static void main(String[] args) throws Exception {
        LdapDirectoryGenerator gen = new LdapDirectoryGenerator();
        gen.init();

        // 測試數據
        List<Person> list = new ArrayList<>();
        Person p = new Person();
        p.setFullName("陳小二");
        p.setMail("yueritian@sohu.com");
        p.setOrg("XX公司/集團");
        p.setTitle("程序員");
        list.add(p);

        gen.generate(list, "result.php");
        System.out.println("生成成功!");
    }
}

關鍵避坑指南

  1. DN 解析:LDAP DN 格式如 cn=張三,ou=研發部,ou=技術中心,o=公司,正則提取所有 ou 組成路徑
  2. 編碼一致性:LDAP 讀取、FreeMarker 模板、輸出文件統一用 GBK(郵件系統要求)
  3. JAR 包部署:ClassTemplateLoader 替代 setDirectoryForTemplateLoading,解決資源文件在 JAR 內無法讀取
  4. 大數據量分批:人員超萬條時,建議分頁查詢 LDAP,分批生成文件,避免 OOM
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved