SpringMVC中的重定向数据传递

        SpringMVC就不用多介绍了,这篇文章总结一下URL重定向的数据保存问题,至于什么是URL重定向?在之前的博客中我有介绍过。

        今天再写项目的时候发现:使用SpringMVC的Controller是可以对同一个URL返回不同的界面的。但是发现了一个问题,如果是一个登录的界面,用户名和密码正确之后返回给用户的是登后的主界面,但是!URL的地址没有变!

        那意思就是说我的URL地址是在登录页面但是视图是登陆完成后的主界面了这好像是有点不太对的吧......

        其实正确的情况应该是:登录的界面的URL叫做/test/login,展现出了一个登录界面。主界面的URL叫做/test/Main,展现出的是主界面的视图。

        现在就用用户登录这个例子练习一下重定向中的数据传输模式。

怎么去重定向?

        但是问题来了:怎么样才可以把地址栏上的URL换掉呢?在这里可以使用重定向的方法来改变URL,首先,我总结了一张图,先放在这,然后再一步一步的细说。

现在对照着图来一步一步细说

一、客户端想要登录,访问到了登录的URL,这里就叫做/test/login吧。因为这是个SpringMVC项目,所以,前端控制器收到请求的URL之后,在已经注册的Controller中找到了登陆界面的Controller,叫做Index-Controller。

二、Index-Controller处理登录请求,它在数据库里核对了一下,发现用户名和密码是对的,所以它得把用户看到的界面和URL换成主界面的,所以它创建了ModelAndView对象(SpringMVC的底层对象),往对象里塞了点属性,并使用

//重定向的时候,不能写jsp文件的名字,必须写映射的URL地址
modelAndView.setViewName("redirect:/test/Main");

想把页面重定向到主界面去,让用户看到这些属性。

三、但是!重定向之后客户端用新请求去访问主界面,这样的话刚刚塞到ModelAndView那些属性不就凉了么。

        在这里,我们可以使用上图的:RedirectAttribute类来保存之前获得的属性,这样就可以避免重定向之后数据丢失的问题。

        就是说:原来我们是向ModelAndView中放属性的,但是现在我们只要往这个类里放就OK了,就可以让用户在主界面看到之前想保存的那一堆属性了。

四、现在看一下Index-Controller的代码吧(主要看后面)

package root.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import root.back.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;


//处理登录请求的后端控制器

//注意:@RequestParam注解中的required注解对表单提交中的属性是没有用的,就算不填它也会默认为空字符串,它只对GET请求中
//在url后加的key-value的属性有限制作用
@Controller
@RequestMapping(value = {"/test"})
public class LoginController {

    private static final String CURRENT_USER = "Now_user";

    //业务层接口
    @Autowired
    private UserService userService;


    //如果是GET方法请求的话,就直接给用户返回登录的页面,此页面表单请求的方法为POST
    @RequestMapping(value = {"/login"},method = {RequestMethod.GET})
    public ModelAndView LoginGet(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("index");
        return modelAndView;
    }

    //该方法主要是用来处理表单提交上来的请求的,@RequestParam中的value属性就是表单中的属性名
    //可以通过这种方法重新定义参数的名字
    @RequestMapping(value = {"login"},method = {RequestMethod.POST})
                                //让请求的url后面必须跟上一个叫做userName的属性,是用户的用户名
    public ModelAndView LoginPost(@RequestParam(value = "userName") String userName,
                                  //请求的url后必须跟上password属性,为用户当前的密码
                                  @RequestParam(value = "password") String password,
                                  //Spring MVC框架集成了Servlet请求响应等一系列参数,可以在有需要的时候使用
                                  HttpServletRequest request, HttpServletResponse response,
                                  HttpSession session, RedirectAttributes redirectAttributes) {

        //这里是和后端交互的代码,如果是用户登录的话就在数据库中查找对应的用户信息
        if(userName.isEmpty() || password.isEmpty()){
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("error","用户名或密码为空");
            modelAndView.setViewName("index");
            return modelAndView;
        }

        //用户名和密码不为空,进入登录的业务层
        //如果登录业务失败,说明用户已经注册过了
        if(!userService.login(userName, password)){
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("error","用户名或密码错误");
            modelAndView.setViewName("index");
            return modelAndView;
        }

        //到了这里就说明用户登录成功了
//        System.out.println("用户名是:" + userName + "密码是:" + password);
        //使用session进行会话跟踪
        session.setAttribute(CURRENT_USER, userName);

        //创建模型与视图类,返回给前端控制器
        ModelAndView modelAndView = new ModelAndView();

        //重定向的时候,因为是客户端重新的请求,所以参数是不会被传到重定向页面的

        //所以使用此方法,可以把属性放到一个叫做FlashMap的Map中
        redirectAttributes.addFlashAttribute("userName",userName);
        redirectAttributes.addFlashAttribute("password",password);

        //使用重定向的时候不能写jsp的名字,要写url映射的路径
        modelAndView.setViewName("redirect:/test/Main");
        return modelAndView;
    }
}

RedirectAttribute类是有两种方法来存属性的,我这里只用了一种,现在看一下上图中红色框中的内容。

