Spring MVC
一、Spring MVC概述
1.1 Spring MVC 简介
- MVC是一种常见的用户界面设计模式(设计套路),其实现方案有很多:Struts2、SpringMVC等等。MVC=Model(数据模型)+View(视图)+Controller(控制器),SpringMVC框架主要解决了VC之间的交互问题,在SpringMVC框架中,并不关心M的问题。
1.2 SpringMVC核心组件和执行流程
-
核心组件
(1)DispatcherServlet:前端控制器,用于接收所有请求。
(2)HandlerMapping:用于配置请求路径与Controller组件的对应关系。
(3)Controller:控制器,具体处理请求的组件。
(4)ModelAndView:Controller组件处理完请求后得到的结果,由数据与视图名称组件。
(5)ViewResolver:视图解析器,可根据视图名称确定需要使用的视图组件。
-
执行流程图
1.3 搭建SpringMVC项目
-
使用SpringMVC强大功能的第一步就是创建SpringMVC项目,SpringMVC项目就是一个标准的Java EE Web项目,在JavaEE项目中配置Spring MVC。
(1)新建Maven Project,并且选择webapp原型,然后next
(2)这里的GroupId和ArtifactID随意填写,但是ArtifactID最好和你的项目一名一致,然后next
(3)这里我们添加一个参数archetypeCatalog=internal,可以帮助我们快速搭建骨架,然后点击Finish
(4)在pom.xml文件中添加SpringMVC和Servlet的依赖
(5)将项目部署到Tomcat服务器上(这里就不做演示了)
(6)创建SpringMVC配置类
(7)启动Tomcat,启动成功之后检索信息,如果检索到下面两行信息表示配置成功06-Nov-2020 22:40:50.383 信息 [RMI TCP Connection(3)-127.0.0.1] org.springframework.web.servlet.FrameworkServlet.initServletBean Initializing Servlet 'dispatcher' 06-Nov-2020 22:40:50.959 信息 [RMI TCP Connection(3)-127.0.0.1] org.springframework.web.servlet.FrameworkServlet.initServletBean Completed initialization in 576 ms
1.4SpringMVC初体验
-
编写配置类SpringMvcConfig,开启组件扫描功能,目的是扫码创建控制器对象
package com.yuanle.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.yuanle.controller") public class SpringMvcConfig { }
-
在WebApp类中注册SpringMvcConfig,目的是启动SpringMvc时候加载SpringMvcConfig类并将请求映射交给DispatcherServlet处理
package com.yuanle.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class WebApp extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[0]; } @Override protected Class<?>[] getServletConfigClasses() { //注册配置类SpringMvcConfig return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { //将*.do请求交给DispatcherServlet处理 return new String[]{"*.do"}; } }
-
编写控制器类,再累上标注@RestController,这样组件扫描功能扫描到@RestController就会创建对象,@GetMapping(“/hello.do”)注解可以将用户的get请求映射到demo()方法,这样在浏览器请求时就会执行该方法,而demo()方法的结果会返回显示在浏览器上。
package com.yuanle.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @Controller public class DemoController { @GetMapping("/hello.do") public String demo(){ System.out.println("demo()"); return "HelloWorld!"; } }
二、视图View
视图就是给用户呈现数据的界面。在SpringMVC中,响应给客户端的View可以是多种,例如JSP、Thymeleaf中的HTML模板页面等。
2.1 Thymeleaf 视图解析器
-
Thymeleaf是Spring MVC推荐的试图模板,其最大的优势是所见即所得。其官方网站是:https://www.thymeleaf.org/。
-
使用Thymeleaf的步骤:
(1)首先导入thymeleaf和thymeleaf整合Spring5的坐标
<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.0.11.RELEASE</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.11.RELEASE</version> </dependency>
(2)将Thymeleaf模板引擎当做Bean组件配置到Spring的配置文件中
@Bean public ThymeleafViewResolver viewResolver(){ //配置ClassLoaderTemplateResolver去/templates/文件夹中读取*.html的模板 ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver(); templateResolver.setPrefix("/templates/"); templateResolver.setSuffix(".html"); templateResolver.setCharacterEncoding("UTF-8"); templateResolver.setTemplateMode(TemplateMode.HTML); templateResolver.setCacheable(true); //创建模板引擎 SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); templateEngine.setEnableSpringELCompiler(true); //创建模板解析器 ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine); viewResolver.setCharacterEncoding("UTF-8"); return viewResolver; }
(3)配置的时候,模板存储有两种常见的方式:
a. 使用ClassLoaderTemplateResolver时候,模板存储位置在src/main.resources/下
b. 使用ServletContextTemplateResolver时候,模板存储位置在/webapp/WEB-INF/下
2.2 将视图显示到浏览器
-
SpringMVC控制器方法可以返回ModelAndView对象,当前端控制器收到控制器返回的ModelAndView对象,前端控制器会利用视图解析器查找视图模板,并且进一步解析视图模板为html页面然后响应给浏览器。
-
实现步骤:
(1)在DemoController中声明控制器方法
@GetMapping("/test.do") public ModelAndView test(){ System.out.println("test()"); return new ModelAndView("helloworld"); }
(2)在templates文件夹下新建一个模板页面,然后打开浏览器访问即可。
三、接收客户端提交的请求参数
3.1 使用控制器方法参数接收表单数据
-
SpringMVC提供了很多封装好的功能,这样可以大大简化编程,其中就包括自动解析接收表单参数。SpringMVC对接收表单数据做了封装,只需要在输入元素的name属性与控制器方法参数名字对应上,SpringMVC就会将数据注入到方法中。
-
处理表单中的中文数据
(1)我们自己的程序是UTF-8,但浏览器传送到服务器的编码是ISO8859-1不支持中文,所以服务器接收表单参数时会乱码。
(2)解决办法:SpringMVC提供了一个编码过滤器,CharacterEncodingFilter,只需要在SpringMVC的配置类中添加上,就可以自动的设置接收时的编码,解决中文编码问题。
3.2 使用JavaBean作为参数接收表单数据
-
SpringMVC提供利用JavaBean打包传递参数功能,这样可以简化控制器参数。
-
注意:
各属性的名称需要与请求参数的名称保持一致,并且,每个属性都要有规范名称的SET/GET方法。
3.3 使用request对象接收数据
- 控制器可以注入request对象,这样就可以获取任何请求参数包含请求头信息,ip等信息,由于request包含getPramater方法,也可以获取请求表示数据。
3.4 特殊参数名处理
- 当参数名与Java关键字冲突的时候,就无法利用默认规则接收参数了,例如:String while需要写成@RequestParam(“while”)String whiles,就可以解决参数名冲突的问题。
四、控制器向页面传递数据
控制器负责处理业务规则,为业务规则处理结束以后需要将处理结果反馈给客户。
4.1 利用request向View传递数据
- 在Servlet中,可以利用request对象的Attribute向页面模板传递数据,在SpringMVC中同样有效。只要在控制器中将需要传递当数据存储到request中,就可以在视图模板中利用表达式显示出来。
4.2 利用ModelAndView向View传递数据
- 上述案例中request对象可以将数据传递到View中。但是在控制器中注入HttpServletRequest类行对象,会造成控制器强依赖于HttpServletRequest API,不能脱离Servlet容器进行测试。
- SpringMVC提供了替代解决方案:ModelAndView,ModelAndView不仅可以封装视图(View)名称,更能封装向视图传递的数据(Model)。其中Model是一个Map类型的数据结构。
4.3 利用ModelMap向View传递数据
- 在控制器方法中添加ModelMap类型的参数,SpringMVC会将传递参数的model对象创建好,注入到控制器,在控制器中将需要传递到数据存储的model中即可。
五、转发、重定向和Session
5.1 什么是转发
- 转发是服务器内部的控制器和视图协作完成同一项任务处理的过程,例如登陆业务中,控制器处理登陆业务过程,处理结束以后将结果发送到视图,这就是转发。
- 使用转发的目的是将控制器处理的结果送给视图去显示,转发是一个请求处理过程两个连续接力处理步骤。
5.2 什么是重定向
-
重定向是Http协议提供的功能,在客户端请求服务器,服务器在响应中反馈状态码“302”,并且提供目标的URL地址,浏览器收到302和URL地址以后,立即向新的URL发起请求,这个重定向的本质是浏览器根据第一次请求结果向新的URL发起第二次请求。
-
SpringMVC对重定向进行了封装,可以很轻松的从控制器发起重定向,具体方式是在控制器中返回以redirect前缀的视图就可以了,例如:
return new ModelAndView("redirect:http://doc.canglaoshi.org");
5.3 重定向的使用
-
当控制器将业务处理完成以后,希望跳转到其它HTTP请求时候,就可以利用重定向功能。例如:一个网站登录成功之后一般都会跳转到网站首页。
(1)登录页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h1>欢迎登陆</h1> <form method="post" action="handle_login.do"> <div> <label>用户名:</label> <input type="text" name="username" /> </div> <div> <label>密码:</label> <input type="password" name="password" /> </div> <div> <input type="submit" value="登陆" /> </div> </form> </body> </html>
(2)显示错误消息页面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>显示消息</title> </head> <body> <h1>消息</h1> <p th:text="${message}"></p> </body> </html>
(3)首页
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h1>首页</h1> <p th:text="${date}"></p> </body> </html>
(4)处理登陆页面的控制器,重定向操作就在其中,在登陆成功之后重定向到首页
@PostMapping("/handle_login.do") public ModelAndView handleLogin(String username, String password, ModelMap model){ if ("王源".equals(username)){ if ("123".equals(password)){ model.put("message","登陆成功!"); return new ModelAndView("redirect:../home/index.do"); }else { model.put("message","密码错误!"); return new ModelAndView("message"); } }else { model.put("message","用户名不存在!"); return new ModelAndView("message"); } }
(5)显示首页控制器
@GetMapping("/index.do") public ModelAndView index(ModelMap model){ String date = LocalDate.now().toString(); model.put("date",date); return new ModelAndView("index"); }
5.4 转发和重定向的区别
-
请求次数上:转发是一次请求,重定向是两次请求
(1)转发是一次请求的两个环节进行协作,控制器转发到视图。
(2)重定向是两次请求,第一次请求结束告诉浏览器可以赚到另外一个请求了。
-
使用目的不同
(1)转发的目的是协作,控制器先处理业务功能,然后利用转发将处理结果转发到视图显示业务结果。
(2)重定向的目的是URL跳转,一个URL处理完成以后,跳转到另外一个URL。
-
作用域有差别
(1)转发是一次请求,在一次请求处理期间可以利用同一个request数据共享。
(2)重定向是两次请求,两次请求各自创建request,这时不能利用request共享数据。
5.5使用Session
- 在开发中经常需要利用Session存储共享信息,SpringMVC中对Session提供了封装,在控制器方法上定义HttpSession类型参数,SpringMVC就会把Session对象注入到控制器中,在控制器中就可以访问这个Session对象了。
六、拦截器
6.1 什么是拦截器
-
拦截器(Interceptor)是SpringMVC中的组件,可以使得若干个请求路径在被处理时,都会执行拦截器中的代码,并且,拦截器可以选择阻止程序继续向后执行,或选择放行。
-
在SpringMVC中可以自定义类,实现HandlerInteceptor拦截器接口,这个类就会是一个拦截器类,实现接口后需要重写三个方法,分别是:
(1)preHandle():利用拦截器编程的核心就在于用控制器preHandle方法的返回值,返回true表示拦截器放过请求继续处理,返回false就表示进行拦截处理,不在之心后续控制器,所以这个方法会在控制器方法执行之前执行。
(2)postHandle():当preHandle方法的返回值为true时,控制器执行完之后,postHandle方法会执行
(3)afterCompletion():会在整个框架处理流程结束之前那一刻被执行。
-
自定义类之后,SpringMVC拦截器还必须在SpringMVC的配置类中进行配置才能使用,配置步骤:
(1)将配置类实现SpringMVC提供的配置接口WebMvcConfigurer,这个配置接口中声明了包含注册拦截器的方法,并且必须在配置类上标注@EnableWebMvc
(2)重写配置接口中的addInterceptors()方法,在方法中注册拦截器对象,以及拦截位置配置拦截器
6.2 拦截器的配置
-
利用.addPathPatterns()设置拦截规则,多个参数可以设置多个拦截规则。
-
利用通配符可以拦截一组规则
(1)*表示一级目录
(2)**表示多级目录,一级和二级都可以拦截
-
利用excludePathPatterns方法可以设置排除规则,用于添加例外清单。
6.3 拦截器与过滤器的区别
- 拦截器和过滤器都可以作用于HTTP请求,并且使得这些路径的请求在被处理时,都会经过相关检查,最终决定组织或放行。
- 过滤器,也称为Servlet过滤器,过滤器是Servlet标注的一部分,可以拦截任意的HTTP请求。
(2)重写配置接口中的addInterceptors()方法,在方法中注册拦截器对象,以及拦截位置配置拦截器