Java Web(八)--Servlet(三)

 会话技术

为什么需要?

  •     每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服务器要想办法为每个用户保存这些数据;
  •     用户通过浏览器访问 Web 应用时,服务器都需要保存和跟踪用户的状态;由于 HTTP 协议是无协议的,无法保存和跟踪用户状态,因此需要会话技术来解决该问题。

是什么?

  • 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,为一次会话。
  • 用户开一个浏览器,点击多个超链接,访问服务器多个 web 资源,然后关闭浏览器,整个过程称之为一个会话。
  • 会话技术是指在会话中,帮助服务器记录用户状态和数据的技术。
  • 会话技术可分为Session(服务端会话技术)和Cookie(客户端服务技术),两者相互关联,可理解为一体的。在Servlet中提供了Cookie对象与HttpSession对象用于维护客户端与服务端的会话状态的维持。

cookie

Cookie(小甜饼)是客户端技术。

  •     服务器把每个用户的数据以 cookie 的形式写给并保存在用户各自的浏览器(客户端);服务器端在需要的时候可以从客户端/浏览器读取(基于 HTTP 协议实现),比如登录名,浏览历史等。
  •     当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去,这样,web 资源处理的就是用户各自的数据。
  •     Cookie 信息的数据量并不大,安全性相对于Session技术来说比较低,因为客户端可以清除Cookie。

缺点:

  • 在 HTTP 请求中,Cookie 是明文传递的,容易泄露用户信息,安全性不高。
  • 浏览器可以禁用 Cookie,一旦被禁用,Cookie 将无法正常工作。
  • Cookie 对象中只能设置文本(字符串)信息。
  • 客户端浏览器保存 Cookie 的数量和长度是有限制的。

工作流程

  1. 客户端浏览器访问服务器时,服务器通过在 HTTP 响应中增加 Set-Cookie 字段,将数据信息发送给浏览器;
  2. 浏览器将 Cookie 保存在内存中或硬盘上【调用 setMaxAge(int maxAge) 方法设置最大有效时间实现,单位为秒】;
  3. 再次请求该服务器时,浏览器通过在 HTTP 请求消息中增加 Cookie 请求头字段,将 Cookie 回传给 Web 服务器服务器根据 Cookie 信息跟踪客户端的状态;

相关API

Cookie 有点象一张表(K-V),分两列,一个是名字,一个是值,数据类型都是 String ;

如何创建一个 Cookie(在服务端创建的)

  • Cookie c=new Cookie(String name,String val);
  • c.setMaxAge();//保存时间;Cookie 保存到浏览器的内存中,默认浏览器关闭则 Cookie 失效

如何将一个 Cookie 添加到客户端 

  •     response.addCookie(c);

如何读取cookie(在服务器端读取到 cookie 信息) 

  •     request.getCookies();

javax.servlet.http.Cookie 类中提供了一系列获取或者设置 Cookie 的方法,如下表。 

返回值类型方法描述
intgetMaxAge() 用于获取指定 Cookie 的最大有效时间,以秒为单位。
默认情况下取值为 -1,表示该 Cookie 保留到浏览器关闭为止。
StringgetName() 用于获取 Cookie 的名称。
StringgetPath()用于获取 Cookie 的有效路径。
booleangetSecure() 如果浏览器只通过安全协议发送 Cookie,则返回 true;如果浏览器可以使用任何协议发送 Cookie,则返回 false。
StringgetValue() 用于获取 Cookie 的值。
 intgetVersion() 用于获取 Cookie 遵守的协议版本。
voidsetMaxAge(int expiry)

用于设置 Cookie 的最大有效时间,以秒为单位。

  • 取值为正值时,表示 Cookie 在经过指定时间后过期。
  • 取值为负值时,表示 Cookie 不会被持久存储,在 Web 浏览器退出时删除。【默认值为-1】
  • 取值为 0 时,表示删除该 Cookie。
voidsetPath(String uri) 用于指定 Cookie 的路径。 
voidsetSecure(boolean flag)用于设置浏览器是否只能使用安全协议(如 HTTPS 或 SSL)发送 Cookie。
 voidsetValue(String newValue)用于设置 Cookie 的值。 

说明:

【1】setMaxAge(int expiry):

