Java基础|Servlet+Filter+Listenler基础入门


文章目录

  • Servlet
    • 1 简介
    • 2 基本部署流程
        • pom.xml
        • web.xml
        • ServletDemo01.java
    • 3 生命周期
    • 4 体系结构
    • 5 ServletContext
      • 5.1 如何获取这个对象
      • 5.2 一些方法
    • 6 Request
      • 6.1 简述
      • 6.2 获取HTTP请求的内容的一些常见方法
      • 6.3 获取请求参数
      • 6.4 获取请求参数乱码
      • 6.5 请求转发
      • 6.6 请求域对象
    • 7 Response
      • 7.1 简述
      • 7.2 输出响应参数乱码
      • 7.3 案例代码
      • 7.4 重定向
    • 8 Cookie
    • 9 Session
  • Filter
    • 1 入门代码
    • 2 生命周期
    • 3 匹配规则
    • 4 过滤链
  • Listenler
    • 1 监听器分类
    • 2 ServletContextListener
      • 作用
      • 使用场景
      • 案例代码
  • over

Servlet 1 简介 sun公司开发动态web的一门技术,是服务器三大组件(servlet,filter,listener)之一,主要用来处理请求和响应
如果想开发 Servlet 程序,需要完成
  • 编写一个类,实现 Servlet 接口,从而继承Servlet接口中所有的抽象方法
  • 通过web.xml的注册
  • 把开发好的 Java类 部署到 web服务器中
2 基本部署流程
  • 创建Maven项目,按照基本web模板新建
  • 配置pom.xml文件,导入Servlet程序包
  • 编辑web.xml文件,针对Servlet拦截转发进行配置
  • 新建实体类,继承Servlet接口并进行方法重写
  • 启动Tomcat进行测试
【Java基础|Servlet+Filter+Listenler基础入门】最后实现的效果是,当url处输入"/hello"时,Servelt将会进行拦截跳转并执行相关的方法
pom.xml
4.0.0org.example 1_Servlet_test 1.0 war1_Servlet_test Maven Webapphttp://www.example.comUTF-8 1.7 1.7 junit junit 4.11 >test javax.servlet javax.servlet-api 4.0.1 >provided 1_Servlet_testmaven-clean-plugin 3.1.0 maven-resources-plugin 3.0.2 maven-compiler-plugin 3.8.0 maven-surefire-plugin 2.22.1 maven-war-plugin 3.2.2 maven-install-plugin 2.5.2 maven-deploy-plugin 2.8.2

web.xml
Archetype Created Web Application>>First>ServletDemo01 >>First/hello

