Loading

java.servlet

image-20210228213836601

HTTP协议

HTTP请求

抓包

image-20211025160720674

请求行

  • 请求行
POST  /myApp/success.html?username=zs&password=123456 HTTP/1.1	
GET  /myApp/success.html HTTP/1.1
  • 请求方式(8种,put,delete等)

    ​ GET:明文传输, 不安全,参数跟在请求路径后面,对请求参数大小有限制,

    ​ POST: 暗文传输,安全一些,请求参数在请求体里,对请求参数大小没有有限制,

  • URI:统一资源标识符(即:去掉协议和IP地址部分)

  • 协议版本:HTTP/1.1

请求头

​ 请求头,以键值对的形式存在,但存在一个key对应多个值的请求头.

​ 作用:浏览器告诉服务器自己相关的设置

  • Accept:浏览器可接受的MIME类型 ,告诉服务器客户端能接收什么样类型的文件。

  • User-Agent:浏览器信息.(浏览器类型, 浏览器的版本....)

  • Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集

  • Content-Length:表示请求参数的长度

  • Host:初始URL中的主机和端口

  • Referer:从哪里里来的(之前是哪个资源)----------防盗链

  • Content-Type:内容类型,告诉服务器,浏览器传输数据的MIME类型,文件传输的类型,application/x-www-form-urlencoded .

  • Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip

  • Connection:表示是否需要持久连接。如果服务器看到这里的值为“Keep -Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接 )

  • Cookie:这是最重要的请求头信息之一(会话技术, 后面会有专门的时间来讲的)

  • Date:Date: Mon, 22Aug 2011 01:55:39 GMT请求时间GMT

  • get方式请求

image-20210228222708036

【请求行】
GET /myApp/success.html?username=zs&password=123456 HTTP/1.1