expiry为正数时,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享。

expiry为正0时,表示cookie即不在内存中存活,也不在硬盘上存活;是为了覆盖客户端原来的这个cookie,使其作废。

【2】有效路径Path
    Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器、 哪些不发;path属性是通过请求的地址来进行有效的过滤。

    规则:cookie1.setPath = /工程路径; cookie2.setPath = /工程路径/aaa;

        请求地址: http://ip:端口/工程路径/资源

  •             cookie1 会发给服务器
  •             cookie2 不会发给服务器

        请求地址: http://ip:端口/工程路径/aaa/资源

  •             cookie1 会发给服务器
  •             cookie2 会发给服务器

应用实例

需求:

演示 Cookie 底层实现机制, 创建和读取 Cookie。

流程:

1、创建src\com\edu\cookie\CreateCookie.java ,并在 web.xml 完成配置

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 演示如何创建cookie,并保存到浏览器
 */
public class CreateCookie extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CreateCookie 被调用...");

        //1. 创建一个Cookie对象
        //1) username 该cookie的名字 是唯一, 可以理解成是key
        //2) lhy : 该cookie的值
        //3) 可以创建多个cookie,老师就创建了一个
        //4) 这是cookie在服务器端, 还没有到浏览器
Cookie cookie = new Cookie("key1", "value1");
Cookie cookie2 = new Cookie("key2", "value2");

        response.setContentType("text/html;charset=utf-8");
        //2. 将cookie发送给浏览器, 让浏览器将该cookie保存
        response.addCookie(cookie);
        response.addCookie(cookie2);

        PrintWriter writer = response.getWriter();
        writer.println("<h1>创建cookie成功~</h1>");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

2、访问 CreateCookie.java, 使用浏览器抓包分析 , 创建 Cookie 的底层机制


3、创建src\com\hspedu\cookie\ReadCookie.java

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 读取从浏览器发送来的cookie信息[底层仍然是http协议]
 */

public class ReadCookies extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ReadCookies 被调用..");
       
 //1. 通过request对象读取cookie信息
        Cookie[] cookies = request.getCookies();

 //2. 遍历cookie
        if (cookies != null && cookies.length != 0) {
            for (Cookie cookie : cookies) {
                System.out.println("cookie name= " + cookie.getName()
                        + " value= " + cookie.getValue());
            }
        }

        //3. 给浏览器返回信息        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>读取cookie信息成功~</h1>");
        writer.flush();
        writer.close();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

4、访问 ReadCookie.java, 使用浏览器抓包分析 读取 Cookie 的底层机制。    

说明:

  • 不同会话,jsessionid 不同;
  • 不同的浏览器,可能看到的cookie信息不完全相同;
  • 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE);
  • 一个WEB站点可以给一个浏览器发送多个Cookie,一个浏览器也可以存储多个WEB站点提供的Cookie;
  • cookie的总数量没有限制,但是每个域名的COOKIE数量和每个COOKIE的大小是有限制的(不同的浏览器限制不同,知道即可),Cookie不适合存放数据量大的信息;
  • 使用 setMaxAge(0) 手动删除 Cookie时,需要使用 setPath 方法指定 Cookie 的路径,且该路径必须与创建 Cookie 时的路径保持一致;
  • 注意:如果存放中文的cookie,默认报错,可以通过URL编码和解码来解决,不建议存放中文的cookie信息;

session

为什么需要?

  •     不同的用户登录网站后,不管该用户浏览该网站的哪个页面,都可显示登录人的名字,还可以随时去查看自己的购物车中的商品,  是如何实现的?
  •         也就是说,一个用户在浏览网站不同页面时,服务器是如何知道是张三在浏览这个页面,还是李四在浏览这个页面?

是什么?

Session 是服务器端技术

  •     当用户打开浏览器,访问 Web 服务器的资源【不是HTML,CSS,图片等静态资源】时,服务器就会在内存(在服务端)为该浏览器分配一个 session 对象,该 session 对象被这个浏览器独占。
  • 由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的 session 中读取/添加数据, 从而完成相应任务;
  • Session 对象也是一种域对象,它可以对属性进行操作,进而实现会话中请求之间的数据通讯和数据共享;

