专栏首页代码拾遗SpringMVC 教程 - Controller

SpringMVC 教程 - Controller

声明Controller

Controller也是一个标准的Spring bean,可以在Servlet的WebApplicationContext中定义。也可以使用@Controller注解,Spring会扫描注解自动注册为Spring的bean。 开启自动注册@Controller注解的bean可以使用如下Java Config的配置:

@Configuration
@ComponentScan("org.example.web")
public class WebConfig {

    // ...
}

如果使用xml配置,如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.example.web"/>

    <!-- ... -->

</beans>
请求映射

@RequestMapping可以将请求映射到具体的Controller方法上。通过找到匹配的url,http 方法,请求参数,header,媒体类型来映射请求。这个注解既可以用在类级别,也可以用在方法级别上。 为了方便@RequestMapping根据HTTP方法不同提供了如下快捷注解:

  • @GetMapping
  • @PostMapping
  • @DeleteMapping
  • @PutMapping
  • @PatchMapping

示例如下所示:

@RestController
@RequestMapping("/persons")
class PersonController {

    @GetMapping("/{id}")
    public Person getPerson(@PathVariable Long id) {
        // ...
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void add(@RequestBody Person person) {
        // ...
    }
}
URI 模式

请求映射支持glob模式和通配符

  • ? 匹配一个字符
  • * 匹配0个或多个字符
  • ** 匹配0个或多个路径 可以通过@PathVariable 访问在URI中定义的变量:
@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
    // ...
}

URI的变量可以在类和方法中定义:

@Controller
@RequestMapping("/owners/{ownerId}")
public class OwnerController {

    @GetMapping("/pets/{petId}")
    public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
        // ...
    }
}

URI变量会自动类型转换,如果失败会抛出TypeMismatchException的异常。默认支持int,long,Date等类型,也可以通过DataBinder和 Type Conversion来注册其他需要支持的类型。 URI变量名也可以明确的支持,例如@PathVariable("customId"),不过如果在编译的时候带着调试信息,或者对于Java8 使用-parameters 编译,则可以不需要明确的命名。 语法{varName:regex}表示变量根据正则表达是来匹配,例如”/spring-web-3.0.5 .jar”可以使用以下表达式匹配

@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String version, @PathVariable String ext) {
    // ...
}

URI同样可以有内嵌的${}的占位符,在应用启动的时候由PropertyPlaceHolderConfigurer从本地,系统,环境变量或者其他配置中解析。 Spring MVC使用的是Spring core 中的AntPathMatcher来匹配路径。

模式对比

