2.MVC框架

本文是读《Spring Boot2精髓-从构件小系统到架构分布式大系统》的读书笔记。

MVC框架 会处理的技术需求

  • HTTP URL映射到Controller某个方法
  • HTTP参数映射到Controller方法的参数上
  • 参数的校验
  • MVC错误处理
  • MVC中如何调用视图
  • MVC中如何序列化对象成JSON
  • 拦截器等高级定制

3.1集成MVC框架

引入依赖
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/static 目录下 。 在 MVC 中, 视图名自动在 templates 目录下找到对
应的模板名称,模板中使用的静态资源将在 static 目录下查找 。 如下 Controller 代码所示,将
“/userdetail.html?id=xxx ”请求映射到 foo 方法:

@RequestMapping("/userdetail.html")
public String foo(String id){
.......
return "/admin/userInfo.btl";
}

Java 包名结构
从上图可以看到,在 Spring Boot 应用中,通常会创建如下子包名 :
Controll er一一此包下包含了 MVC 的 Controller,如 UserControlle r;
Service一一此包下有业务处理代码 , 如 UserService ;
entity一一包含了业务实体 , 如 U s er 类 :
conf一一包含了一些配置类,比如用于配置数据源的 DataSourceCon旬, 还有本章的
JSON 序列化配置 JacksonConf。
Spring Boot 应用的程序入口 Ch3Application 建立在这些包名上 , 这样 Spring Boot 应用能自
动扫描整个项目的结构。
Ch3Application 同其他 Spring Boot 程序一样 , 仅仅是一个带有@SpringBootApplication 注解
的类 :

package com.bee.sample.ch3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Ch3Application {
	public static void main(String[] args) {
		SpringApplication.run(Ch3Application.class, args);

	}
}

3.2 使用Controller

建议熟悉curl命令后再来测试Controller,可以提高开发效率。

3.3 URL映射到方法

@RequestMapping
你可以使用@RequestMapping 来映射 URL,比如/test 到某个 Controller 类 , 或者是某个具
体的方法。通常类上的注解@RequestMapping 用来标注请求的路径 , 方法上的@RequestMapping
注解进一步映射特定的 URL 到某个具体的处理方法。
URL路径匹配

Ant 路径表达式
Ant 用符号“*”来表示匹配任意字符,用“**”来表示统配任意路径,用“?”来匹配
单个字符,比如:

  • /user/*. html ,匹配/user/1.html、/user/2.html 等 。
  • /**/1.html ,匹配/1.html,也匹配/user/1.htm l , 还匹配/user/add/1.html。。
  • /user/?.html,匹配/user/1.html,但不匹配/user/11.htm l 。

HTTP method匹配
@RequestMapping 提供 method 属性来映射对应 HTTP 的请求方法,通常 HTTP 请求方法有
如下内容:

  • GET ,用来获取 URL 对应的内容 。
  • POST , 用来向服务器提交信息。
  • HEAD ,同 GET ,但不返回消息体,通常用于返回 URL 对应的元信息,如过期时间等 。 搜索引擎通常用 HEAD 来获取网页信息。
  • PUT , 同 POST ,用来向服务器提交信息,但语义上更像一个更新操作 。同一个数据 ,多次 PUT 操作 ,也不会导致数据发生改变。 而 POST 在语义上更类似新增操作 。
  • DELETE,删除对应 的资源信息。
  • PATCH 方法 , 类似 PUT 方法 , 表示信息 的局部更新。

Spring 提供了简化后 的 @RequestMapping , 提供了新 的注解来表示 HTTP 方法 :

@GetMapping;
@PostMapping;
@PutMapping;
@DeleteMapping;
@PatchMapping 。

consumes和produces
属性 consumes 意味着请求的 HTTP 头的 Content-Type 媒体类型与 consumes 的值匹配 , 才
能调用此方法 。

params和header匹配

3.4 方法参数

