springmvc的基础知识
2018/5/7
基础知识
springmvc框架(重点)
mvc在b/s系统中应用方式
springmvc框架原理(DispatcherServlet前端控制器、处理器映射器、处理器适配器、视图解析器)
springmvc入门程序
需求:商品列表查询
常用的处理器映射器,处理器适配器
注解的处理器映射器,处理器适配器用于注解开发(重点)
3
注解开发基础
常用的注解使用
参数绑定
自定义参数绑定
springmvc和struts的区别
高级知识
使用springmvc上传图片
集合参数的绑定
validation校验器
异常处理器使用(用于系统异常处理)
RESTful支持
拦截器
学生练习
1 springmvc框架
1.1 springmvc是什么?
springmvc是spring的一个模块,提供web层解决方案(基于mvc设计架构)
1.2 mvc在b/s系统的应用
mvc是一个设计模式,在b/s系统的应用:
1.3 springmvc的框架
第一步:用户发起request请求,请求至DispatcherServlet前端控制器
第二步:DispatcherServlet前端控制器请求HandlerMapping处理器映射器查找Handler
DispatcherServlet:前端控制器,相当于中央调度器,各各组件都和前端控制器进行交互,降低了各各组 件之间耦合度。
第三步:HandlerMapping处理器映射器,根据url及一些配置规则(xml配置、注解配置)查找Handler,将Handler返回给DispatcherServlet前端控制器
第四步:DispatcherServlet前端控制器调用适配器执行Handler,有了适配器通过适配器去扩展对不同Handler执行方式(比如:原始servlet开发,注解开发)
第五步:适配器执行Handler
Handler是后端控制器,当成模型。
第六步:Handler执行完成返回ModelAndView
ModelAndView:springmvc的一个对象,对Model和view进行封装。
第七步:适配器将ModelAndView返回给DispatcherServlet
第八步:DispatcherServlet调用视图解析器进行视图解析,解析后生成view
视图解析器根据逻辑视图名解析出真正的视图。
View:springmvc视图封装对象,提供了很多view,jsp、freemarker、pdf、excel。。。
第九步:ViewResolver视图解析器给前端控制器返回view
第十步:DispatcherServlet调用view的渲染视图的方法,将模型数据填充到request域 。
第十一步:DispatcherServlet向用户响应结果(jsp页面、json数据。。。。)
DispatcherServlet:前端控制器,由springmvc提供
HandlerMappting:处理器映射器,由springmvc提供
HandlerAdapter:处理器适配器,由springmvc提供
Handler:处理器,需要程序员开发
ViewResolver:视图解析器,由springmvc提供
View:真正视图页面需要由程序编写
2 入门程序
2.1 需求
实现商品列表查询
2.2 需要的jar包
使用spring3.2.0(带springwebmvc模块)
2.3 前端控制器
在web.xml中配置:
Servlet拦截方式
1、拦截固定后缀的url,比如设置为 .do、.action, 例如:/user/add.action
此方法最简单,不会导致静态资源(jpg,js,css)被拦截。
2、拦截所有,设置为/,例如:/user/add /user/add.action
此方法可以实现REST风格的url,很多互联网类型的应用使用这种方式。
但是此方法会导致静态文件(jpg,js,css)被拦截后不能正常显示。需要特殊处理。
3、拦截所有,设置为/*,此设置方法错误,因为请求到Action,当action转到jsp时再次被拦截,提示不能根据jsp路径mapping成功。
2.4 springmvc.xml
在springmvc.xml中配置springmvc架构三大组件(处理器映射器、适配器、视图解析器)
2.5 工程结构
2.6 处理器映射器
在springmvc.xml中配置:
BeanNameUrlHandlerMapping:表示将定义的Bean名字作为请求的url,需要将编写的controller在spring容器中进行配置,且指定bean的name为请求的url,且必须以.action结尾。
BeanNameUrlHandlerMapping: 根据请求url(XXXX.action)匹配spring容器bean的 name 找到对应的bean(程序编写的Handler)
<!-- 根据bean的name进行查找Handler 将action的url配置在bean的name中 -->
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
所有处理器映射器都实现HandlerMapping接口。
2.7 处理器适配器
在springmvc.xml配置:
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
所有的适配器都是实现了HandlerAdapter接口。
SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为
Springmvc的后端控制器。
程序编写Handler根据适配器的要求编写。
SimpleControllerHandlerAdapter适配器要求:
通过supports方法知道Handler必须要实现哪个接口:
2.8 Handler编写
需要实现Controller接口:
public class ItemList1 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
//商品列表
List<Items> itemsList = new ArrayList<Items>();
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//创建modelAndView准备填充数据、设置视图
ModelAndView modelAndView = new ModelAndView();
//填充数据
modelAndView.addObject("itemsList", itemsList);
//视图
modelAndView.setViewName("order/itemsList");
return modelAndView;
}
}
org.springframework.web.servlet.mvc.Controller:处理器必须实现Controller 接口。
ModelAndView:包含了模型数据及逻辑视图名
2.9 配置Handler
在springmvc.xml配置Handler由spring管理Handler。
name="/items1.action":前边配置的处理器映射器为BeanNameUrlHandlerMapping,如果请求的URL 为“上下文/items1.action”将会成功映射到ItemList1控制器。
2.10 配置视图解析器
配置视图解析,能够解析jsp视图:
2.11 工程部署
访问:http://localhost:8080/springfrist1110/itemList.action
2.12 异常
2.12.1 HandlerMapping没有找到Handler
HandlerMapping没有找到Handler,404后边不显示jsp路径
2.12.2 jsp页面地址错误
3 其它非注解处理器映射器和适配器
HandlerMapping 负责根据request请求找到对应的Handler处理器及Interceptor拦截器,将它们封装在HandlerExecutionChain 对象中给前端控制器返回。
HandlerAdapter会根据适配器接口对后端控制器进行包装(适配),包装后即可对处理器进行执行,通过扩展处理器适配器可以执行多种类型的处理器,这里使用了适配器设计模式。
3.1 BeanNameUrlHandlerMapping(映射器)
根据请求url(XXXX.action)匹配spring容器bean的 name
找到对应的bean(程序编写的Handler)
3.2 SimpleUrlHandlerMapping(映射器)
simpleUrlHandlerMapping是BeanNameUrlHandlerMapping的增强版本,它可以将url和处理器bean的id进行统一映射配置。
注意:在springmvc.xml配置了多个处理器映射器,多个处理器映射器可以共存。
3.3 SimpleControllerHandlerAdapter(适配器)
要求程序编写的Handler(Controller)需要实现 Controller接口。
SimpleControllerHandlerAdapter简单控制器处理器适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean通过此适配器进行适配、执行。
适配器配置如下:
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
3.4 HttpRequestHandlerAdapter(适配器)
在springmvc.xml配置:HttpRequestHandlerAdapter
要求Handler 实现 HttpRequestHandler接口
HttpRequestHandlerAdapter,http请求处理器适配器,所有实现了org.springframework.web.HttpRequestHandler 接口的Bean通过此适配器进行适配、执行。
适配器配置如下:
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
Controller实现如下:
public class ItemList2 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 商品列表
List<Items> itemsList = new ArrayList<Items>();
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone5 苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
// 填充数据
request.setAttribute("itemsList", itemsList);
// 视图
request.getRequestDispatcher("/WEB-INF/jsp/order/itemsList.jsp").forward(request, response);
}
}
从上边可以看出此适配器器的handleRequest方法没有返回ModelAndView,可通过response修改定义响应内容,比如返回json数据:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
3.4.1 开发Handler
3.4.2 配置Handler
使用简单url映射器:
4 DispatcherServlet.properoties
DispatcherServlet前端控制器加载 DispatcherServlet.properoties 配置文件,从而默认加载各各组件,
如果在springmvc.xml中配置了处理器映射器和适配器,以sprintmvc.xml中配置的为准
5 注解映射器和适配器
5.1 注解映射器
spring3.1之前默认加载映射器是
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping,
3.1之后要使用:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
在springmvc.xml中配置RequestMappingHandlerMapping:
使用RequestMappingHandlerMapping需要在Handler 中使用@controller标识此类是一个控制器,使用@requestMapping指定Handler方法所对应的url。
5.2 注解适配器
spring3.1之前默认加载映射器是
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter,
3.1之后要使用:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
RequestMappingHandlerAdapter,不要求Handler实现任何接口,它需要和RequestMappingHandlerMapping注解映射器配对使用,主要解析Handler方法中的形参。
5.3 注解开发Hanlder
5.4 配置Handler
建议使用组件扫描,组件扫描可以扫描@Controller、@Service、@component、@Repsitory
1.1.1 组件扫描器
使用组件扫描器省去在spring容器配置每个controller类的繁琐。使用<context:component-scan自动扫描标记@controller的控制器类,配置如下:
<!-- 扫描controller注解,多个包中间使用半角逗号分隔 -->
<context:component-scan base-package="cn.itcast.springmvc.controller.first"/>
1.1.2 RequestMappingHandlerMapping
注解式处理器映射器,对类中标记@ResquestMapping的方法进行映射,根据ResquestMapping定义的url匹配ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器,HandlerMethod对象中封装url对应的方法Method。
从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。
配置如下:
<!--注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
注解描述:
@RequestMapping:定义请求url到处理器功能方法的映射
1.1.3 RequestMappingHandlerAdapter
注解式处理器适配器,对标记@ResquestMapping的方法进行适配。
从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。
配置如下:
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
1.1.4
springmvc使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter,可用在springmvc.xml配置文件中使用
<mvc:annotation-driven>替代注解处理器和适配器的配置。
6 小结
DispatcherServlet:前端控制器,相当于中央调度器,可以降低组件之间的耦合度。
HandlerMapping:处理器映射器,负责根据url查找Handler
HandlerAdapter:处理器适配器,负责根据适配器要求的规则去执行处理器。可以通过扩展适配器支持不同类型的Handler。
viewResolver:视图解析器,根据逻辑视图名解析成真正的视图,
真正视图地址==前缀+逻辑视图名+后缀
6.1 springmvc处理流程源码分析
1、DispatcherServlet通过HandlerMapping查找Handler
用户发送请求到DispatherServlet前端控制器
DispatherServlet调用HandlerMapping(处理器映射器)根据url查找Handler
2、DispatcherServlet通过适配器去执行Handler,得到ModelAndview
DispatherServlet调用HandlerAdapter(处理器适配器)对HandlerMapping找到Handler进行包装、执行。
HandlerAdapter执行Handler完成后,返回了一个ModleAndView(springmvc封装对象)
DispatherServlet 找一个合适的适配器:
适配器执行Hanlder
3、视图解析
DispatherServlet拿着ModelAndView调用ViewResolver(视图解析器)进行视图解析,解析完成后返回一个View(很多不同视图类型的View)
视图解析完成得到一个view:
4、进行视图渲染
将Model中的数据 填充到request域。
DispatcherServlet进行视图渲染,将Model中数据放到request域,在页面展示
将model数据放在request域:
7 springmvc和mybatis整合工程搭建
7.1 整合思路
在mybatis和spring整合的基础上 添加springmvc。
spring要管理springmvc编写的Handler(controller)、mybatis的SqlSessionFactory、mapper
第一步:整合dao,spring和mybatis整合
第二步:整合service,spring管理service接口,service中可以调用spring容器中dao(mapper)
第三步:整合controller,spring管理controller接口,在controller调用service
7.2 jar包
mybatis:3.2.7
spring:3.2.0
mybatis的jar
mybatis和spring整合包
spring的所有jar包(包括 springmvc的包)
数据库驱动包
log4j日志..
7.3 工程结构
7.3.1 配置文件
applicationContext-dao.xml---配置数据源、SqlSessionFactory、mapper扫描器
applicationContext-service.xml---配置service接口
applicationContext-transaction.xml--事务管理
sprintmvc.xml---springmvc的配置,配置处理器映射器、适配器、视图解析器
SqlMapConfig.xml---mybatis的配置文件,配置别名、settings、mapper
7.3.2 applicationContext-dao.xml
配置数据源、事务管理,配置SqlSessionFactory、mapper扫描器。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="30"/>
<property name="maxIdle" value="5"/>
</bean>
<!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
</bean>
<!-- mapper扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.springmvc.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
</beans>
7.3.3 applicationContext-transation.xml
在此配置文件配置事务,声明式事务控制。
使用声明式事务配置,可以有效规范代码
7.4 前端控制器配置
7.5 配置springmvc.xml
7.5.1 工程结构
7.6 商品列表开发
7.6.1 需求
查询商品列表
7.6.2 mapper
功能描述:根据条件查询商品信息,返回商品列表
一般情况下针对查询mapper需要自定义mapper。
首先针对单表进行逆向工程,生成代码。
7.6.2.1 mapper.xml
7.6.2.2 包装类:
7.6.2.3 mapper.java
7.6.3 service
7.6.4 在applicationContext-service.xml中配置service
7.6.5 controller
7.6.6 jsp
7.6.7 在web.xml配置spring监听器
8 注解开发基础
8.1 商品修改
8.1.1 需求
功能描述:商品信息修改
操作流程:
1、在商品列表页面点击修改连接
2、打开商品修改页面,显示了当前商品的信息
根据商品id查询商品信息
3、修改商品信息,点击提交。
更新商品信息
8.1.2 mapper
使用逆向工程生成代码:
根据商品id查询商品信息
更新商品信息
ItemsMapper.java
ItemsMapper.xml
8.1.3 service
8.2 @RequestMapping
通过RequestMapping注解可以定义不同的处理器映射规则。
8.2.1 设置方法对应的url(完成url映射)
一个方法对应一个url
@RequestMapping(value="/item")或@RequestMapping("/item)
value的值是数组,可以将多个url映射到同一个方法
8.2.2 窄化请求映射
在class上定义根路径
好处:更新规范系统 的url,避免 url冲突。
在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。
如下:
@RequestMapping放在类名上边,设置请求前缀
@Controller
@RequestMapping("/item")
方法名上边设置请求映射url:
@RequestMapping放在方法名上边,如下:
@RequestMapping("/queryItem ")
访问地址为:/item/queryItem
8.2.3 限制http请求的方法
通过requestMapping限制url请求的http方法,
如果限制请求必须是post,如果get请求就抛出异常:
商品修改方法,限制为http的get:
限定GET方法
@RequestMapping(method = RequestMethod.GET)
如果通过Post访问则报错:
HTTP Status 405 - Request method 'POST' not supported
例如:
@RequestMapping(value="/editItem",method=RequestMethod.GET)
限定POST方法
@RequestMapping(method = RequestMethod.POST)
如果通过Post访问则报错:
HTTP Status 405 - Request method 'GET' not supported
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
8.3 controller方法返回值
8.3.1 返回ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。
8.3.2 返回字符串
如果controller方法返回jsp页面,可以简单将方法返回值类型定义 为字符串,最终返回逻辑视图名。
8.3.3 返回void
使用此方法,容易输出json、xml格式的数据:
在controller方法形参上可以定义request和response,使用request或response指定响应结果:
使用request转向页面,如下:
request.getRequestDispatcher("页面路径").forward(request, response);
通过response页面重定向:
response.sendRedirect("url")
通过response指定响应结果,例如响应json数据如下:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
8.3.4 redirect重定向
如果方法重定向到另一个urk,方法返回值为“redirect:url路径”
使用redirect进行重定向,request数据无法共享,url地址栏会发生变化的。
Contrller方法返回结果重定向到一个url地址,如下商品修改提交后重定向到商品查询方法,参数无法带到商品查询方法中。
//重定向到queryItem.action地址,request无法带过去
return "redirect:queryItem.action";
redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的request和response。
由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以/item/queryItem.action后边加参数,如下:
/item/queryItem?...&…..
8.3.5 forward转发
使用forward进行请求转发,request数据可以共享,url地址栏不会。
方法返回值为“forward:url路径”
controller方法执行后继续执行另一个controller方法,如下商品修改提交后转向到商品修改页面,修改商品的id参数可以带到商品修改方法中。
//结果转发到editItem.action,request可以带过去
return "forward:editItem.action";
forward方式相当于“request.getRequestDispatcher().forward(request,response)”,
转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,
而是和转发前的请求共用一个request和response。
所以转发前请求的参数在转发后仍然可以读取到。
8.4 参数绑定
8.4.1 参数绑定过程
1.2.1 默认支持的参数类型
处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值。
8.4.2 HttpServletRequest
通过request对象获取请求信息
8.4.3 HttpServletResponse
通过response处理响应信息
8.4.4 HttpSession
通过session对象得到session中存放的对象
8.4.5 Model
通过model向页面传递数据,如下:
//调用service查询商品信息
Items item = itemService.findItemById(id);
model.addAttribute("item", item);
页面通过${item.XXXX}获取item对象的属性值。
8.4.6 @RequestParam
@RequestParam用于绑定单个请求参数。
value:参数名字,即入参的请求参数名字,如value=“item_id”表示请求的参数区中的名字为item_id的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报;
HTTP Status 400 - Required Integer parameter 'XXXX' is not present
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
定义如下:
public String editItem(@RequestParam(value="item_id",required=true) String id) {
}
形参名称为id,但是这里使用value=" item_id"限定请求的参数名为item_id,所以页面传递参数的名必须为item_id。
注意:如果请求参数中没有item_id将抛出异常:
HTTP Status 500 - Required Integer parameter 'item_id' is not present
这里通过required=true限定item_id参数为必需传递,如果不传递则报400错误,可以使用defaultvalue设置默认值,即使required=true也可以不传item_id参数值
如果request请求的参数名和controller方法的形参数名称一致,适配器自动进行参数绑定。如果不一致可以通过
@RequestParam 指定request请求的参数名绑定到哪个方法形参上。
对于必须要传的参数,通过@RequestParam中属性required设置为true,如果不传此参数则报错。
对于有些参数如果不传入,还需要设置默认值,使用@RequestParam中属性defaultvalue设置默认值。
8.4.7 可以绑定简单类型
可以绑定整型、 字符串、单精/双精度、日期、布尔型。
8.4.7.1 整型
public String editItem(Model model,Integer id) throws Exception{
}
8.4.7.2 布尔型
处理器方法:
public String editItem(Model model,Integer id,Boolean status) throws Exception
请求url:
http://localhost:8080/springmvc_mybatis/item/editItem.action?id=2&status=false
说明:对于布尔类型的参数,请求的参数值为true或false。
8.4.8 可以绑定简单pojo类型
将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中
页面定义如下;
<input type="text" name="name"/>
<input type="text" name="price"/>
Contrller方法定义如下:
@RequestMapping("/editItemSubmit")
public String editItemSubmit(Items items)throws Exception{
System.out.println(items);
请求的参数名称和pojo的属性名称一致,会自动将请求参数赋值给pojo的属性。
简单pojo类型只包括简单类型的属性。
绑定过程:
request请求的参数名称和pojo的属性名一致,就可以绑定成功。
问题:
如果controller方法形参中有多个pojo且pojo中有重复的属性,使用简单pojo绑定无法有针对性的绑定,
比如:方法形参有items和User,pojo同时存在name属性,从http请求过程的name无法有针对性的绑定到items或user。
8.4.9 可以绑定包装的pojo
如果采用类似struts中对象.属性的方式命名,需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。
包装对象定义如下:
Public class QueryVo {
private Items items;
}
页面定义:
<input type="text" name="items.name" />
<input type="text" name="items.price" />
Controller方法定义如下:
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getItems());
包装的pojo里边包括了pojo。
页面参数定义:
包装类型的属性也是itemsCustom:
按照上边的规则进行包装类型的绑定。
8.4.10 自定义绑定使用属性编辑器
springmvc没有提供默认的对日期类型的绑定,需要自定义日期类型的绑定。
8.4.10.1 使用WebDataBinder(了解)
在controller类中定义:
使用这种方法问题是无法在多个controller共用。
8.4.10.2 使用WebBindingInitializer(了解)
在controller方法中通过@InitBinder标识方法为参数绑定方法,通过WebDataBinder注册属性编辑器,问题是此方法只能在单个controller类中注册。
/**
* 注册属性编辑器(字符串转换为日期)
*/
@InitBinder
public void initBinder(WebDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
使用WebBindingInitializer让多个controller共用 属性编辑器。
自定义WebBindingInitializer,注入到处理器适配器中。
如果想多个controller需要共同注册相同的属性编辑器,可以实现PropertyEditorRegistrar接口,并注入webBindingInitializer中。
如下:
编写CustomPropertyEditor:
配置如下:
<!-- 注册属性编辑器 -->
<bean id="customPropertyEditor" class="cn.itcast.ssm.propertyeditor.CustomPropertyEditor"></bean>
<!-- 自定义webBinder -->
<bean id="customBinder"
class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="propertyEditorRegistrars">
<list>
<ref bean="customPropertyEditor"/>
</list>
</property>
</bean>
<!--注解适配器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="customBinder"></property>
</bean>
8.4.11 自定义参数绑定使用转换器(架构师掌握)
8.4.11.1 实现Converter接口:
定义日期类型转换器和字符串去除前后空格转换器。
public class CustomDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
return simpleDateFormat.parse(source);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
配置方式1
<!--注解适配器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="customBinder"></property>
</bean>
<!-- 自定义webBinder -->
<bean id="customBinder"
class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService" />
</bean>
<!-- conversionService -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 转换器 -->
<property name="converters">
<list>
<bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
</list>
</property>
</bean>
配置方式2
<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<!-- conversionService -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 转换器 -->
<property name="converters">
<list>
<bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
</list>
</property>
</bean>
8.4.11.2 配置转换器
参考教案:
配置方式1针对不使用
配置方式2针对使用的配置
8.5 问题处理
8.5.1 post乱码
在web.xml中加入:
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
以上可以解决post请求乱码问题。
对于get请求中文参数出现乱码解决方法有两个:
修改tomcat配置文件添加编码与工程编码一致,如下:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
另外一种方法对参数进行重新编码:
String userName new
String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码
5.7 与struts2不同
1、 springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
2、 springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
3、 Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
5.5.6.3 ModelAttribute
@ModelAttribute作用如下:
1、绑定请求参数到pojo并且暴露为模型数据传到视图页面
此方法可实现数据回显效果。
// 商品修改提交
@RequestMapping("/editItemSubmit")
public String editItemSubmit(@ModelAttribute("item") Items items,Model model)
页面:
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${item.name }"/></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="${item.price }"/></td>
</tr>
如果不用@ModelAttribute可以使用model.addAttribute("item", items)完成数据回显。
2、将方法返回值暴露为模型数据传到视图页面
//商品分类
@ModelAttribute("itemtypes")
public Map<String, String> getItemTypes(){
Map<String, String> itemTypes = new HashMap<String,String>();
itemTypes.put("101", "数码");
itemTypes.put("102", "母婴");
return itemTypes;
}
页面:
商品类型:
<select name="itemtype">
<c:forEach items="${itemtypes }" var="itemtype">
<option value="${itemtype.key }">${itemtype.value }</option>
</c:forEach>
</select>
5.5.7 集合类
5.5.7.1 字符串数组
页面定义如下:
页面选中多个checkbox向controller方法传递
<input type="checkbox" name="item_id" value="001"/>
<input type="checkbox" name="item_id" value="002"/>
<input type="checkbox" name="item_id" value="002"/>
传递到controller方法中的格式是:001,002,003
Controller方法中可以用String[]接收,定义如下:
public String deleteitem(String[] item_id)throws Exception{
System.out.println(item_id);
}
5.5.7.2 List
List中存放对象,并将定义的List放在包装类中,action使用包装对象接收。
List中对象:
成绩对象
Public class QueryVo {
Private List<Items> itemList;//订单明细
//get/set方法..
}
包装类中定义List对象,并添加get/set方法如下:
页面:
<tr>
<td>
<input type="text" name=" itemList[0].id" value="${item.id}"/>
</td>
<td>
<input type="text" name=" itemList[0].name" value="${item.name }"/>
</td>
<td>
<input type="text" name=" itemList[0].price" value="${item.price}"/>
</td>
</tr>
<tr>
<td>
<input type="text" name=" itemList[1].id" value="${item.id}"/>
</td>
<td>
<input type="text" name=" itemList[1].name" value="${item.name }"/>
</td>
<td>
<input type="text" name=" itemList[1].price" value="${item.price}"/>
</td>
</tr>
Contrller方法定义如下:
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getItemList());
}
5.5.7.3 Map
在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象如下:
Public class QueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
//get/set方法..
}
页面定义如下:
<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>
Contrller方法定义如下:
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}