SpringMVC简介
MVC模型
MVC全称Model View Controller,是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分:
-
Model(模型):指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用中,JavaBean对象,业务模型等都属于Model。
-
View(视图):用于展示模型中的数据的,一般为jsp或html文件。
-
Controller(控制器):是应用程序中处理用户交互的部分。接受视图提出的请求,将数据交给模型处理,并将处理后的结果交给视图显示。
SpringMVC
SpringMVC是一个基于MVC模式的轻量级Web框架,是Spring框架的一个模块,和Spring可以直接整合使用。SpringMVC代替了Servlet技术,它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。
SpringMVC入门案例
接下来我们编写一个SpringMVC的入门案例
-
使用maven创建web项目,补齐包结构。
-
引入相关依赖和tomcat插件
<dependencies><!-- Spring核心模块 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.12.RELEASE</version></dependency><!-- SpringWeb模块 --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.12.RELEASE</version></dependency><!-- SpringMVC模块 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.12.RELEASE</version></dependency><!-- Servlet --><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><!-- JSP --><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency> </dependencies><build><plugins><!-- tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><port>8080</port><path>/</path><uriEncoding>UTF-8</uriEncoding><server>tomcat7</server><systemProperties><java.util.logging.SimpleFormatter.format>%1$tH:%1$tM:%1$tS %2$s%n%4$s: %5$s%6$s%n</java.util.logging.SimpleFormatter.format></systemProperties></configuration></plugin></plugins> </build>
-
在web.xml中配置前端控制器DispatcherServlet。
<web-app><display-name>Archetype Created Web Application</display-name><!--SpringMVC前端控制器,本质是一个Servlet,接收所有请求,在容器启动时就会加载--><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping> </web-app>
编写SpringMVC核心配置文件springmvc.xml,该文件和Spring配置文件写法一样。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 扫描包 --><context:component-scan base-package="com.springMVC"/><!-- 开启SpringMVC注解的支持 --><mvc:annotation-driven/></beans>
编写控制器
@Controller
public class MyController1 {// 该方法的访问路径是/c1/hello1@RequestMapping("/c1/hello1")public void helloMVC(){System.out.println("hello SpringMVC!");}
}
使用tomcat插件启动项目,访问 http://localhost:8080/c1/hello1
SpringMVC执行流程
SpringMVC的组件
- DispatcherServlet:前端控制器,接受所有请求,调用其他组件。
- HandlerMapping:处理器映射器,根据配置找到方法的执行链。
- HandlerAdapter:处理器适配器,根据方法类型找到对应的处理器。
- ViewResolver:视图解析器,找到指定视图。
组件的工作流程
在这里插入图片描述
- 客户端将请求发送给前端控制器。
- 前端控制器将请求发送给处理器映射器,处理器映射器根据路径找到方法的执行链,返回给前端控制器。
- 前端控制器将方法的执行链发送给处理器适配器,处理器适配器根据方法类型找到对应的处理器。
- 处理器执行方法,将结果返回给前端控制器。
- 前端控制器将结果发送给视图解析器,视图解析器找到视图文件位置。
- 视图渲染数据并将结果显示到客户端。
SpringMVC参数获取
封装为简单数据类型
在Servlet中我们通过request.getParameter(name)
获取请求参数。该方式存在两个问题:
- 请求参数较多时会出现代码冗余。
- 与容器紧耦合。
而SpringMVC支持参数注入的方式用于获取请求数据,即将请求参数直接封装到方法的参数当中。用法如下:
-
编写控制器方法
// 获取简单类型参数 @RequestMapping("/c1/param1") public void simpleParam(String username,int age){System.out.println(username);System.out.println(age); }
-
访问该方法时,请求参数名和方法参数名相同,即可完成自动封装。
http://localhost:8080/c1/param1?username=bz&age=10
封装为对象类型
SpringMVC支持将参数直接封装为对象,写法如下:
封装单个对象
-
编写实体类
public class Student {private int id;private String name;private String sex;// 省略getter/setter/tostring }
-
编写控制器方法
// 获取对象类型参数 @RequestMapping("/c1/param2") public void objParam(Student student){System.out.println(student); }
-
访问该方法时,
请求参数名和方法参数的属性名相同,即可完成自动封装。http://localhost:8080/c1/param2?id=1&name=bz&sex=female
封装关联对象
-
编写实体类
public class Address {private String info; //地址信息private String postcode; //邮编// 省略getter/setter/tostring } public class Student {private int id;private String name;private String sex;private Address address; // 地址对象// 省略getter/setter/tostring }
-
编写控制器方法
// 获取关联对象类型参数 @RequestMapping("/c1/param3") public void objParam2(Student student){ System.out.println(student); }
-
访问该方法时,请求参数名和方法参数的属性名相同,即可完成自动封装。
http://localhost:8080/c1/param3?id=1&name=bz&sex=female&address.info=beijing&address.postcode=030000
我们也可以使用表单发送带有参数的请求:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>表单提交</title> </head> <body> <form action="/c1/param3" method="post">id:<input name="id">姓名:<input name="name">性别:<input name="sex">住址:<input name="address.info">邮编:<input name="address.postcode"><input type="submit"> </form> </body> </html>
封装为集合类型
SpringMVC支持将参数封装为List或Map集合,写法如下:
封装为List集合
封装为简单数据类型集合
-
编写控制器方法
// 绑定简单数据类型List参数,参数前必须添加@RequestParam注解 @RequestMapping("/c1/param4") public void listParam(@RequestParam List<String> users){ System.out.println(users); }
该方式也可以绑定数组类型:
@RequestMapping("/c1/param5") public void listParam2(@RequestParam String[] users){ System.out.println(users[0]); System.out.println(users[1]); }
-
请求的参数写法
http://localhost:8080/c1/param4?users=bj&users=springMVC
封装为对象类型集合
SpringMVC不支持将参数封装为对象类型的List集合,但可以封装到有List属性的对象中。
-
编写实体类
public class Student {private int id;private String name;private String sex;private List<Address> address; // 地址集合// 省略getter/setter/tostring }
-
编写控制器方法
// 对象中包含集合属性 @RequestMapping("/c1/param6") public void listParam3(Student student){System.out.println(student); }
-
请求的参数写法
[http://localhost:8080/c1/param6?id=1&name=bz&sex=female&address0].info=bj&address[0].postcode=100010&address[1].info=sh&address[1].postcode=100011
封装为Map集合
同样,SpringMVC要封装Map集合,需要封装到有Map属性的对象中。
-
编写实体类
public class Student {private int id;private String name;private String sex;private Map<String,Address> address; // 地址集合// 省略getter/setter/tostring }
-
编写控制器方法
// 对象中包含Map属性 @RequestMapping("/c1/param7") public void mapParam(Student student){ System.out.println(student); }
-
请求的参数写法
[http://localhost:8080/c1/param7?id=1&name=bz&sex=female&address’one’].info=bj&address[‘one’].postcode=100010&address[‘two’].info=sh&address[‘two’].postcode=100011
使用Servlet原生对象获取参数
SpringMVC也支持使用Servlet原生对象,在方法参数中定义HttpServletRequest
、HttpServletResponse
、HttpSession
等类型的参数即可直接在方法中使用。
// 使用Servlet原生对象
@RequestMapping("/c1/param8")
public void servletParam(HttpServletRequest request, HttpServletResponse response, HttpSession session){ // 原生对象获取参数 System.out.println(request.getParameter("name")); System.out.println(response.getCharacterEncoding()); System.out.println(session.getId());
}
访问该方法即可:http://localhost:8080/c1/param8?name=zhangshan
一般情况下,在SpringMVC中都有对Servlet原生对象的方法的替代,推荐使用SpringMVC的方式代替Servlet原生对象。
自定义参数类型转换器
前端传来的参数全部为字符串类型,SpringMVC使用自带的转换器将字符串参数转为需要的类型。如:
// 获取简单类型参数
@RequestMapping("/c1/param1")
public void simpleParam(String username,int age){ System.out.println(username); System.out.println(age);
}
请求路径:http://localhost:8080/c1/param1?username=bz&age=10
但在某些情况下,无法将字符串转为需要的类型,如:
@RequestMapping("/c1/param9")
public void dateParam(Date birthday){ System.out.println(birthday);
}
由于日期数据有很多种格式,SpringMVC没办法把所有格式的字符串转换成日期类型。比如参数格式为birthday=2025-01-01
时,SpringMVC就无法解析参数。此时需要自定义参数类型转换器。
-
定义类型转换器类,实现Converter接口
// 类型转换器必须实现Converter接口,两个泛型代表转换前的类型,转换后的类型 public class DateConverter implements Converter<String, Date> {/*** 转换方法* @param source 转换前的数据* @return 转换后的数据*/@Overridepublic Date convert(String source) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = sdf.parse(source);} catch (ParseException e) {e.printStackTrace();}return date;} }
-
注册类型转换器对象
<!-- 配置转换器工厂 --> <bean id="converterFactory" class="org.springframework.context.support.ConversionServiceFactoryBean"><!-- 转换器集合 --><property name="converters"><set><!-- 自定义转换器 --><bean class="com.springMVC.converter.DateConverter"></bean></set></property> </bean<!-- 使用转换器工厂 --> <mvc:annotation-driven conversion-service="converterFactory"></mvc:annotation-driven>
-
此时再访问http://localhost:8080/c1/param9?birthday=2025-01-01时,SpringMVC即可将请求参数封装为Date类型的参数。
编码过滤器
在传递参数时,tomcat8以上能处理get请求的中文乱码,但不能处理post请求的中文乱码
-
编写jsp表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>编码过滤器</title></head><body><form action="/cn/code" method="post">姓名:<input name="username"><input type="submit"></form></body> </html>
-
编写控制器方法
@RequestMapping("/cn/code") public void code(String username){System.out.println(username); }
SpringMVC提供了处理中文乱码的过滤器,在web.xml中配置该过滤器即可解决中文乱码问题:
<!--SpringMVC中提供的字符编码过滤器,放在所有过滤器的最上方-->
<filter><filter-name>encFilter</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>encFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>