一、基本概念:
************************************************************************************* 1.标签(Tag): 标签是一种XML元素,通过标签可以使JSP网页变得简洁并且易于维护,还可以方便地实现同一个JSP文件支持多种语言版本。由于标签是XML元素,所以它的名称和属性都是大小写敏感的 2.标签库(Tag library): 由一系列功能相似、逻辑上互相联系的标签构成的集合称为标签库。 3.标签库描述文件(Tag Library Descriptor): 标签库描述文件是一个XML文件,这个文件提供了标签库中类和JSP中对标签引用的映射关系。它是一个配置文件,和web.xml是类似的。 4.标签处理类(Tag Handle Class): 标签处理类是一个Java类,这个类继承了TagSupport或者扩展了SimpleTag接口,通过这个类可以实现自定义JSP标签的具体功能 ************************************************************************************* 二、自定义JSP标签的格式: ************************************************************************************* 1.<% @ taglib prefix=”someprefix” uri=”/sometaglib” %> 为了使到JSP容器能够使用标签库中的自定义行为,必须满足以下两个条件: 1.从一个指定的标签库中识别出代表这种自定义行为的标签 2.找到实现这些自定义行为的具体类 第一个必需条件-找出一个自定义行为属于那个标签库-是由标签指令的前缀(Taglib Directive's Prefix)属性完成,所以在同一个页面中使用相同前缀的元素都属于这个标签库。每个标签库都定义了一个默认的前缀,用在标签库的文档中或者页面中插入自定义标签。所以,你可以使用除了诸如jsp,jspx,java,servlet,sun,sunw(它们都是在JSP白皮书中指定的保留字)之类的前缀。 uri属性满足了以上的第二个要求。为每个自定义行为找到对应的类。这个uri包含了一个字符串,容器用它来定位TLD文件。在TLD文件中可以找到标签库中所有标签处理类的名称 2. 当web应用程序启动时,容器从WEB-INF文件夹的目录结构的META-INF搜索所有以.tld结尾的文件。也就是说它们会定位所有的TLD文件。对于每个TLD文件,容器会先获取标签库的URI,然后为每个TLD文件和对应的URI创建映射关系。 在JSP页面中,我们仅需通过使用带有URI属性值的标签库指令来和具体的标签库匹配 ************************************************************************************* 三、自定义JSP标签的处理过程: ************************************************************************************* 1.在JSP中引入标签库:<% @ taglib prefix=”taglibprefix” uri=”tagliburi” %> 2.在JSP中使用标签库标签: 3.Web容器根据第二个步骤中的prefix,获得第一个步骤中声明的taglib的uri属性值 4.Web容器根据uri属性在web.xml找到对应的 5.从 6.Web容器根据 7.从.tld文件中找到与tagname对应的 8.凑 9.Web容器根据 10. Web容器调用这个实例的doStartTag/doEndTag方法完成相应的处理 ************************************************************************************* 四、创建和使用一个Tag Library的基本步骤: ************************************************************************************* 1.创建标签的处理类(Tag Handler Class) 2.创建标签库描述文件(Tag Library Descrptor File) 3.在web.xml文件中配置 4.在JSP文件中引人标签库 ************************************************************************************* 五、TagSupport类简介: ************************************************************************************* 1.处理标签的类必须扩展javax.servlet.jsp.TagSupport. 2.TagSupport类的主要属性: A.parent属性:代表嵌套了当前标签的上层标签的处理类 B.pageContex属性:代表Web应用中的javax.servlet.jsp.PageContext对象 3.JSP容器在调用doStartTag或者doEndTag方法前,会先调用setPageContext和setParent方法,设置pageContext和parent。因此在标签处理类中可以直接访问pageContext变量 4.在TagSupport的构造方法中不能访问pageContext成员变量,因为此时JSP容器还没有调用 setPageContext方法对pageContext进行初始化 ************************************************************************************* 六、TagSupport处理标签的方法: ************************************************************************************* 1.TagSupport类提供了两个处理标签的方法: public int doStartTag() throws JspException public int doEndTag() throws JspException 2.doStartTag:但JSP容器遇到自定义标签的起始标志,就会调用doStartTag()方法。 doStartTag()方法返回一个整数值,用来决定程序的后续流程。 A.Tag.SKIP_BODY:表示 B.Tag.EVAL_BODY_INCLUDE:表示标签之间的内容被正常执行 3.doEndTag:但JSP容器遇到自定义标签的结束标志,就会调用doEndTag()方法。doEndTag ()方法也返回一个整数值,用来决定程序后续流程。 A.Tag.SKIP_PAGE:表示立刻停止执行网页,网页上未处理的静态内容和JSP程序均被 忽。略任何已有的输出内容立刻返回到客户的浏览器上。 B.Tag_EVAL_PAGE:表示按照正常的流程继续执行JSP网页 ************************************************************************************* 七、用户自定义的标签属性: ************************************************************************************* 如果在标签中还包含了自定义的属性,例如: ... 那么在标签处理类中应该将这个属性作为成员变量,并且分别提供设置和读取属性的方法。 ************************************************************************************* 八、创建标签处理类的步骤: ************************************************************************************* 1.创建包含JSP网页静态文本的文件(即是要替换自定义JSP标签的文本) 2.在Web应用启动时装载静态文本 3.创建标签处理类 ************************************************************************************* 九、如何创建包含JSP网页静态文本的文件: ************************************************************************************* 1.使用java.util.Properties类来存放要替换网页中自定义JSP标签的静态文本 2.Properties类代表了一系列属性的集合,其实例既可以被保存到流中,也可以从流中加 载。这些文本以key/value的形式存放在WEB-INF目录下,例如key=value,在属性列表中 这些key/value都是String类型的 ************************************************************************************* 十、Properties类的常用API: ************************************************************************************* 1.setProperty(String key, String value):调用Hashtable类的put方法添加属性 2.getProperty(String key):获取属性列表中key对应的属性值 3.load(InputStream in):从输入流对象InputStream中读取属性列表(Properties list) 4.store(OutputStream out,String comment):使用适当的格式将属性列表的属性对写入输 出流对象中,默认使用ISO-88590-1编码格式,以行的方式处理输入。属性的key/value之 间以”=、:”配对,以回车、换行分隔key/value对 ************************************************************************************* 十一、ServletContext类的常用API: ************************************************************************************* 1.getContext(String uripath):返回服务器中uripath所代表的ServletContext对象 2.getInitParameter(String name):返回ServletConfig对象中name参数的值 3.getMineType(String file):返回file参数代表的文件的MIME类型 4.getRequestDispatcher(String path):返回path代表的RequestDispacher对象 5.getResourceAsStream(String path):以输入流的形式返回path对应的资源,在输入留中对象可以为任意形式的数据,path参数必须以“/”开始且相对于Context Root ************************************************************************************* 十二、如何使用ServletContxt读取并保存属性文件: ************************************************************************************* 1.创建java.util.Properties类对象 2.获取ServletContext对象 3.将属性文件以输入流的形式读入到某个输入流对象中 4.将输入流对象加载到Properties对象中 5.将Properties对象保存到ServletContext对象中 ************************************************************************************* 十三、如何在Web应用启动时装载静态文本: ************************************************************************************* 1.创建继承了HttpServlet类的子类,在web.xml中配置这Servlet时设置load-on-startup属性: 2.在这个Servlet的init()方法中创建java.util.Properties类 3.获取当前Web应用的ServletContext对象 4.将WEB-INF目录下的属性文件读入到输入流InputStream中: InputStream in = context.getResourceAsString("WEB-INF/someproperties.properties"); 5.将输入流加载到属性对象中 ps.load(in); 6.将属性对象保存到上下文中。 context.setAttribute("attributeName",ps); ************************************************************************************* 十四、如何创建标签处理类: ************************************************************************************* 1.引入必需的资源: import javax.servlet.jsp.*; import javax.servlet.http.*; import java.util.*; import java.io.*; 2.继承TagSupport类并覆盖doStartTag()/doEndTag()方法 3.从ServletContext对象中获取java.util.Properties对象 4.从Properties对象中获取key对应的属性值 5.对获取的属性进行相应的处理并输出结果 ************************************************************************************* 十五、创建标签库描述文件(Tag Library Descriptor): ************************************************************************************* 1.标签库描述文件,简称TLD,采用XML文件格式,定义了用户的标签库。TLD文件中的元素可以分成3类: A. B. C. 2.标签库元素 A.shortname: 指定Tag Library默认的前缀名(prefix) B.uri: 设定Tag Library的惟一访问表示符 3.标签元素 A.name: 设定Tag的名字 B.tagclass: 设定Tag的处理类 C.bodycontent: 设定标签的主体(body)内容 1).empty:表示标签中没有body 2).JSP:表示标签的body中可以加入JSP程序代码 3).tagdependent:表示标签中的内容由标签自己去处理 4.标签属性元素 A.name:属性名称 B.required:属性是否必需的,默认为false C.rtexprvalue:属性值是否可以为request-time表达式,也就是类似于<%=…%>的表达式 ************************************************************************************* 十六、在Web应用中使用标签: ************************************************************************************* 1.如果Web应用中用到了自定义JSP标签,则必须在web.xml文件中加入 2. 3. 4.在JSP文件中需要加入<% @ taglib% >指令来声明对标签库的引用。例如: <% @ taglib prefix = “somePrefix” uri = "/someuri" %> 5.prefix表示在JSP网页中引用这个标签库的标签时的前缀,uri用来指定Tag Library的标识符,它必须和web.xml中的 ************************************************************************************* |
一,
启动BEA 打开控制台:通过浏览器,打开 http://172.18.20.222:7001/console 启动管理控制台。输入管理员用户名和密码(默认:weblogic/weblogic)。 创建JDBC数据源: 在“域结构”树中,展开“服务”>“JDBC”,然后选择“数据源”。 在“数据源概要”页上,单击“新建”。 在“JDBC 数据源属性”页上,输入或选择下列信息: 名称:jdbc/oracle JNDI名称:jdbc/oracle 数据库类型:Oracle 数据库驱动程序:BEA Oracle Driver Type 4 Version ...... 点击“下一步”。 无需改变默认值,再点击“下一步”。 输入以下值: 数据库名称:o9i (应该填写Oracle数据库实例的标识,即SID) 主机名:127.0.0.1 (数据库服务器IP或者HostName) 端口:1521 数据库用户名:** 密码:tiger 确认密码:tiger 点击“下一步”。 点击“测试配置”按钮。若显示“连接测试成功”,则说明以上参数配置正确。点击“下一步”按钮。 在“选择目标”操作中,选择需要将本数据源部署到哪些服务器上,选择“AdminServer”,然后点击“完成”按钮。 点击“激活更改”按钮,是配置信息持久保存并生效。 JNDI数据源已经成功创建且部署成功 重启 BEA 二, Context initContext = new InitialContext(); //Context envContext = (Context) initContext.lookup("java:/comp/env"); javax.sql. DataSource ds = (javax.sql.DataSource) (initContext).lookup("**"); //得到你所配置的数据源 Connection conn=null; conn = ds.getConnection(); return conn; 到此就OK 了,只要返回个conn,就可以操作了。 |
级别:中级
摘要:本文介绍了字符与编码的发展过程,相关概念的正确理解。举例说明了一些实际应用中,编码的实现方法。然后,本文讲述了通常对字符与编码的几种误解,由于这些误解而导致乱码产生的原因,以及消除乱码的办法。本文的内容涵盖了“中文问题”,“乱码问题”。 掌握编码问题的关键是正确地理解相关概念,编码所涉及的技术其实是很简单的。因此,阅读本文时需要慢读多想,多思考。 引言 “字符与编码”是一个被经常讨论的话题。即使这样,时常出现的乱码仍然困扰着大家。虽然我们有很多的办法可以用来消除乱码,但我们并不一定理解这些办法的内在原理。而有的乱码产生的原因,实际上由于底层代码本身有问题所导致的。因此,不仅是初学者会对字符编码感到模糊,有的底层开发人员同样对字符编码缺乏准确的理解。 回页首 1. 编码问题的由来,相关概念的理解 1.1 字符与编码的发展 从计算机对多国语言的支持角度看,大致可以分为三个阶段: 系统内码 说明 系统 阶段一 ASCII 计算机刚开始只支持英语,其它语言不能够在计算机上存储和显示。 英文 DOS 阶段二 ANSI编码 (本地化) 为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。 不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。 中文 DOS,中文 Windows 95/98,日文 Windows 95/98 阶段三 UNICODE (国际化) 为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。 Windows NT/2000/XP,Linux,Java 字符串在内存中的存放方法: 在 ASCII 阶段,单字节字符串使用一个字节存放一个字符(SBCS)。比如,"Bob123" 在内存中为: 42 6F 62 31 32 33 00 B o b 1 2 3 /0 在使用 ANSI 编码支持多种语言阶段,每个字符使用一个字节或多个字节来表示(MBCS),因此,这种方式存放的字符也被称作多字节字符。比如,"中文123" 在中文 Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节: D6 D0 CE C4 31 32 33 00 中 文 1 2 3 /0 在 UNICODE 被采用之后,计算机存放字符串时,改为存放每个字符在 UNICODE 字符集中的序号。目前计算机一般使用 2 个字节(16 位)来存放一个序号(DBCS),因此,这种方式存放的字符也被称作宽字节字符。比如,字符串 "中文123" 在 Windows 2000 下,内存中实际存放的是 5 个序号: 2D 4E 87 65 31 00 32 00 33 00 00 00 ← 在 x86 CPU 中,低字节在前 中 文 1 2 3 /0 一共占 10 个字节。 回页首 1.2 字符,字节,字符串 理解编码的关键,是要把字符的概念和字节的概念理解准确。这两个概念容易混淆,我们在此做一下区分: 概念描述 举例 字符 人们使用的记号,抽象意义上的一个符号。 '1', '中', 'a', '$', '¥', …… 字节 计算机中存储数据的单元,一个8位的二进制数,是一个很具体的存储空间。 0x01, 0x45, 0xFA, …… ANSI 字符串 在内存中,如果“字符”是以 ANSI 编码形式存在的,一个字符可能使用一个字节或多个字节来表示,那么我们称这种字符串为 ANSI 字符串或者多字节字符串。 "中文123" (占7字节) UNICODE 字符串 在内存中,如果“字符”是以在 UNICODE 中的序号存在的,那么我们称这种字符串为 UNICODE 字符串或者宽字节字符串。 L"中文123" (占10字节) 由于不同 ANSI 编码所规定的标准是不相同的,因此,对于一个给定的多字节字符串,我们必须知道它采用的是哪一种编码规则,才能够知道它包含了哪些“字符”。而对于 UNICODE 字符串来说,不管在什么环境下,它所代表的“字符”内容总是不变的。 回页首 1.3 字符集与编码 各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”。比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储。这些 ANSI 编码标准所规定的内容包含两层含义: 1. 使用哪些字符。也就是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符集”。 2. 规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。 各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。 “UNICODE 字符集”包含了各种语言中使用到的所有“字符”。用来给 UNICODE 字符集编码的标准有很多种,比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。 回页首 1.4 常用的编码简介 简单介绍一下常用的编码规则,为后边的章节做一个准备。在这里,我们根据编码规则的特点,把所有的编码分成三类: 分类 编码标准 说明 单字节字符编码 ISO-8859-1 最简单的编码规则,每一个字节直接作为一个 UNICODE 字符。比如,[0xD6, 0xD0] 这两个字节,通过 iso-8859-1 转化为字符串时,将直接得到 [0x00D6, 0x00D0] 两个 UNICODE 字符,即 "ÖÐ"。 反之,将 UNICODE 字符串通过 iso-8859-1 转化为字节串时,只能正常转化 0~255 范围的字符。 ANSI 编码 GB2312, BIG5, Shift_JIS, ISO-8859-2 …… 把 UNICODE 字符串通过 ANSI 编码转化为“字节串”时,根据各自编码的规定,一个 UNICODE 字符可能转化成一个字节或多个字节。 反之,将字节串转化成字符串时,也可能多个字节转化成一个字符。比如,[0xD6, 0xD0] 这两个字节,通过 GB2312 转化为字符串时,将得到 [0x4E2D] 一个字符,即 '中' 字。 “ANSI 编码”的特点: 1. 这些“ANSI 编码标准”都只能处理各自语言范围之内的 UNICODE 字符。 2. “UNICODE 字符”与“转换出来的字节”之间的关系是人为规定的。 UNICODE 编码 UTF-8, UTF-16, UnicodeBig …… 与“ANSI 编码”类似的,把字符串通过 UNICODE 编码转化成“字节串”时,一个 UNICODE 字符可能转化成一个字节或多个字节。 与“ANSI 编码”不同的是: 1. 这些“UNICODE 编码”能够处理所有的 UNICODE 字符。 2. “UNICODE 字符”与“转换出来的字节”之间是可以通过计算得到的。 我们实际上没有必要去深究每一种编码具体把某一个字符编码成了哪几个字节,我们只需要知道“编码”的概念就是把“字符”转化成“字节”就可以了。对于 “UNICODE 编码”,由于它们是可以通过计算得到的,因此,在特殊的场合,我们可以去了解某一种“UNICODE 编码”是怎样的规则。 回页首 2. 字符与编码在程序中的实现 2.1 程序中的字符与字节 在 C++ 和 Java 中,用来代表“字符”和“字节”的数据类型,以及进行编码的方法: 类型或操作 C++ Java 字符 wchar_t char 字节 char byte ANSI 字符串 char[] byte[] UNICODE 字符串 wchar_t[] String 字节串→字符串 mbstowcs(), MultiByteToWideChar() string = new String(bytes, "encoding") 字符串→字节串 wcstombs(), WideCharToMultiByte() bytes = string.getBytes("encoding") 以上需要注意几点: 1. Java 中的 char 代表一个“UNICODE 字符(宽字节字符)”,而 C++ 中的 char 代表一个字节。 2. MultiByteToWideChar() 和 WideCharToMultiByte() 是 Windows API 函数。 回页首 2.2 C++ 中相关实现方法 声明一段字符串常量: // ANSI 字符串,内容长度 7 字节 char sz[20] = "中文123"; // UNICODE 字符串,内容长度 5 个 wchar_t(10 字节) wchar_t wsz[20] = L"/x4E2D/x6587/x0031/x0032/x0033"; UNICODE 字符串的 I/O 操作,字符与字节的转换操作: // 运行时设定当前 ANSI 编码,VC 格式 setlocale(LC_ALL, ".936"); // GCC 中格式 setlocale(LC_ALL, "zh_CN.GBK"); // Visual C++ 中使用小写 %s,按照 setlocale 指定编码输出到文件 // GCC 中使用大写 %S fwprintf(fp, L"%s/n", wsz); // 把 UNICODE 字符串按照 setlocale 指定的编码转换成字节 wcstombs(sz, wsz, 20); // 把字节串按照 setlocale 指定的编码转换成 UNICODE 字符串 mbstowcs(wsz, sz, 20); 在 Visual C++ 中,UNICODE 字符串常量有更简单的表示方法。如果源程序的编码与当前默认 ANSI 编码不符,则需要使用 #pragma setlocale,告诉编译器源程序使用的编码: // 如果源程序的编码与当前默认 ANSI 编码不一致, // 则需要此行,编译时用来指明当前源程序使用的编码 #pragma setlocale(".936") // UNICODE 字符串常量,内容长度 10 字节 wchar_t wsz[20] = L"中文123"; 以上需要注意 #pragma setlocale 与 setlocale(LC_ALL, "") 的作用是不同的,#pragma setlocale 在编译时起作用,setlocale() 在运行时起作用。 回页首 2.3 Java 中相关实现方法 字符串类 String 中的内容是 UNICODE 字符串: // Java 代码,直接写中文 String string = "中文123"; // 得到长度为 5,因为是 5 个字符 System.out.println(string.length()); 字符串 I/O 操作,字符与字节转换操作。在 Java 包 java.io.* 中,以“Stream”结尾的类一般是用来操作“字节串”的类,以“Reader”,“Writer”结尾的类一般是用来操作“字符串”的类。 // 字符串与字节串间相互转化 // 按照 GB2312 得到字节(得到多字节字符串) byte [] bytes = string.getBytes("GB2312"); // 从字节按照 GB2312 得到 UNICODE 字符串 string = new String(bytes, "GB2312"); // 要将 String 按照某种编码写入文本文件,有两种方法: // 第一种办法:用 Stream 类写入已经按照指定编码转化好的字节串 OutputStream os = new FileOutputStream("1.txt"); os.write(bytes); os.close(); // 第二种办法:构造指定编码的 Writer 来写入字符串 Writer ow = new OutputStreamWriter(new FileOutputStream("2.txt"), "GB2312"); ow.write(string); ow.close(); /* 最后得到的 1.txt 和 2.txt 都是 7 个字节 */ 如果 java 的源程序编码与当前默认 ANSI 编码不符,则在编译的时候,需要指明一下源程序的编码。比如: E:/>javac -encoding BIG5 Hello.java 以上需要注意区分源程序的编码与 I/O 操作的编码,前者是在编译时起作用,后者是在运行时起作用。 回页首 3. 几种误解,以及乱码产生的原因和解决办法 3.1 容易产生的误解 对编码的误解 误解一 在将“字节串”转化成“UNICODE 字符串”时,比如在读取文本文件时,或者通过网络传输文本时,容易将“字节串”简单地作为单字节字符串,采用每“一个字节”就是“一个字符”的方法进行转化。 而实际上,在非英文的环境中,应该将“字节串”作为 ANSI 字符串,采用适当的编码来得到 UNICODE 字符串,有可能“多个字节”才能得到“一个字符”。 通常,一直在英文环境下做开发的程序员们,容易有这种误解。 误解二 在 DOS,Windows 98 等非 UNICODE 环境下,字符串都是以 ANSI 编码的字节形式存在的。这种以字节形式存在的字符串,必须知道是哪种编码才能被正确地使用。这使我们形成了一个惯性思维:“字符串的编码”。 当 UNICODE 被支持后,Java 中的 String 是以字符的“序号”来存储的,不是以“某种编码的字节”来存储的,因此已经不存在“字符串的编码”这个概念了。只有在“字符串”与“字节串”转化时,或者,将一个“字节串”当成一个 ANSI 字符串时,才有编码的概念。 不少的人都有这个误解。 第一种误解,往往是导致乱码产生的原因。第二种误解,往往导致本来容易纠正的乱码问题变得更复杂。 在这里,我们可以看到,其中所讲的“误解一”,即采用每“一个字节”就是“一个字符”的转化方法,实际上也就等同于采用 iso-8859-1 进行转化。因此,我们常常使用 bytes = string.getBytes("iso-8859-1") 来进行逆向操作,得到原始的“字节串”。然后再使用正确的 ANSI 编码,比如 string = new String(bytes, "GB2312"),来得到正确的“UNICODE 字符串”。 回页首 3.2 非 UNICODE 程序在不同语言环境间移植时的乱码 非 UNICODE 程序中的字符串,都是以某种 ANSI 编码形式存在的。如果程序运行时的语言环境与开发时的语言环境不同,将会导致 ANSI 字符串的显示失败。 比如,在日文环境下开发的非 UNICODE 的日文程序界面,拿到中文环境下运行时,界面上将显示乱码。如果这个日文程序界面改为采用 UNICODE 来记录字符串,那么当在中文环境下运行时,界面上将可以显示正常的日文。 由于客观原因,有时候我们必须在中文操作系统下运行非 UNICODE 的日文软件,这时我们可以采用一些工具,比如,南极星,AppLocale 等,暂时的模拟不同的语言环境。 回页首 3.3 网页提交字符串 当页面中的表单提交字符串时,首先把字符串按照当前页面的编码,转化成字节串。然后再将每个字节转化成 "%XX" 的格式提交到 Web 服务器。比如,一个编码为 GB2312 的页面,提交 "中" 这个字符串时,提交给服务器的内容为 "%D6%D0"。 在服务器端,Web 服务器把收到的 "%D6%D0" 转化成 [0xD6, 0xD0] 两个字节,然后再根据 GB2312 编码规则得到 "中" 字。 在 Tomcat 服务器中,request.getParameter() 得到乱码时,常常是因为前面提到的“误解一”造成的。默认情况下,当提交 "%D6%D0" 给 Tomcat 服务器时,request.getParameter() 将返回 [0x00D6, 0x00D0] 两个 UNICODE 字符,而不是返回一个 "中" 字符。因此,我们需要使用 bytes = string.getBytes("iso-8859-1") 得到原始的字节串,再用 string = new String(bytes, "GB2312") 重新得到正确的字符串 "中"。 回页首 3.4 从数据库读取字符串 通过数据库客户端(比如 ODBC 或 JDBC)从数据库服务器中读取字符串时,客户端需要从服务器获知所使用的 ANSI 编码。当数据库服务器发送字节流给客户端时,客户端负责将字节流按照正确的编码转化成 UNICODE 字符串。 如果从数据库读取字符串时得到乱码,而数据库中存放的数据又是正确的,那么往往还是因为前面提到的“误解一”造成的。解决的办法还是通过 string = new String( string.getBytes("iso-8859-1"), "GB2312") 的方法,重新得到原始的字节串,再重新使用正确的编码转化成字符串。 回页首 3.5 电子邮件中的字符串 当一段 Text 或者 HTML 通过电子邮件传送时,发送的内容首先通过一种指定的字符编码转化成“字节串”,然后再把“字节串”通过一种指定的传输编码(Content-Transfer-Encoding)进行转化得到另一串“字节串”。比如,打开一封电子邮件源代码,可以看到类似的内容: Content-Type: text/plain; charset="gb2312" Content-Transfer-Encoding: base64 sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg== 最常用的 Content-Transfer-Encoding 有 Base64 和 Quoted-Printable 两种。在对二进制文件或者中文文本进行转化时,Base64 得到的“字节串”比 Quoted-Printable 更短。在对英文文本进行转化时,Quoted-Printable 得到的“字节串”比 Base64 更短。 邮件的标题,用了一种更简短的格式来标注“字符编码”和“传输编码”。比如,标题内容为 "中",则在邮件源代码中表示为: // 正确的标题格式 Subject: =?GB2312?B?1tA=?= 其中, * 第一个“=?”与“?”中间的部分指定了字符编码,在这个例子中指定的是 GB2312。 * “?”与“?”中间的“B”代表 Base64。如果是“Q”则代表 Quoted-Printable。 * 最后“?”与“?=”之间的部分,就是经过 GB2312 转化成字节串,再经过 Base64 转化后的标题内容。 如果“传输编码”改为 Quoted-Printable,同样,如果标题内容为 "中": // 正确的标题格式 Subject: =?GB2312?Q?=D6=D0?= 如果阅读邮件时出现乱码,一般是因为“字符编码”或“传输编码”指定有误,或者是没有指定。比如,有的发邮件组件在发送邮件时,标题 "中": // 错误的标题格式 Subject: =?ISO-8859-1?Q?=D6=D0?= 这样的表示,实际上是明确指明了标题为 [0x00D6, 0x00D0],即 "ÖÐ",而不是 "中"。 回页首 4. 几种错误理解的纠正 误解:“ISO-8859-1 是国际编码?” 非也。iso-8859-1 只是单字节字符集中最简单的一种,也就是“字节编号”与“UNICODE 字符编号”一致的那种编码规则。当我们要把一个“字节串”转化成“字符串”,而又不知道它是哪一种 ANSI 编码时,先暂时地把“每一个字节”作为“一个字符”进行转化,不会造成信息丢失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节串。 误解:“Java 中,怎样知道某个字符串的内码?” Java 中,字符串类 java.lang.String 处理的是 UNICODE 字符串,不是 ANSI 字符串。我们只需要把字符串作为“抽象的符号的串”来看待。因此不存在字符串的内码的问题。 |
1. 概述
本文主要包括以下几个方面:编码基本知识,java,系统软件,url,工具软件等。 在下面的描述中,将以"中文"两个字为例,经查表可以知道其GB2312编码是"d6d0 cec4",Unicode编码为"4e2d 6587",UTF编码就是"e4b8ad e69687"。注意,这两个字没有iso8859-1编码,但可以用iso8859-1编码来"表示"。 2. 编码基本知识 最早的编码是iso8859-1,和ascii编码相似。但为了方便表示各种各样的语言,逐渐出现了很多标准编码,重要的有如下几个。 2.1. iso8859-1 属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列。比如,字母'a'的编码为0x61=97。 很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。而且在很多协议上,默认使用该编码。比如,虽然"中文"两个字不存在iso8859-1编码,以gb2312编码为例,应该是"d6d0 cec4"两个字符,使用iso8859-1编码的时候则将它拆开为4个字节来表示:"d6 d0 ce c4"(事实上,在进行存储的时候,也是以字节为单位处理的)。而如果是UTF编码,则是6个字节"e4 b8 ad e6 96 87"。很明显,这种表示方法还需要以另一种编码为基础。 2.2. GB2312/GBK 这就是汉子的国标码,专门用来表示汉字,是双字节编码,而英文字母和iso8859-1一致(兼容iso8859-1编码)。其中gbk编码能够用来同时表示繁体字和简体字,而gb2312只能表示简体字,gbk是兼容gb2312编码的。 2.3. unicode 这是最统一的编码,可以用来表示所有语言的字符,而且是定长双字节(也有四字节的)编码,包括英文字母在内。所以可以说它是不兼容iso8859-1编码的,也不兼容任何编码。不过,相对于iso8859-1编码来说,uniocode编码只是在前面增加了一个0字节,比如字母'a'为"00 61"。 需要说明的是,定长编码便于计算机处理(注意GB2312/GBK不是定长编码),而unicode又可以用来表示所有字符,所以在很多软件内部是使用unicode编码来处理的,比如java。 2.4. UTF 考虑到unicode编码不兼容 iso8859-1编码,而且容易占用更多的空间:因为对于英文字母,unicode也需要两个字节来表示。所以unicode不便于传输和存储。因此而产生了utf编码,utf编码兼容iso8859-1编码,同时也可以用来表示所有语言的字符,不过,utf编码是不定长编码,每一个字符的长度从1-6 个字节不等。另外,utf编码自带简单的校验功能。一般来讲,英文字母都是用一个字节表示,而汉字使用三个字节。 注意,虽然说utf是为了使用更少的空间而使用的,但那只是相对于unicode编码来说,如果已经知道是汉字,则使用GB2312/GBK无疑是最节省的。不过另一方面,值得说明的是,虽然utf编码对汉字使用3个字节,但即使对于汉字网页,utf编码也会比unicode编码节省,因为网页中包含了很多的英文字符。 3. java对字符的处理 在java应用软件中,会有多处涉及到字符集编码,有些地方需要进行正确的设置,有些地方需要进行一定程度的处理。 3.1. getBytes(charset) 这是java字符串处理的一个标准函数,其作用是将字符串所表示的字符按照charset编码,并以字节方式表示。注意字符串在java内存中总是按unicode编码存储的。比如"中文",正常情况下(即没有错误的时候)存储为"4e2d 6587",如果charset为"gbk",则被编码为"d6d0 cec4",然后返回字节"d6 d0 ce c4"。如果charset为"utf8"则最后是"e4 b8 ad e6 96 87"。如果是"iso8859-1",则由于无法编码,最后返回 "3f 3f"(两个问号)。 3.2. new String(charset) 这是java字符串处理的另一个标准函数,和上一个函数的作用相反,将字节数组按照charset编码进行组合识别,最后转换为unicode存储。参考上述getBytes的例子,"gbk" 和"utf8"都可以得出正确的结果"4e2d 6587",但iso8859-1最后变成了"003f 003f"(两个问号)。 因为utf8可以用来表示/编码所有字符,所以new String( str.getBytes( "utf8" ), "utf8" ) === str,即完全可逆。 3.3. setCharacterEncoding() 该函数用来设置http请求或者相应的编码。 对于request,是指提交内容的编码,指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码,需要进一步处理。参见下述 "表单输入"。值得注意的是在执行setCharacterEncoding()之前,不能执行任何getParameter()。java doc上说明:This method must be called prior to reading request parameters or reading input using getReader()。而且,该指定只对POST方法有效,对GET方法无效。分析原因,应该是在执行第一个getParameter()的时候, java将会按照编码分析所有的提交内容,而后续的getParameter()不再进行分析,所以setCharacterEncoding()无效。而对于GET方法提交表单是,提交的内容在URL中,一开始就已经按照编码分析所有的提交内容,setCharacterEncoding()自然就无效。 对于response,则是指定输出内容的编码,同时,该设置会传递给浏览器,告诉浏览器输出内容所采用的编码。 3.4. 处理过程 下面分析两个有代表性的例子,说明java对编码有关问题的处理方法。 3.4.1. 表单输入 User input *(gbk:d6d0 cec4) browser *(gbk:d6d0 cec4) web server iso8859-1(00d6 00d 000ce 00c4) class,需要在class中进行处理:getbytes("iso8859-1")为d6 d0 ce c4,new String("gbk")为d6d0 cec4,内存中以unicode编码则为4e2d 6587。 l 用户输入的编码方式和页面指定的编码有关,也和用户的操作系统有关,所以是不确定的,上例以gbk为例。 l 从browser到web server,可以在表单中指定提交内容时使用的字符集,否则会使用页面指定的编码。而如果在url中直接用?的方式输入参数,则其编码往往是操作系统本身的编码,因为这时和页面无关。上述仍旧以gbk编码为例。 l Web server接收到的是字节流,默认时(getParameter)会以iso8859-1编码处理之,结果是不正确的,所以需要进行处理。但如果预先设置了编码(通过request. setCharacterEncoding ()),则能够直接获取到正确的结果。 l 在页面中指定编码是个好习惯,否则可能失去控制,无法指定正确的编码。 3.4.2. 文件编译 假设文件是gbk编码保存的,而编译有两种编码选择:gbk或者iso8859-1,前者是中文windows的默认编码,后者是linux的默认编码,当然也可以在编译时指定编码。 Jsp *(gbk:d6d0 cec4) java file *(gbk:d6d0 cec4) compiler read uincode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) compiler write utf(gbk: e4b8ad e69687; iso8859-1: *) compiled file unicode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) class。所以用gbk编码保存,而用iso8859-1编译的结果是不正确的。 class unicode(4e2d 6587) system.out / jsp.out gbk(d6d0 cec4) os console / browser。 l 文件可以以多种编码方式保存,中文windows下,默认为ansi/gbk。 l 编译器读取文件时,需要得到文件的编码,如果未指定,则使用系统默认编码。一般class文件,是以系统默认编码保存的,所以编译不会出问题,但对于 jsp文件,如果在中文windows下编辑保存,而部署在英文linux下运行/编译,则会出现问题。所以需要在jsp文件中用 pageEncoding指定编码。 l Java编译的时候会转换成统一的unicode编码处理,最后保存的时候再转换为utf编码。 l 当系统输出字符的时候,会按指定编码输出,对于中文windows下,System.out将使用gbk编码,而对于response(浏览器),则使用 jsp文件头指定的contentType,或者可以直接为response指定编码。同时,会告诉browser网页的编码。如果未指定,则会使用 iso8859-1编码。对于中文,应该为browser指定输出字符串的编码。 l browser显示网页的时候,首先使用response中指定的编码(jsp文件头指定的contentType最终也反映在response上),如果未指定,则会使用网页中meta项指定中的contentType。 3.5. 几处设置 对于web应用程序,和编码有关的设置或者函数如下。 3.5.1. jsp编译 指定文件的存储编码,很明显,该设置应该置于文件的开头。例如:<%@page pageEncoding="GBK"%>。另外,对于一般class文件,可以在编译的时候指定编码。 3.5.2. jsp输出 指定文件输出到browser是使用的编码,该设置也应该置于文件的开头。例如:<%@ page contentType="text/html; charset= GBK" %>。该设置和response.setCharacterEncoding("GBK")等效。 3.5.3. meta设置 指定网页使用的编码,该设置对静态网页尤其有作用。因为静态网页无法采用jsp的设置,而且也无法执行response.setCharacterEncoding()。例如: 如果同时采用了jsp输出和meta设置两种编码指定方式,则jsp指定的优先。因为jsp指定的直接体现在response中。 需要注意的是,apache有一个设置可以给无编码指定的网页指定编码,该指定等同于jsp的编码指定方式,所以会覆盖静态网页中的meta指定。所以有人建议关闭该设置。 3.5.4. form设置 当浏览器提交表单的时候,可以指定相应的编码。例如: |
准备工作:
安装tomcat5.5(注意这点) 安装mysql 拷贝mysql驱动到tomcat_home/common/lib下 新建一个web工程 在工程中加入index.jsp <% @page import = " java.util.*,javax.naming.*,java.sql.*,javax.sql.* " %>
<% @page contentType = " text/html;charset=BIG5 " %> <% Context ctx = new InitialContext(); String strLookup = " java:comp/env/jdbc/test " ; DataSource ds = (DataSource) ctx.lookup(strLookup); Connection con = ds.getConnection(); if (con != null ) { out.print("success"); } else { out.print("failure"); } %> web.xml中加入 < resource - ref >
< res - ref - name > jdbc / test res - ref - name > < res - type > javax.sql.DataSource res - type > < res - auth > Container res - auth > < res - sharing - scope > Shareable res - sharing - scope > resource - ref > 配置tomcat 方法一: < Context >
< Resource name = " jdbc/test " type = " javax.sql.DataSource " password = " bb " driverClassName = " com.mysql.jdbc.Driver " maxIdle = " 2 " maxWait = " 50 " username = " root " url = " jdbc:mysql://localhost:3306/test " maxActive = " 4 " /> Context > 方法二: 只需在tomcat_home/webapps/myapps/META-INF/context.xml中增加: < context >
< Resource name = " jdbc/test " type = " javax.sql.DataSource " password = " bb " driverClassName = " com.mysql.jdbc.Driver " maxIdle = " 2 " maxWait = " 50 " username = " root " url = " jdbc:mysql://localhost:3306/test " maxActive = " 4 " /> context >
配置类型二: 步骤一:配置全局resource(这一步对于所有的配置都是一样的) < Resource
name = " jdbc/test " type = " javax.sql.DataSource " password = " bb " driverClassName = " com.mysql.jdbc.Driver " maxIdle = " 2 " maxWait = " 50 " username = " root " url = " jdbc:mysql://localhost:3306/test " maxActive = " 4 " />
方法一:(对比类型一的配置理解) < Context >
< ResourceLink global = " jdbc/test " name = " jdbc/test " type = " javax.sql.DataSource " /> Context > 方法二:(对比类型一的配置理解) 在tomcat_home/webapps/myapps/META-INF/context.xml的Context中增加: < context >
< ResourceLink global = " jdbc/test " name = " jdbc/test " type = " javax.sql.DataSource " /> context >
常见错误: 分析: 类型一的方式对应一个应用单独使用这个配置的情况 类型二的方式对应多个应用共享一个配置的情况 最后再次提醒一下:所有的配置必须放在 |
最近写书,写到JNDI,到处查资料,发现所有的中文资料都对JNDI解释一通,配置代码也是copy的,调了半天也没调通,最后到SUN的网站参考了一下他的JNDI tutorial,终于基本上彻底明白了
和多数java服务一样,SUN对JNDI也只提供接口,使用JNDI只需要用到JNDI接口而不必关心具体实现: private static Object jndiLookup() throws Exception { InitialContext ctx = new InitialContext(); return ctx.lookup("java:comp/env/systemStartTime"); } 上述代码在J2EE服务器环境下工作得很好,但是在main()中就会报一个NoInitialContextException,许多文章会说你创建InitialContext的时候还要传一个Hashtable或者Properties,像这样: Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL,"t3://localhost:7001"); InitialContext ctx = new InitialContext(env); 这个在WebLogic环境下是对的,但是换到JBoss呢?再用JBoss的例子? 其实之所以有NoInitialContextException是因为无法从System.properties中获得必要的JNDI参数,在服务器环境下,服务器启动时就把这些参数放到System.properties中了,于是直接new InitialContext()就搞定了,不要搞env那么麻烦,搞了env你的代码还无法移植,弄不好管理员设置服务器用的不是标准端口还照样抛异常。 但是在单机环境下,可没有JNDI服务在运行,那就手动启动一个JNDI服务。我在JDK 5的rt.jar中一共找到了4种SUN自带的JNDI实现: LDAP,CORBA,RMI,DNS。 这4种JNDI要正常运行还需要底层的相应服务。一般我们没有LDAP或CORBA服务器,也就无法启动这两种JNDI服务,DNS用于查域名的,以后再研究,唯一可以在main()中启动的就是基于RMI的JNDI服务。 现在我们就在main()中启动基于RMI的JNDI服务并且绑一个Date对象到JNDI上: LocateRegistry.createRegistry(1099); System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); System.setProperty(Context.PROVIDER_URL, "rmi://localhost:1099"); InitialContext ctx = new InitialContext(); class RemoteDate extends Date implements Remote {}; ctx.bind("java:comp/env/systemStartTime", new RemoteDate()); ctx.close(); 注意,我直接把JNDI的相关参数放入了System.properties中,这样,后面的代码如果要查JNDI,直接new InitialContext()就可以了,否则,你又得写Hashtable env = ... 在RMI中绑JNDI的限制是,绑定的对象必须是Remote类型,所以就自己扩展一个。 其实JNDI还有两个Context.SECURITY_PRINCIPAL和Context.SECURITY_CREDENTIAL,如果访问JNDI需要用户名和口令,这两个也要提供,不过一般用不上。 在后面的代码中查询就简单了: InitialContext ctx = new InitialContext(); Date startTime = (Date) ctx.lookup("java:comp/env/systemStartTime"); 在SUN的JNDI tutorial中的例子用的com.sun.jndi.fscontext.RefFSContextFactory类,但是我死活在JDK 5中没有找到这个类,也就是NoClassDefFoundError,他也不说用的哪个扩展包,我也懒得找了。 |
一、先在自己应用程序WEB-INF目录下的web.xml添加以下语句:
二、例子:以下是假设的项目ACMEWeb: |
JNDI术语 英文全称是:Java Naming and Directory Interface 术语解释:JNDI(Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API。为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。 1.命名服务绑定的概念将对象和名称联系起来,可以通过名称访问对象。 2.目录服务是一种扩展的命名服务,目录服务中的对象不但有名称,还有属性。 JDNI例子: 在一个文件系统中,文件名被绑定给文件。在DNS中,一个IP地址绑定一个URL。在目录服务中,一个对象名被绑定给一个对象实体。 命名系统中的对象可以是DNS记录中的名称、应用服务器中的EJB组件(Enterprise JavaBeans Component)、LDAP(Lightweight Directory Access Protocol)中的用户Profile。 目录服务中的对象有属性,在目录服务中可以根据属性搜索对象。 JNDI可访问的现有的目录及服务有: DNS、LDAP(Lightweight Directory Access Protocol 轻型目录访问协议)、 CORBA对象服务、文件系统、Windows XP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS、XNam 、Novell目录服务。 JNDI构架 JNDI架构提供了一组标准的独立于命名系统的API,构建在与命名系统有关的驱动之上的。 JNDI提供了应用编程接口(application programming interface,API)和服务提供者接口(service provider interface,SPI)。 JNDI API包含以下5个包: javax.naming:命名操作; javax.naming.directory:目录操作; javax.naming.event:在命名目录服务器中请求事件通知; javax.naming.ldap:提供LDAP支持; javax.naming.spi:提供了不同命名和目录服务可以挂接他们的实现的方法。 JNDI具体概念 上下文(context)是一套name-to-object的绑定(bindings),上下文提供了解析的操作,操作还包括,名称的绑定和取消绑定,列出绑定的名称。context还可已包括下一层subContext。 Javax.naming.InitialContext是实现了Context接口的类。在使用命名和目录服务时获得initial context是对整个名字空间操作的入口。 在目录服务中是DirContext. 创建InitialContext对象的一个例子: Hashtable env = new Hashtable(); // select a service provider factory env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContext"); // create the initial context Context contxt = new InitialContext(env); INITIAL_CONTEXT_FACTORY指定了JNDI服务提供者中工厂类(factory class)的名称。Factory负责为其服务创建适当的InitialContext对象。 Name Service Provider Factory : File System com.sun.jndi.fscontext.RefFSContextFactory LDAP com.sun.jndi.ldap.LdapCtxFactory RMI com.sun.jndi.rmi.registry.RegistryContextFactory CORBA com.sun.jndi.cosnaming.CNCtxFactory DNS com.sun.jndi.dns.DnsContextFactory 为了用名称从命名服务或目录中取得或解析对象,使用Context的lookup方法:Object obj=contxt.lookup(name)。Lookup方法返回一个对象,这个对象表示是上下文的儿子。 JNDI应用包含两方面:1.使用JNDI访问EJB。2.使用JNDI访问数据库。 JNDI与JDBC: JNDI提供了一种统一的方式,可以用在网络上查找和访问服务。通过指定一个资源名称,该名称对应于数据库或命名服务中的一个纪录,同时返回数据库连接建立所必须的信息。 代码示例: try{ Context cntxt = new InitialContext(); DataSource ds = (DataSource) cntxt.lookup("jdbc/dpt"); } catch(NamingException ne){ ... } 常用的JNDI操作: void bind(String sName,Object object);――绑定:把名称同对象关联的过程 void rebind(String sName,Object object);――重新绑定:用来把对象同一个已经存在的名称重新绑定 void unbind(String sName);――释放:用来把对象从目录中释放出来 void lookup(String sName,Object object);――查找:返回目录总的一个对象 void rename(String sOldName,String sNewName);――重命名:用来修改对象名称绑定的名称 NamingEnumeration listBinding(String sName);――清单:返回绑定在特定上下文中对象的清单列表 NamingEnumeration list(String sName);--与listBindings(String sName)相似 代码示例: //得到初始目录环境的一个引用 Context cntxt = new InitialContext(); //返回绑定在特定上下文中指定属性名对象的清单列表 NamingEnumeration namEnumList = ctxt.listBinding("cntxtName"); //循环列出所有名字、类和对象 while ( namEnumList.hasMore() ) { Binding bnd = (Binding) namEnumList.next(); String sObjName = bnd.getName(); String sClassName = bnd.getClassName(); SomeObject objLocal = (SomeObject) bnd.getObject(); } JNDI操作步骤 1.建立一个散列表(hashtable)。 2.给散列表添加信息。包含JNDI服务的属性,连接LDAP服务器的IP地址、端口等。 3.创建初始context对象。如果访问命名服务使用InitialContext,如果访问目录服务使用InitialDirContext。 4.用context对象执行操作(如添加新条目或者搜索条目)。 5.关闭context对象。 JNDI存储查询串行化的Java对象 c:/javatest/jndi/ldapDataBind.java jndi用途: 1.列出属性 Attribute attr =directory.getAttributes(personName).get("email"); String email = (String)attr.get(); 2.搜索对象 查找在wiz部门、名字叫Fox的员工 foxes = directory.search("o=Wiz,c= US ", "sn=Fox", controls); 3.查询对象 Printer printer = (Printer)namespace.lookup(printerName); printer.print(document); 4。列出特定内容 NamingEnumeration list = namespace.list("o=Widget, c=US"); while (list.hasMore()) { NameClassPair entry = (NameClassPair)list.next(); display(entry.getName(), entry.getClassName()); |