Java网络开发(servlet思考)——什么时候用转发,什么时候用重定向 & 请求request,响应response

引出

web的 请求request (post和get请求)和 响应response,转发对应request,重定向对应response,在用servlet的时候,究竟要用转发还是重定向?

在这里插入图片描述


转发和重定向

1.请求转发—request

有人来咨询,转给对接咨询的人,请求——>前台(servlet)——>咨询(servlet)

特点:一次性,共享数据

请求转发是指一个请求到服务器后,第一个Servlet接收到这个请求,可以把这个请求再发送给下一个处理的Servlet或者资源,整个过程中,都只有一个请求,比如我们去饭店点餐,下单后,服务员收到请求,发送给厨师,厨师做好后,给端菜的服务员,最终到我们收里,这整个过程,处理的其实是一个请求。Servlet也类似。

代码如下:注意不要忘记后面的.forward(req,resp)

req.getRequestDispatcher("/b").forward(req,resp);

注意转发(forward)的特点:

  • 转发地址栏路径不变

  • 转发只能访问当前服务器下的资源

  • 转发是一次请求,可以使用request对象来共享数据

  • 转发由request控制

2.响应重定向----response

特点:值不共享,浏览器的地址变化

重定向的意思是:第一次请求到达服务器后,服务器处理完成,可以在响应信息中告诉浏览器去下一个地址,浏览器会自动请求下一个路径。这个过程中浏览器发送了两次请求。从这里可以看出重定向是由响应response发起的。

代码如下:其中/day01上下文,可以通过代码获得

resp.sendRedirect("/day01/demo2");

最终的代码如下:不要忘了加req.getContextPath()

resp.sendRedirect(req.getContextPath()+"/news/list.jsp");

重定向的特点:redirect

  1. 地址栏发生变化,因为浏览器要访问重定向的地址

  2. 重定向可以访问其他站点(服务器)的资源

  3. 重定向是两次请求。不能使用request对象来共享数据

  4. 重定向由response控制

在这里插入图片描述

转发?重定向?

以一个新闻阅读的登陆的业务为例:

异步请求axios为例—响应必须是response

在这里插入图片描述

1.新建一个专门用来处理响应的实体类ResData

package com.tianju.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 响应的实体类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResData {
    // 返回码,200正常,10001参数错误。。。
    private Integer code;
    // 正常标识,success,ok
    private String msg;
    // 具体的信息,可以是对象
    private Object data;
}

2.在axios中,所有响应必须是 resp.getWriter().write() 的方式,核心代码如下

resp.getWriter().write(JSON.toJSONString(new ResData(1001, "输入为空", null)));

同步请求情况下—根据需求选response/request

TODO:什么时候跳转到jsp,什么时候重定向,什么时候转发

思考:和需求相关,如果这里直接到一个不需要servlet处理的页面,则用重定向即可

 如果需要处理一下,再到页面,则用转发给另一个servlet继续进行业务处理
 跳转到新闻信息页面---开始为了测试跳转是否实现,用了重定向;
 最终,业务是登陆成功后,查询数据库,进行显示,则转发给ListServlet进行处理,

1.登陆后重定向

在一开始写代码的时候,在login.jsp中进行输入用户名和密码,进行登陆,然后在LoginServlet.java中对前端传进来的用户名和密码进行验证,即处理登陆业务;如果验证成功,则跳转到新闻展示页面。由于一开始代码并不完善,因此:

在这里先让登陆成功后,直接跳转到 list.jsp 前端页面,在页面上只有一个<h1标签。此时,我的目的是,用跳转成功来验证登陆的业务代码是否正确,因此,用了重定向;

resp.sendRedirect(req.getContextPath()+"/news/list.jsp");

login.jsp中的代码:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登陆</title>
</head>
<body>
<h1>杂七杂八新闻管理系统登陆页面</h1>
<form action="/day06/user/login" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录">
    <input type="reset" value="重置">
</form>

</body>
</html>

在这里插入图片描述

LoginServlet.java代码:

/**
 * 处理登陆的servlet
 */
