Spring MVC (二)——控制器定义与@RequestMapping详解

一、控制器定义

控制器提供访问应用程序的行为,通常通过服务接口定义或注解定义两种方法实现。 控制器解析用户的请求并将其转换为一个模型。在Spring MVC中一个控制器可以包含多个Action(动作、方法)。

使用注解@Controller定义控制器

org.springframework.stereotype.Controller注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解);Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。

创建一个名了Bar的类,定义为一个控制器,类的具体实现如下:

package com.zhangsan.springmvc01;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@org.springframework.stereotype.Controller
public class Controller {
    @RequestMapping("/bar")
    public String hi(Model model){
        model.addAttribute("msg","这是通过注解定义的一个控制器中的Action");
        return "hi";
    }
}

还要需要修改Spring mvc配置文件,启用自动组件扫描功能,在beans中增加如下配置:

<!-- 自动扫描包,实现支持注解的IOC -->
    <context:component-scan base-package="com.zhangsan.springmvc01" />

运行结果如下:

小结:从代码与运行结果可以看出BarController与FooController同时都指定了一个视图hi.jsp,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。

二、@RequestMapping详解

@RequestMapping注释用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。该注解共有8个属性,注解源码如下:

package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.Callable;

import org.springframework.core.annotation.AliasFor;

/**
 * 用于映射url到控制器类或一个特定的处理程序方法.
 */
//该注解只能用于方法或类型上
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {

    /**
     * 指定映射的名称
     */
    String name() default "";

    /**
     * 指定请求的路径映射,指定的地址可以是uri模板,别名为path
     */
    @AliasFor("path")
    String[] value() default {};

    /** 别名为value,使用path更加形象
     * 只有用在一个Servlet环境:路径映射URI(例如“/myPath.do”)。
     * Ant风格的路径模式,同时也支持(例如,“/myPath/*.do”)。在方法层面,在主要的映射在类型级别表示相对路径(例如,“edit.do”)
     * 的支持。路径映射的URI可能包含占位符(例如“/$ {}连接”)
     */
    @AliasFor("value")
    String[] path() default {};

    /**
     * 指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. 收窄请求范围 The
     * HTTP request methods to map to, narrowing the primary mapping: GET, POST,
     * HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
     */
    RequestMethod[] method() default {};

    /**
     * 映射请求的参数,收窄请求范围 The parameters of the mapped request, narrowing the
     * primary mapping.
     */
    String[]params() default {};

    /**
     * 映射请求头部,收窄请求范围 The headers of the mapped request, narrowing the primary
     * mapping. RequestMapping(value = "/something", headers =
     * "content-type=text/*")
     */
    String[] headers() default {};

    /**
     * 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html,收窄请求范围 The
     * consumable media types of the mapped request, narrowing the primary
     * mapping.
     */
    String[] consumes() default {};

    /**
     * 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回 The producible media types
     * of the mapped request, narrowing the primary mapping. produces =
     * "text/plain" produces = {"text/plain", "application/*"} produces =
     * "application/json; charset=UTF-8"
     */
    String[] produces() default {};
}

 从上面的源码可以发现除了name基本都是数组类型,在设置时我们可以指定单个值,如@RequestMapping(value="/foo");也可以同时指定多个值如:@RequestMapping(value={"/foo","/bar"})。

2.1、指定具体路径字符

2.1.1 只注解方法

@Controller
public class Controller {
    @RequestMapping("/h1")
    public String h1(){
        return "h1";
    }
}

 访问路径:http://localhost:8080/h1

2.1.2 同时注解类与方法

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping("/h1")
    public String h1(){
        return h1";
    }
}

访问路径:http://localhost:8080/foo/h1

 需要先指定类的路径再指定方法的路径

2.1.3 @RequestMapping 来处理多个 URI

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = {"/hi","/a/b/c"})
    public String h2(Model model){
        model.addAttribute("msg","@RequestMapping 来处理多个 URI!");
        return "hi";
    }
}

访问路径:1、http://localhost:8080/foo/hi

        2、http://localhost:8080/foo/a/b/c

2.1.4、路径变量占位,URI模板模式

在Spring MVC可以使用@PathVariable 注释方法参数的值绑定到一个URI模板变量。

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = {"/h3/{name}/{id}"})
    public String h3(Model model, @PathVariable String name,@PathVariable int id){
        model.addAttribute("msg","路径变量占位,URI模板模式!
名称:"+name+"
编号:"+id);
        return "hi";
    }
}

访问路径:http://localhost:8080/foo/h3/张三/20