ServletDemo01.java
import javax.servlet.*; import java.io.IOException; /** * @author 13544 */public class ServletDemo01 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { // 生命周期方法:当Servlet第一次被创建对象时执行该方法,该方法在整个生命周期中只执行一次 }@Override public ServletConfig getServletConfig() { // 当停止tomcat时也就销毁的servlet return null; }@Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { // 处理请求和响应 System.out.println("hello world"); // ServletRequest 和 ServletResponse //ServletRequest:Servlet容器对于接受到的每一个Http请求,都会创建一个ServletRequest对象,并把这个对象传递给Servlet的Sevice( )方法 //ServletResponse:表示一个Servlet响应,在调用Servlet的Service( )方法前,Servlet容器会先创建一个ServletResponse对象,并把它作为第二个参数传给Service( )方法。ServletResponse隐藏了向浏览器发送响应的复杂过程}@Override public String getServletInfo() { // 提供有关servlet 的信息,如作者、版本、版权 return null; }@Override public void destroy() { // 生命周期方法:当Servlet被销毁时执行该方法 } }

3 生命周期 基本概述和相关方法
public class ServletDemo01 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { // 生命周期方法:当Servlet第一次被创建对象时执行该方法,该方法在整个生命周期中只执行一次 }@Override public ServletConfig getServletConfig() { // 当停止tomcat时也就销毁的servlet return null; }@Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { // 处理请求和响应 // 每当请求Servlet时,Servlet容器就会调用这个方法 }@Override public String getServletInfo() { // 返回一段描述 // 可以提供有关servlet 的信息,如作者、版本、版权 return null; }@Override public void destroy() { // 生命周期方法:当Servlet被销毁时执行该方法 } }

配置Servelt提前创建
有时候我们需要在Servlet创建的时候做一些资源加载等等耗时操作,所以如果Servlet在第一次接收请求的时候才创建的话必然会影响用户的访问速度,所以此时我们需要让Servlet提前创建,将Servlet的创建提前到服务器启动的时候。
通过修改web.xml中Servlet的配置可以实现:
>>HelloServlet>com.atguigu.servlet.HelloServlet1

4 体系结构 Servlet接口有一个实现类是GenericServlet,而GenericServlet有一个子类是HttpServlet,我们创建Servlet的时候会选择继承HttpServlet,因为它里面相当于也实现了Servlet接口,并且对一些方法做了默认实现;而且子类的功能会比父类的更加强大
我们编写Servlet类继承HttpServlet的时候,只需要重写doGet()和doPost()方法就行了,因为HttpServlet重写了service()方法,在service()方法中判断请求方式,根据不同的请求方式执行doXXX()方法
5 ServletContext Servlet上下文,整个项目共享这一个对象,它伴随着Servlet整个的生命周期
5.1 如何获取这个对象
ServletContext servletContext1 = getServletContext(); ServletContext servletContext3 = req.getServletContext();

5.2 一些方法
ServletContext玩法简介
6 Request 6.1 简述
请求
在Servlet API中,定义了一个HttpServletRequest接口,它专门用来封装HTTP请求消息
用我们自己的话来理解: Request就是服务器中的一个对象,该对象中封装了HTTP请求的 请求行、请求头和请求体 的内容
这个对象包含三个部分
  • 请求行: 包含请求方式、请求的url地址、所使用的HTTP协议的版本
  • 请求头: 一个个的键值对,每一个键值对都表示一种含义,用于客户端传递相关的信息给服务器(例如用户名密码等)
  • 请求体: POST请求有请求体,里面携带的是POST请求的参数,而GET请求没有请求体
而Request能干嘛呢?
  • 获取HTTP请求的 行、头、体的内容
  • 进行请求转发跳转
  • 作为请求域对象进行存取数据(有些类似于ServletContext,两者有生命周期的占用空间的不同)
6.2 获取HTTP请求的内容的一些常见方法
getMethod()获取请求方式,如get,post getContextPath()获得当前应用上下文路径 ,就是那个项目路径类似 getRequestURI()获得请求地址,不带主机名 getRequestURL()获得请求地址,带主机名// 根据请求头的name获取value // 目标:获取name为user-agent的请求头的信息 // user-agent请求头中包含的是客户端浏览器信息 getHeader(String name), 根据请求头的name获取请求头的值 // 我的理解就是提交表单的时候,用来获取用户的一些账户密码校验信息

6.3 获取请求参数
请求参数是客户端携带给服务器的由键值对组成的数据,例如"username=aobama&password=123456"这种类型的数据
携带请求参数有如下形式
  • URL地址后面附着的请求参数,例如http://localhost:8080/app/hellServlet?username=汤姆
  • 表单携带请求参数
  • Ajax请求携带请求参数(不知道是什么,后面回来看看)
方法名 返回值类型 方法描述
request.getParameterMap() Map 获取当前请求的所有参数,以键值对的方式存储到Map中
request.getParameter(“请求参数的名字”) String 根据一个参数名获取一个参数值
request.getParameterValues(“请求参数的名字”) String [] 根据一个参数名获取多个参数值
request.getParameterNames() Enumeration 获取当前请求的所有参数的参数名
示例表单代码
发送请求携带请求参数 - 锐客网 访问ServletDemo02
用户名
密码
昵称
邮箱
兴趣爱好篮球 足球 羽毛球 乒乓球

6.4 获取请求参数乱码
解决POST请求的参数乱码只需要在获取请求参数前调用request.setCharacterEncoding("UTF-8")就行了
6.5 请求转发
请求转发是从一个资源跳转到另一个资源,在这个过程中客户端不会发起新的请求
// 操作方法 request.getRequestDispatcher("路径").forward(request,response);

案例代码
ServletDemo03的代码
public class ServletDemo03 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("ServletDemo03执行了...") //请求转发跳转到ServletDemo04 request.getRequestDispatcher("/demo04").forward(request, response); } }

ServletDemo04的代码
public class ServletDemo04 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("ServletDemo04执行了...") } }

特征点
  1. 请求转发的跳转是由服务器发起的,在这个过程中浏览器只会发起一次请求
  2. 请求转发只能跳转到本项目的资源,但是可以跳转到WEB-INF中的资源
  3. 请求转发不会改变地址栏的地址
6.6 请求域对象
我们之前学过全局域的范围(ServletContext),全局域是整个项目范围的所有动态资源都能够共享的一个范围;而请求域的范围只是在一次请求中的动态资源能够共享的一个范围
相关API
  • 往请求域中存入数据:request.setAttribute(key,value)
  • 从请求域中取出数据:request.getAttribute(key)
