• Servlet(四):转发与重定向、路径问题


    在上次的小案例中用到了转发的技术,今天来仔细聊聊转发和重定向的问题,以及一些小知识的汇总。

    一、转发

    1、转发的概念

    转发主要是将浏览器的请求交给另外一个servlet或jsp来处理,借助request对象完成,在服务器内部跳转,浏览器的地址并不发生改变,并且浏览器并不知道服务器内部发生了跳转,整个过程只会发生一次请求,转发的调用者和被调用者都可以共享request对象和response对象。

    2、使用方法

    因为是将数据交到另外一个servlet或jsp来处理请求,所以第一步是将需要处理的数据绑定到request对象上,可以使用request.setAttribute(String name, Object obj)方法,其中name是绑定名,obj是绑定值;也可以使用request.getSession().setAttribute(String name, Object obj)方法,绑定到session对象上。

    第二步是获取转发器,也就是完成转发这件事需要用到的工具。

    RequestDispatcher rd = request.getRequestDispatcher(String url);

    url参数是转发的目标地址,可以是servlet,也可以是一个jsp页面,可以使用相对路径,也可以使用绝对路径。

    第三步是调用转发器的方法来转发。

    rd.forward(request,response);

    当然,如果熟练后,可以将第二步和第三步合并为一步。

    request.getRequestDispatcher(String url).forward(request, response);

    3、转发的优缺点

    转发的优点一是安全性高,在内部发生跳转,浏览器地址不变;二是节省资源,转发只需要一次请求,就可以访问至少两个servlet或jsp页面。在实际开发中,转发用到的较多。

    转发的缺点是只能在同一web应用内使用,不能转发到外部的url地址。

    二、重定向

    1、重定向的概念

    重定向是指服务器通知浏览器向一个新的地址发送请求,由response对象完成,可以重定向到新的servlet(服务器内部),也可以重定向到外部url(外部应用),浏览器地址发生改变,浏览器知道发生了跳转,整个过程会产生两次请求,重定向的调用者和被调用者不能共享request对象和response对象。

    2、使用方法

    response.sendRedirect(String url);

    url是重定向的地址,可以是绝对路径,也可以是相对路径。

    3、重定向的优缺点

    重定向的优点是不限制应用范围,可以重定向到服务器内部其他资源,也可以是外部的应用。

    重定向的缺点是耗费请求资源,重定向整个过程发生了两次的请求,一个是资源消耗上比转发大,效率也比转发低;另外,因为浏览器的地址发生了变化,相对转发来讲,安全性没有转发高。

    三、路径问题

    不管是使用转发还是重定向,都会涉及到路径的问题,路径分为相对路径、绝对路径。

    绝对路径是指以"/"开头的路径信息。相对路径是指不以"/"开头的路径信息。

    在项目中如果要使用绝对路径,重定向的路径是从应用名(上下文)开始,因为重定向时,服务器不知道这个请求是否在应用内部还是外部,所以需要加上应用名;转发时的路径是从应用名之后开始,转发是发生在服务器内部,在同一应用下,可以不用写应用名。

    为了避免直接将应用名写在地址里面,可以使用request.getContextPath()方法来替代。

    四、POST请求和GET请求

    在前几次的小例子中,会经常看见jsp页面写post请求和get请求,在后台处理请求的doPost和doGet方法,下面对post请求和get请求来做下说明。

    1、get请求

    浏览器在下列三种情况出现时,会发送get请求,一是直接输入某个地址,二是点击链接,三是表单默认的提交方式。

    get请求会将请求参数添加到请求资源路径的后面,是在get请求的url中发送的,url中只能存放2k左右的数据,并且请求参数会显示在浏览器地址栏,安全性较低,get请求会被缓存,会被保留在浏览器历史记录中,get请求只应用于取回数据。

    2、post请求

    设置表单的method属性值为post,浏览器会发送post请求。

    post请求会将请求参数放在http消息主体中发送,可以提交大量数据,不会显示在浏览器地址栏,相对安全,但是对于敏感数据需要进行手动加密处理,post请求不会被缓存,也不会被保留在浏览器历史记录中。

    五、验证转发与重定向,分别使用相对路径、绝对路径

    第一步,新建一个Maven项目,建好两个Servlet类,写好两个jsp页面

    package servlet;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 测试转发和重定向,分别使用相对路径、绝对路径
     * @author 小川94
     * @date 2018年6月10日
     */
    public class FirstServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        
        public FirstServlet() {
            super();
        }
        
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("FirstServlet--->>> 进入doGet方法,交由doPost方法处理...");
            doPost(request, response);
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("FirstServlet--->>> 执行POST请求...");
            // 转发到second.jsp,使用绝对路径(不需要带应用名)
            //request.getRequestDispatcher("/second/second.jsp").forward(request, response);
            
            // 转发到second.jsp,使用相对路径(不需要带应用名)
            //request.getRequestDispatcher("second/second.jsp").forward(request, response);
            
            // 重定向到second.jsp,使用绝对路径(需要带应用名),推荐使用第二种写法
            //response.sendRedirect("/servlet_day04/second/second.jsp");
            //response.sendRedirect(request.getContextPath()+"/second/second.jsp");
            
            // 重定向到second.jsp,使用相对路径(不需要带应用名)
            //response.sendRedirect("second/second.jsp");
            
            
            // 转发到SecondServlet,使用绝对路径(不需要带应用名)
            //request.getRequestDispatcher("/SecondServlet").forward(request, response);
            
            // 转发到SecondServlet,使用相对路径(不需要带应用名)
            //request.getRequestDispatcher("SecondServlet").forward(request, response);
            
            // 重定向到SecondServlet,使用绝对路径(需要带应用名),推荐使用第二种写法
            //response.sendRedirect("/servlet_day04/SecondServlet");
            //response.sendRedirect(request.getContextPath()+"/SecondServlet");
            
            // 重定向到SecondServlet,使用相对路径(不需要带应用名)
            response.sendRedirect("SecondServlet");
        }
    
    }
    package servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    public class SecondServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public SecondServlet() {
            super();
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("SecondServlet--->>> 进入doGet方法,交由doPost方法处理...");
            doPost(request, response);
        }
        
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("SecondServlet--->>> 执行POST请求...");
            response.setContentType("text/html;charset=utf-8");
            PrintWriter pw = response.getWriter();
            pw.println("<h1>这是SecondServlet中的响应数据</h1>");
            pw.flush();
            pw.close();
        }
    
    }
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>第一个jsp页面</title>
    </head>
    <body>
    
        <h1>这是第一个jsp页面</h1>
        <hr>
        <!-- ../表示根目录 -->
        <a href="../FirstServlet">这是第一个GET请求</a>
        <br/>
        <!-- request.getContextPath()方法获取的是应用名 -->
        <a href="<%=request.getContextPath() %>/FirstServlet">这是第二个GET请求</a>
    </body>
    </html>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>第二个jsp页面</title>
    </head>
    <body>
    
        <h1>这是第二个jsp页面</h1>
        <hr>
    
    </body>
    </html>

    整个项目的目录结构如下图

    第二步,分别使用相对路径和绝对路径测试转发和重定向

    相对路径和绝对路径都是针对部署在Tomcat上文件的位置,不是工程目录结构,first文件夹和second文件夹下存放的是jsp页面,web-inf文件夹下存放的是编译的servlet的class文件。测试完你会发现使用相对路径是最省事的,但是如果你对相对路径不熟悉,那还是写绝对路径吧,好把控一些。

    文章首发于我的个人公众号:悦乐书。喜欢分享一路上听过的歌,看过的电影,读过的书,敲过的代码,深夜的沉思。期待你的关注!

    公众号后台输入关键字“Java学习电子书”,即可获得12本Java学习相关的电子书资源,如果经济能力允许,还请支持图书作者的纸质正版书籍,创作不易。

  • 相关阅读:
    Python tkinter 实现简单登陆注册 基于B/S三层体系结构,实现用户身份验证
    Python3连接MySQL数据库实战
    Python3 报错'latin-1' codec can't encode character 解决方案
    python 操作excle 之第三方库 openpyxl学习
    对象的深拷贝和浅拷贝
    手机wap站全屏展示隐藏地址栏和状态栏代码
    JS调用App方法及App调用JS方法
    Vue里给v-html元素添加样式
    为什么JavaScript中移动端使用ontouchend无法获取touches数组
    什么是并发和并行
  • 原文地址:https://www.cnblogs.com/xiaochuan94/p/9165557.html
Copyright © 2020-2023  润新知