在 spring 框架和 Spring Boot 中,最常用的技术就是 MVC 框架,MVC 框架会处理类似如下相同技术的需求:
1、HTTP UTL 映射到 Controller 某个方法;
2、HTTP 参数映射到 Controller 方法的参数上,比如参数映射到某个Java对象,或者上传附件映射到某个File对象上;
3、参数的校验;
4、MVC 错误处理;
5、MVC 中如何调用视图;
6、MVC 中如何序列化对象成JSON;
7、拦截器高级定制;
引入依赖
Spring Boot 集成 Spring MVC 框架并实现自动配置,只需要在 pom 中添加以下依赖即可,不需要其他任何配置。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Web 应用目录结构
Web的模板文件位于 resources/templates
目录下,模板文件使用的静态资源文件,如 js css 图片,存放在 resources/statis
目录下。在 MVC 中,视图名自动在 templates 目录下找到对应的模板名称,模板中使用的静态资源将在 static 目录下查找。
Java 包名结构
通常会创建如下子包名:
- Controller ---
- Service ---
- entity ---
- conf ---
使用 Controller
Spring MVC 框架不像传统的 MVC 框架那样必须继承某个基础类才能处理用户的 HTTP 请求, Spring MVC 只需要在类上声明 @Controller
,标注这是一个 Controller 即可。对于用户请求,使用 @RequestMapping
映射 HTTP 请求到特定的方法处理类。
@Controller
@RequestMapping("/test)
public class HelloworldController {
@RequestMapping("/index.html")
public String say(Model model) {
model.addAttribute("name","hello world");
return "/index.html";
}
}
如以上代码所示,@Controller 作用于类上,表示这是一个 MVC 中的 Controller。
@RequestMapping 既可以作用于方法上,也可以作用在类上。如上所示,用户如果访问 /test/index.html
,则会交给 HelloworldController.say 方法来处理。
say 方法有一个参数 Model,这是 Spring MVC 可识别的一个参数类型,用来表示 MVC 中的Model。可以在这个 Model 添加多个变量,这些变量随后可以用于视图渲染。
say 方法返回的类型是字符串,默认是视图名称。Spring Boot 的视图默认保存在 resources/templates
目录下,因此,渲染的视图是 /resources/templates/index.html
模板文件。
MVC 框架有时候返回的是 JSON 字符串,如果想直接返回内容而不是视图名,则需要在方法上使用 @ResponseBody
:
@RequestMapping("/index.json")
public @ResponseBody String say() {
return "hello world";
}
ResponseBody 注解直接将返回的对象输出到客户端,如果是字符串,则直接返回;如果不是,则默认使用 Jackson 序列化成 JSON 字符串后输出。
建议在 Spring Boot 应用中,如果期望返回 JSON, URL 请求后资源后缀是 json;如果期望返回视图,URL 请求资源后缀是 html
URL 映射到方法
RequestMapping
可以使用 @RequestMapping 来映射 URL,比如 /test
到某个 Controller 类,或者是某个具体的方法,通常类上的注解 @RequestMapping
用来标注请求的路径,方法上的 @RequestMapping
注解进一步映射特定的 URL 到某个具体的处理方法。
RequestMapping 有多个属性来进一步匹配 HTTP 请求到 Controller 方法,分别是:
- value, 请求的 URL 路径,支持 URL 模板、正则表达式。
- method,HTTP 请求方法,有 GET、POST、PUT 等。
- consumes,允许的媒体类型(Media Types),如 consumes = "application/json", 对应于请求的 HTTP 的 Content-Type。
- produces, 相应的媒体类型,如 produces = "application/json",对应于 HTTP 的 Accept 字段。
- params,请求参数,如 params="action=update"
- headers, 请求的 HTTP 头的值,如 headers = "myHeader=myValue"
URL 路径匹配
属性 value 用于匹配一个 URL 映射,value 支持简单的表达式类匹配:
@RequestMapping(value="/get/{id}.json")
public @ResponseBody User getById(@PathVariable("id") Long id) {
return userService.getUserById(id);
}
上边访问路径是 /get/1.json, 将调用 getById 方法,且参数 id 的值是 1 。注解 PathVariable 作用在方法参数上,用来表示参数的值来自于 URL 路径。
HTTP method 匹配
@RequestMapping 提供 method 属性来映射对应 HTTP 的请求方法,通常 HTTP 请求方法有以下内容:
- GET, 用来获取 URL 对应的内容
- POST,用来向服务器提交信息
- HEAD,同 GET,但不返回消息体,通常用于返回 URL 对应的元信息,如过期时间等。
- PUT,同 POST,用来向服务器提交信息,但语义上更像一个更新操作。同一个数据,多次 PUT 操作,也不会导致数据发生改变。POST 在语义上更类似新增操作。
- DELETE, 删除对应的资源信息。
- PATCH 方法,类似 PUT 方法,表示信息的局部更新。
通常对于 Web 应用,GET 和 POST 是经常使用的选项,对于 REST 接口,则会使用 PUT、DELETE 等用来从语义上进一步区分操作。
Spring 提供了简化后的 @RequestMapping
, 提供了新的注解来表示 HTTP 方法:
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
- @PatchMapping
consumes 和 produces
属性 consumes 意味着请求的 HTTP 头的 Content-Type 媒体类型与 consumes 的值匹配,才能调用此方法。
@GetMapping(value="/consumes/test.json",consumes="application/json")
@ResponseBody
public User forjson() {
return userService.getUserById(11);
}
这里映射指定请求的媒体类型是 application/json
,因此,此方法接受一个 AJAX 请求。如果通过浏览器直接访问,则会出错,因为通过浏览器访问,通常并没有设置 Context-Type。
为了成功调用上述Controller方法,AJAX调用必须设置 Content-Type 为 application/json
$.ajax({
type: "get",
url: "/consumes/test.json",
contentType: "application/json",
....
})
produces属性对应于 HTTP 请求的 Accept 字段,只有匹配的上的方法才能被调用。
@GetMapping(value="/user/{userid}",produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public User getUser(@PathVariable Long userId, Model model) {
return userService.getUserById(userId);
}
通常浏览器都会将 Accept 设置为 .
params 和 header 匹配
可以从请求参数或者 HTTP 头中提取值来进一步确定调用的方法,有以下三种形式:
- 如果存在参数,则通过;
- 如果不存在参数,则通过;
- 如果参数等于某一个具体值,则通过。
@PostMapping(value="/update.json",params="action=save")
@ResponseBody
public void saveUser() {
System.out.println("call save");
}
header 和 params 一样:
@PostMapping(value="/update.json",headers="action=save")
@ResponseBody
public void saveUser() {
System.out.println("call save");
}
方法参数
Spring 的 Controller 方法可以接受多种类型参数,比如我们看到的 path 变量,还有 MVC 的 Model,除此之外,方法还能接受以下参数。
- @PathVariable, 可以将URL中的值映射到方法参数中。
- Model,Spring 中通用的MVC模型,也可以使用 Map 和 ModelMap 作为渲染视图的模型。
- ModelAndView, 包含了模型和视图路径的对象。
- JavaBean,将HTTP参数映射到 JavaBean对象。
- MultipartFile,用于处理文件上传。
- @ModelAttribute 使用该注解的变量将作为 Model 的一个属性。
- WebRequest 或者 NativeWebRequest,类似 Servlet Requset ,但做了一定封装。
PathVariable
注解 PathVariable 用于从请求 URL 中获取参数并映射到方法参数中
@RequestMapping(value="/get/{id}.json")
public @ResponseBody User getById(@PathVariable("id") Long id) {
return userService.getUserById(id);
}