Http协议
- http协议:针对网络上客户端与服务端在执行http请求时的一种遵守规范。要求客户端访问服务端时要带上什么东西,服务器返回数据时要带上什么东西。
- 版本:
1.0 请求数据,返回数据后断开连接
1.1 请求返回后保持连接,知道客户端或者服务器关闭。
- http请求数据
请求的数据包含三个东西: 请求行、请求头、请求体
-
请求行:
POSThttp://localhost/examples/servlets/servlet/RequestParamExample
POST是请求方式,用post去提交数据。后面的是地址数据,就是要访问到哪里 -
请求头
Accept:客户端向服务器说明他自己可以支持什么类型的数据。
Referer:真正请求的地址路径,谁发出的全路径
Accept-Language:支持语言格式
User-Agent:用户代理,向服务器表明现在访问的客户端信息
Content-Type:提交的数据类型,经过urlencoding编码的表单form数据
Accept-Encoding:gzip ,deflate:压缩算法
Host:主机地址
Content-Length:数据长度
Connection keep-alive:保持连接 -
请求体
浏览器真正发送给服务器的数据
数据呈现形式是key = value 如果有多个数据使用&连接name=zhangsan&password=111111
Http响应数据解析
请求数据里包含:响应行、响应头、响应体
- 响应行
HTTP/1.1 200 OK
协议版本
状态码:本次访问到底返回一个什么样的结果
1. 200成功,得到数据
2. 404 NOT FOUND
3. 403 ForBidden 拒绝访问
4. 500 服务器内部错误异常
OK对应状态码
- 响应头
Server:服务器是哪一种类型
Content-Type:服务器返回给客户端的内容类型
Content-Length:返回的数据长度 - 响应体
GET和POST区别
- 请求路径不同,post请求的URL后面不跟任何东西,get请求在URL后面有数据。
- 带上的数据不同,post使用流的方式写数据,get直接跟在地址栏后面。
- 由于post使用流写数据,所以一定要有一个Content-Length头说明数据的长度是多少。
- post
- 数据以流的方式写上去,不会出现在地址栏。一般客户端提交数据使用这种方式。
- 以流的方式写数据,所以没有数据大小限制。
- get
- 由于get请求直接把数据放到地址栏上,所以不安全。一般从服务器获取数据,但不从客户端获取使用get。
- 数据大小最大约1kb
web资源
- 静态资源
html、css、javascript - 动态资源
servlet、jsp
servlet
- servlet是什么
A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol.
更多的是配合动态资源来做,当然静态资源里也有使用,只不过Tomcat里有一个DefaultServlet.
- servlet执行过程
首先创建一个TestServlet.java文件实现Servlet接口
再配置web.xml
<!-- 向Tomcat告知有一个这样的servlet,名字叫做hello,路径是com.lxr.TestServlet -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.lxr.TestServlet</servlet-class>
</servlet>
<!-- 注册servlet映射,servlet-name找到上面注册的具体servlet, url-pattern是在地址栏上的path-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/a</url-pattern>
</servlet-mapping>
这时候地址栏输入
http://localhost/httpServlet/a
整个过程先是通过地址栏提交的数据找到Tomcat应用、找到项目、找到web.xml里的url-pattern,看有没有哪一个pattern内容是/a、找到对应的servlet-mapping中的servlet-name(上例中就是hello)、找到上面定义的servlet元素中的servlet-name中的hello(两个的servlet-name内容必须一致)、找到下面定义的servlet-class开始创建实例、最后执行servlet中的service方法。
- servlet通用写法
Servlet(接口)------GenericServlet(实现接口)------HttpServlet(前者的子类,处理http请求)
HttpServlet中有自己的service方法,不是从Servlet继承的,它的参数是ServletRequest arg0和ServletResponse arg1,强转成HttpServletRequest arg0, HttpServletResponse arg1可以调用Servlet中的service方法。
- 定义一个类继承HttpServlet,复写doGet方法和doPost方法
Servlet的生命周期
-
init方法
在创建该servlet的实例时,就执行该方法。
一个servlet只会初始化一次, init方法只会执行一次
默认情况下是 : 初次访问该servlet,才会创建实例。 -
service方法
只要客户端来了一个请求,那么就执行这个方法了。
该方法可以被执行很多次。 一次请求,对应一次service方法的调用 -
destroy方法
servlet销毁的时候,就会执行该方法1. 该项目从tomcat的里面移除。 2. 正常关闭tomcat就会执行 shutdown.bat
doGet 和 doPost不算生命周期方法,所谓的生命周期方法是指,从对象的创建到销毁一定会执行的方法, 但是这两个方法,不一定会执行。
Servlet创建实例的时间提前
如果init方法中要做一些很复杂的逻辑或者某些初始化工作,而要等到第一次访问这个Servlet才执行,那么耗时长,需要在该init方法中逗留较长的时间。这时候应该让这个方法提前执行,就好比你要去请客吃饭,但你不能等到客人来了才准备饭菜,需要提前执行。
解决方法:
<servlet>
<servlet-name>hello3</servlet-name>
<servlet-class>com.lxr.TestServlet2</servlet-class>
<!-- 里面数字越小越先执行,一般不写负数 -->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello3</servlet-name>
<url-pattern>/c</url-pattern>
</servlet-mapping>
ServletConfig
获取servlet在配置的一些信息
创建TestServletConfig.java文件
public class TestServletConfig extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建ServletConfig 对象
ServletConfig config = getServletConfig();
//获取servlet的名称
String servletName = config.getServletName();
System.out.println("servletName:" + servletName);
//根据参数名获取具体某一初始化参数值
String address = config.getInitParameter("address");
System.out.println("address:" + address);
//遍历取出所有参数名
Enumeration<String> names = config.getInitParameterNames();
while(names.hasMoreElements()) {
String key = names.nextElement();
String value = config.getInitParameter(key);
System.out.println("key=" + key + ";value=" + value);
}
}
}
配置的web.xml
<servlet>
<servlet-name>hello4</servlet-name>
<servlet-class>com.lxr.TestServletConfig</servlet-class>
<init-param>
<param-name>address</param-name>
<param-value>西安</param-value>
</init-param>
<init-param>
<param-name>telephone</param-name>
<param-value>13789087456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>hello4</servlet-name>
<url-pattern>/d</url-pattern>
</servlet-mapping>
运行TestServletConfig结果:
可见获取的是配置的servlet中的servlet-name中的文本内容
ServletConfig作用
一个写好的项目jar包给你,你将这个jar包导入你的项目,在你的项目里直接配置web.xml就可以进行一些操作。
- 将写好的ServletConfig项目导成jar包:
2.导入新的项目:
将jar包copy导项目的lib文件夹下,配置项目的web.xml文件
<servlet>
<servlet-name>config</servlet-name>
<servlet-class>com.lxr.config.ServletConfigDemo</servlet-class>
<init-param>
<param-name>number</param-name>
<param-value>20</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>config</servlet-name>
<url-pattern>/config</url-pattern>
</servlet-mapping>
其中servlet-class内容如下图选择:(记得删掉.class)
结论:
2. 未来我们自己开发的一些应用,使用到了一些技术,或者一些代码,我们不会。 但是有人写出来了。它的代码放置在了自己的servlet类里面。
- 刚好这个servlet 里面需要一个数字或者叫做变量值。 但是这个值不能是固定了。 所以要求使用到这个servlet的公司,在注册servlet的时候,必须要在web.xml里面,声明init-params
Servlet匹配方式
- 全路径匹配
localhost/项目名/a/b
web.xml中的配置:
<url-pattern>/a/b</url-pattern>
- 路径匹配
localhost/项目名/a/随便写
web.xml配置:
<url-pattern>/a/*</url-pattern>
其中*是通配符,也就是说,只有前半段需要匹配,后面不需要
- 扩展名匹配
localhost/项目名/*.test
web.xml配置:
<url-pattern>*.test</url-pattern>
其中test是扩展名
ServletContext
在每一个项目里都有一个ServletContext对象,那么在任意一个servlet中获取的这个类的对象都是这一个。
//获取对象
ServletContext context = getServletContext();
- 作用
- 获取全局参数
- 可以进行不同servlet数据共享存取
- 获取web工程中的资源
获取全局参数:
web.xml:
<context-param>
<param-name>apple</param-name>
<param-value>苹果</param-value>
</context-param>
TestServletContext:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取对象
ServletContext context = getServletContext();
//获取参数值
String value = context.getInitParameter("apple");
System.out.println("apple:" + value);
//获取项目在Tomcat下的根目录
String root = context.getRealPath("");
System.out.println("项目在Tomcat中的根目录" + root);
//获取资源在Tomcat下的绝对路径
String realPath = context.getRealPath("com/lxr/servlet/Demo.java");
System.out.println("Demo的目录 :" + realPath);
}
这里要清楚两个概念:
-
ServletContext的相对路径:
相对的是工程在Tomcat中的根目录参照为 D:\apache-tomcat-8.0.52\webapps\ServletRegister 需要写的是: com\lxr\servlet\Demo.java
-
绝对路径:
没有参照 需要写的: D:\apache-tomcat-8.0.52\webapps\ServletRegister\com\lxr\servlet\Demo.java
- 获取web应用中的资源,以properties文件为例
config.properties:
name=zhangsan
age=20
address=\u9655\u897F\u7701\u897F\u5B89\u5E02
TestProperties:
- 获取资源在Tomcat里的绝对路径:
@WebServlet("/TestProperties")
public class TestProperties extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建属性对象
Properties properties = new Properties();
ServletContext context = getServletContext();
//获取给定的文件在服务器上的绝对路径
String path = context.getRealPath("file/config.properties");
//指定载入的数据源
InputStream is = new FileInputStream(path);
properties.load(is);
//获取属性值
String name = properties.getProperty("name");
String age = properties.getProperty("age");
String add = properties.getProperty("address");
System.out.println("name=" + name + " age=" + age + " add=" + add);
}
}
- getResourceAsStream 获取资源 流对象
ServletContext context = getServletContext();
String path = context.getRealPath("file/config.properties");
Properties properties = new Properties();
//获取资源流对象
//InputStream is = context.getResourceAsStream("file/config.properties");
properties.load(is);
//获取属性值
String name = properties.getProperty("name");
//...
通过classloader获取web工程下资源
-
绝对路径
你要找的: D:\apache-tomcat-8.0.52\webapps\ServletRegister\Demo.java
-
相对路径
参照的路径: D:\apache-tomcat-8.0.52\webapps\ServletRegister\WEB-INF\classes 你要找的: ../../Demo.java
以绝对路径列举的例子,知道我们要找的文件在classloader相对路径的上跳两级的下面。
测试:
@WebServlet("/TestProperties2")
public class TestProperties2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Properties properties = new Properties();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("../../file/config.properties");
properties.load(is);
System.out.println(properties.getProperty("address"));
}
}
其中getResourceAsStream里的内容有…/…/的存在就是因为classloader的相对路径不同于ServletContext,我们需要回跳两次到同一目录再去找