天天看点

Spring MVC 实践 - Base Spring MVC 实践

标签 : Java与Web

Spring-Web-MVC是一种基于请求驱动的轻量级Web-MVC设计模式框架, Spring MVC使用MVC架构思想, 对Web层进行<code>职责解耦</code>,使用请求-响应模型将数据、业务与视图进行分离, 简化开发.

MVC(模型-视图-控制器)是一个以设计界面应用程序为基础的架构模式,通过分离模型-视图-控制器在应用中的角色将业务逻辑从界面中解耦:

模型负责封装应用数据和业务逻辑; 视图仅负责展示数据; 控制器负责接收用户请求,并调用模型(Service/Manger/DAO)来处理业务逻辑.模型可能会返回一些数据需要在视图层展示,控制器就需要整理模型数据并调用视图展示.

MVC模式的核心思想就是将业务逻辑从界面中分离出来,允许它们单独改变而不会相互影响.

Spring MVC框架是基于Java语言的MVC架构具体实现.他的设计围绕<code>DispatcherServlet</code>展开,<code>DispatcherServlet</code>负责将请求分派给指定的<code>Controller</code>(<code>Handler</code>),通过可配置的<code>HandlerMapping</code>、<code>HandlAdapter</code>、<code>Controller</code>、<code>ViewResolver</code>来处理请求拿到数据并填充对应的视图View:

组件

名称

描述

<code>DispatcherServlet</code>

调度器/前端控制器

<code>HandlerMapping</code>

处理器映射器

<code>HandlerMapping</code>负责根据用户请求<code>URI</code>找到对应的<code>Controller</code>与<code>Interceptor</code>,并将它们封装在<code>HandlerExecutionChain</code>中返回给<code>DispatcherServlet</code>.

<code>HandlAdapter</code>

处理器适配器

Spring MVC通过<code>HandlerAdapter</code>执行<code>Controller</code>,这是适配器模式的应用,通过扩展适配器可以执行更多类型的<code>Controller</code>.

<code>Controller</code>

处理器

<code>Controller</code>(又称<code>Handler</code>)是继<code>DispatcherServlet</code>前端控制器之后的后端控制器,在<code>DispatcherServlet</code>的控制下<code>Controller</code>对具体的用户请求进行处理.

<code>ViewResolver</code>

视图解析器

负责将<code>Model</code>数据填充到<code>View</code>, 组合生成视图展示:他首先将逻辑视图名解析成物理视图名,生成<code>View</code>视图对象,最后对<code>View</code>进行渲染(填充数据). Spring默认提供了针对JSP/Velocity/PFD等视图的<code>ViewResolver</code>实现.

创建Maven Web项目

依赖管理

在pom.xml中添加Spring、Spring MVC、 Sevlet及Velocity依赖:

配置<code>DispatcherServlet</code>(web.xml)

配置<code>HandlerMapping</code>/<code>HandlerAdapter</code>(mvc-servlet.xml)

配置<code>ViewResolver</code>(mvc-servlet.xml)

由于我们视图选用的是Velocity,因此配置<code>VelocityViewResolver</code>:

View(/views/users.vm)

前端控制器

Spring MVC <code>DispatcherServlet</code>的<code>url-pattern</code>有两种配置方式:

<code>*.do</code>: 拦截所有以<code>.do</code>结尾的URI.

<code>/</code> : 拦截 所有 URI.

<code>BeanNameUrlHandlerMapping</code>指定将Bean的Name作为URI映射; Spring还提供了<code>SimpleUrlHandlerMapping</code>将URI和<code>Controller</code>的id统一映射配置.

<code>SimpleControllerHandlerAdapter</code>对所有实现了<code>Controller</code>接口的JavaBean适配.Spring还提供<code>HttpRequestHandlerAdapter</code>对所有实现了<code>HttpRequestHandler</code>接口的JavaBean适配.

前面使用Velocity作为视图展示,如果使用的是JSP的话, 需要配置另一种视图解析器<code>InternalResourceViewResolver</code>:

从2.5版本开始, Spring引入了注解开发:

注解驱动(mvc-servlet.xml)

从3.1版本开始,Spring MVC使用<code>RequestMappingHandlerMapping</code> 注解式处理器映射器 对标有<code>@ResquestMapping</code>的方法进行映射.

从3.1版本开始,Spring MVC使用<code>RequestMappingHandlerAdapter</code> 注解式处理器适配器 对标记有<code>@ResquestMapping</code>的方法进行适配.

Spring MVC使用<code>&lt;mvc:annotation-driven/&gt;</code> 注解驱动自动加载<code>RequestMappingHandlerMapping</code>和<code>RequestMappingHandlerAdapter</code>及其他相关配置. 因此在mvc-servlet.xml最简单有效的配置方式是使用<code>&lt;mvc:annotation-driven/&gt;</code>替代注解处理器和适配器:

尽管<code>&lt;mvc:annotation-driven/&gt;</code>很小, 但他具有足够的威力, 它注册了很多的特性, 包括对JSR-303校验、信息转换以及对域格式化的支持.

组件扫描(mvc-servlet.xml):

使用Spring的组件扫描来省去为每个<code>Controller</code>注册的麻烦:

注解<code>Controller</code>