案例代码
ServletDemo03的代码
public class ServletDemo03 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("ServletDemo03执行了...") String username = "aobama"; //将username存储到request域对象中 request.setAttribute("username",username); //请求转发跳转到ServletDemo04 request.getRequestDispatcher("/demo04").forward(request, response); } }

ServletDemo04的代码
public class ServletDemo04 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = (String)request.getAttribute("username"); System.out.println("在ServletDemo04中获取username:"+username) } }

7 Response 响应
7.1 简述
在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法
用我们自己的话说: Response就是服务器端一个对象,它里面可以封装要响应给客户端的响应行、头、体的信息
这个对象包含三个部分
  • 响应行:包含响应状态码(如404、403)、状态码描述信息、HTTP协议的版本
  • 响应头:一个个的键值对,每一个键值对都包含了具有各自含义的发送给客户端的信息
  • 响应体内容:用于展示在客户端的文本、图片,或者供客户端下载或播放的内容
能做些什么?
  • 设置响应行信息,例如设置响应状态码
  • 做响应头和响应体内容反馈给用户浏览器
7.2 输出响应参数乱码
由于服务器端在输出内容的时候进行编码使用的字符集和客户端进行解码的时候使用的字符集不一致,所以会发生响应数据乱码问题。
我们解决响应数据乱码问题只需要在获取字符输出流之前,执行如下代码就可以了:
// 输出的文本/超文本内容的编码格式设置为UTF-8 response.setContentType("text/html; charset=UTF-8");

7.3 案例代码
Servlet基础之HttpServletResponse详解
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 响应resp 一些方法的使用resp.setStatus(403); 状态码//resp.setContentType("text/html; charset=UTF-8"); // 踩坑,如果输出的是图片,设置UTF-8会乱码 String realPath = getServletContext().getRealPath("WEB-INF/m2a.jpg"); FileInputStream is = new FileInputStream(realPath); byte[] buffer = new byte[1024]; int len = 0; ServletOutputStream os = resp.getOutputStream(); while ((len = is.read(buffer)) != -1) { //写 os.write(buffer, 0, len); } os.close(); is.close(); }

7.4 重定向
重定向是由项目中的一个资源跳转到另一个资源,在这个过程中客户端会发起新的请求
response.sendRedirect("路径");

案例代码
ServletDemo02的代码
public class ServletDemo01 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("ServletDemo02执行了...") //请求转发跳转到ServletDemo02 response.sendRedirect("/webday0602/demo03"); } }

ServletDemo03的代码
public class ServletDemo03 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("在ServletDemo03执行了.....") } }

重定向的特征
  1. 重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求
  2. 重定向跳转可以跳转到任意服务器的资源,但是无法访问WEB-INF中的资源
  3. 重定向跳转浏览器的地址栏中的地址会变成跳转到的路径
重定向和请求转发的对比
  1. 重定向会由浏览器发起新的请求,而请求转发不会发起新的请求
  2. 重定向可以访问任意互联网资源,而请求转发只能访问本项目资源
  3. 重定向不能访问本项目的WEB-INF内的资源,而请求转发可以访问本项目的WEB-INF内的资源
  4. 发起重定向的资源和跳转到的目标资源没在同一次请求中,所以重定向不能在请求域中使用;而发起请求转发的资源和跳转到的目标资源在同一次请求中,所以请求转发可以在请求域中使用
8 Cookie 相关API
  • 创建一个Cookie对象(cookie只能保存字符串数据。且不能保存中文)
new Cookie(String name,String value);

  • 把cookie写回浏览器
response.addCookie(cookie);

  • 获得浏览器带过来的所有Cookie:
request.getCookies() ; //得到所有的cookie对象。是一个数组,开发中根据key得到目标cookie

  • cookie的 API
cookie.getName() ; //返回cookie中设置的key cookie.getValue(); //返回cookie中设置的value

案例代码
在ServletDemo01中创建Cookie数据并响应给客户端
public class ServletDemo01 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 创建一个cookie对象,用于存放键值对 Cookie cookie = new Cookie("cookie-message","hello-cookie"); //2. 将cookie添加到response中 //底层是通过一个名为"Set-Cookie"的响应头携带到浏览器的 response.addCookie(cookie); } }

ServletDemo02获取Cookie数据的代码
public class ServletDemo02 extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 从请求中取出cookie //底层是由名为"Cookie"的请求头携带的 Cookie[] cookies = request.getCookies(); //2. 遍历出每一个cookie if (cookies != null) { for (Cookie cookie : cookies) { //匹配cookie的name if (cookie.getName().equals("cookie-message")) { //它就是我们想要的那个cookie //我们就获取它的value String value = https://www.it610.com/article/cookie.getValue(); System.out.println("在ServletDemo02中获取str的值为:" + value); } } } } }