【请求头】
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 41723-10011
Referer: http://localhost:8080/myApp/login.html
Accept-Language: zh-Hans-CN,zh-Hans;q=0.5
User-Agent: Mozilla/5.0 (MSIE 9.0; qdesk 2.4.1266.203; Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: localhost:8080
Connection: Keep-Alive
Cookie: Idea-b77ddca6=4bc282fe-febf-4fd1-b6c9-72e9e0f381e8
  • post请求

image-20210228222815950

【请求行】
POST /myApp/success.html HTTP/1.1

【请求头】
Accept: text/html, application/xhtml+xml, */*
X-HttpWatch-RID: 37569-10012
Referer: http://localhost:8080/myApp/login.html
Accept-Language: zh-Hans-CN,zh-Hans;q=0.5
User-Agent: Mozilla/5.0 (MSIE 9.0; qdesk 2.4.1266.203; Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8080
Content-Length: 27
Connection: Keep-Alive
Cache-Control: no-cache

【请求体】
username=zs&password=123456

请求体

​ get方式没有请求体,只有post请求才有请求体. 即post请求时,请求参数(提交的数据)所在的位置

HTTP响应

抓包

image-20211025160645648

  • 响应部分

    【响应行】
    HTTP/1.1 200
    
    【响应头】
    Accept-Ranges: bytes
    ETag: W/"143-1557909081579"
    Last-Modified: Wed, 15 May 2019 08:31:21 GMT
    Content-Type: text/html
    Content-Length: 143
    Date: Sun, 08 Dec 2019 02:20:04 GMT
    
    【响应体】
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        Success
    </body>
    </html>
    

响应行

HTTP/1.1 200
  • 协议/版本

  • 响应状态码

    ​ 200:正常,成功

    ​ 302:重定向

    ​ 304:表示客户机缓存的版本是最新的,客户机可以继续使用它,无需到服务器请求. 读取缓存

    ​ 404:客户端错误(一般是路径写错了,没有这个资源)

    ​ 500:服务器内部错误

响应头

响应头以key:vaue存在, 可能多个value情况. 服务器指示浏览器去干什么,去配置什么.

  • Location: http://www.it315.org/index.jsp指示新的资源的位置,通常和状态,码302一起使用,完成请求重定向

  • Content-Type: text/html; charset=UTF-8; 设置服务器发送的内容的MIME类型,文件下载时候

  • Refresh: 5;url=http://www.baidu.com 指示客户端刷新频率。单位是秒 eg: 告诉浏览器5s之后跳转到百度

  • Content-Disposition: attachment; filename=a.jpg 指示客户端(浏览器)下载文件

  • Content-Length:80 告诉浏览器正文的长度

  • Server:apachetomcat 服务器的类型

  • Content-Encoding: gzip服务器发送的数据采用的编码类型

  • Set-Cookie:SS=Q0=5Lb_nQ;path=/search服务器端发送的Cookie

  • Cache-Control: no-cache (1.1)

  • Pragma: no-cache  (1.0)  表示告诉客户端不要使用缓存

  • Connection:close/Keep-Alive

  • Date:Tue, 11 Jul 2000 18:23:51 GMT

响应体

​ 页面展示内容, 和网页右键查看的源码一样

general

Request URL: http://localhost:8080/Servlet_war_exploded/   请求地址
Request Method: GET 请求方法
Status Code: 200  状态码
Remote Address: [::1]:8080 远程IP地址
Referrer Policy: strict-origin-when-cross-origin 上一个链接转过来的地址

Response Headers

Connection: keep-alive 客户端与服务器保持连接 Connection: close表示关闭连接
Content-Length: 606 返回的内容长度
Content-Type: text/html;charset=UTF-8 返回的内容类型,这里是html
Date: Mon, 25 Oct 2021 10:24:14 GMT 东八区时间,北京时间-8小时
Keep-Alive: timeout=20 
Set-Cookie: JSESSIONID=4B7A9A0CD40520648860788AC48F751F; Path=/Servlet_war_exploded; HttpOnly

Request Headers

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 浏览器能够接收的类型
Accept-Encoding: gzip, deflate, br 浏览器支持的压缩编码类型
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 浏览器支持的语言
Cache-Control: no-cache 通过首部指令操作缓存
Connection: keep-alive 保持连接
Cookie: JSESSIONID=83A0C7616581A88BFC549EAB425072DE; Idea-717fcd95=c68c8a9c-8c64-42f7-9586-99850f2b9b07; Pycharm-f2f043dd=526d43bc-6c5a-4c00-a7c2-8b72be16e308; Idea-e5a52c40=b26af877-cd61-46ac-9d33-af5a2522b4fd 发送请求时把保存在该请求下的所有cookie值一起发给浏览器
Host: localhost:8080 指定请求的服务器的域名和编号
Pragma: no-cache 
信息安全    sec-ch-ua: "Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"
            sec-ch-ua-mobile: ?0
            sec-ch-ua-platform: "Windows"
            Sec-Fetch-Dest: document
            Sec-Fetch-Mode: navigate
            Sec-Fetch-Site: none
            Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1  升级不安全的请求 http - https
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 服务器信息

Servlet的实现

部署Tomcat项目

		* 部署项目的方式:
			1. 直接将项目放到webapps目录下即可。
				* /hello:项目的访问路径-->虚拟目录
				* 简化部署:将项目打成一个war包,再将war包放置到webapps目录下。
					* war包会自动解压缩

			2. 配置conf/server.xml文件
				在<Host>标签体中配置
				<Context docBase="D:\hello" path="/hehe" />
				* docBase:项目存放的路径
				* path:虚拟目录

			3. 在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写
				<Context docBase="D:\hello" />
				* 虚拟目录:xml文件的名称

servlet的生命周期(重点)

先看与Servlet生命周期有关的三个方法:init(), service(), destroy(). Servlet生命周期可被定义为从创建
直到毁灭的整个过程。以下是三个方法分别对应的Servlet过程:
    init():Servlet进行初始化;
    service():Servlet处理客户端的请求;
    destroy():Servlet结束,释放资源;
在调用destroy()方法后,Servlet由JVM的垃圾回首器进行垃圾回收。

init()方法

Servlet被装载后,Servlet容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化在Servlet生命周期中init()方法只被调用一次

当用户调用一个Servlet时,Servlet容器就会创建一个Servlet实例,每一个用户请求都会产生一个新的线程,init()方法简单的创建或加载一些数据,这些数据将会被用在Servlet的整个生命周期。

init()方法的定义如下:

public void init() throws ServletException {
    // 初始化代码... 
}

service()方法

service()方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service()方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service()方法检查HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用doGet()、doPost()等方法。

service()的定义如下:

public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{
    // service()代码... 
}

destroy()方法

destroy()方法只会被调用一次,在Servlet生命周期结束时被调用。destroy()方法可以让Servlet关闭数据库连接、停止后台、把cookie列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

在调用destroy()方法之后,Servlet对象被标记为垃圾回收。

destroy()方法的定义如下所示:

public void destroy() {
    // 终止化代码... 
}

总结:

  1. 在首次访问某个Servlet时,init()方法会被执行,而且也会执行service()方法。
  2. 再次访问时,只会执行service()方法,不再执行init()方法。
  3. 在关闭Web容器时会调用destroy()方法。

创建WEB项目

image-20210228230655927

image-20210228230849103

实现Servlet

image-20210228231110220

image-20210228231217787

配置servlet的两种方式

1.通过web.xml文件配置servlet

<servlet>
    <servlet-name>servlet01</servlet-name>
    <servlet-class>com.ccl.servlet.servlet01</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>servlet01</servlet-name>
    <url-pattern>/ser.do</url-pattern>
</servlet-mapping>

image-20210301220413282

2.通过注解配置servlet

image-20211024152626259

servlet的匹配规则

精确匹配

<servlet-mapping>
    <servlet-name>UserServlet</servlet-name>
    <url-pattern>/user.html</url-pattern>
    <url-pattern>/user.do</url-pattern>
</servlet-mapping>

在浏览器中输入如下几种url时,都会被匹配到该servlet

http://localhost:4444/servlet01/user.html
http://localhost:4444/servlet01/user.do

image-20210301232409042

image-20210301232425832

路径匹配 ,以"/"开头,并以"/*"结尾的字符串用于路径匹配

<servlet-mapping>
    <servlet-name>UserServlet</servlet-name>
    <url-pattern>/user/*</url-pattern>
</servlet-mapping>

路径以/user/开始,后面的路径可以任意。比如下面的url都会被匹配

image-20210301233307086

扩展名匹配,以"*"结尾的字符串用于扩展名匹配

<servlet-mapping>
    <servlet-name>UserServlet</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

则任何扩展名为jsp或action的url请求都会匹配,比如下面的url都会被匹配

image-20210301232604317

image-20210301232733993

缺省匹配

<servlet-mapping>
    <servlet-name>UserServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

以任意字符开头,/结尾该servlet被匹配

image-20210301232949888

匹配顺序

  1. 精准匹配
  2. 路径匹配,优先最长路径匹配
  3. 扩展名匹配

注意:两种配置方法不能同时使用

创建servlet的三种方式

1.实现javax.servlet.Servlet接口,这个接口定义了servlet的生命周期,所有的方法都要实现

@WebServlet("/HelloServlet")
public class UserServlet 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 {
        servletResponse.getWriter().print("<h1>hello servlet</h1>");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

image-20210301222250230

2.继承javax.servlet.GenericServlet类

public class GenServlet extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        servletResponse.getWriter().print("<h1>hello GenericServlet</h1>");
    }
}

image-20210301223043024

3.继承javax.servlet.http.HttpServlet类,会根据请求的类型进行特殊的调用

public class HServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().print("<h1>hello HttpServlet</h1>");
    }
}

image-20210301223842017

请求和响应

RERUEST

概述

request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法,这说明在service()方法中可以通过request对象来获取请求数据。

request的功能可以分为以下几种:

  • 封装了请求头数据;
  • 封装了请求正文数据,如果是GET请求,那么就没有正文;
  • request是一个域对象,可以把它当成Map来添加获取数据;
  • request提供了请求转发和请求包含功能。(以后学习)

操作请求行和请求头方法

方法名 描述
getRequestURL() 获取客户端发出请求时的完整URL
getRequestURI() 获取请求行中的资源名称部分(项目名称开始)
getQueryString() 获取请求行中的参数部分
getMethod() 获取客户端请求方式
getProtocol() 获取HTTP版本号
getContextPath() 获取webapp名字
getRemoteAddr() 获取客户机的IP地址(知道是谁请求的)
getServerPort 获得服务端的端口
// 获取客户端请求的完整URL (从http开始,到?前面结束)
String url = req.getRequestURL().toString();
System.out.println("获取客户端请求的完整URL:" + url);
// 获取客户端请求的部分URL (从站点名开始,到?前面结束)
String uri = req.getRequestURI();
System.out.println("获取客户端请求的部分URL:" + uri);
// 获取请求行中的参数部分 (从?后面开始,到最后)
String queryString = req.getQueryString();
System.out.println("获取请求行中的参数部分:" + queryString);
// 获取客户端的请求方式
String method = req.getMethod();
System.out.println("获取客户端的请求方式:" + method);
// 获取HTTP版本号
String protocol = req.getProtocol();
System.out.println("获取HTTP版本号:" + protocol);
// 获取webapp名字(站点名)
String webapp = req.getContextPath();
System.out.println("获取webapp:" + webapp);

操作请求体方法

方法名 描述
getParameter(name) 获取指定名称的参数
getParamerterValues(String name) 获取指定名称参数的所有值,返回数组
Map<String , String[]> getParamterMap() 获得所有的请求参数。key为参数名,value为key对应的值
setCharcterEncoding("UTF-8") 针对POST乱码问题的处理方式
// 针对POST乱码问题的处理方式
req.setCharacterEncoding("UTF-8");
// 获取指定名称的参数,返回字符串
String uname = req.getParameter("uname");
System.out.println("uname的参数:" + uname);
// 获取指定名称参数的所有参数值,返回数组
String[] hobbys = req.getParameterValues("hobby");
System.out.println("获取指定名称参数的所有参数值:" + Arrays.toString(hobbys));

请求转发

特点:

  • 请求路径不会变化
  • 请求转发只有1次请求
  • 路径写相对路径,不要写绝对路径
  • 转发只能转发到当前项目的资源,不能转发到外部资源
  • 可以转发到WEB-INF里面的资源
  • 请求转发的路径只能写相对路径,不能写绝对路径
  • 请求转发地址栏不会变

请求转发表示由 多个Servlet共同来处理一个请求 。例如Servlet1来处理请求,然后Servlet1又转发给Servlet2来继续处理这个请求。

public class AServlet extends HttpServlet { 
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        System.out.println("AServlet"); 
        RequestDispatcher rd = request.getRequestDispatcher("/BServlet"); 
        rd.forward(request, response); 
    }
}
public class BServlet extends HttpServlet { 
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        System.out.println("BServlet"); 
    } 
}

request域方法

方法名 描述
void setAttribute(String name, Object value) 用来存储一个对象,也可以称之为存储一个域属性,
Object getAttribute(String name) 用来获取request中的数据,当前在获取之前需要先去存储才行例如:String value = (String)request.getAttribute(“xxx”);,获取名为xxx的域属性;
void removeAttribute(String name) 用来移除request中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
Enumeration getAttributeNames() 获取所有域属性的名称;

一个请求会建一个request对象,如果在一个请求中经历了多个Servlet,那么多个Servlet就可以使用request来共享数据。

域方法通常在进行重定向时使用,多个servlet共享数据。

@WebServlet("/ris")
public class RegionServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("RegionServlet");

        req.setAttribute("akey", "aaa");
        //一次请求转发
        req.getRequestDispatcher("/trs").forward(req, resp);
    }
}
@WebServlet(name = "TheRequestServlet", urlPatterns = "/trs")
public class TheRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //取值
        System.out.println("akey的值:" + req.getAttribute("akey"));
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

RESPONSE

概述

response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse。在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作。

response对象的功能分为以下四种:

  • 设置响应头信息;
  • 发送状态码;
  • 设置响应正文;
  • 重定向;

操作响应行

方法名 描述
void setStatus(int sc) 设置状态码
HTTP/1.1 200

常用的状态码:(必须记忆)

​ 200:成功

302:重定向

​ 304:访问缓存

​ 404:客户端错误

​ 500:服务器错误

操作响应头

方法名 描述
void setDateHeader(String name,long date)
void setHeader(String name,String value)(重点)
void setHeader(String name,int value)
void addDateHeader(String name,long date)
void addHeader(String name,String value)
void addHeader(String name,int value)

常用的响应头

​ Refresh:定时跳转 (eg:服务器告诉浏览器5s之后跳转到百度)

​ Location:重定向地址(eg: 服务器告诉浏览器重定向到xxx)

​ Content-Disposition: 告诉浏览器下载

​ Content-Type:设置响应内容的MIME类型(服务器告诉浏览器内容的类型)

响应乱码问题

* 字符流
* getWriter()
*      一定会乱码,应为服务器默认的解析编码时ISO-8869-1,该编码不支持中文
*
* 字节流
* getOutputStream()
*      可能乱码,当前服务器的编码与客户端的编码不一致时,会出现乱码
*      
* 解决方案
*          1.设置服务端的编码格式
*          2.设置客户端的编码格式
* 总结:
*      设置客户端和服务端的编码格式保持一致,且支持中文
*      响应json格式的数据时,设置响应类型为application/json
public class Servlet02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //方法一
        //同时设置客户端和服务端的编码(推荐)
        resp.setContentType("text/html;charset=UTF-8");

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

        PrintWriter writer = resp.getWriter();
        writer.write("<h2>你好</h2>");
        writer.flush();
        writer.close();
    }
}

定时刷新

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletRefresh...");
        resp.setHeader("Content-type", "text/html;charset=utf-8");

        resp.getWriter().write("<h1>刷新</h1>");
        //定时刷新当前页面,循环
//        resp.setHeader("Refresh", "3");
        //定时刷新指定页面,刷新一次
        resp.setHeader("Refresh", "3;https://www.baidu.com");
        //定时刷新本地页面
//        resp.setHeader("Refresh", "3;trs");

    }

重定向

方法名 描述
void sendRedirect(String location) 重定向
  1. 重定向两次请求
  2. 重定向的地址栏路径改变
  3. 重定向的路径写绝对路径(带域名/ip地址的, 如果是同一个项目里面的,域名/ip地址可以省略)
  4. 重定向的路径可以是项目内部的,也可以是项目以外的(eg:百度)
  5. 重定向不能重定向到WEB-INF下的资源
  6. 把数据存到request里面, 重定向不可用

设置状态码重定向

响应码为200表示响应成功,而响应码为302表示重定向。所以完成重定向的第一步就是设置响应码为302。

因为重定向是通知浏览器再第二个请求,所以浏览器需要知道第二个请求的URL,所以完成重定向的第二步是设置Location头,指定第二个请求的URL地址。

public class Servlet03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ///设置状态码重定向
        resp.setStatus(302);
        resp.setHeader("Location","http://www.baidu.com");
    }
}

便捷重定向

public class Servlet03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //便捷重定向
        resp.sendRedirect("http://www.baidu.com");
        //如果要重定向的URL是在同一个服务器内,那么可以使用相对路径,例如:
        resp.sendRedirect("/serspn/ser04");
    }
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 重定向的路径: 相对路径
    //resp.sendRedirect("index.html");
    // 重定向的路径: 绝对路径
    //resp.sendRedirect("http://localhost:8080/day24/index.html");
    // 使用绝对路径访问内部项目中的资源可以省略http,ip地址,端口号
    //resp.sendRedirect("/day24/index.html");// 绝对路径

    // 重定向到WEB-INF下的资源
    //resp.sendRedirect("http://localhost:8080/day24/WEB-INF/b.html");// 报错,不可以
}

重定向小结

  • 重定向是两次请求,请求转发是一次
  • 重定向的URL可以是其他应用,不局限于当前应用;
  • 重定向的响应头为302,并且必须要有Location响应头;
  • 重定向就不要再使用response.getWriter()或response.getOutputStream()输出数据,不然可能会出现异常;

请求转发与重定向的区别

  1. 转发是一次请求, 重定向是二次请求
  2. 转发的路径不会改变,重定向的路径会改变
  3. 转发只能转发到项目的内部资源,重定向可以重定向到项目的内部资源, 也可以是项目外部资源(eg:百度)
  4. 转发可以转发到WEB-INF下面的资源, 重定向不可以重定向到WEB-INF下面的资源
  5. 把数据存到request里面,转发有效, 重定向无效
  6. 转发的路径写相对的(不带http,不带ip,不带项目名), 重定向的路径写绝对的(带http,带ip,带项目名),重定向到内部项目,可以省略http,ip地址,端口号

操作响应体

方法名 描述
ServletOutputStream getOutputStream()
PrintWriter getWriter()

响应正文

response是响应对象,向客户端输出响应正文(响应体)可以使用response的响应流,repsonse一共提供了两个响应流对象:

  • PrintWriter out = response.getWriter():获取字符流,处理字符;
  • ServletOutputStream out = response.getOutputStream():获取字节流,处理文件;

在一个请求中,不能同时使用这两个流!也就是说,要么你使用repsonse.getWriter(),要么使用response.getOutputStream(),但不能同时使用这两个流。不然会抛出IllegalStateException异常。

public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /**
         * 字符输出流
         */
        PrintWriter writer = resp.getWriter();
        writer.write("<h2>你好</h2>");
        writer.flush();
        writer.close();

        /**
         * 字节输出流
         */
        ServletOutputStream out = resp.getOutputStream();
        out.write("你好".getBytes());
        out.write("<h2>你好</h2>".getBytes());
        out.flush();
        out.close();
    }
}

