SpringMVC学习记录03——Controller与页面数据传递

###0.前言
《Java EE互联网轻量级框架整合开发——SSM框架(Spring MVC+Spring+MyBatis)和Redis实现》

本文主要记录Controller与页面数据传递

  1. Controller接收参数:
    1. 普通参数接收
    2. 对象类型参数接收
    3. 接收参数别名(@RequestParam)
    4. URL参数(@PathVariable)
    5. 请求实体提交(@RequestBody):数组类型、集合类型、JSON等
  2. Controller传递参数:
    1. 基础参数传递
    2. 对象类型参数传递
  3. 缓存数据到HTTP
    1. @RequestAttribute:获取HTTP的请求(request)对象属性值,用来传递给控制器的参数。
    2. @SessionAttribute/@SessionAttributes:在HTTP的会话(Session)对象属性中,用来传递给控制器的参数
    3. @CookieValue:获取cookie参数
    4. @RequestHeader:获取请求头参数
  4. 重定向(redirect)

###1. Controller接收参数

####1.1 普通参数接收
一般情况下保持HTTP的请求参数的名称控制器方法的参数名称一致,就可以获取到HTTP的请求参数。

eg:

请求为: http://..../getRole?id=1&roleName=test

Controller中方法:(普通参数接收)

public ModelAndView getRole(String id,String roleName){
    //...
}


####1.2 对象类型参数接收
存在一些情况导致接收参数过多,可以考虑通过POJO来管理参数

eg:

请求为:http://..../getRole?id=1&roleName=test

POJO类定义:

public class RoleParams{
    private String id;
    private String roleName;
    //...getter/setter
}

Controller中方法: (对象类型参数接收)

public ModelAndView getRole(RoleParams roleParams){
    //...
}

只要请求参数名与controller中的接收参数的名称一致,那么就能接收。


####1.3 参数别名接收
在多人开发的过程中,前端请求可能由第三方完成,导致命名规范不一样。

那么在不修改程序命名的情况下接收参数就需要用到@RequestParam

eg:

请求为:http://..../getRole?id=1&role_name=test

Controller中方法:(参数别名接收)

public ModelAndView getRole(String id,@RequestParam("role_name")String roleName){
    //...
}

需要注意的是:使用@RequestParam注解后,参数默认情况下不为空,为空会抛出异常。

允许为空的设置:设置required = false

@RequestParam(value = "role_name",required = false)String roleName


####1.4 URL中的参数接收
如果使用RESTful风格的请求,那么参数的传递可能直接在URL中。

eg:

请求为:http://..../getRole/1

Controller中方法:(URL中的参数接收)

@RequestMapping("/getRole/{id}")
public ModelAndView getRole(@PathVariable("id")String id){ //@PathVariable允许参数为空
    //...
}


####1.5 请求实体提交
在HTTP的Post请求中,存在一类需求是将数据序列化后直接提交到报文中的。

默认的POST提交的内容实体的格式为:key1=value1&key2=value2

需求需要提交JSON数据到报文中:contentType:"application/json"
内容为:{"key1":"value1","key2":"value2"}

POJO类定义:

public class JsonParams{
    private String key1;
    private String key2;
    //...getter/setter
}

Controller中方法:(请求实体提交的参数接口)

public ModelAndView getData(@RequestBody JsonParams jsonParams){ 
    //...
}

集合类JSON:[{"key1":"value1","key2":"value2"},{"key1":"value1","key2":"value2"}]

Controller中方法:(请求实体提交的参数接口(集合))

public ModelAndView getData(@RequestBody List<JsonParams> jsonParamsList){
    //...
}

通常情况,复杂的数据结构都通过序列化为JSON格式后提交,controller中通过@RequestBody接收

###2. Controller传递参数
Controller可以通过Model、ModelMap和ModelAndView向页面传递参数,一般只需要在控制器的方法中添加它们的其中一个,Spring MVC运行的时候,会自动初始化它们

  • Model:

    public ModelAndView getRoleByModel(@RequestParam("id") Long id, Model model) {
        Role role = roleService.getRole(id);
        ModelAndView mv = new ModelAndView();
        mv.setViewName("roleDetails");
        model.addAttribute("name","test");//传递字符串对象
        model.addAttribute("role", role); //传递Role对象到页面
        return mv;
    }    
    
  • ModelMap:

    public ModelAndView getRoleByModelMap(@RequestParam("id") Long id, ModelMap modelMap) {
            Role role = roleService.getRole(id);
            ModelAndView mv = new ModelAndView();
            mv.setViewName("roleDetails");
            modelMap.addAttribute("name","test");//传递字符串对象
            modelMap.addAttribute("role", role);//传递Role对象到页面
            return mv;
        }
    
  • ModelAndView:

    public ModelAndView getRoleByMv(@RequestParam("id") Long id, ModelAndView mv) {
        Role role = roleService.getRole(id);
        mv.setViewName("roleDetails");
        mv.addObject("name","test");//传递字符串对象
        mv.addObject("role", role); //传递Role对象到页面
        return mv;
    }
    

