Spring MVC 学习总结

未分类 发表评论

每个请求处理方法可以有多个不同的参数,以及一个多种类型的返回结果。

一、Action参数类型

如果在请求处理方法中需要访问HttpSession对象,则可以添加HttpSession作为参数,Spring会将对象正确的传递给方法,如:publish String action(HttpSession session);若需要访问客户端语言环境和HttpServletRequest对象,则可以在方法签名上包含这样的参数,如:public String action(HttpServletRequest request,Locale locale)。可以在请求中出现的参数类型有:

org.springframework.web.context.request.WebRequest
org.springframework.web.context.request.NativeWebRequest
java.util.Locale 当前请求的语言环境
java.util.TimeZone 时区
java.io.InputStream或java.io.Reader
java.io.OutputStream或java.io.Writer
org.springframework.http.HttpMethod
java.security.Principal
HttpEntity <?>参数用于访问Servlet的HTTP请求的标题和内容
java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap 视图隐含模型
org.springframework.web.servlet.mvc.support.RedirectAttributes 重定向
命令或表单对象

基本数据类型,如int,String,double…

复杂数据类型,如自定义的POJO对象
HandlerAdapter
org.springframework.validation.Errors / org.springframework.validation.BindingResult 验证结果
org.springframework.web.bind.support.SessionStatus 会话状态
org.springframework.web.util.UriComponentsBuilder
@PathVariable 注解参数访问URI模板变量。
@MatrixVariable 注释参数用于访问位于URI路径段键值对对,矩阵变量。
@RequestParam 注解参数访问特定的Servlet请求参数,请求参数绑定。
@RequestHeader 注解参数访问特定的se​​rvlet请求HTTP标头,映射请求头。
@RequestBody 注解参数访问HTTP请求主体,注解映射请求体
@RequestPart 注解参数访问“的multipart / form-data的”请求部分的内容。处理客户端上传文件,多部分文件上传的支持
@SessionAttribute 注解参数会话属性
@RequestAttribute 注解参数访问请求属性

1.1、自动参数映射

方法的参数可以是任意基本数据类型,如果方法参数名与http中请求的参数名称相同时会进行自动映射,视图foo目录下的index.jsp与示例代码如下:

    //自动参数映射
    @RequestMapping("/action0")
    public String action0(Model model,int id,String name){
        model.addAttribute("message", "name="+name+",id="+id);
        return "foo/index";
    }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Foo</title>
</head>
<body>
${message}
</body>
</html>

运行结果如下:

除了基本数据类型,也可以映射复杂的数据类型,如一个自定义的POJO对象,Spring MVC会通过反射把请中的参数设置到对象中,转换类型,示例代码如下:

package com.zhangguo.springmvc03.entities;

import java.io.Serializable;

/**
 * 产品
 */
public class Product implements Serializable {
    private static final long serialVersionUID = 1L;
    private int id;
    private String name;
    private double price;

    public Product() {
    }

    public Product(String name, double price) {
        super();
        this.name = name;
        this.price = price;
    }

    public Product(int id, String name, double price) {
        super();
        this.id = id;
        this.name = name;
        this.price = price;
    }
    