@WebServlet("/user/login")
public class LoginServlet extends HttpServlet {
    private IUserService userService = new UserServiceImpl();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(username+password);

        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)){
            // TODO:给前端
            System.out.println("输入空");
            return;
        }

        User userDb = userService.queryByUsername(username);

        if (userDb==null || !password.equals(userDb.getPassword())){
            System.out.println("用户名|密码错误");
            return;
        }

        // 登陆成功的信息保存到session中
        HttpSession session = req.getSession();
        session.setAttribute("user", userDb);

        // TODO:什么时候跳转到jsp,什么时候重定向,什么时候转发
        // 思考:和需求相关,如果这里直接到一个不需要servlet处理的页面,则用重定向即可
        //      如果需要处理一下,再到页面,则用转发给另一个servlet继续进行业务处理
        // 跳转到新闻信息页面---开始为了测试跳转是否实现,用了重定向
        resp.sendRedirect(req.getContextPath()+"/news/list.jsp");
    }
}

此时展示新闻的 list.jsp页面代码如下:就是简单在前端显示一个标签

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>新闻浏览页面</title>
</head>
<body>
<h1>新闻浏览页面</h1>
</body>
</html>

在这里插入图片描述

2.登陆后转发

实际上,新闻的页面需要先查询一下数据库,获取数据库中的新闻后,再发送到 list.jsp 页面进行显示,此时,就用请求的转发,从LoginServlet.java的
@WebServlet(“/user/login”) 转发到 ListServlet.java 的@WebServlet(“/news/list”),在这个servlet里面进行新闻的查询,然后把查询到的新闻共享到 list.jsp 页面进行展示。

此时LoginServlet.java用请求转发:

req.getRequestDispatcher("/news/list").forward(req, resp);

进行数据库查询的ListServlet.java代码如下:


/**
 * 文章列表显示的servlet
 */

@WebServlet("/news/list")
public class ListServlet extends HttpServlet {
    private IArticleService articleService = new ArticleServiceImpl();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1.获取前端的输入:第几页,每页数据量,查询关键词是啥
        String pageNumStr = req.getParameter("pageNum"); // 第几页
        String pageSizeStr = req.getParameter("pageSize"); // 每页显示数据条数
        String keyword = req.getParameter("name");

        // 2.进行赋值,默认首页,默认每页3条
        Integer pageNum = StringUtils.isBlank(pageNumStr) ? 1:Integer.parseInt(pageNumStr);
        Integer pageSize = StringUtils.isBlank(pageSizeStr) ? 3:Integer.parseInt(pageSizeStr);

        // 3.计算数据总条数
        Integer total = articleService.countLikeLines(keyword);

        // 4.计算总页数
        Integer pages = total % pageSize==0 ? total/pageSize:total/pageSize+1;

        // 5.new pageInfo对象
        List<Article> list = articleService.queryByKeyWordDescLimit(keyword, pageNum, pageSize);
        PageInfo<Article> pageInfo = new PageInfo<>(pageNum,pageSize,total, pages, list);

        System.out.println(list);

        // 6.共享值
        req.setAttribute("pageInfo", pageInfo);
        req.setAttribute("name", keyword);
        System.out.println(pageInfo);

        // 6.转发给前端显示
        req.getRequestDispatcher("/news/list.jsp").forward(req, resp);

    }
}

转发到list.jsp进行前端展示,代码如下:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>新闻浏览页面</title>
</head>
<body>
<h1>新闻浏览页面</h1>

${pageInfo}<br>

<%--${param}<br>--%>
<%--${sessionScope}--%>
<%--    输入查询的条件--%>
<div style="align-content: center">
    <form action="/day06/news/list">
        <%--        隐藏框--%>
        <input type="hidden" name="pageSize" value="${pageInfo.pageSize}">
        <input type="hidden" name="pageNum" value="${pageInfo.pageNum}">
        查询:<input type="text" placeholder="输入要查询关键字" name="name" value="${param.name}">
        <input type="submit" value="搜索"><br>
    </form>
</div>

<div style="color: blueviolet" >
    <form action="/day06/news/list">
        <input type="hidden" name="name" value="${name}">
        <input type="hidden" name="pageNum" value="${pageInfo.pageNum}">
        每页显示条数:<input type="text" name="pageSize" value="${pageInfo.pageSize}">
        <input type="submit" value="提交"><br>
    </form>
</div>


<a href="/day06/news/addPage">发布文章</a><br>