2.1.5、正则表达式模式的URI模板

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h4/{id:\d{6}}-{name:[a-z]{3}}")
    public String h4(Model model, @PathVariable String name,@PathVariable int id){
        model.addAttribute("msg","正则表达式模式的URI模板!
名称:"+name+"
编号:"+id);
        return "hi";
    }
}

访问路径:http://localhost:8080/foo/h4/123456-abc

正则要求id必须为6位的数字,而name必须为3位小写字母,访问结果如下:

2.1.6、Ant风格路径模式
@RequestMapping注解也支持ant风格的路径模式,如/foo/h5/*.do,示例代码如下:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h5/*.do")
    public String h5(Model model){
        model.addAttribute("msg","Ant风格路径模式");
        return "hi";
    }
}

访问路径:http://localhost:8080/foo/h5/任意符号.do

ANT通配符有三种:

 

2.2、method属性指定谓词类型

用于约束请求的谓词类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE,如下代码所示:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h6",method = {RequestMethod.POST,RequestMethod.DELETE})
    public String h6(Model model){
        model.addAttribute("msg","请求谓词只能是POST与DELETE");
        return "hi";
    }
}

 要访问h6请求谓词类型必须是POST或者为DELETE,当我们从浏览器的URL栏中直接请求时为一个GET请求,则结果是405,如下所示:

 如果将POST修改为GET则正常了,如下所示:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h6",method = {RequestMethod.GET})
    public String h6(Model model){
        model.addAttribute("msg","请求谓词只能是GET");
        return "hi";
    }
}

 

Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。

所有的请求默认都会是 HTTP GET 类型的。

为了能降一个请求映射到一个特定的 HTTP 方法,你需要在 @RequestMapping 中使用 method 来声明 HTTP 请求所使用的方法类型,如下所示:

@RestController  
@RequestMapping("/home")  
public class IndexController {  
    @RequestMapping(method = RequestMethod.GET)  
    String get() {  
        return "Hello from get";  
    }  
    @RequestMapping(method = RequestMethod.DELETE)  
    String delete() {  
        return "Hello from delete";  
    }  
    @RequestMapping(method = RequestMethod.POST)  
    String post() {  
        return "Hello from post";  
    }  
    @RequestMapping(method = RequestMethod.PUT)  
    String put() {  
        return "Hello from put";  
    }  
    @RequestMapping(method = RequestMethod.PATCH)  
    String patch() {  
        return "Hello from patch";  
    }  
}

在上述这段代码中, @RequestMapping 注解中的 method 元素声明了 HTTP 请求的 HTTP 方法的类型。 
所有的处理处理方法会处理从这同一个 URL( /home)进来的请求, 但要看指定的 HTTP 方法是什么来决定用哪个方法来处理。 
例如,一个 POST 类型的请求 /home 会交给 post() 方法来处理,而一个 DELETE 类型的请求 /home 则会由 delete() 方法来处理。 
你会看到 Spring MVC 将使用这样相同的逻辑来映射其它的方法。

2.3、consumes属性指定请求的Content-Type

@RequestMapping 注解的 produces 和 consumes 这两个元素来缩小请求映射类型的范围,达到处理生产和消费对象的目的。 

 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html,收窄请求范围,如果用户发送的请求内容类型不匹配则方法不会响应请求,具体使用如下代码所示:

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h7",consumes = "text/html")
    public String h7(Model model){
        model.addAttribute("msg", "请求的提交内容类型(Content-Type)是text/html");
        return "hi";
    }
}

在h7的注解中约束发送到服务器的Content-Type必须是text/html类型,如果类型不一致则会报错(415),测试结果如下:

请求的提交内容类型(Content-Type)是text/html 

注意:可以使用!号,如consumes="!text/html"

2.4、produces属性指定响应的Content-Type,约束Accept类型

指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回,方法才处理客户端的请求否则会报406错误,常用设置如下:

produces = "text/plain"  //客户端只接收纯文本

produces = {"text/plain", "application/*"}   //客户端接收纯文本与application/*类型的内容

produces = "application/json; charset=UTF-8"  //客户端接收json且编码为utf-8/;

@Controller
@RequestMapping("/foo")
public class Controller {
    @RequestMapping(value = "/h8",produces = "application/json;charset=UTF-8")
    public String h8(Model model){
        model.addAttribute("msg", "客户端可以接收的类型是application/json; charset=UTF-8");
        return "hi";
    }
}

 运行结果:

 注意:可以使用!号,如produces="!text/html"

原文地址:https://www.cnblogs.com/huoqin/p/9846181.html