【Spring-Controller 整理研究】@RequestMapping略解

本文以纯后端的角度,去研究Spring Controller在各种情况的行为,及各种属性的作用。

实验准备

利用https://start.spring.io/快速生成一个开箱即用的小巧spring boot项目,无需进行复杂配置,非常适合进行研究实验使用。

若以下例子未说明,结果为下述代码所示。

@Controller
@RequestMapping(value = "/terra")
public class TestController {
    // 放置实验的Controller  
}

端口号在application.properties设置为9000

server.port=9000
server.contextPath=/
server.tomcat.uri-encoding=UTF-8

 

@RequestMapping

@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。(抄)

一. value

value不设置和设置为""的情况下会产生冲突,编译会报错。

    @RequestMapping()
    public String voidController1() {
        return "voidController1";
    }

    @RequestMapping(value = "")
    public String voidController2() {
        return "voidController2";
    }

两者可以看做等价,但是又存在区别。

value不设置的情况下,认为是默认控制器,此时不能令返回值=void,否则会在请求时报错

// TODO 需要翻源码了解为何报错

Circular view path [second]: would dispatch back to the current handler URL [/second] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

但是可以跳转到其他类下的路径,而value = "" 时则不会有这些问题.

@Controller
@RequestMapping(value = "/second")
public class SecondPageController {

    @RequestMapping()
    public String defaultController() {
        // 报错
        // return "/terra";
        return "/terra/test";
    }
}

于是乎可以做到类似以下的杂技般有趣但又没多大意义的跳转,需要注意的是默认控制器无法直接使用本类下的子路径,原因不明。

@Controller
@RequestMapping(value = "/terra")
public class TestController {


    @RequestMapping(value = "test")
    public String testController() {
        System.out.println("测试请求");
        return "/terra";
    }

    @RequestMapping()
    public String defaultController() {
        System.out.println("请求跳转到了默认请求控制器");
        // 无法跳转
        // return "/jump";
        return "/terra/jump";
    }

    @RequestMapping(value = "jump")
    public String jumpController() {
        System.out.println("请求跳转到了jump");
        return "void";
    }

    @RequestMapping(value = "void")
    public void voidController() {
        System.out.println("请求跳转到了void,终止");
    }

}
localhost:9000/terra/test 或者localhost:9000/second 请求控制台输出:
测试请求
请求跳转到了默认请求控制器
请求跳转到了jump
请求跳转到了void,终止

顺带一提value支持中文,猜想支持的范围=String.equal,但是一般不会有猿们这么用吧

@Controller
@RequestMapping(value = "/中文")
public class ZnTestController {

    @RequestMapping(value = "测试")
    public void testController() {
        System.out.println("测试请求");
    }
}

想写下一个内容的过程发现 value值中带不带“/”是等价的,下面两个test会报错,且用无斜杠与有斜杠的路径没有区别

@Controller
@RequestMapping("value")
public class ValueBindController {

    @RequestMapping(value = "/test")
    public void hasSlash() {
        System.out.println("有斜杠");
    }

    @RequestMapping(value = "test")
    public void noneSlash() {
        System.out.println("无斜杠");
    }
}

路径貌似不支持其他特殊字符,如#value或/#value时无法与localhost:/#value/test进行匹配

......好吧正题

value支持使用占位符对url进行值绑定到参数上,如下列形式,这种即是REST风格的入参形式

@Controller
@RequestMapping("value")
public class ValueBindController {

    @RequestMapping(value = "printValue/{value}")
    public void printValue(@PathVariable String value) {
        // localhost:9000/value/printValue/1
        System.out.println(value);
    }

    @RequestMapping(value = "printPrintValue/{value}")
    public void printPrintValue(@PathVariable("value") String printValue) {
        // localhost:9000/value/printPrintValue/1
        System.out.println(printValue);
    }

    @RequestMapping(value = "printValues/{value1}/{value2}")
    public void printValues(@PathVariable String value1, @PathVariable Integer value2) {
        // localhost:9000/value/printValues/1/2
        System.out.println(value1 + "/" + value2);
    }

    @RequestMapping(value = "printMap/{value1}/{value2}")
    public void printValues(@PathVariable Map<String, String> map) {
        // localhost:9000/value/printValues/1/2
        System.out.println(map.get("value1") + "/" + map.get("value2"));
    }

    @RequestMapping(value = "printList/{list}")
    public void printValues(@PathVariable List<String> list) {
        // localhost:9000/value/printList/1,2,3
        list.stream().forEach(k -> System.out.print(k + " "));
        System.out.println();
    }
}

博客上有人提到过使用@PathVariable会产生截断问题,即value/{value},若输入为1.jpg,value =1。但是测试时发现非常非常的正常,版本问题么?

value支持多路径,如下,这种形式还可以解决当参数参数非必传时的问题

@Controller
@RequestMapping(value = "mul")
public class MulValueController {

    @RequestMapping(value = {"one", "two", "three"})
    public void test() {
        // localhost:9000/mul/one
        // localhost:9000/mul/two
        // localhost:9000/mul/three
        System.out.println("多路径匹配");
    }

    @RequestMapping(value = {"value/{value1}", "value/{value1}/{value2}"})
    public void printValues(@PathVariable String value1, @PathVariable(required = false) String value2) {
        // localhost:9000/value/1
        // localhost:9000/value/1/2
        System.out.println(value1 + "/" + value2);
    }
}

value亦支持正则表达式

@Controller
@RequestMapping(value = "regex")
public class RegexController {

    @RequestMapping(value = "tel/{number:^18[0-9]\\d{8}$}")
    public void telPhone(@PathVariable String number) {
        // 匹配以18开头的手机号码
        // localhost:9000/regex/tel/18123456890
        System.out.println(number);
    }
}

但是复杂一些的正则会出一些莫名其妙的错误,原因不明,比如

^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$

会报下面这个异常。

The number of capturing groups in the pattern segment (^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\d{8}$) does not match the number of URI template variables it defines, which can occur if capturing groups are used in a URI template regex. Use non-capturing groups instead.

二. method

method用于指定请求类型,如GET,POST

路径相同类型不同的方法可以共存(value =value , method != method) ,

如下GET请求会到getController,POST请求会执行postController,其余类型的请求会执行allController

    @RequestMapping(method = RequestMethod.GET)
    public String getController() {
        return "Get请求";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String postController() {
        return "Post请求";
    }

    @RequestMapping()
    public String allController() {
        return "任意请求";
    }

method支持多参数,这里用GET还是用POST都会调用这个方法

   @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
    public String getPostController() {
        return "GetOrPost请求";
    }

猜你喜欢

转载自www.cnblogs.com/syui-terra/p/10175514.html