页面的接收:

页面通过${参数名}获取Controller传递到页面的值:

  • addAttribute("name","test") 对应:${name}
  • addAttribute("role", role) 对应:${role.id}${role.roleName}

需要注意:重定向不能通过这种方式传递POJO对象(使用RedirectAttributes.addFlashAttribute)

###3. 缓存数据到HTTP

####3.1 RequestAttribute
从Request对象中取出请求属性,有效期为:单次请求中。

JSP页面代码:

<%
    //设置请求属性
    request.setAttribute("id",1L);
    //转发给控制器
    request.getRequestDispatcher("./attribute/requestAttribute.do").forward(request, response);
%>

Controller中接收代码:

@RequestMapping("/requestAttribute")
public ModelAndView reqAttr(@RequestAttribute("id") Long id) {
    //...
}

注:@RequestAttribute默认为非空。 可以为空需要设置:required = false(类似@RequestParam)

####3.2 @SessionAttribute和@SessionAttributes
从HTTP的会话中取出属性,有效期是:本次会话期间

@SessionAttributes只能设置在类名上,不能设置在方法和参数上。

eg:

//可以配置数据模型的名称和类型,两者取或关系
@SessionAttributes(names ={"id"}, types = { Role.class })
public class AttributeController {

    @RequestMapping("/sessionAttributes")
    public ModelAndView sessionAttrs(Long id) {
        ModelAndView mv = new ModelAndView();
        Role role = roleService.getRole(id);
        //根据类型,session将会保存角色信息
        mv.addObject("role", role); 
        //根据名称,session将会保存id
        mv.addObject("id", id);
        //视图名称,定义跳转到一个JSP文件上
        mv.setViewName("sessionAttribute");
        return mv;
    }
}

如上述代码:
AttributeController配置了两个session属性。分别是:

  • 根据名称的:id
  • 根据类型的:Role.class

JSP页面接收session代码:

 <%
  Role role = (Role) session.getAttribute("role");//获取Role类型参数
  out.println("id = " + role.getId());

  Long id = (Long) session.getAttribute("id");//获取名称为id的参数
  out.println("id = " + id + "<p/>");

  session.setAttribute("id",2L);//设置值到属性id中
    //执行跳转
  response.sendRedirect("./attribute/sessionAttribute.do");
%>

Controller类中接收session属性的方法

@RequestMapping("/sessionAttribute")
public ModelAndView sessionAttr(@SessionAttribute("id") Long id) {
    //...
}

####3.3 @RequestHeader 和 @CookieValue
用户可以禁用Cookie,所以使用时候需要注意

@RequestMapping("/getHeaderAndCookie")
public String testHeaderAndCookie(
    @RequestHeader(value="User-Agent", required = false, defaultValue = "attribute")
         String userAgent,
    @CookieValue(value = "JSESSIONID", required = true, defaultValue = "MyJsessionId") 
         String jsessionId) {
    System.out.println("User-Agent:" + userAgent);
    System.out.println("JSESSIONID:" + jsessionId);
    return "index";
}

###4.重定向
在Spring MVC中当返回的字符串带有redirect的时候,它会认为这是一个重定向。

eg:

@RequestMapping("/test")
public String testRedirect(Model model){
    model.addAttribute("name","test");//传递参数到index页面
    return "redirect:./index";
}

或者:

@RequestMapping("/test")
public ModelAndView testRedirect(RedirectAttributes ra)
    ModelAndView mv = new ModelAndView();
    mv.addObject("name","test");//传递参数到index页面
    ra.addFlashAttribute("obj",obj); //传递POJO对象参数到index页面
    mv.setViewName("redirect:./index");
    return mv;
}

addFlashAttribute(…)的功能主要是将POJO对象保存到session中,再执行重定向,在取出POJO数据后,清除session中保存的数据,最后显示页面。

###5.总结

  1. Spring MVC 中,页面与Controller之间的参数传递相对比较简单。
    • Controller接收简单参数只需要在方法中定义参数的名称请求参数的名称一致就可以获取值。
    • Controller中的数据传递到页面也只需要在方法中使用Model、ModelMap或者ModelAndView就可以了。
    • 复杂的数据类型可以通过@RequestBody进行接收,传递可以通过序列化为JSON字符串


  2. 把数据直接保存到HTTP的request对象、session对象、Cookie和请求头(Header)中,需要注意的是request和session需要遵循它们的有效期。 而Cookie需要考虑到用户是否禁止了Cookie功能。
  3. 重定向传递数据时,需要POJO类型的传递需要使用RedirectAttributes进行。

END

–Nowy

–2018.12.21

分享到