Web服务器的作用
用于实时接收浏览器的请求,并将相应结果回送给浏览器。
对于静态 html 文件内容的访问请求,Web服务器 可以直接从文件系统中读取文件内容返回给浏览器。
但对于要根据某些条件去动态创建内容的访问请求,Web服务器本身不具备处理这种请求的能力,
而是需要专门的Web服务器程序模块来处理
因此,动态网页内容的创建过程包含两个步骤:首先使用某种编程语言写出相应的动态网页程序;
然后由一个专门的Web服务器程序模块来解释执行该动态网页程序。
引擎是什么?它是怎么和动态网页进行交互的?
专门解释执行某种动态网页的Web服务器程序模块习惯上被称之为引擎,如ASP引擎、JSP引擎、Servlet引擎。
引擎以Web服务器的扩张模块的形式提供的。通常由那些提供动态网页解决方案的公司开发的。引擎要与动态网页进行通信,必须要提供一些API(Application Programming Interface编程接口)给动态网页程序使用。
引擎提供的API有哪些作用?
将请求的相关信息传递给动态网页,例如访问者的IP地址和请求消息头。
将动态网页程序产生的结果传递给引擎。
引擎的作用?
只有引擎才会与浏览器直接进行信息交互。动态网页程序不直接与浏览器进行信息交交互,他只与引擎进行信息的交互,动态网页程序需要一个专门的Web服务器程序模块来解释执行(引擎)。
Web容器是什么?
Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,他不能独立运行。
Servlet与Servlet引擎之间的关系就如Applet与Web浏览器之间的关系一样。
Servlet的运行完全由Servlet引擎控制来调度。
Servlet引擎是一种容器程序,他负责管理维护所有的Servlet对象的生命周期。因此也被称之为Web容器或Servlet容器。
Web服务器与Web容器的区别?
Web容器也就是某种引擎,引擎以Web服务器的扩张模块的形式提供的。Web容器是Web服务器的一种能力,是他的一个模块。
什么是Servlet
Servlet技术是Sun公司提供一种实现动态网页的解决方案,它是基于java编程语言的Web服务器端编程技术。
主要用于在Web服务器端获得客户端的访问请求信息和动态生成客户端的响应消息。Servlet技术也是JSP技术的基础。
ServletConfig接口
Servlet引擎将代表Servlet容器的对象和Servlet的配置参数信息一并封装到一个成为ServletConfig对象中
并在初始化Servlet实例对象(通过init(ServletConfig config)方法)时传递给该Servlet。
ServletConfig接口则定义了ServletConfig对象对外提供的方法。
GenericServlet类实现ServletConfig接口目的
虽然可以Servlet.getServletConfig.ServletConfig方法。
为了Servlet程序更方便的访问ServletConfig的各个方法。
GenericServlet与HttpServlet类
GenericServlet是一个实现了Servlet接口的基本特征和功能的基类
HttpServlet是GenericServlet的子类,他提供了处理HTTP协议的基本架构。
如果一个Servlet要充分利用HTTP协议的功能,就应该继承HttpServlet。
所以HttpServlet不仅可以调用内部新定义的方法还可以调用Servlet、GenericServlet、ServletConfig类中定义的方法。
区分回调方法和工具方法
专门用于系统调用的方法被称之为回调方法,也就是会过来被系统调用的方法。
GenericServlet和HttpServlet类中的回调方法是供容器调用的方法,可以在子类中进行覆盖,但是不能在程序代码块中直接调用。
GenericServlet和HttpServlet类中处理有回调方法还有工具方法,编程人员可以在程序代码块中直接调用去完成某种任务。
如GenericServlet中的log方法用于将一条信息记录到日志文件中。
ServletContext类
每一给Web应用程序都是一个独立的Servlet容器,每一个应用程序分别用一个ServletContext对象表示。
ServletContext接口定义了ServletContext对象对外提供的方法,Servlet程序通过这些方法与Servlet容器进行通信。
Servlet引擎为每一个W恶补、应用程序都创建一个对应的ServletContext对象。
ServletContext对象被包含在ServletConfig对象中。
关于server.xml和web.xml
在server.xml文件和web.xml文件中都可以为某个Web应用程序设置若干个初始化参数。
比如,如果一个Web应用程序中的多个Servlet程序都要输出当前站点的公司名称,
而这个Web应用程序可能会交给多个公司使用,那么我们可以把公司名称作为初始化参数进行设置,
那么只需要在web.xml文件中修改公司名称,所有的Servlet程序输出的公司名称就会随之更改。
如果要在server.xml文件中为某个web应用程序设置初始化信息,
需要在该web应用程序所对应的<Context>元素增加<Parameter>子元素。
ServletContext记录日志
ServletContext接口中定义了两个重载的log方法类记录日志。
GenericServlet类中也定义了两个log方法。他们分别调用ServletContext对象中对应的log方法。
log方法记录日志文件名称和存储路径因web服务器而定,
Tomcat中的日志文件的存储路径和server.xml文件中进行设置。
<Logger className="" directory="" prefix="" suffix="" timestamp="true">.
获取虚拟路径所映射的本地路径:
ServletContext接口中定义了一个getRealPath()方法,用于返回某个虚拟路径所映射的本地文件系统路径。
如果传递给getRealPath方法的路径字符串以"/"作为起始字符,这个“/”代表的是当前Web应用程序的根目录,
要返回Web应用程序的根目录所映射的本地文件路径系统,
传递给getRealPath()方法的路径字符传中可以只有一个“/”字符,也可以是一个空字符串。
HttpServletResponse对象
如果一个网页查看源文件的中文没有乱码,而显示是乱码,可能是因为浏览器显示网页的字符编码有问题。
Java程序的字符文本在内存中是以unicode编码的形式存在的
ServletResponse对象的getWriter方法返回的PrintWriter对象默认使用ISO8859-1字符编码进行unicode字符串到字节数组的转换。
然而ISO8859-1字符集里又没有中文字符,Unicode编码的中文被被转换成无效的字符编码后输出给客户端。
可以使用 setCharacterEncoding、setContentType和setLocale 等方法指定 ServletResponse.getWriter 对象所使用的字符编码。
response控制定时刷新
让浏览器定时刷新网页或跳转到其他页面。HTTP协议中定义了一个Refresh头字段。
response.setHeader("Refresh", "2;URL=/zhangxiaoxiangbook1/index.jsp");
response.setHeader("Refresh", "2");
禁止浏览器缓存当前文档内容
有三个HTTP响应头字段都可以禁止浏览器缓存当前页面。
response.setDateHeader("Expires",0);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragam","no-cache");
不是所有的浏览器都能完全支持这三个响应头。最好是同时使用。
使用<meta>标签模拟响应消息头。
利用HTTP消息的响应头字段,可以让浏览器完成各种有用的功能,例如不想让浏览器缓存一个内容经常要被更新的静态HTML页面,那么可以在他的<head></head>标签之间增加如下三条语句:
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
然而,如果在网页正文增加如下语句:<meta http-equiv="Refresh" content="0;url=http://www.baidu.com">
当浏览器打开这个网页文档之后,将立即跳转到 www.baidu.com 站点的首页。
<meta>标签的一个最常见的作用就是用来设置当前网页的字符编码。当我们访问中文网站的静态的页面时候,
只要查看他的源文件基本上都包含如下<meta>语句:<meta http-equiv="content-type" content="text/html; charset=UTF-8">
他会暗示浏览器用什么编码显示网页。每个静态中文HTML页面的开始出都应该增加一条<meta>语句来设置页面的字符集编码,已经成为设计HTML页面的指导性原则和验收标准。
ServletResponse输出方法
ServletResponse是Servlet程序和Servlet引擎进行通信的接口,Servlet程序通过ServletResponse对象将响应正文传递给Servlet引擎,再由Servlet引擎将响应正文输出到客户端。
如果两个模块之间要传输大量的数据。最好是以输入或者输出流来作为两个模块传递数据的接口方式。
response.getOutputStream 方法返回的字节输出流对象类型为ServletOutputStream,ServletOutputStream是OutputStream的子类,它可以直接输出字节数组中的二进制数据。如果Servlet要输出二进制格式的响应正文,就应该使用此方法。
response.getWriter 方法将Servlet引擎的数据缓冲区包装成PrintWriter类型的字符输出流对象后返回。PrintWriter对象可以直接输出字符文本内容,所以他专用来输出内容全为文本字符的网页文档。
以上2个方法不能同时使用。
最好在使用PrintWriter或ServletOutputStream对象之前调用HTTP的响应头信息的方法,特别要注意设置MIME类型的Content-Type头字段。
最后要注意的是,Servlet的service方法结束后,Servlet 引擎将检测getWriter或getOutputStream方法的输出流对象是否已经调用close方法,如果没有调用,service引擎会自动关闭。最好还是开发人员自己关闭,以便尽快的释放相关资源。
Servlet程序中可以多次调用HttpServletResponse对象的getWriter方法吗?如可以是否是同一个对象?
可以,是同一个对象。ServletOutputStream也是一样。
PrintWriter.print方法和PrintWriter.println方法有什么区别?
在html显示的时候没有什么区别。只是查看源文件的时候,有如果是PrintWriter.println他会自动换行,以便员阅读和理解。
输出缓冲区
Servlet程序输出的HTTP消息的响应正文不是直接发送到客户端,而是首先被写到了Servlet引擎提供一种输出缓冲区中。
这个缓冲区被填满或者Servlet程序已经写入了所有响应内容,缓冲区中的内容才会被Servlet引擎发送到客户端。
使用缓冲区那些好处?
Servlet引擎就可以将响应状态行、各响应头和响应正文严格按照HTTP消息的位置顺序进行调整后再输出到客户端,
特别是可以自动对Context-Length头字段进行设置和调整,如果不使用输出缓冲区,
Servlet请亲无法在向客户端输出响应正文之前知道响应正文的大小,也就不能自动设置Context-Length头字段。
如果在提交响应到客户端时,输出缓冲区载入的内容只是全部响应的一部分,
那么Servlet引擎将无法再计算Context-Length头字段,
他将使用HTTP1.1的chunked编码方式(通过设置Transfer-Encoding头字段来指定)传输响应内容,
这样就不用设置Context-Length头字段了。
ServletResponse定义了若干输出缓冲区有关的方法:
- setBufferSize() 用于设置期望的输出缓冲区大小,Servlet引擎实际使用的缓冲区不一定等于该值,但不会小于他。
- getBufferzsize()用于返回Servlet引擎实际使用的缓冲区大小。
- flushBuffer()用于将缓冲区的内容强制输出到客户端,
- reset()用于清空输出缓冲区中的内容,以及设置的响应状态码和各个响应头。如果当前响应已经向客户端输出过部分内容,将会抛出异常。要注意区别flushBuffer(),flushBuffer()将缓冲区的内容提前交给客户端后腾出缓冲区空间,reset()是将缓冲区的内容作废后腾出缓冲区空间。
- inCommitted()判断是否已经提交部分响应内容到客户端,如果已经提交返回true,反之false。
JSP的基本语法
JSP表达式(expression)
JSP表达式(expression)提供了将一个java变量或表达式的计算结果到客户端的简化方式,
jsp表达式中的变量或表达式后面不能有分号(;),jsp表达式被翻译成Servlet程序中的一条out.print(...)语句。
如<%=new java.util.Date()%>翻译成Servlet程序中的一条out.print(new java.util.Date())语句
JSP脚本(scriptlet)
JSP脚本(scriptlet)是嵌套在<%和%>之间的一条或多条java程序代码。
在jsp脚本片段中,可以实现定义变量、执行基本的程序运算、调用其他java类等普通java程序所能实现的功能。
在jsp脚本片段中必须符合java语法要求的程序代码。在一个jsp页面中可以有多个脚本片段。
注意:单个脚本片段中的java语句可以不是完整的,但是多个脚本组合后的结果必须是完整的java语句吗,例如条件语句或循环控制语句。
因为所有的脚本片段中的java代码将原封不动的搬进由jsp页面所翻译成的Servlet的_jspService方法中。
JSP声明(declaration)
JSP页面最终会编译成Servlet程序。在脚本片段声明的变量是局部变量。
如果在脚本中定义方法,也会被搬进_jspService()中,这样就会变成方法里嵌套方法的错误。
而jsp声明就是解决这样的错误,他将代码封装子在<%!和%>中,他写的代码将插在_jspService()之外。
jsp声明只能定义静态代码块,方法和变量的定义.由于jsp内置对象的作用范围只限于Servlet的_jspService()方法内。
jsp指定(directive):
page、include、taglib.
out对象
如果out.println语句位于response.getWriter().println语句前,但是输出的内容却位于后者输出的内容之后
这是因为out.println语句只是把内容写入到out对象的缓冲区中,知道整个jsp页面结束时,
out对象才把他的缓冲区里的内容真正写到Servlet引擎提供的缓冲区中,
而response.getWriter().println语句则是直接把内容写到Servlet引擎提供的缓冲区中。
注意:在如下jsp中
<%
ServletOutputStream sos=response.getOutputStream();
sos.println("dddddd");
%>
如果在此jsp中的最开始的“<%”前面或者最后的“%>”后面输入了任意字符,例如在最后的“%>”后面输入了一个回车键,用浏览器中显示,就会报异常。
因为位于jsp脚本元素之外的任何字符文本,在jsp页面所翻译成的Servlet源文件中都要被转换成以这些字符文本作为参数的out.write语句输出到客户端,
即使在jsp脚本元素之外输入的是一个回车符,它也将被转换成一条out.write("\r\t");语句。
由于只要向out对象中写入了内容,它就会在jsp页面结束时调用ServletResponse.getWriter方法,
这就与程序中调用的response.getOutputStream方法发生了冲突。
<%
RequestDispatch rd = application.getRequestDispatch("test.html");
rd.forword(request,response);
%>
如果在此jsp中的最开始的“<%”前面或者最后的“%>”后面输入了任意字符,例如在最后的“%>”后面输入了一个回车键,用浏览器中显示,就会报异常。
因为客户端对静态HTML文件和图片的访问请求都是由Tomcat的缺省Servlet开处理,缺省的Servlet首先检查是否已经调用过当前HttpServletResponse对象的getWriter对象,
如果调用,则使用getWriter方法返回的PrintWriter对象输出HTML文件中内容,否则,缺省的Servlet调用getOutputStream方法返回的servOutputStream对象来将静态HTML文件中的内容按按字节流的形式原封不动地输出到客户端。
上面的jsp文件将请求转发给test.html页面时,还没有真正调用过ServletResponse.getWriter方法,缺省的Servlet将调用ServletResponse.getOutputStream方法,
缺省的Servlet处理完之后,程序又回到jsp页面中继续执行,因为jsp页面随后又向out对象中写入了内容(回车符造成的“\r\t”)
所以jsp页面结束时又将调用ServletResponse.getWriter方法,这就造成冲突。
如果在jsp页面的jsp脚本片段中的第一句前面增加如下一条语句:response.getWriter();
pageContext对象
pageContext对象是javax.servlet.jsp.PageContext类的实例对象,
pageContext对象封装了当前jsp页面的运行信息,他提供了返回jsp页面的其他隐式对象的方法。
获得其他隐式对象:
- getException方法返回exception隐式对象;
- getPage方法返回page隐式对象;
- getRequest方法返回request隐式对象;
- getResponse方法返回response隐式对象;
- getServletConfig方法返回config隐式对象;
- getServletContext方法返回application隐式对象;
- getSession方法返回session隐式对象;
- getOut方法返回out隐式对象;
JSP标签
<jsp:include>标签用于把一个资源的输出内容插入进当前jsp页面的输出内容之中。
<jsp:forword>标签用于把转发给另一个资源。page用来指定请求转发到的资源相对路径。
<jsp:param>标签用于当使用<jsp:include>、<jsp:forword>
标签引入或将请求转发给的资源是一个能动态执行的程序时,例如Servlet和jsp页面,那么还可以使用<jsp:param>标签想这个程序传递参数信息。如:
<jsp:include page ="">
<jsp:param name="" value=""/>
</jsp:include>
脚本元素标签:jsp2.0规范定义了一些标签页面中的脚本片段、jsp声明和jsp表达式,以便这些脚本元素可以采用XML的语法编写:
·<%%>可以代替为<jsp:scriptlet></jsp:scriptlet>
·<%!%>可以代替为<jsp:declaration></jsp:declaration>
·<%=%>可以代替为<jsp:expression></jsp:expression>
指定标签:jsp2.0规范定义了<jsp:directive.directiveType>来代替<% @ directive...%>以便采用XML格式来定义jsp指定。如:
<%@ page import=""%>可代替为<jsp:directive.page import=""/>
JSP中文乱码问题
当jsp引擎要确定某个jsp文件的字符集编码时,首先在web应用程序的部署描述符中查找是否有于jsp文件匹配的<page-encoding>元素设置。如果没有找到则往下找:
page指定的pageEncoding属性--->page指定的contextType属性中查找字符集编码--->使用ISO-8859-1。
在web.xml文件中输入如下代码:
<jsp-config>
<jsp-property-group>
<url-pattern>/jsp/*</url-pattern>
<page-encoding>GB2312</page-encoding>
</jsp-property-group>
</jsp-config>
需要注意的是:web.xml文件中没有声明它所遵循的Servlet规范版本,Tomcat默认它遵循Servlet2.3规范,而jsp-cofig、jsp-proprty-group和page-encoding等元素是在Servlet2.4规范的部署描述文件中新定义的元素,所以上面配置的<jsp-config>元素及其中的内容不会生效。需要声明web.xml文件遵循Servlet2.4规范(可以在文档复制)。
处理get方式提交乱发问题
①String name = request.getParameter("name");
可以使用new String(name.getBytes("ISO-8859-1"),"gbk");
②在Tomcat的server.xml文件中修改,为get方式获取数据添加URIEncoding参数指定utf-8(默认为iso-8859-1):
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8433" URIEcoding="utf-8"/>