<table width="100%" border="1px">
    <tr>
        <th>编号</th>
        <th>栏目</th>
        <th>标题</th>
        <th>内容</th>
        <th>操作</th>
    </tr>

    <c:forEach items="${pageInfo.list}" var="ar">
        <tr>
            <td>${ar.articleId}</td>
            <td>${ar.channelName}</td>
            <td>${ar.articleTitle}</td>
            <td>${ar.articleContent}</td>
            <td>
                <a href="/day06/news/delete?id=${ar.articleId}">删除</a>
                <a href="/day06/update/page?id=${ar.articleId}">修改</a>
            </td>

        </tr>

    </c:forEach>

</table><br><hr>

<c:if test="${pageInfo.pageNum!=1}">
    <a href="/day06/news/list?pageNum=1&pageSize=${pageInfo.pageSize}&name=${name}">首页</a>
    <a href="/day06/news/list?pageNum=${pageInfo.pageNum-1}&pageSize=${pageInfo.pageSize}&name=${name}">上一页</a>
</c:if>

<%--     如果当前页是尾页,需要控制下一页和尾页不显示 --%>
<c:if test="${pageInfo.pageNum!=pageInfo.pages}">
    <a href="/day06/news/list?pageNum=${pageInfo.pageNum+1}&pageSize=${pageInfo.pageSize}&name=${name}">下一页</a>
    <a href="/day06/news/list?pageNum=${pageInfo.pages}&pageSize=${pageInfo.pageSize}&name=${name}">尾页</a>
</c:if>

总计${pageInfo.pages}页/当前${pageInfo.pageNum}


<form action="/day06/news/list" method="get">
    <input type="hidden" name="name" value="${name}">
    <input type="hidden" name="pageSize" value="${pageInfo.pageSize}">
    跳转到:<input type="text" name="pageNum" value="${pageInfo.pageNum}">
    <input type="submit" value="提交">
</form>


</body>
</html>

在这里插入图片描述

3.总结

总结,个人认为有以下两点:
(1)如果处理的业务需要进行值的共享,那肯定是要用request的转发;
(2)如果并不涉及到值的共享,并且下一个业务和当前的业务相对独立,则可以用response的重定向;
(3)总归是看自己业务的需求,因为猫走不走直线完全取决于耗子;

案例:图书信息管理系统–同步请求

以一个图书信息的管理系统为例
在这里插入图片描述

1.用户相关操作—注册,登陆,修改密码 / 昵称,退出登陆

(1)注册成功后重定向到 login.jsp 页面;
(2)登陆成功后重定向到 index.jsp 页面;
(3)修改密码后重定向到 login.jsp 页面;
(4)修改昵称后重定向到 index.jsp 页面;
(5)退出登陆后重定向到 login.jsp 页面;

序号业务选择目标
1注册成功重定向login.jsp 页面
2登陆成功重定向index.jsp页面
3修改密码重定向login.jsp 页面
4修改昵称重定向index.jsp页面
5退出登陆重定向login.jsp 页面

2.图书相关操作—图书的 增删改查 和 统计

(0)查询图书list,
点击图书信息,由ListServlet.java进行数据库查询,查询到的图书信息,共享值并转发到 list.jsp 页面进行展示;

(1)增加一本图书
由AddPageServlet.java 处理, 获取 类型信息, 共享值并转发到 addPage.jsp 进行展示 ,用户填写后表单提交到 AddServlet.java 进行业务处理,新增成功后,重定向 到ListServlet.java进行数据库查询,查询到的图书信息,共享值并转发到 list.jsp 页面进行展示;

(2)修改一本图书
和上面流程类似,不同的是还要把原来的值 回传到updatePage.jsp 进行展示;

(3)删除一本书
点击删除按钮,删除成功后, 重定向 到ListServlet.java进行数据库查询,查询到的图书信息,共享值并转发到 list.jsp 页面进行展示;

(4)统计相关
由CountOpusServlet.java进行处理,得到统计信息,共享值到 count.jsp 页面,进行展示;


总结

0.异步请求axios为例—响应必须是response
1.转发用request,记得加上.forward(req, resp);
2.重定向用response,记得加上上下文,req.getContextPath();
3.转发和重定向的选择本质是和业务有关;
4.如果要共享值,就得使用request的转发;
5.用户相关的操作大部分用重定向;
6.图书相关的操作,需要共享值,用转发,不需要共享就可以用重定向;

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Arya's Blog

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

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

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

打赏作者

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

抵扣说明:

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

余额充值