|spring mvc:基于MVC思想的应用框架的快速入门



|spring mvc:基于MVC思想的应用框架的快速入门
本文插图

导包
在使用SpringMVC时 , 都需要在web.xml中配置一个前端控制器DispatcherServlet , 控制器是一个servlet 。 这个控制器可以把.action结尾的给拦住了 , 拦到controller层(就是上面的处理器) , 处理器处理之后返回处理结果 , 这个处理结果是ModelAndView
springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc.xml springmvc *.action 控制器通过配置文件找到处理器映射器 , 处理器适配器 , 这些都配置在springmvc.xml文件中 , 所以需要在init-param中指定对应的springmvc.xml文件
<!--
1. /* 拦截所有 jsp js png .css 真的全拦截 建议不使用
2. *.action *.do 拦截以do action 结尾的请求 肯定能使用 ERP
3. / 拦截所有 (不包括jsp) (包含.js .png.css) 强烈建议使用 前台 面向消费者 www.jd.com/search /对静态资源放行
-->
springmvc.xml
SpringMVC本身就是Spring的子项目 , 对Spring兼容性很好 , 不需要做很多配置 。
这里只配置一个Controller扫描就可以了 , 让Spring对页面控制层Controller进行管理 。
这个就是指示springmvc.xml去com.huanfeng以及之后的子包进行扫描 , 我们就可以使用注解来配置了
第一个小程序
package com.huanfeng.springmvc.controller; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.web.HttpRequestHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.huanfeng.springmvc.pojo.Items; @Controller public class ItemController { @RequestMapping(valuehttp://news.hoteastday.com/a/= ''/item/itemlist.action'') public ModelAndView itemList(){ // 创建页面需要显示的商品数据 List list = new ArrayList(); list.add(new Items(1, ''小米'', 2399f, new Date(), ''国产!1'')); list.add(new Items(2, ''华为'', 2399f, new Date(), ''国产!2'')); list.add(new Items(3, ''荣耀'', 2399f, new Date(), ''国产!3'')); list.add(new Items(4, ''Apple'', 2399f, new Date(), ''国外!4'')); ModelAndView mav = new ModelAndView(); //数据 mav.addObject(''itemList'', list); mav.setViewName(''/WEB-INF/jsp/itemList.jsp''); return mav; } }这个我们在类上使用了@Controller注解 , 这个就表示了将这个类对象给spring管理了 。 然后我们在这个类中的方法中配置了@RequestMapping(valuehttp://news.hoteastday.com/a/= ''/item/itemlist.action'') , 这个意思是说浏览器器如果发访问/item/itemlist.action就会执行这个方法 , 这个方法返回一个ModelAndView就是模型和视图 , 我们可以在ModelAndView中添加itemList数据 , 以及itemList.jsp视图,然后返回mav,这两个步骤就像是存入request域中并且转发一样
ModelAndView是spring mvc创造的 , 我们可以应用它存放数据和视图
之后浏览器访问:
http://localhost:8080/spring_mvc/item/itemlist.action就可以执行了
架构分析

|spring mvc:基于MVC思想的应用框架的快速入门
本文插图


|spring mvc:基于MVC思想的应用框架的快速入门
本文插图

http://localhost:8080/spring_mvc/item/itemlist.action
用户请求 , 被前端控制器拦截 , 它会先去找处理器映射器 , 让它帮忙去spring容器中找和请求item/itemlist.action对应的方法 , 找到之后返回包名+类名+方法名形式的Handler , 然后前端控制器 , 可以使用这个Handler去处理器适配器请求执行这个Handler , 经过5、6步之后就得到了ModelAndView , 得到之后 , 它请求视图解析器去解析视图 , 也就是根据ModelAndView的jsp的地址获取到对应的jsp页面 , 然后返回这个页面的view对象(包含数据+页面) , 然后第十步经过渲染 , 就会生成html页面 , 返回给用户
上面是架构 , 我们只需要配置前端控制器 , 然后自己写处理器中的内容 , 然后我们还要写视图 , 也就是jsp页面
1、用户发送请求至前端控制器DispatcherServlet
2、DispatcherServlet收到请求调用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响应用户
1.1. 组件说明
以下组件通常使用框架提供实现:
u DispatcherServlet:前端控制器
用户请求到达前端控制器 , 它就相当于mvc模式中的c , dispatcherServlet是整个流程控制的中心 , 由它调用其它组件处理用户的请求 , dispatcherServlet的存在降低了组件之间的耦合性 。
u HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求url找到Handler即处理器 , springmvc提供了不同的映射器实现不同的映射方式 , 例如:配置文件方式 , 实现接口方式 , 注解方式等 。
u Handler:处理器
Handler 是继DispatcherServlet前端控制器的后端控制器 , 在DispatcherServlet的控制下Handler对具体的用户请求进行处理 。
由于Handler涉及到具体的用户业务请求 , 所以一般情况需要程序员根据业务需求开发Handler 。
u HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行 , 这是适配器模式的应用 , 通过扩展适配器可以对更多类型的处理器进行执行 。
下图是许多不同的适配器 , 最终都可以使用usb接口连接
|spring mvc:基于MVC思想的应用框架的快速入门
本文插图


u ViewResolver:视图解析器
View Resolver负责将处理结果生成View视图 , View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址 , 在生成View视图对象 , 最后对View进行渲染将处理结果通过页面展示给用户 。
u View:视图
springmvc框架提供了很多的View视图类型的支持 , 包括:jstlView、freemarkerView、pdfView等 。 我们最常用的视图就是jsp 。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户 , 需要由程序员根据业务需求开发具体的页面 。
|spring mvc:基于MVC思想的应用框架的快速入门
本文插图

我们可以看到有三大组件 , 处理器映射器、处理器适配器、视图解析器这三个 , 我们可以看到这三个组件我们并没有配置 , 之所以这样是因为spring mvc都会使用默认的来帮助我们来配置 , 它使用的默认的三个组件是:
DefaultAnnotationHandlerMapping( 配置处理器映射器)
AnnotationMethodHandlerAdapter(配置处理器适配器)
InternalResourceViewResolver(视图解析器)
但是DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter这两个都过时了 , 所以我们需要手动配置没有过时的这两个组件RequestMappingHandlerMapping、RequestMappingHandlerAdapter
但是配置这两个组件也比较麻烦 , 我们可以使用使用注解驱动来加载 。 SpringMVC使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter可以在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置 。
在springmvc.xml中配置

|spring mvc:基于MVC思想的应用框架的快速入门
本文插图


我们在前面的时候逻辑视图名需要在controller中返回ModelAndView指定 , 比如逻辑视图名为ItemList , 则最终返回的jsp视图地址:“WEB-INF/jsp/itemList.jsp” , 这样比较麻烦 , 我们可以进行如下的处理:
<bean class=''org.springframework.web.servlet.view.InternalResourceViewResolver''>
<property name=''prefix'' value=''/WEB-INF/jsp/''/>
<property name=''suffix'' value=''.jsp''/>
</bean>
这样我们就可以在setViewName的时候写
|spring mvc:基于MVC思想的应用框架的快速入门
本文插图

整合
整合的第一步:spring+mybatis的整合 , 首先先将mybaitis和spring需要的jar包导入进去
这个我们前面整个过 , 需要完成四个配置文件 , 分别是:
|spring mvc:基于MVC思想的应用框架的快速入门
本文插图

其中db.propertie是用户配置数据库的 , log4j.properties是用户配置日志的 , 在application.xml中我们要进行如下的配置:
其中它需要配置mybaits的工厂 , 这个工厂中需要注入dataSource、还需要配置sqlMapConfig文件 , 之后还需要配置Mapper动态代理扫描 , 配置好了之后 , 它就会自动去存放mapper接口的位置 , 为每一个mapper接口生成动态的实现类 , 这个类中的每一个方法对应着mapper.xml中的sql语句 , 然后我们可以从容器中获取这个mapper实现对象 , 然后用这个对象来执行这个类中的方法 。
然后sqlMapConfig是用于配置mybaitis的 , 这个只需要配置一个别名就可以了 , 其它的都有spring管理 , 它没有什么需要配置的:
然后配置好了之后 , 我们如何才能使得启动服务器之后加载到这些文件呢?需要使用一个监听器 , 来使得启动之后就自动加载spring , 在web.xml中进行配置
contextConfigLocation classpath:applicationContext.xml org.springframework.web.context.ContextLoaderListener 至此spring+mybatis就在web中整合完毕了 , 还剩下spring.mvc , 它不需要整合 , 只需要将springmvc.xml拿过来 , 然后再web.xml中配置好前端控制器就好了
springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc.xml springmvc 然后在applicationContext中配置事务
一套完整的流程
浏览器访问 , 处理器进行处理 , 去servic层 , service层去dao层 , dao层查询数据库 , 获取数据之后 , 返回service , 然后返回控制层 , 最终到jsp页面 , 这就是基本的web开发逻辑
首先application.xml,springmvc.xml,sqlMapConfig.xml、web.xml的四个文件的配置
application.xml
springmvc.xml
配置这个扫描之后ssm包以及子包中的所有子类都会被spring实例化
sqlMapConfig.xml
web.xml
contextConfigLocation classpath:applicationContext.xml org.springframework.web.context.ContextLoaderListener springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc.xml springmvc *.action 控制层
package com.huanfeng.ssm.controller; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.HttpRequestHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import com.huanfeng.ssm.pojo.Items; import com.huanfeng.ssm.pojo.QueryVo; import com.huanfeng.ssm.service.ItemService; @Controller public class ItemController { @Autowired private ItemService itemService; @RequestMapping(valuehttp://news.hoteastday.com/a/= ''/item/itemlist.action'') public ModelAndView itemList(){ //从Mysql中查询 List list = itemService.selectItemsList(); ModelAndView mav = new ModelAndView(); //数据 mav.addObject(''itemList'', list); mav.setViewName(''itemList''); return mav; } }因为控制层需要service的对象 , 所以我们使用@Autowired的方式完成itemService的配置
Service层
package com.huanfeng.ssm.service; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.huanfeng.ssm.dao.ItemsMapper; import com.huanfeng.ssm.pojo.Items; @Service public class ItemServiceImpl implements ItemService { @Autowired private ItemsMapper itemsMapper; //查询商品列表 public List selectItemsList(){ return itemsMapper.selectByExampleWithBLOBs(null); } }在这个层中我们写业务 , 这里并没有什么功能 , 只需要获取到dao层的对象 , itemsMapper就可以执行dao层的方法了 , 因为dao是接口 , 里面的方法都是抽象方法 , 这是因为spring会帮助实例化mapper对象的实现类 。 所以我们要做的就是在service中挑选一个符合我们本次请求业务的方法 , 这里是挑选了
selectByExampleWithBLOBs方法 , 这个方法的详情sql语句可以在mapper.xml中看到
select distinct , from items order by ${orderByClause} 参数绑定之默认参数绑定
在浏览器请求访问的时候 , 往往会携带参数 , 那么我们可以在方法中绑定一些默认的参数 , 这些参数分别是HttpServletRequest、HttpServletResponse、HttpSession、Model , 然后我们就可以使用request.getParameter(''id'')的方式来获取这个请求传递过来的id
想获得Request对象只需要在Controller方法的形参中添加一个参数即可 。 Springmvc框架会自动把Request对象传递给方法 。
处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值 。
1.1.1.1. HttpServletRequest
通过request对象获取请求信息
1.1.1.2. HttpServletResponse
通过response处理响应信息
1.1.1.3. HttpSession
通过session对象得到session中存放的对象
除了ModelAndView以外 , 还可以使用Model来向页面传递数据 ,
Model是一个接口 , 在参数里直接声明model即可 。
如果使用Model则可以不使用ModelAndView对象 , Model对象可以向页面传递数据 , View对象则可以使用String返回值替代 。
不管是Model还是ModelAndView , 其本质都是使用Request对象向jsp传递数据 。
ModelMap是Model接口的实现类 , 也可以通过ModelMap向页面传递数据
使用Model和ModelMap的效果一样 , 如果直接使用Model , springmvc会实例化ModelMap 。
@RequestMapping(''/itemEdit'') public String queryItemById(HttpServletRequest request, ModelMap model) { // 从request中获取请求参数 String strId = request.getParameter(''id''); Integer id = Integer.valueOf(strId); // 根据id查询商品数据 Item item = this.itemService.queryItemById(id); // 把结果传递给页面 // ModelAndView modelAndView = new ModelAndView(); // 把商品数据放在模型中 // modelAndView.addObject(''item'', item); // 设置逻辑视图 // modelAndView.setViewName(''itemEdit''); // 把商品数据放在模型中 model.addAttribute(''item'', item); return ''itemEdit''; } @RequestMapping(''/itemEdit'') public String queryItemById(HttpServletRequest request, Model model) { // 从request中获取请求参数 String strId = request.getParameter(''id''); Integer id = Integer.valueOf(strId); // 根据id查询商品数据 Item item = this.itemService.queryItemById(id); // 把结果传递给页面 // ModelAndView modelAndView = new ModelAndView(); // 把商品数据放在模型中 // modelAndView.addObject(''item'', item); // 设置逻辑视图 // modelAndView.setViewName(''itemEdit''); // 把商品数据放在模型中 model.addAttribute(''item'', item); return ''itemEdit''; } //去修改页面 入参 id @RequestMapping(valuehttp://news.hoteastday.com/a/= ''/itemEdit.action'') public ModelAndView toEdit( HttpServletRequest request,HttpServletResponse response ,HttpSession session,Model model){ String id = request.getParameter(''id''); tems items = itemService.selectItemsById(Integer.parseInt(id)); ModelAndView mav = new ModelAndView(); mav.addObject(''item'', items); mav.setViewName(''editItem''); return mav; }参数绑定之基本类型
在前面传递过来 , 我们仅仅想要一个id而已 , 所以我们可以直接写上id参数 , 这样就可以直接获取这个参数id 。 当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定 。
这样 , 从Request取参数的方法就可以进一步简化 。
参数类型推荐使用包装数据类型 , 因为基础数据类型不可以为null
整形:Integer、int
字符串:String
单精度:Float、float
双精度:Double、double
布尔型:Boolean、boolean
说明:对于布尔类型的参数 , 请求的参数值为true或false 。 或者1或0
请求url:
http://localhost:8080/xxx.action?id=2&status=false
处理器方法:
public String editItem(Model model,Integer id,Boolean status)
public ModelAndView toEdit(Integer id, HttpServletRequest request,HttpServletResponse response ,HttpSession session,Model model){ Items items = itemService.selectItemsById(id); ModelAndView mav = new ModelAndView(); //数据 mav.addObject(''item'', items); mav.setViewName(''editItem''); return mav; }这样就可以直接将请求的id和参数id对应上 , 但是我们需要注意的是 , 我们必须要二者名字一样 , 如果二者的名字不一致也没有关系 , 我们可以配置一下:
public ModelAndView toEdit(@RequestParam(valuehttp://news.hoteastday.com/a/= ''id'',required = false,defaultValuehttp://news.hoteastday.com/a/= ''1'') Integer idid......)
6.2.2. @RequestParam 使用@RequestParam常用于处理简单类型的绑定 。value:参数名字 , 即入参的请求参数名字 , 如value=http://news.hoteastday.com/a/“itemId”表示请求的参数区中的名字为itemId的参数的值将传入 required:是否必须 , 默认是true , 表示请求中一定要有相应的参数 , 否则将报错 TTP Status 400 - Required Integer parameter'XXXX' is not present defaultValue:默认值 , 表示如果请求中没有同名参数时的默认值 定义如下: @RequestMapping(''/itemEdit'') public String queryItemById(@RequestParam(valuehttp://news.hoteastday.com/a/= ''itemId'', required = true, defaultValuehttp://news.hoteastday.com/a/= ''1'') Integer id, ModelMap modelMap) { // 根据id查询商品数据 Item item = this.itemService.queryItemById(id); // 把商品数据放在模型中 modelMap.addAttribute(''item'', item); return ''itemEdit''; }1.1. 绑定pojo类型
1.1.1. 需求
将页面修改后的商品信息保存到数据库中 。
1.1.2. 需求分析
请求的url:/updateItem.action
参数:表单中的数据 。
【|spring mvc:基于MVC思想的应用框架的快速入门】响应内容:更新成功页面
1.1.3. 使用pojo接收表单数据
如果提交的参数很多 , 或者提交的表单中的内容很多的时候,可以使用简单类型接收数据,也可以使用pojo接收数据 。
要求:pojo对象中的属性名和表单中input的name属性一致 。
请求的参数名称和pojo的属性名称一致 , 会自动将请求参数赋值给pojo的属性 。
public ModelAndView updateitem(QueryVo vo){ //修改 itemService.updateItemsById(vo.getItems()); ModelAndView mav = new ModelAndView(); mav.setViewName(''success''); return mav;注意:
提交的表单中不要有日期类型的数据 , 否则会报400错误 。 如果想提交日期类型的数据需要用到后面的自定义参数绑定的内容 。
乱码问题
乱码问题只需要配置一个编码拦截器 , 然后拦截的内容和前端控制器一样就好了 , 然后给这个拦截类配置一个参数encoding使用UTF-8就可以了 , 在web.xml
encoding org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 encoding *.action 对于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编码
传递自定义pojo(pojo里面还有pojo)作为参数
package com.huanfeng.ssm.pojo; public class QueryVo { private Items items; public Items getItems() { return items; } public void setItems(Items items) { this.items = items; } }比如现在参数是pojo:
@RequestMapping(valuehttp://news.hoteastday.com/a/= ''/updateitem.action'') public ModelAndView updateitem(QueryVo vo){ //修改 itemService.updateItemsById(items); ModelAndView mav = new ModelAndView(); mav.setViewName(''success''); return mav; }那么我们就需要将参数的名称和pojo中的一致 , 原来的参数名为:
商品名称 商品价格 如果此时要是使用QueryVo那么就不能完成自动的映射 , 因为二者并不是一致的 , 所以需要修改成下面的形式:
商品名称 商品价格 自定义传参
在以上我们学习了诸多的参数绑定 , 只要我们保证清楚参数和pojo的参数名是一致的 , 那么就可以解决这个问题 , 这些都是自动的参数绑定 , spring可以帮助我们完成 , 但是有的参数是不可以绑定的 , 可能会出问题:
由于日期数据有很多种格式 , springmvc没办法把字符串转换成日期类型 。 所以需要自定义参数绑定 。
前端控制器接收到请求后 , 找到注解形式的处理器适配器 , 对RequestMapping标记的方法进行适配 , 并对方法中的形参进行参数绑定 。 可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定 。
一般使用<mvc:annotation-driven/>注解驱动加载处理器适配器 , 可以在此标签上进行配置 。
conversionServiceFactoryBean表示转换器工厂 , 这里我们可以在list中配置多个转换器 , 这里只配置一个DateConveter , 然后将转换器注入给Converters
转换器的具体转换操作需要我们自己来实现 , 我们这里实现了Converter,就表示一个转换器了 , 然后转换器中泛型<S,T>,S表示请求传递的类型(一般是String),T表示我们想转成的类型 , 这里我们使用Data , 这样在item的pojo中 , 只有time是这个类型 , 也就是只有页面传递过来的time会作为source传进来 , 我们可以内部处理它 , 然后将它返回 , 这样它就会自动被赋值给pojo了 。
package com.huanfeng.ssm.conversion; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.core.convert.converter.Converter; public class DateConveter implements Converter{ public Date convert(String source) { System.out.println(source); try { if(null != source){ DateFormat df = new SimpleDateFormat(''yyyy-MM-dd HH:mm:ss''); return df.parse(source); } } catch (Exception e) { } return null; } }我们可以看到
7. springmvc与struts2不同
1、 springmvc的入口是一个servlet即前端控制器 , 而struts2入口是一个filter过滤器 。
2、 springmvc是基于方法开发(一个url对应一个方法) , 请求参数传递到方法的形参 , 可以设计为单例或多例(建议单例) , struts2是基于类开发 , 传递参数是通过类的属性 , 只能设计为多例 。
3、 Struts采用值栈存储请求和响应的数据 , 通过OGNL存取数据 ,springmvc通过参数解析器是将request请求内容解析 , 并给方法形参赋值 , 将数据和视图封装成ModelAndView对象 , 最后又将ModelAndView中的模型数据通过request域传输到页面 。 Jsp视图解析器默认使用jstl 。


    推荐阅读