SpringMVC的基础知识

SpringMVC的简介

MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

M:Model,模型层 ,指工程中的JavaBean,作用是处理数据

JavaBean分为两类:

一类称为实体类Bean:专门存储业务数据的,如 Student、User 等

一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

V:View,视图层 ,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

MVC的工作流程: 用户通过视图层 发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器

SpringMVC入门案例

HelloWorld实现对首页的访问

Controller

java 复制代码
// @RequestMapping注解:处理请求和控制器方法之间的映射关系
// @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径
// localhost:8080/springMVC/
@RequestMapping("/")
public String index() {
//设置视图名称
return "index";
}

通过超链接跳转到指定页面

java 复制代码
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<a th:href="@{/hello}">HelloWorld</a><br/>
</body>
</html>

在请求控制器中创建处理请求的方法

java 复制代码
@RequestMapping("/hello")
public String HelloWorld() {
return "target";
}

浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器

DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称 ,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面

SpringMVC获取请求参数

SpringMVC获取从客户端发送到服务器的HTTP请求的相关参数
通过ServletAPI获取

将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象

示例

java 复制代码
@RequestMapping("/testParam")
public String testParam(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}

对应前端

java 复制代码
<html>
<head>
    <title>Test Form</title>
</head>
<body>
    <form action="/testParam" method="post">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username"><br><br>
        <label for="password">Password:</label>
        <input type="password" id="password" name="password"><br><br>
        <input type="submit" value="Submit">
    </form>
</body>
</html>

通过控制器方法的形参获取请求参数

在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参

java 复制代码
@RequestMapping("/testParam")
public String testParam(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "success";
}

@RequestParam

java 复制代码
@RequestParam是将请求参数和控制器方法的形参创建映射关系
@RequestParam注解一共有三个属性:
value:指定为形参赋值的请求参数的参数名
required:设置是否必须传输此请求参数,默认值为true
若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter 'xxx' is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null
defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值
为""时,则使用默认值为形参赋值

@RequestHeader

@RequestHeader是将请求头信息和控制器方法的形参创建映射关系

@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
@CookieValue

@CookieValue是将cookie数据和控制器方法的形参创建映射关系

@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
通过POJO获取请求参数

可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值

java 复制代码
<form th:action="@{/testpojo}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
性别:<input type="radio" name="sex" value="男">男<input type="radio"
name="sex" value="女">女<br>
年龄:<input type="text" name="age"><br>
邮箱:<input type="text" name="email"><br>
<input type="submit">
</form>
java 复制代码
@RequestMapping("/testpojo")
public String testPOJO(User user){
System.out.println(user);
return "success";
}

@RequestMapping注解的params属性

@RequestMapping注解的params属性通过请求的请求参数匹配请求映射

java 复制代码
@RequestMapping(
value = {"/testRequestMapping", "/test"}
,method = {RequestMethod.GET, RequestMethod.POST}
,params = {"username","password!=123456"}
)
public String testRequestMapping(){
return "success";
}

注:若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面回报错400:Parameter conditions "username, password!=123456" not met for actual request parameters: username={admin}, password={123456}
SpringMVC支持路径中的占位符

SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参

java 复制代码
@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id, @PathVariable("username")String username){
	System.out.println("id:"+id+",username:"+username);
	return "success";
}

使用ModelAndView向request域对象共享数据

java 复制代码
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
	/**
	* ModelAndView有Model和View的功能
	* Model主要用于向请求域共享数据
	* View主要用于设置视图,实现页面跳转
	*/
	ModelAndView mav = new ModelAndView();
	//向请求域共享数据
	mav.addObject("testScope", "hello,ModelAndView");
	//设置视图,实现页面跳转
	mav.setViewName("success");
	return mav;
}

使用Model向request域对象共享数据

java 复制代码
@RequestMapping("/testModel")
public String testModel(Model model){
	model.addAttribute("testScope", "hello,Model");
	return "success";
}

