目录

前言

一 DispatchServlet

1.什么是DispatchServlet

2.源码分析

(1)几个重要的属性

(2)onRefresh

(2)关键方法doService()

3.总结DispatchServlet

二 实例

1.web.xml中配置DispatchServlet

2.配置Spring MVC的context的内容

3.使用@Controller和 @RequestMapping增加业务逻辑代码

 三 总结


前言

经过小白新手web开发简单总结(十一)-数据库连接的相关优化(数据源DataSource)小白新手web开发简单总结(十二)-数据库连接的相关优化(事务管理)小白新手web开发简单总结(十三)-数据库连接的相关优化( Hibernate的使用)小白新手web开发简单总结(十五)-数据库连接的相关优化( MyBatis的使用)已经将小白新手web开发简单总结(八)-数据库HSQLDB实例这个中的数据访问层(DAO层)的逻辑已经优化好了,增加了数据库连接池、ORM以及业务逻辑层增加事务管理。但是在小白新手web开发简单总结(八)-数据库HSQLDB实例中的web层一直都是直接通过HttpServlet来处理浏览器发送过来的请求。而在Spring MVC中有一个专门前端控制器DispatchServlet,进行URL的请求处理。

web层的Spring MVC架构具有开发灵活,松散耦合特点:

  • Model层:封装了需要返回给浏览器显示的信息,一般是HTML;
  • View层:网页、jsp,展示Model层的数据;
  • Controller层:处理浏览器发送过来的请求,将不同的Model,传递到对应的View中

一 DispatchServlet

1.什么是DispatchServlet

DispatchServlet实际上继承于HttpServlet,是一个标准的Servlet。作用:根据设置的匹配规则进行拦截浏览器发出的请求,然后将请求转发给Spring MVC控制器。

2.源码分析

(1)几个重要的属性

  • private MultipartResolver multipartResolver:用于处理文件上传服务,如果有文件需要上传,那么就需要将当前的HttpServletRequest包装成DefaultMultipartHttpServletRequest,并将么个上传的内容封装成CommonsMultipartFile对象
  • private LocaleResolver localeResolver:国际化问题,本地解析策略
  • private ThemeResolver themeResolver:解析主题,比如可以定制个性化版面
  • private List<HandlerMapping> handlerMappings:主要负责预处理、后处理等一系列执行处理和满足条件的控制器的执行,如请求映射关系
  • private List<HandlerAdapter> handlerAdapters:根据Handler的类型定义不同的处理规则
  • private List<HandlerExceptionResolver> handlerExceptionResolvers:当Hander处理出错后,会通过该类将错误日志保存在log文件中,默认的实现类为SimpleMappingExceptionResolver
  • private RequestToViewNameTranslator viewNameTranslator:将指定的viewName按照定义的RequestToViewNameTranslator替换成想要的格式
  • private FlashMapManager flashMapManager:用于生成FlashMap管理器
  • private List<ViewResolver> viewResolvers:根据视图名称解析视图。

(2)onRefresh

    protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }

 通过该方法来初始化里面的各个属性。基本逻辑就是首先会读取在自行配置的bean,如果没有配置,则读取默认的 org.springframework.web.servlet目录下的DispatchServlet.properties里面指定的bean:

# 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.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	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

(2)关键方法doService()

因为DispatchServlet继承于HttpServlet,那么当接收到对应匹配的url之后,那么就会执行到doService()方法,那么其中关键的实现应该就在该doService()中。梳理doSerivice()代码,里面重要的代码逻辑就是调用了

 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  //。。。。。。。
        //最终就是调用了下面的方法来实现逻辑
        this.doDispatch(request, response);
  //。。。。。。。
}

进入到doDispatch()中看下具体的逻辑:源码可以具体查看在 org.springframework.web.servlet目录下的DispatchServlet.java代码,这里主要标识几个主要的逻辑:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    //1.如果指定multipartResolver,则将request包装成MultipartHttpServletRequest
                    processedRequest = this.checkMultipart(request);
                    //2.获取该请求对应的HandlerMapper
                    mappedHandler = this.getHandler(processedRequest);
                    //3.获取该Handler对应的HandlerAdapter
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
               //=== HandlerMapper的拦截作用,调用拦截器HandlerInterceptor的preHandler()
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    //4.执行Handler里面的业务逻辑,返回ModelAndView
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    //5.如果没有设置视图,则应用默认的视图
                    this.applyDefaultViewName(processedRequest, mv);
              //=== HandlerMapper的拦截作用,调用拦截器HandlerInterceptor的postHandle()
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                } 
                //6.将封装的ModelAndView转发到对应的页面
              //=== HandlerMapper的拦截作用,调用拦截器HandlerInterceptor的afterCompletion()
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {    
            } 
        } finally {
        }
    }
  • 第一步:如果指定multipartResolver,则通过checkMultipart(request)将request包装成MultipartHttpServletRequest,供后面去使用
  • 第二步:通过getHandler(processedRequest)获取MapperHandler