总结一下:

        1、addAttribute()方法直接把你的参数加到url的后面进行重定向,使用这个方法之后,虽然你成功的跳到了主界面,但是!页面的URL变成了:/test/Main?userName=10000&password=22222,一般的网站登录好像是没人这么干的吧,所以这就不做讲解了。而且要是想获取数据的话,可以直接用@RequestParam或者@ModelAttribute来获取。

        2、但是如果使用addFlashAttribute()方法就没有那么多事了,这个方法的使用和上面的那个是一样的,唯一的区别就是传输数据的方法不一样。这个方法会把你加入的数据放在一个叫做FlashMap的Map中。在进行重定向的时候,这个Map中的数据会跟着新生成的Request一起到去请求重定向到的页面(也就是程序的的主界面),当重定向之后,这个Map里的数据会被清空,意思就是现在只有新页面的Request才有这些数据了。

        当然,如果现在刷新一下页面,你会发现展示的数据(一开始你存储在FlashMap中的数据)没了。这其实也很好理解吧,刚刚说了,FlashMap在把数据给重定向生成的Request后,就把自己的数据删了。现在你刷新了一下页面相当于客户端又对这个URL产生了新请求,这个新请求是不可能有上一个请求中的信息的,所以避免了表单的重复提交。

        FlashMap:由一个叫做FlashMapManager的管理器管理,一般默认使用的是SessionFlashMapManager,不过如果你想在你的Session中找到你的数据的话那是找不到的。

五、怎么才能拿到通过addFlashAttribute()存储在FlashMap中的属性呢?

        刚刚是登录界面的Controller怎样才能把数据在重定向的过程中不丢失的问题,但是,数据是没有丢,但是还是得取的吧,只会存不会取那还是有点凉的。。这里取数据的操作是在主界面的Controller(就叫main-Controller吧)完成的。先看代码。

package root.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;

@Controller
@RequestMapping(value = {"/test"})
public class MainController {

    @RequestMapping(value = {"/Main"},method = {RequestMethod.GET})
    public ModelAndView GetMain(
                          HttpServletRequest request, HttpSession session){

        ModelAndView modelAndView = new ModelAndView();

        //对FlashMap中的参数进行提取,有两种方法
        //第一种,使用RequestContextUtils(请求工具包),因为在重定向后FlashMap会把表单中的属性
        //放在重定向新的请求中,所以可以获得请求中的FlashMap
        Map<String,?> map = RequestContextUtils.getInputFlashMap(request);
        //把FlashMap直接放入模型,传给前端控制器
        modelAndView.addAllObjects(map);
        //视图名传入
        modelAndView.setViewName("main");

        return modelAndView;

    }


    //第二种:使用@ModelAttribute注解
    //因为FlashMap是处理这个url的初始化数据模型,所以可以通过这个注解拿到FlashMap的属性
    @RequestMapping(value = {"/Main"},method = {RequestMethod.POST})
    public String PostMain(@ModelAttribute(value = "userName") String userName,
                           @ModelAttribute(value = "password") String password){
        return "main";
    }
}

登录的Controller返回的视图名是:redirect:/test/Main,前端控制器找到了这个Controller,所以这个Controller负责渲染并返回视图。

渲染的话就是往视图里放数据,所以这里就要把FlashMap中的数据取出来了,先放张图。

虽然说,管理FlashMap的管理器默认是SessionFlashMapManager,保存在Session中。但是,通过Session是无法获得数据的。

方法一:使用RequestContextUtils.getInputFlashMap()来直接获取FlashMap(重点)

        我们在Index-Controller中,把数据使用RedirectAttribute.addFlashAttribute()保存在FlashMap中,在重定向的时候,FlashMap中的数据被添加到了Request中,所以使用这个方法可以从Request中获取到FlashMap。

        FlashMap本质上还是一个Map,所以这个方法的返回值是Map<String,?>,我们只要用一个Map来接收就可以了,然后我们就可以提取我们之前存储下的那些属性了。(就是可以直接在视图上使用 ${属性名} 来获取)。

方法二、通过(@ModelAttribute(value="属性名")String xxx)通过属性名称获取属性值(推荐)

        刚刚已经说过了,一开始储存的数据在重定向的时候都放在Request里了,这些数据被作为初始化的模型(通俗的来讲就是这些数据被这个控制器的所有方法共享,即为共享数据),所以通过@ModelAttribute可以在Main-Controller中的任意一个方法里通过属性名获取这些属性。比上面的那个要简单多了,所以推荐使用这个方法。

其实!想要获得FlashMap中的数据,就算你啥都不写!都可以在视图里通过${属性名}来获取!

 

六、页面展示

首先是登录/主界面的jsp。

Index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>主界面</title>
</head>
<body>



<script>
    function Logout() {
        <%
        session.invalidate();
        %>


    }
</script>

<p>登录成功</p>
你的用户名为:<p>${userName}</p>
你的密码为:<p>${password}</p>
<a href="login" onclick="Logout">退出</a>


</body>
</html>

main.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>主界面</title>
</head>
<body>



<script>
    function Logout() {
        <%
        session.invalidate();
        %>


    }
</script>

<p>登录成功</p>
你的用户名为:<p>${userName}</p>
你的密码为:<p>${password}</p>
<a href="login" onclick="Logout">退出</a>


</body>
</html>

1、首先是登陆界面(注意看URL)

2、登录,界面的URL变了而且登陆的Controller存储的数据(用户名和密码)

先总结到这了

仅供个人学习使用!

        

猜你喜欢

转载自blog.csdn.net/qq_38449518/article/details/82560347
今日推荐