1.1 Web MVC
mvc设计模式在b/s系统下应用:
1、用户发起request请求至控制器(Controller)
控制接收用户请求的数据,委托给模型进行处理
2、控制器通过模型(Model)处理数据并得到处理结果
模型通常是指业务逻辑
3、模型处理结果返回给控制器
4、控制器将模型数据在视图(View)中展示
web中模型无法将数据直接在视图上显示,需要通过控制器完成。如果在C/S应用中模型是可以将数据在视图中展示的。
5、控制器将视图response响应给用户
通过视图展示给用户要的数据或处理结果。
1.2 Spring web mvc 架构
架构图:
架构流程:
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响应用户
DispatcherServlet前端控制器:接收request,进行response
以下组件通常使用框架提供实现:
-
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等
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
第一步 前端控制器配置
在WEB-INF\web.xml中配置前端控制器
<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
load-on-startup:表示servlet随服务启动;
url-pattern:*.action的请交给DispatcherServlet处理。
contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加
载WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.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成功。
第二步springmvc配置文件
Springmvc默认加载WEB-INF/[前端控制器的名字]-servlet.xml,也可以在前端控制器定义处指定加载的配置文件,如下:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
如上代码,通过contextConfigLocation加载classpath下的springmvc.xml配置文件。
第三部 配置处理器适配器
在springmvc.xml文件配置如下:
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现org.springframework.web.servlet.mvc.Controller 接口的Bean作为
Springmvc的后端控制器;
第四步 处理器开发
public class ItemList1 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
//商品列表
List<Items> itemsList = new ArrayList<Items>();
itemsList.add(items_1);
//创建modelAndView准备填充数据、设置视图
ModelAndView modelAndView = new ModelAndView();
//填充数据
modelAndView.addObject("itemsList", itemsList);
//视图
modelAndView.setViewName("order/itemsList")
return modelAndView;
}
}
org.springframework.web.servlet.mvc.Controller:处理器必须实现Controller 接口。
ModelAndView:包含了模型数据及逻辑视图名
第五步 配置处理器映射器
在springmvc.xml文件配置如下:
<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 ">
<!-- 处理器映射器 -->
<!-- 根据bean的name进行查找Handler 将action的url配置在bean的name中 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
BeanNameUrlHandlerMapping:表示将定义的Bean名字作为请求的url,需要将编写的controller在spring容器中进行配置,且指定bean的name为请求的url,且必须以.action结尾。
第六步 处理器配置
在springmvc.xml文件配置如下:
<!-- controller配置 -->
<bean name="/items1.action" id="itemList1"
class="cn.itcast.springmvc.controller.first.ItemList1"/>
name="/items1.action":前边配置的处理器映射器为BeanNameUrlHandlerMapping,如果请求的URL 为“上下文/items1.action”将会成功映射到ItemList1控制器。
第七步 配置视图解析器
在springmvc.xml文件配置如下:
<!-- ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
InternalResourceViewResolver:支持JSP视图解析
viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,所以classpath中必须包含jstl的相关jar 包;
prefix 和suffix:查找视图页面的前缀和后缀,最终视图的址为:
前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址 “WEB-INF/jsp/hello.jsp”
非注解处理器和适配器
HandlerMapping处理器映射器:
HandlerMapping 负责根据request请求找到对应的Handler处理器及Interceptor拦截器,将它们封装在HandlerExecutionChain 对象中给前端控制器返回。
- BeanNameUrlHandlerMapping
BeanNameUrl处理器映射器,根据请求的url与spring容器中定义的bean的name进行匹配,从而从spring容器中找到bean实例。
<!—beanName Url映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
- SimpleUrlHandlerMapping
simpleUrlHandlerMapping是BeanNameUrlHandlerMapping的增强版本,它可以将url和处理器bean的id进行统一映射配置。
<!—简单url映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/items1.action">controller的bean id</prop>
<prop key="/items2.action">controller的bean id</prop>
</props>
</property>
</bean>
HandlerAdapter处理器适配器:
HandlerAdapter会根据适配器接口对后端控制器进行包装(适配),包装后即可对处理器进行执行,通过扩展处理器适配器可以执行多种类型的处理器,这里使用了适配器设计模式。
- SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter简单控制器处理器适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean通过此适配器进行适配、执行。
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
- HttpRequestHandlerAdapter
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 联想笔记本电脑!");
itemsList.add(items_1);
// 填充数据
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串");
注解映射器和适配器
组件扫描器:
使用组件扫描器省去在spring容器配置每个controller类的繁琐。使用<context:component-scan自动扫描标记@controller的控制器类,配置如下:
<!-- 扫描controller注解,多个包中间使用半角逗号分隔 -->
<context:component-scan base-package="cn.itcast.springmvc.controller.first"/>
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到处理器功能方法的映射
RequestMappingHandlerAdapter:
注解式处理器适配器,对标记@ResquestMapping的方法进行适配。
从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<mvc:annotation-driven>
springmvc使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter,
可在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。
开发注解Handler:
使用注解的映射器和注解的适配器。(注解的映射器和注解的适配器必须配对使用)
//使用Controller标识 它是一个控制器
@Controller
public class ItemsController3 {
//商品查询列表
//@RequestMapping实现 对queryItems方法和url进行映射,一个方法对应一个url
//一般建议将url和方法写成一样
@RequestMapping("/queryItems")
public ModelAndView queryItems()throws Exception{
//调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
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();
//相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList);
//指定视图
modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
return modelAndView;
}
在spring容器中加载Handler:
<context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>
视图解析器配置前缀和后缀:
第一步:整合dao层
mybatis和spring整合,通过spring管理mapper接口。
使用mapper的扫描器自动扫描mapper接口在spring中进行注册。
第二步:整合service层
通过spring管理 service接口。
使用配置方式将service接口配置在spring配置文件中。
实现事务控制。
第三步:整合springmvc
由于springmvc是spring的模块,不需要整合。
mybatis和spring进行整合
applicationContext-dao.xml
配置:
数据源
SqlSessionFactory
mapper扫描器
在spring容器配置service(applicationContext-service.xml)
创建applicationContext-service.xml,文件中配置service。
事务控制(applicationContext-transaction.xml)
在applicationContext-transaction.xml中使用spring声明式事务控制方法。
整合springmvc
创建springmvc.xml文件,配置处理器映射器、适配器、视图解析器。
可以扫描controller、service、…这里让扫描controller,指定controller的包
<context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>
//注解适配器
<mvc:annotation-driven></mvc:annotation-driven>
//视图解析器解析jsp解析,默认使用jstl标签,classpath下的得有jstl的包
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置jsp路径的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 配置jsp路径的后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
加载spring容器
将mapper、service、controller加载到spring容器中。
在web.xml中,添加spring容器监听器,加载spring容器。
@RequestMapping
-
url映射
定义controller方法对应的url,进行处理器映射使用。 -
窄化请求映射
-
限制http请求方法
出于安全性考虑,对http的链接进行方法限制。
如果限制请求为post方法,进行get请求,报错:
@RequestParam
通过@RequestParam对简单类型的参数进行绑定。
如果不使用@RequestParam,要求request传入参数名称和controller方法的形参名称一致,方可绑定成功。
如果使用@RequestParam,不用限制request传入参数名称和controller方法的形参名称一致。
通过required属性指定参数是否必须要传入,如果设置为true,没有传入参数,报下边错误:
controller方法的返回值
-
返回ModelAndView
需要方法结束时,定义ModelAndView,将model和view分别进行设置。 -
返回string
如果controller方法返回string
1、表示返回逻辑视图名。
真正视图(jsp路径)=前缀+逻辑视图名+后缀
2、redirect重定向
商品修改提交后,重定向到商品查询列表。
redirect重定向特点:浏览器地址栏中的url会变化。修改提交的request数据无法传到重定向的地址。因为重定向后重新进行request(request无法共享)
3、forward页面转发
通过forward进行页面转发,浏览器地址栏url不变,request可以共享。
-
返回void
在controller方法形参上可以定义request和response,使用request或response指定响应结果:
1、使用request转向页面,如下:
request.getRequestDispatcher(“页面路径”).forward(request, response);
2、也可以通过response页面重定向:
response.sendRedirect(“url”)
3、也可以通过response指定响应结果,例如响应json数据如下:
response.setCharacterEncoding(“utf-8”);
response.setContentType(“application/json;charset=utf-8”);
response.getWriter().write(“json串”);
post乱码
在web.xml添加post乱码filter
<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>
springmvc中对多部件类型解析
在 页面form中提交enctype="multipart/form-data"的数据时,需要springmvc对multipart类型的数据进行解析
在springmvc.xml中配置multipart类型解析器。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
<property name="maxUploadSize">
<value>32505856</value><!-- 上传文件大小限制为31M,31*1024*1024 -->
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
json数据交互
1、请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不太方便。
2、请求key/value、输出json。此方法比较常用。
配置json转换器
在注解适配器中加入messageConverters
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
注意:如果使用<mvc:annotation-driven /> 则不用定义上边的内容。
RESTful支持
RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
RESTful(即Representational State Transfer的缩写)其实是一个开发理念,是对http的很好的诠释。
1、对url进行规范,写RESTful格式的url
非REST的url:http://…/queryItems.action?id=001&type=T01
REST的url风格:http://…/items/001
特点:url简洁,将参数通过url传到服务端
2、http的方法规范
不管是删除、添加、更新。。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加。。。
后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加。
3、对http的contentType规范
请求时指定contentType,要json数据,设置成json格式的type。。
REST的例子
定义方法,进行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不用指定名称。
REST方法的前端控制器配置
在web.xml配置:
springmvc和struts2的区别
1、springmvc基于方法开发的,struts2基于类开发的。
springmvc将url和controller方法映射。映射成功后springmvc生成一个Handler对象,对象中只包括了一个method。
方法执行结束,形参数据销毁。
springmvc的controller开发类似service开发。
2、springmvc可以进行单例开发,并且建议使用单例开发,struts2通过类的成员变量接收参数,无法使用单例,只能使用多例。
3、经过实际测试,struts2速度慢,在于使用struts标签,如果使用struts建议使用jstl。