文章目录
HTTP协议
概述
HTTP协议(HyperText Transfer Protocol,超文本传输协议)详细的规定了浏览器和服务器之间进行通信的规则,通过网络传输HTML文档数据的协议 。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果。
HTTP协议是一个应用层的协议,由请求和响应构成,一次请求一次响应。
HTTP1.0之前使用的是种短连接的方式,即限制每次连接只处理一个请求,服务器处理完成并收到浏览器的应答之后,就会断开连接。
优点:可以节省传输时间
缺点:如果客户端连接频繁,会在会话的建立和关闭上浪费时间。
HTTP1.1使用的是长连接,即当一个网页打开完成后,客户端和服务端之间传输数据时,连接不会关闭。如果客户端再次访问这个服务器上的网页,会继续使用这一条连接
优点:长连接可以省去较多的会话建立/关闭的操作,减少浪费,节省时间
缺点:随着客户的越来越多,client和server如果长时间不关闭的话,服务器迟早会无法承受,可能会损害服务器的整体性能
HTTP协议是一种无状态协议,即HTTP不会为了下一次连接,而维护本次连接所传输的数据,如果在一个网站中的多个页面间需要共享数据,可以通过Cookie和Session来实现。
Request 请求
请求是指浏览器向服务器发送的数据
请求的组成
- 请求行:请求信息的第一行
- 请求头:从请求信息的第二行开始到请求空行结束 。请求头包含许多有关的客户端环境和请求正文的有用信息。
- 请求体(请求正文):请求头和请求体之间有一个空行(请求空行),它表示请求头已经结束,接下来的是请求体
常见的请求头
Accept: text/html,image/* 客户端可以接收的文档的类型
Accept-Charset: ISO-8859-1 客户端提交的表单可能使用的编码类型
Accept-Encoding: gzip 浏览器支持的编码类型
Accept-Language:zh-cn 语言环境
Host: localhost:8080 访问主机及端口号
Referer: http://www.baidu.com/index.jsp 来自哪个页面,可用于防盗链
Connection:Keep-Alive 链接状态,长链接
GET请求
请求行:
GET /HTTPTest/login?username=zhangsan&password=123456 HTTP/1.1
格式: 请求方式 /请求的URI?请求参数 协议/版本
GET请求的参数会拼接请求路径(URI)的后面,请求数据的大小有限制,无请求体
POS请求
请求行:
POST /login/login HTTP/1.1
格式: 请求方式 /请求的URI 协议/版本
POST有请求体,请求参数在请求体中,请求数据的大小无限制
请求体:
username=zhangsan&password=123456
Response 响应
响应是指在请求过后服务器向浏览器发送的数据
响应的组成:
- 响应行:响应信息第一行
HTTP/1.1 200 OK
格式: 协议/版本 响应状态码 响应的描述 - 响应头:响应信息第二行到响应空行
- 响应体:响应空行以下
常见的响应状态码:
200 成功响应
404 请求的资源没有找到
302 重定向
500 服务器内部错误
Servlet
Servlet接口定义所有Servlet都必须实现的方法
Servlet是运行在Web服务器中的小型Java程序。Servlet通常通过 HTTP(超文本传输协议)接收和响应来自Web客户端的请求。
创建Servlet项目的步骤
定义一个类实现Servlet接口并重写其中的抽象方法
import javax.servlet.*;
import java.io.IOException;
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("请求来了......");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
在项目的web目录下的WEB-INF目录下的web.xml文件中配置Servlet,配置如下:
<servlet>
<!--<servlet-name>中的名称没有要求-->
<servlet-name>myServlet</servlet-name>
<!--<servlet-class>中需要定义的Servlet子类的全路径-->
<servlet-class>myServletDemo1.MyServlet</servlet-class>
</servlet>
<!--配置Servlet的映射路径-->
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<!--Servlet的映射路径(以'/'开头),浏览器通过映射路径,可以访问到我们的Servlet-->
<url-pattern>/demo</url-pattern>
</servlet-mapping>
在配置文件中可以配置多个Servlet子类,但是映射路径不能相同
运行项目后,会打开网页,默认打开web目录下的index.jsp这个html文件
在地址栏输入demo,就可以在网页访问我们的Servlet项目,执行service方法中的代码
原理:
当请求服务器时,服务器就会读取web.xml文件中的配置内容。通过浏览器请求的映射路径找到servlet-class中的全路径,通过反射(Class.forname方法)创建该Servlet(MyServlet)的对象,调用service方法
Servlet生命周期方法
Servlet接口定义了初始化Servlet的方法、为请求提供服务的方法和从服务器移除Servlet的方法。这些方法称为生命周期方法,它们是按以下顺序调用的:
- 构造Servlet,然后使用init方法将其初始化。
- 处理来自客户端的对service方法的所有调用。
- 从服务中取出Servlet,然后使用destroy方法销毁它,最后进行垃圾回收并终止它。
除了生命周期方法之外,此接口还提供了getServletConfig方法和getServletInfo方法,Servlet可使用前一种方法获得任何启动信息,而后一种方法允许Servlet返回有关其自身的基本信息,比如作者、版本和版权。
//由Servlet容器调用,指示将该Servlet放入服务。
public void init(ServletConfig config) throws ServletException
//由Servlet容器调用,以允许Servlet响应某个请求。
public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException
//由Servlet容器调用,指示将从服务中取出该Servlet。
public void destroy()
//返回有关Servlet的信息,比如作者、版本和版权。
public String getServletInfo()
//返回ServletConfig对象,该对象包含此Servlet的初始化和启动参数。
public ServletConfig getServletConfig()
import javax.servlet.*;
import java.io.IOException;
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//在init方法中进行初始化的准备工作
//init方法只会在浏览器第一次请求实例化该Servlet对象后执行一次,当浏览器再次请求时,不会再执行
System.out.println("init() run...");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//对外提供服务的方法,每次请求都会调用该方法。在该方法中处理请求,作出响应
System.out.println("service() run...");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
//Servlet销毁前,调用destroy方法,在该方法中做一些关闭资源的收尾工作
System.out.println("destroy() run...");
}
}
可以在配置文件中,设置init方法调用的时间
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>myServletDemo1.MyServlet</servlet-class>
<!--设置init方法调用的时间
默认值为-1,代表实例化Servlet后调用
非负数代表在服务器开启过程中调用,数字越小,越早调用
如果两个配置的load-on-startup值相同,在下面的配置的Servlet的init方法先调用-->
<load-on-startup>1</load-on-startup>
</servlet>
Servlet是单例多线程的
尽量在Servlet中定义成员变量,可能会出现线程安全问题
创建Servlet的3种方式
第一种方法:定义一个类实现Servlet接口并重写其中抽象方法,即以上的方法
第二种方法:定义一个类继承GenericServlet类,并重写抽象方法service方法。GenericServlet类实现了Servlet类,并重写了除service方法外的所有抽象方法,而我们只需要在自定义类中重写service方法
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class MyServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
}
第三种方法:定义一个类继承HttpServlet类。
HttpServlet类继承了GenericServlet类,在该类重写的service方法中,会获取请求方法,根据请求方法进行不同的处理,调用不同的方法,而我们只需要重写不同请求方法的处理的方法即可
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*使用注解@WebServlet配置Servlet
name相当于<servlet-name>
value和urlPatterns相当于<url-pattern>
在注解中可以进行大部分配置*/
@WebServlet(name = "MyServlet",value = "/demo")
public class MyServlet extends HttpServlet {
//重写doGet方法和doPost方法,分别处理Get请求和Post请求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//在处理GET和POST请求时,如果处理代码相同,可以在某一个方法中只写一遍代码,在另一个方法中调用该方法
this.doPost(request, response);
}
}
/*value和urlPatterns是一个String类型的数组
所以一个Servlet可以由多个映射路径,用"{}"包裹,但是一个映射路径只能对应一个Servlet*/
@WebServlet(name = "MyServlet",value = {"/demo1","/demo2","/demo3"})
ServletContext
ServletContext接口定义一组方法,Servlet使用这些方法与其Servlet容器进行通信,例如,获取文件的MIME类型、分发请求或写入日志文件。
每个Java虚拟机的每个“Web 应用程序”都有一个上下文,即ServletContext对象,一个Web应用对应一个ServletContext对象,同时该对象也是一个域对象。该对象全局唯一,工程内部的所有Servlet都共享这个对象
服务器启动后,该对象被创建,服务器关闭,该对象被销毁,该对象是单例的
共享数据
作为一个全局域对象,可以在整个Web应用中共享数据
//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
//getServletContext方法在底层是通过ServletConfig对象获取ServletContext对象的
public ServletContext getServletContext() {
return this.getServletConfig().getServletContext();
}
//对于域对象,都可以使用这3个方法,用于存储、取出、删除数据
//将对象绑定到此Servlet上下文中的给定属性名称
//如果已将指定名称用于某个属性,则此方法将使用新属性替换具有该名称的属性。
public void setAttribute(String name, Object object)
//返回具有给定名称的Servlet容器属性,如果不具有该名称的属性,则返回null
public Object getAttribute(String name)
从Servlet上下文中移除具有给定名称的属性。
public void removeAttribute(String name)
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "MyServlet1",value = "/demo1")
public class ServletDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
//将该数据共享到MyServlet2中
String name="abc";
servletContext.setAttribute("name",name);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
@WebServlet(name = "MyServlet2",value = "/demo2")
public class ServletDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String name = (String) servletContext.getAttribute("name");
System.out.println(name);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
JavaWeb中有四个域对象(作用范围从大到小),之后会详细讲解,我们需要在不同情况下选择不同的域对象。
ServletContext全局域对象,作用于整个Web应用
Session会话域,作用于一次会话中
Request请求域,作用于一次请求和响应
PageContext页面域,作用于整个JSP页面
获取服务器真实路径
在Web项目的web目录下存在文件a.txt,在WEB-INF目录下存在文件b.txt,在src目录下存在文件c.txt,我们要访问这三个文件
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet(name = "MyServlet",value = "/demo")
public class MyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
File file = new File("src/c.txt");
//报异常FileNotFoundException,提示系统找不到指定的路径
//Web项目不是本地项目,需要部署到服务器上,路径会发生改变
FileInputStream in = new FileInputStream(file);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet(name = "MyServlet",value = "/demo")
public class MyServlet3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*项目编译过后,web目录变为项目的根目录,a.txt文件在项目根目录下
b.txt在项目根目录的WEB-INF目录下
src目录变为WEB-INF目录下的classes目录,c.txt在classes目录下*/
ServletContext servletContext = this.getServletContext();
/*为给定虚拟路径返回包含实际路径的 String
public String getRealPath(String path)*/
//动态获取当前项目的真实路径,"/"代表当前项目的根目录的虚拟路径
String realPath = servletContext.getRealPath("/");
//E:\MyProject\servletdemo\out\artifacts\servletdemo_war_exploded\
System.out.println(realPath);
//通过拼串的方式访问这些文件
FileInputStream in1 = new FileInputStream(new File(realPath+"a.txt"));
FileInputStream in2 = new FileInputStream( new File(realPath+"WEB-INF/b.txt"));
FileInputStream in3 = new FileInputStream( new File(realPath+"WEB-INF/classes/c.txt"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
Web项目发布后,项目可以放到到tomcat文件下的webapps目录下
也可以放在任意目录下,但是要在tomcat文件下的conf/server.xml下的Host标签下配置
或者在tomcat/conf/Catalina(引擎目录)/localhost(主机目录)下新建一个xml文件配置
配置语句如下:
<Context path="/项目名" docBase="项目的磁盘目录"/>
所以在访问项目中的文件时,要通过getRealPath方法动态获取真实路径。
在Web项目中普通类读取src下的文件
//返回该类的类加载器
public ClassLoader getClassLoader()
//返回读取指定资源的输入流
public InputStream getResourceAsStream(String name)
import java.io.InputStream;
public class Demo {
public static void main(String[] args) {
//直接输入资源名称"c.txt",获取src目录下的文件
InputStream in = Demo.class.getClassLoader().getResourceAsStream("c.txt");
}
}