Servlet面试题

更新时间:2024-05-02 09:55:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

1、Servlet如何得到服务器的信息?

Servlet可以使用如下四种方法来得到server的name, port和info publicString ServletRequest.getServerName() publicString ServletRequest.getServerPort() publicString ServletContext.getServerInfo()

publicString ServletRequest.getAttributes(String name)

如下代码实现用servlet取得server的信息并输出到客户端浏览器: importjava.io.*; importjava.util.*; importjavax.servlet.*; importjavax.servlet.http.*;

public classDemoServerSnoopextendsGenericServlet{

publicvoidservice(ServletRequest req , ServletResponse res) throwsServletException,IOException{

res.setContentType(\); PrintWriter out= res.getWriter();

out.println(\+ req.getServerName()); out.println(\+ req.getServerPort());

out.println(\+ getServletContext().getServerInfo());

out.println(\+

getServerInfoName(getServletContext().getServerInfo()));

out.println(\+

getServerInfoVersion(getServletContext().getServerInfo()));

out.println(\+ getServletContext().getAttribute(\)); }

privateString getServerInfoName(String serverInfo){

intslash = serverInfo.indexOf('/'); if(slash==-1)

returnserverInfo; else

return(String)serverInfo.subSequence(0,slash); }

privateString getServerInfoVersion(String serverInfo){

intslash = serverInfo.indexOf('/'); if(slash==-1) return null; else

returnserverInfo.substring(slash +1); }}

2、Servlet如何得到客户端机器的信息?

Servlet可以使用getRemoteAddr()和getRemoteHost()来得到客户端的IP地址和host, 代码如下所示:

publicString ServletRequest.getRemoteAddr() publicStirng ServletRequest.getRemoteHost()

用这些方法来访问客户端有所限制,如下代码实现了对客户端配置进行检查并把相关消息发送到客户端的功能: importjava.io.*; importjava.util.*; importjavax.servlet.*; importjavax.servlet.http.*;

public classDemoExportRestrictionextendsHttpServlet{

publicvoiddoGet(HttpServletRequest req,HttpServletResponse res) throwsServletException,IOException{

res.setContentType(\); PrintWriter out= res.getWriter();

//得到客户端的hostname

String remoteHost = req.getRemoteHost();

//查看客户端是否允许这样的操作 if(!isHostAllowed(remoteHost)){

out.println(\); }else{

out.println(\); } }

