学习Spring MVC
当我们在浏览器中输入了url之后, Spring MVC项目就可以感知到用户的请求, 并给予响应.
学习Spring MVC, 重点也就是学习如何通过浏览器和用户程序进行交互.
主要分以下三个方面:
1.建立连接: 将用户(浏览器)和 java 程序连接起来,也就是访问一个地址能够调用到我们的Spring 程序。
**2.请求: **用户请求的时候会带一些参数,在程序中要想办法获取到参数,所以请求这块主要是获取参 数的功能.
**3.响应: **执行了业务逻辑之后,要把程序执行的结果返回给用户,也就是响应.
建立连接
在Spring MVC中使用 @RequestMapping 来实现URL路由映射,也就是浏览器连接程序的作用
我们先来看看代码怎么写
创建一个UserController类,实现用户通过浏览器和程序的交互,具体实现代码如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping("sayHi")
public String hello() {
return "Hello SpringMVC!";
}
}
@RequestMapping 注解介绍
@RequestMapping 是 Spring Web MVC 应用程序中最常被用到的注解之一, 它是用来注册接口的路由映射的.
表示服务收到请求时, 路径为 /sayHi 的请求就会调用 sayHi 这个方法的代码.
路由映射: 当用户访问一个URL时,将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射.
既然 @RequestMapping 已经可以达到我们的⽬的了, 我们为什么还要加 @RestController 呢? 我们把 @RestController 去掉, 再来访问⼀次:
可以看到, 程序报了404, 找不到该页⾯.
这就是 @RestController 起到的作用.
一个项目中,会有很多类,每个类可能有很多的方法, Spring 程序怎么知道要执行哪个方法呢?
Spring 会对所有的类进行扫描,如果类加了注解 @RestController , Spring 才会去看这个类里面的方法有没有加 @RequestMapping 这个注解, 当然他的作用不止这一点,我们先学会用.
@RequestMapping 使用
@RequestMapping 既可修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类路径+方
法路径.
@RequestMapping 标识一个类: 设置映射请求的请求路径的初始信息
@RequestMapping 标识一个方法: 设置映射请求请求路径的具体信息
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("sayHi")
public String hello() {
return "Hello SpringMVC!";
}
}
访问地址:http://127.0.0.1:8080/user/sayHi
**注意: **@RequestMapping 的 URL 路径最前面加不加 / (斜杠)都可以, Spring 程序启动时,会进行判断,如果前面没有加 / , Spring会拼接上一个 / , 通常情况下, 我们加上/
@RequestMapping 的 URL 路径也可以是多层路径, 最终访问时, 依然是 类路径 + 方法路径
@RequestMapping 既支持Get请求,又支持Post请求.同理,也支持其他的请求方式.
那如何指定GET或者POST类型呢?
我们可以显示的指定@RequestMapping来接收POST的情况,如下所示:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping(value = "/getRequest",method= RequestMethod.POST)
public String sayHi(){
return "get request...";
}
}
传参介绍
在测试传参时, 我们需要借助一个后端开发常用的接口测试工具 Postman , 这里就不对其进行过多的介绍了.
下载连接: https://www.postman.com/downloads/
为了方便演示, 下面的传参只放了其中核心部分的代码, 如下图红色框内部分:
传递单个参数
接收单个参数,在Spring MVC中直接用方法中的参数就可以,比如以下代码:
@RequestMapping("/r1")
public String r1(String name) {
return "接收到参数, name= " + name;
}
使用 Postman 进行传参测试:
也可使用浏览器发送请求并传参: http://127.0.0.1:8080/request/r1?name=zhangsan
可以看到,后端程序正确拿到了name参数的值.
Spring MVC会根据方法的参数名,找到对应的参数,赋值给方法
如果参数不一致, 是获取不到参数的. 比如:
注意事项
使用基本类型来接收参数时,参数必须传(boolean类型),否则会报500错误
类型不匹配时,会报400错误.
传递多个参数
如何接收多个参数呢?
和接收单个参数一样,直接使用方法的参数接收即可.使用多个形参.
@RequestMapping("/r4")
public String r4(String name, Integer age) {
return "接收到参数, name= " + name + ", age = " + age;
}
使用 Postman 测试:
当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置是不影响后端获取参数的结果.
传递对象
如果参数比较多时,方法声明就需要有很多形参. 并且后续每次新增一个参数, 也需要修改方法声明. 我们不妨把这些参数封装为一个对象.
SpringMVC 也可以自动实现对象参数的赋值,比如Student对象:
class Student {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
传递对象代码实现:
@RequestMapping("/r5")
public String r5(Student student) {
return "接收到参数: " + student.toString();
}
使用 Postman 测试:
Spring 会根据参数名称自动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为 null (基本类型则赋值为默认初识值, 比如 int类型的属性, 会被赋值为 0)
后端参数重命名(后端参数映射)@RequestParam
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不一致,比如前端传递了一个 name 给后端,而后端是使用 username 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用 @RequestParam 来重命名前后端的参数值.
@RequestMapping("/r6")
public String r6(@RequestParam("name") String username, Integer age) {
return "接收到参数, name= " + username + ", age = " + age;
}
使用 Postman 测试:
可以看到, Spring 可以正确的把浏览器传递的参数 time 绑定到了后端参数 caretetime 参数. 上
此时,如果使用 caretetime 进行参数传递呢?
使用 Postman 测试:
错误日志信息为:
控制台打印日志显示:请求参数 'username' 不存在
可以得出结论:
1.使用 @RequestParam 进行参数重命名时,请求参数只能和 @RequestParam 声明的名称一
致,才能进行参数绑定和赋值.
2.使用 @RequestParam 进行参数重命名时,参数就变成了必传参数.
非必传参数设置
如果我们的实际业务前端的参数是一个非必传的参数, 针对上述问题, 如何解决呢?
先来了解下参数必传的原因,我们查看 @RequestParam 注解的实现细节就可以发现端倪,注解实现如下:
可以看到 required 的默认值为 true ,表示含义就是:该注解修饰的参数默认为必传, 既然如此, 我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错.
具体实现如下:
@RequestMapping("/r7")
public String r7(@RequestParam(value = "name", required = false) String name) {
return "接收到参数, name= " + name;
}
可以看到,添加 required=false 之后,time 前面也加了 key ,变成了 value = "time"
注解属性赋值时,没有指明 key 的话,默认为 value 属性.
如果需要有多个属性进行赋值时,需要写上 key
传递数组
Spring MVC 可以自动绑定数组参数的赋值
后端实现代码:
@RequestMapping("/r8")
public String r8(int[] array) {
return "接收到参数" + Arrays.toString(array);
}
使用 Postman 测试:
传递集合
集合参数:和数组类似,同一个请求参数名有为多个,且需要使用 @RequestParam 绑定参数关系
默认情况下,请求中参数名相同的多个值,是封装到数组.如果要封装到集合,要使用@RequestParam 绑定参数关系
请求方式和数组类似:
后端接收代码:
@RequestMapping("/r9")
public String r9(@RequestParam List<String> list) {
return "接收到参数" + list;
}
使用 Postman 测试:
传递JSON数据
JSON的语法:
- 数据在键值对 (Key/Value) 中
- 数据由逗号,分隔
- 对象用 { } 表示
- 数组用 [ ] 表示
- 值可以为对象, 也可以为数组,数组中可以包含多个对象
JSON的两种结构
1.对象: 大括号 { } 保存的对象是一个无序的键值对集合. 一个对象以左括号 { 开始,右括号 } 结束。每个"键"后跟一个冒号 : ,键值对使用逗号,分隔
**2.数组: **中括号 [ ] 保存的数组是值(value) 的有序集合.一个数组以左中括号 [ 开始,右中括号 ] 结束,值之间使用逗号,分隔。
传递JSON对象
接收JSON对象,需要使用 @RequestBody 注解
RequestBody: 请求正文,意思是这个注解作用在请求正文的数据绑定,请求参数必须在写在请求正文中.
后端实现:
@RequestMapping("/r10")
public String r10(@RequestBody Student student) {
return "接收到参数: " + student.toString();
}
使用 Postman 来发送 json 请求参数:
可以看到,后端正确接收了
通过 Fiddler 观察一下请求参数:
如果去除掉 @RequestBody , 后端会无法给 Student 对象赋值. 这里就不给大家演示了.
获取URL中参数@PathVariable
path variable: 路径变量
和字面表达的意思一样,这个注解主要作用在请求 URL 路径上的数据绑定
默认传递参数写在 URL 上,SpringMVC 就可以获取到
后端实现代码:
@RequestMapping("/article/{articleId}/{name}")
public String r12(@PathVariable("articleId") Integer articleId, @PathVariable("name") String name) {
return "接收到参数, articleId:" + articleId + " , name: " + name;
}
使用 Postman 测试:
可以看到,后端正确获取到了URL中的参数
参数对应关系如下:
如果方法参数名称和需要绑定的 URL 中的变量名称一致时,可以简写,不用给 @PathVariable 的属性赋值,如上述例子中的 articleId 变量
如果方法参数名称和需要绑定的 URL 中的变量名称不一致时, 需要 @PathVariable 的属性 value赋值,如上述例子中的 articleName 变量.
上传文件@RequestPart
后端实现代码:
@RequestMapping("/r13")
public String r13(@RequestPart("file") MultipartFile imgFile) {
String originalFilename = imgFile.getOriginalFilename();
return "接收到文件, 文件名: " + originalFilename;
}
使用 Postman 测试:
获取Cookie/Session
这部分的内容比较多, 详细介绍在下一篇文章.
响应
在我们前面的代码例子中,都已经设置了响应数据, Http响应结果可以是数据,也可以是静态页面,也可以针对响应设置状态码, Header 信息等.
返回静态页面
创建前端页面index.html(注意路径)
后端代码:
运行结果:
结果却发现,页面未正确返回, http 响应把 " / index. html" 当做了 http 响应正文的数据
那 Spring MVC 如何才能识别出来 index.html 是一个静态页面,并进行返回呢?
我们需要把 @RestController 改为@Controller
正确代码如下:
发现页面正确展示了:
@RestController和@Controller有着什么样的关联和区别呢?
咱们前面讲了MVC模式,后端会返回视图,这是早期时的概念
随着互联网的发展,目前项目开发流行"前后端分离"模式, Java主要是用来做后端项目的开发,所以也就不再处理前端相关的内容了
MVC 的概念也逐渐发生了变化,View 不再返回视图,而是返回显示视图时需要的数据.
所以前面使用的 @RestController 其实是返回的数据.
@RestController = @Controller + @ResponseBody
@Controller: 定义一个控制器, Spring 框架启动时加载,把这个对象交给 Spring 管理.
@ResponseBody: 定义返回的数据格式为非视图,返回一个 text/html 信息
如果想返回视图的话, 只需要把 @ResponseBody 去掉就可以了,也就是 @Controller
返回数据@ResponseBody
我们上面讲到, @ResponseBody 表示返回数据.
@ResponseBody 既是类注解,又是方法注解
如果作用在类.上,表示该类的所有方法,返回的都是数据,如果作用在方法上,表示该方法返回的是数据.
也就是说: 在类上添加 @ResponseBody 就相当于在所有的方法上添加了 @ResponseBody 注解.
同样,如果类.上有@RestController 注解时:表示所有的方法上添加了 @ResponseBody 注解,也就是当前类下所有的方法返回值做为响应数据
如果一个类的方法里,既有返回数据的,又有返回页面的,就把 @ResponseBody 注解添加到对应的方法上即可.
返回HTML代码片段
后端返回数据时,如果数据中有HTML代码,也会被浏览器解析
@ResponseBody
@RequestMapping("/indexData2")
public String indexData2() {
return "<h1>我是中国人</h1>";
}
运行结果:
通过Fiddler观察响应结果,Content-Type为text/html
响应中的 Content-Type 常见取值有以下几种:
● text/html|: body数据格式是 HTML
● text/css : body数据格式是 CSS
● application/j avascript : body 数据格式是 JavaScript
● application/json : body 数据格式是 JSON
返回JSON
Spring MVC 也可以返回 JSON
后端方法返回结果为对象
@ResponseBody
@RequestMapping("/getMap")
public HashMap<String,String> getMap() {
HashMap<String,String> map = new HashMap<>();
map.put("k1","v1");
map.put("k2","v2");
map.put("k3","v3");
map.put("k4","v4");
return map;
}
运行结果:
设置状态码
Spring MVC 会根据我们方法的返回结果自动设置响应状态码,程序员也可以手动指定状态码通过Spring MVC 内置对象 HttpServletResponse 提供的方法来进行设置
@ResponseBody
@RequestMapping("/setStat")
public String setStatus(HttpServletResponse response) {
response.setStatus(500);
return "设置状态码";
}
状态码不会影响页面展示, 通过 FIddler 来观察设置的结果:
设置Content-Type
我们通过设置 produces 属性的值,设置响应的报头Content-Type
@RequestMapping(value = "/returnJson2",produces = "application/json")
@ResponseBody
public String returnJson2() {
return "{\"success\":true}";
}
总结
版权归原作者 夏微凉. 所有, 如有侵权,请联系我们删除。