04-SpringBoot (四) --- MVC支持及JSR303数据校验

SpringBoot (四) — MVC支持及JSR303数据校验


MVC支持

提到MVC支持我们先暂且来讲解几个项目中常用的注解,后续会出集成SpringMVC的文章,这几个注解分别为,@RestController@RequestMapping@PathVariable@RequestParam 以及 @RequestBody

@RestController

前文我们已经介绍过@RestController,这里再简单介绍下,该注解包含了原来的 @Controller@ResponseBody 注解,我们提到,@ResponseBody 注解是将返回的数据结构转换为 Json 格式。这就提醒我们需要注意一个问题:

如果是前后端分离,不用模板渲染的话,比如 Thymeleaf,这种情况下是可以直接使用@RestController 将数据以 json 格式传给前端,前端拿到之后解析;但如果不是前后端分离,需要使用模板来渲染的话,一般 Controller 中都会返回到具体的页面,那么此时就不能使用@RestController了

public String goHome() {
	return "home";
}

此时我们是想返回home.html页面,如果使用 @RestController 的话,会将 “home“作为字符串返回的,所以这时候我们需要使用 @Controller 注解。

@RequestMapping

@RequestMapping 是一个用来处理请求地址映射的注解,它可以用于类上,也可以用于方法上。在类的级别上的注解会将一个特定请求或者请求模式映射到一个控制器之上,表示类中的所有响应请求的方法都是以该地址作为父路径;在方法的级别表示进一步指定到处理方法的映射关系

