由于项目文案须要,因而乎翻阅spring相关资料。顿觉该篇不错详尽易懂,特转载之。javascript
转载出处:css
http://blog.csdn.net/gane_cheng/article/details/52787040html
http://www.ganecheng.tech/blog/52787040.html (浏览效果更好)前端
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson建立。简单来讲,Spring是一个开源的控制反转(Inversion of Control ,IoC)和面向切面(AOP)的容器框架。它的主要目得是简化企业开发。java
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了建立、配置和管理 bean 的方式。程序员
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。经过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。web
MVC是一个设计模式,MVC在B/S系统 下的应用:spring
执行步骤:数据库
第一步:发起请求到前端控制器(DispatcherServlet)apache
第二步:前端控制器请求HandlerMapping查找 Handler 能够根据xml配置、注解进行查找
第三步:处理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView ModelAndView是SpringMVC框架的一个底层对象,包括 Model和view
第八步:前端控制器请求视图解析器去进行视图解析 根据逻辑视图名解析成真正的视图(jsp)
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染 视图渲染将模型数据(在ModelAndView对象中)填充到request域
第十一步:前端控制器向用户响应结果
组件:
一、前端控制器DispatcherServlet(不须要程序员开发) 做用接收请求,响应结果,至关于转发器,中央处理器。 有了DispatcherServlet减小了其它组件之间的耦合度。
二、处理器映射器HandlerMapping(不须要程序员开发) 做用:根据请求的url查找Handler
三、处理器适配器HandlerAdapter 做用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
四、处理器Handler(须要程序员开发) 注意:编写Handler时按照HandlerAdapter的要求去作,这样适配器才能够去正确执行Handler
五、视图解析器View resolver(不须要程序员开发) 做用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
六、视图View(须要程序员开发jsp) View是一个接口,实现类支持不一样的View类型(jsp、freemarker、pdf...)
在web.xml中配置前端控制器。
<!-- SpringMVC前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation配置SpringMVC加载的配置文件(配置处理器映射器、适配器等等) 若是不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-serlvet.xml(springmvc-servlet.xml) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 第一种:*.action,访问以.action结尾 由DispatcherServlet进行解析 第二种:/,因此访问的地址都由DispatcherServlet进行解析,对于静态文件的解析须要配置不让DispatcherServlet进行解析 使用此种方式能够实现 RESTful风格的url 第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时, 仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错。 --> <url-pattern>*.action</url-pattern> </servlet-mapping>
在classpath下的springmvc.xml中配置处理器适配器
<!-- 处理器适配器 全部处理器适配器都实现 HandlerAdapter接口 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <!-- 另外一个非注解的适配器 --> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
查看源码
SimpleControllerHandlerAdapter.java
public class SimpleControllerHandlerAdapter implements HandlerAdapter { public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); } } public interface Controller { ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; }
HttpRequestHandlerAdapter.java
public class HttpRequestHandlerAdapter implements HandlerAdapter { public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; } } public interface HttpRequestHandler { void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; }
编写Handler类
方式①:须要实现 Controller接口,才能由org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter适配器执行。
public class ItemsController1 implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) 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; } }
方式②:须要实现 HttpRequestHandler接口,才能由org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter 适配器执行。
public class ItemsController2 implements HttpRequestHandler { @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //调用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); //设置模型数据 request.setAttribute("itemsList", itemsList); //设置转发的视图 request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward(request, response); //使用此方法能够经过修改response,设置响应的数据格式,好比响应json数据 /* response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("json串");*/ } }
将编写Handler在spring容器加载。
<!-- 配置Handler --> <bean id="itemsController1" name="/queryItems.action" class="cn.itcast.ssm.controller.ItemsController1" /> <!-- 配置另一个Handler --> <bean id="itemsController2" class="cn.itcast.ssm.controller.ItemsController2" />
在classpath下的springmvc.xml中配置处理器映射器
处理器映射器: org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
另外一个映射器: org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
<!-- 处理器映射器① 将bean的name做为url进行查找 ,须要在配置Handler时指定beanname(就是url) 全部的映射器都实现 HandlerMapping接口。 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!--处理器映射器② 简单url映射 --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <!-- 对itemsController1的Handler进行url映射,url是/queryItems1.action --> <prop key="/queryItems1.action">itemsController1</prop> <prop key="/queryItems2.action">itemsController1</prop> <prop key="/queryItems3.action">itemsController2</prop> </props> </property> </bean>
须要配置解析jsp的视图解析器。
<!-- 视图解析器 解析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>
前端控制器从上边的文件中加载处理映射器、适配器、视图解析器等组件,若是不在springmvc.xml中配置,使用默认加载的。
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver #处理器映射器 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping #处理器适配器 org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator #视图解析器 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
手动在配置文件中配置处理器Handler,处理器映射器HandlerMapping,若是在文件太多的状况下会比较麻烦。并且每次都要实现Controller接口和HttpRequestHandler接口,而且只有一个实现方法。每次为了一个方法去实现接口,会形成Handler类愈来愈多。太麻烦。SpringMVC提供了注解模式开发处理器Handler,大大下降了工做量,提升了易用性。
注解模式的处理器映射器HandlerMapping和处理器适配器HandlerAdapter须要这样配置。
使用注解的映射器和注解的适配器。(注解的映射器和注解的适配器必须配对使用)
<!--注解映射器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!--注解适配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!-- 使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置 mvc:annotation-driven默认加载不少的参数绑定方法, 好比json转换解析器就默认加载了,若是使用mvc:annotation-driven不用配置上边的RequestMappingHandlerMapping和RequestMappingHandlerAdapter 实际开发时使用mvc:annotation-driven --> <!-- <mvc:annotation-driven></mvc:annotation-driven> -->
编写Handler,无需继承任何接口,仅需加入@Controller注解
//使用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(使用注解扫描方式加载)
<!-- 对于注解的Handler能够单个配置 实际开发中建议使用组件扫描 --> <!-- <bean class="cn.itcast.ssm.controller.ItemsController3" /> --> <!-- 能够扫描Controller、Service、... 这里让扫描Controller,指定Controller的包 --> <context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>
使用以上配置,就能够运行起来SpringMVC程序了。
对标记@Controller类中标识有@RequestMapping的方法进行映射。在@RequestMapping里边定义映射的url。使用注解的映射器不用在xml中配置url和Handler的映射关系。
注解处理器适配器和注解的处理器映射器是配对使用。理解为不能使用非注解映射器进行映射。
<mvc:annotation-driven></mvc:annotation-driven>
能够代替下边的配置:
<!--注解映射器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!--注解适配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
视图解析器配置前缀和后缀:
<!-- 视图解析器 解析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>
程序中不用指定前缀和后缀:
//没有前缀和后缀时 modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp"); //有前缀和后缀时 modelAndView.setViewName("items/itemsList");
经过前端控制器源码分析SpringMVC的执行过程。
第一步:前端控制器接收请求
调用doDiapatch
public class DispatcherServlet extends FrameworkServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
第二步:前端控制器调用处理器映射器查找 Handler
// Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); public class DispatcherServlet extends FrameworkServlet { protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; } }
第三步:调用处理器适配器执行Handler,获得执行结果ModelAndView
// Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
第四步:视图渲染,将model数据填充到request域。
视图解析,获得view:
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
render(mv, request, response);
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = this.localeResolver.resolveLocale(request); response.setLocale(locale); View view; if (mv.isReference()) { // We need to resolve the view name. view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException( "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + getServletName() + "'"); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'"); } view.render(mv.getModelInternal(), request, response); } // We need to resolve the view name. view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
调用view的渲染方法,将model数据填充到request域
渲染方法:
view.render(mv.getModelInternal(), request, response);
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception { for (Map.Entry<String, Object> entry : model.entrySet()) { String modelName = entry.getKey(); Object modelValue = entry.getValue(); if (modelValue != null) { request.setAttribute(modelName, modelValue); if (logger.isDebugEnabled()) { logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() + "] to request in view with name '" + getBeanName() + "'"); } } else { request.removeAttribute(modelName); if (logger.isDebugEnabled()) { logger.debug("Removed model object '" + modelName + "' from request in view with name '" + getBeanName() + "'"); } } } }
① url映射
定义Controller方法对应的url,进行处理器映射使用。
② 窄化请求映射
@Controller // 为了对url进行分类管理 ,能够在这里定义根路径,最终访问url是根路径+子路径 // 好比:商品列表:/items/queryItems.action @RequestMapping("/items") public class ItemsController { }
③ 限制http请求方法
出于安全性考虑,对http的连接进行方法限制。 若是限制请求为post方法,进行get请求,则会报错。
//限制http请求方法,只能够post @RequestMapping(value="/editItems",method={RequestMethod.POST}) public ModelAndView editItems()throws Exception { }
在编写控制器Handler能够有三种返回值。
① 返回ModelAndView
须要方法结束时,定义ModelAndView,将model和view分别进行设置。
② 返回String
若是Controller方法返回String,能够有如下三种形式。
(1)、表示返回逻辑视图名。
真正视图(jsp路径)=前缀+逻辑视图名+后缀
@RequestMapping(value="/editItems",method={RequestMethod.POST,RequestMethod.GET}) public String editItems(Model model)throws Exception { //调用Service根据商品id查询商品信息 ItemsCustom itemsCustom = itemsService.findItemsById(1); //将商品信息放到model model.addAttribute("itemsCustom", itemsCustom); return "items/editItems"; }
(2)、redirect重定向
redirect重定向特色:浏览器地址栏中的url会变化。修改提交的request数据没法传到重定向的地址。由于重定向后从新进行request(request没法共享)
return "redirect:items/queryItems.action";
(3)、forward页面转发
经过forward进行页面转发,浏览器地址栏url不变,request能够共享。
return "forward:items/queryItems.action";
③ 返回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串");
SpringMVC参数绑定过程
从客户端请求key/value数据,通过参数绑定,将key/value数据绑定到Controller方法的形参上。
SpringMVC中,接收页面提交的数据是经过方法形参来接收。而不是在Controller类定义成员变量接收!!!!(与Struts2明显不一样的实现逻辑)
(1) 默认支持的类型
直接在Controller方法形参上定义下边类型的对象,就可使用这些对象。在参数绑定过程当中,若是遇到下边类型直接进行绑定。
① HttpServletRequest
经过request对象获取请求信息
② HttpServletResponse
经过response处理响应信息
③ HttpSession
经过session对象获得session中存放的对象
④ Model/ModelMap
model是一个接口,modelMap是一个接口实现 。
做用:将model数据填充到request域。
(2) 简单类型
经过@RequestParam对简单类型的参数进行绑定。
若是不使用@RequestParam,要求request传入参数名称和Controller方法的形参名称一致,方可绑定成功。
若是使用@RequestParam,不用限制request传入参数名称和Controller方法的形参名称一致。
经过required属性指定参数是否必需要传入,若是设置为true,没有传入参数,则会报错。
// @RequestParam里边指定request传入参数名称和形参进行绑定。 // 经过required属性指定参数是否必需要传入 // 经过defaultValue能够设置默认值,若是id参数没有传入,将默认值和形参绑定。 public String editItems(Model model,@RequestParam(value = "id", required = true) Integer items_id) throws Exception { }
(3) pojo绑定
页面中input的name和Controller的pojo形参中的属性名称一致,将页面中数据绑定到pojo对应的属性。
页面定义:
Controller的pojo形参的定义:
须要说明的是:简单类型的参数绑定和pojo参数绑定互不影响。
// @RequestParam里边指定request传入参数名称和形参进行绑定。 // 经过required属性指定参数是否必需要传入 // 经过defaultValue能够设置默认值,若是id参数没有传入,将默认值和形参绑定。 public String editItems(Model model,@RequestParam(value = "id", required = true) Integer items_id, Items item) throws Exception { }
一、SpringMVC基于方法开发的,struts2基于类开发的。
SpringMVC将url和Controller方法映射。映射成功后SpringMVC生成一个Handler对象,对象中只包括了一个method。 方法执行结束,形参数据销毁。 SpringMVC的Controller开发相似Service开发。
二、SpringMVC能够进行单例开发,而且建议使用单例开发,struts2经过类的成员变量接收参数,没法使用单例,只能使用多例。(缘由就是第一句)
三、通过实际测试,struts2速度慢,在于使用struts标签,若是使用struts建议使用jstl。
在页面form中提交enctype="multipart/form-data"的数据时,须要SpringMVC对multipart类型的数据进行解析。
在springmvc.xml中配置multipart类型解析器。
<!-- 文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置上传文件的最大尺寸为5MB --> <property name="maxUploadSize"> <value>5242880</value> </property> </bean>
<form id="itemForm" action="${pageContext.request.contextPath }/items/editItemsSubmit.action" method="post" enctype="multipart/form-data"> <input type="hidden" name="id" value="${items.id }"/> 修改商品信息: <table width="100%" border=1> <tr> <td>商品图片</td> <td> <c:if test="${items.pic !=null}"> <img src="/pic/${items.pic}" width=100 height=100/> <br/> </c:if> <input type="file" name="items_pic"/> </td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="提交"/> </td> </tr> </table> </form>
@RequestMapping("/editItemsSubmit") public String editItemsSubmit(Model model,HttpServletRequest request,Integer id, MultipartFile items_pic//接收商品图片 ) throws Exception { }
RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,因此正获得愈来愈多网站的采用。
RESTful(即Representational State Transfer的缩写)实际上是一个开发理念,是对http的很好的诠释。
一、对url进行规范,写RESTful格式的url
非REST的url:http://...../queryItems.action?id=001&type=T01 REST的url风格:http://..../items/001 特色:url简洁,将参数经过url传到服务端
二、http的方法规范
不论是删除、添加、更新。。使用url是一致的,若是进行删除,须要设置http的方法为delete,同理添加。。。
后台Controller方法:判断http方法,若是是delete执行删除,若是是post执行添加。
三、对http的contentType规范
请求时指定contentType,要json数据,设置成json格式的type。。
Controller中设置
定义方法,进行url映射使用REST风格的url,将查询商品信息的id传入Controller .
输出json使用@ResponseBody将java对象输出json。
//查询商品信息,输出json ///itemsView/{id}里边的{id}表示占位符,经过@PathVariable获取占位符中的参数, //若是占位符中的名称和形参名一致,在@PathVariable能够不指定名称 @RequestMapping("/itemsView/{id}") public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id)throws Exception { //调用Service查询商品信息 ItemsCustom itemsCustom = itemsService.findItemsById(id); return itemsCustom; }
@RequestMapping(value="/ itemsView/{id}"):{×××}占位符,请求的URL能够是“/viewItems/1”或“/viewItems/2”,经过在方法中使用@PathVariable获取{×××}中的×××变量。
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。 若是RequestMapping中表示为"/ itemsView /{id}",id和形参名称一致,@PathVariable不用指定名称。
REST方法的前端控制器配置
在web.xml配置:
<!-- SpringMVC前端控制器,rest配置 --> <servlet> <servlet-name>springmvc_rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation配置SpringMVC加载的配置文件(配置处理器映射器、适配器等等) 若是不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-serlvet.xml(springmvc-servlet.xml) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc_rest</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
对静态资源的解析
配置前端控制器的url-pattern中指定/,对静态资源的解析出现问题:
在springmvc.xml中添加静态资源解析方法。
<!-- 静态资源解析 包括 :js、css、img、.. --> <mvc:resources location="/js/" mapping="/js/**"/> <mvc:resources location="/img/" mapping="/img/**"/>
拦截定义
定义拦截器,实现HandlerInterceptor接口。接口中提供三个方法。
public class HandlerInterceptor1 implements HandlerInterceptor { //进入 Handler方法以前执行 //用于身份认证、身份受权 //好比身份认证,若是认证经过表示当前用户没有登录,须要此方法拦截再也不向下执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //return false表示拦截,不向下执行 //return true表示放行 return false; } //进入Handler方法以后,返回modelAndView以前执行 //应用场景从modelAndView出发:将公用的模型数据(好比菜单导航)在这里传到视图,也能够在这里统一指定视图 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } //执行Handler完成执行此方法 //应用场景:统一异常处理,统一日志处理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
拦截器配置
SpringMVC配置相似全局的拦截器,SpringMVC框架将配置的相似全局的拦截器注入到每一个HandlerMapping中。
<!--拦截器 --> <mvc:interceptors> <!--多个拦截器,顺序执行 --> <!-- 登录认证拦截器 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cn.itcast.ssm.interceptor.LoginInterceptor"></bean> </mvc:interceptor> <mvc:interceptor> <!-- /**表示全部url包括子url路径 --> <mvc:mapping path="/**"/> <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
根据测试结果,对拦截器应用。
好比:统一日志处理拦截器,须要该 拦截器preHandle必定要放行,且将它放在拦截器连接中第一个位置。
好比:登录认证拦截器,放在拦截器连接中第一个位置。权限校验拦截器,放在登录认证拦截器以后。(由于登录经过后才校验权限)