Spring 的 Controller 方法可以接受多种类型参数,比如我们看到的 path 变量,还有 MVC 的Model 。 除此之外,方法还能接受以下参数。

  • @PathVariable,可以将 URL 中的值映射到方法参数中。
  • Model, Spring 中通用的 MVC 模型,也可以使用 Map 和 ModelMap 作为渲染视图的模
    型 。
  • ModelAndView,包含了模型和视图路径的对象 。
  • JavaBean ,将 HTTP 参数映射到 JavaBean 对象 。
  • MultipartFile ,用于处理文件上传 。
  • @ModeIAttribute,使用该注解的变量将作为 Model 的一个属性 。
  • WebRequest 或者 NativeWebRequest,类似 Servlet Request ,但做了 一定封装。
  • java.io.InputStream 和 java.io.Reader ,用来获取 Servlet API 中的 lnputStream/Reader 。
  • java.io.OutputStream I java.io.Writer,用来获取 Servlet API 中的 OutputStream/Writer 。
  • HttpMethod , 枚举类型 , 对应于 HTTP Method,如 POST 、 GET.
  • @MatrixVariable,矩阵变量。
  • @RequestParam , 对应于 HTTP 请求的参数,自动转化为参数对应的类型。
  • @RequestHeader,对应于 HTTP 请求头参数,自动转化为对应的类型。
  • @RequestBody , 自动将请求内容转为指定的对象 , 默认使用 HtψMessageConverters - 来转化。
  • @RequestPart,用于文件上传,对应于 HTTP 协议的 multipart/form-data 。
  • @SessionAttribute , 该方法标注的变量来自于 Session 的属性。
  • @RequestAttribute,该标注的变量来自于 request 的属性。
  • @InitBinder,用在方法上,说明这个方法会注册多个转化器,用来个性化地将 HTTP请求参数转化成对应的 Java 对象,如转化为 日期类型、浮点类型 、 JavaBean 等,当然,也可以实现 WebBindinglnitializer 接口来用于 Spring Boot 应用所需要的 dataBinder。
  • BindingResult 和 Errors , 用来处理绑定过程中的错误。

这里部分含义比较明确,限于篇幅不做详细讲解,下面会对常用 的 PathVariable 、 Model 、
ModelAndView 、 JavaBean 、 文件上传、 ModelAttribute 进行讲解 。
PathVariable
注解 PathVariable 用于从请求 URL 中获取参数井映射到方法参数中
Model&ModelAndView
任何 MVC 框架都有一个类似 Map 结构的 Model,可以向 Model 添加视图需要的变量, Spring
MVC 中的 Model 就是完成此功能的 。
JavaBean接受HTTP参数
@RequsetBody接受JSON
curl命令在linux、Mac系统里都是内置的,Windows系统 则需要自己下载安装。
MultipartFile
通过 MultipartFile 来处理文件上传:
@ModelAttribute
注解 ModelAttribute 通常作用在 Controller 的某个方法上,此方法会首先被调用,井将方法
结果作为 Model 的属性 , 然后再调用对应的 Controller 处理方法。

package com.bee.sample.ch3.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.bee.sample.ch3.controller.form.OrderPostForm;
import com.bee.sample.ch3.service.UserService;

@Controller
@RequestMapping("/modelattribute")
public class ModelAttributeController {
	@Autowired UserService userService;
	/**
	 * Controller方法中的公共放啊,调用方法前先调用此方法。
	 * @param id
	 * @param model
	 */
	@ModelAttribute
	public void findUserById(@PathVariable Long id,Model  model) {
		model.addAttribute("user", userService.getUserById(id));
	}
	
	@GetMapping(path = "/{id}/get.json")
	@ResponseBody
	public String getUser(Model model) {
		System.out.println(model.containsAttribute("user"));
		return "success";
	}
}	

@InitBinder

3.5 验证框架

Spring Boot 支持 JSR-303 、 Bean 验证框架 , 默认实现用的是 Hibernate validator。在 Spring
MVC 中,只需要使用@Valid 注解标注在方法参数上, Spring Boot 即可对参数对象进行校验 ,
校验结果放在 BindingResult 对象中。
JSR-303
MVC中使用@Validated
在 Controller 中 ,只需要给方法参数加上@Validated 即可触发一次校验 。
自定义校验

3.6 WebMvcConfigurer

WebMvcConfigurer 是用来全局定制 化 Spring Boot 的 MVC 特性。开发者通过实现WebMvcConfigurer 接口来配置应用的 MVC 全局特性。
拦截器
通过 addlnterceptors 方法可以设置多个拦截器,比如对特定的 URI 设定拦截器以检查用户是否登录,打印处理用户请求耗费的时间等。
跨域访问
出于安全的考虑,浏览器会禁止 AJAX 访问不同域的地址 。 W3C 的 CORS 规范( Cross-origin
resource sharing )允许实现跨域访问,并被现在大多数浏览器支持,包括:
Spring Boot 提供了对 CORS 的支持,可 以实现 addCorsMappings 接口来添加特定的配置 :
格式化
将 HTTP 请求映射到 Controller 方法的参数上后 , Spring 会自动进行类型转化。对于日 期类
型的参数, Spring 默认并没有配置如何将字符串转为日期类型。为了支持可按照指定格式转为
日期类型,需要添加一个 DateFormatter 类 :

public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new DateFormatter (”yyyy- MM-dd HH:mm:ss ”)); 
}

DateFormatter 类实现将字符串转为日期类型 java. util.Data 。
注册Controller
应用有时候没有必要为一个 URL 指定一个 Contro ller 方法,可以直接将 URI 请求转到对模
板的渲染上 。 比如应用中的如下代码:

视图技术