使用map向request域对象共享数据

java 复制代码
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
	map.put("testScope", "hello,Map");
	return "success";
}

使用ModelMap向request域对象共享数据

java 复制代码
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
	modelMap.addAttribute("testScope", "hello,ModelMap");
	return "success";
}

Model、ModelMap、Map的关系

Model、ModelMap、Map类型的参数其实本质上都是BindingAwareModelMap 类型的

转发视图

当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部

分作为最终路径通过转发的方式实现跳转

java 复制代码
@RequestMapping("/testForward")
public String testForward(){
	return "forward:/testHello";
}

重定向视图

SpringMVC中默认的重定向视图是RedirectView 当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转

java 复制代码
@RequestMapping("/testRedirect")
public String testRedirect(){
	return "redirect:/testHello";
}

SpringMVC处理ajax请求

@RequestBody

@RequestBody可以获取请求体信息,使用@RequestBody注解标识控制器方法的形参,当前请求的请

求体就会为当前注解所标识的形参赋值

@RequestBody获取json格式的请求参数

在使用了axios发送ajax请求之后,浏览器发送到服务器的请求参数有两种格式:

1、name=value&name=value...,此时的请求参数可以通过request.getParameter()获取,对应SpringMVC中,可以直接通过控制器方法的形参获取此类请求参数

2、{key:value,key:value,...},此时无法通过request.getParameter()获取,之前我们使用操作json的相关jar包gson或jackson处理此类请求参数,可以将其转换为指定的实体类对象或map集合。在SpringMVC中,直接使用@RequestBody注解标识控制器方法的形参即可将此类请求参数转换为java对象

java 复制代码
<input type="button" value="测试@RequestBody获取json格式的请求参数"
@click="testRequestBody()"><br>
<script type="text/javascript" th:src="@{/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/js/axios.min.js}"></script>
<script type="text/javascript">
var vue = new Vue({
	el:"#app",
	methods:{
	testRequestBody(){
	axios.post(
	"/SpringMVC/test/RequestBody/json",
	{username:"admin",password:"123456"}
	).then(response=>{
	console.log(response.data);
	});
}
}
});
</script>
java 复制代码
@RequestMapping("/test/RequestBody/json")
public void testRequestBody(@RequestBody Map<String, Object> map,
	HttpServletResponse response) throws IOException {
	System.out.println(map);
	//{username=admin, password=123456}
	//response.getWriter()获取了响应的PrintWriter对象,然后使用print方法发送字符串。这将是发送回客户端的数据。
	response.getWriter().print("hello,axios");
}

HttpServletResponse response:这个参数允许方法与HTTP响应交互,例如发送数据回客户端。
@ResponseBody

@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器

java 复制代码
@RequestMapping("/testResponseBody")
public String testResponseBody(){
	//此时会跳转到逻辑视图success所对应的页面
	return "success";
}
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
	//此时响应浏览器数据success
	return "success";
}

@ResponseBody响应浏览器json数据

java 复制代码
<input type="button" value="测试@ResponseBody响应浏览器json格式的数据"
@click="testResponseBody()"><br>
<script type="text/javascript" th:src="@{/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/js/axios.min.js}"></script>
<script type="text/javascript">
	var vue = new Vue({
	el:"#app",
	methods:{
	testResponseBody(){
	axios.post("/SpringMVC/test/ResponseBody/json").then(response=>{
	console.log(response.data);
		});
	}
	}
	});