文件下载案例

Cookie对象

Cookie的创建和发送

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

public class scookie01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //创建Cookie
        Cookie cookie = new Cookie("name","zhangsan");
        //发送cookie
        resp.addCookie(cookie);
    }
}

image-20210307195306092

Cookie的获取

在服务器端只提供了一个getCookie()方法用来获取客户端回传的所有cookie组成的一个数组,如果需要获取单个cookie则需要通过遍历,getName()获取Cookie的名称getValue()获取Cookie值

public class SCookie02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie[] cookies = req.getCookies();
        if (cookies != null & cookies.length > 0){
            for (Cookie cookie : cookies){
                System.out.println(cookie.getName());
                System.out.println(cookie.getValue());
            }
        }
    }
}

Cookie设置到期时间

默认当前浏览器关闭即失效。我们可以手动设定cookie的有效时间(通过到期时间计算),通过setMaxAge(int time);方法设定cookie的最大有效时间,以秒为单位

负整数

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

正整数

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

表示cookie作废,如果原来浏览器已经保存了这个Cookie,那么可以通过setMaxAge(0)来删除这个Cookie

public class SCookie03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("aa","AAA");
        // 负整数,表示浏览器关闭即失效
        //cookie.setMaxAge(-1);
        // 正整数,表示存活指定秒数
        //cookie.setMaxAge(15);
        // 零,表示删除cookie
        cookie.setMaxAge(0);
        //响应cookie
        resp.addCookie(cookie);
        
        // 删除已有cookie
        Cookie cookie1 = new Cookie("name", null);
        cookie1.setMaxAge(0);
        resp.addCookie(cookie1);

    }
}

