Spring MVC框架教程
学习的目标:
- Servlet开发步骤及问题
- SpringMVC框架入门案例
- SpringMVC的注解
- 页面数据参数传递封装给后台
- SpringMVC原理
- RestFul风格的数据传输
复习回顾
1 SpringMVC框架简介
1.Servlet非常麻烦,每一个模块都需要去创建对应的Servlet组件,在和视图层进行配合开发需要大量的配置。
2.SpringMVC前端控制器,可以和客户端进行数据的通信(请求处理、响应数据)。
2 SpringMVC开发步骤
1.导入SpringMVC的依赖:spring-webmvc依赖。
2.在web.xml配置文件中添加DispatcherServlet配置(前端控制器)。
3.编写一个控制器类:必须实现Controller接口(ModelAndView)。定义请求处理业务方法,同时可以将请求发送给目标指定的视图页面。
4.在SpringMVC核心配置文件中完成组件的配置(springmvc-servlet.xml)。配置4个组件:
- 配置控制器类:自定义的Controller。
- 配置处理器映射器类:HandlerMapping。
- 配置处理器适配器类:HandlerAdapter。
- 配置视图解析器类:ViewResolver。
5.分析了SpringMVC执行流程。
1 Spring MVC简介
1.1 Servlet开发缺点
1.每一个Servlet都需要在web.xml文件中配置,如果很多个Servlet,就会导致web.xml文件内容过于繁重。
2.Servlet具有容器的依赖性,Tomcat如果没有启动,则无法进行功能测试的。
3.Servlet处理请求局限性大。
4…
1.2 Spring MVC简介
Spring MVC是是一个前端控制器框架(负责前端的请求和响应-控制者),主要负责来和客户端进行后台数据的通信。Spring家族中非常多框架,其中SpringMVC是极为重要一个组件,可以和Spring框架完美整合在一起。
1.3 Spring MVC开发Web项目流程
应用程序分层:
分层名称 | 描述 |
---|---|
Model | 模型层。即表示业务模型,负责完成业务中数据通信处理,对应项目中service和dao层。 |
View | 视图层。渲染数据,生成页面,对应项目中的JSP、Vue… |
Controller | 控制层。直接对接请求,控制MVC执行流程,调度模型层和视图层,对应项目中Servlet、Spring MVC |
Spring MVC开发Web应用程序项目一个设计架构。
1.4 SpringMVC入门案例
1.SpringMVC的开发步骤
1.在项目中导入SpringMVC相关的依赖spring-web、spring-webmvc。
2.编写SpringMVC的控制层。
3.需要配置SpringMVC的核心配置文件: spring-servlet.xml。
4.配置url映射。
2.SpringMVC的开发实现
1.导入相关依赖。
<!-- 导入SpringMVC的webmvc模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.22</version>
</dependency>
<!-- Spring Web模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.22</version>
</dependency>
<!-- Spring框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.22</version>
</dependency>
2.配置什么请求可以提交给Spring MVC前端控制器。在web.xml文件中配置。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置Spring MVC的前端控制器:DispatcherServlet,作用是可以处理哪些请求 -->
<!-- 1.注册Servlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 表示给当前的Servlet配置初始化参数信息-->
<init-param>
<!-- contextConfigLocation: 表示给上下文配置核心文件 -->
<param-name>contextConfigLocation</param-name>
<!-- 表示核心文件的位置 -->
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
</servlet>
<!-- 2.配置Servlet映射 -->
<servlet-mapping>
<!--servlet的名称上下需保持一致-->
<servlet-name>springmvc</servlet-name>
<!-- url映射路径。"/"表示所有的请求都可以拦截到当前的Servlet中 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.编写一个HelloController类,控制器类,将来和一个url地址进行映射,当访问这个url地址会自动触发此控制器。
注意:需要使用一个接口Controller接口。
package com.qf.springmvc01introduction.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 控制器:SpringMVC框架提供了一个接口Controller,实现该接口的类,就是SpringMVC的控制器
*/
public class HelloController implements Controller {
/**
* 请求url找到对应的Controller类之后,回去执行handleRequest方法
* @param request 请求对象,打包有请求客户端过来数据
* @param response 响应对象,打包有响应客户端的数据
* @return 模型和视图,数据和展示页面
* @throws Exception 会抛出异常
*/
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
/**
* 请求:/hello请求发送给后台,响应一个数据"Spring MVC"给到前端。
*/
// 创建一个ModelAndView的对象,然后绑定数据到这个对象,绑定页面(视图)
ModelAndView modelAndView = new ModelAndView();
// 1.绑定数据到ModelAndView对象:key:value键值对形式来绑定
modelAndView.addObject("msg", "Hello Spring MVC!!!");
// 2.绑定跳转指定的页面:如何跳转到hello.jsp。可以设置视图名称,ModelAndView就知道往哪个页面跳转了
modelAndView.setViewName("hello"); // 文件名:hello.jsp, 视图名:hello
// 3.返回ModelAndView对象
return modelAndView;
}
}
4.配置spring-servlet.xml文件。
- 处理器映射器:将请求的url地址和bean对象(Controller)进行绑定。
- 处理器适配器:根据访问的请求,来调用对应的处理方法(addUser()方法)。
- 视图解析器:根据配置的文件前缀和后缀找到数据渲染的视图文件,将数据渲染在页面上。
- 注册控制器:需要由一个url地址映射一个Controller控制器,对应请求触发这个控制器。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1.注册处理器映射器:
作用:处理器映射器会根据请求的url与Spring容器中定义的bean的名称进行匹配,从而Spring容器中找到对应的bean.
说明:不需要手动定义一个id,id规则:包名.类名#数字 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 2.注册处理器:
name: 表示对应一个前端的请求,name属性的取值必须以"/"开头
class: 表示对应请求从后台处理的类是谁 -->
<bean name="/hello" class="com.qf.springmvc01introduction.controller.HelloController"></bean>
<!-- 3.配置处理器适配器:
作用:根据处理器映射器返回的Controller,执行哪一个方法 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 4.配置视图解析器:
作用:根据路径的前缀和后缀来找到匹配的jsp页面,然后执行页面数据的渲染操作 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 1.配置路径的前缀,其中prefix属性表示视图文件的前缀:/WEB-INF/目录下 -->
<property name="prefix" value="/WEB-INF/"></property>
<!-- 2.配置路径后缀:.jsp -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
1.2 SpringMVC执行流程
核心组件:
- DispatcherServlet:前端控制器
- HandlerMapping: 处理器映射器
- HandlerAdapter:处理器适配器
- ViewResolver:视图解析器
1.4 HandlerMapping
1.4.1 BeanNameUrlHandlerMapping
如果想多个url绑定在同一个Controller,需要将控制器的标签进行多次定义,将name属性的制作为url的访问地址进行映射。
<!-- 1.注册处理器映射器:
作用:处理器映射器会根据请求的url与Spring容器中定义的bean的名称进行匹配,从而Spring容器中找到对应的bean.
说明:不需要手动定义一个id,id规则:包名.类名#数字 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 2.注册处理器:
name: 表示对应一个前端的请求,name属性的取值必须以"/"开头
class: 表示对应请求从后台处理的类是谁 -->
<bean name="/hello" class="com.qf.springmvc01introduction.controller.HelloController"></bean>
<bean name="/world" class="com.qf.springmvc01introduction.controller.HelloController"></bean>
缺点:
- Controller配置显得极为冗余。
- 在标签的属性设置上,容易产生歧义。
1.4.2 SimpleUrlHandlerMapping
可以将url请求和对应的处理器的配置分离开来完成,可以多个url地址抽离出来,放在一个独立的标签中,然后通过其他配置完成映射。
<!--配置处理器映射器类:-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!--mappings属性:表示给当前的处理器映射器配置访问的url地址 -->
<!--
<property name="mappings">
props用来声明一组url地址
prop标签:表示一个url地址的映射,key表示具体的url
<props>
<prop key="/hello">helloController</prop>
<prop key="/world">helloController</prop>
</props>
</property>
-->
<!-- urlMap表示给指定的控制器配置多个url地址映射 -->
<property name="urlMap">
<map>
<!-- entry表示配置一组url映射 -->
<entry key="/hello" value="helloController" />
<entry key="/world" value="helloController" />
</map>
</property>
</bean>
<!-- 配置处理器类 -->
<bean id="helloController" class="com.qf.springmvc01introduction.controller.HelloController"></bean>
2 Spring MVC注解
2.1 SpringMVC注解项目分析
1.Spring框架注解:创建的Bean注解、DI依赖注入的注解(@AutoWride)。
2.SpringMVC注解:
- @RequestMapping:表示给当前方法添加一个请求url映射,在访问固定请求的时候,可以出发此方法。可以处理get和post请求。
- @GetMapping: 表示只有get类型的请求才可以触发被标记的方法。
- @PostMappiint: 表示只有post类型的请求才可以出发被标记的方法。
2.1 SpringMVC注解开发步骤
1.导入依赖:spring-webmvc。
2.在web.xml配置前端控制器:DispacherServlet。
3.定义控制器:Controller。通过SpringMVC的注解和处理请求的方法完成映射。
4.在springmvc-servlet.xml文件中配置视图解析器。
3 SpringMVC用户注册
3.1 SpringMVC请求类型
1.精确匹配
<url-pattern>/hello</url-pattern>
2.通配符匹配:可以使用“*”来表示多个任意的字符
<url-pattern>/*</url-pattern>
<url-pattern>/hello/*</url-pattern>
3.后缀匹配
<url-pattern>*.do</url-pattern>
<url-pattern>*.action</url-pattern>
3.2 SpringMVC用户注册实现
1.导入依赖:spring-webmvc。
2.在web.xml配置前端控制器:DispacherServlet。
3.定义控制器:Controller。通过SpringMVC的注解和处理请求的方法完成映射。
4.在springmvc-servlet.xml文件中配置视图解析器。
5.在项目添加了一个新的表单页面:addUser.jsp页面。
6.将表单中的数据在后台处理请求的方法上进行数据解析:
- HttpServletRequest: 如果请求的数据会自动打包在request对象上,需要在request上获取数据(getParamater("name值")方法);
- Model: 如果数据要向视图页面传递,需要将数据绑定在Model上,在页面上通过${属性名称}来获取到绑定的数据。
3.3 SpringMVC中文乱码处理
1.在web.xml配置文件中添加一个过滤器,设置编码为画utf-8。
<!-- 配置过滤器:配置解决中文乱码的问题 -->
<!-- 1.注册过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 设置编码:ISO-8895-1 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<!-- 2.添加过滤器映射:将请求配置到过滤器上,当前的过滤器可以处理什么样的请求 -->
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<!-- "/*"不会忽略JSP文件 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
2.常见BUG问题分析:
- 在配置SpringMVC前端控制器的时候,如果要拦截所有的请求“/”。
- 编辑Tomcat - Depenment选项 - 【+】 - Artifact选项 - 选择带有war explord类型的。把最新的项目加载到Tomcat中。
3.4 前后端数据通信
后端接收前端数据常见有三种方式:
- HttServletRequst:需要大量的调用request.getParameter()方法,代码冗余。
- 参数名称和表单name属性值保持一致,自动进行注入。如果表单的参数过多,那么方法的参数列表需要定义大量的参数来接受。
- 封装的pojo实体类来接收表单中的数据,适合处理数据比较多的情况,需要保证表单的name属性值和实体类的属性名相同。
3.5 SpringMVC日期类型转化
原因:前端表单在进行date控件数据传输的时候,当给到后台,SpringMVC无法解析表单类型的date。
解决:需要自定义一种日期类型的映射,来解决时间转化的问题。
-
@InitBinder:SpringMVC提供的,被此注解标记的方法表示是SpringMVC的初始化方法,执行早于请求处理方法。
-
CustomDateEditor:表示创建一个自定义的日期编辑器对象。
-
ServletRequestDataBinder:表示Servlet请求中绑定的数据。通过此对象格式化日期转化的类型(Date.class)。
@InitBinder public void initBinder(ServletRequestDataBinder binder) { //创建时间编辑器,并指定格式 CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true); //将转化的日期绑定到servlet上 binder.registerCustomEditor(Date.class, editor); }
4 RestFul风格
4.1 RestFul风格
这通过key=value的形式和后端进行数据交互时,get请求数据的体量在2KB左右,将导致无法在有限的数据限制内,发送更多的数据给到后台服务器进行处理。
http://localhost:8080/reg?username=tom&pwd=123456&age=20&gender=M
可以使用RestFul风格的url请求来传递数据。语法格式:
客户端:http://localhost:port/服务器程序名称/请求/参数值1/参数值2/参数值3/....
服务器:http://localhost:port/服务器程序名称/请求/{参数名1}/{参数名2}/{参数名3}/....
举例:
客户端:http://localhost:port/springmvc-reg/reg/tom/123456/24/....
服务器:http://localhost:port/springmvc-reg/reg/{username}/{pwd}/{age}/....
4.2 RestFul案例
需求:
http://localhost:port/程序名/userInfo/Jack/24
5 Spring MVC文件上传
5.1 文件上传接口介绍
1.MultipartFile接口
接口中常用的API:
方法 | 功能描述 |
---|---|
String getOriginalFilename() | 获取上传文件的原始文件名,即该文件在客户端中的文件名 |
boolean isEmpty() | 判断上传的文件是否为空,当没有选择文件就直接上传,或者选中的文件是0字节的空文件时,返回true,否则返回false |
long getSize() | 获取上传的文件大小,以字节为单位 |
String getContentType() | 根据所上传的文件的扩展名决定该文件的MIME类型,例如上传.jpg格式的图片,将返回image/jpeg |
InputStream getInputStream() | 获取上传文件的输入字节流,通常用于自定义读取所上传的文件的过程,该方法与transferTo()方法不可以同时使用 |
void transferTo(File dest) | 保存上传的文件,该方法与getInputStream()方法不可以同时使用 |
2.MultipartResolver接口
将文件解析成多不部件(MultipartFile)。
在xm核心配置文件中来完成MultipartResolver解析器的配置,后台完成文件数据的解析。
5.2 SpringMVC文件上传案例
-
导入依赖:
<!--文件上传--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency>
-
在web.xml文件中配置前端控制器与乱码过滤器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--前端控制器--> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--中文乱码过滤器--> <filter> <filter-name>chatset</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>chatset</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
-
在springmvc.xml文件中配置包扫描和MultipartResolver解析器。
<!--配置注解申明--> <aop:aspectj-autoproxy/> <!--包扫描 内置注解驱动--> <context:component-scan base-package="com.lty"/> <!--文件解析器--> <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"> <!--最大上传文件的大小--> <!-- <property name="maxUploadSize" value="1048567"/>--> </bean>
-
前端页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form method="post" action="${pageContext.request.contextPath}/user/file" enctype="multipart/form-data"> 文件:<input type="file" name="file"> <input type="submit" value="upload"> </form> </body> </html>
-
编写请求处理类,就是将客户端的文件数据转移到目标文件中(底层使用的是IO技术来完成数据的输出到目标文件中)。
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/toUpload")
public String toUpload() {
return "upload";
}
@RequestMapping(value = "/file",produces = "text/html;charset=utf-8")//produces 防止中文乱码
@ResponseBody
public String upload(HttpServletRequest request, MultipartFile file) {
//获取源文件的文件名
String originalFilename = file.getOriginalFilename();
System.out.println(originalFilename);
//得到该文件的后缀名,也可以找到最后一个.利用字符串的截取获取
String endName = FilenameUtils.getExtension(originalFilename);
System.out.println(endName);
//生成新文件的文件名
//目标文件的名称:1666535390435.docx
/* String desc = Calendar.getInstance().getTimeInMillis() +"."+ endName;*/
//目标文件的名称:QQ录屏202210231727041666535690345.mp4
String desc=originalFilename.substring(0,originalFilename.lastIndexOf("."))+System.currentTimeMillis()+originalFilename.substring(originalFilename.lastIndexOf("."));
System.out.println("目标文件的名称:" + desc);
//获取上下文路径找文件夹”upload“
String realPath = request.getServletContext().getRealPath("upload");
System.out.println("upload的路径+" + realPath);
//判断该目录是否存在,不存在就创建
File dir = new File(realPath);
if (!dir.exists()) {
dir.mkdirs();
}
//生成目标文件
File descFileName = new File(dir, desc);
System.out.println("目标目录:"+descFileName);
//向此文件中写入
try {
file.transferTo(descFileName);
return "成功";
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
6 Spring MVC文件下载
文件下载案例:
-
jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--filename:源文件的文件名 下载路径在浏览器中设置--%> <a href="${pageContext.request.contextPath}/download?filename=de356aa6-18a6-483c-b605-67d155e2690f.docx">下载</a> </body> </html>
-
Controller层实现:
@Controller public class DownloadController { @RequestMapping("/toDownLoad") public String toDownload() { return "download"; } @RequestMapping(value = "/download",produces = "text/html;charset=utf-8") public void downLoad(String filename, HttpServletResponse response, HttpSession session) throws IOException { //设置响应头,以附件的形式进行下载 response.setHeader("content-disposition", "attachment;filename=" + filename); String realPath=session.getServletContext().getRealPath("/upload"); //源文件的路径 String file=realPath+"\\"+filename; //以流的形式对外输出,输出服务器指定的file IOUtils.copy(new FileInputStream(file),response.getOutputStream()); } }