当有很多模式匹配URI的时候,必须通过对比来找到最合适的匹配。这个是通过AntPathMatcher.getPatternComparator(String path)来实现。 可以根据URI中的变量个数,通配符个数来给URL打分,如果一个URI的变量少,通配符多,那么他得到的分数就会低。当匹配的模式分数相同是,选择匹配模式长的那个,如果分数和长度都相同,选择变量比通配符少的那个。 /**是不参与评分的,而且总会是最后一个选择。同样/plublic/**也是当匹配不到其他没有两个通配符的模式的时候才会被选择。 了解更加详细的信息可以查看AntPathMatcher中的AntPatternComparator。同时也可个继承PathMatcher来定制URI匹配。

后缀匹配

Spring MVC 默认启动.*后缀匹配模式,这样映射到/person的controller 同样可以映射到/person.*。扩展名可以用来代替header中的Accept表示请求返回的类型。例如person.pdf,person.xml等。 因为过去浏览器的Accept头很难解析,所以这么是有意要的,但是现在浏览器的Accept更加清晰明确了,所以更好的选择是用Accept。而且过去一段时间内,使用后缀名匹配的时候会有各种各样的问题,当使用URI变量,路径参数,URI编码时后缀模式会导致歧义。 可以使用以下方法关闭后缀模式:

  • PathMatchConfigureruseSuffixPatternMatching(false)
  • ContentNeogiationConfigurerfavorPathExtension(false)后缀匹配和RFD 反射型文件下载(RFD)攻击和XSS攻击很相似。XSS依赖于请求的输入,例如查询参数,URI变量等,而RFD是用户点击URL浏览器会下载恶意文件,用户点击后会攻击主机。 由于Spring MVC的 @ResponseBodyResponseEntity会根据URI后缀来渲染不同类型的响应内容,所以可能受到RFD攻击。关闭后缀匹配可以降低攻击的风险,但是不能完全防止RFD攻击。 为了防止RFD攻击,可以在渲染响应内容的时候添加Content-Disposition:inline;filename=f.txt确保一个安全的下载文件。 默认情况下大多数扩展名都有白名单,可以通过继承HttpMessageConverter对内容协商注册扩展,可以避免在响应中添加Content-Disposition可消费媒体类型 通过请求的Content-Type可以缩小请求的匹配范围,例如:@PostMapping(path = "/pets", consumes = "application/json") public void addPet(@RequestBody Pet pet) { // ... }

consumes也支持表达式求反操作,例如!text/plain指的就除了text/plain都可以。 可以定义一个类级别的consumes,其方法共享这个consumes,和其他的@ReqeustMapping的属性不同,方法的consumes会覆盖类的定义。

可产生的媒体类型

可以通过Accept头来缩小请求的匹配范围,例如:

@GetMapping(path = "/pets/{petId}", produces = "application/json;charset=UTF-8")
@ResponseBody
public Pet getPet(@PathVariable String petId) {
    // ...
}

媒体类型可以指定一个字符集。对表达式取反也是支持的,例如:!text/plain指的就是除了text/plain都可以。 和consumes一样,也可以指定一个类级别的produces,其方法属性也会覆盖类的属性。

参数和HTTP header

可以通过参数来缩小请求匹配的范围。可以设置是否有参数(“myParam”),反过来是否没有(“!myParam”)或者指定一个值(”myParam=myValue”)。

@GetMapping(path = "/pets/{petId}", params = "myParam=myValue")
public void findPet(@PathVariable String petId) {
    // ...
}

同样的情况也适合HTTP header

@GetMapping(path = "/pets", headers = "myHeader=myValue")
public void findPet(@PathVariable String petId) {
    // ...
}

本文分享自微信公众号 - 代码拾遗(gh_8f61e8bcb1b1)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Boot 2.0 教程 - 配置详解

    Spring Boot 可以通过properties文件,YAML文件,环境变量和命令行参数进行配置。属性值可以通过,@Value注解,Environment...

    代码拾遗
  • JPA 详解

    Java Persistence API(JPA)是将Java对象和关系型数据库对象映射起来规范。实现这个规范后开发者可以使用相同的代码可以在任意的数据库中执行...

    代码拾遗
  • Spring Cloud 教程 - Eureka Server

    将groupId 为 org.springframework.cloud,artifactId 为spring-cloud-starter-netflix-eu...

    代码拾遗
  • 两个数组的交集II

    遍历nums1并使用一HashMap存储每个元素出现的次数,接着遍历nums2,若当前元素在在map中出现次数大于0,则说明当前元素为交集记录该元素,将map中...

    你的益达
  • 算法提高 简单加法

    问题描述   小于10的自然数中有四个数字能除尽3或5(3, 5, 6, 9),它们的和为23。   请计算所有小于1000的自然数中能除尽3或5的数字...

    AI那点小事
  • 设计模式-策略模式

    将原先耦合的if进行拆分成类,然后使用的时候注入类即可。或者使用枚举类型,如果需要增加,需要实现抽象方法。

    mySoul
  • 写出优质Java代码的4个技巧

    如果现在要求对你写的Java代码进行优化,那你会怎么做呢?作者在本文介绍了可以提高系统性能以及代码可读性的四种方法,如果你对此感兴趣,就让我们一起来看看吧。

    lyb-geek
  • 写出优质Java代码的4个技巧

    如果现在要求对你写的Java代码进行优化,那你会怎么做呢?作者在本文介绍了可以提高系统性能以及代码可读性的四种方法,如果你对此感兴趣,就让我们一起来看看吧。

    Java团长
  • 写出优质Java代码的4个技巧

    如果现在要求对你写的Java代码进行优化,那你会怎么做呢?作者在本文介绍了可以提高系统性能以及代码可读性的四种方法,如果你对此感兴趣,就让我们一起来看看吧。

    Java后端工程师
  • Android 深入(一)- 自定义View之BottomTitleImageView

    1)从图中我们View的整个生命周期,主要由三部分操作完成分别是measure()、layout()、draw(),作用如下:

    热心的程序员

扫码关注云+社区

领取腾讯云代金券