Cookie的注意点

输入中文

public class SCookie04 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = "姓名";
        String value = "李青";
        // 通过URLEncoder.encode()进行编码
        name = URLEncoder.encode(name);
        value = URLEncoder.encode(value);
        // 创建Cookie对象
        Cookie cookie = new Cookie(name, value);
        // 发送Cookie对象
        resp.addCookie(cookie);
    }
}

同名问题

如果浏览器发送重复的Cookie会覆盖原有的Cookie

浏览器存放Cookie的数量

不同的浏览器对Cookie有限定,Cookie的存储是有上限的。Cookie是存储在客户端(浏览器)的,而且一般是由服务器创建和设定。后期结合Session来实现回话跟踪。

Cookie的路径

public class SCookie06 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //当前项目下的资源可获取Cookie对象(默认不设置Cookie的path)
        Cookie cookie = new Cookie("a1", "A1");
        resp.addCookie(cookie);

        // 当前服务器中,任意资源都可以访问
        Cookie cookie1 = new Cookie("a2", "A2");
        cookie1.setPath("/");
        resp.addCookie(cookie1);

        //指定目录下的资源可以获取Cookie对象
        Cookie cookie2 = new Cookie("a3", "A3");
        cookie2.setPath("/serspn/test/scok02");
        resp.addCookie(cookie2);

        //指定项目下的资源可获取Cookie对象(指定站点名)
        Cookie cookie3 = new Cookie("a4", "A4");
        cookie3.setPath("/ser");
        resp.addCookie(cookie3);
    }
}