通过Spring将各层整合: 持久层DAO(MyBatis的Mapper)注册到Spring容器中. 业务层Service/Manager从Spring容器中拿到DAO接口, 并注册Service服务. 表现层Controller从Spring容器中拿到Service接口, 通过Spring MVC进行数据展示.

mybatis-configuration.xml

domain: User

UserDAO

applicationContext-datasource.xml(配置数据源)

db.properties

applicationContext.xml(配置组件扫描与事务控制)

Controller

mvc-servlet.xml

web.xml

View视图同前

为了能够看到Spring MVC的运行时信息, 最好在应用中集成一种Log实现, 在此选用LogBack:

logback.xml

add_user.vm

Service/DAO实现简单,不再赘述.

在传统的Servlet编程中, 可以使用<code>HttpServletRequest</code>的<code>getParameter()</code>方法来获取请求参数值, 而在Spring MVC中, 它会调用请求参数解析组件将客户端传过来的<code>String</code>字符串解析为指定的Java对象并传递给<code>Controller</code>, 这个过程称为请求参数解析.

Spring MVC默认提供了很多参数解析组件, 因此<code>Controller</code>的请求处理方法默认就可以接收很多不同类型:

JavaEE

JavaSE

Spring

<code>ServletRequest</code> / <code>HttpServletRequest</code>

<code>InputStream</code> / <code>Reader</code>

<code>WebRequest</code> / <code>NativeWebRequest</code>

<code>ServletResponse</code> / <code>HttpServletResponse</code>

<code>OutputStream</code> / <code>Writer</code>

<code>Model</code> / <code>ModelMap</code>

<code>HttpSession</code>

命令或表单对象 (如<code>String</code> / <code>Integer</code> / <code>User</code>)

<code>RedirectAttributes</code>

<code>HttpEntity&lt;?&gt;</code>

<code>Array</code> / <code>List</code> / <code>Map</code>

<code>Errors</code> / <code>BindingResult</code>

带<code>@PathVariable</code> / <code>@MatrixVariable</code>注解的对象

<code>@RequestParam</code> / <code>@RequestHeader</code> / <code>@RequestBody</code> / <code>@RequestPart</code>

<code>Principal</code> / <code>Locale</code>

<code>SessionStatus</code>

<code>UriComponentsBuilder</code>

注: 1. 如果<code>Controller</code>形参名与URI中<code>name</code>不一致, 可使用<code>@RequestParam</code>注解对其进行修饰.

Spring MVC会在每次调用请求处理方法时都创建一个<code>Model</code>对象, 若打算使用该实例, 则可以在方法的形参添加一个<code>Model</code>形参. 其实还可以使用<code>@ModelAttribute</code>注解来访问<code>Model</code>实例: 使用<code>@ModelAttribute</code>注解标注参数或方法,该方法会将其输入的或创建的参数对象添加到<code>Model</code>对象中:

<code>@ModelAttribute</code>标注形参

<code>String</code>实例将以<code>id</code>做key添加到<code>Model</code>对象中(如果key未命名,则默认使用类型的名称(如<code>string</code>)做key).

<code>@ModelAttribute</code>标注方法

<code>@ModelAttribute</code>的第二个用途是标注一个非请求处理方法: 被<code>@ModelAttribute</code>标注的方法会在每次调用<code>Controller</code>的请求处理方法时调用.该方法可以返回对象或<code>void</code>:

如果返回对象, 该对象会自动添加到<code>Model</code>中:

若返回<code>void</code>, 则必须添加一个<code>Model</code>类型参数, 自行将实例添加到<code>Model</code>中:

使用重定向的一个重要场景是避免用户重新加载页面再次调用相同动作. 比如<code>add_user.do</code>: 当用户提交表单时会将用户信息插入数据库. 但如果在提交表单后重新加载页面, <code>add_user.do</code>会被再次调用, 相同的用户可能会被再次添加.为了避免这种情况, 最好的办法是在提交表单后将用户重定向到一个不同的页面,这个页面任意重新加载都没有副作用.

但使用重定向的一个不便之处在于: 无法轻松的给目标页面传值. 如果采用转发, 可属性添加到<code>Model</code>, 使得目标视图可以轻松访问. 但用户重定向需要经过客户端, 所以<code>Model</code>的一切内容都会在重定向中丢失. 幸运的是, 在Spring 3.1之后,可以通过<code>Flash</code>属性提供重定向传值的方法:

要使用Flash属性, 必须要有<code>&lt;annotation-driven/&gt;</code>注解驱动支持, 然后在方法上添加一个新的参数类型<code>RedirectAttributes</code>:

应用了<code>@Controller</code>与<code>@RequestMapping</code>注解之后,<code>Controller</code>不再需要<code>implements</code>特定的接口, 因此<code>Controller</code>的返回值也变得多种多样:

返回值

<code>ModelAndView</code>

包含视图名与Model数据

<code>Model</code>

<code>Map</code>

包含模型的属性

<code>View</code>

<code>String</code>

代表逻辑视图名

<code>void</code>

可以在参数中传入request/response完成对参数的解析, 对客户端的响应

<code>HttpEntity</code>/<code>ResponseEntity</code>

提供对Servlet的访问, 以响应HTTP头部和内容

<code>Callable</code>

<code>DeferredResult</code>

其他任意类型

常与响应JSON/XML结合