http协议以及Servlet
1.1 http协议
协议:是指双方按照一定的规则进行某种行为
http协议:(超文本传输协议)定义了浏览器域服务器之间的相互通信的规则
请求协议:浏览器端发送给服务器端
响应协议:服务器端发送给浏览器端
1.1.1 http之请求协议
请求格式如下,如果浏览器不按照这个格式服务器将无法识别
请求格式: 请求首行; 请求头信息; 空行; 请求体; |
GET /javaWEB1/index.jsp HTTP/1.1 //请求方式为GET请求,路径是javaWEB1/index.jsp 协议版本1.1 Accept: text/html, application/xhtml+xml, */* //接受参数类型*/*表示所有 Accept-Language: zh-CN //接受语言是中文 User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) //浏览器版本,操作系统类型 Accept-Encoding: gzip, deflate //接受编码,压缩以及解压缩 Host: localhost:8888 //主机名称 Connection: Keep-Alive //连接状态 存活 Cookie: JSESSIONID=03A34AAB1E01103D443520A7F0B88DC5 //后面再讲 //空格 |
1、GET/javaWEB1/index.jsp HTTP/1.1 //请求方式为GET请求,路径是javaWEB1/index.jsp 协议版本1.1
2、Host:localhost:8888 请求主机名为localhost,端口号为8888
3、User-Agent 发送一些关于浏览器的信息给服务器,例如浏览器版本,操作系统的版本等。
1.1.2 http之响应协议
响应协议格式如下:
响应首行; 响应头信息; 空行; 响应体。 |
在刚才的JavaWEB中服务器响给浏览器的内容如下
HTTP/1.1 200 OK //协议版本 状态码 状态码的解释 Server: Apache-Coyote/1.1 //服务器名称 Content-Type: text/html;charset=UTF-8 //文本类型以及编码 Content-Length: 619 //文本大小 Date: Thu, 08 Jun 2017 02:58:18 GMT //时间 //空格
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">//响应体 <html> ............响应具体内容........ </html> |
1、HTTP/1.1 200OK:表示协议版本号为1.1版本,状态码为200,表示请求成功,OK是对状态码的解释
2、Server:Apache-Coyote/1.1:服务器的名称
3、Content-Type:text/html;charset=UTF-8:响应文本类型以及编码格式
响应协议状态码所表示的含义: 200:表示请求成功 404:表示资源路径没有找到 405:请求的方式有问题(get、post等) 500:表示服务器的错误 302:表示重定向(服务器没有资源,提供一个url地址给浏览器访问)
|
1.2 Servlet组件
Servlet是我们JavaWeb三大组件之一,(Servlet和filter、listener),Servlet属于动态资源,服务器将浏览器发出的请求交给servlet来处理。接收请求数据,处理请求信息,完成响应。
一句话总结:servlet处理浏览器的请求,并且处理请求然后完成对浏览器的响应
注意:
一个功能的Servlet只能被Tomcat创建一次,很多次访问都是访问同一个Servlet(线程不安全)
实现Servlet的三种方式:
1.实现Servlet接口
2.继承GenericServlet类
3.继承HttpServlet类(重点掌握,常用)
1.2.1 Servlet接口
1.2.1.1 Servlet的实现方法
我们在新建类时实现Servlet接口,将会在servlet中实现如下方法
@Override public void destroy() { }
@Override public ServletConfig getServletConfig() { return null; }
@Override public String getServletInfo() { return null; }
@Override public void init(ServletConfig arg0) throws ServletException { }
@Override public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { } |
注意:
在servlet大部分的方法都是由服务器,即tomcat来调用,并且方法中的类类型参数,也就是对象也是由服务器来创建,服务器已经将固化代码写入,我们只需写其中的逻辑实现,直接使用即可。
1.2.1.1.1 Servlet中的生命周期
Method Summary |
|
|
destroy |
getServletConfig |
|
|
getServletInfo |
|
init |
|
service |
服务器会在servlet第一次被调用时来创建servlet对象,并且一个servlet只被创建一个对象。
|
|
|
1.2.1.1.2 Servlet中的参数
1、ServletConfig一个ServletConfig对应一段web.xml文件中的<servlet>元素,每个servlet都有自己的ServletConfig。
ServletConfig对象对应web.xml文件中的<servlet>元素。例如你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法获取!
ServletConfig本身来讲是一个接口,具体的实现类是由tomcat来完成的,这并不是我们所关心的问题
ServletConfig中提供方法有
Method Summary |
|
|
getInitParameter |
|
getInitParameterNames |
getServletContext |
|
|
getServletName |
1.getInitParameter( String name) 可以获取初始化参数值
2.getInitParameterNames() 获得一个存有所有param-name值的枚举集合
3.getServletContext() 获取上下文
4.getServletName() 获取servlet名称(不用)
web.xml文件配置: <servlet> <servlet-name>BServlet</servlet-name> //表示给该servlet一个名字用于标识 <servlet-class>com.edu118.servlet.BServlet</servlet-class> //该servlet所在的路径 <init-param> <param-name>p1</param-name> <param-value>v1</param-value> </init-param> <init-param> <param-name>p2</param-name> <param-value>v2</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>BServlet</servlet-name> <url-pattern>/BServlet</url-pattern> //映射一个URL地址让浏览器访问,必须以“/”开始对命名规范没有要求
</servlet-mapping>
<!--浏览器访问地址:http://localhost:8080/day02/BServlet -->
|
public void init(ServletConfig config)throws ServletException { String parameter = config.getInitParameter("p1"); System.out.println(parameter); System.out.println("---------------");
Enumeration<String> parameterNames =config.getInitParameterNames(); //迭代器遍历 while(parameterNames.hasMoreElements()){ System.out.println(config.getInitParameter(parameterNames.nextElement())); } } |
结果: v1 --------------- v1 v2 |
2、ServletRequest和ServletResponse是Servlet#service() 方法的两个参数,一个是请求对象,一个是响应对象,可以从ServletRequest对象中获取请求数据,可以使用ServletResponse对象完成响应。你以后会发现,这两个对象就像是一对恩爱的夫妻,永远不分离,总是成对出现
Request:
a) String s = httprquest.getLocalAddr(); --获取浏览器访问服务器的ip地址
b) String name = httprquest.getMethod(); --获取访问的方式(get或post等)
Response:
a) getWriter():获取字符响应流,使用该流可以向客户端输出响应信息。例如response.getWriter().print(“<h1>HelloJavaWeb!</h1>”);
b) void setCharacterEncoding(String encoding):用来设置字符响应流的编码
1.2.2 GenericServlet类
源码
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() { // NOOP } @Override public void destroy() { // NOOP by default } @Override public String getInitParameter(Stringname) { return getServletConfig().getInitParameter(name); }
@Override public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); } @Override public ServletConfig getServletConfig() { returnconfig; } @Override public ServletContext getServletContext() { return getServletConfig().getServletContext(); }
@Override public String getServletInfo() { return""; }
@Override public void init(ServletConfig config)throws ServletException { this.config =config; this.init(); }
public void init() throws ServletException { // NOOP by default }
public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwablet) { getServletContext().log(getServletName() + ": " + message, t); }
@Override public abstract void service(ServletRequestreq, ServletResponse res) throws ServletException, IOException;
@Override public String getServletName() { returnconfig.getServletName(); } } |
模拟GenericServlet类
public class EServlet implements Servlet { //定义一个全局变量,使继承EServlet的类都可以使用 private ServletConfigconfig; //初始化 public void init(ServletConfig config)throws ServletException { this.config =config; /* * 对init初始化进行补充,让继承EServlet的类可以再次实现对servlet的初始化 * 并且不影响config这个变量 */ init(); }
public void init() {
} //重写ServletConfig接口中的方法 //对接口中的方法进行实现 public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames();
}
public String getInitParametername(Stringname){ return getServletConfig().getInitParameter(name); }
public ServletContext getServletContext(){ return getServletConfig().getServletContext();
}
public String getServletName(){ return getServletConfig().getServletName(); } public ServletConfig getServletConfig() { // TODO Auto-generated method stub return null; }
public void service(ServletRequest req, ServletResponseres) throws ServletException, IOException { // TODO Auto-generated method stub
}
public String getServletInfo() { // TODO Auto-generated method stub return null; }
public void destroy() { // TODO Auto-generated method stub
}
} |
1.2.3 HttpServlet类
HttpServlet是对GenericServlet的一个继承,它除了有GenericServlet的service(ServletRequest,ServletResponse)方法之外,还有自身的service(HttpServletRequest,HttpServletResponse)来对Http协议的支持。
|
service |
|
service |
Httpservlet的工作流程如下:
1.浏览器发出请求,服务器首先会运行生命周期方法service
2.然后将service(ServletRequest,ServletResponse)强转为支持http的servlet
3.获取请求方法,根据请求方式来调用doGet还是doPost方法(这两个方法是由我们自己来覆盖的,需要注意的是当请求方式在servlet没有对应的方法复写会出现405错误)
1.3 ServletContext域
ServletContext是JavaWeb四大域之一,每一个项目都有且只有一个ServletContext,作用范围是整个web项目用于不同的servlet之间进行通信的。可以在不同的servlet中来获取这个ServletContext从而到达共享数据的目的,在服务器启动的时候被创建,在服务器关闭的时候被销毁。
1.3.1 ServletContext域对象的获取
因为我们新建的servlet类都是继承自HttpServlet类,而HttpServlet类继承自GnericServlet类,GenericServlet类中有getServletContext()的方法来获取ServletContext对象。所以可以直接使用this.getServletContext()获取
1.3.2 ServletContext的域功能
四个功能方法:
1、voidsetAttribute(String name,Object value):
void setAttribute(String name,Object value):存储数据 设置域属性以及域属性的值。域属性的名称为name,域属性的值为value。如果多次调用该方法设置相同的name域属性名称,那么会覆盖上一次设置的值。 |
2、ObjectgetAttribute(String name):
Object getAttribute(String name):获取数据 通过域属性的名称name获取对应的域属性值value,如果域对象中没有该域属性,会自动帮你创建该域属性。-->String value =(String)ServletContext.getAttribute(name); |
3、voidremoveAttribute(String name):
void removeAttribute(String name):用来移除ServletContext对象中的域属性 |
4、Enumeration<String>getAttributeNames():
Enumeration<String> getAttributeNames():获取所有域属性的名称。 返回的是一个枚举集合,通过迭代器进行迭代。使用方法与Vector的迭代方式一样。 |
1.3.3 ServletContext获取资源的相关路径
1.3.3.1 获取真实路径
String getRealPath(): 获取与给定的虚拟路径相对应的真实路径。
获取a.txt的真实路径:
String realPath= servletContext.getRealPath(“/a.txt”);
(realPath的值为a.txt文件的绝对路径:F:\tomcat6\webapps\hello\a.txt;)
1.3.3.2 获取资源流
获取a.txt资源流:
InputStream in =servletContext.getResourceAsStream(“/a.txt”);
获取b.txt资源流:
InputStream in =servletContext.getResourceAsStream(“/WEB-INF/b.txt”);
获取指定目录下所有资源路径:
Set set =context.getResourcePaths("/WEB-INF");
System.out.println(set);
注意,本方法必须以“/”开头!!!
访问网站统计访问量的小案例:
@Override protected void doGet(HttpServletRequest req, HttpServletResponseresp) throws ServletException, IOException { // 获得ServletContext域对象 ServletContext context =this.getServletContext(); // 获得一个属性,如果这个属性没有就自动帮你创建 Integer countNum = (Integer)context.getAttribute("count"); // 判断是否是第一次访问网站 if (countNum ==null) { //设置属性值 context.setAttribute("count", 1); // count = (Integer)context.getAttribute("count"); } else { context.setAttribute("count",countNum++); } //更新了属性值然后重新赋值 countNum = (Integer)context.getAttribute("count"); // 输出一下 System.out.println(countNum); PrintWriter writer = resp.getWriter(); writer.println("<h1>" +countNum + "</h1>"); } |