一. Servlet
1. 什么是 Servlet ?
Java Servlet 是运行在服务器上的程序,Servlet 本身是一个接口,多数人所说的 Servlet 泛指一个实现了此接口的类,用于扩展基于 HTTP 协议的 web服务器(如 Tomcat,就是一个Servlet容器 ),从而实现网页上的一些交互功能。交互的实现:客户端通过 HTTP 协议发送请求到服务器,服务器调用 Servlet 对请求生成响应后返回给客户端。
SpringBoot 内置了三种 Servlet容器
- Tomcat:默认web服务器,最稳定,最好
- Jetty:最垃圾
- Undertow:更适用于IO密集型服务器,性能和Tomcat差不多
2. Servlet 原理
package javax.servlet;
import java.io.IOException;
public interface Servlet {
/*
Tomcat传入一个ServletConfig对象,创建并初始化出一个Servlet对象
这个Servlet对象只能被初始化出一次,以后不再调用此方法
*/
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig(); //返回Tomcat传入的ServletConfig对象
/*
当有请求发送到Servlet,Tomcat就调用service()方法处理请求
每收到一次请求,Tomcat就调用一次service()方法
ServletRequest和ServletResponse对象由Tomcat封装好自动传入
*/
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo(); //返回关于此Servlet的一些描述信息
/*
当关闭Tomcat时,就会调用destroy()方法销毁Servlet
*/
void destroy();
}
Servlet 生命周期:
- 初次访问,调用 init() 和 service() 方法
- 后续访问,调用 service() 方法
- 关闭 Tomcat 服务器,调用 destroy() 方法
ServletConfig 接口
Tomcat 实现了 ServletConfig 接口,提供此对象,从而调用 init() 方法初始化 Servlet
package javax.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();//获取Servlet在 web.xml 或 注解 中配置的name属性值
ServletContext getServletContext();//获取Servlet上下文对象
String getInitParameter(String var1);//获取Servlet初始化参数
Enumeration<String> getInitParameterNames();//获取所有Servlet初始化参数名
}
ServletContext 接口(三大域对象之一,另外两个是request,session)
Tomcat 实现 ServletContext 接口,该对象是一个全局的储存信息的空间,被称为 Servlet应用程序,它提供了所有 Servlet 所共有的各种资源和功能的访问(即共享),交互时所有用户共用一个 ServletContext 对象可以节省空间,提高效率。
ServletContext 和 request 可以实现 Servlet 之间的通讯
使用request域,request对象会随着请求的结束而结束,资源会被回收(最常用)
使用ServletContext会消耗大量的资源
ServletContext 里保存的对象被称为属性(Attribute),以下方法负责处理属性
Object getAttribute(String var1);
Enumeration<String> getAttributeNames();
void setAttribute(String var1, Object var2);
void removeAttribute(String var1);
GenericServlet 抽象类
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {}
GenericServlet 类实现了 Servlet和ServletConfig 接口,对其中的所有方法提供了默认实现,从而简化了代码的维护
HttpServlet 抽象类
public abstract class HttpServlet extends GenericServlet {}
HttpServlet 扩展了 GenericServlet,提供了两个 service() 的重写方法,同时定义了7个do方法,分别为:doGet,doPost,doHead,doPut,doTrace,doOptions,doDelete
/*
第一个重写的service方法
1.子类转父类,把ServletRequest和ServletResponse对象强制转换为HttpServletRequest和HttpServletResponse类型
2.把强转的对象作为参数调用另一个service重写方法
*/
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException("non-HTTP request or response");
}
this.service(request, response);
/*
第二个重写的service方法
1.解析传入的HttpServletRequest和HttpServletResponse对象
2.根据解析逻辑,选择调用doGet,doPost,doHead,doPut,doTrace,doOptions,doDelete中的一个方法
*/
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
其中,doGet 和 doPost 方法最常用,这就是为什么我们自己定义一个Servlet,它继承 HttpServlet 后不需要自己重写 service 方法而只需要重写 doGet 或 doPost 方法的原因
3. HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网应用最广泛的一种网络协议,它是TCP/IP协议的一个应用层协议
4. 请求 和 响应
HttpServletRequest 接口
提供了获得请求行、请求头、请求体里各类信息的方法
service中默认使用ISO-8859-1编码,要解决中文乱码,则:
doGet方法中:parameter = newString(parameter.getbytes(“iso8859-1”),“utf-8”);
doPost方法中:request.setCharacterEncoding(“UTF-8”);
public interface HttpServletRequest extends ServletRequest {
String BASIC_AUTH = "BASIC";
String FORM_AUTH = "FORM";
String CLIENT_CERT_AUTH = "CLIENT_CERT";
String DIGEST_AUTH = "DIGEST";
String getAuthType();
Cookie[] getCookies();
long getDateHeader(String var1);
String getHeader(String var1);
Enumeration<String> getHeaders(String var1);
Enumeration<String> getHeaderNames();
int getIntHeader(String var1);
String getMethod();
String getPathInfo();
String getPathTranslated();
String getContextPath();
String getQueryString();
String getRemoteUser();
boolean isUserInRole(String var1);
Principal getUserPrincipal();
String getRequestedSessionId();
String getRequestURI();
StringBuffer getRequestURL();
String getServletPath();
HttpSession getSession(boolean var1);
HttpSession getSession();
boolean isRequestedSessionIdValid();
boolean isRequestedSessionIdFromCookie();
boolean isRequestedSessionIdFromURL();
}
HttpServletResponse 接口
提供各种响应错误代号,常见404,500等
public interface HttpServletResponse extends ServletResponse {
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
void addCookie(Cookie var1);
boolean containsHeader(String var1);
String encodeURL(String var1);
String encodeRedirectURL(String var1);
void sendError(int var1, String var2) throws IOException;
void sendError(int var1) throws IOException;
void sendRedirect(String var1) throws IOException;
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
void setStatus(int var1);
int getStatus();
String getHeader(String var1);
Collection<String> getHeaders(String var1);
Collection<String> getHeaderNames();
}
以流的方式加载请求数据到response缓冲区,随后由Tomcat返回响应到客户端
PrintWriter writer = response.getWriter();
ServletOutputStream outputStream = response.getOutputStream();
二. Filter(过滤器)
1. 什么是 Filter?
在客户端和Servlet容器间添加过滤器,可以拦截web资源,并在服务器获取请求前和客户端获取响应前指定特殊功能
2. 编写过滤器
- 实现 Filter接口,重写 doFilter()方法
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//filterConfig对象包含了初始化过滤器时加载的所有配置信息
//通过get方法可以获取想要的信息并打印到控制台
System.out.println("过滤器名称" + filterConfig.getFilterName());
System.out.println("初始化参数" + filterConfig.getInitParameter("username"));
System.out.println("servlet上下文对象" + filterConfig.getServletContext());
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
.../*功能代码*/
filterChain.doFilter(servletRequest, servletResponse) //完成处理后放行,继续执行下一个过滤器
}
@Override
public void destroy() {
}
}
- 在 web.xml 中配置 filter
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.codfish.filter.MyFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>zhangsan</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- SpringBoot中没有filter的配置文件,则在Filter上使用 @WebFilter 注解,在启动类上加 @ServletComponentScan(basePackages=“全包名”)
Filter 生命周期
- filter对象创建时执行 init() 方法初始化
- 每次拦截到请求,就执行过滤方法 doFilter()
- 服务器关闭,执行 destroy() 方法销毁
3. Interceptor(拦截器)
SpringMVC中使用拦截器,它是过滤器的升级版,使用方法如下
- 实现 HandlerInterceptor接口 并重写方法
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
.../*目标方法运行前的处理代码*/
return true; //类似filterChain.doFilter的功能,只有为true才可以继续后续功能
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
.../*目标方法运行后的处理代码*/
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
.../*页面响应完成之后的处理代码*/
}
}
- 在 springmvc.xml 中配置拦截器
<mvc:interceptors>
<<mvc:interceptor>
<mvc:mapping path="/*"/>
<bean class="com.codfish.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
- SpringBoot没有配置文件,则写一个配置类,实现 WebMvcConfigurer接口
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//调用registry.addInterceptor()方法配置
}
}
三. Listener(监听器)
1. 什么是 Listener?
监听器可以监听web中对象的创建、销毁、增加,修改,删除等动作的发生,然后通过回调函数进行响应处理
2. Servlet 监听器
public class MyListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("Context对象增加了属性");
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("Context对象删除了属性");
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("Context对象替换了属性");
}
}