HttpSession对 象

基本使用

public class Session01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取Session对象(如果session对象不存在,则新建session对象;如果session存在,则获取session对象)
        HttpSession session = req.getSession();
        //获取session的标识符
        System.out.println(session.getId());
        //获取第一次访问时间
        System.out.println(session.getCreationTime());
        //获取最后一次访问时间
        System.out.println(session.getLastAccessedTime());
        //是否是新的session对象
        System.out.println(session.isNew());
        //设置session域对象(一次对话有效)
        session.setAttribute("uname","admin");
        //获取指定名称的session域对象
        String uname = (String) req.getAttribute("uname");
        //移除指定名称的session域对象
        session.removeAttribute("uname");
    }
}

session对象的销毁

默认时间到期

Tomcat中conf目录下的web.xml文件中进行修改

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

自己设定到期时间

通过session.setMaxInactiveInterval(int)来设定session的最大活动时间,单位为秒

//获取session对象
HttpSession session = req.getSession();
//设置session的最大活动时间
session.setMaxInactiveInterval(15);
//获取session的最大不活动时间
int time = session.getMaxInactiveInterval();       

立刻失效

//销毁session对象
session.invalidate();

关闭浏览器

seesion的底层依赖cookie实现,cookie的有效时间为关闭浏览器,从而seesion在浏览器关闭时也会失效

