一、SpringMVC介绍
1.SpringMVC框架:
2.SpringMVC架构:
2.1 架构图:
2.2 架构说明:
- 1.用户发送请求至前端控制器
DispatchServlet
- 2.
DispatchServlet
收到请求调用处理器映射器HandlerMapping
- 3.处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给
DispatcherServlet
。 - 4.
DispatcherServlet
通过HandlerAdapter
处理器适配器调用处理器 - 5.执行处理器(Controller,也叫后端控制器)
- 6.Controller执行完成返回
ModelAndView
- 7.
HandlerAdapter
将controller执行结果ModelAndView
返回给DispatcherServlet
- 8.
DispatcherServlet
将ModelAndView
传给ViewReslover
视图解析器 - 9.
ViewReslover
解析后返回具体View - 10.
DispatcherServlet
对View进行渲染视图(即将模型数据填充至视图中) - 11.
DispatcherServlet
响应用户
2.3 组件说明:
以下组件通常使用框架提供的实现:
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Handler:处理器
Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
==由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler==
HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
View Resolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等
==一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面==
二、入门程序
1.项目介绍:
1.1 需求:==实现商品查询列表功能==
1.2 开发环境装备:Eclipse+tomcat
1.3 建立一个WEB项目
为了让在Eclipse中建立的项目能够在MyEclipse中也可以导入,做以下修改:
1.4 导入相关jar包:
需要导入的包(项目最终所有的jar包):
2.配置前端控制器
|
|
3.配置处理器适配器
3.1 在springmvc.xml中进行如下配置:
|
|
3.2 编写Handler(Controller):
因为处理器适配器使用的是
SimpleControllerHandlerAdapter
,所以Handler必须实现Controller接口。123456789101112131415161718192021222324public class ItemsController1 implements Controller{public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {// 创建静态数据List<Items> itemsList = new ArrayList<>();Items item1 = new Items();item1.setName("联想笔记本");item1.setPrice(6000f);item1.setDetail("ThinkPad T430 联想笔记本电脑");Items item2 = new Items();item2.setName("苹果手机");item2.setPrice(5000f);item2.setDetail("IPhone6 64G 黑色");itemsList.add(item1);itemsList.add(item2);// 返回ModelAndViewModelAndView modelAndView = new ModelAndView();// 相当于request的setAttribute方法modelAndView.addObject("itemsList",itemsList);// 指定视图modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");return modelAndView;}}视图编写:
4.配置处理器映射器
4.1 在springmvc.xml中进行如下配置:
|
|
4.2 配置Handler:
|
|
5.配置视图解析器
5.1 在springmvc.xml中进行如下配置:
|
|
5.2 访问Url:
http://localhost:8088/SpringMVCProduct/queryItems.action
三、非注解的处理器映射器和适配器
1.映射器
1.1 BeanNameUrlHandlerMapping
|
|
1.2 SimpleUrlHandlerMapping
|
|
==多个映射器可以共存==
2.适配器
2.1 SimpleControllerHandlerAdapter
- 要求编写的Handler实现Controller接口(
前面已经示例
)
2.2 HttpRequestHandlerAdapter
配置:
12<bean id="itemsController2" class="com.ssm.controller.ItemsController2"/><bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>要求编写的Handler实现HttpRequestHandler接口
具体实现:
123456789101112131415161718192021public class ItemsController2 implements HttpRequestHandler{public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 创建静态数据List<Items> itemsList = new ArrayList<>();Items item1 = new Items();item1.setName("联想笔记本");item1.setPrice(6000f);item1.setDetail("ThinkPad T430 联想笔记本电脑");Items item2 = new Items();item2.setName("苹果手机");item2.setPrice(5000f);item2.setDetail("IPhone6 64G 黑色");itemsList.add(item1);itemsList.add(item2);// 设置模型数据request.setAttribute("itemsList",itemsList);// 设置转发的视图request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward(request, response);}}==多个适配器可以共存,也可以不写,因为springmvc提供了一些默认的配置==
==在spring-webmvc的jar包的org.springframework.web.servlet包中DispatcherServlet.properties中提供了系统的一些默认配置。==
四、注解的处理器映射器和适配器
spring3.1之前:
映射器:
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
适配器:
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
spring3.1之后:
映射器:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
适配器:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
1.配置注解映射器和注解适配器
|
|
2.Handler开发
|
|
3.配置Handler Bean:
|
|
五、视图解析器配置前缀和后缀
1.配置
|
|
2.指定视图
|
|
六、SpringMVC和MyBatis整合:
1.需求:==使用SpringMVC和MyBatis完成商品列表查询==:
2.整合思路:
2.1 整合Dao层:
- mybatis和spring整合,通过spring管理mapper接口
- 使用mapper的扫描器自动扫描mapper接口在spring中进行注册
2.2 整合service层:
- 通过spring管理service接口
- 使用配置方式将service接口配置在spring配置文件中
- 实现事务控制
2.3 整合springmvc
- 由于springmvc是spring的模块,不需要整合
3.搭建环境
3.1 所需要的jar包
- 数据库驱动包、mybatis的jar包、mybatis和spring整合包、log4j包、dbcp数据库连接池包、spring的jar包、jstl包
3.2 工程结构:
3.3 最终代码
4.整合dao
mybatis和spring整合:
4.1 sqlMapConfig.xml:
|
|
4.2 applicationContext-dao.xml
配置:数据源、SqlSessionFactory、mapper扫描器
|
|
4.3 逆向工程生成po类及mapper(单表CRUD)
- 过程如附录一
4.4 手动定义商品查询mapper
针对综合查询mapper,一般情况会有关联查询,建议自定义mapper
ItemsMapperCustom.java
123public interface ItemsMapperCustom {public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception;}ItemsMapperCustom.xml
123456789101112131415161718<mapper namespace="com.ssm.mapper.ItemsMapperCustom"><sql id="query_items_where"><!-- 使用动态sql,通过if判断,满足条件进行sql拼接 --><if test="itemsCustom!=null"><if test="itemsCustom.name!=null and itemsCustom.name!=''">items.name LIKE '%${itemsCustom.name}%'</if></if></sql><!-- 商品列表查询 --><select id="findItemsList" parameterType="com.ssm.po.ItemsQueryVo" resultType="com.ssm.po.ItemsCustom">SELECT * FROM items<where><include refid="query_items_where"></include></where></select></mapper>ItemsCustom.java—商品的扩展类(不要在mybatis生成的po类中扩展)
ItemsQueryVo.java—商品的包装类
5.整合service
让spring管理service接口
5.1 定义service接口
|
|
实现接口:
|
|
5.2 在Spring容器中配置Service
创建applicationContext-service.xml,并配置service接口
12<!-- 定义商品管理的service --><bean id="itemsService" class="com.ssm.service.ItemsService"></bean>
5.3 事务控制—applicationContext-transaction.xml
在applicationContext-transaction.xml中使用spring的声明式方法进行配置
123456789101112131415161718192021222324<beans><!-- 事务管理器,对mybatis操作数据库事务控制,spring使用jdbc的事务控制类 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 数据源 --><property name="dataSource" ref="dataSource"></property></bean><!-- 通知 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!-- 传播行为 --><tx:method name="save*" propagation="REQUIRED"/><tx:method name="delete*" propagation="REQUIRED"/><tx:method name="insert*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="find*" propagation="SUPPORTS" read-only="true"/><tx:method name="get*" propagation="SUPPORTS" read-only="true"/><tx:method name="select*" propagation="SUPPORTS" read-only="true"/></tx:attributes></tx:advice><!-- aop --><aop:config><aop:advisor advice-ref="txAdvice" pointcut="execution(* com.ssm.service.impl.*.*(..))"/></aop:config></beans>
6.整合springmvc
6.1 创建springmvc.xml文件,配置处理器映射器、适配器、视图解析器
|
|
6.2 配置前端控制器
- 参考入门程序中的配置
6.3 开发controller
|
|
6.4 编写jsp:itemsList.jsp
7.加载spring容器
将mapper、service、controller加载到spring容器中
建议使用通配符加载上面的配置文件
在web.xml中,添加spring容器监听器,加载spring容器
12345678<!-- 加载spring容器 --><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/classes/spring/applicationContext-*.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
七、商品修改功能的开发
1.分析:
- 进入商品查询列表界面
- 点击修改,进入商品修改页面(商品详细信息根据id从数据库查询)
- 在商品修改页面,修改商品信息后,点击提交
2.开发mapper
mapper:
根据id查询商品信息
根据id更新items表的数据
不用开发,使用逆向工程生成的
3.开发service
接口功能:
根据id查询商品信息
修改商品信息
12345678public interface ItemsService {// 商品查询列表public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception;// 根据id查询商品信息public ItemsCustom findItemsById(int id) throws Exception;// 修改商品信息public void updateItems(int id, ItemsCustom itemsCustom);}接口实现:
1234567891011121314151617181920212223242526public class ItemsServiceImpl implements ItemsService {private ItemsMapperCustom itemsMapperCustom;private ItemsMapper itemsMapper;public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo)throws Exception{// 通过itemsMapperCustom查询数据库return itemsMapperCustom.findItemsList(itemsQueryVo);}public ItemsCustom findItemsById(Integer id) throws Exception {Items items = itemsMapper.selectByPrimaryKey(id);// 中间对商品信息进行业务处理...ItemsCustom itemsCustom = new ItemsCustom();// 将items的值拷贝到itemsCustomBeanUtils.copyProperties(items, itemsCustom);return itemsCustom;}public void updateItems(Integer id, ItemsCustom itemsCustom) throws Exception {// 添加业务校验,通常在service接口对关键数据进行校验itemsCustom.setId(id);itemsMapper.updateByPrimaryKeyWithBLOBs(itemsCustom);}}
4.开发controller
方法:
商品详细信息展示
|
|
商品详细信息修改提交
|
|
八、@RequestMapping
- 定义controller方法对应的url,进行处理器映射使用。
1.URL路径映射:
@RequestMapping(value="/item")或@RequestMapping("/item)
- value的值是数组,可以将多个url映射到同一个方法
2.窄化请求映射:
在class上添加@RequestMapping(url)指定通用请求前缀,限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。
例如:
12345678// @RequestMapping放在类名上边,设置请求前缀"/item")(// @RequestMapping放在方法名上边,如下:"/queryItem ")(// 最终访问地址为:/item/queryItem
3.限制请求方法:
@RequestMapping(method = RequestMethod.GET)
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
九、Controller方法的返回值:
1.返回ModelAndView:
- controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。
|
|
2.返回String:
2.1 逻辑视图名:
|
|
2.2 Redirect重定向:
- Contrller方法返回结果重定向到一个url地址,如下商品修改提交后重定向到商品查询方法,参数无法带到商品查询方法中。
|
|
- redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的request和response。由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以
/item/queryItem.action
后边加参数,如:/item/queryItem?key&value
2.3 forward转发:
- controller方法执行后继续执行另一个controller方法,如下商品修改提交后转向到商品修改页面,修改商品的id参数可以带到商品修改方法中。
|
|
- forward方式相当于“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,而是和转发前的请求共用一个request和response。所以转发前请求的参数在转发后仍然可以读取到。
3.返回void:
在controller方法形参上可以定义request和response,使用request或response指定响应结果:
1public void editItemsSubmit(HttpServletRequest request, HttpServletResponse response) throws Exception
3.1 使用request转向页面:
|
|
3.2 通过response页面重定向:
|
|
3.3 通过response指定响应结果,例如响应json数据如下:
|
|
十、参数绑定:
- 处理器适配器在执行Handler之前需要把http请求的key/value数据绑定到Handler方法形参数上。
1. 默认支持的参数类型
- 处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值。
1.1 HttpServletRequest
- 通过request对象获取请求信息
1.2 HttpServletResponse
- 通过response处理响应信息
1.3 HttpSession
- 通过session对象得到session中存放的对象
1.4 Model/ModelMap
- ModelMap是Model接口的实现类,通过Model或ModelMap向页面传递数据
2. 参数绑定介绍
- 注解适配器对RequestMapping标记的方法进行适配,对方法中的形参会进行参数绑定,早期springmvc采用PropertyEditor(属性编辑器)进行参数绑定将request请求的参数绑定到方法形参上,3.X之后springmvc就开始使用Converter进行参数绑定。
2.1 简单类型:
当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。
使用@RequestParam常用于处理简单类型的绑定
12// value:请求参数名,required:是否必须,默认true,defaultValue:默认值public String editItem(@RequestParam(value="item_id",required=true) String id) {}
2.2 pojo类型:
简单pojo:将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中
1234567// 页面定义如下;<input type="text" name="name"/><input type="text" name="price"/>// Contrller方法定义如下:"/editItemSubmit")(public String editItemSubmit(Items items)throws Exception{}// 请求的参数名称和pojo的属性名称一致,会自动将请求参数赋值给pojo的属性。包装pojo:
123456789// 包装对象定义如下: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{}
2.3 自定义参数绑定:
需求:根据业务需求自定义日期格式进行参数绑定。将日期字符串转成java.util.Date。
自定义参数Converter
123456789101112public class CustomDateConverter implements Converter<String, Date> {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;}}注入配置:
123456789<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven><bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><!-- 转换器 --><property name="converters"><list><bean class="com.ssm.controller.converter.CustomDateConverter"/></list></property></bean>
2.4 集合类型:
字符串数组:
1234567// 页面定义如下:<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 ExceptionList:
123456789101112131415161718192021222324252627// List中存放对象,并将定义的List放在包装类中,action使用包装对象接收。Public class QueryVo {Private List<Items> itemList;//商品列表//get/set方法..}// 页面定义如下:<tr><td><input type="text" name=" itemsList[0].id" value="${item.id}"/></td><td><input type="text" name=" itemsList[0].name" value="${item.name }"/></td><td><input type="text" name=" itemsList[0].price" value="${item.price}"/></td></tr><tr><td><input type="text" name=" itemsList[1].id" value="${item.id}"/></td><td><input type="text" name=" itemsList[1].name" value="${item.name }"/></td><td><input type="text" name=" itemsList[1].price" value="${item.price}"/></td></tr>// 动态jsp代码如下:<c:forEach items="${itemsList }" var="item" varStatus="s"><tr><td><input type="text" name="itemsList[${s.index }].name" value="${item.name }"/></td><td><input type="text" name="itemsList[${s.index }].price" value="${item.price }"/></td>..........</tr></c:forEach>// Contrller方法定义如下:public String useraddsubmit(Model model,QueryVo queryVo)throws Exception;Map:
12345678910111213141516// 在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。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;
十一、校验:
1.校验说明:
- b/s系统中对http请求数据的校验多数在客户端进行,这也是出于简单及用户体验性上考虑,但是在一些安全性要求高的系统中服务端校验是不可缺少的,本节主要学习springmvc实现控制层添加校验。
- 控制层Controller:校验页面请求参数的合法性。
- 业务层Service:主要校验关键业务参数,仅限于service接口中使用的参数。
- 持久层Dao:一般不校验。
2.SpringMVC校验:
- Spring3支持JSR-303验证框架,JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,官方参考实现是Hibernate Validator(与Hibernate ORM 没有关系),JSR 303 用于对Java Bean 中的字段的值进行验证。
2.1 需求:
- 在商品信息修改提交时对商品信息内容进行校验,例如商品名称必须输入,价格合法性校验。
2.2 加入相关的jar包:
2.3 配置validator:
|
|
2.4 将validator加到处理器适配器
|
|
2.5 添加校验规则:
|
|
2.6 错误消息文件CustomValidationMessages.properties
|
|
- 如果在eclipse中编辑properties文件无法看到中文则添加propedit插件。
2.7 捕获错误:
|
|
2.8 分组校验:
如果两处校验使用同一个Items类则可以设定校验分组,通过分组校验可以对每处的校验个性化。
实际需求:商品修改只校验商品名称长度
定义分组:
1234public interface ValidGroup1 {}public interface ValidGroup2 {}pojo类指定分组校验:
121,max=10,message="{items.name.length.error}",groups={ValidGroup1.class})(min=private String name;controller方法修改:
12"/editItemsSubmit")(public String editItemsSubmit(Model model, HttpServletRequest request,Integer id,@Validated(value=ValidGroup1.class) ItemsCustom itemsCustom, BindingResult bindingResult) throws Exception在@Validated中添加value={ValidGroup1.class}表示商品修改使用了ValidGroup1分组校验规则,也可以指定多个分组中间用逗号分隔:
1(value={ValidGroup1.class,ValidGroup2.class })
2.9 校验注解:
|
|
十二、数据回显:
1.需求:
- 表单提交失败需要再回到表单页面重新填写,原来提交的数据需要重新在页面上显示。
2. 简单数据类型:
对于简单数据类型,如:Integer、String、Float等使用Model将传入的参数再放到request域实现数据回显。
model.addAttribute("id", id)
3.pojo类型:
- springmvc默认支持pojo数据回显,springmvc自动将形参中的pojo重新放回request域中,request的key为pojo的类名(首字母小写),如下:
|
|
4.@ModelAttribute作用
对于页面key和controller中方法的pojo形参名不一致的情况,可以使用@ModelAttribute完成数据回显。此作用可实现数据回显效果。
1234567891011121314151617181920@RequestMapping("/editItemsSubmit")public String editItemsSubmit(Model model,Integer id,@ModelAttribute("items") @Validated(value=ValidGroup1.class) ItemsCustom itemsCustom, BindingResult bindingResult) throws Exception{if(bindingResult.hasErrors()){List<ObjectError> allErrors = bindingResult.getAllErrors();model.addAttribute("allErrors", allErrors);return "items/editItems";}itemService.updateItems(id, itemsCustom);return "forward:queryItems.action";}// jsp页面<tr><td>商品名称</td><td><input type="text" name="name" value="${items.name }"/></td></tr><tr><td>商品价格</td><td><input type="text" name="price" value="${items.price }"/></td></tr>// 如果不用@ModelAttribute也可以使用model.addAttribute("item", itemsCustom)完成数据回显。将方法返回值暴露为模型数据传到视图页面
123456789101112131415// Controller方法://商品分类@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>
十三、异常处理器
- springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。
1.异常处理思路:
系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
2.自定义异常类:
2.1自定义异常类:
|
|
2.2自定义异常处理类:
|
|
3.将异常处理类添加到spring容器:
|
|
4.Controller方法抛出异常:
|
|
5.异常显示页面:
|
|
十四、图片上传
1.需求
- 在修改商品页面,添加上传商品图片功能。
2.配置虚拟路径:
2.1 Tomcat配置:
- 在tomcat下conf/server.xml中添加:
|
|
2.2 Eclipse配置:
- ==实际项目中一般会采用独立的图片服务器,且图片目录最好按日期建立,可以提高io性能==
2.配置springmvc对多部件类型的解析
|
|
3.相关的Jar包
|
|
4.图片上传:
- Controller方法:
|
|
- jsp页面:
|
|
为了防止重复提交时,因为未选择图片,而将原来的图片信息删除,可以添加如下代码:
1<input type="hidden" name="pic" value="${items.pic }" />
十五、Json数据交互:
1.注解说明:
1.1 @RequestBody:
- @RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。
- 本例子应用:@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象
1.2 @ResponseBody
- 用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
- 本例子应用:@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端
2.准备环境:
2.1 添加相关的Jar包:
2.2 springmvc配置:
|
|
- ==注意:如果使用 则不用定义上边的内容。==
3.请求json响应json:
|
|
4.请求key/value响应json:
|
|
- jsonTest.jsp
|
|
十六、RESTful支持
1.什么是RESTful
- RESTful(即Representational State Transfer的缩写)其实是一个开发理念,是对http的很好的诠释。
1.1 对Url进行规范,写RESTful格式的Url
REST的url风格:http://....../items/001
特点:url简洁,将参数通过url传到服务端
1.2 对http的方法规范
- 不管是删除、添加、更新。。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加……
- 后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加。
1.3 对http的contentType规范
- 请求时指定contentType,要json数据,设置成json格式的type…..
==注意:实现项目只是对Url进行规范==
2.使用示例:
2.1 需求:
- 查询商品信息,返回json数据。
2.2 Controller方法:
- 定义方法,进行url映射使用REST风格的url,将查询商品信息的id传入controller 。输出json使用@ResponseBody将java对象输出json。
|
|
- @RequestMapping(value=”/ itemsView/{id}”):{×××}占位符,请求的URL可以是“/viewItems/1”或“/viewItems/2”,通过在方法中使用@PathVariable获取{×××}中的×××变量
- @PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。如果RequestMapping中表示为”/ itemsView /{id}”,id和形参名称一致,@PathVariable不用指定名称。
2.3 前端控制器配置:
- 因为REST风格的url没有.action后缀,所以需要重新配置前端控制器;可以和原来配置的前端控制器共存。
|
|
2.4 静态资源解析:
- 同样REST风格的url也会影响到静态资源的获取,可以在springmvc.xml中通过以下配置解决:
|
|
十七、拦截器:
1.定义:
- Spring Web MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
2.拦截器实现:
|
|
3.拦截器配置:
3.1 针对某种mapping配置拦截器
|
|
3.2 针对所有mapping配置全局拦截器
|
|
4.拦截流程测试:
- HandlerInterceptor1和HandlerInterceptor2配置如上
4.1 正常流程测试:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2,每个拦截器的preHandler方法都返回true(即不拦截)。
运行流程:
12345678HandlerInterceptor1..preHandle..HandlerInterceptor2..preHandle..HandlerInterceptor2..postHandle..HandlerInterceptor1..postHandle..HandlerInterceptor2..afterCompletion..HandlerInterceptor1..afterCompletion..总结:preHandle方法按顺序执行,postHandle和afterCompletion按拦截器配置的逆向顺序执行。
4.2 中断流程测试:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2。
运行流程:
(1). HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,运行流程如下:
HandlerInterceptor1..preHandle..
从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且controller也不执行了。
(2).HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程如下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的postHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且controller也不执行了。
总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用
5.拦截器应用:
5.1 需求:
- 用户请求url
- 拦截器进行拦截校验
- 如果请求的url是公开地址(无需登陆即可访问的url),则放行。
- 如果用户session 不存在跳转到登陆页面。
- 如果用户session存在则放行,继续操作。
5.2 登录Controller实现:
|
|
5.3 登录认证拦截实现:
- 拦截器:
|
|
- 配置:
|
|
- login.jsp
|
|
- itemsList.jsp中添加:
|
|
6.项目整体代码
附录一:MyBatis逆向工程:
db.properties
文件:123456789101112# 数据库驱动jar 路径drive.class.path=/Users/***/Documents/libs/mysql-connector-java-5.1.40/mysql-connector-java-5.1.40-bin.jar# 数据库连接参数jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/ssm1?useUnicode=true&characterEncoding=utf-8&useSSL=falsejdbc.username=rootjdbc.password=root# 包路径配置model.package=com.ssm.podao.package=com.ssm.mapperxml.mapper.package=com.ssm.mappertarget.project=/Users/***/Documents/workspace/j2eespace/SpringMVCProduct/src
DBGenerator.xml
文件:具体配置:http://www.mybatis.org/generator/configreference/xmlconfig.html
1234567891011121314151617181920212223242526272829303132333435363738PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!-- 配置文件路径 --><properties resource="db.properties"/><classPathEntry location="${drive.class.path}" /><context id="DB2Tables" targetRuntime="MyBatis3"><commentGenerator ><property name="suppressAllComments" value="false"/><!-- 是否取消注释 --><property name="suppressDate" value="true" /> <!-- 是否生成注释代时间戳--></commentGenerator><jdbcConnection driverClass="${jdbc.driver}"connectionURL="${jdbc.url}" userId="${jdbc.username}"password="${jdbc.password}"></jdbcConnection><javaTypeResolver><property name="forceBigDecimals" value="false" /></javaTypeResolver><javaModelGenerator targetPackage="${model.package}"targetProject="${target.project}"><property name="enableSubPackages" value="false" /><property name="trimStrings" value="true" /></javaModelGenerator><sqlMapGenerator targetPackage="${xml.mapper.package}"targetProject="${target.project}"><property name="enableSubPackages" value="false" /></sqlMapGenerator><javaClientGenerator type="XMLMAPPER"targetPackage="${dao.package}" targetProject="${target.project}"><property name="enableSubPackages" value="false" /></javaClientGenerator><table tableName="items"></table><table tableName="orders"></table><table tableName="orderdetail"></table><table tableName="user"></table></context></generatorConfiguration>DBGenerator.java
文件:123456789101112public class DBGenerator {public static void main(String[] args) throws Exception{List<String> warnings = new ArrayList<String>();boolean overwrite = true;File configFile = new File("db/DBGenerator.xml");ConfigurationParser cp = new ConfigurationParser(warnings);Configuration config = cp.parseConfiguration(configFile);DefaultShellCallback callback = new DefaultShellCallback(overwrite);MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);myBatisGenerator.generate(null);}}
附录二:请求乱码问题:
POST请求乱码:
12345678910111213<!-- 在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>GET请求乱码:
方法1:修改tomcat配置文件添加编码与工程编码一致:
1<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>方法2:对参数进行重新编码:
1String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8") ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。