每个请求都需要一个HandlerMethod来处理,具体接收一个请求交给哪个HandlerMethod来处理,那就是有HandlerMapping来处理。

HandlerMethod(控制器)也就是我们在项目中定义实现业务逻辑的地方,有多种实现方式:

  • 1)实现org.springframework.web.servlet.mvc.Controller接口

通过复写handleRequest()来实现具体的业务逻辑

  • 2)基于@Controller注解方式

          @Controller:可以返回到指定的如jsp、ftl、html等模版页面,需要配合视图解析器InternalResourceViewResolver才可以,若要返回实体对象,必须在增加@@ResponseBody

          @RestController:相当于@ResponseBody+@Controller,只能返回String、Object、Json等实体对象,无法返回jsp或者http页面

  • 3)实现org.springframework.web.HttpRequestHandler接口

通过复写handleRequest()来实现具体的业务逻辑

HandlerMapping就是负责将url映射到对应的handler上,根据请求的url查找对应的实际业务逻辑处理的Handler,具体完成两项工作:

  •  1)根据请求获取HandlerMethod,即当前的请求具体交给哪个Controller的哪个方法来处理;
  •  2)将HanlderMethod和当前系统的Interceptor又被封装到HanlderExcutionChain,最后返回的就是这个HanlderExcutionChain对象,完成Interceptor的拦截作用。

HandlerMapping(url mapping的控制器),有几种实现方式:

  • 1)org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping:默认的方式,不需要显示声明。需要在配置文件中将url和controller name绑定到一起
  • 2)org.springframework.web.servlet.handler.SimpleUrlHandlerMapping:通过properties形式,配置url和controller的映射,而不需要controller name,需要显示声明SimpleUrlHandlerMapping
  • 3)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping:通过@RequestMapping,配置url和controller的映射
  • 4)org.springframework.web.servlet.function.support.RouterFunctionMapping 
  • 第三步:通过getHandlerAdapter(mappedHandler.getHandler())获取HandlerAdapter

遍历所有的HandlerAdapter集合,查找支持到这次请求的HandlerAdapter。

HandlerMethod要与HandlerAdapter配合使用,有什么样的Handler就要配置什么样的HandlerAdapter:

  • 1)org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter:Http请求处理适配器:处理的HandlerMethod是需要实现HttpRequestHandler接口的实现类
  • 2)org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter:简单控制器处理适配器:处理的HandlerMethod是需要实现Controller的实现类
  • 3)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter:通过@Controller的处理适配器:处理的HandlerMethod是需要增加@Controller的类
  • 4)org.springframework.web.servlet.function.support.HandlerFunctionAdapter
  • 第四步:通过 ha.handle(processedRequest, response, mappedHandler.getHandler())获取ModelAndView

在Handler里会含有一些逻辑处理,逻辑处理完会产生一些需要显示到浏览器中的信息,这些信息称为Model,当然这些Model是普通用户无法查看的,所以就需要将这些Model发送到一个视图View(如jsp),这个Model和View封装到一起就是ModelAndView。

在找到对应的HandlerAdapter之后,那么在HandlerAdapter中就根据特定规则,通过handle()去执行Handler(也就是在项目中增加的url对应的业务逻辑的方法里面的功能,通常也会在该项目中对应的业务逻辑方法中返回ModelAndView对象),最后将Model和View打包,返回ModelAndView。那么我觉得这个HandlerAdapter也就是承担了在MVC中的Controller的作用:处理浏览器发送过来的请求,并将返回的Model传递给View层,这样控制器和特定的视图进行解耦。

ModelAndView:模型和视图(View)。视图的设置方式有两种:可采用字符串视图名称形式,通过配置的ViewResolver对象解析成View;或者直接设置View。

  • 1)可以通过不同的构造函数指定返回的页面,如

    public ModelAndView(String viewName) {
        this.view = viewName;
    }
  • 2)可以通过setViewName()跳转到指定的页面,如

    public void setViewName(@Nullable String viewName) {
        this.view = viewName;
    }
  • 3)可以通过addObject()方法返回给View(如jsp)相应的数据,在View中可以直接通过attributeName取出对应的值。
  public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) {
        this.getModelMap().addAttribute(attributeName, attributeValue);
        return this;
  }