关闭浏览器

关闭服务器意味着此次会话结束,数据共享结束

ServletContext对象

public class ServletContext extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过request获取对象
        javax.servlet.ServletContext servletContext = req.getServletContext();
        //通过Session获取
        javax.servlet.ServletContext servletContext1 = req.getSession().getServletContext();
        //通过ServletConfig对象获取
        javax.servlet.ServletContext servletContext2 = getServletConfig().getServletContext();
        //直接获取
        javax.servlet.ServletContext servletContext3 = getServletContext();

        //常用方法
        //获取服务器版本信息
        String serverInfo = servletContext.getServerInfo();
        System.out.println("获取服务器的版本信息:" + serverInfo);

        //获取项目的真实路径
        String realPath = servletContext.getRealPath("/");
        System.out.println("获取项目的真实路径:" + realPath);
    }
}

Servlet三大作用域

request域对象
再一次请求中有效,请求转发有效,重定向有效
session域对象
在一次会话中有效,请求转发和重定向都有效,seesion销毁后失效
servletContext域对象
在整个应用程序中有效,服务器关闭后失效

Jsp

jsp基本语法

<% %> Service()方法内操作
request.setAttribute("key",value)

<%= %> Service()方法内输出操作
request.getAttribute("key");

<%! %> class中操作
private int a;