privatebooleanisHostAllowed(String host) { return(host.endsWith(\))|| (host.indexOf('.')==-1);//没有域名 ok } }

3、一家美资企业的java servlet面试题

filter 的作用是什么?主要实现什么方法?doFilter方法里面的2个参数request 和 response 他问 这两个接口的全称是什么?

1.Filter使用户可以改变一个request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开servlet时处理response.换种说法,filter其实是一个”servlet chaining”(servlet 链).一个filter 包括:

1. 在servlet被调用之前截获;

2. 在servlet被调用之前检查servlet request; 3. 根据需要修改request头和request数据; 4. 根据需要修改response头和response数据; 5. 在servlet被调用之后截获.

2. request的全称是 HttpServletRequest response的全称是 HttpServletResponse . 4、JDBC操作数据库的基本流程是什么?

所有的JDBC应用程序都具有下面的基本流程: 1、建立到数据库的连接。 2、执行SQL语句。 3、处理结果。 4、从数据库断开连接。

下面我们就来仔细看一看每一个步骤。 建立到数据库的连接

通过JDBC使用数据库的第一步就是建立一个连接。JDBC连接是由URL指定的,它的格式如下:

jdbc::

其中subprotocol是被请求的数据库连接的类型(如ODBC,ORACLE,Informix等等),而subname提供了所要建立的连接的一些附加信息。当JDBC驱动程序管理器收到一个连接的URL时,所有已知的JDBC驱动程序会被询问是否可以为这个URL服务。请求一个通过JDBC-ODBC桥到叫做MyData的ODBC数据源的连接的例子如下: Connection con = DriverManage.getconnection(”jdbc:odbc:MyData”);

看上去一切都很顺利,但是JDBC驱动程序管理器是怎么知道哪些JDBC驱动程序在当前的系统中可用呢?有两种机制可以通知驱动程序管理器一个JDBC驱动程序可以使用:sql.drivers属性和JDBC驱动程序注册。

驱动程序管理器引用sql.drivers系统属性来取得当前系统中可用的JDBC驱动程序列表。这个系统属性包含一些用冒号隔开的JDBC驱动程序的类名,通过这个类名,驱动程序管理器可以试图满足一个连接请求。

使用驱动程序注册更为常见。这种方法使你对你要使用的JDBC驱动程序有更多的控制。所有的JDBC驱动程序在实例化的时候都必须在驱动程序管理器中注册自己,注册可以通过下列两个方法来实现:

1.Class.forName(”foo.Driver”).newInstance(); 2.new foo.Driver();

我个人比较喜欢使用Class.forName()这种方法,不过这两种方法的效果是相同的。JDBC驱动程序用驱动程序管理器注册自己,这样,它就可以为连接请求服务了。 执行SQL语句

在数据库连接成功建立之后,我们就可以执行那些完成实际工作的SQL语句了。在执行SQL语句之前,我们必须首先创建一个语句对象,这个对象提供了到特定数据库SQL引擎的接口。有下列三种不同类型的语句对象:

1.Statement——基本的语句对象,它提供了直接在数据库中执行SQL语句的方法。对于那些只执行一次的查询以及DDL语句如CREATE TABLE,DROP TABLE等等来说,statement对象就足够了。

2.Prepared statement——这种语句对象用于那些需要执行多次,每次仅仅是数据取值不同的SQL语句,它还提供了一些方法,以便指出语句所使用的输入参数。

3.Callable statement——这种语句对象被用来访问数据库中的存储过程。它提供了一些方法来指定语句所使用的输入输出参数。

下面是一个用语句类来执行SQL SELECT语句的一个例子: Statement stmt = con.createStatement();

ResultSet rs = stmt.executeQuery(”SELECT * FROM MyTable”); 处理结果

在执行了一个SQL语句之后,我们必须处理得到的结果。有些语句仅仅返回一个整形数,指出受到影响的行数(比如UPDATE和DELETE语句)。SQL查询(SELECT语句)返回一个含有查询结果的结果集。结果集由行和列组成,各列数据可以通过相应数据库类型的一系列get方法(如getString,getInt,getDate等等)来取得。在取得了一行数据的所有数据之后,我们可以调用next()方法来移到结果集中的下一条记录。JDBC规范的1.1版只允许forward-onle(只向前)型的游标,而在JDBC2.0中有更健壮的游标控制功能,我们可以向后移动游标而且可以将游标移动到指定行。 从数据库断开连接

在结果集、语句和连接对象用完以后,我们必须正确地关闭它们。连接对象、结果集对

象以及所有的语句对象都有close()方法,通过调用这个方法,我们可以确保正确释放与特定数据库系统相关的所有资源。

有些开发者喜欢将引用乱放,然后用一个垃圾收集程序专门负责正确清除对象。我强烈建议大家在使用了JDBC驱动程序之后调用close()方法。这样可以尽可能的减少由于挂起的对象残留在数据库系统中而造成的内存泄漏。

5、为什么要使用servlet

servlet可以很好地替代公共网关接口(Common Gateway Interface,CGI)脚本。通常CGI脚本是用Perl或者C语言编写的,它们总是和特定的服务器平台紧密相关。而servlet是用Java编写的,所以它们一开始就是平台无关的。这样,Java编写一次就可以在任何平台运行(write once,run anywhere)的承诺就同样可以在服务器上实现了。servlet还有一些CGI脚本所不具备的独特优点:

■servlet是持久的。servlet只需Web服务器加载一次,而且可以在不同请求之间保持服务(例如一次数据库连接)。与之相反,CGI脚本是短暂的、瞬态的。每一次对CGI脚本的请求,都会使Web服务器加载并执行该脚本。一旦这个CGI脚本运行结束,它就会被从内存中清除,然后将结果返回到客户端。CGI脚本的每一次使用,都会造成程序初始化过程(例如连接数据库)的重复执行。

■servlet是与平台无关的。如前所述,servlet是用Java编写的,它自然也继承了Java的平台无关性。

■servlet是可扩展的。由于servlet是用Java编写的,它就具备了Java所能带来的所有优点。Java是健壮的、面向对象的编程语言,它很容易扩展以适应你的需求。servlet自然也具备了这些特征。

■servlet是安全的。从外界调用一个servlet的惟一方法就是通过Web服务器。这提供了高水平的安全性保障,尤其是在你的Web服务器有防火墙保护的时候。

■setvlet可以在多种多样的客户机上使用。由于servlet是用Java编写的,所以你可以很方便地在HTML中使用它们,就像你使用applet一样。在本书中您将看到这一点。 6、什么是servlet

servlet可以被认为是服务器端的applet。servlet被Web服务器加载和执行,就如同applet被浏览器加载和执行一样。servlet从客户端(通过Web服务器)接收请求,执行某种作业,然后返回结果。

使用servlet的基本流程如下:

·客户端(很可能是Web浏览器)通过HTTP提出请求。

·Web服务器接收该请求并将其发给servlet。如果这个servlet尚未被加载,Web服务器将把它加载到Java虚拟机并且执行它。 ·servlet将接收该HTTP请求并执行某种处理。 ·servlet将向Web服务器返回应答。

·Web服务器将从servlet收到的应答发送给客户端。

由于servlet是在服务器上执行,通常与applet相关的安全性的问题并不需实现。servlet

3.调用init初始化servlet实例,

2.调用service方法,传递一个请求和响应对象

容器要移除一个servlet,调用servlet的destroy方法结束该servlet 2.简述动作和response.sendRedirect()的异同(5分)

重定向分为两类。一类是客户端重定向,一类是服务器端重定向。客户端重定向可以通过设置特定的HTTP头,或者写javaScirpt脚本实现。 服务器端的重定向方式

服务器的重定向有两种方式,一种是HttpServletResponse的sendRedirect()方法,一个是使用RequestDispatcher的forward()方法。 HttpServletResponse.sendRedirect()方法

HttpServletResponse接口定义了可用于转向的sendRedirect方法,这个方法将响应定向到指定的,新的

URL,location

可以是一个绝对的

URL,如

response.sendRedirect(“http://java.sun.com”)也可以使用相对的URL location可以是一个绝对的URL,如response.sendRedirect(”http://java.sun.com”)也可以使用相对的URL。如果location以“/”开头,则容器认为相对于当前Web应用的根,否则,容器将解析为相对于当前请求的URL。这种重定向的方法,将导致客户端浏览器的请求URL跳转。从浏览器中的地址栏中可以看到新的URL地址,作用类似于上面设置HTTP响应头信息的实现。 RequestDispatcher.forward()方法

RequestDispatcher是一个Web资源的包装器,可以用来把当前request传递到该资源,或者把新的资源包括到当前响应中。RequestDispatcher接口中定义了两个方法,参见如下代码:

public interface RequestDispatcher {

void forward(ServletRequest request, ServletResponse response); void include(ServletRequest request, ServletResponse response); }

forward()方法将当前的request和response重定向到该RequestDispacher指定的资源。这在实际项目中大量使用,因为完成一个业务操作往往需要跨越多个步骤,每一步骤完成相应的处理后,转向到下一个步骤。比如,通常业务处理在Servlet中处理,处理的结果转向到一个JSP页面进行显示。这样看起来类似于Servlet链的功能,但是还有一些区别。一个RequestDispatcher对象可以把请求发送到任意一个服务器资源,而不仅仅是另外一个Servlet。 include()方法将把Request Dispatcher资源的输出包含到当前输出中。 注意,只有在尚未向客户端输出响应时才可以调用forward()方法,如果页面缓存不为空,在重定向前将自动清除缓存。否则将抛出一个IllegalStateException异常。 如何得到RequestDispatcher

有三种方法可以得到Request Dispatcher对象。

1.javax.servlet. ServletRequest的getRequestDispatcher(String path)方法,其中path可以是相对路径,但不能越出当前Servlet上下文。如果path以“/”开头,则解析为相对于当前

上下文的根。

2.javax.servlet. ServletContext的getRequestDispatcher(String path)方法,其中path必须以“/”开头,路径相对于当前的Servlet上下文。可以调用ServletContext的getContext(String uripath)得到另一个Servlet上下文,并可以转向到外部上下文的一个服务器资源链接。 3.使用javax.servlet. ServletContext的getNamedDispatcher(String name)得到名为name的一个Web资源,包括Servlet和JSP页面。这个资源的名字在Web应用部署描述文件web.xml中指定。

这三种方法的使用有细微的差别。比如,下面是一个应用的配置文件web.xml:

FirstServlet

org. javaresearch.redirecttest.ServletOne

SecondServlet

org.javaresearch. redirecttest.ServletTwo

FirstServlet /servlet/firstservlet/

SecondServlet /servlet/secondservlet/

其中定义了两个Servlet,名字分别为FirstServlet和SecondServlet,对应的类分别为org.javaresearch. redirecttest.ServletOne和org. javaresearch.redirecttest.ServletTwo。可以在浏览器中通过类似于下面的链接访问: http://localhost:8080/servlet/firstservlet/

使用1中方法,例如在firstservlet可以写入下面的代码:

RequestDispatcher rd = request.getRequestDispatcher(”secondservlet”); rd.forward(request, response);

此时控制权将转向到第二个Servlet了。

使用2中的方法,可以从Servlet Context中得到RequestDispatcher代码如下: RequestDispatcher rd = getServletContext().getRequest Dispatcher(”/servlet/secondservlet”); rd.forward(request, response);

使用3中的方法,从上面的web. xml配置文件可以看到定义了两个Servlet,名字分别为FirstServlet和SecondServlet,所以可以得到命名的Dispatcher:

RequestDispatcher rd = getServletContext().getNamedDispatcher(”SecondServlet”); rd.forward(request, response);

这样也可以重定向到SecondServlet了。 JSP页面中的重定向

JSP在解析后编译为一个Servlet运行,所以在JSP中也可以使用上面的重定向代码,并且,JSP还提供了更便利的操作,如下:

JSP页面执行到这儿,将终止当前的处理,将控制权交由nextpage.jsp。 如何选择

RequestDispatcher.forward()方法和HttpServletResponse.sendRedirect()方法的区别是:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用Request Dispatcher.forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用HttpServletResponse.sendRequest()方法。

3.。用图形画出一个web.应用程序部署在Tomcat5的基本目录结构,说明每个目录下 保存哪些文件。(8分)

4.提交表单请求时,post和get有哪些区别? (5分)

以Get方式请求方式传输,所带参数附加在请求URL后直接传给服务器,并可以从服务器端的QUERY_STRING这个环境变量中读取;如果以POST请求方式传输则参数被打包在数据包中传给服务器

使用Post方法数据由标准的输入设备读入,使用Get方法,数据由CGI变量Query_STRING传递给表单数据处理程序,即附加在请求地址的后面,在浏览器的地址栏可看到servlet会自动将以上两种方法得到的数据进行处理,对于两种方法servlet处理方法是一样的,用户只要调用HttpServletRequest的getParameter()方法,给出变量名称即可取出变量的值。 5.。MVC的各个部分都由那些技术来实现?(9分)

MVC是Model-View-Controller的简写。”Model” 代表的是应用的业务逻辑(通过JavaBean,EJB组件实现), “View” 是应用的表示面(由JSP页面产生),”Controller” 是提供应用的处理过程控制(一般是一个Servlet),通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。

6. 什么叫DTO,简述基于struts的应用在模型层和视图层之间加入DTO的优点 (8分)

Data access object 数据访问对象

主要用来封装对数据库的访问,通过她可以把POJO持久化PO,用PO组装出来的VO,DTO

PO :persistent Object持久对象,可以看成与数据库中的表相映射的java对象,最简单的PO就是对应数据库中某个表的一条记录,多个记录可以用PO的集合。PO应该不包含任何对数据库的操作。

VO:value object值对象 通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已,但应是抽象出的的业务对象,可以和表对应,也可以不

DAO:data access object数据访问对象,此对象用于访问数据库,通常与PO结合使用,DAO中包含了各种数据库的操作方法,通过它的方法,结合PO对数据库进行相关的操作 BO:business object 业务对象,封装业务逻辑的java对象,通过调用DAO方法,结合PO,VO进行业务操作

POJO:plain ordinary java object 简单屋规则java对象 9/如何解决Java中的中文乱码问题? 一、中文问题的来源

计算机最初的操作系统支持的编码是单字节的字符编码,于是,在计算机中一切处理程序最初都是以单字节编码的英文为准进行处理。随着计算机的发展,为了适应世界其它民族的语言(当然包括我们的汉字),人们提出了UNICODE编码,它采用双字节编码,兼容英文字符和其它民族的双字节字符编码,所以,目前,大多数国际性的软件内部均采用UNICODE编码,在软件运行时,它获得本地支持系统(多数时间是操作系统)默认支持的编码格式,然后再将软件内部的UNICODE转化为本地系统默认支持的格式显示出来。Java的JDK和JVM即是如此,我这里说的JDK是指国际版的JDK,我们大多数程序员使用的是国际化的JDK版本,以下所有的JDK均指国际化的JDK版本。我们的汉字是双字节编码语言,为了能让计算机处理中文,我们自己制定的gb2312、GBK、GBK2K等标准以适应计算机处理的需求。所以,大部分的操作系统为了适应我们处理中文的需求,均定制有中文操作系统,它们采用的是GBK,GB2312编码格式以正确显示我们的汉字。如:中文Win2K默认采用的是GBK编码显示,在中文WIN2k中保存文件时默认采用的保存文件的编码格式也是GBK的,即,所有在中文WIN2K中保存的文件它的内部编码默认均采用GBK编码,注意:GBK是在GB2312基础上扩充来的。

由于Java语言内部采用UNICODE编码,所以在JAVA程序运行时,就存在着一个从UNICODE编码和对应的操作系统及浏览器支持的编码格式转换输入、输出的问题,这个转换过程有着一系列的步骤,如果其中任何一步出错,则显示出来的汉字就会出是乱码,这就是我们常见的JAVA中文问题。

同时,Java是一个跨平台的编程语言,也即我们编写的程序不仅能在中文windows上运行,也能在中文Linux等系统上运行,同时也要求能在英文等系统上运行(我们经常看到有人把

在中文win2k上编写的JAVA程序,移植到英文Linux上运行)。这种移植操作也会带来中文问题。

还有,有人使用英文的操作系统和英文的IE等浏览器,来运行带中文字符的程序和浏览中文网页,它们本身就不支持中文,也会带来中文问题。

有,几乎所有的浏览器默认在传递参数时都是以UTF-8编码格式来传递,而不是按中文编码传递,所以,传递中文参数时也会有问题,从而带来乱码现象。

总之,以上几个方面是JAVA中的中文问题的主要来源,我们把以上原因造成的程序不能正确运行而产生的问题称作:JAVA中文问题。 2、JAVA编码转换的详细过程 我们常见的JAVA程序包括以下类别:

*直接在console上运行的类(包括可视化界面的类) *JSP代码类(注:JSP是Servlets类的变型) *Servelets类 *EJB类

*其它不可以直接运行的支持类

这些类文件中,都有可能含有中文字符串,并且我们常用前三类JAVA程序和用户直接交互,用于输出和输入字符,如:我们在JSP和Servlet中得到客户端送来的字符,这些字符也包括中文字符。无论这些JAVA类的作用如何,这些JAVA程序的生命周期都是这样的: *编程人员在一定的操作系统上选择一个合适的编辑软件来实现源程序代码并以.java扩展名保存在操作系统中,例如我们在中文win2k中用记事本编辑一个java源程序; *编程人员用JDK中的javac.exe来编译这些源代码,形成.class类(JSP文件是由容器调用JDK来编译的);

*直接运行这些类或将这些类布署到WEB容器中去运行,并输出结果。

那么,在这些过程中,JDK和JVM是如何将这些文件如何编码和解码并运行的呢? 这里,我们以中文win2k操作系统为例说明JAVA类是如何来编码和被解码的。

第一步,我们在中文win2k中用编辑软件如记事本编写一个Java源程序文件(包括以上五类JAVA程序),程序文件在保存时默认采用了操作系统默认支持GBK编码格式(操作系统默认支持的格式为file.encoding格式)形成了一个.java文件,也即,java程序在被编译前,我们的JAVA源程序文件是采用操作系统默认支持的file.encoding编码格式保存的,java源程序中含有中文信息字符和英文程序代码;要查看系统的file.encoding参数,可以用以下代码: public class ShowSystemDefaultEncoding { public static void main(String[] args) {

String encoding = System.getProperty(”file.encoding”); System.out.println(encoding); }}

第二步,我们用JDK的javac.exe文件编译我们的Java源程序,由于JDK是国际版的,在编译的时候,如果我们没有用-encoding参数指定我们的JAVA源程序的编码格式,则

javac.exe首先获得我们操作系统默认采用的编码格式,也即在编译java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数(它保存的就是操作系统默认的编码格式,如WIN2k,它的值为GBK),然后JDK就把我们的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格式放入内存中。然后,javac把转换后的unicode格式的文件进行编译成.class类文件,此时.class文件是UNICODE编码的,它暂放在内存中,紧接着,JDK将此以UNICODE编码的编译后的class文件保存到我们的操作系统中形成我们见到的.class文件。对我们来说,我们最终获得的.class文件是内容以UNICODE编码格式保存的类文件,它内部包含我们源程序中的中文字符串,只不过此时它己经由file.encoding格式转化为UNICODE格式了。

这一步中,对于JSP源程序文件是不同的,对于JSP,这个过程是这样的:即WEB容器调用JSP编译器,JSP编译器先查看JSP文件中是否设置有文件编码格式,如果JSP文件中没有设置JSP文件的编码格式,则JSP编译器调用JDK先把JSP文件用JVM默认的字符编码格式(也即WEB容器所在的操作系统的默认的file.encoding)转化为临时的Servlet类,然后再把它编译成UNICODE格式的class类,并保存在临时文件夹中。如:在中文win2k上,WEB容器就把JSP文件从GBK编码格式转化为UNICODE格式,然后编译成临时保存的Servlet类,以响应用户的请求。 第三步,运行第二步编译出来的类,分为三种情况: A、 直接在console上运行的类

B、 EJB类和不可以直接运行的支持类(如JavaBean类) C、 JSP代码和Servlet类 D、 JAVA程序和数据库之间 下面我们分这四种情况来看。 A、直接在console上运行的类

这种情况,运行该类首先需要JVM支持,即操作系统中必须安装有JRE。运行过程是这样的:首先java启动JVM,此时JVM读出操作系统中保存的class文件并把内容读入内存中,此时内存中为UNICODE格式的class类,然后JVM运行它,如果此时此类需要接收用户输入,则类会默认用file.encoding编码格式对用户输入的串进行编码并转化为unicode保存入内存(用户可以设置输入流的编码格式)。程序运行后,产生的字符串(UNICODE编码的)再回交给JVM,最后JRE把此字符串再转化为file.encoding格式(用户可以设置输出流的编码格式)传递给操作系统显示接口并输出到界面上。

以上每一步的转化都需要正确的编码格式转化,才能最终不出现乱码现象。 B、EJB类和不可以直接运行的支持类(如JavaBean类)

由于EJB类和不可以直接运行的支持类,它们一般不与用户直接交互输入和输出,它们常常与其它的类进行交互输入和输出,所以它们在第二步被编译后,就形成了内容是UNICODE编码的类保存在操作系统中了,以后只要它与其它的类之间的交互在参数传递过程中没有丢失,则它就会正确的运行。 C、JSP代码和Servlet类

经过第二步后,JSP文件也被转化为Servlets类文件,只不过它不像标准的Servlets一校存在于classes目录中,它存在于WEB容器的临时目录中,故这一步中我们也把它做为Servlets来看。

对于Servlets,客户端请求它时,WEB容器调用它的JVM来运行Servlet,首先,JVM把Servlet的class类从系统中读出并装入内存中,内存中是以UNICODE编码的Servlet类的代码,然后JVM在内存中运行该Servlet类,如果Servlet在运行的过程中,需要接受从客户端传来的字符如:表单输入的值和URL中传入的值,此时如果程序中没有设定接受参数时采用的编码格式,则WEB容器会默认采用ISO-8859-1编码格式来接受传入的值并在JVM中转化为UNICODE格式的保存在WEB容器的内存中。Servlet运行后生成输出,输出的字符串是UNICODE格式的,紧接着,容器将Servlet运行产生的UNICODE格式的串(如html语法,用户输出的串等)直接发送到客户端浏览器上并输出给用户,如果此时指定了发送时输出的编码格式,则按指定的编码格式输出到浏览器上,如果没有指定,则默认按ISO-8859-1编码发送到客户的浏览器上。 D、Java程序和数据库之间

对于几乎所有数据库的JDBC驱动程序,默认的在JAVA程序和数据库之间传递数据都是以ISO-8859-1为默认编码格式的,所以,我们的程序在向数据库内存储包含中文的数据时,JDBC首先是把程序内部的UNICODE编码格式的数据转化为ISO-8859-1的格式,然后传递到数据库中,在数据库保存数据时,它默认即以ISO-8859-1保存,所以,这是为什么我们常常在数据库中读出的中文数据是乱码。 3、分析常见的JAVA中文问题几个必须清楚的原则

首先,经过上面的详细分析,我们可以清晰地看到,任何JAVA程序的生命期中,其编码转换的关键过程是在于:最初编译成class文件的转码和最终向用户输出的转码过程。 其次,我们必须了解JAVA在编译时支持的、常用的编码格式有以下几种: *ISO-8859-1,8-bit, 同8859_1,ISO-8859-1,ISO_8859_1等编码 *Cp1252,美国英语编码,同ANSI标准编码 *UTF-8,同unicode编码

*GB2312,同gb2312-80,gb2312-1980等编码 *GBK , 同MS936,它是gb2312的扩充

及其它的编码,如韩文、日文、繁体中文等。同时,我们要注意这些编码间的兼容关体系如下:

unicode和UTF-8编码是一一对应的关系。GB2312可以认为是GBK的子集,即GBK编码是在gb2312上扩展来的。同时,GBK编码包含了20902个汉字,编码范围为:0×8140-0xfefe,所有的字符可以一一对应到UNICODE2.0中来。

再次,对于放在操作系统中的.java源程序文件,在编译时,我们可以指定它内容的编码格式,具体来说用-encoding来指定。注意:如果源程序中含有中文字符,而你用-encoding指定为其它的编码字符,显然是要出错的。用-encoding指定源文件的编码方式为GBK或gb2312,无论我们在什么系统上编译含有中文字符的JAVA源程序都不会有问题,它都会

正确地将中文转化为UNICODE存储在class文件中。

然后,我们必须清楚,几乎所有的WEB容器在其内部默认的字符编码格式都是以ISO-8859-1为默认值的,同时,几乎所有的浏览器在传递参数时都是默认以UTF-8的方式来传递参数的。所以,虽然我们的Java源文件在出入口的地方指定了正确的编码方式,但其在容器内部运行时还是以ISO-8859-1来处理的。 4、中文问题的分类及其建议最优解决办法

了解以上JAVA处理文件的原理之后,我们就可以提出了一套建议最优的解决汉字问题的办法。

我们的目标是:我们在中文系统中编辑的含有中文字符串或进行中文处理的JAVA源程序经编译后可以移值到任何其它的操作系统中正确运行,或拿到其它操作系统中编译后能正确运行,能正确地传递中文和英文参数,能正确地和数据库交流中英文字符串。

我们的具体思路是:在JAVA程序转码的入口和出口及JAVA程序同用户有输入输出转换的地方限制编码方法使之正确即可。 具体解决办法如下:

1、 针对直接在console上运行的类

对于这种情况,我们建议在程序编写时,如果需要从用户端接收用户的可能含有中文的输入或含有中文的输出,程序中应该采用字符流来处理输入和输出,具体来说,应用以下面向字符型节点流类型:

对文件:FileReader,FileWrieter

其字节型节点流类型为:FileInputStream,FileOutputStream 对内存(数组):CharArrayReader,CharArrayWriter

其字节型节点流类型为:ByteArrayInputStream,ByteArrayOutputStream 对内存(字符串):StringReader,StringWriter 对管道:PipedReader,PipedWriter

其字节型节点流类型为:PipedInputStream,PipedOutputStream 同时,应该用以下面向字符型处理流来处理输入和输出: BufferedWriter,BufferedReader

其字节型的处理流为:BufferedInputeStream,BufferedOutputStream InputStreamReader,OutputStreamWriter

其字节型的处理流为:DataInputStream,DataOutputStream

其中InputStreamReader和InputStreamWriter用于将字节流按照指定的字符编码集转换到字符流,如:

InputStreamReader in = new InputStreamReader(System.in,”GB2312″); OutputStreamWriter out = new OutputStreamWriter (System.out,”GB2312″); 例如:采用如下的示例JAVA编码就达到了要求: //Read.java import java.io.*;

public class Read {

public static void main(String[] args) throws IOException {

String str = ” 中文测试,这是内部硬编码的串”+” test english character”; String strin= “”; BufferedReader BufferedWriter stdout.write(”请输入:”); stdout.flush();

strin = stdin.readLine();

stdout.write(”这是从用户输入的串:”+strin); stdout.write(str); stdout.flush(); }}

同时,在编译程序时,我们用以下方式来进行: javac -encoding gb2312 Read.java

2、 针对EJB类和不可以直接运行的支持类(如JavaBean类)

由于这种类它们本身被其它的类调用,不直接与用户交互,故对这种类来说,我们的建议的处理方式是内部程序中应该采用字符流来处理程序内部的中文字符串(具体如上面一节中一样),同时,在编译类时用-encoding gb2312参数指示源文件是中文格式编码的即可。 3、 针对Servlet类

针对Servlet,我们建议用以下方法:

在编译Servlet类的源程序时,用-encoding指定编码为GBK或GB2312,且在向用户输出时的编码部分用response对象的setContentType(”text/html;charset=GBK”);或gb2312来设置输出编码格式,同样在接收用户输入时,我们用request.setCharacterEncoding(”GB2312″);这样无论我们的servlet类移植到什么操作系统中,只有客户端的浏览器支持中文显示,就可以正确显示。如下是一个正确的示例: //HelloWorld.java package hello; import java.io.*; import javax.servlet.*; import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {

public void init() throws ServletException { }

public void doGet(HttpServletRequest request, HttpServletResponse response) throws

stdin stdout

= =

new new

BufferedReader(new BufferedWriter(new

InputStreamReader(System.in,”gb2312″)); //设置输入接口按中文编码 OutputStreamWriter(System.out,”gb2312″)); //设置输出接口按中文编码

IOException, ServletException {

request.setCharacterEncoding(”GB2312″); //设置输入编码格式

response.setContentType(”text/html;charset=GB2312″); //设置输出编码格式 PrintWriter out = response.getWriter(); //建议使用PrintWriter输出 out.println(”


”);

out.println(”Hello World! This is created by Servlet!测试中文!”); out.println(”


”); }

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

request.setCharacterEncoding(”GB2312″); //设置输入编码格式

response.setContentType(”text/html;charset=GB2312″); //设置输出编码格式 String name = request.getParameter(”name”); String id = request.getParameter(”id”); if(name==null) name=”\if(id==null) id=”\

PrintWriter out = response.getWriter(); //建议使用PrintWriter输出 out.println(”


”);

out.println(”你传入的中文字串是:” + name); out.println(”


你输入的id是:” + id); out.println(”
”); }

public void destroy() { } }

请用javac -encoding gb2312 HelloWorld.java来编译此程序。 测试此Servlet的程序如下所示:

<%@page contentType=”text/html; charset=gb2312″%> <%request.setCharacterEncoding(”GB2312″);%>

Top