默认的ViewResolver为org.springframework.web.servlet.view.InternalResourceViewResolver。

InternalResourceViewResolver用于访问如jsp、HTML、XHTML这样的View,其中有prefix(前缀)和suffix(后缀)两个属性,将在ModelAndView中配置的视图字符串转换成真实路径的资源url。prefix配置的就是View存放的路径,而suffix配置的就是View的后缀名


前面四步都是Controller层的相关逻辑,接下来就是Model层和View层 

  • 第五步:如果ModelAndView没有设置view,则通过applyDefaultViewName(processedRequest, mv)给定一个默认的View

遗留问题:需要验证下是不是该第四步返回的ModelAndView是不是就是Handler中返回的ModelAndView呢?

解答问题:这个就是我们在Controller中定义的与url相关的Handler里面实例化的ModelAndView

遗留问题:需要验证下该ModelAndView默认的View是指的什么?

解答问题:例如jsp就会对应的JspView等,就是实际的渲染的View

  • 第六步:通过processDispatchResult()将最后的ModelAndView的Model转发到对应到View中。

该方法的主要功能体现在this.render(mv, request, response)中,进入到该方法中看下主要逻辑:

 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String viewName = mv.getViewName();
        View view;
        if (viewName != null) {
        //1.如果获取ModelAndView中设置了viewName,则通过配置的viewResolvers将字符串路径转换成View
            view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
        } else {
         // 2.如果没有设置viewName,则从ModelAndView中获取View
            view = mv.getView();
        }
        try {
            if (mv.getStatus() != null) {
                response.setStatus(mv.getStatus().value());
            }
           //3.将Model传递到view
            view.render(mv.getModelInternal(), request, response);
        } catch (Exception var8) {
        }
    }

 这样就完成了将Model层的信息显示到View层。


通过上面六步之后完成了一个请求从接收到返回给浏览器的整个过程,当然刚才在介绍HandlerMapping作用的时候,一个作用就是url和controller的映射,另外一个作用就是Interceptor拦截作用,那么其实在可以看到在doDispatch()方法中的第四步执行业务逻辑之前、第六步业务逻辑之后,将Model返回给View之前、以及最后完成View渲染(这个相关代码在render()中实现的)之后已经分别完成Interceptor对应的方法的调用。

那么很明显的Interceptor主要作用拦截Controller请求,作用在用户的每一次请求过程中,那么像一些用户登陆权限的校验等就可以放到Interceptor中,对一些静态资源无法拦截。一般需要通过实现HandlerInterceptor或继承HandlerInterceptorAdapter,通常配置在该Servlet的配置文件中;

public interface HandlerInterceptor {
    //在业务处理器处理请求之前被调用。预处理,可以登陆校验、权限校验等
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
    //在业务处理器处理请求执行完成后,生成视图之前
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
    //完全处理请求后被调用,可用于清理资源等。处理返回,此时已经完成了页面渲染
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

而在web.xml配置的Filter主要作用统一设置字符集等。依赖于Servlet容器,仅在初始化的时候调用一次。一般需要实现Filter接口,通常配置在web.xml中。

public interface Filter {
    //filter对象创建时执行(Tomcat加载Filter时)
    default void init(FilterConfig filterConfig) throws ServletException {
    }
    //执行过滤的逻辑的具体实现
    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
    //filter对象销毁时(Tomcat关闭时)
    default void destroy() {
    }
}

3.总结DispatchServlet

经过源码分析之后,再来看其DispatchServlet整个过程大体如下:

(1)DispatchServlet通过匹配到对应的url,拦截对应请求;

(2)通过HandlerMapping来匹配到对应的Handler,同时返回增加了拦截功能的HandlerExecutionChain;

(3)通过HandlerMapping中的对应的Handler找到对应的HandlerAdapter,通过HandlerAdapter来执行Handler的相关业务逻辑;

(4)在HandlerAdapter 中将Handler返回的Model以及View的封装ModelAndView返回给DispatchServelet;

(5)DispatchServelet调用ViewResolver返回View;

(6)完成View的渲染。

遗留问题:需要增加一个流程图来进一步分析DispatchServlet

二 实例

还是通过一个实例来看下Spring MVC到底是怎么优化小白新手web开发简单总结(八)-数据库HSQLDB实例中的第(6)步的操作。

1.web.xml中配置DispatchServlet

