首页 > 技术文章 > Servlet笔记

heatainf 2020-04-21 19:24 原文

概念

Servlet(Servlet Applet),全称Java Servlert .是用Java编写的服务器端程序。其主要功能在与交互式的浏览和修改数据,生成动态Web内容。狭义的servlet是指Java语言实现的一个接口,广义的*Servlet是指任何实现了这个Servlet的类*,一般情况下,人们将Servlet理解为后者。比如HttpServlet类继承自Servlet类,可以利用继承Http Servlet 来实现Http请求,当不是Http请求的时候,也可以定义其他形式的Servlet。

​ Servlet 运行于支持Java的服务器中,从现实上讲,servlet 可以响应任何类型的请求,但是绝大多数情况下*Servlet只用于来扩展基于THHP协议的Web服务器*

第一个Servlet程序

手动实现一个Servlet程序:

1.编写一个类去实现Servlet接口

2.实现service方法,处理请求,并响应数据

3.到web.xml中去配置servlet程序的访问地址

    <!-- servlet标签给Tomcat配置Servlet程序 -->
    <servlet>
        <!--servlet-name标签 Servlet程序起一个别名(一般是类名) -->
        <servlet-name>HelloServlet</servlet-name>
        <!--servlet-class是Servlet程序的全类名-->
        <servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--servlet-mapping标签给servlet程序配置访问地址-->
    <servlet-mapping>
        <!--servlet-name标签的作用是告诉服务器,我当前配置的地址给哪个Servlet程序使用-->
        <servlet-name>HelloServlet</servlet-name>
        <!--
            url-pattern标签配置访问地址                                     <br/>
               / 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径          <br/>
               /hello 表示地址为:http://ip:port/工程路径/hello              <br/>
        -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
注意:
  1. 配置一个servlet程序后都要给其配置访问地址也就是标签,这个标签里的name标签也要跟上面的标签里的name一样,不然编译时就会报错。每写一个servlet程序都要在web.xml配置一个。

  2. 标签里的标签是表示访问这个Servlet的资源路径,这个地址一定要以 / 开头不然会出异常。而在浏览器访问这个地址后便会跳转到自己写的相应的Servlet,你就可以在这个Servlet里编写自己想写的程序(如在浏览器响应信息或者在控制台打印什么信息)。

  3. 里的类名如果写错的话编译时就会报错,在浏览器访问后会显示500的错误状态码。

执行原理:
1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
3. 如果有,则在找到对应的<servlet-class>全类名
4. tomcat会将字节码文件加载进内存,并且创建其对象
5. 调用其方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1syOsnpJ-1585802254074)(images/servlet执行原理.jpg)]

Servlet的生命周期

1.被创建:

执行init方法,只执行一次

Servlet什么时候被创建?

默认情况下,第一次被访问时,Servlet被创建

可以配置执行Servlet的创建时机。

标签下配置

第一次被访问时,创建

的值为负数

在服务器启动时,创建

的值为0或正整数

Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的

多个用户同时访问时,可能存在线程安全问题。

解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值

2.提供服务:

执行service方法,执行多次

每次访问Servlet时,Service方法都会被调用一次。

3.被销毁:

执行destroy方法,只执行一次

Servlet被销毁时执行。服务器关闭时,Servlet被销毁

只有服务器正常关闭时,才会执行destroy方法。

destroy方法在Servlet被销毁之前执行,一般用于释放资源

Servlet的体系结构

​ Servlet -- 接口
​ |
​ GenericServlet -- 抽象类
​ |
​ HttpServlet -- 抽象类

GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象

将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可

HttpServlet:对http协议的一种封装,简化操作

定义类继承HttpServlet

重写doGet/doPost方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhy3cHmP-1585802254075)(images/Servlet 类的继承体系.jpg)]

ServletConfig 类

ServletConfig 类从类名上来看,就知道是Servlet 程序的配置信息类。
Servlet 程序和ServletConfig 对象都是由Tomcat 负责创建,我们负责使用。
Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个Servlet 程序创建时,就创建一个对应的ServletConfig 对象。
a)ServletConfig 类的三大作用
1、可以获取Servlet 程序的别名servlet-name 的值
2、获取初始化参数init-param
3、获取ServletContext 对象

ServletContext 类

