目录
一、SpringMVC 简介
1、什么是 MVC
2、什么是 SpringMVC
3、SpringMVC 实现原理
4、SpringMVC 的特点
二、简单案例
1、引入依赖
2、在 web.xml 中配置前端控制器 DispatcherServlet
3、创建 SpringMVC 的配置文件
4、创建请求控制器
5、测试页面
6、访问不到 Controller
7、修改项目结构
三、@RequestMapping
1、@RequestMapping 注解的功能
2、@RequestMapping 注解的位置
3、@RequestMapping 的 value 属性
4、@RequestMapping 的 method 属性
5、SpringMVC 支持 ant 风格的路径
6、@RequestMapping 中的占位符(重点)
四、SpringMVC 获取请求参数
1、通过 ServletAPI 获取
2、通过设置方法形参名与请求参数名一致
3、通过 POJO 获取请求参数
4、解决中文乱码
记住一句话:SpringMVC 封装了 Servlet。
(1)MVC
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
(2)工作流程
用户通过视图层发送请求到服务器,在服务器中请求被 Controller 接收,Controller 调用相应的 Model 层处理请求,处理完毕将结果返回到 Controller,Controller 再根据请求处理的结果找到相应的 View 视图,渲染数据后最终响应给浏览器。
(1)三层架构
我们通过浏览器访问前端页面,前端页面通过异步提交的方式,发送请求到后端服务器,后端服务器采用 web层(servlet)、业务层(service)、数据层(dao)的三层架构形式进行开发,其中数据的交互使用 json 来传输。
(2)SpringMVC 是一种基于 Java 实现 MVC 模型的轻量级 Web 框架
(1)用户发送请求到前端控制器 DispatcherServlet
(2)DispatcherServlet 收到请求后调用处理器映射器 HandlerMapping
(3)DispatcherServlet 调用处理器适配器 HandlerAdapter
(3-1)HandlerAdapter 经过适配调用具体的 Controller 的方法;(Controller--> service --> Dao --> 数据库)
(3-2)HandlerAdapter 将 Controller 执行的结果 ModelAndView 返回给 DispatcherServlet
(4)DispatcherServlet 将执行的结果 ModelAndView 传给视图解析器 ViewReslover
(5)DispatcherServlet 根据 Model 对 View 进行渲染(将模型数据填充至视图中)
即将使用 Thymeleaf 视图模板技术,因此引入了相关依赖。
javax.servlet
javax.servlet-api
3.1.0
provided
org.springframework
spring-webmvc
5.3.1
org.thymeleaf
thymeleaf-spring5
3.0.12.RELEASE
DispatcherServlet
org.springframework.web.servlet.DispatcherServlet
DispatcherServlet
/
(1)标签中使用 / 和 /* 的区别
JSP 是通过 Tomcat 的 JspServlet 来处理的,然后 JspServlet 将响应结果回传给页面,所以 DispatcherServlet 处理不了 jsp 页面。
(1)SpringMVC 的配置文件的默认地址和名称:
但实际开发中,通常将 SpringMVC 的配置文件放在 resource 目录下。
(2)Thymeleaf 模板文件路径
我们通常在 WEB-INF 目录下建立一个 templates 目录,用来存放视图模板。而访问 WEB-INF 目录下的资源,需要服务器端进行请求转发,所以逻辑视图就被用上了。
(3)配置文件
(1)@Controller
由于 DispatcherServlet 已经对浏览器发送的请求进行了统一的处理,所以我们不需要自己创建 Servlet 去处理请求。
但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器。
package com.demo.controller;
import org.springframework.stereotype.Controller;
@Controller
public class HelloController {
}
SpringMVC 的控制器由一个 POJO(普通的Java类)担任,因此需要通过 @Controller 注解将其标识为一个控制层组件,交给 Spring 的 IOC 容器管理,此时 SpringMVC 才能够识别控制器的存在。
(2)@RequestMapping
请求映射:把浏览器发送的请求,映射到具体方法去处理。
(2-1)其中的 value 属性值,填写的是方法的路径:
当 value 的值,与浏览器发送的请求路径是一样的,说明这个方法就是用来处理该请求的方法。
(2-2)方法返回值
前面我们说到,服务器端进行请求转发需要用到逻辑视图,那么怎么用呢?
其实我们返回的字符串,就是所谓的逻辑视图。紧接着 web.xml 中配置的视图解析器,就会将这个返回值用视图前缀和视图后缀组装起来,最终形成了请求转发的地址。
package com.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/")
public String index() {
System.out.println("index");
// 返回逻辑视图
return "index";
}
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
注意:测试页面使用了 Thymeleaf 的语法。
(1)index.html
Title
index 页面
测试 SpringMVC
测试绝对路径
(2)hello.html
Title
hello
(3)项目结构
SpringMVC 访问不到 Controller,网上有很多解决方法,如果再尝试之后都没有办法解决(比如我),那么可以尝试删除当前工件,新建一个该项目的工件。
有关更多项目结构问题,可以查看:https://www.bilibili.com/video/BV1Ry4y1574R?p=15
按照其中的步骤,设置 web 目录即可。
将 DispatcherServlet-servlet.xml 文件,放到 resource 目录下,然后在 web.xml 文件中作如下修改:
DispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:SpringMVC.xml
1
DispatcherServlet
/
(1)contextConfigLocation
这是正常项目中 Spring 配置文件放置在 resource 目录下的写法。
(2)
由于 DispatcherServlet 需要初始化的内容非常地多,因此将其放在服务器启动期间去初始化,可以节省页面访问的时间。
如下面代码所示:
@Controller
@RequestMapping("/manager")
public class ManagerController {
@RequestMapping("/user")
public String user() {
return "user";
}
}
请求路径为:
http://ip:port/工程路径/manager/user
一个 Servlet 可以处理多个请求(在 url-pattern 中设置),同样的,value 属性值为数组的时候,就可以接收多个请求。
@Controller
@RequestMapping("/manager")
public class ManagerController {
@RequestMapping({"/hello", "/also_hello"})
public String hello() {
return "hello";
}
}
若当前请求的请求地址满足请求映射的 value 属性,但是请求方式不满足 method 属性,则浏览器报错 405。
@RequestMapping(
value = {"/hello"},
method = {RequestMethod.GET, RequestMethod.POST}
)
public String hello() {
return "hello";
}
(1)对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解
(2)常用的请求方式有get,post,put,delete
ant 风格的路径是指:
在 @RequestMapping 中,value 属性值可以包含上面三种格式。
@RequestMapping("/a?a/test/ant")
public String testAnt() {
return "hello";
}
@RequestMapping("/a?a/*/ant")
public String testAnt2() {
return "hello";
}
@RequestMapping("**ant")
public String testAnt3() {
return "hello";
}
以上代码,下面三种请求路径都能访问到 hello.html:
@RequestMapping 修饰的方法想要使用请求参数的方法有很多,其中一种就是在 @RequestMapping 的 value 属性中使用“占位符{ }”。
(1)书写格式
假设请求路径 /func 可以访问到目标方法,通常我们添加参数,请求路径会这么写:
/func?id=1&name=admin
而如果使用 @RequestMapping,那么应该这么写:
/func/1/admin
(2)对应地,在代码中要怎么获取到这两个参数呢?
@RequestMapping("/func/{id}/{name}")
public String func(@PathVariable("id") String id, @PathVariable("name") String name) {
System.out.println("id: " + id);
System.out.println("name: " + name);
return "index";
}
(3)请求路径:
(4)输出结果:
如果要使用 servlet 相关的方法,那么给方法的参数列表添加 request 等参数即可。
(1)测试代码
(1-1)controller(success.html 可以自己写)
@RequestMapping("/login")
public String login(HttpServletRequest req) {
System.out.println("username: " + req.getParameter("username"));
System.out.println("password: " + req.getParameter("password"));
return "success"; // return 相当于请求转发
}
(1-2)index.html
(2)输出结果
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参。
(1)测试代码
(1-1)controller
@RequestMapping("/login/param")
public String loginParam(String username, String password) {
System.out.println("username: " + username);
System.out.println("password: " + password);
return "success";
}
(1-2)index.html(改了 action)
(2)输出结果
(3)@RequestParam
为了保证一定能获取到对应值,可以使用 @RequestParam:
public String loginParam(@RequestParam(value = "username", required = true) String username, String password)
(4)@RequestHeader
用法与 @RequestParam 一致。
@RequestMapping("/login/param")
public String loginParam(@RequestParam(value = "username") String name,
String password,
@RequestHeader(value = "referer") String refer) {
System.out.println("username: " + name);
System.out.println("password: " + password);
System.out.println("referer: " + refer);
return "success";
}
(5)@CookieValue
用法与 @RequestParam 一致。
@RequestMapping("/login")
public String login(HttpServletRequest req) {
HttpSession session = req.getSession();
System.out.println("创建 JSESSIONID: " + session.getId());
return "index"; // return 相当于请求转发
}
@RequestMapping("/login/param")
public String loginParam(@RequestParam(value = "username") String name,
String password,
@RequestHeader(value = "referer") String refer,
@CookieValue(value = "JSESSIONID") String sessionId) {
System.out.println("username: " + name);
System.out.println("password: " + password);
System.out.println("referer: " + refer);
System.out.println("JSESSIONID: " + sessionId);
return "success";
}
(5-1)先访问 /login,使服务器创建 JSESSIONID
(5-2)输入 username、password,点击登录,观察控制台输出
通常情况下,我们会有非常多的方法参数需要设置/获取请求参数值,如果都用 @RequestParam 这几个注解来获取,也非常麻烦。
(1)解决方法
@RequestMapping("/login/pojo")
public String pojo(User user) {
System.out.println(user);
return "success";
}
(2) 输出结果
因为没有 request 和 response,所以无法用这两个变量设置。
并且就算使用 request 和 response,其实也无法设置,因为其他参数都是已经从请求中获取到了,再设置也没有用了。
注意:
(1)解决方法
解决获取请求参数的乱码问题,可以使用 SpringMVC 提供的编码过滤器 CharacterEncodingFilter,再所有 servlet 处理之前,拦截所有请求,然后设置编码。
需要注意的是,CharacterEncodingFilter 必须在 web.xml 中进行注册:
(2)web.xml 配置文件
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceResponseEncoding
true
CharacterEncodingFilter
/*
(3)输出结果