Servlet

HTTP协议

浏览器将给出的请求解析位满足HTTP协议的格式并发出。

我们发出的请求格式需要按照浏览器规定的格式来书写。

在浏览器中书写格式如下:

image-20220417170400243

HTTP之URL

HTTP(超文本传输协议)是一个基于请求与响应模式的、应用层的协议,常基于TCP的连接方式,绝大多数的Web开发,都是构建在HTTP协议之上的 Web 应用。
HTTP URL(URL是一种特殊类型的URL,包含了用于查找某个资源的足够的信息)的格式如下

http: //host[:port]/[abc_path]

http://IP(主机名/域名):端口/访问的资源路径

  • http表示要通过HTTP协议来定位网络资源

  • host表示合法的 Internet主机域名或者IP地址;

  • port指定一个端口号,为空则使用缺省端口80;

  • abs_path 指定请求资源的URL;如果URL中没有给出abs_path,那么当它作为请求URI时,必须以”/‘’的形式给出,通常这个工作浏览器自动帮我们完成。

HTTP请求

HTTP请求由三部分组成:请求行,请求头,请求正文。

  1. Get请求,没有请求体
  2. Post请求

格式

1
2
3
4
5
6
请求行
请求头1
请求头2
……
请求空行
请求体

请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本。
格式如下:Method Request-URI HTTP-Version CRLF
Method表示请求方法;
Request-URI是一个统一资源标识符;
HTTP-Version表示请求的HTTP 协议版本;

CRLF表示回车和换行;

HTTP响应

在接收和解释请求消息后,服务器返回一个HTTP响应消息。HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文。

格式

1
2
3
4
5
状态行
响应头1
响应头2
……
响应正文

消息头

请求头

请求报头允许客户端向服务器传递请求的附加信息以及客户端自身的信息

  • Referer: 指明请求从哪里来

响应头

响应报头允许服务器传递不能放在状态行中的附加响应信息,

  • Location: Location 响应报头域用于重定向接受者到一个新的位置

    Location响应报头域,常用在更换域名的 时候

1
response.sendRedirect("http://www.baidu.com");
  • Refresh:自动跳转(单位s),可以在页面通过meta标签实现,也可以在后台实现
1
<meta http-equiv="refresh" content="3;url=http://www.baidu.com">

Tomcat服务器

什么是Tomcat

面向java的性能稳定而且免费的轻量级服务器

Tomcat目录结构

image-20220417180946849

IDEA配置Tomcat

点击设置中的应用程序服务器,点击加号选择Tomcat服务器,

选择tomcat的bin目录的上一级目录

点击确定即可

image-20220417181903993

IDEA2021版教材 参考这个:

新手在IDEA如何创建一个Web项目_Kevinvcc200的博客-CSDN博客_idea建立一个web项目

Servlet的实现

​ Servlet是Server与Applet 的缩写,是服务端小程序的意思。使用Java语言编写的服务器端程序,可以像生成动态的WEB页,Servlet主要运行在服务器端,并由服务器调用执行,是一种按照Servlet标准来开发的类。是SUN公司提供的一门用于开发动态Web资源的技术。(言外之意:要实现 web开发,需要实现.Servlet标准)

​ Servlet 本质上也是Java类,但要遵循Servlet规范进行编写,没有main()方法,它的创建、使用、销毁都由Servlet容器进行管理(如Tomcat)。(言外之意:写自己的类,不用写main方法,别人自动调用)

Servlet是和HTTP协议是紧密联系的,其可以处理HTTP协议相关的所有内容。这也是Servlet应用广泛的原因之一。

​ 提供了Servlet功能的服务器,叫做Servlet容器,其常见容器有很多,如Tomcat, Jetty, WebLogic Server,WebSphere,JBoss 等等。

Servlet工作流程

在src下新建一个包

在包下创建java类Servlet01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.web_test01.servlet;

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;

/**
* 实现Servlet
* 1.创建普通java类
* 2.实现Serlet规范,继承HttpSerlet类
* 3.重写service方法,用来处理请求
* 4.设置注解,指定访问的路径
* **/
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("hello servlet");
//通过流输出数据到浏览器
resp.getWriter().write("hello servlet");
}
}

Servlet的生命周期

​ Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度。所谓生命周期,指的是servlet容器何时创建servlet实例、何时调用其方法进行请求的处理、何时并销毁其实例的整个过程。

  • 实例和初始化时机
    当请求到达容器时,容器查找该servlet对象是否存在,如果不存在,则会创建实例并进行初始化。

  • 就绪/调用/服务阶段
    有请求到达容器,容器调用servlet对象的service()方法,处理请求的方法在整个生命周期中可以被多次调用;HttpServlet的service()方法,会依据请求方式来调用doGet()或者doPost()方法。但是,这两个do方法默认情况下,会抛出异常,需要子类去override。

  • 销毁时机
    当容器关闭时(应用程序停止时),会将程序中的Servlet实例进行销毁。
    上述的生命周期可以通过Servlet中的生命周期方法来观察。在Servlet中有三个生命周期方法,不由用户手动调用,而是在特定的时机有容器自动调用,观察这三个生命周期方法即可观察到Servlet的生命周期。
    init方法,在Servlet 实例创建之后执行((证明该Servlet有实例创建了)

init 方法,在Servlet实例创建之后执行(证明该Servlet有实例创建了)

1
2
3
public void init() throws ServletException {
System.out.println("Servlet被初始化了");
}

service方法,每次有请求到达某个Servlet方法时执行,用来处理请求(证明该Servlet进行服务了)

1
2
3
public void destroy() {
System.out.println("Servlet被销毁了");
}

destroy方法,Servlet实例销毁时执行(证明该Servlet的实例被销毁了)

1
2
3
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet被调用了");
}

image-20220417222506808

HttpServletRequest对象

主要作用:用来接收客户端发送过来的请求信息,

在HttpServletRequest接口中,不需要拿到该对象了,直接在Service方法中由容器传过来,而我们需要取出对象中的数据,进行分析、处理、

接收请求

常用方法

  1. 方法

  2. 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//获取请求时的完整路径(从http开始,到"?"前面结束)
String url=request.getRequestURL()+"";
System.out.println("获取请求时的完整路径: "+url);

//获取请求时的部分路径(从项目的站点名开始,到“?”前面结束)
String uri = request.getRequestURI()+"";
System.out.println("获取请求时的部分路径: "+uri);
//获取请求时的参数字符串(从“?”后面开始,到最后的字符串)
String queryString = request.getQueryString();
System.out.println("获取请求时的参数字符串: "+queryString);
//获取请求方式(GET和POST)
String method = request.getMethod();
System.out.println("method: "+method);
//获取当前协议版本(HTTP/1.1)
String protocol =request.getProtocol();
System.out.println("protocal: "+protocol);
//获取醒目的站点名(项目对外访问路径)
String webapp=request.getContextPath();
System.out.println("path: "+webapp);

在浏览器中访问:localhost:8081/sr02/s01

然后编译器中运行结果为

image-20220426114138935

获取请求参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 获取请求的参数 */
//获取指定名称的参数值,返回字符串
String uname = request.getParameter("uname");
String upwd = request.getParameter("upwd");
System.out.println("uname: "+uname+",upwd: "+upwd);

//获取指定名称的参数和所有参数值,返回字符串数组(用于复选框传值)
String[] hobbys=request.getParameterValues("hobby");
//判断数组是否为空
if (hobbys!=null&&hobbys.length>0){
for(String hobby:hobbys){
System.out.println("爱好: "+hobby);
}
}

在浏览器中访问:localhost:8081/sr02/s01?uname=admin&upwd=123456&hobby=sing&hobby=dance&hobby=rap

运行结果:

image-20220426142328038

请求乱码问题

way one:

1
request.setCharacterEncoding("UTF-8");

此方法只针对POST有效(必须在接收所有数据之前设定)

way two:

1
String name = String(request.getParameter("uname").getBytes(charseName:"ISO-8859-1"),charsetName::"UTF-8");

解决Tomcat7及以后版本get请求乱码

请求转发

请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的URL地址不会改变,得到响应后,服务器端再将响应发送给客户端,从始至终只有一个请求发出。实现方式如下,达到多个资源协同响应的效果。

1
request.getRequestDispatcher(url).forward(req,resp);

request作用域

通过改对象可以在一个请求中传递数据,作用范围:在一次请求中有效,即服务器跳转有效。

1
2
3
4
5
6
//设置域对象内容
request.setAttribute(String name, Object value);
//获取域对象内容
request.getAtrribute(String name);
//删除与对象内容
request.removeAtrribute(String name);

request 域对象中的数据在一次请求中有效,则经过请求转发,request域中的数据依然存在,则在请求转发的过程中可以通过request来传输/共享数据。

HttpServletResponse对象

​ Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象。

​ request和response对象代表请求和响应:获取客户端数据,需要通过request对象;向客户端输出数据,需要通过response对象

​ HttpServletResponse 的主要功能用于服务器对客户端的请求进行响应,将Web服务器处理后的结果返回给客户端。service()方法中形参接收的是HttpServletResponse接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。

响应数据

两种形式:

getWriter() 获取字符流(只能响应字符)

getOutputStream() 获取字节流(能响应一切数据)

响应回的数据到客户端被浏览器解析。

ps:两者不能同时使用。

1
2
3
4
5
6
7
8
     //字符输出流
PrintWriter writer = resp.getWriter();
//输出数据
//writer.write("hello");

//字节输出流
ServletOutputStream out =resp.getOutputStream();
out.write("Hi".getBytes());

响应乱码问题

​ 在响应中,如果我们响应的内容中含有中文,则有可能出现乱码。这是因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。
getWriter()的字符乱码
​ 对于getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用ISO-8859-1格式的编码,该编码方式并不支持中文。
​ 要解决该种乱码只能在服务器端告知服务器使用一种能够支持中文的编码格式,比如我们通常用的”UTF-8”。

way one:

1
2
3
4
//设置服务端的编码方式
resp.setCharacterEncoding("UTF-8");
//设置客户端的编码方式
resp.setHeader("content-type","text/html;charset=UTF-8");

way two:

1
2
//同时设置客户端和服务端的编码格式
resp.setContentType("text/html;charset=UTF-8");

重定向问题

​ 重定向是一种服务器指导,客户端的行为。客户端发出第一个请求,被服务器接收处理后,服务器会进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址response.sendRedirect(url);),当客户端接收到响应后,会立刻、马上、自动根据服务器给的新地址发起第二个请求,服务器接收请求并作出响应,重定向完成。

​ 重定向当中有两个请求存在,并且属于客户端行为。

1
2
//重定向跳转到index.jsp
response.sendRedirect("index.jsp")

请求转发与重定向的区别

请求转发 重定向
一次请求,数据在request域中共享 两次请求,request域中数据不共享
服务端行为 客户端行为
地址栏不发生变化 地址栏发生变化
绝对地址定位到站点后 绝对地址可写到http://

Cookie对象

Cookie的创建的发送

​ 通过new Cookie(“key”,”value”);来创建一个Cookie对象,要想将Cookie随响应发送到客户端,需要先添加到response对象中,response.addCookie(cookie);此时该cookie对象则随着响应发送至了客户端。在浏览器上可以看见。

1
Cookie cookie = new Cookie("name","admin");
1
2
3
4
5
6
7
8
9
10
11
//获取cookie数组
Cookie[] cookies = req.getCookies();
//判断cookie是否为空
if (cookies !=null &&cookies.length>0){
//遍历cookie数组
for(Cookie cookie:cookies){
String name=cookie.getName();
String value=cookie.getValue();
System.out.println("名称: "+name+",值: "+value);
}
}

Cookie设置到期时间

setMaxAge(int time)

到期时间的取值

  • 负整数

若为负数,表示不存储该cookie。
cookie的maxAge属性的默认值就是-1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那么cookie就会消失。

  • 正整数

    若大于0的整数,表示存储的秒数。
    表示cookie对象可存活指定的秒数。当生命大于0时,浏览器会把Cookie保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie 也会存活相应的时间。


  • 若为0,表示删除该cookie。
    cookie生命等于0是一个特殊的值,它表示 cookie被作废!也就是说,如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的setMaxAge(0)来删除这个Cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。
    设置Cookie对象指定时间后失效

1
2
3
4
5
6
7
8
9
10
11
12
13
//到期时间,负整数(默认值-1,表示只在浏览器内存中存活,关闭失效)
Cookie cookie = new Cookie("uname1","zhangsan");
cookie.setMaxAge(-1); //关闭浏览器失效
resp.addCookie(cookie);
//到期时间,正整数(存磁盘中)、
Cookie cookie2=new Cookie("uname2","lisi");
cookie2.setMaxAge(30); //存活30s
resp.addCookie(cookie2);

//到期时间,0(删除cookie)
Cookie cookie3 = new Cookie("uname3","wangwu");
cookie3.setMaxAge(0); //删除cookie
resp.addCookie(cookie3);

Cookie路径问题

cookie.setPath(“/“);

cookie.setPath(“/s01”);

HttpSession对象

JSESIONID

session域对象