本文简介
在前一篇文章中给大家讲述了SpringMVC基本开发框架的搭建,相信看过的朋友已经可以搭建出SpringMVC开发环境了。在本篇文章中,本人将使用Web应用中最常见的注册功能作为引子给大家讲述一下SpringMVC框架的原理。让大家知道SpringMVC框架执行的完整流程。
SpringMVC框架向大多数MVC框架一样基于请求驱动,设计围绕一个中心Servlet,把请求转发给控制器,提供其他功能,便于web应用程序的开发。然而,Spring的DispatcherServlet远远不止这些。这是完全与Spring IoC容器集成,从而允许你使用Spring拥有的其它功能。
下图中所示的Spring Web MVC的DispatcherServlet的请求处理流程。精通设计模式的读者会认识到,DispatcherServlet的是“前端控制器设计模式”(这是一个模式,SpringMVC与许多其他领先的Web框架的所共有的)。
(此图源自Spring官方入门指南) 从图中可以看到,请求经过前端控制器也就是DispatcherServlet把请求委托给后台控制器(我们自己创建的Controller),控制器再处理请求,返回model到DispatcherServlet ,DispatcherServlet再解析根据对应的配置文件(servlet-context.xml)解析model为对应的视图返回给用户。 具体的详细流程为: 1.客户端发出Http请求,Web应用服务器接收到这个请求,如果匹配在web.xml中配置的DispatcherServlet请求路径,web容器将请求转交给DispatcherServlet处理。 2.DispatcherServlet接收到请求以后,根据请求的信息(包括URL、HTTP方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理请求的Handler(我们定义的Controller,SpringMVC没有规定Controller需要继承或者实现相应的接口,这也为我们提供了很大的方便,任何Object都可以成为Controller). 3.DispatcherServlet根据HandlerMapping得到相应请求的Handler后,通过HandlerAdapter进行封装,再以统一的适配器接口调用Handler(HandlerAdapter.handle() 代码可以参见:DispatcherServlet.doDispatch()方法)。 4.HandlerAdapter.handle()方法返回的是ModelAndView,ModelAndView包含了视图逻辑名称以及模型数据信息。 5.DispatcherServlet根据ModelAndView里面的逻辑视图名称使用ViewResolver完成逻辑视图名称到真实视图对象的解析工作。 6.得到真实的视图对象View后,DispatcherServlet就使用后整个View对象对ModelAndView中的模型数据进行视图渲染。 7.最终用户得到的响应消息,可能是普通的HTML页面,也可能是XML或者JSON字符串,甚至是一张图片或者一个PDF文档。 流程讲完了,我们做一个登录功能给大家演示一下这个流程。首先回顾一下SpringMVC应用开发的基本步骤: 1.配置web.xml 指定业务层对应的Spring配置文件,定义DispatcherServlet. 2.编写视图对象 3.编写请求的控制器 4.配置SpringMVC的配置文件,使控制器视图解析器生效。 在HelloWorld中1、4 我们已经做过了,这里继续使用上次的架子进行开发。 编写视图对象在webapp/WEB-INF/views/user/下面创建register.jsp页面 代码清单如下:
- <%@ page language="java" contentType="text/html; charset=GBK"
- pageEncoding="GBK"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <!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=GBK">
- <title>SpringMVC 注册页面</title>
- </head>
- <body>
- <form action="user/register">
- <table>
- <c:if test="${!empty errorMsg}">
- <tr>
- <td colspan="2">
- <font color="red">${errorMsg}</font>
- </td>
- </tr>
- </c:if>
- <tr>
- <td>用户名:</td>
- <td><input type="text" name="username"/></td>
- </tr>
- <tr>
- <td>密码:</td>
- <td><input type="password" name="password"/></td>
- </tr>
- <tr>
- <td><input type="submit" value="注册"/></td>
- <td><input type="reset" value="重置"/></td>
- </tr>
- </table>
- </form>
- </body>
- </html>
在webapp/WEB-INF/views/user/下面创建register_ok.jsp页面 代码清单如下:
- <%@ page language="java" contentType="text/html; GBK"
- pageEncoding="GBK"%>
- <!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; GBK">
- <title>SpringMVC 注册成功</title>
- </head>
- <body>
- <h2>恭喜您,注册成功!用户名:${username}</h2><br>
- <a href="../">返回首页</a>
- </body>
- </html>
在上一节home.jsp页面上加上<a href="user/toRegister">注册新用户</a> 用于跳转
编写控制器
创建com.yubai.springmvc.web.UserController控制器 用于处理所有与用户有关的操作,代码如下:
- package com.yubai.springmvc.web;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.stereotype.Controller;
- import org.springframework.util.StringUtils;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.servlet.ModelAndView;
- import com.yubai.springmvc.entity.User;
- //此注解表明当前类为控制器
- @Controller
- // 此注解表明 此控制器负责处理来自/user的请求
- @RequestMapping("/user")
- public class UserController {
- private final static Logger logger = LoggerFactory
- .getLogger(UserController.class);
- /**
- * 跳转到注册页面
- *
- * @return
- */
- // 此注解表示处理/user/toRegister 请求
- @RequestMapping("/toRegister")
- public String toRegister() {
- // 视图解析器会在/user目录下 找到register.jsp页面返回
- logger.debug("跳转到注册页面");
- return "/user/register";
- }
- /**
- * 注册
- *
- * @param user
- * @return
- */
- // 此注解表示处理/user/register 请求
- @RequestMapping("/register")
- public ModelAndView register(User user) {
- //User对象SpringMVC自动注入进来的
- logger.debug("注册……");
- ModelAndView mv = new ModelAndView();
- if (StringUtils.isEmpty(user.getUsername())
- || StringUtils.isEmpty(user.getPassword())) {
- logger.warn("用户名或者密码为空,注册失败");
- mv.setViewName("/user/register");
- mv.addObject("errorMsg", "用户名或密码不能为空");
- } else {
- mv.setViewName("/user/register_ok");
- mv.addObject("username", user.getUsername());
- logger.debug("注册成功");
- }
- return mv;
- }
- }
运行注册模块
流程解析
对于注册这一过程,再简单的解析一下。
1.DispatcherServlet接收到客户端的user/toRegister请求 ,使用DefaultAnnotationHadnlerMapping查询负责处理请求的处理器为user/toRegister。
2.DispatcherServlet将请求分发给名称user/toRegister的UserController处理器。
3.处理器处理完后返回ModelAndView 其中视图名称为/user/register,DispatcherServlet调用InternalResourceViewResolver组件对ModelAndView中的逻辑视图名称进行解析,得到真是的/WEB-INF/view/user/register.jsp页面。
4.返回响应页面给客户端。
5. ......同上面
知识点解析
@Controller:在POJO类定义处标注此注解,再通过<context:component-scan/>扫描响应的类包,即可使POJO成为一个能处理HTTP请求的控制器。 你可以创建很多个控制器,每个控制器用来处理不同的业务方法。如何将请求对应到控制器的任务由@RequestMapping注解承担。 @RequestMapping:在控制器的定义处以及方法的定义出都可以标注@RequestMapping注解。类的定义处标注此注解提供请求的初步映射信息,方法提供进一步的详细映射信息(也可以不在类定义出定义,在那定义的好处是省略了后面重复的定义路径同时也限制死了 当前控制器只能处理当前请求路径下的请求。)下面一节将详细讲述强大的SpringMVC请求映射规则。注意:此节我们使用了JSTL标签所以需要增加两个jar包jstl-api-1.2.jar jstl-1.2.jar 我已经将jar包放在项目lib路径下了。其它jar包已经在第一篇文章中提供,不予以重复上传。使用MAVEN的同学可以无需理会,MAVEN配置文件中已经增加着两个jar包的依赖。
结束语
在本节大家已经大致了解了SpringMVC的内部运作机制,其内部实现代码暂不作剖析。注册功能还很不完善,如AJAX请求校验,SpringMVC自带的校验处理 本节均为涉及。后面章节会专门作出讲解。
下一讲我们将学习Spring的映射规则已经参数的绑定,URL映射、请求参数映射、请求方法映射、请求头映射等。通过下节大家可以看到Spring强大而又灵活的映射方法为我们的开发带来了很多好处。