什么是ServletContext?
1、ServletContext 是一个接口,它表示Servlet 上下文对象
2、一个web 工程,只有一个ServletContext 对象实例。
3、ServletContext 对象是一个域对象。
4、ServletContext 是在web 工程部署启动的时候创建。在web 工程停止的时候销毁。
什么是域对象?
域对象,是可以像Map 一样存取数据的对象,叫域对象。
这里的域指的是存取数据的操作范围,整个web 工程。
存数据取数据删除数据
Map put() get() remove()
域对象setAttribute() getAttribute() removeAttribute();
b)ServletContext 类的四个作用
1、获取web.xml 中配置的上下文参数context-param
2、获取当前的工程路径,格式: /工程路径
3、获取工程部署后在服务器硬盘上的绝对路径
4、像Map 一样存取数据

演示代码:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
// 1、获取web.xml 中配置的上下文参数context-param
ServletContext context = getServletConfig().getServletContext();
String username = context.getInitParameter("username");
System.out.println("context-param 参数username 的值是:" + username);
System.out.println("context-param 参数password 的值是:" +
context.getInitParameter("password"));
// 2、获取当前的工程路径,格式: /工程路径
System.out.println( "当前工程路径:" + context.getContextPath() );
// 3、获取工程部署后在服务器硬盘上的绝对路径
/**
* / 斜杠被服务器解析地址为:http://ip:port/工程名/ 映射到IDEA 代码的web 目录<br/>
*/
System.out.println("工程部署的路径是:" + context.getRealPath("/"));
System.out.println("工程下css 目录的绝对路径是:" + context.getRealPath("/css"));
System.out.println("工程下imgs 目录1.jpg 的绝对路径是:" + context.getRealPath("/imgs/1.jpg"));
}

web.xml 中的配置:

<!--context-param 是上下文参数(它属于整个web 工程)-->
<context-param>
<param-name>username</param-name>
<param-value>context</param-value>
</context-param>
<!--context-param 是上下文参数(它属于整个web 工程)-->
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>

ContextServlet1 代码:

public class ContextServlet1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
// 获取ServletContext 对象
ServletContext context = getServletContext();
System.out.println(context);
System.out.println("保存之前: Context1 获取key1 的值是:"+ context.getAttribute("key1"));
context.setAttribute("key1", "value1");
System.out.println("Context1 中获取域数据key1 的值是:"+ context.getAttribute("key1"));
}
}

HTTP协议:

a)什么是HTTP 协议
什么是协议?
协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议。
所谓HTTP 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫HTTP 协议。
HTTP 协议中的数据又叫报文。
b)请求的HTTP 协议格式
客户端给服务器发送数据叫请求。
服务器给客户端回传数据叫响应。
请求又分为GET 请求,和POST 请求两种
i. GET 请求
1、请求行
(1) 请求的方式GET
(2) 请求的资源路径[+?+请求参数]
(3) 请求的协议的版本号HTTP/1.1
2、请求头
key : value 组成不同的键值对,表示不同的含义。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lKgxAcfW-1585802254076)(F:/学习资料/Java学习资料/学习记录/images/http请求.jpg)]

Referer: 表示这个请求是从哪个url跳过来的,通过百度来搜索淘宝网,那么在进入淘宝网的请求报文中,Referer的值就是:www.baidu.com。如果是直接访问就不会有这个头。常用于防盗链
Accept: 告诉服务端,该请求所能支持的响应数据类型,专业术语称为MIME 类型(文件类型的一种描述方式)
if-Modified-Sincce: 浏览器通知服务器,本地缓存的最后变更时间。与另一个响应头组合控制浏览器页面的缓存
Cokkie:客户端的Cookie就是通过这个报文头属性传给服务端的哦!
User-Agent: 浏览器通知服务器,客户端浏览器与操作系统相关信息
Connection: 表示客户端与服务连接类型;Keep-Alive表示持久连接,close已关闭
Host: 请求的服务器主机名
Content-Length: 请求体的长度
Content-Type: 请求的与实体对应的MIME信息。如果是post请求,会有这个头,默认值为application/x-www-form-urlencoded,表示请求体内容使用url编码
Accept-Encoding:浏览器通知服务器,浏览器支持的数据压缩格式。如GZIP压缩
Accept-Language:浏览器通知服务器,浏览器支持的语言。各国语言(国际化i18n)
Cache-Control:指定请求和响应遵循的缓存机制

状态码:

由3位数字组成,第一个数字定义了响应的类别

1xx:指示信息,表示请求已接收,继续处理

2xx:成功,表示请求已被成功接受,处理。

200 OK:客户端请求成功
204 No Content:无内容。服务器成功处理,但未返回内容。一般用在只是客户端向服务器发送信息,而服务器不用向客户端返回什么信息的情况。不会刷新页面。
206 Partial Content:服务器已经完成了部分GET请求(客户端进行了范围请求)。响应报文中包含Content-Range指定范围的实体内容
3xx:重定向