存储结构为 ConcurrentHashMap, 可以把 session  看作是一容器类似 HashMap,有两列(K-V),每一行就是 session 的一个属性。每个属性包含有两个部分,一个是该属性的名字(String),另外一个是它的值(Object)。       

    应用场景

  •     网上商城中的购物车
  •     保存登录用户的信息
  •     将数据放入到 Session 中,供用户在访问不同页面时,实现跨页面访问数据
  •     防止用户非法登录到某个页面。。。

工作原理

  1. 当客户端第一次请求会话对象时,服务器会创建一个 Session 对象,并为该 Session 对象分配一个唯一的 SessionID(用来标识这个 Session 对象);
  2. 服务器将 SessionID 以 Cookie(Cookie 名称为:“JSESSIONID”,值为 SessionID 的值)的形式发送给客户端浏览器;
  3. 客户端浏览器再次发送 HTTP 请求时,会将携带 SessionID 的 Cookie 随请求一起发送给服务器;
  4. 服务器从请求中读取 SessionID,然后根据 SessionID 找到对应的 Session 对象。

说明

【1】session 对象的存活时间

session 对象也可看做是一个容器/集合,默认存在时间为 30min。【指Session 对象在服务器中驻留一段时间后没有被使用,就会被销毁】
    设置方式

  •         1. 使用 <session-config> 元素
  •         2. 调用 setMaxInactiveInterval() 方法    
在 web.xml 中,使用 <session-config> 及其子元素 <session-timeout> 可以配置 Session 的默认过期时间,代码如下。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!--设置session的过期时间-->
    <session-config>
        <session-timeout>10</session-timeout>
    </session-config>
</web-app>

<session-timeout> 元素用来指定默认 Session 过期时间,以分钟为单位,该元素值必须为整数。
<session-timeout> 元素的值为零或负数,表示 Session 永远不会过期。
//设置会话的过期时间
//以秒为单位,零和负数表示会话永远不会过期
request.getSession().setMaxInactiveInterval(100);

public int getMaxInactiveInterval()
	获取  Session 的超时时间
public void invalidate()  
	让当前  Session 会话立即无效

【2】 Cookie对象

流程中的 Cookie 是容器自动生成的,它的 maxAge 属性取值为 -1,表示仅当前浏览器有效。

浏览器关闭时,对应的 Session 并没有失效,但此时与此 Session 对应的 Cookie 已失效,导致浏览器无法再通过 Cookie 获取服务器端的 Session 对象。

同一浏览器的不同窗口共享同一 Session 对象,但不同浏览器窗口之间不能共享 Session 对象。


相关API

Session 对象由服务器创建,通过 HttpServletRequest.getSession() 方法可以获得 HttpSession 对象,例如:

  • //获取session对象
  • HttpSession session=request.getSession();

HttpSession 接口定义了一系列对 Session 对象操作的方法,如下表。

返回值类型方法描述
longgetCreationTime()返回创建 Session 的时间。
StringgetId()返回获取 Seesion 的唯一的 ID。
longgetLastAccessedTime()返回客户端上一次发送与此 Session 关联的请求的时间。
intgetMaxInactiveInterval() 返回在无任何操作的情况下,Session 失效的时间,以秒为单位。
ServletContextgetServletContext() 返回 Session 所属的 ServletContext 对象。
voidinvalidate() 使 Session 失效。
voidsetMaxInactiveInterval(int interval)指定在无任何操作的情况下,Session 失效的时间,以秒为单位。负数表示 Session 永远不会失效。

生命周期

Session 的生命周期指的是 :客户端/浏览器同一个会话两次请求之间最大间隔时长,而不是累积时长。

  •         值为正数,设定Session的超时时长
  •         值为负数,表示永不超时
  •         即当客户端访问了自己的 session,session 的生命周期将从 0 开始重新计算;
  •         底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁;
  • 如果你在 session 没有过期的情况下,操作 session, 则会重新开始计算生命周期;而    session 是否过期,是由服务器来维护和管理

包括

  •     1、Session对象的创建:在容器第一次调用 request.getSession() 方法时创建。
  •     2、Session对象的销毁
    •     Session 过期;
    •     调用 session.invalidate() 方法,手动销毁 Session;
    •     服务器关闭或者应用被卸载
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

