本文主要是介绍码农小汪-SpringMVC-入门篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Spring MVC 是什么
Spring Web MVC 是一种基于 Java 的实现了 Web MVC 设计模式的请求驱动类型的轻量级 Web 框架, 即使用了 MVC 架构模式的思想,将 web 层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC 也是要简化我们日常 Web 开发的。
Spring Web MVC 也是服务到工作者模式的实现,但进行可优化。
前端控制器是 DispatcherServlet;应用控制器其实拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resolver)进行视图管理;页面控制器/动作/处理器为 Controller 接口(仅包含 ModelAndView handleRequest(request, response) 方法)的实现(也可以是任何的 POJO 类) ;支持本地化(Locale)解析、主题(Theme)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持
Spring Web MVC 能帮我们做什么
- 让我们能非常简单的设计出干净的 Web 层和薄薄的 Web 层;
- 天生与 Spring 框架集成(如 IoC 容器、AOP 等)
- 能简单的进行 Web 层的单元测试;
- 能简单的进行 Web 层的单元测试;
- 非常容易与其他视图技术集成,如 Velocity、FreeMarker 等等,因为模型数据不放在特定的 API 里,而是放在一个Model 里(Map 数据结构实现,因此很容易被其他框架使用)
- 非常灵活的数据验证、格式化和数据绑定机制,能使用任何对象进行数据绑定,不必实现特定框架的 API
- 提供一套强大的 JSP 标签库,简化 JSP 开发
- 支持灵活的本地化、主题等解析;
Spring Web MVC 处理请求的流程
Spring Web MVC 架构
哇瑟,这个图真的很清楚的给我们描述啦,绿色的是我们需要去书写的东西,红色的就是禁区了涩!
我们首先经过过滤器之后才是进入我们的控制器,然后返回模型数据,返回我们的界面之后我们就可以快速的开发啦!
核心代码
//前端控制器分派方法protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;int interceptorIndex = -1;try {ModelAndView mv;boolean errorView = false;try {//检查是否是请求是否是multipart(如文件上传),如果是将通过MultipartResolver解析processedRequest = checkMultipart(request);//步骤2、请求到处理器(页面控制器)的映射,通过HandlerMapping进行映射mappedHandler = getHandler(processedRequest, false);if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}//步骤3、处理器适配,即将我们的处理器包装成相应的适配器(从而支持多种类型的处理器)HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 304 Not Modified缓存支持//此处省略具体代码// 执行处理器相关的拦截器的预处理(HandlerInterceptor.preHandle)//此处省略具体代码// 步骤4、由适配器执行处理器(调用处理器相应功能处理方法)mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// Do we need view name translation?if (mv != null && !mv.hasView()) {mv.setViewName(getDefaultViewName(request));}// 执行处理器相关的拦截器的后处理(HandlerInterceptor.postHandle)//此处省略具体代码}catch (ModelAndViewDefiningException ex) {logger.debug("ModelAndViewDefiningException encountered", ex);mv = ex.getModelAndView();}catch (Exception ex) {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(processedRequest, response, handler, ex);errorView = (mv != null);}//步骤5 步骤6、解析视图并进行视图的渲染//步骤5 由ViewResolver解析View(viewResolver.resolveViewName(viewName, locale))//步骤6 视图在渲染时会把Model传入(view.render(mv.getModelInternal(), request, response);)if (mv != null && !mv.wasCleared()) {render(mv, processedRequest, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isDebugEnabled()) {logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +"': assuming HandlerAdapter completed request handling");}}// 执行处理器相关的拦截器的完成后处理(HandlerInterceptor.afterCompletion)//此处省略具体代码catch (Exception ex) {// Trigger after-completion for thrown exception.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);throw ex;}catch (Error err) {ServletException ex = new NestedServletException("Handler processing failed", err);// Trigger after-completion for thrown exception.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);throw ex;}finally {// Clean up any resources used by a multipart request.if (processedRequest != request) {cleanupMultipart(processedRequest);}}}
核心架构的具体流程步骤如下:
1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术; 我们在配置的时候,可以设置我们的视图的后缀~~
6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
- 前端控制器如何根据请求信息选择页面控制器进行功能处理? 我们需要配置 HandlerMapping 进行映射
- 如何支持多种页面控制器呢?配置 HandlerAdapter 从而支持多种类型的页面控制器
- 如何页面控制器如何使用业务对象?可以预料到,肯定利用 Spring IoC 容器的依赖注入功能
- 页面控制器如何返回模型数据?使用 ModelAndView 返回
- 前端控制器如何根据页面控制器返回的逻辑视图名选择具体的视图进行渲染? 使用 ViewResolver 进行解析
- 不同的视图技术如何使用相应的模型数据? 因为 Model 是一个 Map 数据结构,很容易支持其他视图技术
Spring MVC核心的开发的步骤如下:
- DispatcherServlet 在 web.xml 中的部署描述,从而拦截请求到 Spring Web MVC
- HandlerMapping 的配置,从而将请求映射到处理器
- HandlerAdapter 的配置,从而支持多种类型的处理器
- ViewResolver 的配置,从而将逻辑视图名解析为具体视图技术
- 处理器(页面控制器)的配置,从而进行功能处理
基本的使用配置流程~
web.xml
<servlet><servlet-name>chapter2</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>chapter2</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
在Spring配置文件中配置HandlerMapping、HandlerAdapter(现在都是用注解,这里使用的配置文件,我还是看哈吧~)
具体配置在WEB-INF/ chapter2-servlet.xml文件中:
<!-- HandlerMapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/><!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
BeanNameUrlHandlerMapping:表示将请求的URL和Bean名字映射,如URL为 “上下文/hello”,则Spring配置文件必须有一个名字为“/hello”的Bean,上下文默认忽略。
SimpleControllerHandlerAdapter:表示所有实现了org.springframework.web.servlet.mvc.Controller接口的Bean可以作为Spring Web MVC中的处理器。如果需要其他类型的处理器可以通过实现HadlerAdapter来解决。
在Spring配置文件中配置ViewResolver
具体配置在WEB-INF/ chapter2-servlet.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:用于支持Servlet、JSP视图解析;
viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,classpath中必须包含jstl的相关jar包;
prefix和suffix:查找视图页面的前缀和后缀(前缀[逻辑视图名]后缀),比如传进来的逻辑视图名为hello,则该该jsp视图页面应该存放在“WEB-INF/jsp/hello.jsp”;
开发处理器/页面控制器
package cn.javass.chapter2.web.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloWorldController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {//1、收集参数、验证参数//2、绑定参数到命令对象//3、将命令对象传入业务对象进行业务处理//4、选择下一个页面ModelAndView mv = new ModelAndView();//添加模型数据 可以是任意的POJO对象mv.addObject("message", "Hello World!");//设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面mv.setViewName("hello");return mv;}
}
org.springframework.web.servlet.mvc.Controller:页面控制器/处理器必须实现Controller接口,注意别选错了;
public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) :
功能处理方法,实现相应的功能处理,比如收集参数、验证参数、绑定参数到命令对象、将命令对象传入业务对象进行业务处理、最后返回ModelAndView对象;
ModelAndView:包含了视图要实现的模型数据和逻辑视图名;
mv.addObject(“message”, “Hello World!”);
表示添加模型数据,此处可以是任意POJO对象;
“mv.setViewName(“hello”);”
表示设置逻辑视图名为“hello
视图解析器会将其解析为具体的视图,
如前边的视图解析器InternalResourceVi。wResolver会将其解析为“WEB-INF/jsp/hello.jsp”。
我们需要将其添加到Spring配置文件(WEB-INF/chapter2-servlet.xml),让其接受Spring IoC容器管理:
<!-- 处理器 -->
<bean name="/hello" class="cn.javass.chapter2.web.controller.HelloWorldController"/>
开发视图页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello World</title>
</head>
<body>
${message}
</body>
</html>
运行流程分析
1、 首先用户发送请求http://localhost:9080/springmvc-chapter2/hello——>web容器,web容器根据“/hello”路径映射到DispatcherServlet(url-pattern为/)进行处理;
2、 DispatcherServlet——>BeanNameUrlHandlerMapping进行请求到处理的映射,BeanNameUrlHandlerMapping将“/hello”路径直接映射到名字为“/hello”的Bean进行处理,即HelloWorldController,BeanNameUrlHandlerMapping将其包装为HandlerExecutionChain(只包括HelloWorldController处理器,没有拦截器);
3、 DispatcherServlet——> SimpleControllerHandlerAdapter,SimpleControllerHandlerAdapter将HandlerExecutionChain中的处理器(HelloWorldController)适配为SimpleControllerHandlerAdapter;
4、 SimpleControllerHandlerAdapter——> HelloWorldController处理器功能处理方法的调用,SimpleControllerHandlerAdapter将会调用处理器的handleRequest方法进行功能处理,该处理方法返回一个ModelAndView给DispatcherServlet;
5、 hello(ModelAndView的逻辑视图名)——>InternalResourceViewResolver, InternalResourceViewResolver使用JstlView,具体视图页面在/WEB-INF/jsp/hello.jsp;
6、 JstlView(/WEB-INF/jsp/hello.jsp)——>渲染,将在处理器传入的模型数据(message=HelloWorld!)在视图中展示出来;
7、 返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
解决中文乱码的问题
spring Web MVC框架提供了org.springframework.web.filter.CharacterEncodingFilter用于解决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>
Spring3.1新特性(别人写的还不错)
- Spring2.5之前,我们都是通过实现Controller接口或其实现来定义我们的处理器类。
- Spring2.5引入注解式处理器支持,通过@Controller 和 @RequestMapping注解定义我们的处理器类
需要通过处理器映射 DefaultAnnotationHandlerMapping 和处理器适配器 AnnotationMethodHandlerAdapter 来开启支
持@Controller 和 @RequestMapping 注解的处理器。
@Controller:用于标识是处理器类;
@RequestMapping:请求到处理器功能方法的映射规则;
@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute:请求参数到命令对象的绑定;
@SessionAttributes:用于声明session级别存储的属性,放置在处理器类上,通常列出模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到session中;
@InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
Spring3.0引入RESTful架构风格支持(通过@PathVariable注解和一些其他特性支持),且又引入了更多的注
@CookieValue:cookie数据到处理器功能处理方法的方法参数上的绑定;
@RequestHeader:请求头(header)数据到处理器功能处理方法的方法参数上的绑定;
@RequestBody:请求的body体的绑定(通过HttpMessageConverter进行类型转换);
@ResponseBody:处理器功能处理方法的返回值作为响应体(通过HttpMessageConverter进行类型转换);
@ResponseStatus:定义处理器功能处理方法/异常处理器返回的状态码和原因;
@ExceptionHandler:注解式声明异常处理器;
@PathVariable:请求URI中的模板变量部分到处理器功能处理方法的方法参数上的绑定,从而支持RESTful架构风格还有比如
JSR-303验证框架的无缝支持(通过@Valid注解定义验证元数据);
使用Spring 3开始的ConversionService进行类型转换(PropertyEditor依然有效),支持使用@NumberFormat 和 @DateTimeFormat来进行数字和日期的格式化;
HttpMessageConverter(Http输入/输出转换器,比如JSON、XML等的数据输出转换器);
ContentNegotiatingViewResolver,内容协商视图解析器,它还是视图解析器,只是它支持根据请求信息将同一模型数据以不同的视图方式展示(如json、xml、html等),RESTful架构风格中很重要的概念(同一资源,多种表现形式);
Spring 3 引入 一个 mvc XML的命名空间用于支持mvc配置,包括如:
< mvc:annotation-driven>:
自动注册基于注解风格的处理器需要的DefaultAnnotationHandlerMapping、AnnotationMethodHandlerAdapter
支持Spring3的ConversionService自动注册
支持JSR-303验证框架的自动探测并注册(只需把JSR-303实现放置到classpath)
自动注册相应的HttpMessageConverter(用于支持@RequestBody 和 @ResponseBody)(如XML输入输出转换器(只需将JAXP实现放置到classpath)、JSON输入输出转换器(只需将Jackson实现放置到classpath))等。
< mvc:interceptors>:注册自定义的处理器拦截器;
< mvc:view-controller>:和ParameterizableViewController类似,收到相应请求后直接选择相应的视图;
< mvc:resources>:逻辑静态资源路径到物理静态资源路径的支持;
< mvc:default-servlet-handler>:当在web.xml 中DispatcherServlet使用< url-pattern>/ 映射时,能映射静态资源(当Spring Web MVC框架没有处理请求对应的控制器时(如一些静态资源),转交给默认的Servlet来响应静态文件,否则报404找不到资源错误,)。
……等等。
- Spring3.1新特性:
@EnableWebMvc:用于在基于Java类定义Bean配置中开启MVC支持,和XML中的< mvc:annotation-driven>功能一样;
新的@Contoller和@RequestMapping注解支持类:处理器映射RequestMappingHandlerMapping 和 处理器适配器RequestMappingHandlerAdapter组合来代替Spring2.5开始的处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter,提供更多的扩展点,它们之间的区别我们在处理器映射一章介绍。
新的@ExceptionHandler 注解支持类:ExceptionHandlerExceptionResolver来代替Spring3.0的 AnnotationMethodHandlerExceptionResolver,在异常处理器一章我们再详细讲解它们的区别。
@RequestMapping的”consumes” 和 “produces” 条件支持:用于支持@RequestBody 和 @ResponseBody,
1consumes指定请求的内容是什么类型的内容,即本处理方法消费什么类型的数据,如consumes=”application/json”表示JSON类型的内容,Spring会根据相应的HttpMessageConverter进行请求内容区数据到@RequestBody注解的命令对象的转换;
2produces指定生产什么类型的内容,如produces=”application/json”表示JSON类型的内容,Spring的根据相应的HttpMessageConverter进行请求内容区数据到@RequestBody注解的命令对象的转换,Spring会根据相应的HttpMessageConverter进行模型数据(返回值)到JSON响应内容的转换
URI模板变量增强:URI模板变量可以直接绑定到@ModelAttribute指定的命令对象、@PathVariable方法参数在视图渲染之前被合并到模型数据中(除JSON序列化、XML混搭场景下)。
@Validated:JSR-303的javax.validation.Valid一种变体(非JSR-303规范定义的,而是Spring自定义的),用于提供对Spring的验证器(org.springframework.validation.Validator)支持,需要hibernate Validator 4.2及更高版本支持;
@RequestPart:提供对“multipart/form-data”请求的全面支持,支持Servlet 3.0文件上传(javax.servlet.http.Part)、支持内容的HttpMessageConverter(即根据请求头的Content-Type,来判断内容区数据是什么类型,如JSON、XML,能自动转换为命令对象),比@RequestParam更强大(只能对请求参数数据绑定,key-alue格式),而@RequestPart支持如JSON、XML内容区数据的绑定;详见本章的第×××节;
Flash 属性 和 RedirectAttribute:通过FlashMap存储一个请求的输出,当进入另一个请求时作为该请求的输入,典型场景如重定向(POST-REDIRECT-GET模式,1、POST时将下一次需要的数据放在FlashMap;2、重定向;3、通过GET访问重定向的地址,此时FlashMap会把1放到FlashMap的数据取出放到请求中,并从FlashMap中删除;从而支持在两次请求之间保存数据并防止了重复表单提交)。
Spring Web MVC提供FlashMapManager用于管理FlashMap,默认使用SessionFlashMapManager,即数据默认存储在session中。
这篇关于码农小汪-SpringMVC-入门篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!