 <!--增加Spring MVC-->
    <servlet>
        <servlet-name>sql-web</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--如果需要设置init-param,必须要放到load-on-startup之前-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/spring-context.xml</param-value>
        </init-param>
        <!--表示启动容器的时候就初始化该Servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>sql-web</servlet-name>
        <!--https://blog.csdn.net/weixin_44415997/article/details/100098081解决路径匹配不到的情况-->
<!--        <url-pattern>/mvc/*</url-pattern>-->
        <!--第二种解决方式:直接通过添加后缀名的形式来拦截请求。该后缀名任意-->
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
  • (1)<servlet-mapping>

每个<servlet>必须匹配<servlet-mapping>,通过<servlet-mapping>去拦截匹配<url-pattern>规则的相应的浏览器发送过来的请求:如果匹配成功,那么对应的这些请求就交给DispatcherServlet来处理。

具体对这个的一个理解可参见小白新手web开发简单总结(十七)-DispatcherServlet中的url-pattern的一点反思。在本实例中采用后缀名的方式来进行拦截url。

 

 

  <!--第二种解决方式:直接通过添加后缀名的形式来拦截请求。该后缀名任意-->
        <url-pattern>*.html</url-pattern>

 其中像<serlvet-name>等这些简单的配置项不在多余介绍,主要总结下下面两个:

  • (2)<init-param>

其中DispatcherServet使用的默认的WebApplicationContext作为上下文,默认的配置读取的配置文件是“/WEB-INF/<servlet-name>-servlet.xml”,当然DispatcherServet也提供了<init-param>来配置初始化参数,从而替换默认值。

  • contextConfigLocation

指定Context的位置,这个<param-value>可以指定多个字符串,使用“,”作为分隔符。

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/application-context*.xml</param-value>
        </init-param>
  • contextClass

实现了WebApplicationContext的类,默认的就是org.springframework.web.context.support.XmlWebApplicationContext。该类用来创建web组件的JavaBean,如控制器、视图解析器以及处理器映射。

        <init-param>
            <param-name>contextClass</param-name>
            <param-value></param-value>
        </init-param>

这个WebApplicationContext与小白新手web开发简单总结(九)-ContextLoaderListener通过ContextLoaderListener中返回的WebApplicationContext是由不同作用的,可以看见小白新手web开发简单总结(九)-ContextLoaderListener

ContextLoaderListener初始化的WebApplicationContext是为整个应用程序所共享,不管表现层采用什么框架,主要针对的就是Dao层、Service层的JavaBean;

而通过DispatcherServlet初始化的WebApplicationContext只是针对Spring Web MVC有效的JavaBean,如Controller、HandlerMappping、HandlerAdapter等等,主要针对的web相关的JavaBean。

并且DispatcherServlet初始化的WebApplicationContext会将ContextLoaderListener初始化的WebApplicationContext设置为Parent。

遗留问题:感觉还是没有理解透彻,需要在细一点,为什么要有这两个WebApplicationContext呢?两个可以互相使用吗(加载对方的xml文件)?

注意如果要设置<init-param>一定要放到 <load-on-startup>之前。

  • (3)<load-on-startup>

用来标记web应用启动的时候,加载对应Servlet的顺序:

(1)如果>=0:在web应用启动的时候,就加载该Servlet。数字越小,优先级越高;当值一致的时候,自行选择加载。

(2)当不设置该配置项或者<0时:在使用Servlet的时候,在加载该Servlet。

2.配置Spring MVC的context的内容

在DispatcherSerlvet的源码中可以看到里面有一个默认的org/springframework/web/servlet/DispatcherServlet.properties文件,当然这些属性也可以自行定义。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--注解驱动:自动配置最新的注解的处理器映射器和处理器适配器-->
    <!--    <mvc:annotation-driven/>-->
    <!--    <mvc:default-servlet-handler/>-->
    <!--如果要使用RequestMappingHandlerMapping这种方式,必须增加,否则无法加载对应注解的类-->
    <context:component-scan base-package="com.wj.mysql.controller"/>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

    <!--    <bean id=""-->
    <!--在web.xml中也可以配置拦截器-->
    <!--    <mvc:interceptors>-->
    <!--        <mvc:interceptor>-->
    <!--            <mvc:mapping path="/**"/>-->
    <!--            <ref bean=""-->
    <!--        </mvc:interceptor>-->
    <!--    </mvc:interceptors>-->
    <!--jsp最佳是放到WEB-INF文件下,避免JSP可以通过手动输入的url被直接访问到,只有控制器才能访问。
    支持多个view resolver。-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:suffix=".jsp"
          p:prefix="/WEB-INF/views"/>
    <!--解决路径模糊匹配,页面404-->
    <!--  <bean class="com.wj.mysql.utils.SetAlwaysUseFullPathForDispatcher"/>-->

</beans>

这里唯一要提的一点就是如果要使用RequestMappingHandlerMapping这种方式,必须增加  <context:component-scan base-package="com.wj.mysql.controller"/>,否则无法加载对应注解的类。base-package就是你对应的所有Spring MVC对应的类的包。

可以配置拦截器,用来对该次请求进行拦截。

可以增加InternalResourceViewResolver,通过添加p:prefix和p:suffix,这样在跳转到对应的jsp页面的时候,就不需要添加对应的路径,只需要使用jsp的文件名就可以了。

3.使用@Controller和 @RequestMapping增加业务逻辑代码

代码逻辑很简单就是利用之前增加的DAO层的代码,完成一次插入和查询操作,并且把查出的内容放到booklist.jsp中显示

@Controller
@RequestMapping("/mvc")
public class BookMvcController {
    @Autowired
    private BookServiceImpl service;
    @RequestMapping(value = "/getbook")
    public ModelAndView getBook(HttpServletRequest request,
                                HttpServletResponse response) {
        Book book = new Book();
        book.setName("Spring MVC");
        book.setPrice(49.0);
        book.setOnline(new Date());
        int result = service.insert(book);
        System.out.println("=====  插入的数据,返回为:" + result);
        List<Book> books = service.select();
        System.out.println("====   查询的数据为:");
        for (Book bo : books) {
            System.out.println(bo.toString());
        }
        ModelAndView modelAndView = new ModelAndView("/booklist");
        modelAndView.addObject("book",books);

        //增加业务处理之后,将返回的数据传递给ModelAndView
        return  modelAndView;
    }
}

对应的booklist.jsp的代码逻辑如下

<%@ page import="com.wj.mysql.model.Book" %>
<%@ page import="java.util.List" %><%--
  Created by IntelliJ IDEA.
  User: wenjing.liu
  Date: 2021/3/31
  Time: 14:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<P>目前数据库中的所有的书的信息如下:</P>
<%
    List<Book> bookList = (List<Book>) request.getAttribute("book");
    for (int i = 0; i < bookList.size(); i++) {
        Book book = bookList.get(i);
%>
        <label><%= book.toString() %>
        </label>
        <br>
<%
    }
%>

</body>
</html>

通过IDEA成功运行项目,通过访问http://localhost:8080/mvc/getbook.html,已经可以成功的显示目前数据库中已有的数据的信息。 

代码以及上传到github:https://github.com/wenjing-bonnie/sql-web.git对应的代码的tag为example16(因为项目在一直更新,所以通过打tag的方式来标记这次代码) 


通过@Controller和 @RequestMapping两个注解,简化之前方式自行去继承HttpServlet的方式。在写请求的时候,可以不在需要对每个请求单独去继承HttpServlet。

 三 总结

  • 1.DispatcherServlet继承于HttpServlet,可根据设置的url匹配原则,拦截浏览器发出的请求;
  • 2.在DispatcherServlet中有几个重要的属性,默认值在org.springframework.web.servlet目录下的DispatchServlet.properties目录下,如果在项目中不指定,则使用默认值
  • 3.HandlerMethod对应项目中url匹配的处理业务逻辑的方法;

  • 4.HandlerMapping是url与HandlerMethod的映射关系的集合,常用的为RequestMappingHandlerMapping,即通过@RequestMapping的方式将url与HandlerMethod进行映射;

  • 5.HandlerMapping还具有Interceptor作用,可以针对该次的请求进行拦截处理;

  • 6.HandlerAadapter是根据HandlerMethod来找到对应的处理适配器,用来执行HandlerMethod中的处理业务的方法,与RequestMappingHandlerMapping对应的处理适配器为RequestMappingHandlerAdapter;

  • 7.通过HandlerAadapter执行完业务逻辑之后,返回ModelAndView;所以HandlerAadapter承担了MVC模型中的Controller的作用;

  • 8.根据设置的ViewResolver,将对应业务逻辑处理之后的信息Model,传递给View,完成View的渲染;

经过前面的一些积累,在使用web应用开发中的一些框架,显得比以前轻松很多。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