public class CreateSession2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("CreateSession2 被调用");

        //创建session
        HttpSession session = request.getSession();
        System.out.println("CreateSession2 sid= " + session.getId());

        //设置生命周期为 60s
        session.setMaxInactiveInterval(60);
        session.setAttribute("u", "jack");

        //回复一下浏览器
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>创建session成功, 设置生命周期60s</h1>");
        writer.flush();
        writer.close();

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

区别

不同点CookieSession
存储位置不同Cookie 将数据存放在客户端浏览器内存中或硬盘上。Session 将数据存储在服务器端。
大小和数量限制不同浏览器对 Cookie 的大小和数量有限制。Session 的大小和数量一般不受限制。
存放数据类型不同Cookie 中保存的是字符串。Session 中保存的是对象。
安全性不同Cookie 明文传递,安全性低,他人可以分析存放在本地的 Cookie 并进行 Cookie 欺骗。Session 存在服务器端,安全性较高。
对服务器造成的压力不同Cookie 保存在客户端,不占用服务器资源。Session 保存在服务端,每一个用户独占一个 Session。若并发访问的用户十分多,就会占用大量服务端资源。
跨域支持上不同Cookie 支持跨域名访问。Session 不支持跨域名访问。

请求的转发和重定向

转发

为什么用? 
    在实际开发中,往往业务比较复杂,需要在一次请求中,使用到多个 Servlet 完成一个任务(Servlet 链,  流水作业)  。【而 Serlvet 对象无法直接调用其他 Servlet 的 service() 方法】

是什么?

请求转发属于服务器行为,指一个 web 资源收到客户端请求后,通知服务器去调用另外一个 web 资源进行处理。在Servlet中,Servlet(源组件)先对客户请求做一些预处理操作,然后把请求转发给其它Servlet(目标组件)来完成包括生成响应结果在内的后续操作。

javax.servlet 包中定义了一个 RequestDispatcher 接口,RequestDispatcher 对象由 Servlet 容器创建,用于封装由路径所标识的 Web 资源,利用 RequestDispatcher 对象的 forward 方法可以把请求转发给其它的 Web 资源。

RequestDispatcher 对象的创建

  •     调用 ServletContext 的 getRequestDispatcher(String path) 方法,参数 path 指定目标资源的路径,必须为绝对路径;
  •     调用 ServletRequest 的 getRequestDispatcher(String path) 方法,参数 path 指定目标资源的路径,可以为绝对路径,也可为相对路径;

RequestDispatcher 的相关API如下: 

返回类型方法描述
voidforward(ServletRequest request,ServletResponse response) 用于将请求转发给另一个 Web 资源。该方法必须在响应提交给客户端之前被调用,否则将抛出 IllegalStateException 异常
voidinclude(ServletRequest request,ServletResponse response) 用于将其他的资源作为当前响应内容包含进来

特点:

    请求转发不支持跨域访问,只能跳转到当前应用中的资源。

  •         可以转发到  WEB-INF 目录下(后面做项目使用),不能访问当前WEB 工程外的资源;

    请求转发之后,浏览器地址栏中的 URL 不会发生变化,因此浏览器不知道在服务器内部发生了转发行为,更无法得知转发的次数。 

  • 地址会保留在第 1 个 servlet 的 url;如果你刷新页面,会再次发出请求(并且会带数据);所以在支付页面情况下,不要使用请求转发,否则会造成重复支付。

    参与请求转发的 Web 资源之间共享同一 request 对象和 response 对象。在同一次HTTP 请求中,进行多次转发,仍然是一次 HTTP 请求;因为 forward() 方法会先清空 response 缓冲区,因此只有转发到最后一个 Web 资源时,生成的响应才会被发送到客户端。

代码实现
	1、开发一个登录页面
	2、创建src\com\hspedu\servlet\request\CheckServlet.java
	3、创建src\com\hspedu\servlet\request\ManageServlet.java
	4、测试
		注意看浏览器的请求次数和数据通信情况
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form action="http://localhost:8080/servlet/computerServlet" method="post">
    u: <input type="text" name="username"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>


