闲暇之余想要整理一下java开发进程中拦截器的各种创建方式,也为大家以后创建能够作为一个参考。(在这里我是用idea进行编程,个人习惯)

一、java创建servlet原理内容

在运行一个程序之前我习惯性的了解一下这个东西的原理内容,也把我的理解分享给大家。

  • 1.什么是servlet
    servlet是基于客户端与服务端数据库或者容器的一个中间层,它所实现的功能与CGI(Common Gateway Interface,公共网关接口)几乎相同,但是在性能以及耦合性等大大优于CGI,因为独立于容器,所以一套统一的API就可以调用可访问容器,对于容器java开发程序员也可以不用了解的很全面。
  • 2.servlet工作原理

    下面就详细解释一下这张图,首先客户端发送一个Http请求到给容器,例如我本地访问http://127.0.0.1:8080,随后容器会从磁盘中加载相应servlet,随后会将http请求处理为request请求发送给加载完成的servlet,这个时候就是咱们的代码处理了,处理完成后以response回传到容器,容器会将回传信息处理为http信息,响应客户端请求。

这个图应该能比较直观的看到其实在tomcat中,tomcat相当于旁观者模式,真正管理servlet的是context,servlet生命周期等其余问题这里不做详细介绍。

二、基本创建servlet

首先我们需要新建一个web项目(新学习的朋友可以看一下其他博客去进行项目创建),然后配置web.xml,如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>test</servlet-name>
<!--        servlet路径配置-->
        <servlet-class>com.test.demo.Demo</servlet-class>
        <init-param>
<!--            配置初始化参数-->
            <param-name>param1</param-name>
            <param-value>xiaoming</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>test</servlet-name>
        <url-pattern>/api/v1/test.do</url-pattern>
    </servlet-mapping>
</web-app>

我们在com.test.demo的package下创建我们的servlet类,代码实现比较简单,如下:

package com.test.demo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class Demo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //        获取初始化参数
        String name = req.getParameter("param1");
        System.out.println(name);
//        重定向页面
        resp.sendRedirect(req.getContextPath()+"/index.jsp");
    }
}

三、springMvc创建servlet

springMvc主要介绍一下三个servlet,HttpServletBean、FrameworkServlet、DispatcherServlet。

  • 1.HttpServletBean

HttpServletBean没有参与实现,只是重写了GenericServlet的init方法为initServletBean()方法,这个时候我们可以在FrameworkServlet中看到这个方法被重写。

  • 2.FrameworkServlet
    上图中有一个比较重要的点即
this.webApplicationContext = this.initWebApplicationContext();

这个位置创建并刷新了spring的子容器,以后都不用去初始化容器,并且重写了doGet,doPost,service等方法,查看源码会发现所有重写的方法都实现了一个方法叫processRequest,继续深入,我们会发现这里面实现了doService,这个doService是一个空方法,会在DispatcherServlet中进行具体实现,其实不难看出FrameworkServlet在这里起到的作用就是初始化容器并且作为程序的入口。

  • 3.DispatcherServlet

DispatcherServlet在FrameworkServlet初始化容器以后会对组件进行初始化,如下图:

springboot对用servlet版本 springboot与servlet关系_java

下面我们只简单介绍各组件的含义:

initMultipartResolver为处理文件上传请求;

initLocaleResolver为通过request解析出locale,locale为当前区域声明;

initThemeResolver为通过request解析出Theme;

initHandlerMappings为存储URL与controller之间的映射;

initHandlerAdapters为自定义各种Handler;

initHandlerExceptionResolvers为页面渲染前异常处理;

initRequestToViewNameTranslator如没有返回值,则此组件可查询到相关view;

initViewResolvers将String或者locale类型的视图名解析为view;

initFlashMapManager管理FlashMap。

除了初始化组件之外还会对请求进行处理,这个时候入口自然就是我们之前所说的doService,在doService中会对request请求设置了一些属性,这里不详细介绍,主要介绍它调用的另一个方法doDispatch,也是DispatcherServlet最重要的方法。下面边通过看代码边了解。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//接受的request
    HttpServletRequest processedRequest = request;
//处理请求的处理器链
//包含有处理器Handler和对应的拦截器Interceptor
    HandlerExecutionChain mappedHandler = null;
//判断是否为上传
    boolean multipartRequestParsed = false;
//获取异步请求
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
//ModelAndView网上有很多详细的介绍
        ModelAndView mv = null;
//如果是处理请求中出现的异常渲染到视图中;
//如果是渲染中出现异常,则直接抛出
      Exception dispatchException = null;
        try {
            processedRequest = this.checkMultipart(request);
            multipartRequestParsed = processedRequest != request;
            //找到相应的Handle
            mappedHandler = this.getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                this.noHandlerFound(processedRequest, response);
                return;
            }
	    //找到相应的HandlerAdapter
            HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
            //判断头文件中Last-Modified是否与上一次请求相同
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }

                if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            //拦截器执行
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            //相应HandlerAdapter开始执行,并返回数据
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            this.applyDefaultViewName(processedRequest, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception var19) {
            dispatchException = var19;
        }
        //数据处理并展示在view
	this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } catch (Exception var20) {
        this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20);
    } catch (Error var21) {
        this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21);
    } finally {
    //判断是否异步请求
        if (asyncManager.isConcurrentHandlingStarted()) {
        //执行异步拦截器
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
            //删除上传请求资源
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }

    }

}

上面简单介绍了大致的执行流程以及代码含义,小伙伴们要学会自己理解哦。

四、springBoot创建servlet

其实通过之前的讲解已经把servlet讲的差不多了,springBoot更多是通过注解去节省配置文件的繁琐过程,所以通过一个小例子大家简单看一下。
首先第一步一定要记得在启动类上添加@ServletComponentScan注解,此注解主要扫描包里面的servlet容器。

@SpringBootApplication
@ServletComponentScan
public class SpringbootApplication extends SpringBootServletInitializer{
   
   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(SpringbootApplication.class);
   }

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

其次只需要通过在servlet中调用注解@WebServlet即可

@WebServlet(name = "userServlet",urlPatterns = "/v1/api/test/customs")
public class UserServlet extends HttpServlet{

    @Override
     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       
       resp.getWriter().print("custom sevlet");
         resp.getWriter().flush();
         resp.getWriter().close();
     }

    
   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
         throws ServletException, IOException {
      this.doGet(req, resp);
   }

    
    
}

以上便简单的介绍了一下servlet的大概创建过程,如过程中有问题,请指正!