301 Moved Permanently:永久重定向,表示请求的资源已经永久的搬到了其他位置。

302 Found:临时重定向,表示请求的资源临时搬到了其他位置

303 See Other:临时重定向,应使用GET定向获取请求资源。303功能与302一样,区别只是303明确客户端应该使用GET访问

307 Temporary Redirect:临时重定向,和302有着相同含义。POST不会变成GET

304 Not Modified:表示客户端发送附带条件的请求(GET方法请求报文中的IF…)时,条件不满足。返回304时,不包含任何响应主体。虽然304被划分在3XX,但和重定向一毛钱关系都没有

4xx:客户端错误

400 Bad Request:客户端请求有语法错误,服务器无法理解。
401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
403 Forbidden:服务器收到请求,但是拒绝提供服务
404 Not Found:请求资源不存在。比如,输入了错误的url
415 Unsupported media type:不支持的媒体类型
5xx:服务器端错误,服务器未能实现合法的请求。

500 Internal Server Error:服务器发生不可预期的错误。
503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。

POST 请求的中文乱码解决

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
    // 设置请求体的字符集为UTF-8,从而解决post 请求的中文乱码问题
    req.setCharacterEncoding("UTF-8");
    System.out.println("-------------doPost------------");
    // 获取请求参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String[] hobby = req.getParameterValues("hobby");
    System.out.println("用户名:" + username);
    System.out.println("密码:" + password);
    System.out.println("兴趣爱好:" + Arrays.asList(hobby));
}

请求的转发

什么是请求的转发?
请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRtcgphn-1585802254076)(images/请求转发.jpg)]

servlet1:

public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws 	ServletException,IOException {
    // 获取请求的参数(办事的材料)查看
    String username = req.getParameter("username");
    System.out.println("在Servlet1(柜台1)中查看参数(材料):" + username);
    // 给材料盖一个章,并传递到Servlet2(柜台2)去查看
    req.setAttribute("key1","柜台1 的章");
    // 问路:Servlet2(柜台2)怎么走
    /**
    * 请求转发必须要以斜杠打头,/ 斜杠表示地址为:http://ip:port/工程名/ , 映射到IDEA 代码的web 目录
    <br/>
    *
    */
    RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
    // RequestDispatcher requestDispatcher = req.getRequestDispatcher("http://www.baidu.com");
    // 走向Sevlet2(柜台2)
    requestDispatcher.forward(req,resp);
    }
}

servlet2:

public class Servlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
    // 获取请求的参数(办事的材料)查看
    String username = req.getParameter("username");
    System.out.println("在Servlet2(柜台2)中查看参数(材料):" + username);
    // 查看柜台1 是否有盖章
    Object key1 = req.getAttribute("key1");
    System.out.println("柜台1 是否有章:" + key1);
    // 处理自己的业务
    System.out.println("Servlet2 处理自己的业务");
    }
}
共享数据:

域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:

void setAttribute(String name,Object obj):存储数据
Object getAttitude(String name):通过键获取值
void removeAttribute(String name):通过键移除键值对

base 标签的作用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mBftECPQ-1585802254077)(images/base标签.jpg)]

代码:

<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--base 标签设置页面相对路径工作时参照的地址
href 属性就是参数的地址值
-->
<base href="http://localhost:8080/07_servlet/a/b/">
</head>
<body>
这是a 下的b 下的c.html 页面<br/>
<a href="../../index.html">跳回首页</a><br/>
</body>
</html>

响应的乱码解决

解决响应中文乱码方案一(不推荐使用):
// 设置服务器字符集为UTF-8
resp.setCharacterEncoding("UTF-8");
// 通过响应头,设置浏览器也使用UTF-8 字符集
resp.setHeader("Content-Type", "text/html; charset=UTF-8");
解决响应中文乱码方案二(推荐):
// 它会同时设置服务器和客户端都使用UTF-8 字符集,还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8");

JavaEE项目的三层架构

a href="../../index.html">跳回首页

```

响应的乱码解决

解决响应中文乱码方案一(不推荐使用):
// 设置服务器字符集为UTF-8
resp.setCharacterEncoding("UTF-8");
// 通过响应头,设置浏览器也使用UTF-8 字符集
resp.setHeader("Content-Type", "text/html; charset=UTF-8");
解决响应中文乱码方案二(推荐):
// 它会同时设置服务器和客户端都使用UTF-8 字符集,还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8");

JavaEE项目的三层架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eDxUBHqD-1585802254077)(images/JavaEE项目的三层架构.jpg)]

推荐阅读