该注解有8个属性,一般在项目中比较常用的有三个属性:value、method 和 produces。

  • value 属性:指定请求的实际地址,当括号内只有一个值的时候value 可以省略不写,value属性支持通配符匹配@RequestMapping(value=“getUser/*”)
  • method 属性:指定请求的类型,主要有 GET、PUT、POST、DELETE以及 PATCH,默认为 GET。@RequestMapping(value = “getUser”,method = {RequestMethod.GET,RequestMethod.POST}),说明该方法可以同时支持GET和POST请求。如果没有method属性,则说明该方法支持全部的HTTP请求。
  • produces属性:指定返回内容类型,如 produces = “application/json; charset=UTF-8”
  • path属性: 和value属性使用一致,两者都是用来作为映射使用的,同样支持通配符匹配
  • name属性:相当于方法的注释,使方法更易理解 ,@RequestMapping(value = "getUser",name = "获取用户信息")
  • params属性:请求中必须包含params属性规定的参数时,才能执行该请求,参数值不做要求
  • header属性:请求中必须包含某些指定的header值,才能够让该方法处理请求
  • consumers属性:指定处理请求的提交内容类型(Content-Type),例如:application/json、text/html时,才能够让该方法处理请求
@RestController
@RequestMapping(value = "/test", produces = "application/json; charset=UTF-8")
public class TestController {
 
    @RequestMapping(value = "/get", method = RequestMethod.GET)
    public String testGet() {
        return "success";
    }
}

这个很简单,启动项目在浏览器中输入 localhost:8080/test/get 测试一下即可。

针对四种不同的请求方式,是有相应注解的,不用每次在 @RequestMapping 注解中加 method 属性来指定,上面的 GET 方式请求可以直接使用 @GetMapping(“/get”) 注解,效果一样。相应地,PUT 方式、POST 方式和 DELETE 方式对应的注解分别为 @PutMapping、@PostMapping 和 DeleteMapping等。

利用produces 和 consumes属性来处理生产和消费对象

使用 @RequestMapping 注解的 produces 和 consumes 这两个属性来缩小请求映射类型的范围。

为使用请求的媒体类型来产生对象, 你要用到 @RequestMapping 的 produces 元素再结合着 @ResponseBody 注解。

也可以利用 @RequestMapping 的 comsumes 元素再结合着 @RequestBody 注解用请求的媒体类型来消费对象。

@RestController
public class IdController {
    @RequestMapping(value = "/produce", produces = {"application/JSON"})
    @ResponseBody
    String getProduces() {
        return "Produces attribute";
    }

    @RequestMapping(value = "/consume", consumes = {
        "application/JSON",
        "application/XML"
    })
    String getConsumes() {
        return "Consumes attribute";
    }
}

getProduces() 处理方法会产生一个 JSON 响应, @ResponseBody 的作用其实是将 java 对象转为 json 格式的数据。

getConsumes() 处理方法可以同时处理请求中的 JSON 和 SML 内容。

header属性来处理消息头

header 元素来根据请求中的消息头内容缩小请求映射的范围

@RestController
public class IdController {
    @RequestMapping(value = "/head", headers = {
        "content-type=text/plain"
    })
    String post() {
        return "hello world";
    }
}

post() 方法就只会处理到 /head 并且 content-type被指定为 text/plain 这个值的请求。可以利用{}指定多个请求头

params属性来处理请求参数
@RestController
public class IdController {
    @RequestMapping(value = "/par", params = {
        "userId=10"
    })
    String getParams(@RequestParam("userId") String id) {
        return "id = " + id;
    }
    
    @RequestMapping(value = "/par", params = {
        "userId=20"
    })
    String getParamsDifferent(@RequestParam("userId") String id) {
        return "id = " + id;
    }
}

在这段代码中,getParams() 和 getParamsDifferent() 两个方法都能处理相同的一个 URL (/par) ,但是会根据 params 元素的配置不同而决定具体来执行哪一个方法。

例如,当 URL 是 /par?id=10 的时候, getParams() 会执行。当 URL 是 /par?id=20 的时候,getParamsDifferent() 处理方法会得到执行。

带有 @RequestParam 的 @RequestMapping

@RequestParam 注解使用的时候可以有一个值,也可以没有值。这个值指定了需要被映射到处理方法参数的请求参数

@RestController
public class IdController {

    @RequestMapping(value = "/id")
    // 实现请求参数 id 与 处理方法参数 userId 的绑定。
    String getIdByValue(@RequestParam("id") String userId) {
        System.out.println("ID is " + userId);
        return "hello world";
    }
    @RequestMapping(value = "/userId")
    String getId(@RequestParam String userId) {
        System.out.println("ID is " + userId);
        return "hello world";
    }
}

getIdByValue()方法实现了请求参数 id 与 处理方法参数 userId的绑定。

getId()方法实现了请求参数 userId与 处理方法参数 userId的绑定。

如果请求参数和处理方法参数的名称一样的话,@RequestParam 注解的 value 这个参数就可省掉了。

@PathVariable

@PathVariable 注解主要是用来获取 url 参数,Spring Boot 支持 restfull 风格的 url,比如一个 GET 请求携带一个参数 id 过来,我们将 id 作为参数接收,可以使用 @PathVariable 注解。

@GetMapping("/user/{id}")
public String test(@PathVariable Integer id) {
	System.out.println("获取到的id为:" + id);
	return "success";
}

这里需要注意一个问题,如果想要 url 中占位符中的 id 值直接赋值到参数 id 中,需要保证 url 中的参数和方法接收参数一致,否则就无法接收。如果不一致的话,需要用 @PathVariable 中的 value 属性来指定对应关系。

@RequestMapping("/user/{idd}")
public String test(@PathVariable(value = "idd") Integer id) {
	System.out.println("获取到的id为:" + id);
	return "success";
}

对于访问的 url,占位符的位置可以在任何位置,不一定非要在最后,比如这样也行:/xxx/{id}/user。另外,url 也支持多个占位符,方法参数使用同样数量的参数来接收

@GetMapping("/user/{idd}/{name}")
    public String test(@PathVariable(value = "idd") Integer id, @PathVariable String name) {
        System.out.println("获取到的id为:" + id);
        System.out.println("获取到的name为:" + name);
        return "success";
    }

运行项目,在浏览器中请求 localhost:8080/user/18/tom 可以看到控制台输出如下信息:

获取到的id为:18
获取到的name为:tom

所以支持多个参数的接收。同样地,如果 url 中的参数和方法中的参数名称不同的话,也需要使用 value 属性来绑定两个参数。

@RequestMapping 利用 @PathVaraible实现动态url

使用正则表达式来只处理可以匹配到正则表达式的动态 URI。

@RestController
public class IdController {
  
    @RequestMapping(value = "/user/{id:[a-z]+}/{name}")
    String getDynameValueRegex(@PathVariable("name") String name) {
        System.out.println("Name is " + name);
        return "hello world";
    }
}

当我们输入的URI能匹配正则表达式时,访问成功,例如:localhost:8080/user/hsjkl/tom

@RequestParam

@RequestParam 注解顾名思义,也是获取请求参数的,上面我们介绍了 @PathValiable 注解也是获取请求参数的,那么 @RequestParam 和 @PathVariable 有什么不同呢?主要区别在于: @PathValiable 是从 url 模板中获取参数值, 即这种风格的 url:http://localhost:8080/user/{id} ;而 @RequestParam 是从 request 里面获取参数值,即这种风格的 url:http://localhost:8080/user?id=1 。我们使用该 url 带上参数 id 来测试一下如下代码:

@GetMapping("/user")
public String testRequestParam(@RequestParam Integer id) {
	System.out.println("获取到的id为:" + id);
	return "success";
}

可以正常从控制台打印出 id 信息。同样地,url 上面的参数和方法的参数需要一致,如果不一致,也需要使用 value 属性来说明,比如 url 为:http://localhost:8080/user?idd=1

@RequestMapping("/user")
public String testRequestParam(@RequestParam(value = "idd", required = false) Integer id) {
	System.out.println("获取到的id为:" + id);
	return "success";
}

除了 value 属性外,还有个两个属性比较常用:

  • required 属性:true 表示该参数必须要传,否则就会报 404 错误,false 表示可有可无。
  • defaultValue 属性:默认值,表示如果请求中没有同名参数时的默认值。
@RequestParam 的 required 属性

@RequestParam 注解的 required 这个参数定义了参数值是否是必须要传的。

@RestController
public class IdController {
    @RequestMapping(value = "/name")
    String getName(@RequestParam(value = "user", required = true) String userName) {
        return "hello world";
    }
}

因为 required 被指定为 true,所以 getName() 处理方法对于如下两个 URL 只会对前一个进行处理:

/home/name?user=tom

/home/name

当request被指定为false时:

@RestController
public class IndexController {
    @RequestMapping(value = "/name")
    String getName(@RequestParam(value = "user", required = false) String userName) {
        return "hello world";
    }
}

此时getName()方法对如下两个url都会进行处理:

/home/name?user=tom

/home/name
@RequestParam 的 defaultValue属性

@RequestParam 的 defaultValue 取值就是用来给取值为空的请求参数提供一个默认值的。

@RestController
public class IdController {
    @RequestMapping(value = "/name")
    String getName(@RequestParam(value = "user", defaultValue = "tom") String userName) {
        return "hello world";
    }
}

在这段代码中,如果 user 这个请求参数为空,那么 getName() 处理方法就会接收 tom 这个默认值作为其参数。

从 url 中可以看出,@RequestParam 注解用于 GET 请求上时,接收拼接在 url 中的参数。除此之外,该注解还可以用于 POST 请求,接收前端表单提交的参数,假如前端通过表单提交 username 和 password 两个参数,那我们可以使用 @RequestParam 来接收,用法和上面一样。

@PostMapping("/form")
    public String testForm(@RequestParam String username, @RequestParam String password) {
        System.out.println("获取到的username为:" + username);
        System.out.println("获取到的password为:" + password);
        return "success";
    }

我们使用postman 来模拟一下表单提交,测试一下接口:

image-20230327155350971

image-20230327155430704

那么问题来了,如果表单数据很多,我们不可能在后台方法中写上很多参数,每个参数还要 @RequestParam 注解。针对这种情况,我们需要封装一个实体类来接收这些参数,实体中的属性名和表单中的参数名一致即可。

public class User {
	private String username;
	private String password;
	// set get
}

使用实体接收的话,我们不能在前面加 @RequestParam 注解了,直接使用即可。

@PostMapping("/form2")
    public String testForm(User user) {
        System.out.println("获取到的username为:" + user.getUsername());
        System.out.println("获取到的password为:" + user.getPassword());
        return "success";
    }

使用 postman 再次测试一下表单提交,观察一下返回值和控制台打印出的日志即可。在实际项目中,一般都是封装一个实体类来接收表单数据,因为实际项目中表单数据一般都很多。

@RequestBody

@RequestBody 注解用于接收前端传来的实体,接收参数也是对应的实体,比如前端通过 json 提交传来两个参数 username 和 password,此时我们需要在后端封装一个实体来接收。在传递的参数比较多的情况下,使用 @RequestBody 接收会非常方便。

public class User {
	private String username;
	private String password;
	// set get
}
@PostMapping("/user")
public String testRequestBody(@RequestBody User user) {
	System.out.println("获取到的username为:" + user.getUsername());
	System.out.println("获取到的password为:" + user.getPassword());
	return "success";
}

我们使用 postman 工具,参数我们用 json 来模拟:

image-20230327160421256

返回结果仍然为 success。

同时看一下后台控制台输出的日志:

获取到的username为:tom
获取到的password为:123456

可以看出,@RequestBody 注解用于 POST 请求上,接收 json 实体参数。它和上面我们介绍的表单提交有点类似,只不过参数的格式不同,一个是 json 实体,一个是表单提交。在实际项目中根据具体场景和需要使用对应的注解即可。

JSR303数据校验

Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式

@Component //注册bean
@ConfigurationProperties(prefix = "person")
@Validated  //数据校验
public class Person {

    @Email(message="邮箱格式错误") //name必须是邮箱格式
    private String name;
}
运行结果 :default message [不是一个合法的电子邮件地址];

常见的参数

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")	// 必须是Email,也可以通过正则表达式和flag指定自定义的Email格式

private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串,不能为null但是可以为空
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串有效,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY,而且长度必须大于0
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
数字检查
@Max@DecimalMax:必须为一个不大于指定值的数字
@Min@DecimalMin:必须为一个不大于指定值的数字
@Digits:必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Range:必须在合适的范围内
      
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 DateCalendar 对象是否在当前时间之前  
@Future     验证 DateCalendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值