    @Override
    public String toString() {
        return "编号(id):"+this.getId()+",名称(name):"+this.getName()+",价格(price):"+this.getPrice();
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

View Code

    //自动参数映射 复杂数据类型
    @RequestMapping("/action01")
    public String action01(Model model,Product product){
        model.addAttribute("message", product);
        return "foo/index";
    }

 

1.2、使用@RequestParam请求参数绑定

虽然自动参数映射很方便,但有些细节是不能处理的,如参数是否为必须参数,参数的默认值就没有有办法做到了。如果使用@RequestParam可以实现请求参数绑定,Spring MVC会自动查找请求中的参数转类型并将与参数进行绑定,示例代码如下:

package com.zhangguo.springmvc03.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/foo")
public class FooController {
    @RequestMapping("/action1")
    public String action1(Model model,@RequestParam(required=false,defaultValue="99") int id){
        model.addAttribute("message", id);
        return "foo/index";
    }
}

@RequestParam共有4个注解属性,required属性表示是否为必须,默认值为true,如果请求中没有指定的参数会报异常;defaultValue用于设置参数的默认值,如果不指定值则使用默认值,只能是String类型的。

运行结果:

1.3、重定向与Flash属性

在一个请求处理方法Action中如果返回结果为“index”字符则表示转发到视图index,有时候我们需要重定向,则可以在返回的结果前加上一个前缀“redirect:”,可以重定向到一个指定的页面也可以是另一个action,示例代码如下:

    //重定向
    @RequestMapping("/action2")
    public String action2(Model model){
        return "foo/index";
    }
    
    @RequestMapping("/action3")
    public String action3(Model model){
        model.addAttribute("message", "action3Message");
        return "redirect:action2";
    }

当请求http://localhost:8087/SpringMVC02/foo/action3时运行结果如下:

在action3中返回的结果为redirect:action2,则表示重定向到action2这个请求处理方法,所有重定向都是以当前路径为起点的,请注意路径。在action3向model中添加了名称message的数据,因为重定向到action2中会发起2次请求,为了保持action3中的数据Spring MVC自动将数据重写到了url中。为了实现重定向时传递复杂数据,可以使用Flash属性,示例代码如下:

    //接收重定向参数
    @RequestMapping("/action2")
    public String action2(Model model,Product product){
        model.addAttribute("message", product);
        System.out.println(model.containsAttribute("product"));  //true
        return "foo/index";
    }
    
    //重定向属性
    @RequestMapping("/action3")
    public String action3(Model model,RedirectAttributes redirectAttributes){
        Product product=new Product(2, "iPhone7 Plus", 6989.5);
        redirectAttributes.addFlashAttribute("product", product);
        return "redirect:action2";
    }

当访问action3时,首先创建了一个product产口对象,将该对象添加到了Flash属性中,在重定向后取出,个人猜测应该暂时将对象存入了Session中。当请求foo/action3时运行结果如下:

url地址已经发生了变化,product对象其实也已经被存入了model中,在action的视图中可以直接拿到。

 1.4、@ModelAttribute模型特性

@ModelAttribute可以应用在方法参数上或方法上,他的作用主要是当注解在方法中时会将注解的参数对象添加到Model中;当注解在请求处理方法Action上时会将该方法变成一个非请求处理的方法,但其它Action被调用时会首先调用该方法。

1.4.1、注解在参数上

当注解在参数上时会将被注解的参数添加到Model中,并默认完成自动数据绑定,示例代码如下:

    @RequestMapping("/action6")
    public String action6(Model model,@ModelAttribute(name="product",binding=true) Product entity){
        model.addAttribute("message", model.containsAttribute("product")+"<br/>"+entity);
        return "foo/index";
    }

运行结果:

其实不使用@ModelAttribute我也样可以完成参数与对象间的自支映射,但使用注解可以设置更多详细内容,如名称,是否绑定等。

1.4.2、注解在方法上

用于标注一个非请求处理方法,通俗说就是一个非Action,普通方法。如果一个控制器类有多个请求处理方法,以及一个有@ModelAttribute注解的方法,则在调用其它Action时会先调用非请求处理的Action,示例代码如下:

    @RequestMapping("/action7")
    public String action7(Model model){
        Map<String,Object> map=model.asMap();
        for (String key : map.keySet()) {
            System.out.println(key+":"+map.get(key));
        }
        return "foo/index";
    }
    
    @ModelAttribute
    public String noaction(){
        System.out.println("noaction 方法被调用!");
        String message="来自noaction方法的信息";
        return message;
    }

当访问http://localhost:8087/SpringMVC03/foo/action7时,控制台显示结果如下:

非请求处理方法可以返回void,也可以返回一个任意对象,该对象会被自动添加到每一个要被访问的Action的Model中,key从示例中可以看出为类型名称。

二、Action返回值类型

ModelAndView
Model
Map 包含模型的属性
View
String 视图名称
void
HttpServletResponse
HttpEntity<?>或ResponseEntity<?>
HttpHeaders
Callable<?>
DeferredResult<?>
ListenableFuture<?>
ResponseBodyEmitter
SseEmitter
StreamingResponseBody
其它任意类型,Spring将其视作输出给View的对象模型

2.1、视图中url问题

新增一个action5,代码如下:

    @RequestMapping("/action5")
    public String action5(Model model){
        return "foo/action5";
    }

在foo目录下添加视图action5.jsp,内容如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>action5的视图</title>
</head>
<body>
    <img alt="风景" src="../../images/3.jpg">
</body>
</html>

目标结构如下:

访问结果:

这里图片访问不到的原因是因为:action5.jsp视图此时并非以它所在的目录为实际路径,他是以当前action所在的控制器为起始目录的,当前控制器的url为:http://localhost:8087/SpringMVC02/foo/,而图片的src为:../../images/3.jpg,向上2级后变成:http://localhost:8087/images/3.jpg,但我们的项目实际路径中并没有存放3.jpg这张图片,解决的办法是在视图中使用“绝对”路径;另外一个问题是我们将静态资源存放到WEB-INF下不太合理,因为该目录禁止客户端访问,修改后的视图如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>action5的视图</title>
</head>
<body>
    <img alt="风景" src="<c:url value="/images/3.jpg"></c:url>">
</body>
</html>

目录结构变化后如下所示:

 

运行结果:

小结:主要是借助了标签<c:url value=”/images/3.jpg”></c:url>,将路径转换成“绝对路径”;建议在引用外部资源如js、css、图片信息时都使用该标签解析路径。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

昵称 *