EL语法

​ 作用域:resquest session application(ServletContext)

获取数据
    ${requestScope.get("AName")}  &  ${AName}  获取简单数据
    ${sessionScopr.get("ArrayName")[index]}  &  ${ArrayName[index]} 获取数组数据
    ${application.get("ListName").get(index)}  &  ${ListName[index]}  获取list数据
    ${map.get(key)  &  ${map.Key} 获取map数据
    ${class.getField()}  &  ${class.filed} 获取Bean数据 

运算
    ${int + int}
    判断
    ${int > int}

JSTL语法

​ jar包:standard.jar & jstl.jar
​ 核心标签库:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.apache.taglibs/taglibs-standard-impl -->
<dependency>
    <groupId>org.apache.taglibs</groupId>
    <artifactId>taglibs-standard-impl</artifactId>
    <version>1.2.5</version>
    <scope>runtime</scope>
</dependency>

if标签

    <c:if test="${el判断}" [var="给定test结果一个变量名"] [scope="将变量名保存域中 默认page"]>
    	test=true则在代码块中执行操作
    </c:if>

choose标签 (了解)

    <c:choose>
        <c:when test="el表达式"> 
        	test=true则在代码块中执行操作
        </c:when>  == if(){}  
        可以有多个when
        
        <c:otherwise>
        	上面条件都不满足执行此代码块操作
        </c:otherwise>== else{}
    </c:choose>

forEach标签

07-1635680725382

image-20211031193958836

<%
    ArrayList<String> list = new ArrayList<>();
    list.add("leesin");
    list.add("zed");
    list.add("king");
    request.setAttribute("list", list);
%>

<%--       迭代对象          迭代步数  起始索引    结束索引    当前对象存到page域    当前对象的迭代信息存到page域--%>
<c:forEach items="${list}" step="1" begin="0" end="3"   var="e"            varStatus="status">
    ${e}<br/>
    当前循环的索引:${status.index}<br/>
    当前循环的次数:${status.count}<br/>
    当前迭代出来的元素是否是最后一个元素:${status.last}<br/>
    当前迭代出来的元素是否是第一个元素:${status.first}<br/>
    当前索引:${status.current}<br/>
    迭代步长:${status.step}<br/>
    迭代终位:${status.end}<br/>
    迭代始位:${status.begin}<br/>
    <hr/>
</c:forEach>

image-20211031195507600

posted @ 2021-03-07 22:28  yonugleesin  阅读(133)  评论(0编辑  收藏  举报