import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CheckServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CheckServlet 被调用..");

        //根据用户名来确定该用户是什么身份
        String username = request.getParameter("username");
        //注意:如果是同一个request对象(请求转发),那么可以在不同的servlet中,是getParameter
        if ("tom".equals(username)) {
            //分配
            request.setAttribute("role", "管理员");
        } else {
            request.setAttribute("role", "普通用户");
        }

//获取分发器RequestDispatcher对象
// 1. /manageServlet写的是 要转发的servlet的url
// 2. / 会被解析成 /servlet
// 3. forward(request, response) 表示把当前servlet的request对象和response对象,传递给下一个servlet使用

        RequestDispatcher requestDispatcher =
                request.getRequestDispatcher("/manageServlet");

        requestDispatcher.forward(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}



import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class ManageServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("ManageServlet 被调用..");

        String username = request.getParameter("username");
        String role = (String) request.getAttribute("role");

        //输出信息
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("用户名: " + username + "<br/>");
        writer.print("角色 : " + role);
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

重定向

重定向属于客户端行为。

请求重定向指的是服务器端接收到客户端的请求之后,会给客户端返回了一个临时响应头,这个临时响应头中记录了客户端需要再次发送请求(重定向)的 URL 地址,客户端再次收到了地址之后,会将请求发送到新的地址上,这就是请求重定向。

响应重定向是通过HttpServletResponse对象sendRedirect(“路径”)的方式实现是,是服务器通知浏览器,让浏览器去自主请求其他资源的一种方式。

  •     本质上是两次 HTTP 请求,对应两个 request 对象和两个 response 对象
  •     不能重定向到  /WEB-INF 下的资源,可以重定向到Web  工程以外的资源, 比如 到 www.baidu.com ;

最佳应用场景

  •     网站迁移,比如原域名是 www.hsp.com    迁移到 www.hsp.cn  ,但是百度抓取的还是原来网址.

如何实现:

方式1__推荐方式: response.sendRedirect("/hiServlet/servlet02")

方式2:

//1.设置响应状态码302,表示重定向;

//2.设置响应头,说明新的地址在哪里

response.setStatus(302);

response.setHeader("Location","/hiServlet/servlet02")

原理说明 

  1.  用户在浏览器中输入 URL,请求访问服务器端的 Web 资源。
  2.  服务器端的 Web 资源返回一个状态码为 302 的响应信息;该响应的含义为:通知浏览器再次发送请求,访问另一个 Web 资源(在响应信息中提供了另一个资源的 URL)。
  3.     当浏览器接收到响应后,立即自动访问另一个指定的 Web 资源。
  4.     另一 Web 资源将请求处理完成后,由容器把响应信息返回给浏览器进行展示。

应用案例:
需求:演示请求重定向的使用:当访问DownServlet下载文件,重定向到DownServletNew下载文件。

1、创建src\com\hspedu\servlet\response\DownServlet.java
2、创建src\com\hspedu\servlet\response\DownServletNew.java
3、在 web.xml 中完成 servlet 配置
4、测试

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class DownServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // System.out.println("DownServlet 被调用");
        // response.setContentType("application/x-tar;charset=utf-8");
        // PrintWriter writer = response.getWriter();
        // writer.print("hi");
        // writer.flush();
        // writer.close();
        //完成了自己业务
        //发出请求重定向-> DownServletNew
        //1. sendRedirect 本质就会 返回 302 状态码 Location: /servlet/downServletNew
        //2. 因此 302和 /servlet/downServletNew 是浏览器解析,而不是服务器
        //3. 浏览器在解析 /servlet/downServletNew => http://localhost:8080/servlet/downServletNew
        //4. 动态获取到application context

        String contextPath = getServletContext().getContextPath();
        System.out.println("contextPath= " + contextPath);
        //response.sendRedirect("/servlet/downServletNew");
        response.sendRedirect(contextPath + "/downServletNew");
        //response.sendRedirect("http://www.baidu.com");

        //第二种重定向的写法
        // System.out.println("第二种方式重定向...");
        // response.setStatus(302); //设置http响应的状态码
        // //设置http响应的 Location: /servlet/downServletNew
        // response.setHeader("Location", "/servlet/downServletNew");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}



