SpringMVC
1.SpringMVC中几个重要的组件。
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
处理器或页面控制器(Controller)
验证器( Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
2.SpringMVC需要的jar。
- spring容器的jar
- spring整合MVCjar
- springweb的jar
- jsp和servlet的jar
<!-- 版本锁定 -->
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
3. 整合SpringMVC
- SpringMVC的核心控制器DispatcherServlet其实是一个servlet,所以在web.xml中先配置。
- 配置核心控制器的同时也要把我们的spring工厂创建出来。
- 解决乱码问题,需要配置UTF-8编码格式
<!-- web.xml-->
<!-- 解决乱码问题-->
<filter>
<filter-name>encodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置springMVC的核心控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 同时加载bean.xml文件,创建spring工厂-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:bean.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>
- spring容器中依然需要开启注解扫描。
- 配置mvc的适配器,为页面跳转准备。
<!-- 扫描注解支持-->
<context:component-scan base-package="com.itzpx"/>
<!-- 配置适配器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 配置mvc支持-->
<mvc:annotation-driven conversion-service="conversionService"/>
- 测试方法
@Controller("helloController")
public class HelloController {
@RequestMapping("/hello")
public String sayHello() {
System.out.println("HelloController 的 sayHello 方法执行了。。。。");
return "success"; } }
4. SpringMVC是如何实现功能的?
- 当我们页面发生请求时,会被我们的DispatcherServlet(一个servlet)核心控制器拦截到。
- 根据我们发送的请求(hello),找到对应的方法(sayHello()),结果逻辑层代码后最终会返回一个字符串(return “success”)。
- 根据方法返回值,与视图解析器拼接,得到一个地址
(/WEB-INF/pages/success.jsp)。
5. 入门案例涉及到的组件
- DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由
它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。 - HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的
映射方式,例如:配置文件方式,实现接口方式,注解方式等。 - Handler:处理器
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由
Handler 对具体的用户请求进行处理。 - HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理
器进行执行。 - View Resolver:视图解析器
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名
即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。 - View:视图
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView
等。我们最常用的视图就是 jsp。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开
发具体的页面。 - <mvc:annotation-driven>说明
这玩意比较重要,
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用 <mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping (处理映射器) 和
RequestMappingHandlerAdapter ( 处 理 适 配 器 )
该配置相当于
<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- HadnlerExceptionResolvers -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
<!-- End -->
6. 注解
- RequestMapping
1.1 位置:类、方法
1.2 作用:用于建立请求 URL 和处理请求方法之间的对应关系。
1.3 参数:
① value:用于指定请求的 URL。它和 path 属性的作用是一样的。
② method:用于指定请求的方式。
③ params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样。
例如:
params = {“accountName”},表示请求参数必须有 accountName
params = {“moeny!100”},表示请求参数中 money 不能是 100。
④ headers:用于指定限制请求消息头的条件。 - RequestParam
2.1位置:方法形参中
2.2作用:把请求中指定名称的参数给控制器中的形参赋值。
2.3属性:
① value:请求参数中的名称。
② required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。 - RequestBody
3.1位置:方法形参中
3.2作用:用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。get 请求方式不适用。
3.3属性:
①required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。 - PathVaribale
4.1位置:方法形参中
4.2作用:用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
4.3属性:
①value:用于指定 url 中占位符名称。
②required:是否必须提供占位符。 - RequestHeader
5.1位置:方法形参中
5.2作用:用于获取请求消息头。
5.3属性:
①value:提供消息头名称
②required:是否必须有此消息头 - CookieValue
6.1位置:方法形参中
6.2作用:用于把指定 cookie 名称的值传入控制器方法参数。
6.3属性:
①value:指定 cookie 的名称。
②required:是否必须有此 cookie。 - ModelAttribute
7.1位置:方法体上
7.2作用:该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可
以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
7.3属性:
①value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
7.4应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
7.5该注解有两种使用方式
①:方法有返回值,方法参数可以接收请求参数,根据请求参数查询出其他属性,并封装到Account中,返回。
请求中只提供部分属性
<form action="<%=request.getContextPath()%>/saveUser03" method="post">
账户名:<input type="text" name="accountName"/><br/>
<input type="submit" value="提交"/>
</form>
在方法执行之前被ModelAttribute拦截,将Account对象中的属性补充完整
@ModelAttribute
public Account saveU(String accountName){
System.out.println("ModelAttribute开始"+accountName);
Account account = new Account();
// 获取传递过来的accountName
account.setAccountName(accountName);
// 模拟查询数据库
account.setDate(new Date());
User user = new User();
user.setUserName("lisi");
user.setUserAge("19");
account.setUser(user);
// 将剩余的属性补充完整后返回account对象
System.out.println("ModelAttribute结束");
return account;
}
然后再执行被请求的方法
@RequestMapping(path="/saveUser02")
public String saveUser02(Account account){
System.out.println("account="+account);
return "success";
}
②基于 Map 的应用场景
请求还是那样,只是我们的对象不是以返回值的形式,给到我们的方法中,是放入map中。
@ModelAttribute
public void showModel(String username,Map<String,User> map) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了 showModel 方法"+user);
map.put("abc",user);
}
而方法可以使用@ModelAttribute(“abc”)注解来给参数(也是我们的pojo对象)赋值。
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success"; }
- SessionAttribute
8.1位置:在类上面
8.2作用:用于多次执行控制器方法间的参数共享。
8.3属性:
①value:用于指定存入的属性名称
②type:用于指定存入的数据类型。
8.4使用场景:
jsp 中的代码:
<!-- SessionAttribute 注解的使用 --> <a href="springmvc/testPut">存入 SessionAttribute</a> <hr/>
<a href="springmvc/testGet">取出 SessionAttribute</a> <hr/>
<a href="springmvc/testClean">清除 SessionAttribute</a>
控制器中的代码:
/**
* SessionAttribute 注解的使用
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
@Controller("sessionAttributeController")
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class})
public class SessionAttributeController {
/**
* 把数据存入 SessionAttribute
* @param model
* @return
* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
*/
@RequestMapping("/testPut")
public String testPut(Model model){
model.addAttribute("username", "泰斯特");
model.addAttribute("password","123456");
model.addAttribute("age", 31);
//跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有
这几个参数
return "success";
}
@RequestMapping("/testGet")
public String testGet(ModelMap model){
System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a
ge"));
return "success";
}
@RequestMapping("/testClean")
public String complete(SessionStatus sessionStatus){
sessionStatus.setComplete();
return "success";
}
}
7.请求参数的绑定
如何获取请求中的参数
- 基本类型参数:
包括基本类型和 String 类型 - POJO 类型参数:
包括实体类,以及关联的实体类 - 数组和集合类型参数:
包括 List 结构和 Map 结构的集合(包括数组)
规则:
- 如果是基本类型或者 String 类型:
要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写) - 如果是 POJO 类型,或者它的关联对象:
要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的3. 参数类型是 POJO 类型。 - 如果是集合类型,有两种方式:
第一种:
要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。
给 List 集合中的元素赋值,使用下标。
给 Map 集合中的元素赋值,使用键值对。
第二种:
接收的请求参数是 json 格式数据。需要借助一个注解实现。
8. 请求参数乱码问题
web.xml
<!-- 解决乱码问题-->
<filter>
<filter-name>encodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
静态资源不过滤
bean.xml
<!-- 过滤器配置-->
<mvc:resources location="/WEB-INF/css/" mapping="/css/**"/>
<mvc:resources location="/WEB-INF/images/" mapping="/images/**"/>
<mvc:resources location="/WEB-INF/scripts/" mapping="/javascript/**"/>
get请求方式的乱码问题
tomacat 对 GET 和 POST 请求处理方式是不同的,GET 请求的编码问题,要改 tomcat 的 server.xml
配置文件,如下:
<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"
useBodyEncodingForURI="true"/>
如果遇到 ajax 请求仍然乱码,请把:
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"
即可。
9. 自定义类型转换器
当参数数据类型转化不满足我们的要求时,我们可以进行改造
添加一个类型转化器
写一个类(Converson)转化器,实现Converter<T,S>,接口中的方法convert,该方法接收T类型的数据,返回值为S类型的数据,从而实现参数数据类型转化。
public class Conversion implements Converter<String, Date> {
public Date convert(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
System.out.println(s);
Date date = sdf.parse(s);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
将自定义的转化器加入到原有的转化器中
bean.xml
<!-- 配置mvc支持-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 配置转化器-->
<bean name="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itzpx.utils.Conversion"></bean>
</set>
</property>
</bean>
10.springmvc支持servlet原生的API
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request,
HttpServletResponse response,
HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success"; }