SpringMVC
SpringMVC
本文分为以下几个部分:
Controller 和 RestController
新建一个 SpringMVC 项目,配置相应 controller 扫描包、jsp 文件位置。
笔者此处配置了 test.jsp 文件
<h1>
我是test
</h1>
配置两个 controller
@Controller
public class Controller1 {
@RequestMapping("/c1")
public String test1(){
return "test";
}
}
@RestController
public class Controller2 {
@RequestMapping("/rc2")
public String test1(){
return "test";
}
}
启动项目,访问两个 controller,@Controller 注解示例图如下,正常访问 test.jsp 页面
@RestController 注解示例图如下,并 没有正常访问 test.jsp 页面:
查看对应源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(annotation = Controller.class)
String value() default "";
}
相比之下, RestController 比 Controller 多了一个 @ResponseBody 注解,其他无差,导致访问 RestController 的方法不走视图解析器,直接把返回值响应回去。
所以
@RestController
相当于
@Controller
@ResponseBody
我们再看 @ResponseBody
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}
@ResponseBody 不仅可以用于 ElementType.TYPE(class),也能用于 ElementType.METHOD (方法),刚才@RestController就是用于 class 上方,等同于整个class 都不走视图解析器。
所以如果在一个 @Controller 的方法中,想要部分直接把返回值响应回去,直接在方法上添加 @ResponseBody 即可。
@RequestMapping("/c2")
@ResponseBody
public String test2(){
return "test";
}
RequestParam 和 RequestBody
Get 方法传参为链接地址传值,此处说的均为 POST 方法请求
RequestParam
我们先来看普通的处理 post 方法,编写一个form表单来仿造post方法
后台编写对应的 p1 controller方法
@RestController
public class Controller3 {
@PostMapping("/p1")
public String test1(String username,String password){
return username + ":" + password;
}
}
查看对应效果
由于配置的是 RestController,所以直接返回字符串。
如果有些前端不讲武德,将 password 改成 name="pwd" ,但后端没变化,依旧访问 p1 请求,此时会得到
后端可能存在使用password较为频繁,但此时如果修改传参为 String pwd,难免会有些麻烦,此时采用@RequestParam("pwd") String password 来指定前端传的值
@PostMapping("/p2")
public String test2(@RequestParam("username") String userName,
@RequestParam("pwd") String password){
return userName + ":" + password;
}
此时,前端把 pwd 又改成了 password,不动后台代码的情况。
直接报错,原因是没有传pwd这个key,后台解析的时候需要pwd,但无法获取
点击RequestParam查看源码
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
//参数,和value一样,可以看成别名
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
//是否必须存在
boolean required() default true;
//默认值
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
将required改成 false,同时将请求参数改成 name = "pwd" 或者 value ="pwd",此时就算前端不传该值,也不会报错。
@PostMapping("/p2")
public String test2(@RequestParam(value = "username",required = false) String userName,
@RequestParam(name = "pwd",required = false) String password){
return userName + ":" + password;
}
此时不会报错,直接显示null
RequestBody
直接修改controller的方法
@PostMapping("/p3")
public String test3(@RequestBody String body){
return body;
}
前台 form 提交至p3
启动项目访问
由于前端传过来会变成一个字符串,所以建议使用 JSON 传输数据。
使用 ajax 传输json字符串
ajax访问p3,返回的结果为刚才传输的json字符串
解析 JSON 虽然不麻烦,但是可以改成自动装配,添加一个 DTO 文件
package com.yb.dto;
/**
* @author yb
* @version 1.0
* @date 2021/8/23 15:41
* @description 前端传输配置类
*/
public class UserDTO {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserDTO() {
}
public UserDTO(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String toString() {
return "UserDTO{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
新增controller方法,将ajax 请求P4,会自动装配值 UserDTO 中
@PostMapping("/p4")
public String test4(@RequestBody UserDTO user){
return user.toString();
}
结语
- @RestController 比 @Controller 只多配置了 @ResponseBody ,配置了 @ResponseBody 则不走视图解析器。
- @RequestParam 可以看成是前端传输字段时候的一个获取方法,当字段名和前端传输的字段相同时,可以不配置 @RequestParam。当配置 @RequestParam 报错时,可以看看是否该字段不存在(不存在和为空是两个概念)。
- @RequestBody 是直接将前端所有数据放在一个中获取,通常前端使用JSON时候接收,当然不知道前端传的啥,可以使用RequestBody来接收试试(一个方法只存在一个@RequestBody)