</script>
java 复制代码
//响应浏览器list集合
@RequestMapping("/test/ResponseBody/json")
@ResponseBody
public List<User> testResponseBody(){
	User user1 = new User(1001,"admin1","123456",23,"男");
	User user2 = new User(1002,"admin2","123456",23,"男");
	User user3 = new User(1003,"admin3","123456",23,"男");
	List<User> list = Arrays.asList(user1, user2, user3);
	return list;
}
//响应浏览器map集合
@RequestMapping("/test/ResponseBody/json")
@ResponseBody
public Map<String, Object> testResponseBody(){
	User user1 = new User(1001,"admin1","123456",23,"男");
	User user2 = new User(1002,"admin2","123456",23,"男");
	User user3 = new User(1003,"admin3","123456",23,"男");
	Map<String, Object> map = new HashMap<>();
	map.put("1001", user1);
	map.put("1002", user2);
	map.put("1003", user3);
	return map;
}
//响应浏览器实体类对象
@RequestMapping("/test/ResponseBody/json")
@ResponseBody
public User testResponseBody(){
	return user;
}

拦截器

SpringMVC中的拦截器用于拦截控制器方法的执行

SpringMVC中的拦截器需要实现HandlerInterceptor

SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:
拦截器的三个抽象方法

SpringMVC中的拦截器有三个抽象方法:
preHandle :控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
postHandle :控制器方法执行之后执行postHandle()
afterCompletion :处理完视图和模型数据,渲染视图完毕之后执行afterCompletion()
多个拦截器的执行顺序

①若每个拦截器的preHandle()都返回true此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行

②若某个拦截器的preHandle()返回了false

preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterCompletion()会执行

异常处理器

SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver

HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
基于注解的异常处理

java 复制代码
@ControllerAdvice
public class ExceptionController {
//@ExceptionHandler用于设置所标识方法处理的异常
	@ExceptionHandler(ArithmeticException.class)
//ex表示当前请求处理中出现的异常对象
	public String handleArithmeticException(Exception ex, Model model){
	model.addAttribute("ex", ex);
	return "error";
	}
}

注解配置SpringMVC

使用配置类和注解代替web.xml和SpringMVC配置文件的功能
创建SpringConfig配置类,代替spring的配置文件

java 复制代码
@Configuration
public class SpringConfig {
//ssm整合之后,spring的配置信息写在此类中
}

创建WebConfig配置类,代替SpringMVC的配置文件

java 复制代码
@Configuration
//扫描组件
@ComponentScan("com.atguigu.mvc.controller")
//开启MVC注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
//使用默认的servlet处理静态资源
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer
configurer) {
	configurer.enable();
}
//配置文件上传解析器
@Bean
public CommonsMultipartResolver multipartResolver(){
	return new CommonsMultipartResolver();
}
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
	FirstInterceptor firstInterceptor = new FirstInterceptor();
	registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
}

SpringMVC执行流程

  • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
  • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供作用:根据请求的url、method等信息查找Handler,即控制器方法
  • Handler:处理器,需要工程师开发
    作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
  • HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供
    作用:通过HandlerAdapter对处理器(控制器方法)进行执行
  • ViewResolver:视图解析器,不需要工程师开发,由框架提供
    作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、 RedirectView
  • View:视图 作用:将模型数据通过页面展示给用户

SpringMVC的执行流程

  1. 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。
  2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:
    a) 不存在
    i. 再判断是否配置了mvc:default-servlet-handler
    ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误
    b) 存在则执行下面的流程
  3. 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及
    Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。
  4. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
  5. 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(...)方法【正向】
  6. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。
    在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
    a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定
    的响应信息
    b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
    c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
    d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
  7. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。
  8. 此时将开始执行拦截器的postHandle(...)方法【逆向】。
  9. 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行
    HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model
    和View,来渲染视图。
  10. 渲染视图完毕执行拦截器的afterCompletion(...)方法【逆向】。
  11. 将渲染结果返回给客户端。
相关推荐
P.H. Infinity38 分钟前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天41 分钟前
java的threadlocal为何内存泄漏
java
caridle1 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋31 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花1 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端1 小时前
第六章 7.0 LinkList
java·开发语言·网络
Wx-bishekaifayuan1 小时前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
全栈开发圈1 小时前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