一. Spring Boot 里的 Spring MVC
- Spring Boot 是什么 ?
Spring Boot 在之前的文章中有介绍过, 它是一个快速构建生产级别的 Spring 引用程序的框架, 它基于 Spring Frameword, 并通过自动配置、约点大于配置、快速开发等方式, 开发人员更快地创建出高效、可靠的 Spring 应用程序
- Spring MVC 是什么?
Spring MVC 是基于 Servlet API 构建的原始 Web 框架, 它全称叫做 Spring Web MVC 来自于其源模块的名称( spring-webmvc ), 也就是我们现在常叫做的 Spring MVC
Spring MVC 中的 MVC 全程为 Model View Controller, M-模型, V-视图, C-控制器, 也就是视图模型控制器, 它是一种软件构架模式( 它是后面出现的一种设计模式 )
所以 MVC 是一种思想, 而 Spring MVC 是对 MVC 的一种具体实现
- Spring Boot 和 Spring MVC 之前有什么关系 ?
对于这二者之间, Spring Boot 是构建在 Spring Framework 之上的, 而 Spring MVC 是 Spring Framework 中的一个模块, 因此 Spring Boot 中也包含了 Spring MVC.
具体来说便是, Spring Boot 中默认使用 Spring MVC 作为 Web 开发框架, 并通过自动配置的方式简化了 Spring MVC 的配置过程, 开发人员通过添加正确的依赖和一些简单的配置, 快速的搭建一个完整的 Web 应用程序
因此可以说 Spring Boot 是围绕 Spring MVC 和其他 Spring 模块构建的一个全新引用程序开发框架, 在提供 Spring MVC 功能的同时又提供了额外的便利功能, 使得开发可以更加高效便捷的构建 Web 应用程序
二. Spring MVC 的具体使用
1. Spring MVC 的创建
我们前面说道, Spring MVC 是 Spring 中的一个模块而已, 因此我们在用 Spring Boot 框架开发时, 只需要添加 Spring MVC 的起步依赖就好. 并且通过添加 Spring Web 依赖说明时, 就可以看到 Spring Web 其实就是 Spring MVC
2. 和浏览器建立连接
2.1 @RequestMapping 注解建立连接
通过标准分层, 在controller 包下创建一个 UserController, 并添加一个方法, 方法上添加 @RequestMapping 注解
// 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 public class UserController { @RequestMapping("/user1") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } }
启动项目后, 此时通过本地 localhost 就可以访问当前页面了.这样就和浏览器建立了连接
可以看到的是, 这里@RequestMapping 注解是 Spring Web 程序中最常用的一个注解, 它用来注册接口的路由映射的( 当用户访问一个 url 时, 将用户的请求对应到程序中某个类下的某个方法的过程就为路由映射 ).
- 而这里的 @RequestMapping 注解除了上面加在了方法上, 它也可以加载类上, 此时访问的 url 就为类上的路径 + 方法的路径
// 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 @RequestMapping("user") public class UserController { @RequestMapping("/user1") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } }
只访问方法上的路径是不对的, 必须是类路径加方法路径
- 方法上和类上也可以实现多级路由
// 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 @RequestMapping("user") public class UserController { @RequestMapping("/user1/fun") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } }
具体要如何实现, 可以根据自己的需求来实现.
- @RequestMapping 是什么类型的请求 ?
首先, 它肯定是支持 Get 请求的, 因为我们之前访问 localhost 时, 使用的就是 Get 方法. 那它支不支持其他方法呢 ?
// 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 public class UserController { @RequestMapping("/user1") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } }
- 使用 Postman 构造一个 Post 请求和 Delete 请求看看, 还能访问这个方法嘛 ?
可以看到的是, @RequestMapping 注解不指定特定路由方法下, 是支持多种路由请求的, 具体有哪些我们可以在源码中看到, 下面这些都是 @RequestMapping 注解支持的路由方法
b. 只允许 Post 请求或者 Get 请求能实现嘛 ?
// 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 public class UserController { @RequestMapping(value = "/user1", method = RequestMethod.POST) public String fun1() { return "这是 user1 路由下的 fun1 方法"; } }
在@RequestMapping 里设置 method 属性, 选择路由方法为 POST. 在去通过 Postman 构建一个 Get 请求, 看看还能发送成功嘛 ?
可以看到, 此时它报了 405, 提示方法不被允许, 因此可以看到在 @RequestMapping 注解里, 不仅可以设置多级路由, 还可以限定路由的访问方法
只能由指定的路由方法访问 ! ! !
2.2 其他注解建立连接
上面的指定路由方法建立连接, 在我们的 Spring Web 里提供了更便捷的注解进行连接, 例如只允许 Post 的路由方法
@PostMapping("/user2") public String fun() { return "这是 user2 路由下的 Post治党路由方法"; }
还是一样, 当我们去通过 Postman 进行构造一个 GET 方法访问时, 是不被允许的
只有 POST 方法才可以, 其他路由方法都不行
3. 获取参数
建立连接后, 对于我们的项目中, 最重要的就是获取 web 项目中的一些参数.
3.1 获取 url 参数
@RequestMapping("/user3") public String getParameter(String name) { return "这是获取到的参数 : " + name; }
建立路由方法, 启动项目后访问, 此时我们并没有传入参数, 因此此处为默认值 ( 需要注意, 包装类的默认值也是 null )
当我们 url 中传入参数时, 可以正确获取到参数属性
需要注意的时, 必须和方法的参数一致, 才能在 url 中获取到正确的属性值, 当参数为 user 时, 与方法中的参数对不上, 因此无法正确获取
*既然可以获取一个参数, 那么是不是也可以获取两个参数呢 ? **
@RequestMapping("/user5") public String getParameter1(String name, String password) { return "获取到的 name : " + name + " password : " + password; }
注意, 此时我在 url 中是先输入的 password 后 输入的 name 但是, 并不会影响正确获取参数, 因为此处是通过 key 和 value 去匹配的, 只需要 key 正确即可匹配对应的 value
之前我们 Servlet 是通过 request 去获取 url 的参数的, 而 Spring MVC 值基于 Servlet API 的, 因此 Servlet 的方法也是可以在这里使用的
@RequestMapping("/user4") public String getParameter1(HttpServletRequest request, HttpServletResponse response) { return "这是获取到的参数 : " + request.getParameter("name"); }
这里的 request 和 response 等同于是框架内置的, 可以直接使用, 因此这里也是可以正确获取的
3.2 获取 url 对象
Web 项目中除了获取 URL 参数外, 获取对象也是非常常见和重要的, 下面就来看如何获取一个对象
- 先构建一个实体类 userInfo
@Data public class UserInfo { private int age; private String name; private String password; }
- 构造路由方法
@RequestMapping("/reg") public Object reg(UserInfo userInfo) { return userInfo; }
- 访问路由方法观察
是不是特别简单 ? 并且, 我们前端传来的是参数, 怎么会变成了对象呢 ?** 原因就在于我们的框架帮我们做了这事, 当程序执行后, Spring MVC 会自动将我们的参数对象映射, 只需要我们传入的属性和对象拥有的属性一致, 框架会根据返回的类型, 自动帮我们匹配是返回标签 还是 JSON 对象返回**
例如 :
@RequestMapping("/html") public Object reg1() { return "<h1> 这是一个 HTML 标签</h1>"; }
在抓包确认一下, 框架自动将我们返回的 Object 对象转为需要的 HTML 形式了
3.3 参数重命名( 前端传入参数和后端参数不一致 )
3.3.1 @Value 注解
在生产中, 前后端的约定不一致时, 比如在注册中, 前端传入的是 username 而后端规定要使用的为 name, 这时候怎么办 ? 如果还用之前的方法, 那么我们将无法获取到对应的属性值, 为了解决这个问题, Spring Boot 框架提供了 @Value 注解, 将指定属性获取后赋值给指定参数, 例如下面 :
@RequestMapping("/reg1") public Object reg1(@Value("username") String name, String password) { return "name : " + name + " password : " + password; }
此时, 我们方法中的参数为 name, 但 url 中传入的为 username 但是同样正确获取了 username 的参数. 由于我们此处的重命名, 将 username 属性对应的值获取后赋值给了 name 属性
3.3.2 @RequestParam 注解
使用 @RequestParam 注解同样可以重命名参数, 但是 @RequestParam 注解还有一个别的功能, 设置参数是否为非必传参数
@RequestMapping("/reg2") public Object reg2(@RequestParam("username") String name, String password) { return "name : " + name + " password : " + password; }
同样, 使用@RequestParam 是否能够重命名呢 ? 运行后发现是可以的
那么, 刚刚说的是否为非必传参数又是怎么回事呢 ? 当我们不传入 password, 预期应该是 password
当我们尝试不传 username 属性看看, 预期是否和之前一样, 不传入那么默认为 null 呢 并且可以正确访问呢 ?
可以看到, 是无法正确访问的, 并且还给我们提示了报错信息 : username 为一个该方法的必传参数
因此, 在重命名时, 如果使用 @RequestParam 注解会带来一个必传参数的问题, 那么, 如何解决这个问题呢 ?
我们可以在 @RequestParam 里面添加 required 属性, 可以看到, 默认是 true 的代表这是一个必传参数, 当设置为 false 时, 此时这个重命名的参数就不是必传的了
@RequestMapping("/reg2") public Object reg2(@RequestParam(value = "username", required = false) String name, String password) { return "name : " + name + " password : " + password; }
此时不传入重命名后的 username 也可以正确访问了.