9 Session 相关API
// 获得session(如果第一次调用的时候其实是创建session,第一次之后通过sessionId找到session进行使用) request.getSession(); // 获取值 Object getAttribute(String name) ; // 存储值 void setAttribute(String name, Object value) ; // 移除值 void removeAttribute(String name); // 强制Session立即失效 session.invalidate(); // 获取默认的最大闲置时间 int maxInactiveIntervalSecond = session.getMaxInactiveInterval(); // 设置默认的最大闲置时间 session.setMaxInactiveInterval(15); // 1.调用request对象的方法尝试获取HttpSession对象 HttpSession session = request.getSession(); // 2.调用HttpSession对象的isNew()方法 boolean wetherNew = session.isNew(); // 3.打印HttpSession对象是否为新对象 System.out.println("wetherNew = " + (wetherNew?"HttpSession对象是新的":"HttpSession对象是旧的")); // 4.调用HttpSession对象的getId()方法 String id = session.getId(); // 5.打印JSESSIONID的值 System.out.println("JSESSIONID = " + id);

Filter 拦截器,Filter 不是一个servlet,它不能产生一个response,但是它能够在一个request到达servlet之前预处理request,也可以在 response离开servlet时处理response。换句话说,filter其实是客户端与servlet中间的一个传递者,并且它可以对要传递 的东西进行修改。
1 入门代码 效果:访问被拦截器拦的链接时会进入后端拦截器
Web.xml配置拦截器
>>First>servlet.ServletDemo01 >>First/hello encodingFilter servlet.FilterDemo01 encodingFilter/*

FilterDemo01.java
package servlet; import java.util.logging.LogRecord; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author 13544 */ @WebFilter("/*") // 访问所有资源前都会被拦截 public class FilterDemo01 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("FilterDemo01-init...."); //Filter.super.init(filterConfig); } @Override public void destroy() { System.out.println("FilterDemo01-destroy"); //Filter.super.destroy(); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("UTF-8"); // System.out.println("FilterDemo01-doFilter....."); //这句代码表示放行 filterChain.doFilter(servletRequest, servletResponse); } }

2 生命周期
生命周期阶段 执行时机 生命周期方法
创建对象 Web应用启动时 init方法,通常在该方法中做初始化工作
拦截请求 接收到匹配的请求 doFilter方法,通常在该方法中执行拦截过滤
销毁 Web应用卸载前 destroy方法,通常在该方法中执行资源释放
3 匹配规则
/* /hello *.png First

4 过滤链 一个请求可能被多个过滤器所过滤,只有当所有过滤器都放行,请求才能到达目标资源,如果有某一个过滤器没有放行,那么请求则无法到达后续过滤器以及目标资源,多个过滤器组成的链路就是过滤器链
过滤器链中每一个Filter执行的顺序是由web.xml中filter-mapping配置的顺序决定的。如果某个Filter是使用ServletName进行匹配规则的配置,那么这个Filter执行的优先级要更低
Listenler 1 监听器分类 监听器分类
2 ServletContextListener 作用
ServletContextListener是监听ServletContext对象的创建和销毁的,因为ServletContext对象是在服务器启动的时候创建、在服务器关闭的时候销毁,所以ServletContextListener也可以监听服务器的启动和关闭
使用场景
将来学习SpringMVC的时候,会用到一个ContextLoaderListener,这个监听器就实现了ServletContextListener接口,表示对ServletContext对象本身的生命周期进行监控。
案例代码
创建监听器类
package com.atguigu.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * 包名:com.atguigu.listener * * @author Leevi * 日期2021-06-1910:26 * 编写监听器的步骤: * 1. 写一个类实现对应的:Listener的接口(我们这里使用的是ServletContextListener),并且实现它里面的方法 *1.1 contextInitialized()这个方法在ServletContext对象被创建出来的时候执行,也就是说在服务器启动的时候执行 *1.2 contextDestroyed()这个方法会在ServletContext对象被销毁的时候执行,也就是说在服务器关闭的时候执行 * * 2. 在web.xml中注册(配置)监听器 */ public class ContextLoaderListener implements ServletContextListener {@Override public void contextInitialized(ServletContextEvent sce) { System.out.println("在服务器启动的时候,模拟创建SpringMVC的核心容器..."); }@Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("在服务器启动的时候,模拟销毁SpringMVC的核心容器..."); } }

注册监听器
com.atguigu.listener.ContextLoaderListener

over

    推荐阅读