import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class DownServletNew extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("DownServletNew 被调用");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("ok");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}


 <servlet>
        <servlet-name>DownServlet</servlet-name>
        <servlet-class>com.hspedu.servlet.response.DownServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>DownServlet</servlet-name>
        <url-pattern>/downServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>DownServletNew</servlet-name>
        <servlet-class>com.hspedu.servlet.response.DownServletNew</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>DownServletNew</servlet-name>
        <url-pattern>/downServletNew</url-pattern>
    </servlet-mapping>




比较

请求转发和重定向的区别  

● 对于客户端浏览器来说,转发是一个请求,重定向是两个请求;

● 转发浏览器地址栏不变化,重定向会变成转发后的 URL ;

● 转发只能在一个项目内,而重定向没有限制,可以重定向到任意网(也就是跨域),如京东、淘宝等 ;

● 转发可以使用 request 域传递数据,而重定向不能。因为转发是一个请求,重定向是两个请求;

● 转发只有一个请求,原来是什么请求方式就是什么方式;而重定向两个请求,第一个可能为 post 可能为 get ,但是第二个请求一定是 get 。

区别转发重定向
浏览器地址栏 URL 是否发生改变
是否支持跨域跳转
请求与响应的次数一次请求和一次响应两次请求和两次响应
是否共享 request 对象和 response 对象
是否能通过 request 域对象传递数据
速度相对要快相对要慢
行为类型服务器行为客户端行为

其他

请求转发和重定向的路径问题

请求路径

@WebServlet(urlPatterns = "/Servlet1.do")
//@WebServlet(urlPatterns = "/c/c2/servlet1.do")

public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /**
         * 请求转发的路径写法
         * 相对基准路径:相对于当前Servlet本身的位置,urlPattern决定了位置
         * 绝对基准路径:永远是以项目为基准路径(不允许跨服务,所以绝对路径只能是本服务内的资源)
         */

        /*相对路径访问a1.html*/
        //RequestDispatcher requestDispatcher = req.getRequestDispatcher("a/a2/a1.html");

        /*urlpatterns会影响相对路径*/
        //RequestDispatcher requestDispatcher = req.getRequestDispatcher("../../a/a2/a1.html");

        /*绝对路径访问a1*/
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/a/a2/a1.html");
        requestDispatcher.forward(req,resp);
    }
}

请求转发路径总结:

1. 以"/"开头的路径是绝对路径,不以"/"开头是相对路径;

2. 绝对路径以当前项目名(或叫部署名)为根路径,"/"后不需要写当前项目名;

3. ../代表向上一层的路径;

4. Servlet的相对路径是相对于url-pattern中的路径,是虚拟的路径。

重定向路径

//@WebServlet(urlPatterns = "/c/c2/servlet2.do")
@WebServlet(urlPatterns = "/Servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 请求重定向到a1.html
        /**
         * 相对路径 相对于urlPatterns定义的路径
         * 绝对路径 :以项目部署路径为基准路径 (webapps)
         * 请求重定向的绝对路径中,要加项目部署名,除非当前项目没有给定部署名
         *
         */
        // resp.sendRedirect("../../a/a2/a1.html");
        //resp.sendRedirect("a/a2/a1.html");
        ServletContext servletContext = this.getServletContext();
        String contextPath = servletContext.getContextPath();//  /ServletModule5
        resp.sendRedirect(contextPath+"/a/a2/a1.html");
    }
}

请求重定向路径总结:

1. 以"/"开头的路径是绝对路径,不以"/"开头是相对路径;

2. 绝对路径以当前项目所在目录(Tomcat的webapps下)为根路径,绝对路径后需要写当前项目部署名;

3. ../代表向上一层的路径;

4. Servlet的相对路径是相对于url-pattern中的路径,是虚拟的路径;

路径的使用和记忆建议:

建议在url-pattern中,不要书写没有必要的多层次路径如:"/c/c2" ,因为这会影响请求转发和重定向的相对路径写法;

绝对路径在书写时,只有请求转发不需要写项目部署名,页面(如超链接)上和重定向的绝对路径都需要写项目的部署名;

相对路径在使用时,无论是页面(如超链接)还是请求转发还是请求重定向都不需要项目名;

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hahaha2221

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值