闲暇之余想要整理一下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初始化容器以后会对组件进行初始化,如下图:
下面我们只简单介绍各组件的含义:
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的大概创建过程,如过程中有问题,请指正!