SpringMVC框架学习(二)

三、SpringMVC进阶

1、运行流程图解

<1>、流程图

SpringMVC框架学习(二)

<2>、Spring工作流程描述

1) 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获;
2) DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI):
判断请求URI对应的映射
① 不存在:
 再判断是否配置了mvc:default-servlet-handler:
 如果没配置,则控制台报映射查找不到,客户端展示404错误
 如果有配置,则执行目标资源(一般为静态资源,如:JS,CSS,HTML)
② 存在:
 执行下面流程
3) 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
4) DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
5) 如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法【正向】
6) 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
① HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
② 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
③ 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
④ 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
7) Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
8) 此时将开始执行拦截器的postHandle(…)方法【逆向】
9) 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet,根据Model和View,来渲染视图
10) 在返回给客户端时需要执行拦截器的AfterCompletion方法【逆向】
11) 将渲染结果返回给客户端

2、Spring整合SpringMVC

<1>、配置监听器
 <!--初始化SpringIOC容器的监听器-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
 <!--SpringMVC的前段控制器-->
    <servlet>
        <servlet-name>springDispatcherServlet</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>springDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

创建Spring的配置文件:applicationContext.xml

 <!--Spring的配置文件-->
    <bean id="person" class="ss.beans.Person">
        <property name="name" value="Spring+SpringMVC"></property>
    </bean>

    <!--Spring的组件扫描-->
    <context:component-scan base-package="ss">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:exclude-filter>
    </context:component-scan>

springmvc的配置文件:

 <!--SpingMVC组件扫描-->
    <context:component-scan base-package="ss" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:include-filter>
    </context:component-scan>

    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--处理静态资源-->
    <mvc:default-servlet-handler/>
    <mvc:annotation-driven/>

DAO层:

@Repository
public class UserDao {
    public UserDao() {
        System.out.println("UserDao......");
    }
    public void hello(){
        System.out.println("UserDao Hello");
    }
}

Service层:

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    public UserService() {
        System.out.println("UserService......");
    }
    public void hello(){
        userDao.hello();
    }
}

Handler层:

@Controller
public class UserHandler {

    @Autowired
    private UserService userService;

    public UserHandler() {
        System.out.println("UserHandler......");
    }

    @RequestMapping("/hello")
    public String hello(HttpSession session){
        userService.hello();

        ServletContext servletContext = session.getServletContext();
        //SpringIOC容器
        //ApplicationContext context = (ApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        //工具类
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);

        Person person = context.getBean("person", Person.class);
        person.sayHello();

        return "success";
    }
}

index.jsp:

<body>
    <a href="hello">Hello SpringMVC</a>
  </body>

当然我们也可以书写我们自己的监听器和Servlet:
监听器:

@WebListener()
public class MyServletContextListener implements ServletContextListener{

    /**
     * 当监听到ServletContext被创建,执行该方法
     * @param sce
     */
    public void contextInitialized(ServletContextEvent sce) {
        //创建SpringIOC容器对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //将SpringIOC容器对象绑定到ServletContext
        ServletContext servletContext = sce.getServletContext();
        servletContext.setAttribute("applicationContext", context);
    }

    public void contextDestroyed(ServletContextEvent sce) {

    }
}

Servlet:

public class HelloServlet extends HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
            throws javax.servlet.ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
            throws javax.servlet.ServletException, IOException {
        //访问SpringIOC容器中的person对象
        //从ServletContext对象中获取SpringIOC容器对象
        ServletContext servletContext = getServletContext();

        ApplicationContext applicationContext = (ApplicationContext) servletContext.getAttribute("applicationContext");

        Person person = applicationContext.getBean("person", Person.class);
        person.sayHello();
    }
}
<2>、SpringIOC容器和SpringMVC IOC容器的关系

1) 在 Spring MVC 配置文件中引用业务层的 Bean
2) 多个 Spring IOC 容器之间可以设置为父子关系,以实现良好的解耦。
3) Spring MVC WEB 层容器可作为 “业务层” Spring 容器的子容器:
即 WEB 层容器可以引用业务层容器的 Bean,而业务层容器却访问不到 WEB 层容器的 Bean
SpringMVC框架学习(二)