Github上搭建博客

Posted on

Github上搭建博客 - 小妖_OTZ - 博客园

午饭

Github上搭建博客

本文将详细介绍如何在Windows系统下搭建博客,并发布到GitHub Pages上,以及后期博客发布后的更新工作....

一、博客整体效果

搭建博客效果http://www.sunfanwu.com/(绑定域名后的效果,未绑定则调转到sunfanwu.github.com

网站成本:域名注册http://www.sunfanwu.com/ 50元(可不要)

服 务 器:免费托管在GitHub个人主页上(无数据库,但有整个网站备份。由于GitHub网站性质,博客源码文档为所有人可见)。

博客类型:静态博客,无数据库,博客通过html编写。

本地软件:msysgitrubyDevKitpython

备 注:GitHub为开源项目网站,请不要上传过大的且无意义的附件(如视频等)。

二、搭建本地环境

   为了在Github上使用Octopress,需要首先配置一下本地环境:

   安装Git,下载[msysgit](http://code.google.com/p/msysgit/downloads/list),安装可参考[官方文档](https://help.github.com/articles/set-up-git)。(Git分布式版本管理系统,在此主要是用来操作GitHub。不推荐使用Git 客户端—github for windows)

   然后安装Ruby,[Octopress 官方文档](http://octopress.org/docs/setup/)中指定的 Ruby 版本是 1.9.2,下载 [rubyinstaller-1.9.2-p290.exe](http://rubyforge.org/frs/download.php/75127/rubyinstaller-1.9.2-p290.exe),安装时记得选中“Add Ruby executables to your PATH”。

   为了检查Git、ruby是否已加入到PATH中,可在 Windows 的cmd窗口中执行以下命令:

path

   接着安装Devkit,选择下载 4.5.2 版本:[DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe](https://github.com/downloads/oneclick/rubyinstaller/DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe),下载完成后,将其解压到如 E:DevKit,然后在win的cmd窗口中执行如下命令进行安装:

E: cd E:DevKit ruby dk.rb init ruby dk.rb install

    (选装)最后安装python,主要是博客代码加亮模块需要python环境的支持,[下载2.7版](http://www.activestate.com/activepython/downloads),安装完以后,在Windows的cmd窗口中执行:

     本地环境配置结束。

三、更新本地环境配置

   为了支持中文UTF-8编码,对Windows环境变量配置如下:

LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8

  也可在直接在Windows的cmd窗口下运行命令:

set LANG=zh_CN.UTF-8 set LC_ALL=zh_CN.UTF-8

    更新gem的更新源,ruby的官方更新源经常被河蟹,换成国内的更新源,这样速度就快多了,变更如下:

gem sources -a http://ruby.taobao.org/ gem sources -r http://rubygems.org/ gem sources -l

    最后一个命令可查看更改后的更新源列表。

四、下载并配置Octopress

    首先下载Octopress源码,可以使用下面git命令(具体应用可参见git官方文档)下载,也可直接在Octopress Github库中下载octopress的zip包([点击下载](https://nodeload.github.com/imathis/octopress/zipball/master)),然后将下载的压缩包解压到E盘根目录,修改解压后的文件夹名称为 octopress。

E: git clone git://github.com/imathis/octopress.git octopress

     然后更新 Octopress 的gem更新源:进到 E:octopress 目录,用文本编辑器(例如记事本)打开文件Gemfile,将里面source “http://rubygems.org/”改为source “http://ruby.taobao.org/”。

     最后安装Octopress的依赖项,在Windows的CMD窗口输入以下命令:

E: cd octopress gem install bundler bundle install

五、新建Github Repositories

   登录[Github](https://github.com/),假设你的用户名是username,首先要新建一个命名为 **username.github.com**的Repo,命名必须是这个格式,如果不这样命名的话,在运行命令 rake setup_github_pages  之后不能够自动创建后面提到的master和source 分支,而是作为普通仓库生成 gh-pages 分支。

   创建Repo(如果没用过GitHub,需先注册账户),如下图:

image

   Repo的设置,如下图:

20121016155745

六、发布Octopress到Github

   1、打开Windows下的命令窗口,进入到Octopress所在的目录,输入命令:

rake setup_github_pages

    按照提示输入刚才新建的Repo地址,类似:[git@github.com:用户名/用户](mailto:git@github.com:用户名/用户)[名.github.com.git](mailto:git@github.com)。

在Github上搭建Octopress博客03

   2、接着输入命令:

rake install

rake generate

rake preview

 其中rake install是安装Octopress默认主题的,rake gnerate是生成静态页面的,这两个命令是必须运行的,而rake preview则是用来本地浏览的(运行时看屏幕上提示,按Ctrl+C并输入Y来终止批处理操作),运行后打开浏览器,输入 [http://localhost:4000/](http://localhost:4000/) 就可以看到如下的界面了,不想预览的话也可以不运行,直接进入下一步。

在Github上搭建Octopress博客04

  3、将博客发布到Github上,输入下面命令:

rake deploy

 **备注:此处遇到错误,请看问题一。**

 这样,生成的内容将会自动发布到master分支,并且可以使用 [http://用户名.github.com](http://用户名.github.com/) 访问内容。

在Github上搭建Octopress博客05

    4、别忘了把所有源文件发布到 source 分支下面:

git add .

git commit -m “your message”

git push origin source

    至此,所有发布完成,接下来就是对博客的设置了。

七、Ocotpress博客配置

      更改下面的配置后,还需要运行 rake generate、rake deploy等等命令的。

  1、默认的博客运行成功的话,就需要按照自己的要求对博客配置进行修改了,主要是修改Octopress根目录下的主配置文件_config.yml。

url: http://username.github.com /# 博客地址

title: /# 博客标题 subtitle: /# 副标题 author: /# 作者 simple_search: http://www.google.com.hk/search /# 搜索引擎 description: /# 关于博客的描述 subscribe_rss: /atom.xml /# Rss订阅地址, 默认是 /atom.xml subscribe_email: /# 提供Email订阅的地址 email: /# Rss订阅的Email地址

root: / /# 博客路径,默认是“/“,如果你打算在子目录中,记得修改这个路径 permalink: /blog/:year/:month/:day/:title/ /# 文章的固定链接形式

 2、更换主题

     主题位于 octopress/.theme 目录下,默认主题为 classic。 如果需要更改主题(可在网上查找),下载后将主题也放在.theme目录下即可,如果主题名字为blog_theme,那么安装主题时输入以下命令即可:

rake install ['blog_theme']

八、绑定域名

    Github Pages绑定域名,需要在Octopress/source目录下建个无后缀的CNAME文本文件,文件内容就是你的域名,例如:

www.sunfanwu.com

    然后进入你的域名管理网站,修改A纪录为:“207.97.227.245” ,或者 CNAME 指向 username.github.com,下面就等着解析生效了。

九、更新博客(发布日志将在下一篇进行详细说明,敬请期待....)

    由于每次写博客都通过html格式比较麻烦,所以此处推荐使用[Windows Live Writer](http://baike.baidu.com/view/1049077.htm)本地编辑。

    1.编辑完成,选择以“源代码”形式查看,复制文本。

    2.在本地“octopress/public/blog/”找到需要更新的日志,通过记事本软件打开此html。

    3.找到<div class="entry-content"></div>,将复制的代码粘贴进去,保存关闭。

    4.通过之前说过的“rake deploy”命令就可以发布了。(发布之前可“rake preview”本地查看一下~)

   **备注:**如有图片的话,一般做法还需将图片保存到对应文件夹。此处可以先在“博客园”等网站通过[Windows Live Writer](http://baike.baidu.com/view/1049077.htm)发布博客,再将源码复制。即省去图片调用。又可做到一篇博客不同地方迅速发布,保留备份。

问题一:发布时git出现提示: Agent admitted failure to sign using the key. Permission denied (publickey) fatal: The remote end hung up unexpectedly

github的官方文档

/#1. Check for SSH keys. $ cd ~/.ssh /#2. Backup and remove existing SSH keys. $ lsLists all the subdirectories in the current directory $ mkdir key_backupmakes a subdirectory called "key_backup" in the current directory $ cp id_rsa/ key_backupCopies the contents of the id_rsa directory into key_backup $ rm id_rsa/ /#3. Generate a new SSH key. $ ssh-keygen -t rsa -C "your_email@youremail.com" /#4. Add your SSH key to GitHub. /#5. Test everything out. $ ssh -T git@github.com

 大概意思就是你先在本地建立自己的SSH密码对,然后将公钥上传到github。进行上传服务时输入密码即可(cmd输入密码是为不可见状态,输入好后点击“回车”即可)。

参考文章:

        教程参考: [http://xuhehuan.com/783.html](http://xuhehuan.com/783.html) (80%为参考此处进行整理)。

                      [http://mrzhang.me/blog/blog-equals-github-plus-octopress.html](http://mrzhang.me/blog/blog-equals-github-plus-octopress.html "http://mrzhang.me/blog/blog-equals-github-plus-octopress.html")

                      [http://caok.github.com/blog/2012/06/24/install-octopress-to-write-blog/](http://caok.github.com/blog/2012/06/24/install-octopress-to-write-blog/ "http://caok.github.com/blog/2012/06/24/install-octopress-to-write-blog/")

        octopress官方建立github主页参考: [http://octopress.org/docs/deploying/github/](http://octopress.org/docs/deploying/github/ "http://octopress.org/docs/deploying/github/")

posted @ 2012-10-16 16:10 小妖.OTZ 阅读(2654) 评论(0) 编辑 收藏

刷新评论刷新页面返回顶部

博客园首页博问新闻闪存程序员招聘知识库

公告

Copyright ©2013 小妖.OTZ

2013年前端开发者如何提升自己

Posted on

2013年前端开发者如何提升自己 - Web前端 - ITeye资讯

您还未登录 ! 登录 注册

ITeye3.0

资讯频道Web前端

20顶

0踩

Web前端

转载新闻 2013年前端开发者如何提升自己

2012-12-28 16:07 by 见习编辑 WnouM 评论(10) 有6735人浏览

css javascript 技能 html5

< > 猎头职位: 陕西: 西安:senior java engineer 大部分人非常在意个人在技术上的提升。但是保持对新技术的了解是一项不小的挑战, 毕竟我们需要的信息在数量上过于庞大。2012年里,伴随着前端发展的是大量的革命性突破和对前端的重新定义。 我们在实践的路上飞速前进,具体的进步体现在使用抽象化,优秀的代码质量,维护性上的提升以及更好的性能。如果你实在忙到没有时间来跟上最新的技术,不用担心。 随着假日的来临,我们就有了一些空闲的时间可以自己支配,我想,如果我把我收集的前端相关的精品讨论列表分享出来,那一定会对大家有一些帮助。你不需要把所有的都阅读一遍,但是这些相关的建议会让你了解更多相关的知识,为明年成为一名更好的前工程端开发师做准备。 以下是一些关于前端开发的优秀的PPT,你可以通过文中的链接来访问。 一、基础部分 走在技术前沿的方法 PPT:How to Stay Up to Date on Web Stuff, Chris Coyier 即使技术相关的理念会不断变化,我们依然可以做到让自己处于技术的前沿。 确保你的开发模式已经跟上时代 PPT:A New Baseline for Front-End Developers, Rebecca Murphey 曾经在我们编辑文件的时候,本地测试完然后传到ftp上是最常规的做法。我们通过一个前端是否能编写一个兼容ie6的页面来判断他的前端水平。我们在html,css和javascript中的技术都不够强悍。 这样的情况在近几年有了很大的转变,随着工作方式的改进和各类工具的推出。前端开发越来越受到重视,这个主题讲解了前端在开发中的新起点。 二、前端开发工程师的新起点 理解浏览器在屏幕后面的工作原理 PPT:So, You Want to Be a Front-End Engineer, David Mosher (Video) 有些人会说,浏览器是他所知道的开发平台中最不稳定的一个。如果你是一个客户端开发工程师,理解浏览器内部工作原理会帮助你作出更好的决定,并且你也会赞叹那些最佳实践背后的种种辩论。在这个今年最好的主题之一里,david mosher会待你了解浏览器的解析和页面的渲染。 了解web平台现在需要提供什么 PPT:Tooling for the Modern Web App Developer, Addy Osmani web在不断的进化,了解这个平台中新出的技术不是一件容易的事情。html5的新特性让我们可以构建一个完全崭新的web应用,包含很多以前无法实现的特性(至少,在没有插件的情况下)。 在这个主题中,我的队友eric会带你了解html5的痛苦边缘,关注很多解决现实世界问题的方案。你会了解媒体流,设备输入,现代css设计,媒体捕捉,文件i/o等等。 三、工作方式 web app开发工程师的工作方式 无论你在使用coffeescript还是javascript,less还是sass,构建一个好的web应用在现在需要大量引用外部资源,框架,工具和结合工具来将他们整合到一起。简单地说,你需要一个打屁股用的实用腰带。 在这个主题中,你会了解到当前前端系统的概况,并学习到一个新工具来整合这些系统,叫做yeoman。 你还可以访问这个主题的扩展版本。 PPT:Tooling For The Modern WebApp Developer web设计师的工作方式 PPT:A Modern Web Designer’s Workflow, Chris Coyier (Video) 今天我们对web构架师的要求很高。如果在以前,这个岗位名称已经表达了它所对应的工作,但是现在不仅仅是视觉设计岗位,甚至涉及到交互的构建。设计师需要考虑不同形状,不同尺寸,不同连接方式的不同设备,并且这些设备下都要能正常工作。 作为一个设计师,你通常需要在团队之间沟通和分享代码,并且需要了解很多不同的技术。在这个主题中,chris coyier会说到很多令人赞叹的工具来帮助手头的工作更加顺利地完成,还会讨论应该做些什么来提供一个高水准的现代工作流。 移动web开发的工作方式 PPT:Mobile Web Developers Toolbelt, Pete Le Page (Video) 移动端开发和PC端开发有很大的不同,这个主题讲述了各种工具来让移动web开发更加方便,让移动web开发更加容易。 如何调试 PPT:Secrets of the Chrome DevTools, Patrick Dubroy (Video) 深度了解谷歌开发者工具 四、面向未来的开发 CSS PPT:The CSS of Tomorrow, Peter Gasston 这个主题介绍了CSS给你现在的开发带来了什么,作为一个CSS程序员,如何利用CSS3来实现面向未来的开发。 JAVASCRIPT PPT:The Future of JavaScript, Dave Herman 了解ES6的新特性,以及使用方式 WEB APPLICATIONS PPT:Web Components and the Future of Web App Development, Eric Bidelman 如何更好地将各种新技术整合到你的web应用中。 五、CSS CSS领域中的艺术 PPT:All the New CSS Hawtness, Darcy Clarke 这个主题介绍了最新的CSS实现以及相关的标准,并且学习到这些新的CSS技术是如何改变我们的日常开发。 模块化CSS PPT:Your CSS Is a Mess, Jonathan Snook 大部分人的CSS代码都是一团糟,在这个主题中,你会知道如何解决CSS的模块化问题,方便管理和维护。 CSS的预处理器 PPT:CSS Pre-Processors, Bermon Painter 如果你还没有用过CSS预处理器,那你就OUT了。这个主题会对比较流行的几个CSS预处理器进行概述。 文档 PPT:A Better Future With KSS, Kyle Neath 本主题介绍了Kyle的一个工具,KSS,用于生成CSS文件的文档和代码格式化。 六、JavaScript 代码风格的重要性 PPT:Maintainable JavaScript, Nicholas Zakas 编写有趣的JavaScript代码和编写专业的JavaScript代码是两码事,在Zakas的这个主题中,你会学习到如何做到编写可持续性维护的JavaScript代码 构建大规模的APP PPT:SoundCloud’s Stack, Nick Fisher 这个主题中,来自SoundCloud的Nick Fisher会介绍他们公司开发一个大规模JavaScript APP的故事,并且分享他们的开发步骤以及如何提高开发效率。 重新思考应用的结构 PPT:Re-Imagining the Browser With AngularJS, Igor Minar 在这个主题中,你会了解如何将未来Web平台的力量使用到当前的Web应用中。 国际化 PPT:Entschuldigen you, parlez vouz JavaScript, Sebastian Golasch (Video) 这个主题中,Sebastian介绍了从如何定位现实世界中的国际化问题,到如何用优雅的方式进行解决。 模式和原则 PPT:The Plight of Pinocchio, Brandon Keepers 我们需要将JavaScript作为一门真正的语言,就需要能在JavaScript上使用真正的语言会使用的各种最佳实践。JavaScript不再是一门玩具语言。 什么时候来延迟(惰性)加载脚本 PPT:How Late Is Later?, Massimiliano Marcon 我们都知道延迟(惰性)加载脚本可以提高Web应用的加载时间,那么什么时候才是正确的时间来加载脚本呢? 七、移动Web开发 PPT:Creating Responsive HTML5 Touch Interfaces, Stephen Woods (Video | Audio) 如何去解决UI和用户间交互的问题,避免这些陷阱是很多应用开发者在未来需要面对的。 来自滚动条的挑战 PPT:Embracing Touch: Cross-Platform Scrolling, Mark Dalgleish (Video) 滚动效果是最流行的移动页面的方式。可惜滑动的效果总是不能与原生滚动条媲美。我们应该如何在移动浏览器上解决这个问题? 原生,HTML5和混合的应用 PPT:Native, HTML5 and Hybrid Mobile Development, Eran Zinman 这个主题中,Eran分享了他在跨平台开发中的经验。 性能,分布和facebook在HTML5上的实践 PPT:On the Future of Mobile Web Apps, Simon Cross facebook利用HTML5做了什么?还有什么需要改进? 移动开发的调试工具 PPT:Mobile Debugging, Remy Sharp 响应式设计技术 PPT:Responsive Web Design: Clever Tips and Techniques, Vitaly Friedman 这个主题提供了响应式设计实现的概述。 八、Web Apps 离线的web应用 PPT:Offline Rules, Andrew Betts (Video) 如何在Web应用中做到客户端的存储,并且如何将其用在提高网站的体验上。 STATE OF THE ART PPT:Building Web Apps of the Future: Tomorrow, Today and Yesterday, Paul Kinlan (Audio) Paul介绍了如何构建面向未来的web app。 客户端存储 PPT:Storage in the Browser, Andrew Betts 应用缓存 PPT:Application Cache: Douchebag, Jake Archibald (Video) 如何利用Application Cache来构建你的网站 九、性能 CSS PPT:High-Performance CSS, Paul Irish 找出那些影响页面性能的CSS,比如引发浏览器绘制至少多70毫秒的box-shadow,以及解决方案。 PPT:GitHub’s CSS Performance, Jon Rohan 避免JANK PPT:Jank-Free: In Pursuit of Smooth Web Apps, Tom Wiltzius JANK是指当动画顿卡,特效执行缓慢,或者页面滚动慢时的一种状态。该主题介绍了如何避免这些状态。 Web PPT:Building Faster Websites, Ilya Grigorik 如何在网站的角度考虑整体性能的提升。 JavaScript PPT:Breaking the JavaScript Speed Limit With V8, Daniel Clifford 如何打破V8执行脚本的速度限制。 十、测试 理解代码的不好的原因 PPT:Why Our Code Smells, Brandon Keepers (Video) 这个主题中,Brandon会介绍他日常的代码,寻找那些会引起问题的劣质代码,理解为什么会出现这些代码,并且这些代码意味着什么,最后介绍如何对其进行重构。 CURRENT STATE OF THE ART PPT:JavaScript Testing: The Holy Grail, Adam Hawkins (Video) 如何利用测试工具,来保证一个应用的体验。 提高代码的可测试性 PPT:Writing Testable JavaScript, Rebecca Murphey (Audio) 十一、总结 花在思考自己技术提升上的时间是非常值得的。磨练的越多,你就更有机会去成为一名优秀的工程师。 这个列表不一定会覆盖今年所有优秀的PPT,不过还是希望能给大家提供一些指引。去阅读一些你感兴趣的。这样的阅读会提高你的能力,也希望能真正为你的日常开发提供帮助。 最后,祝大家享受节日,新的一年有更多的进步和突破。 原文:Talks To Help You Become A Better Front-End Engineer In 2013(译文来自w3ctech

  • 大小: 25.8 KB

  • 大小: 22.5 KB

  • 大小: 44.2 KB

  • 大小: 13.5 KB

  • 大小: 18.7 KB

  • 大小: 11.8 KB

  • 大小: 15 KB

  • 大小: 24 KB

  • 大小: 69.1 KB

  • 大小: 18.6 KB

  • 大小: 10.5 KB

  • 大小: 36.5 KB

  • 大小: 57.6 KB

  • 大小: 26.7 KB

  • 大小: 32 KB

  • 大小: 31 KB

  • 大小: 16.2 KB

  • 大小: 25.1 KB

  • 大小: 36.3 KB

  • 大小: 56 KB

  • 大小: 40.1 KB

  • 大小: 54.7 KB

  • 大小: 26.3 KB

  • 大小: 16.1 KB

  • 大小: 17.9 KB

  • 大小: 29.3 KB

  • 大小: 66.6 KB

  • 大小: 35.1 KB

  • 大小: 37.1 KB

  • 大小: 27.7 KB

  • 大小: 32.9 KB

  • 大小: 12.3 KB

  • 大小: 10.4 KB

  • 大小: 9.9 KB

  • 大小: 12.8 KB

  • 大小: 17.4 KB

  • 大小: 55.5 KB

  • 大小: 79.1 KB

  • 大小: 48.7 KB

  • 查看图片附件 来自: w3ctech

分享到:

200 踩 评论 共 10 条 请登录后发表评论

10 楼 vtaminn 2013-01-04 08:49

很好。很强悍!

9 楼 rayzy1991 2013-01-01 16:50

革命尚未成功,同志仍需努力!

8 楼 dianthus 2012-12-31 13:38

mark..

7 楼 caizi12 2012-12-31 10:06

”前端开发工程师的新起点“ 配图里面的人物不是“军团要塞”上的火箭兵吗?

6 楼 sdhery 2012-12-30 09:14

文章很长,很好很强大

5 楼 geminiyellow 2012-12-29 18:47

nm,好多

4 楼 tianshaojie 2012-12-29 11:20

方向大而全

3 楼 topcss 2012-12-29 09:18

很多打不开呀

2 楼 beeke 2012-12-28 21:01

这篇文章很酷

1 楼 xingkongxieyang 2012-12-28 17:34

很好,很强大!

发表评论

您还没有登录,请您登录后再发表评论

2012 ITeye&CSDN最新职位火热招聘中!急聘ruby研发、编辑、运营!请将简历发送至hrzhaopin@csdn.net

相关资讯

相关博客

© 2003-2012 ITeye.com. [ 京ICP证110151号 京公网安备110105010620 ] 百联优力(北京)投资有限公司 版权所有

Git详解之一:Git起步

Posted on

Git详解之一:Git起步

原文:《Pro Git》

起步

本章介绍开始使用 Git 前的相关知识。我们会先了解一些版本控制工具的历史背景,然后试着让 Git 在你的系统上跑起来,直到最后配置好,可以正常开始开发工作。读完本章,你就会明白为什么 Git 会如此流行,为什么你应该立即开始使用它。(查看Git详解系列的全部文章

1.1 关于版本控制

什么是版本控制?我真的需要吗?版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统。在本书所展示的例子中,我们仅对保存着软件源代码的文本文件作版本控制管理,但实际上,你可以对任何类型的文件进行版本控制。

如果你是位图形或网页设计师,可能会需要保存某一幅图片或页面布局文件的所有修订版本(这或许是你非常渴望拥有的功能)。采用版本控制系统 (VCS)是个明智的选择。有了它你就可以将某个文件回溯到之前的状态,甚至将整个项目都回退到过去某个时间点的状态。你可以比较文件的变化细节,查出最 后是谁修改了哪个地方,从而导致出现怪异问题,又是谁在何时报告了某个功能缺陷等等。使用版本控制系统通常还意味着,就算你乱来一气把整个项目中的文件改 的改删的删,你也照样可以轻松恢复到原先的样子。但额外增加的工作量却微乎其微。

本地版本控制系统

许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。这么做唯一的好处就是简单。不过坏处也不少:有时候会混淆所在的工作目录,一旦弄错文件丢了数据就没法撤销恢复。

为了解决这个问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异(见图 1-1)。

Git详解之一:Git起步

图 1-1. 本地版本控制系统

其中最流行的一种叫做 rcs,现今许多计算机系统上都还看得到它的踪影。甚至在流行的 Mac OS X 系统上安装了开发者工具包之后,也可以使用 rcs 命令。它的工作原理基本上就是保存并管理文件补丁(patch)。文件补丁是一种特定格式的文本文件,记录着对应文件修订前后的内容变化。所以,根据每次 修订后的补丁,rcs 可以通过不断打补丁,计算出各个版本的文件内容。

集中化的版本控制系统

接下来人们又遇到一个问题,如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统( Centralized Version Control Systems,简称 CVCS )应运而生。这类系统,诸如 CVS,Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这 已成为版本控制系统的标准做法(见图 1-2)。

Git详解之一:Git起步

图 1-2. 集中化的版本控制系统

这种做法带来了许多好处,特别是相较于老式的本地 VCS 来说。现在,每个人都可以在一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限,并且管理一个 CVCS 要远比在各个客户端上维护本地数据库来得轻松容易。

事分两面,有好有坏。这么做最显而易见的缺点是中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。要 是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就还是会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,而被客户端 提取出来的某些快照数据除外,但这样的话依然是个问题,你不能保证所有的数据都已经有人事先完整提取出来过。本地版本控制系统也存在类似问题,只要整个项 目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。

分布式版本控制系统

于是分布式版本控制系统( Distributed Version Control System,简称 DVCS )面世了。在这类系统中,像 Git,Mercurial,Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜 像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份(见图 1-3)。

Git详解之一:Git起步 图 1-3. 分布式版本控制系统

更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。

1.2 Git 简史

同生活中的许多伟大事件一样,Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用分布式版本控制系统 BitKeeper 来管理和维护代码。

到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds )不得不吸取教训,只有开发一套属于自己的版本控制系统才不至于重蹈覆辙。他们对新的系统制订了若干目标:

/ 速度 / 简单的设计 / 对非线性开发模式的强力支持(允许上千个并行开发的分支) / 完全分布式 /* 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)

自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。它的速度飞快,极其适合管理大项目,它还有着令人难以置信的非线性分支管理系统(见第三章),可以应付各种复杂的项目开发需求。

1.3 Git 基础

那么,简单地说,Git 究竟是怎样的一个系统呢?请注意,接下来的内容非常重要,若是理解了 Git 的思想和基本工作原理,用起来就会知其所以然,游刃有余。在开始学习 Git 的时候,请不要尝试把各种概念和其他版本控制系统(诸如 Subversion 和 Perforce 等)相比拟,否则容易混淆每个操作的实际意义。Git 在保存和处理各种信息的时候,虽然操作起来的命令形式非常相近,但它与其他版本控制系统的做法颇为不同。理解这些差异将有助于你准确地使用 Git 提供的各种工具。

直接记录快照,而非差异比较

Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。这类系统 (CVS,Subversion,Perforce,Bazaar 等等)每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容,请看图 1-4。

Git详解之一:Git起步 图 1-4. 其他系统在每个版本中记录着各个文件的具体差异

Git 并不保存这些前后变化的差异数据。实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照 的索引。为提高性能,若文件没有变化,Git 不会再次保存,而只对上次保存的快照作一链接。Git 的工作方式就像图 1-5 所示。

Git详解之一:Git起步 图 1-5. Git 保存每次更新时的文件快照

这是 Git 同其他系统的重要区别。它完全颠覆了传统版本控制的套路,并对各个环节的实现方式作了新的设计。Git 更像是个小型的文件系统,但它同时还提供了许多以此为基础的超强工具,而不只是一个简单的 VCS。稍后在第三章讨论 Git 分支管理的时候,我们会再看看这样的设计究竟会带来哪些好处。

近乎所有操作都是本地执行

在 Git 中的绝大多数操作都只需要访问本地文件和资源,不用连网。但如果用 CVCS 的话,差不多所有操作都需要连接网络。因为 Git 在本地磁盘上就保存着所有当前项目的历史更新,所以处理起来速度飞快。

举个例子,如果要浏览项目的历史更新摘要,Git 不用跑到外面的服务器上去取数据回来,而直接从本地数据库读取后展示给你看。所以任何时候你都可以马上翻阅,无需等待。如果想要看当前版本的文件和一个月 前的版本之间有何差异,Git 会取出一个月前的快照和当前文件作一次差异运算,而不用请求远程服务器来做这件事,或是把老版本的文件拉到本地来作比较。

用 CVCS 的话,没有网络或者断开 VPN 你就无法做任何事情。但用 Git 的话,就算你在飞机或者火车上,都可以非常愉快地频繁提交更新,等到了有网络的时候再上传到远程仓库。同样,在回家的路上,不用连接 VPN 你也可以继续工作。换作其他版本控制系统,这么做几乎不可能,抑或非常麻烦。比如 Perforce,如果不连到服务器,几乎什么都做不了(译注:默认无法发出命令

p4 edit file 开始编辑文件,因为 Perforce 需要联网通知系统声明该文件正在被谁修订。但实际上手工修改文件权限可以绕过这个限制,只是完成后还是无法提交更新。);如果是 Subversion 或 CVS,虽然可以编辑文件,但无法提交更新,因为数据库在网络上。看上去好像这些都不是什么大问题,但实际体验过之后,你就会惊喜地发现,这其实是会带来很大不同的。

时刻保持数据完整性

在保存到 Git 之前,所有数据都要进行内容的校验和(checksum)计算,并将此结果作为数据的唯一标识和索引。换句话说,不可能在你修改了文件或目录之后,Git 一无所知。这项特性作为 Git 的设计哲学,建在整体架构的最底层。所以如果文件在传输时变得不完整,或者磁盘损坏导致文件数据缺失,Git 都能立即察觉。

Git 使用 SHA-1 算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个 SHA-1 哈希值,作为指纹字符串。该字串由 40 个十六进制字符(0-9 及 a-f)组成,看起来就像是: 124b9da6552252987aa493b52f8696cd6d3b00373

Git 的工作完全依赖于这类指纹字串,所以你会经常看到这样的哈希值。实际上,所有保存在 Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名。

多数操作仅添加数据

常用的 Git 操作大多仅仅是把数据添加到数据库。因为任何一种不可逆的操作,比如删除数据,都会使回退或重现历史版本变得困难重重。在别的 VCS 中,若还未提交更新,就有可能丢失或者混淆一些修改的内容,但在 Git 里,一旦提交快照之后就完全不用担心丢失数据,特别是养成定期推送到其他仓库的习惯的话。

这种高可靠性令我们的开发工作安心不少,尽管去做各种试验性的尝试好了,再怎样也不会弄丢数据。至于 Git 内部究竟是如何保存和恢复数据的,我们会在第九章讨论 Git 内部原理时再作详述。

文件的三种状态

好,现在请注意,接下来要讲的概念非常重要。对于任何一个文件,在 Git 内都只有三种状态:已提交(committed),已修改(modified)和已暂存(staged)。已提交表示该文件已经被安全地保存在本地数据库 中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。

由此我们看到 Git 管理项目时,文件流转的三个工作区域:Git 的工作目录,暂存区域,以及本地仓库。

Git详解之一:Git起步

图 1-6. 工作目录,暂存区域,以及本地仓库

每个项目都有一个 Git 目录(译注:如果

git clone 出来的话,就是其中

.git 的目录;如果

git clone --bare 的话,新建的目录本身就是 Git 目录。),它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。

从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。这些文件实际上都是从 Git 目录中的压缩对象数据库中提取出来的,接下来就可以在工作目录中对这些文件进行编辑。

所谓的暂存区域只不过是个简单的文件,一般都放在 Git 目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。

基本的 Git 工作流程如下:

  1. 在工作目录中修改某些文件。 2. 对修改后的文件进行快照,然后保存到暂存区域。 3. 提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中。

所以,我们可以从文件所处的位置来判断状态:如果是 Git 目录中保存着的特定版本文件,就属于已提交状态;如果作了修改并已放入暂存区域,就属于已暂存状态;如果自上次取出后,作了修改但还没有放到暂存区域,就 是已修改状态。到第二章的时候,我们会进一步了解其中细节,并学会如何根据文件状态实施后续操作,以及怎样跳过暂存直接提交。

1.4 安装 Git

是时候动手尝试下 Git 了,不过得先安装好它。有许多种安装方式,主要分为两种,一种是通过编译源代码来安装;另一种是使用为特定平台预编译好的安装包。

从源代码安装

若是条件允许,从源代码安装有很多好处,至少可以安装最新的版本。Git 的每个版本都在不断尝试改进用户体验,所以能通过源代码自己编译安装最新版本就再好不过了。有些 Linux 版本自带的安装包更新起来并不及时,所以除非你在用最新的 distro 或者 backports,那么从源代码安装其实该算是最佳选择。

Git 的工作需要调用 curl,zlib,openssl,expat,libiconv 等库的代码,所以需要先安装这些依赖工具。在有 yum 的系统上(比如 Fedora)或者有 apt-get 的系统上(比如 Debian 体系),可以用下面的命令安装: 1

2 3

4 5$ yum

install

curl-devel expat-devel gettext-devel \

openssl-devel zlib-devel

$ apt-get

install

libcurl4-gnutls-dev libexpat1-dev gettext \

libz-dev libssl-dev

之后,从下面的 Git 官方站点下载最新版本源代码:

1http:

//git-scm

.com

/download

然后编译并安装:

1

2 3

4 $

tar

-zxf git-1.7.2.2.

tar

.gz

$

cd

git-1.7.2.2 $

make

prefix=

/usr/local

all

$

sudo

make

prefix=

/usr/local

install

现在已经可以用

git 命令了,用

git 把 Git 项目仓库克隆到本地,以便日后随时更新:

1$ git clone git:

//git

.kernel.org

/pub/scm/git/git

.git

在 Linux 上安装

如果要在 Linux 上安装预编译好的 Git 二进制安装包,可以直接用系统提供的包管理工具。在 Fedora 上用 yum 安装: 1$ yum

install

git-core

在 Ubuntu 这类 Debian 体系的系统上,可以用 apt-get 安装:

1$ apt-get

install

git-core

在 Mac 上安装

在 Mac 上安装 Git 有两种方式。最容易的当属使用图形化的 Git 安装工具,界面如图 1-7,下载地址在: http://code.google.com/p/git-osx-installer

Git详解之一:Git起步 图 1-7. Git OS X 安装工具

另一种是通过 MacPorts (

http://www.macports.org ) 安装。如果已经装好了 MacPorts,用下面的命令安装 Git: 1$

sudo

port

install

git-core +svn +doc +bash_completion +gitweb

这种方式就不需要再自己安装依赖库了,Macports 会帮你搞定这些麻烦事。一般上面列出的安装选项已经够用,要是你想用 Git 连接 Subversion 的代码仓库,还可以加上 +svn 选项,具体将在第八章作介绍。(译注:还有一种是使用 homebrew(

https://[GitHub](http://blog.jobbole.com/6492/ "GitHub如何运作:时间并不决定一切").com/mxcl/homebrew ):

brew install git 。)

在 Windows 上安装

在 Windows 上安装 Git 同样轻松,有个叫做 msysGit 的项目提供了安装包,可以到 Google Code 的页面上下载 exe 安装文件并运行: 1http:

//code

.google.com

/p/msysgit

完成安装之后,就可以使用命令行的

git 工具(已经自带了 ssh 客户端)了,另外还有一个图形界面的 Git 项目管理工具。

1.5 初次运行 Git 前的配置

一般在新的系统上,我们都需要先配置下自己的 Git 工作环境。配置工作只需一次,以后升级时还会沿用现在的配置。当然,如果需要,你随时可以用相同的命令修改已有的配置。

Git 提供了一个叫做 git config 的工具(译注:实际是

git-config 命令,只不过可以通过

git 加一个名字来呼叫此命令。),专门用来配置或读取相应的工作环境变量。而正是由这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:

●/etc/gitconfig 文件:系统中对所有用户都普遍适用的配置。若使用

git config 时用

--system 选项,读写的就是这个文件。

●~/.gitconfig 文件:用户目录下的配置文件只适用于该用户。若使用

git config 时用

--global 选项,读写的就是这个文件。

●当前项目的 git 目录中的配置文件(也就是工作目录中的

.git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以

.git/config 里的配置会覆盖

/etc/gitconfig 中的同名变量。

在 Windows 系统上,Git 会找寻用户主目录下的

.gitconfig 文件。主目录即

$HOME 变量指定的目录,一般都是

C:\Documents and Settings\$USER 。此外,Git 还会尝试找寻

/etc/gitconfig 文件,只不过看当初 Git 装在什么目录,就以此作为根目录来定位。

用户信息

第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录: 1

2 $ git config --global user.name

"John Doe"

$ git config --global user.email johndoe@ example.com

如果用了

--global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉

--global 选项重新配置即可,新的设定保存在当前项目的

.git/config 文件里。

文本编辑器

接下来要设置的是默认使用的文本编辑器。Git 需要你输入一些额外消息的时候,会自动调用一个外部文本编辑器给你用。默认会使用操作系统指定的默认编辑器,一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置: 1$ git config --global core.editor emacs

差异分析工具

还有一个比较常用的是,在解决合并冲突时使用哪种差异分析工具。比如要改用 vimdiff 的话: 1$ git config --global merge.tool vimdiff

Git 可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合并工具的输出信息。当然,你也可以指定使用自己开发的工具,具体怎么做可以参阅第七章。

查看配置信息

要检查已有的配置信息,可以使用

git config --list 命令: 1

2 3

4 5

6 7

8 $ git config --list

user.name=Scott Chacon user.email=schacon@ gmail.com

color.status=auto color.branch=auto

color.interactive=auto color.

diff

=auto

...

有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如

/etc/gitconfig 和

~/.gitconfig ),不过最终 Git 实际采用的是最后一个。

也可以直接查阅某个环境变量的设定,只要把特定的名字跟在后面即可,像这样: 1$ git config user.name Scott Chacon

1.6 获取帮助

想了解 Git 的各式工具该怎么用,可以阅读它们的使用帮助,方法有三: 1

2 3

4 5

6 $ git help

$ git

--help

$

man

git-

比如,要学习 config 命令可以怎么用,运行:

1$ git help config

我们随时都可以浏览这些帮助信息而无需连网。不过,要是你觉得还不够,可以到 Frenode IRC 服务器(irc.freenode.net)上的

/#git 或

/#github 频道寻求他人帮助。这两个频道上总有着上百号人,大多都有着丰富的 git 知识,并且乐于助人。


1.7 小结

至此,你该对 Git 有了点基本认识,包括它和以前你使用的 CVCS 之间的差别。现在,在你的系统上应该已经装好了 Git,设置了自己的名字和电邮。接下来让我们继续学习 Git 的基础知识。

6 votes, average: 5.00 out of 56 votes, average: 5.00 out of 56 votes, average: 5.00 out of 56 votes, average: 5.00 out of 56 votes, average: 5.00 out of 5 (*6 个评分,平均: 5.00*)

Loading ... Loading ...

Java6.0_API_for_LDAP (2)

Posted on

Java6.0_API_for_LDAP (2)

Java6.0 API for LDAP**概述 从JDK5.0开始,对LDAP协议的数据访问操作就被集成在javax的扩展API包中,并随同JDK一并发布,这一章节,我们主要介绍API包中的类信息。 javax.naming.directory**包的结构 http://linliangyi2007.javaeye.com/upload/picture/pic/8744/0369fc37-7571-3409-9013-f036763eebdd.gif 常用API解析 javax.naming.directory.InitialDirContext**,初始化目录服务上下文类 该类是LDAP数据内容的操作工具类,通过该类可以执行绑定LDAP服务器、新增LDAP条目、获取条目实例、修改条目属性、删除条目和根据条件搜索条目等操作。常用方法说明如下: 初始化LDAP 目录服务上下文(相当于使用JDBC打开一个数据库链接)**

  • InitialDirContext(Hashtable<?,?> environment)

绑定/创建LDAP条目对象(相当于新增一个LDAP条目数据bind(Name

  • name, Object obj, Attributes attrs)
  • bind(String name, Object obj, Attributes attrs)
  • createSubcontext(Name name, Attributes attrs)
  • createSubcontext(String name, Attributes attrs)

获取条目实例(属性集)

  • getAttributes(Name name)
  • getAttributes(Name name, String[] attrIds)
  • getAttributes(String name)
  • getAttributes(String name, String[] attrIds)

修改条目属性

  • modifyAttributes(Name name, int mod_op, Attributes attrs)
  • modifyAttributes(Name name, ModificationItem[] mods)

modifyAttributes(String name, int mod_op, Attributes attrs)

  • modifyAttributes(String name, ModificationItem[] mods)

u 删除条目

  • destroySubcontext(Name name)
  • destroySubcontext(String name)

根据属性集搜索条目

  • search(Name name, Attributes matchingAttributes)
  • search(Name name, Attributes matchingAttributes, String[] attributesToReturn)
  • search(String name, Attributes matchingAttributes)
  • search(String name, Attributes matchingAttributes, String[] attributesToReturn)

u 根据过滤器搜索条目

  • search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons)
  • search(Name name, String filter, SearchControls cons)
  • search(String name, String filterExpr, Object[] filterArgs, SearchControls cons)
  • search(String name, String filter, SearchControls cons)

javax.naming.directory.BasicAttribute**,LDAP基本属性对象 该类用来表示LDAP条目中的单个属性对象。在目录服务中,每个属性名称是可以对应多个的属性值的。 构建属性对象**

  • BasicAttribute(String id)
  • BasicAttribute(String id, boolean ordered)
  • BasicAttribute(String id, Object value)
  • BasicAttribute(String id, Object value, boolean ordered)

添加属性值

  • add(int ix, Object attrVal),添加属性值到多值属性的指定位置
  • add(Object attrVal) , 追加属性值到多值属性尾部

判断属性值是否包含

  • contains(Object attrVal) , 多值属性中有一个值是匹配的,返回true

获取属性值

  • get(),取得属性值中的一个
  • get(int ix),从多值属性中的指定位置取值

获取属性ID

  • getID(),属性的ID就是属性名

删除属性值

  • remove(int ix),删除指定位置的属性值
  • remove(Object attrval),删除指定的属性值

javax.naming.directory.BasicAttributes**,LDAP实体的属性集 该类表示一个LDAP条目绑定的属性集合,在绝大多数情况下,一个LDAP条目存在多个属性。 构造属性集**

  • BasicAttributes()
  • BasicAttributes(boolean ignoreCase),属性ID是否大小写敏感,建议不要使用敏感
  • BasicAttributes(String attrID, Object val)
  • BasicAttributes(String attrID, Object val, boolean ignoreCase)

获取属性集中的单个属性对象

  • get(String attrID)

获取全部属性的枚举

  • getAll()

获取全部属性的ID枚举

  • getIDs()

u 添加新属性

  • put(Attribute attr)
  • put(String attrID, Object val)

u 移除指定属性

  • remove(String attrID)

javax.naming.directory.SearchControls , LDAP**目录服务搜索控制对象 该类负责控制LDAP搜索行为的范围、设定返回结果数上限,搜索耗时上限,指定结果所包括的属性集等。 设定搜索行为的范围**

  • setSearchScope(int scope)

u 设定返回结果数上限

  • setCountLimit(long limit)

u 设定搜索耗时上限

  • setTimeLimit(int ms) , 以毫秒为单位

u 指定结果所包括的属性集

  • setReturningAttributes(String[] attrs)

javax.naming.directory.SearchResult**, 表示.search() 方法的返回结果集中的一项。 SearchResult类是对LDAP条目属性集的封装。在search()操作中可能返回完整的条目属性,也可能是条目属性的一部分。 获取SearchResult封装的条目属性**

  • getAttributes()

以上只列举了LDAP操作API的常用部分,更多更详细的描述,请参考 Sun Java6.0 API DOC。 LDAP**操作代码样例 在这个章节中,我们将结合LDAP操作的代码实例了解API使用。 初始化LDAP 目录服务上下文** 该例子中,我们使用uid=linly,ou=People,dc=jsoso,dc=net这个账号,链接位于本机8389端口的LDAP服务器(ldap://localhost:8389),认证方式采用simple类型,即用户名/密码方式。

Java代码 复制代码

  1. private static void initialContext() throws NamingException{
  2. if(singleton == null){
  3. singleton = new LDAPConnection();
  4. //*
  5. /* 在实际编码中,这些环境变量应尽可能通过配置文件读取
  6. /*/
  7. //LDAP服务地址
  8. singleton.sLDAP_URL = "ldap://localhost:8389";
  9. //管理员账号
  10. singleton.sMANAGER_DN = "uid=linly,ou=People,dc=jsoso,dc=net";
  11. //管理员密码
  12. singleton.sMANAGER_PASSWORD = "coffee";
  13. //认证类型
  14. singleton.sAUTH_TYPE = "simple";
  15. //JNDI Context工厂类
  16. singleton.sCONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
  17. singleton.envProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, singleton.sCONTEXT_FACTORY);
  18. singleton.envProps.setProperty(Context.PROVIDER_URL, singleton.sLDAP_URL);
  19. singleton.envProps.setProperty(Context.SECURITY_AUTHENTICATION, singleton.sAUTH_TYPE);
  20. singleton.envProps.setProperty(Context.SECURITY_PRINCIPAL, singleton.sMANAGER_DN);
  21. singleton.envProps.setProperty(Context.SECURITY_CREDENTIALS, singleton.sMANAGER_PASSWORD);
  22. //*
  23. /* 绑定ldap服务器
  24. /*/
  25. singleton.dirCtx = new InitialDirContext(singleton.envProps);
  26. }
  27. }

    private static void initialContext() throws NamingException{

    if(singleton == null){

    singleton = new LDAPConnection();

    //*

    /* 在实际编码中,这些环境变量应尽可能通过配置文件读取

    /*/

    //LDAP服务地址

    singleton.sLDAP_URL = "ldap://localhost:8389";

    //管理员账号

    singleton.sMANAGER_DN = "uid=linly,ou=People,dc=jsoso,dc=net";

    //管理员密码

    singleton.sMANAGER_PASSWORD = "coffee";

    //认证类型

    singleton.sAUTH_TYPE = "simple";

    //JNDI Context工厂类

    singleton.sCONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";

 singleton.envProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, singleton.sCONTEXT_FACTORY);

 singleton.envProps.setProperty(Context.PROVIDER_URL, singleton.sLDAP_URL);

 singleton.envProps.setProperty(Context.SECURITY_AUTHENTICATION, singleton.sAUTH_TYPE);

 singleton.envProps.setProperty(Context.SECURITY_PRINCIPAL, singleton.sMANAGER_DN);

 singleton.envProps.setProperty(Context.SECURITY_CREDENTIALS, singleton.sMANAGER_PASSWORD);

 //*

  /* 绑定ldap服务器

  /*/

 singleton.dirCtx = new InitialDirContext(singleton.envProps);

}

}

通过一个Hashtable或者Properties对象为LDAP的Context设置参数,而后初始化InitialDirContext,即可绑定LDAP服务。这相当于JDBC中获取数据库的Connection对象。 绑定/创建LDAP条目对象 用户可以使用bind方法创建新的LDAP条目,下面的代码创建一个DN:"ou=Employee , dc=jsoso ,dc=net"的OrganizationUnit类LDAP条目如下:

Java代码 复制代码

  1. public boolean createOrganizationUnit(){
  2. String ldapGroupDN = "ou=Employee , dc=jsoso ,dc=net";
  3. try {
  4. //*
  5. /* 查找是否已经存在指定的OU条目
  6. /* 如果存在,则打印OU条目的属性信息
  7. /* 如果不存在,则程序会抛出NamingException异常,进入异常处理
  8. /*/
  9. Attributes attrs = dirContext.getAttributes(ldapGroupDN);
  10. System.out.println("Find the group , attributes list :");
  11. NamingEnumeration nEnum = attrs.getIDs();
  12. for( ; nEnum.hasMore() ; ){
  13. String attrID = nEnum.next();
  14. Attribute attr = (Attribute)attrs.get(attrID);
  15. System.out.println(attr.toString());
  16. }
  17. return false;
  18. } catch (NamingException e) {
  19. //*
  20. /* 没有找到对应的Group条目,新增Group条目
  21. /*/
  22. //创建objectclass属性
  23. Attribute objclass = new BasicAttribute("objectclass");
  24. objclass.add("top");
  25. objclass.add("organizationalunit");
  26. //创建cn属性
  27. Attribute cn = new BasicAttribute("ou", "Employee");
  28. //创建Attributes,并添加objectclass和cn属性
  29. Attributes attrs = new BasicAttributes();
  30. attrs.put(objclass);
  31. attrs.put(cn);
  32. //将属性绑定到新的条目上,创建该条目
  33. try {
  34. dirContext.bind(ldapGroupDN, null, attrs);
  35. System.out.println("Group created successful");
  36. return true;
  37. } catch (NamingException e1) {
  38. e1.printStackTrace();
  39. }
  40. }
  41. return false;
  42. }

    public boolean createOrganizationUnit(){

    String ldapGroupDN = "ou=Employee , dc=jsoso ,dc=net";

    try {

    //*

    /* 查找是否已经存在指定的OU条目

    /* 如果存在,则打印OU条目的属性信息

    /* 如果不存在,则程序会抛出NamingException异常,进入异常处理

    /*/

    Attributes attrs = dirContext.getAttributes(ldapGroupDN);

    System.out.println("Find the group , attributes list :");

    NamingEnumeration nEnum = attrs.getIDs();

    for( ; nEnum.hasMore() ; ){

    String attrID = nEnum.next();

    Attribute attr = (Attribute)attrs.get(attrID);

    System.out.println(attr.toString());

    }

    return false;

    } catch (NamingException e) {

    //*

    /* 没有找到对应的Group条目,新增Group条目

    /*/

    //创建objectclass属性

    Attribute objclass = new BasicAttribute("objectclass");

    objclass.add("top");

    objclass.add("organizationalunit");

    //创建cn属性

    Attribute cn = new BasicAttribute("ou", "Employee");

    //创建Attributes,并添加objectclass和cn属性

    Attributes attrs = new BasicAttributes();

    attrs.put(objclass);

    attrs.put(cn);

    //将属性绑定到新的条目上,创建该条目

    try {

    dirContext.bind(ldapGroupDN, null, attrs);

    System.out.println("Group created successful");

    return true;

    } catch (NamingException e1) {

    e1.printStackTrace();

    }

    }

    return false;

    }

或者使用createSubcontext方法创建亦可,以下例子我们新增一个inetorgperson类的LDAP条目:

Java代码 复制代码

  1. ///
  2. /* 创建LDAP用户条目
  3. /* @param user
  4. /* @return
  5. /*/
  6. public boolean createUser(LDAPUser user){
  7. if(user == null){
  8. return false;
  9. }
  10. if(user.getUserID() == null || user.getUserID().length() == 0
  11. || user.getFirstName() == null || user.getFirstName().length() == 0
  12. || user.getLastName() == null || user.getLastName().length() == 0
  13. || user.getCommomName() == null || user.getCommomName().length() == 0){
  14. return false;
  15. }
  16. //判断用户条目是否已经存在
  17. if(isUserexist(user.getDistinguishedName())){
  18. return true;
  19. }
  20. //*
  21. /* 新建条目属性集
  22. /*/
  23. Attributes attrs = new BasicAttributes();
  24. setBasicAttribute(attrs , "objectclass" , "top,person,organizationalPerson,inetorgperson");
  25. setBasicAttribute(attrs , "cn" , user.getCommomName());
  26. setBasicAttribute(attrs , "givenname" , user.getFirstName());
  27. setBasicAttribute(attrs , "sn" , user.getLastName());
  28. setBasicAttribute(attrs , "uid" , user.getUserID());
  29. setBasicAttribute(attrs , "userpassword" , user.getPassword());
  30. //添加用户条目节点
  31. try {
  32. dirContext.createSubcontext(user.getDistinguishedName(), attrs);
  33. System.out.println("Add User(" + user.getDistinguishedName() + ") ok.");
  34. return true;
  35. } catch (NamingException e) {
  36. e.printStackTrace();
  37. }
  38. return false;
  39. }

    ///

    /* 创建LDAP用户条目

    /* @param user

    /* @return

    /*/

    public boolean createUser(LDAPUser user){

    if(user == null){

    return false;

    }

if(user.getUserID() == null || user.getUserID().length() == 0

  || user.getFirstName() == null || user.getFirstName().length() == 0

  || user.getLastName() == null || user.getLastName().length() == 0

  || user.getCommomName() == null || user.getCommomName().length() == 0){

 return false;

}

//判断用户条目是否已经存在

if(isUserexist(user.getDistinguishedName())){

 return true;

}

//*

/* 新建条目属性集

/*/

Attributes attrs = new BasicAttributes();

setBasicAttribute(attrs , "objectclass" , "top,person,organizationalPerson,inetorgperson");

setBasicAttribute(attrs , "cn" , user.getCommomName());

setBasicAttribute(attrs , "givenname" , user.getFirstName());

setBasicAttribute(attrs , "sn" , user.getLastName());

setBasicAttribute(attrs , "uid" , user.getUserID());

setBasicAttribute(attrs , "userpassword" , user.getPassword());

//添加用户条目节点

try {

 dirContext.createSubcontext(user.getDistinguishedName(), attrs);

 System.out.println("Add User(" + user.getDistinguishedName() + ") ok.");

 return true;

} catch (NamingException e) {

 e.printStackTrace();

}

return false;

}

获取条目属性 下面一段代码获取entryDN参数指定条目中的属性集合,并打印到控制台

Java代码 复制代码

  1. ///
  2. /* 获取一个指定的LDAP Entry
  3. /* @param entryDN
  4. /*/
  5. public void find(String entryDN){
  6. try {
  7. Attributes attrs = dirContext.getAttributes(entryDN);
  8. if (attrs != null) {
  9. NamingEnumeration nEnum = attrs.getIDs();
  10. for( ; nEnum.hasMore() ; ){
  11. String attrID = nEnum.next();
  12. Attribute attr = (Attribute)attrs.get(attrID);
  13. System.out.println(attr.toString());
  14. }
  15. System.out.println();
  16. }else{
  17. System.out.println("No found binding.");
  18. }
  19. }catch(NamingException ne) {
  20. ne.printStackTrace();
  21. }
  22. }

    ///

    /* 获取一个指定的LDAP Entry

    /* @param entryDN

    /*/

    public void find(String entryDN){

    try {

    Attributes attrs = dirContext.getAttributes(entryDN);

    if (attrs != null) {

    NamingEnumeration nEnum = attrs.getIDs();

    for( ; nEnum.hasMore() ; ){

     String attrID = nEnum.next();
    
     Attribute attr = (Attribute)attrs.get(attrID);
    
     System.out.println(attr.toString());
    

    }

    System.out.println();

    }else{

    System.out.println("No found binding.");

    }

    }catch(NamingException ne) {

    ne.printStackTrace();

    }

    }

修改条目属性 修改DN=user.getDistinguishedName()的条目中的cn、givenname、sn和userpassword四个属性值。 (注:参数DirContext.REPLACE_ATTRIBUTE有另外两个常量:DirContext.ADD_ATTRIBUTE;DirContext.REMOVE_ATTRIBUTE,分别表示新增属性和删除属性。)

Java代码 复制代码

  1. ///
  2. /* 修改用户信息
  3. /* @param user
  4. /* @return
  5. /* @throws Exception
  6. /*/
  7. public boolean modifyUser(LDAPUser user) throws Exception {
  8. //用户对象为空
  9. if (user == null) {
  10. throw new Exception("No user information!n");
  11. }
  12. //检查uid
  13. String userDN = user.getDistinguishedName();
  14. if (userDN == null && userDN.length() == 0) {
  15. throw new NamingException("No userDN you specify!n");
  16. }
  17. //判断用户条目是否已经存在
  18. if(!isUserexist(userDN)){
  19. return false;
  20. }
  21. //设置属性
  22. Attributes attrs = new BasicAttributes();
  23. setBasicAttribute(attrs, "cn", user.getCommomName());
  24. setBasicAttribute(attrs, "givenname", user.getFirstName());
  25. setBasicAttribute(attrs, "sn", user.getLastName());
  26. setBasicAttribute(attrs, "userpassword", user.getPassword());
  27. //修改属性
  28. try{
  29. dirContext.modifyAttributes(user.getDistinguishedName(),DirContext.REPLACE_ATTRIBUTE, attrs);
  30. System.out.println("User(" + user.getDistinguishedName() + ") information modified.n");
  31. return true;
  32. }catch(NamingException ne){
  33. ne.printStackTrace();
  34. }
  35. return false;
  36. }

    ///

    /* 修改用户信息

    /* @param user

    /* @return

    /* @throws Exception

    /*/

    public boolean modifyUser(LDAPUser user) throws Exception {

    //用户对象为空

    if (user == null) {

    throw new Exception("No user information!n");

    }

//检查uid

String userDN = user.getDistinguishedName();

if (userDN == null && userDN.length() == 0) {

 throw new NamingException("No userDN you specify!n");

}

//判断用户条目是否已经存在

if(!isUserexist(userDN)){

 return false;

}

//设置属性

Attributes attrs = new BasicAttributes();

setBasicAttribute(attrs, "cn", user.getCommomName());

setBasicAttribute(attrs, "givenname", user.getFirstName());

setBasicAttribute(attrs, "sn", user.getLastName());

setBasicAttribute(attrs, "userpassword", user.getPassword());

//修改属性

try{

 dirContext.modifyAttributes(user.getDistinguishedName(),DirContext.REPLACE_ATTRIBUTE, attrs);

 System.out.println("User(" + user.getDistinguishedName() + ") information modified.n");

 return true;

}catch(NamingException ne){

 ne.printStackTrace();

}

return false;

}

删除条目 删除DN= userDN条目

Java代码 复制代码

  1. ///
  2. /* 删除用户
  3. /* @param userDN
  4. /* @return
  5. /*/
  6. public boolean deleteUser(String userDN) {
  7. if(!isUserexist(userDN)) {
  8. return true;
  9. }
  10. try {
  11. dirContext.destroySubcontext(userDN);
  12. System.out.println("User( " + userDN + ") deleted.n");
  13. return true;
  14. } catch (NamingException e) {
  15. e.printStackTrace();
  16. }
  17. return false;
  18. }

    ///

    /* 删除用户

    /* @param userDN

    /* @return

    /*/

    public boolean deleteUser(String userDN) {

    if(!isUserexist(userDN)) {

    return true;

    }

    try {

    dirContext.destroySubcontext(userDN);

    System.out.println("User( " + userDN + ") deleted.n");

    return true;

    } catch (NamingException e) {

    e.printStackTrace();

    }

    return false;

    }

根据属性集搜索条目 根据属性集matchingAttributes中的匹配值,在上下文DN= "ou=People,dc=jsoso ,dc=net"中搜索它的所有子树中的匹配条目。 (注:SearchControls的SCOPE参数详见SearchControls SCOPE补充说明)

Java代码 复制代码

  1. ///
  2. /* 通过属性搜索LDAP范例
  3. /* @return
  4. /*/
  5. public void searchByAttribute(Attributes matchingAttributes){
  6. String baseDN = "ou=People,dc=jsoso ,dc=net";
  7. SearchControls cons = new SearchControls();
  8. cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
  9. try {
  10. Name baseName = new LdapName(baseDN);
  11. NamingEnumeration ne = dirContext.search(baseName, matchingAttributes);
  12. SearchResult entry = null;
  13. for(;ne.hasMore();){
  14. entry = ne.next();
  15. showEntry(entry);
  16. }
  17. } catch (NamingException e) {
  18. e.printStackTrace();
  19. }
  20. }

       //*/*
    

    /* 通过属性搜索LDAP范例

    /* @return

    /*/

    public void searchByAttribute(Attributes matchingAttributes){

    String baseDN = "ou=People,dc=jsoso ,dc=net";

    SearchControls cons = new SearchControls();

    cons.setSearchScope(SearchControls.SUBTREE_SCOPE);

    try {

    Name baseName = new LdapName(baseDN);

    NamingEnumeration ne = dirContext.search(baseName, matchingAttributes);

    SearchResult entry = null;

    for(;ne.hasMore();){

    entry = ne.next();

    showEntry(entry);

    }

    } catch (NamingException e) {

    e.printStackTrace();

    }

    }

根据过滤器搜索条目 根据过滤器条件,在上下文DN = "ou=People,dc=jsoso ,dc=net"中,搜索它的所有子树中的匹配条目。 (注:过滤器filter的相关语法详见LDAP filter语法补充说明)

Java代码 复制代码

  1. ///
  2. /* 通过过滤器搜索LDAP范例
  3. /* @return
  4. /*/
  5. public void searchByFilter(String filter){
  6. String baseDN = "ou=People,dc=jsoso ,dc=net";
  7. SearchControls cons = new SearchControls();
  8. cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
  9. try {
  10. NamingEnumeration ne = dirContext.search(baseDN, filter , cons);
  11. SearchResult entry = null;
  12. for(;ne.hasMore();){
  13. entry = ne.next();
  14. showEntry(entry);
  15. }
  16. } catch (NamingException e) {
  17. e.printStackTrace();
  18. }
  19. }

    ///

    /* 通过过滤器搜索LDAP范例

    /* @return

    /*/

    public void searchByFilter(String filter){

    String baseDN = "ou=People,dc=jsoso ,dc=net";

    SearchControls cons = new SearchControls();

    cons.setSearchScope(SearchControls.SUBTREE_SCOPE);

    try {

    NamingEnumeration ne = dirContext.search(baseDN, filter , cons);

    SearchResult entry = null;

    for(;ne.hasMore();){

    entry = ne.next();

    showEntry(entry);

    }

    } catch (NamingException e) {

    e.printStackTrace();

    }

    }

相关补充 javax.naming.Name**对象说明 在API中,我们常常见到对LDAP上下文条目有两种参数形式,一种是大家都熟悉的String参数,如: String baseDN = "ou=People,dc=jsoso ,dc=net"; 另一种是使用javax.naming.Name类型的参数,那么Name类和String有什么区别呢? 简单的说,Name是对String类DN的封装,它把一个完整的DN字窜分解成了RDN的list。这个list的顺序刚好和String相反。就拿"ou=People,dc=jsoso ,dc=net"为例,Name中的RDN顺序是[0]=net,[1]=jsoso,[2]=People。这样做的好处是更方便对Name进行操作,比如取其前缀或者后缀。 SearchControls SCOPE**补充说明 http://linliangyi2007.javaeye.com/upload/picture/pic/8746/655c33eb-9277-3740-834c-63a17e48085e.gif LDAP filter**语法补充说明 filter的运算符 http://linliangyi2007.javaeye.com/upload/picture/pic/8734/d1a62a84-b638-32d7-9d4f-f6829ba54dbf.gif filter布尔运算符 http://linliangyi2007.javaeye.com/upload/picture/pic/8736/a151eb07-48b5-3d42-a191-67ea6f694aa8.gif 搜索过滤器示例**

  • 下列过滤器将搜索包含一个或多个 manager 属性值的条目。这也称为存在搜索: manager=/*
  • 下列过滤器将搜索包含通用名 Ray Kultgen 的条目。这也称为等价搜索:cn=Ray Kultgen
  • 下列过滤器返回所有不包含通用名 Ray Kultgen 的条目:(!(cn=Ray Kultgen))
  • 下列过滤器返回的所有条目中都有包含子字符串 X.500 的说明属性:description=/X.500/
  • 下列过滤器返回所有组织单元为 Marketing 且说明字段中不包含子字符串 X.500 的条目: (&(ou=Marketing)(!(description=/X.500/)))
  • 下列过滤器返回所有组织单元为 Marketing 且 manager 为 Julie Fulmer 或 Cindy Zwaska 的条目: (&(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))
  • 下列过滤器返回所有不代表人员的条目: (!(objectClass=person))
  • 下列过滤器返回所有不代表人员且通用名近似于 printer3b 的条目:(&(!(objectClass=person))(cn~=printer3b))

Java6.0_API_for_LDAP

Posted on

Java6.0_API_for_LDAP

Java6.0 API for LDAP概述 从JDK5.0开始,对LDAP协议的数据访问操作就被集成在javax的扩展API包中,并随同JDK一并发布,这一章节,我们主要介绍API包中的类信息。 javax.naming.directory**包的结构 http://linliangyi2007.javaeye.com/upload/picture/pic/8744/0369fc37-7571-3409-9013-f036763eebdd.gif 常用API解析 javax.naming.directory.InitialDirContext**,初始化目录服务上下文类 该类是LDAP数据内容的操作工具类,通过该类可以执行绑定LDAP服务器、新增LDAP条目、获取条目实例、修改条目属性、删除条目和根据条件搜索条目等操作。常用方法说明如下: 初始化LDAP 目录服务上下文(相当于使用JDBC打开一个数据库链接)

  • InitialDirContext(Hashtable<?,?> environment)

绑定/创建LDAP条目对象(相当于新增一个LDAP条目数据bind(Name

  • name, Object obj, Attributes attrs)
  • bind(String name, Object obj, Attributes attrs)
  • createSubcontext(Name name, Attributes attrs)
  • createSubcontext(String name, Attributes attrs)

获取条目实例(属性集)

  • getAttributes(Name name)
  • getAttributes(Name name, String[] attrIds)
  • getAttributes(String name)
  • getAttributes(String name, String[] attrIds)

修改条目属性

  • modifyAttributes(Name name, int mod_op, Attributes attrs)
  • modifyAttributes(Name name, ModificationItem[] mods)

modifyAttributes(String name, int mod_op, Attributes attrs)

  • modifyAttributes(String name, ModificationItem[] mods)

u 删除条目

  • destroySubcontext(Name name)
  • destroySubcontext(String name)

根据属性集搜索条目

  • search(Name name, Attributes matchingAttributes)
  • search(Name name, Attributes matchingAttributes, String[] attributesToReturn)
  • search(String name, Attributes matchingAttributes)
  • search(String name, Attributes matchingAttributes, String[] attributesToReturn)

u 根据过滤器搜索条目

  • search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons)
  • search(Name name, String filter, SearchControls cons)
  • search(String name, String filterExpr, Object[] filterArgs, SearchControls cons)
  • search(String name, String filter, SearchControls cons)

javax.naming.directory.BasicAttribute**,LDAP基本属性对象 该类用来表示LDAP条目中的单个属性对象。在目录服务中,每个属性名称是可以对应多个的属性值的。 构建属性对象**

  • BasicAttribute(String id)
  • BasicAttribute(String id, boolean ordered)
  • BasicAttribute(String id, Object value)
  • BasicAttribute(String id, Object value, boolean ordered)

添加属性值

  • add(int ix, Object attrVal),添加属性值到多值属性的指定位置
  • add(Object attrVal) , 追加属性值到多值属性尾部

判断属性值是否包含

  • contains(Object attrVal) , 多值属性中有一个值是匹配的,返回true

获取属性值

  • get(),取得属性值中的一个
  • get(int ix),从多值属性中的指定位置取值

获取属性ID

  • getID(),属性的ID就是属性名

删除属性值

  • remove(int ix),删除指定位置的属性值
  • remove(Object attrval),删除指定的属性值

javax.naming.directory.BasicAttributes**,LDAP实体的属性集 该类表示一个LDAP条目绑定的属性集合,在绝大多数情况下,一个LDAP条目存在多个属性。 构造属性集**

  • BasicAttributes()
  • BasicAttributes(boolean ignoreCase),属性ID是否大小写敏感,建议不要使用敏感
  • BasicAttributes(String attrID, Object val)
  • BasicAttributes(String attrID, Object val, boolean ignoreCase)

获取属性集中的单个属性对象

  • get(String attrID)

获取全部属性的枚举

  • getAll()

获取全部属性的ID枚举

  • getIDs()

u 添加新属性

  • put(Attribute attr)
  • put(String attrID, Object val)

u 移除指定属性

  • remove(String attrID)

javax.naming.directory.SearchControls , LDAP**目录服务搜索控制对象 该类负责控制LDAP搜索行为的范围、设定返回结果数上限,搜索耗时上限,指定结果所包括的属性集等。 设定搜索行为的范围**

  • setSearchScope(int scope)

u 设定返回结果数上限

  • setCountLimit(long limit)

u 设定搜索耗时上限

  • setTimeLimit(int ms) , 以毫秒为单位

u 指定结果所包括的属性集

  • setReturningAttributes(String[] attrs)

javax.naming.directory.SearchResult**, 表示.search() 方法的返回结果集中的一项。 SearchResult类是对LDAP条目属性集的封装。在search()操作中可能返回完整的条目属性,也可能是条目属性的一部分。 获取SearchResult封装的条目属性**

  • getAttributes()

以上只列举了LDAP操作API的常用部分,更多更详细的描述,请参考 Sun Java6.0 API DOC。 LDAP**操作代码样例 在这个章节中,我们将结合LDAP操作的代码实例了解API使用。 初始化LDAP 目录服务上下文** 该例子中,我们使用uid=linly,ou=People,dc=jsoso,dc=net这个账号,链接位于本机8389端口的LDAP服务器(ldap://localhost:8389),认证方式采用simple类型,即用户名/密码方式。

Java代码 复制代码

  1. private static void initialContext() throws NamingException{
  2. if(singleton == null){
  3. singleton = new LDAPConnection();
  4. //*
  5. /* 在实际编码中,这些环境变量应尽可能通过配置文件读取
  6. /*/
  7. //LDAP服务地址
  8. singleton.sLDAP_URL = "ldap://localhost:8389";
  9. //管理员账号
  10. singleton.sMANAGER_DN = "uid=linly,ou=People,dc=jsoso,dc=net";
  11. //管理员密码
  12. singleton.sMANAGER_PASSWORD = "coffee";
  13. //认证类型
  14. singleton.sAUTH_TYPE = "simple";
  15. //JNDI Context工厂类
  16. singleton.sCONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
  17. singleton.envProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, singleton.sCONTEXT_FACTORY);
  18. singleton.envProps.setProperty(Context.PROVIDER_URL, singleton.sLDAP_URL);
  19. singleton.envProps.setProperty(Context.SECURITY_AUTHENTICATION, singleton.sAUTH_TYPE);
  20. singleton.envProps.setProperty(Context.SECURITY_PRINCIPAL, singleton.sMANAGER_DN);
  21. singleton.envProps.setProperty(Context.SECURITY_CREDENTIALS, singleton.sMANAGER_PASSWORD);
  22. //*
  23. /* 绑定ldap服务器
  24. /*/
  25. singleton.dirCtx = new InitialDirContext(singleton.envProps);
  26. }
  27. }

    private static void initialContext() throws NamingException{

    if(singleton == null){

    singleton = new LDAPConnection();

    //*

    /* 在实际编码中,这些环境变量应尽可能通过配置文件读取

    /*/

    //LDAP服务地址

    singleton.sLDAP_URL = "ldap://localhost:8389";

    //管理员账号

    singleton.sMANAGER_DN = "uid=linly,ou=People,dc=jsoso,dc=net";

    //管理员密码

    singleton.sMANAGER_PASSWORD = "coffee";

    //认证类型

    singleton.sAUTH_TYPE = "simple";

    //JNDI Context工厂类

    singleton.sCONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";

 singleton.envProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, singleton.sCONTEXT_FACTORY);

 singleton.envProps.setProperty(Context.PROVIDER_URL, singleton.sLDAP_URL);

 singleton.envProps.setProperty(Context.SECURITY_AUTHENTICATION, singleton.sAUTH_TYPE);

 singleton.envProps.setProperty(Context.SECURITY_PRINCIPAL, singleton.sMANAGER_DN);

 singleton.envProps.setProperty(Context.SECURITY_CREDENTIALS, singleton.sMANAGER_PASSWORD);

 //*

  /* 绑定ldap服务器

  /*/

 singleton.dirCtx = new InitialDirContext(singleton.envProps);

}

}

通过一个Hashtable或者Properties对象为LDAP的Context设置参数,而后初始化InitialDirContext,即可绑定LDAP服务。这相当于JDBC中获取数据库的Connection对象。 绑定/创建LDAP条目对象 用户可以使用bind方法创建新的LDAP条目,下面的代码创建一个DN:"ou=Employee , dc=jsoso ,dc=net"的OrganizationUnit类LDAP条目如下:

Java代码 复制代码

  1. public boolean createOrganizationUnit(){
  2. String ldapGroupDN = "ou=Employee , dc=jsoso ,dc=net";
  3. try {
  4. //*
  5. /* 查找是否已经存在指定的OU条目
  6. /* 如果存在,则打印OU条目的属性信息
  7. /* 如果不存在,则程序会抛出NamingException异常,进入异常处理
  8. /*/
  9. Attributes attrs = dirContext.getAttributes(ldapGroupDN);
  10. System.out.println("Find the group , attributes list :");
  11. NamingEnumeration nEnum = attrs.getIDs();
  12. for( ; nEnum.hasMore() ; ){
  13. String attrID = nEnum.next();
  14. Attribute attr = (Attribute)attrs.get(attrID);
  15. System.out.println(attr.toString());
  16. }
  17. return false;
  18. } catch (NamingException e) {
  19. //*
  20. /* 没有找到对应的Group条目,新增Group条目
  21. /*/
  22. //创建objectclass属性
  23. Attribute objclass = new BasicAttribute("objectclass");
  24. objclass.add("top");
  25. objclass.add("organizationalunit");
  26. //创建cn属性
  27. Attribute cn = new BasicAttribute("ou", "Employee");
  28. //创建Attributes,并添加objectclass和cn属性
  29. Attributes attrs = new BasicAttributes();
  30. attrs.put(objclass);
  31. attrs.put(cn);
  32. //将属性绑定到新的条目上,创建该条目
  33. try {
  34. dirContext.bind(ldapGroupDN, null, attrs);
  35. System.out.println("Group created successful");
  36. return true;
  37. } catch (NamingException e1) {
  38. e1.printStackTrace();
  39. }
  40. }
  41. return false;
  42. }

    public boolean createOrganizationUnit(){

    String ldapGroupDN = "ou=Employee , dc=jsoso ,dc=net";

    try {

    //*

    /* 查找是否已经存在指定的OU条目

    /* 如果存在,则打印OU条目的属性信息

    /* 如果不存在,则程序会抛出NamingException异常,进入异常处理

    /*/

    Attributes attrs = dirContext.getAttributes(ldapGroupDN);

    System.out.println("Find the group , attributes list :");

    NamingEnumeration nEnum = attrs.getIDs();

    for( ; nEnum.hasMore() ; ){

    String attrID = nEnum.next();

    Attribute attr = (Attribute)attrs.get(attrID);

    System.out.println(attr.toString());

    }

    return false;

    } catch (NamingException e) {

    //*

    /* 没有找到对应的Group条目,新增Group条目

    /*/

    //创建objectclass属性

    Attribute objclass = new BasicAttribute("objectclass");

    objclass.add("top");

    objclass.add("organizationalunit");

    //创建cn属性

    Attribute cn = new BasicAttribute("ou", "Employee");

    //创建Attributes,并添加objectclass和cn属性

    Attributes attrs = new BasicAttributes();

    attrs.put(objclass);

    attrs.put(cn);

    //将属性绑定到新的条目上,创建该条目

    try {

    dirContext.bind(ldapGroupDN, null, attrs);

    System.out.println("Group created successful");

    return true;

    } catch (NamingException e1) {

    e1.printStackTrace();

    }

    }

    return false;

    }

或者使用createSubcontext方法创建亦可,以下例子我们新增一个inetorgperson类的LDAP条目:

Java代码 复制代码

  1. ///
  2. /* 创建LDAP用户条目
  3. /* @param user
  4. /* @return
  5. /*/
  6. public boolean createUser(LDAPUser user){
  7. if(user == null){
  8. return false;
  9. }
  10. if(user.getUserID() == null || user.getUserID().length() == 0
  11. || user.getFirstName() == null || user.getFirstName().length() == 0
  12. || user.getLastName() == null || user.getLastName().length() == 0
  13. || user.getCommomName() == null || user.getCommomName().length() == 0){
  14. return false;
  15. }
  16. //判断用户条目是否已经存在
  17. if(isUserexist(user.getDistinguishedName())){
  18. return true;
  19. }
  20. //*
  21. /* 新建条目属性集
  22. /*/
  23. Attributes attrs = new BasicAttributes();
  24. setBasicAttribute(attrs , "objectclass" , "top,person,organizationalPerson,inetorgperson");
  25. setBasicAttribute(attrs , "cn" , user.getCommomName());
  26. setBasicAttribute(attrs , "givenname" , user.getFirstName());
  27. setBasicAttribute(attrs , "sn" , user.getLastName());
  28. setBasicAttribute(attrs , "uid" , user.getUserID());
  29. setBasicAttribute(attrs , "userpassword" , user.getPassword());
  30. //添加用户条目节点
  31. try {
  32. dirContext.createSubcontext(user.getDistinguishedName(), attrs);
  33. System.out.println("Add User(" + user.getDistinguishedName() + ") ok.");
  34. return true;
  35. } catch (NamingException e) {
  36. e.printStackTrace();
  37. }
  38. return false;
  39. }

    ///

    /* 创建LDAP用户条目

    /* @param user

    /* @return

    /*/

    public boolean createUser(LDAPUser user){

    if(user == null){

    return false;

    }

if(user.getUserID() == null || user.getUserID().length() == 0

  || user.getFirstName() == null || user.getFirstName().length() == 0

  || user.getLastName() == null || user.getLastName().length() == 0

  || user.getCommomName() == null || user.getCommomName().length() == 0){

 return false;

}

//判断用户条目是否已经存在

if(isUserexist(user.getDistinguishedName())){

 return true;

}

//*

/* 新建条目属性集

/*/

Attributes attrs = new BasicAttributes();

setBasicAttribute(attrs , "objectclass" , "top,person,organizationalPerson,inetorgperson");

setBasicAttribute(attrs , "cn" , user.getCommomName());

setBasicAttribute(attrs , "givenname" , user.getFirstName());

setBasicAttribute(attrs , "sn" , user.getLastName());

setBasicAttribute(attrs , "uid" , user.getUserID());

setBasicAttribute(attrs , "userpassword" , user.getPassword());

//添加用户条目节点

try {

 dirContext.createSubcontext(user.getDistinguishedName(), attrs);

 System.out.println("Add User(" + user.getDistinguishedName() + ") ok.");

 return true;

} catch (NamingException e) {

 e.printStackTrace();

}

return false;

}

获取条目属性 下面一段代码获取entryDN参数指定条目中的属性集合,并打印到控制台

Java代码 复制代码

  1. ///
  2. /* 获取一个指定的LDAP Entry
  3. /* @param entryDN
  4. /*/
  5. public void find(String entryDN){
  6. try {
  7. Attributes attrs = dirContext.getAttributes(entryDN);
  8. if (attrs != null) {
  9. NamingEnumeration nEnum = attrs.getIDs();
  10. for( ; nEnum.hasMore() ; ){
  11. String attrID = nEnum.next();
  12. Attribute attr = (Attribute)attrs.get(attrID);
  13. System.out.println(attr.toString());
  14. }
  15. System.out.println();
  16. }else{
  17. System.out.println("No found binding.");
  18. }
  19. }catch(NamingException ne) {
  20. ne.printStackTrace();
  21. }
  22. }

    ///

    /* 获取一个指定的LDAP Entry

    /* @param entryDN

    /*/

    public void find(String entryDN){

    try {

    Attributes attrs = dirContext.getAttributes(entryDN);

    if (attrs != null) {

    NamingEnumeration nEnum = attrs.getIDs();

    for( ; nEnum.hasMore() ; ){

     String attrID = nEnum.next();
    
     Attribute attr = (Attribute)attrs.get(attrID);
    
     System.out.println(attr.toString());
    

    }

    System.out.println();

    }else{

    System.out.println("No found binding.");

    }

    }catch(NamingException ne) {

    ne.printStackTrace();

    }

    }

修改条目属性 修改DN=user.getDistinguishedName()的条目中的cn、givenname、sn和userpassword四个属性值。 (注:参数DirContext.REPLACE_ATTRIBUTE有另外两个常量:DirContext.ADD_ATTRIBUTE;DirContext.REMOVE_ATTRIBUTE,分别表示新增属性和删除属性。)

Java代码 复制代码

  1. ///
  2. /* 修改用户信息
  3. /* @param user
  4. /* @return
  5. /* @throws Exception
  6. /*/
  7. public boolean modifyUser(LDAPUser user) throws Exception {
  8. //用户对象为空
  9. if (user == null) {
  10. throw new Exception("No user information!n");
  11. }
  12. //检查uid
  13. String userDN = user.getDistinguishedName();
  14. if (userDN == null && userDN.length() == 0) {
  15. throw new NamingException("No userDN you specify!n");
  16. }
  17. //判断用户条目是否已经存在
  18. if(!isUserexist(userDN)){
  19. return false;
  20. }
  21. //设置属性
  22. Attributes attrs = new BasicAttributes();
  23. setBasicAttribute(attrs, "cn", user.getCommomName());
  24. setBasicAttribute(attrs, "givenname", user.getFirstName());
  25. setBasicAttribute(attrs, "sn", user.getLastName());
  26. setBasicAttribute(attrs, "userpassword", user.getPassword());
  27. //修改属性
  28. try{
  29. dirContext.modifyAttributes(user.getDistinguishedName(),DirContext.REPLACE_ATTRIBUTE, attrs);
  30. System.out.println("User(" + user.getDistinguishedName() + ") information modified.n");
  31. return true;
  32. }catch(NamingException ne){
  33. ne.printStackTrace();
  34. }
  35. return false;
  36. }

    ///

    /* 修改用户信息

    /* @param user

    /* @return

    /* @throws Exception

    /*/

    public boolean modifyUser(LDAPUser user) throws Exception {

    //用户对象为空

    if (user == null) {

    throw new Exception("No user information!n");

    }

//检查uid

String userDN = user.getDistinguishedName();

if (userDN == null && userDN.length() == 0) {

 throw new NamingException("No userDN you specify!n");

}

//判断用户条目是否已经存在

if(!isUserexist(userDN)){

 return false;

}

//设置属性

Attributes attrs = new BasicAttributes();

setBasicAttribute(attrs, "cn", user.getCommomName());

setBasicAttribute(attrs, "givenname", user.getFirstName());

setBasicAttribute(attrs, "sn", user.getLastName());

setBasicAttribute(attrs, "userpassword", user.getPassword());

//修改属性

try{

 dirContext.modifyAttributes(user.getDistinguishedName(),DirContext.REPLACE_ATTRIBUTE, attrs);

 System.out.println("User(" + user.getDistinguishedName() + ") information modified.n");

 return true;

}catch(NamingException ne){

 ne.printStackTrace();

}

return false;

}

删除条目 删除DN= userDN条目

Java代码 复制代码

  1. ///
  2. /* 删除用户
  3. /* @param userDN
  4. /* @return
  5. /*/
  6. public boolean deleteUser(String userDN) {
  7. if(!isUserexist(userDN)) {
  8. return true;
  9. }
  10. try {
  11. dirContext.destroySubcontext(userDN);
  12. System.out.println("User( " + userDN + ") deleted.n");
  13. return true;
  14. } catch (NamingException e) {
  15. e.printStackTrace();
  16. }
  17. return false;
  18. }

    ///

    /* 删除用户

    /* @param userDN

    /* @return

    /*/

    public boolean deleteUser(String userDN) {

    if(!isUserexist(userDN)) {

    return true;

    }

    try {

    dirContext.destroySubcontext(userDN);

    System.out.println("User( " + userDN + ") deleted.n");

    return true;

    } catch (NamingException e) {

    e.printStackTrace();

    }

    return false;

    }

根据属性集搜索条目 根据属性集matchingAttributes中的匹配值,在上下文DN= "ou=People,dc=jsoso ,dc=net"中搜索它的所有子树中的匹配条目。 (注:SearchControls的SCOPE参数详见SearchControls SCOPE补充说明)

Java代码 复制代码

  1. ///
  2. /* 通过属性搜索LDAP范例
  3. /* @return
  4. /*/
  5. public void searchByAttribute(Attributes matchingAttributes){
  6. String baseDN = "ou=People,dc=jsoso ,dc=net";
  7. SearchControls cons = new SearchControls();
  8. cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
  9. try {
  10. Name baseName = new LdapName(baseDN);
  11. NamingEnumeration ne = dirContext.search(baseName, matchingAttributes);
  12. SearchResult entry = null;
  13. for(;ne.hasMore();){
  14. entry = ne.next();
  15. showEntry(entry);
  16. }
  17. } catch (NamingException e) {
  18. e.printStackTrace();
  19. }
  20. }

       //*/*
    

    /* 通过属性搜索LDAP范例

    /* @return

    /*/

    public void searchByAttribute(Attributes matchingAttributes){

    String baseDN = "ou=People,dc=jsoso ,dc=net";

    SearchControls cons = new SearchControls();

    cons.setSearchScope(SearchControls.SUBTREE_SCOPE);

    try {

    Name baseName = new LdapName(baseDN);

    NamingEnumeration ne = dirContext.search(baseName, matchingAttributes);

    SearchResult entry = null;

    for(;ne.hasMore();){

    entry = ne.next();

    showEntry(entry);

    }

    } catch (NamingException e) {

    e.printStackTrace();

    }

    }

根据过滤器搜索条目 根据过滤器条件,在上下文DN = "ou=People,dc=jsoso ,dc=net"中,搜索它的所有子树中的匹配条目。 (注:过滤器filter的相关语法详见LDAP filter语法补充说明)

Java代码 复制代码

  1. ///
  2. /* 通过过滤器搜索LDAP范例
  3. /* @return
  4. /*/
  5. public void searchByFilter(String filter){
  6. String baseDN = "ou=People,dc=jsoso ,dc=net";
  7. SearchControls cons = new SearchControls();
  8. cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
  9. try {
  10. NamingEnumeration ne = dirContext.search(baseDN, filter , cons);
  11. SearchResult entry = null;
  12. for(;ne.hasMore();){
  13. entry = ne.next();
  14. showEntry(entry);
  15. }
  16. } catch (NamingException e) {
  17. e.printStackTrace();
  18. }
  19. }

    ///

    /* 通过过滤器搜索LDAP范例

    /* @return

    /*/

    public void searchByFilter(String filter){

    String baseDN = "ou=People,dc=jsoso ,dc=net";

    SearchControls cons = new SearchControls();

    cons.setSearchScope(SearchControls.SUBTREE_SCOPE);

    try {

    NamingEnumeration ne = dirContext.search(baseDN, filter , cons);

    SearchResult entry = null;

    for(;ne.hasMore();){

    entry = ne.next();

    showEntry(entry);

    }

    } catch (NamingException e) {

    e.printStackTrace();

    }

    }

相关补充 javax.naming.Name**对象说明 在API中,我们常常见到对LDAP上下文条目有两种参数形式,一种是大家都熟悉的String参数,如: String baseDN = "ou=People,dc=jsoso ,dc=net"; 另一种是使用javax.naming.Name类型的参数,那么Name类和String有什么区别呢? 简单的说,Name是对String类DN的封装,它把一个完整的DN字窜分解成了RDN的list。这个list的顺序刚好和String相反。就拿"ou=People,dc=jsoso ,dc=net"为例,Name中的RDN顺序是[0]=net,[1]=jsoso,[2]=People。这样做的好处是更方便对Name进行操作,比如取其前缀或者后缀。 SearchControls SCOPE**补充说明 http://linliangyi2007.javaeye.com/upload/picture/pic/8746/655c33eb-9277-3740-834c-63a17e48085e.gif LDAP filter**语法补充说明 filter的运算符 http://linliangyi2007.javaeye.com/upload/picture/pic/8734/d1a62a84-b638-32d7-9d4f-f6829ba54dbf.gif filter布尔运算符 http://linliangyi2007.javaeye.com/upload/picture/pic/8736/a151eb07-48b5-3d42-a191-67ea6f694aa8.gif 搜索过滤器示例**

  • 下列过滤器将搜索包含一个或多个 manager 属性值的条目。这也称为存在搜索: manager=/*
  • 下列过滤器将搜索包含通用名 Ray Kultgen 的条目。这也称为等价搜索:cn=Ray Kultgen
  • 下列过滤器返回所有不包含通用名 Ray Kultgen 的条目:(!(cn=Ray Kultgen))
  • 下列过滤器返回的所有条目中都有包含子字符串 X.500 的说明属性:description=/X.500/
  • 下列过滤器返回所有组织单元为 Marketing 且说明字段中不包含子字符串 X.500 的条目: (&(ou=Marketing)(!(description=/X.500/)))
  • 下列过滤器返回所有组织单元为 Marketing 且 manager 为 Julie Fulmer 或 Cindy Zwaska 的条目: (&(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))
  • 下列过滤器返回所有不代表人员的条目: (!(objectClass=person))
  • 下列过滤器返回所有不代表人员且通用名近似于 printer3b 的条目:(&(!(objectClass=person))(cn~=printer3b))