Spring Boot 支持多种视图技术,内置支持如下:
• FreeMarker:
• Groovy:
• Thyneleaf:
• Mustache 。
本章将简要介绍如何在 Spring 中使用模板技术,并会在第 4 章重点介绍笔者开发的 Beet!
模板引擎 。
使用FreeMarker

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>

使用Beetl

使用Jackson
在 MVC 框架中,Spring Boot 内置了 Jackson 来完成 JSON 的序列化和反序列化 。在 Controller
中,方法注解为@ResponseBody,自动将方法返回的对象序列化成 JSON 。
Redirect和Forward
通常而言 , Controller 都会返回一个视图名称 , 比如以 btl 结尾的视图会交给 Beetl模板引擎
渲染。有些情况下 , Controller 会返回客户端一个 HTTP Redirect 重定向请求,希望客户端按照
指定地址重新发起一次请求 ,比如客户登录成功后 , 重定向到后台系统首页 。 再比如客户端通
过 POST 提交了一个名单 , 可 以返回 一个重定向请求到此订单明细的请求地址。这样做的好处
是 , 如果用户再次刷新页面, 则访 问的是订单详情地址,而不会再次提交订单 。
Controller 中 重定向可 以 返回 以 “redirect: ”为前缀的 URI:
Spring MVC 也支持 foward前缀,用来在 Controller 执行完毕后,再执行另外一个 Controller
的方法。

3.8 通用错误处理

在 Spring Boot 中,Controller 中抛出的异常默认交给了/error 来处理,应用程序可以将/error 映射
到一个特定的 Controller 中处理来代替 Spring Boot 的默认实现, 应用可以继承 AbstractErrorController
来统一处理系统的各种异常。

3.9 @Service和@Transactional

到目前为止 , Spring Boot 的 Controller 介绍完毕 , 在 Spring Boot 中 , Controller 调用业务逻
辑处理交给了被@Service 注解的类,这也是个普通的 JavaBean,Controller 中可以自动注入这
种 Bean,并调用其方法完成主要的业务逻辑。正如 Controller 注解经常和@RequestMapping 搭
配使用一样,@Service 和@Transactional 配合使用 。
声明一个Service类
在 Spring Boot 应用中 , 业务逻辑集中在 Service 中处理 , 井自动注入到 Controller 中处理。
实现一个 Service 类,需要定义一个业务的接口,比如根据 id 查询用户及更新用户状态 :

package com.bee.sample.ch3.service;

import java.util.List;

import com.bee.sample.ch3.entity.User;

public interface UserService {
	public List<User> allUser();
	public User getUserById(Long id);
	public void updateUser(Long id,Integer type);
}

然后实现此业务接口 ,不要忘记增加@Service 来引起 Spring Boot 的“注意”,同时搭配上
@Transactional, Spring Boot 会对这样的 Bean 进行事务增强。

package com.bee.sample.ch3.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.bee.sample.ch3.entity.User;
import com.bee.sample.ch3.service.UserService;

@Service
public class UserServiceImpl implements UserService {

	public List<User> allUser() {
		return sampleUser(5);
	}
	
	

	public User getUserById(Long id) {
		User user = sampleUser(1).get(0);
		user.setId(id);
		return user;
	}

	
	private List<User> sampleUser(int num){
		List<User> list = new ArrayList<User>(num);
		for(int i=0;i<num;i++){
			User user = new User();
			user.setId((long)i);
			user.setName("mame"+i);
			list.add(user);
		}
		return list;
	}


	public void updateUser(Long id, Integer type) {
		// TODO Auto-generated method stub
		
	}
}

尽管 Spring Boot 不要求 Service 必须实现某个接口,但笔者建议还是为 Service 定义接
口,这样可以允许为这个 Service 提供不同的实现 , 比如模拟业务实现 , 单元测试中通
过Mock 来模拟一个 Service 实现 。
事务管理
Spring 简单地实现了事务管理 ,通过在 Service 类中使用@Transanal 来让Service参与事务管理。为了使用事务 , 需要在 pom 中添加 以下依赖:

spring-boot-starter-jdbc

@Transactional 可以作用在类上,这样,所有的接口方法都会参与事务管理。也可以放到
方法上,上述的 update 方法可以使用@Transactional 来声明调用该方法会处于事务上下文中。
当 Controller调用 Service 方法的时候,会开启 一个事务上下文,随后的调用都将处于这个事务上下文中。如果调用这个 Service 方法抛出 RuntimeException , 事务会自动回滚。否则,事务将提交。

3.10 curl命令

如果你的开发环境是 Mac或者 Linux , 会自带 curl;如果是 Windows 系统, 需要从https://curl.haxx.se/下载 window 版本;如果你安装了 git shell ,也自带了 curl 。

Ch rome 插件 Postman 能可视化地完成像 curl 这样的工作,如果不喜欢 curl 命令行方式,
推荐使用 Postman 。

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值