一、HTTP协议(超级重要:必须记住)
超文本传输协议
HTTP(Hyper Text Transport Protocol) W3C组织制定的。HTTP协议默认监听80端口
HTTP协议的具体组成:
一、请求部分(客户端向服务器发送的数据)
1、请求行:位于信息的第一行
GET /App1/2.html HTTP/1.1
GET:请求方式(method)。是默认的请求方式。常用的还有POST(引入表单)等。
POST:通过html中的form标签中的属性method指定。
GET /App1/3.html?username=chenlili&password=123 HTTP/1.1
1、提交的数据出现在请求行中。(消息行有长度限制;数据太不安全)
2、 /App1/2.html:访问的资源的
URI(Union Resource Indentity)。
3、http://localhost:8080/App1/login.html:
URL(Union Resource Location)协议+主机地址+资源地
HTTP/1.1:客户端使用的协议
2、请求消息头:从第二行开始,至第一个空行结束。
*Accept: text/html, application/xhtml+xml, */*
浏览器可接受的MIME类型.(文件系统中采用扩展名区分不同的文件的。网络上是用MIME类型来区分
不同的数据、有一定的对应关系(Tomcat\conf\web.xml有)
MIME类型:大类型/具体类型.例如jpg:image/jpeg或者bmp: image/bmp
Accept-Charset:浏览器通过这个头告诉服务器,它支持哪种字符集
*Accept-Encoding:gzip, deflate
浏览器能够进行解码的数据编码方式,比如gzip
Accept-Language:zh-Hans-CN,zh-Hans;q=0.5
浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。 可以在浏览器中进行设置。
Host:localhost:8080
初始URL中的主机和端口
*Referer:www.baidu.com
包含一个URL,取值为当前页面之前的那个页面地址
应用:1.看广告投放效果, 2.防盗链
*Content-Type:application/x-www-form-urlencoded; charset=UTF-8
请求正文内容类型。目前:只有通过表单提交数据,且请求方式是post时,才会出现请求正文内容,才会有该头。
默认值是:application/x-www-form-urlencoded
对应的是<form action="3.html" method="post" enctype="application/x-www-form-urlencoded">
常用可选值:multipart/form-data
If-Modified-Since: Wed, 02 Feb 2011 12:04:56 GMT
利用这个头与服务器的文件进行比对,如果一致,则从缓存中直接读取文件。
User-Agent:浏览器类型.
Content-Length:表示请求正文的长度 ,数据字节长度。
Connection:表示是否需要持久连接。如果服务器看到这里的值为“Keep -Alive”,
或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接)
*****Cookie:这是最重要的请求头信息之一 (会话管理)
Date:Date: Mon, 22 Aug 2011 01:55:39 GMT请求时间GMT
3、请求正文:第一个空行之后的所有内容。
只有通过表单,且请求方式是POST时才能看到正文。
当Content-Type是:application/x-www-form-urlencoded,表单提交的数据表现形式为
username=chenlili&password=321 username和password表单中输入域的name
chenlili和321就是用户输入的数据 多个输入域用&进行分割的。
二、响应部分(服务器向客户端发送的数据)
分为三部分:
1、响应行:位于信息的第一行 HTTP/1.1 200 OK
HTTP/1.1:服务器使用的协议
200:响应码。(预留了500个,目前真正有意义的也就30个左右)常用响应码:
200:一切正常
302/307:临时重定向
304:未修改(缓存)
404:资源不存在
500:服务器内部错误(自己的程序出错了)。
OK:对错误的描述信息。(OK表示一切正常)
2、响应消息头:从第二行开始,至第一个空行结束。
*Location: http://www.it315.org/index.jsp指示新的资源的位置
302+该头:完成是请求的重定向。
public
void doGet(HttpServletRequest request, Http
ServletResponse response)
throws ServletException, IOException {
response.setStatus( 302); //临时重定向响应码
response.setHeader( "Location" , "/day03_00_ResponseHeader/servlet/ResponseHeaderDemo2" );
throws ServletException, IOException {
response.setStatus( 302); //临时重定向响应码
response.setHeader( "Location" , "/day03_00_ResponseHeader/servlet/ResponseHeaderDemo2" );
Server:apache tomcat指示服务器的类型
*Content-Encoding:告知客户端服务器发送的数据采用的编码类型gzip(压缩格式)
//把数据压缩后打给浏览器:节省带宽,增强用户体验
public class ResponseHeaderDemo3 extends Http Servlet {
public void doGet(Http ServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "aaaaaa" ;
//GZIP压缩
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //内存输出流
GZIPOutputStream gout = new GZIPOutputStream(baos);
gout.write(data.getBytes()); //输出---压缩---》 baos 中
gout.close();
byte b[] = baos.toByteArray(); //压缩后的数据
//通知客户端采用编码方式
response.setHeader( "Content-Encoding" , "gzip" );
response.setHeader( "Content-Length" , b. length + "" );
response.getOutputStream().write(b); //把数据打给浏览器
public class ResponseHeaderDemo3 extends Http Servlet {
public void doGet(Http ServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "aaaaaa" ;
//GZIP压缩
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //内存输出流
GZIPOutputStream gout = new GZIPOutputStream(baos);
gout.write(data.getBytes()); //输出---压缩---》 baos 中
gout.close();
byte b[] = baos.toByteArray(); //压缩后的数据
//通知客户端采用编码方式
response.setHeader( "Content-Encoding" , "gzip" );
response.setHeader( "Content-Length" , b. length + "" );
response.getOutputStream().write(b); //把数据打给浏览器
*Content-Length:80 告诉浏览器正文的长度
Content-Language:zh-cn服务发送的文本的语言
*Content-Type:text/html默认的; 告知客户端请求正文的MIME类型
Last-Modified:Tue, 11 Jul 2000 18:23:51 GMT文件的最后修改时间
*Refresh: 1;url=http://www.it315.org
1:指示客户端刷新频率。单位是秒
1;url=http://www.it315.org:指示客户端1秒后刷新到指定网址
//自动刷新 Refersh
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// response.setHeader("Refresh", "2");//2秒后刷新自己
response.setHeader( "Refresh" , "3;url=http://www.baidu.com" );
response.getWriter().write( "heihei" ); }
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// response.setHeader("Refresh", "2");//2秒后刷新自己
response.setHeader( "Refresh" , "3;url=http://www.baidu.com" );
response.getWriter().write( "heihei" ); }
*Content-Disposition: attachment; filename=aaa.zip
指示客户端下载文件,并制定文件的名称
//文件下载
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取下载文件的绝对路径
String filePath = getServletContext().getRealPath( "/WEB-INF/files/2.jpg" ); //获取下载文件的绝对路径
//通知客户端已下载的方式接受数据
response.setHeader( "Content-Disposition" , "attachment;filename=2.jpg" );
//告知客户端响应正文类型
response.setHeader( "Content-Type" , "application/octet-stream" );
InputStream in = new FileInputStream(filePath);
OutputStream out = response.getOutputStream();
int len = - 1;
byte b[] = new byte [ 1024];
while ((len =in.read(b)) != - 1){
out.write(b, 0, len);
}
in.close();
out.close(); }
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取下载文件的绝对路径
String filePath = getServletContext().getRealPath( "/WEB-INF/files/2.jpg" ); //获取下载文件的绝对路径
//通知客户端已下载的方式接受数据
response.setHeader( "Content-Disposition" , "attachment;filename=2.jpg" );
//告知客户端响应正文类型
response.setHeader( "Content-Type" , "application/octet-stream" );
InputStream in = new FileInputStream(filePath);
OutputStream out = response.getOutputStream();
int len = - 1;
byte b[] = new byte [ 1024];
while ((len =in.read(b)) != - 1){
out.write(b, 0, len);
}
in.close();
out.close(); }
*****Set-Cookie:SS=Q0=5Lb_nQ; path=/search
服务器端发送的Cookie(会话管理)
控制浏览器不要缓存
Expires: -1Cache-Control: no-cache (1.1)Pragma: no-cache (1.0)
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setHeader( "Expires" , "-1" );
response.setHeader( "Cache-Control" , "no-cache" );
response.setHeader( "Pragma" , "no-cache" );
throws ServletException, IOException {
response.setHeader( "Expires" , "-1" );
response.setHeader( "Cache-Control" , "no-cache" );
response.setHeader( "Pragma" , "no-cache" );
Connection: close/Keep-Alive 服务器告知是否保持连接
Date: Tue, 11 Jul 2000 18:23:51 GMT 响应时间
3、响应正文:第一个空行之后的所有内容。
浏览器要显示的数据。在未压缩的前提下,与右键 查看源码完全对应。
二、Servlet概述 (是sun公司制定的)
Servlet就是一个java程序,运行在服务器端.进行创建,运用和销毁
.JCP规定的servlet规范,不是sun规定的,但是我们一般说是sun公司规定的.
建一个类,去实现Servlet就可以了.但是一般我们继承
GenericServlet和HttpServlet。
GenericServlet:service(ServletRequest req, ServletResponse res)
覆盖service方法.ServletRequest:客户端请求,ServletResponse服务端的响应
覆盖service方法.ServletRequest:客户端请求,ServletResponse服务端的响应
#FormatImgID_0#
三、HelloServlet第一个Servlet
编写步骤:
1、编写一个类,直接或间接实现javax.servlet.Servlet接口(一般选择继承实现了该接口的类)
public
class HelloServlet
extends GenericServlet{
public void service(ServletRequest req,ServletResponse res)
throws ServletException,IOException{
String data = "hello servlet";
res.getOutputStream().write(data.getBytes());
}
}
public void service(ServletRequest req,ServletResponse res)
throws ServletException,IOException{
String data = "hello servlet";
res.getOutputStream().write(data.getBytes());
}
}
2、编译。进入源码所在的文件夹,执行javac(注意要把servlet-api.jar加入到构建路径中)
set classpath=%classpath%;C:\apache-tomcat-6.0.35\lib\servlet-api.jar
E:\ITHEIMA\JavaEE05\day03_httpServlet\资料\hello\WEB-INF\classes>javac -d . HelloServlet.java
3、对Servlet进行映射。修改web.xml,增加以下内容:
<servlet>
<servlet- name> HelloServlet</servlet -name> <!--和类名保持一致,但这不是必须的.-->
<servlet- class> com.itheima.servlet.HelloServlet</servlet- class>
</servlet>
<servlet-mapping> <!--进行映射-->
<servlet- name> HelloServlet</servlet- name>
< url-pattern> /Hello</ url-pattern>
</servlet-mapping>
<servlet- name> HelloServlet</servlet -name> <!--和类名保持一致,但这不是必须的.-->
<servlet- class> com.itheima.servlet.HelloServlet</servlet- class>
</servlet>
<servlet-mapping> <!--进行映射-->
<servlet- name> HelloServlet</servlet- name>
< url-pattern> /Hello</ url-pattern>
</servlet-mapping>
绝对匹配
4、部署应用到Tomcat中(把文件拷贝到服务器中的webapps目录)
访问地址:http://localhost:8080/hello/Hello(注意,hello是应用(文件名),Hello是地址(就是映射名))
http://localhost:8080/hello/WEB-INF/classes/com/itheima/servlet/HelloServlet(不对的)
四、GenericServlet和HttpServlet(模板方法设计模式)
模板(Template)模式
模板模式是类的行为模式。
1.定义:定义一个操作中算法的骨架(或称为顶级逻辑),将一些步骤(或称为基本方法)的执行延迟到其子类中.
2.模板模式与继承
模板方法估计恰当地使用继承。此模式可以用来改写一些拥有相同功能的相关的类,将可复用的一般性行为代码移到基类里面,而把特殊化的行为代码移到子类里面。熟悉模板方法模式是重新学习继承的开始。
3.模板模式中的方法
1)模板方法:必须由抽象类实现,该方法是一个顶级逻辑,调用任意多个基本方法。子类不应该修改该方法
2)基本方法:模板方法所调用的方法,有可细分为抽象方法,具体方法,钩子方法
抽象方法:强迫子类重写的
具体方法:不需要子类重写的,最好声明为final
钩子方法:子类可以重写的,一般是个空方法(钩子方法的命名应该以do开头,这是一个通用规范)
补充:模板模式的设计理念是尽量减少必须由子类置换掉的基本方法的数量(可以理解为尽量减少抽象方法和钩子方法的数量。)
4.重构的原则
总的原则:行为上移,状态下移(抽象类中的具体方法应该尽量多,而成员变量应该尽量少)
1)应当根据行为而不是状态定义一个类
2)在实现行为时,应该尽量用取值方法获取成员变量,而不是直接应用成员变量
3)给操作划分层次。一个类的行为应当放到一个小组核心方法里面,这些方法可以很方便地在子类中置换
4)将状态的确认推迟到子类中去。
5.使用模板模式,用多态取代条件转移(也可以使用策略模式)
6.问题:模板模式和策略模式的区别
补充:个人认为这个模式比较好理解,而且在实际编程中是十分常用。虽然如此,但是学习这个模式的过程中,我还是有许多收获的,主要是加深了对继承的理解,对OO的核心思想有了新的认识,就像阎博士说的“熟悉模扳方法模式便成为一个重新学习继承的好地方”
模板模式:原理为:子类对象的方法覆盖了父类的方法(父类对象调用子类方法)。
策略模式:确定操作的方法和策略,策略的具体实现行为不同。通过组合实现。原理就是:组合大于继承,实现更大的灵活性。
例子:
类加载,dao实现对object的增删改查。
适用的范围:许多应用的实现有许多公共的部分,但细节有差异。
1.从一张数据表,生成许多统计报表。
2.severlet对象service方法中doget,dopost方法。
五、Servlet生命周期

Servlet对象是在第一次访问时由容器创建,并完成初始化工作。
对于用户的多次请求,都会调用service为您服务,而不会再创建新的对象。
当应用被卸载或者Tomcat关闭,就是执行destroy进行清理工作。
如果希望Tomcat在加载应用时就实例化并完成对Servlet的初始化。web.xml做如下配置:
<servlet>
<servlet- name> HelloServlet</servlet- name>
<servlet- class> com.itheima.servlet.HelloServlet</servlet- class>
<load-on-startup> 2</load-on-startup> <!--1已经被使用了,需要使用2或者2以后的数字-->
</servlet>
<servlet- name> HelloServlet</servlet- name>
<servlet- class> com.itheima.servlet.HelloServlet</servlet- class>
<load-on-startup> 2</load-on-startup> <!--1已经被使用了,需要使用2或者2以后的数字-->
</servlet>
Tips:修改MyEclipse生成的Servlet模板
1、关掉MyEclipse
2、找到MyEclipse安装目录的上一次目录
搜索:com.genuitec.eclipse.wizards_*.jar
3、用压缩软件打开jar包。找到template/Servlet.java(模板文件),解压出来。
4、修改:修改前先备份。
5、把修改后的Servlet.java拖进去
6、重启MyEclipse,生效
六、ServletConfig配置
作用:针对某个Servlet的配置信息,一开始就需要初始化的参数。
<servlet>
<!--对ServletDemo3这个Servlet进行配置-->
< servlet-name>ServletDemo3</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo3</servlet-class>
<init- param> <!--表示aaa的值是bbb -->
<param-name>aaa</param-name>
<param-value>bbb</param-value>
</init-param>
</servlet>
< servlet-name>ServletDemo3</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo3</servlet-class>
<init- param> <!--表示aaa的值是bbb -->
<param-name>aaa</param-name>
<param-value>bbb</param-value>
</init-param>
</servlet>
//获取 Servlet 的配置信息,并打印
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletConfig sc = getServletConfig();
String value = sc.getInitParameter( "encoding" );
if (value == null )
value = "GBK" ;
response.getWriter().write(value);
//在控制台打印该 Servlet 所有的参数及取值
Enumeration e = sc.getInitParameterNames(); //所有参数名
while (e.hasMoreElements()){
String paramName = (String)e.nextElement();
System. out .println(paramName + "=" +sc.getInitParameter(paramName));
} }
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletConfig sc = getServletConfig();
String value = sc.getInitParameter( "encoding" );
if (value == null )
value = "GBK" ;
response.getWriter().write(value);
//在控制台打印该 Servlet 所有的参数及取值
Enumeration e = sc.getInitParameterNames(); //所有参数名
while (e.hasMoreElements()){
String paramName = (String)e.nextElement();
System. out .println(paramName + "=" +sc.getInitParameter(paramName));
} }
Tips:Servlet的映射细节。
1、可以把一个Servlet映射到多个地址上
<servlet-mapping><!-- 把一个Servlet映射到了多个地址上 -->
<servlet-name>ServletDemo4</servlet-name>
<url-pattern>/servlet/ServletDemo4</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ServletDemo4</servlet-name>
<url-pattern>/servlet/ServletDemo44</url-pattern>
</servlet-mapping>
2、映射还可以使用通配符*
使用方式:
a、*.扩展名:必须以*开头,以某个扩展名结尾。比如*.do
b、/action/*:必须以/开头,*在末尾。比如/action/*
原则:b优先级比a高。如果都是a或都是b,从前往后匹配。
完全匹配的映射优先级最高.
七、Servlet线程安全
1、同步处理(不靠谱)
2、创建Servlet的多个实例(不靠谱)。Tomcat采用的此种方式。
由于Servlet在内存中只有一个实例,service又是多线程来调用的。
因此定义变量尽量使用局部变量.
如果必须用实例变量,要做好同步处理(同步代码块尽量包围少的代码)