7. JavaWeb

TomCat

1. 程序架构

1.1 C/S

  • (client/server) 比如:QQ、 微信、 LOL

  • 优点:有一部分代码写在客户端, 用户体验比较好

  • 缺点: 服务器更新,客户端也要随着更新。 占用资源大。

1.2 B/S

  • (browser/server) 比如:网页游戏 、 WebQQ、天猫、京东等

  • 优点: 客户端只要有浏览器就可以了。占用资源小,不用更新。

  • 缺点:用户体验不佳。

2. Web服务器

2.1 简介

在浏览器上输入地址 ,web服务器软件接收请求,然后响应消息。 处理客户端的请求, 返回资源(信息)

  • Web应用 需要服务器支撑

  • Tomcat apache

  • WebLogic BEA

  • Websphere IBM

  • IIS 微软

2.2 web资源

  • web资源按实现的技术和呈现的效果的不同分为 静态资源和动态资源两种
    • 静态资源:html,css,js,txt,mp4,jpg
    • 动态资源:jsp界面,servlet程序

3. Tomcat

3.1 安装

官网下载,这里推荐安装Tomcat8,因为比较稳定。

启动步骤

  1. 安装, 直接解压 ,然后找到bin/startup.bat, 前提必须配置JAVA_HOME

  2. 启动startup.bat,能看到黑窗口表明成功安装,在浏览器的地址栏上输入: http://localhost:8080 , 有内容表明安装成功

PS: 如果双击了startup.bat, 看到一闪而过的情形,一般都是 JDK的环境变量没有配置。

3.2 目录介绍

bin   	可执行程序
conf 		配置文件
lib 		服务器的 jar 包
logs 		日记信息
temp 		临时数据
webapps  专门用来存放部署的 Web 工程。
work 		作时的目录, 用来存放 jsp 翻译为 Servlet的源码和 Session 钝化的目录。

4. 项目发布

PS:这里只推荐拷贝到webapps文件夹下

项目发布步骤

  1. 在webapps下面新建一个文件夹 Test_Operator , 然后拷贝文件放置到这个文件夹中
  2. 使用IP地址访问:http://localhost:8080/Test_Operator/index.html
  3. 看到画面即可成功发布。

5. idea整合

整合步骤:

  1. 创建web项目
  2. 增加web framework支持
  3. 发布项目到tomcat 方式二:step4
  4. 以war方式发布项目

    在这里插入图片描述
    在这里插入图片描述

方式二 :以war方式发布,在上面的基础上进行:

在这里插入图片描述
在这里插入图片描述

最后:把war文件拷贝到tomcat的webapps目录下,tomcat启动会自动解压这个war文件,我们可以直接访问。

HTTP

1. 简介

HTTP协议即 超文本传输协议 (HTTP-Hypertext transfer protocol)

它定义了浏览器 怎样向万维网服务器发送请求,以及服务器怎样把文档传送给浏览器。

HTTP是面向 应用层协议,它是万维网上能够可靠地交换文件的重要基础。 并规定了浏览器与服务器互相通信的规则

  • 客户端发送给服务器的”信”,我们称之为”请求协议”。
  • 服务器端发送给浏览器的”信”,我们称之为”响应协议”。

可以使用Fiddler文件进行抓包。

总之:HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。

2. 主要特点

  • 简单快速
  • 灵活
  • 无连接
  • 支持B/S和C/S模式

3. URL

3.1 组成

http://httpbin.org:8080/ROOT/index.jsp?username=mickey&password=123456

  • 协议 http://网页使用HTTP协议,
  • 域名 httpbin.org
  • 端口 8080不是必须的部分,可以省略,默认端口为:80
  • 虚拟目录 ROOT从第一个“/”开始 到“/”为止,
  • 文件名 index.jsp从 “/”开始 到“?”
  • 参数 username=mickey&password=123456剩下的为参数部分。

3.2 URI和URL区别

URI是(uniform resource identifier),统一资源标识符,用来唯一的标识一个资源。是以一种抽象的高层次概念定义统一资源标识

URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,还指明了如何定位这个资源

URNuniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com

4. 请求和响应

4.1 Request

  • 通过下面的代码向 服务器端(httpbin.org) 发送请求:
<form action="http://httpbin.org/get" method="get">
    <input type="text" name="username" value="Wzx"><br>
    <input type="text" name="password" value="123456"><br>
    <input type="submit" value="提交">
</form>

<form action="http://httpbin.org/post" method="post">
    <input type="text" name="username" value="Wzx"><br>
    <input type="text" name="password" value="123456"><br>
    <input type="submit" value="提交">
</form>
  • 使用Fidller抓包结果:

在这里插入图片描述

4.2 Response

在这里插入图片描述

4.3 区别

  • GET提交的数据会放在URL之后,POST方法是把提交的数据放在HTTP包的Body(请求体)中.

  • GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.

  • GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。

  • GET方式提交数据,会带来安全问题,如登录一个系统时用户名和密码将出现在URL上,信息可能会被窃取。

5. 状态码

1xx:指示信息-->表示请求已接收,但未响应
2xx:成功-->表示请求已被成功接收、理解、接受。
3xx:重定向-->要完成请求必须进行更进一步的操作
4xx:客户端错误-->请求有语法错误或请求无法实现
5xx:服务器端错误-->服务器未能实现合法的请求

常见的状态码
200 OK 	//客户端请求成功
400 Bad Request 	//客户端有语法错误
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器超时,一段时间后可能恢复正常

6. 请求方式

  • get 请求指定的页面信息,并返回实体主体。
  • head 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
  • POST 数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
  • PUT 从客户端向服务器传送的数据取代指定的文档的内容。
  • DELETE 请求服务器删除指定的页面。
  • CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。\
  • OPTIONS 允许客户端查看服务器的性能。
  • trace 回显服务器收到的请求,主要用于测试或诊断。

7. 工作原理

  1. 客户端连接到Web服务器

一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。

  1. 发送HTTP请求

客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。

  1. 服务器接受请求并返回HTTP响应

服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。

  1. 释放连接TCP连接

若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若

connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;

  1. 客户端浏览器解析HTML内容

浏览器先解析响应行,查看请求的状态码。

然后解析响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。

浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。

总结举例:在浏览器地址栏键入URL,按下回车之后会经历以下流程

1. 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;

2. 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;

3. 浏览器发出读取文件(URL中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;

4. 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;

5. 释放 TCP连接;

6. 浏览器将该 html 文本并显示内容;

Servlet

1. Servlet

1.1 概念

  1. servlet是javaEE规范之一,规范就是接口
  2. Servlet就是javaweb三大组件之一,三大组件分别为:Servlet程序,Filter过滤器,listener监听器
  3. Servlet服务于HTTP协议的服务端的一个小程序,”接受请求,解析请求,根据请求业务做出响应“
  4. Servlet的作用可以总结为如下图:

在这里插入图片描述

1.2 入门案例

基于注解的配置

  1. 导入依赖

在这里插入图片描述

  1. 在src下创建HttpServlet
@WebServlet("/hello")//访问方式为:http://localhost:8080/servlet/hello
public class HelloServlet extends HttpServlet {
   
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) //使用post的响应方式
throws ServletException, IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
      String line = null;				获取request请求的流 即请求体的参数
		while ((line = in.readLine()) != null) {
		System.out.println(line);//循环并打印在控制台
	}
	in.close();//关闭输入
}
   
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponseresponse) //使用Get的响应方式
throws ServletException, IOException {
		System.out.println("queryString = " + request.getQueryString());//获取请求URL的参数部分
		response.getWriter().print(request.getQueryString());//将获取的参数作为响应再写回去
	}
}

基于XML的配置

  1. web.xml配置如下:
<servlet>
   <servlet-name>hello</servlet-name> -->名字随意,但必须是唯一
   <servlet-class>com.wzx.demo.ServletTest2</servlet-class> --> src下java文件的相对路径
</servlet>
<servlet-mapping>
   <servlet-name>hello</servlet-name>  -->与上面的<servlet-name>的值一致
   <url-pattern>/hello</url-pattern> -->‘/hello’必须唯一且不能省略‘/’该值为资源的URL路径
</servlet-mapping>
  1. 上面的代码HttpServlet.java文件的注解 == 该XML配置

1.3 Servlet生命周期

  1. 执行servlet的构造函数
  2. 执行init初始化方法
  3. 执行service方法,每次访问都会执行
  4. 执行destroy方法,当工程停止时调用

注意:1,2 是再第一次访问Servlet时才调用。

1.4 解决乱码

  • 出现乱码的原因:idea使用的是UTF-8,浏览器使用的并非是UTF-8.会导致在浏览器输入中文,idea控制台出现乱码的情况。

  • 解决方案:再idea右上角configurations 再VM options处输入-Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8即可。

1.5 Servlet继承图

在这里插入图片描述

1.6 配置详情

  • 从Servlet3.0开始,使用Servlet有两种方式
    • Servlet类上使用@WebServlet()注解
    • web.xml文件中配置
  • 常用的属性
1. initParams  配置初始化参数、
2. loadOnStartup  是否再启动是加载及加载顺序。
3. servlet-name  指定servlet的名字
4. urlPatterns 指定servlet的执行路径
5. value  	等价于urlPatterns
	@WebServlet(value="/hello",loadOnStartup=1)
6. /* 和 / 常用的拦截,拦截所有。
	*.jpg  拦截指定的后缀
eg:
<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>*.jpg</url-pattern>  //将*.jpg形式的资源拦截,执行default的servlet程序
</servlet-mapping>

2. ServletConfig

2.1 简介

Servlet是程序配置的信息类。

ServletConfig的作用

  • 获取 Servlet 程序的别名 servlet-name 的值
  • 获取初始化参数 init-param
  • 获取 ServletContext 对象

2.2 web.xml配置

1. web.xml展示:
<!--  ServletTest1 -->
<servlet>
   <servlet-name>hello</servlet-name>
   <servlet-class>com.wzx.demo.ServletTest2</servlet-class>

   <init-param>
      <param-name>helloConfig1</param-name> 初始化参数名1
      <param-value>hello servletconfigvalue1</param-value> 该参数的值1
   </init-param>
   <init-param>
      <param-name>helloConfig2</param-name>  初始化参数名2
      <param-value>hello servletconfig value2</param-value>该参数的值2
   </init-param>

   <load-on-startup>1</load-on-startup>   启动时是否加载,数字表示执行顺序
</servlet>
<servlet-mapping>
   <servlet-name>hello</servlet-name>
   <url-pattern>/hello</url-pattern>
</servlet-mapping>


<!--  ServletTest2 -->
<servlet>
   <servlet-name>world</servlet-name>
   <servlet-class>com.wzx.demo.ServletTest</servlet-class>
   <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>world</servlet-name>
   <url-pattern>/world</url-pattern>
</servlet-mapping>

2.3 servlet程序配置

2. hello.java
public class ServletTest2 extends HttpServlet {
    public ServletTest2() {
        System.out.println("hello构造函数");}		//先执行构造函数

    @Override
    public void init(ServletConfig config) throws ServletException {//init方法
        super.init(config); 得到配置的int-parameter参数; 必须要写
        //init中使用servletconfig必须要使用super()
       
        System.out.println(config.getInitParameter("helloConfig1"));//在init中获取初始化参数1的值
        System.out.println(config.getInitParameter("helloConfig2"));//在init中获取初始化参数2的值
        System.out.println("Hello Servlet 初始化");
    }

    @Override
    public void destroy() {//destroy方法
        System.out.println("hello销毁方法");
    }

    @Override//doPost
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            System.out.println("hello " + line);
        }
        in.close();
       
        //得到配置的init-parameter参数
        System.out.println(this.getInitParameter("helloConfig1"));//在post中得到init参数1
        System.out.println(this.getInitParameter("helloConfig2"));//在post中得到init参数2
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
        System.out.println("hello " + request.getQueryString());
        response.getWriter().println(request.getQueryString());
    }
}   
3. world.java 于hello.java代码基本相同

public class ServletTest extends HttpServlet {

   public ServletTest() {
      System.out.println("world构造函数");
   }
   @Override
   public void init() throws ServletException {
      System.out.println("world初始化");
   }
   @Override
   public void destroy() {
      System.out.println("world销毁方法");
   }

   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
      BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
      String line;
      while ((line = in.readLine()) != null) {
         System.out.println("world "+ line);
      }
      in.close();
      
      //得到配置的init-parameter参数
      System.out.println(this.getInitParameter("helloConfig1"));//null,出现null原因:在web.xml中未设置初始化参数
      System.out.println(this.getInitParameter("helloConfig2"));//null,同理
   }

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
      System.out.println( "world"+ request.getQueryString());
      //将请求内容写回去
      response.getWriter().println(request.getQueryString());
   }
}   

3. ServletContext

3.1 简介

ServletContext:Servlet上下文,servlet容器。

  • 当WEB服务器启动时,会为每一个WEB应用程序(webapps下的每个目录就是一个应用程序)创建一块共享的存储区域
  • ServletContext也叫做“公共区域”,也就是同一个WEB应用程序中,所有的Servlet和JSP都可以共享同一个区域。
  • ServletContext在WEB服务器启动时创建,服务器关闭时销毁。
  • ServletContext 对象是一个域对象。

3.2 作用域

域对象:可以像 Map 一样存取数据的对象, 叫域对象。这里的域指的是存取数据的操作范围

javaweb中有4个域对象分别如下

  • pageContext
  • request
  • session
  • application(ServletContext)

ServletContext 类的四个作用

  • 获取 web.xml 中配置的参数 context-param
  • 获取当前的工程路径, 格式: /工程路径
  • 获取工程部署后在服务器硬盘上的绝对路径
  • 像 Map 一样存取数据

3.3 web.xml配置

<context-param>
   <param-name>contextParam1</param-name>//全局参数1
   <param-value>servlet context parameter value1</param-value>
</context-param>
<context-param>
   <param-name>contextParam2</param-name>//全局参数2
   <param-value>servlet context parameter value2</param-value>
</context-param>

3.4 servlet.程序配置

1. hello.java
   
public class ServletTest2 extends HttpServlet {
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
       //作为全局作用域,必须先执行setAttribute方法才能执行getAttribute方法
        getServletContext().setAttribute("globalKey", "hello servlet global");

        //获取 全局 初始化参数//hello.java中可以获取,在该项目下的其它servlet程序均可获取
        System.out.println(getServletConfig().getServletContext().getInitParameter("contextParam1"));
        System.out.println(getServletConfig().getServletContext().getInitParameter("contextParam2"));
    }//通过getServletConfig()方法获取

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {

        System.out.println(getServletContext().getAttribute("globalKey"));//全局,一个web均可访问

        //得到项目的绝对路径
        System.out.println(this.getServletContext().getRealPath("/"));
    }
}   
2. world.java
 
public class ServletTest extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException { }//doPost方法

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {

		//全局之作用域,所以另一个servlet程序也可以访问
        System.out.println("world " + getServletContext().getAttribute("globalKey"));
    }
}
   

4. HttpServletRequest

4.1 简介

每次只要有请求进入 Tomcat 服务器, Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到Request 对象中。然后传递到 service 方法( doGet 和 doPost) 中给我们使用。 我们可以通过HttpServletRequest 对象获取到所有的请求

4.2 常用方法

1. getRequestURI() 获取请求的资源路径		
   getRequestURL() 获取请求的统一资源定位符(绝对路径)
   getHeader() 获取请求头		
   getMethod() 获取请求的方式 GETPOST
   
2. getParameter() 获取请求的参数
	getParameterValues() 获取请求的参数(多个值的时候使用)

3. setAttribute(key, value); 设置域数据
	getAttribute(key); 获取域数据
   
4. getRequestDispatcher() 获取请求转发对象

5. 案例展示:
@WebServlet("/request")
public class requestDemo extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");//设置request解码的字符集

        System.out.println("-----请求行------");
        System.out.println("getRequestURI = " + request.getRequestURI());
        //getRequestURI() 获取请求的资源路径       getRequestURL() 获取请求的统一资源定位符(绝对路径)
        System.out.println("getRequestURL = " + request.getRequestURL());
       
        //获取请求方法
        System.out.println("Method=" + request.getMethod());//Post or Get

        System.out.println("协议=" + request.getProtocol());//获取请求协议及其版本
       
        System.out.println("------请求头------");//主要是各个属性:线面演示获取全部属性
        Enumeration<String> header = request.getHeaderNames();//获取请求头的属性名 来获取所有的属性。
        while (header.hasMoreElements()) {
            String head = header.nextElement();
            System.out.println(head + " : " + request.getHeader(head));//request.getHeader(head)属性值
        }

        System.out.println("------请求体------");//PS:使用API参数情况下不使用数据流。否则出错
       
        System.out.println(request.getParameter("userName"));//得到一个参数:
        System.out.println(Arrays.toString(request.getParameterValues("id"))); //同时得到同名的参数放在数组中

        				//得到并打印所有的参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            System.out.println(entry.getKey() + " : " + Arrays.toString(entry.getValue()));
        }

        //获取请求体的参数名。
        Enumeration<String> params = request.getParameterNames();
        while (params.hasMoreElements()) {
            String param = params.nextElement();
            System.out.println(param);
        }
    }
}  

4.3 request作用域

  • request作用范围:在一次请求中可以访问的作用,当前的servlet和当前servlet转发的servlet可以访问
request.setAttribute("requestKey3", "hello servlet3 attribute value1");//在request作用域中设置属性

request.getAttribute("requestKey3") //request作用域取

5. HttpServletResponse

5.1 简介

HttpServletResponse 类在每次请求进来, Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。

  • HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,

我们如果需要设置返回给客户端的信息, 都可以通过HttpServletResponse 对象来进行设置

两个输出流的说明

  • 字节流 getOutputStream(); 常用于下载(传递二进制数据)

  • 字符流 getWriter(); 常用于回传字符串(常用)

两个流同时只能使用一个。使用了字节流, 就不能再使用字符流, 反之亦然, 否则就会报错。

5.2 常用方法

setContentType() 设置客户端的解码方式
setStatus()  设置状态码
addHeader() 添加响应头属性
getWriter().pring() 写回   
   
@WebServlet("/response")
public class ResponseDemo extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
       //设置响应字符集的解码方式.PS:做出响应时一定要放在第一位
        response.setContentType("text/html;charset=UTF-8"); //设置客户端浏览器的解码方式

        System.out.println("--------响应行-------");
        response.setStatus(HttpServletResponse.SC_OK);//设置指定的响应码

        System.out.println("----------响应头---------");
        response.addHeader("user-name", "mickey");//添加响应头属性

        System.out.println("----------响应体---------");
        response.getWriter().print("中文响应体");//写回指定内容到客户端
    }
}   

6. 转发和重定向

6.1 区别

  • 请求转发:服务器收到请求后, 从一个资源跳转到另一个资源的操作

  • 请求重定向:服务器收到请求后 告诉客户端: 我给你地址。 你去新地址访问。 (因为之前的地址可能已经被废弃)

在这里插入图片描述

6.2 转发演示

1. 演示请求转发-->

   servlet程序1   
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) 
throws ServletException, IOException {//该方法所有请求方式都可以访问。
        
        request.setAttribute("requestKey1", "request.setAttribute servelet1(value)");//request作用域
       
        //在控制台打印请求体的参数。
        request.getParameterMap().forEach((k, v) -> {
            System.out.println("servlet1.name = " + k + " and value= " + Arrays.toString(v));
        });
       
        //转发发生在服务器内部,所以不用加context-path:/servlet。即:相对虚拟主机:从URL上相对。
        request.getRequestDispatcher("/servlet2").forward(request, response);//发生转发
    }
}   

	servlet程序2
@WebServlet("/servlet2")
public class servlet2 extends HttpServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) 
throws ServletException, IOException {
       
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter writer = response.getWriter();//向客户端响应
        System.out.println(request.getAttribute("requestKey1"));//取出并打印request作用域中的属性
        writer.print(request.getAttribute("requestKey1"));
        writer.print("<hr>");

        //向浏览器响应内容:参数列表
        request.getParameterMap().forEach((k,v)->{//数据流
            writer.print("servelt2.name = " + k + " and value= " + Arrays.toString(v));
        });
    }
}      

运行结果:

在这里插入图片描述

6.3 重定向演示

2. 演示请求重定向 -->
   
   servlet程序3
@WebServlet("/servlet3")
public class servlet3 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
       
        request.setAttribute("servlet3", "request.areat.servlet3");
       
//重定向方式一:response.sendRedirect("/servlet/servlet4");
      
       //重定向方式二:
        response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);//设置状态码302
        response.setHeader("location", "/servlet/servlet4");

//跳转到错误界面:response.sendError(HttpServletResponse.SC_NOT_FOUND, "资源未找到");

    }
}   

	servlet程序4
@WebServlet("/servlet4")
public class servlet4 extends HttpServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) 
throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.getAttribute("servlet3");

        PrintWriter out = response.getWriter();
        out.print(request.getAttribute("servlet3")); //回应浏览器的请求-->响应
        out.print("<hr>");

        request.getParameterMap().forEach((k, v) -> {
            out.print("servelt4.name = " + k + " and value= " + Arrays.toString(v)); //响应协议
            out.print("<hr>"); //响应协议
            out.print("123");
        });
    }
}      

运行结果:

在这里插入图片描述

Jsp

1. 简介

JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计

它是在传统的网页HTML文件中插入Java程序段,从而形成JSP文件。 用JSP开发的Web应用是跨平台的,能在Linux和其它系统下运行

  • *.html 静态页面(包含固定的页面内容)

  • *.jsp 动态页面(页面数据可以动态更新,支持嵌套java代码和html代码)

  • 与servlet同理,也需要导入依赖
    在这里插入图片描述

2. 语法格式

  1. 在jsp中使用java代码 ---->使用小脚本<% java代码 %>
  2. 各种标签
  3. .jsp文件会自动产生session
1. 声明标签   <%!变量或者方法声明%> 
2. 表达式标签  <%= 表达式%> 在页面上显示的效果
3. 程序代码标签  <%java代码%> 页面上动态展示内容
   
<%-- 变量或方法的声明,后面的表达式或小脚本可以使用 --%>
	<%! LocalTime localTime = LocalTime.now();%>
	<%--使用上面声明的变量--%>
	<%=localTime%>   
   
<%-- 表达式标签,等价于:<% out.print(LocalDate.now()) %> --%>
	<%= LocalDate.now() %>   

<%--小脚本--%>
	<%LocalDateTime ldt = LocalDateTime.now();
   out.print(ldt);%>
  1. jsp中的注释
<!-- html注释内容,查看源码时能看到 -->
<%-- jsp注释,查看页面源码时看不到 --%>
  1. 执行情况
第一次执行:
	翻译index.jsp翻译成/work/..../index_jsp.java
	编译index_jsp.java编译成class文件index_jsp.class
	执行service
第二次执行:
	执行service

PS:小脚本翻译成service中一段代码,使用out打印变量到页面。
	脚本表达式默认使用out输出一个变量,
	脚本声明,声明一个实例方法,或者实例变量

文件过程(了解):当浏览器访问http://localhost:8080/jsp/index.jsp时,服务器发现后缀为.jsp,它会根据路径找到index.jsp文件,
	会将index.jsp翻译成index_jsp.java文件,对这个java文件进行编译,产生一个index_jsp.class文件,将class文件加载运行。
	将JSP翻译成java文件,它是将JSP中的所有的HTML代码通过流进行输出,也就是说最终翻译成class,被虚拟机加载,它本质是servlet,
	它就会往回响应,响应回去就是把JSP中的HTML代码以流的方式写回浏览器。所以在JSP中展示出了HTML代码

3 .内置对象

3.1 重要的对象

request、response、session、application、out、pagecontext、config、page、exception

request

request 对象是 javax.servlet.httpServletRequest类型的对象。该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。

response

response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。所属类型:HttpServletResponse

pageContext

pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象。

application

application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量” ServletContext

3.2 作用域

pageContext -> request -> session -> application

​ 当前页面 单次请求有效 当前会话期间 服务器运行期间有效

代码演示:a.jsp设置参数;b,c获取参数,查看获取情况
1. a.jsp
<body>
<h5>a.jsp</h5>
<%--对象域--%>
<%
    application.setAttribute("key1", "value1");
    session.setAttribute("key2", "value2");
    request.setAttribute("key3", "value3");
    pageContext.setAttribute("key4", "value4");
    request.getRequestDispatcher("/b.jsp").forward(request, response);//转发请求
%>
</body>
------------------------
2. b.jsp
<body>
<h5>b.jsp</h5>
<%--对象域--%>
<%
    out.print(application.getAttribute("key1") + "<br>");//servletContext
    out.print(session.getAttribute("key2") + "<br>");//同一个浏览器的会话,关闭浏览器后打开 或 打开另一个浏览器失效
    out.print(request.getAttribute("key3") + "<br>");//HttpServletRequest 作用于一次请求或转发
    out.print(pageContext.getAttribute("key4") + "<br>");//只能在该页面有效
%>
</body>
------------------------
3. c.jsp
<body>
<h5>c.jsp</h5>
<%--作为直接访问--%>
<%
    out.print(application.getAttribute("key1") + "<br>");//true
    out.print(session.getAttribute("key2") + "<br>");//true  同一个浏览器生效
    out.print(request.getAttribute("key3") + "<br>");//false  request不同
    out.print(pageContext.getAttribute("key4") + "<br>");//false  不是同一个page
%>
</body>   

4. EL表达式(重点)

1. <%--设置作用域参数--%>
	<%
    pageContext.setAttribute("key", "page scope value");
    request.setAttribute("key", "request scope value");
    session.setAttribute("key", "session scope value");
    application.setAttribute("key", "application scope value");
    pageContext.setAttribute("num", 100);
	%>

2. <%--El表达式可以取出作用域中的数据--%>
	<%--下面的表达式 == out.print(application.getAttribute(“key1”))--%>
	${applicationScope.key}
	${requestScope.key}<br>
	${sessionScope.key}<%--取出session范围的属性--%>

3. ${key}  <%--直接写参数:从作用范围从小到大遍历,所以结果为:page scope value--%>

4. <h5>EL表达式运算符</h5>
	${key == "page scope value"}//可以进行加减乘除 判断
	${num + 1}


6. <h5>el访问对象的属性</h5>
	<%
    User user = new User();
    user.setUsername("mickey");
    user.setPassword("123456");
    user.setAge(18);
    request.setAttribute("user", user);//前提:必须将属性放在作用域中才能访问

    List<User> list = new ArrayList<>();
    list.add(new User("abc", "123", 22));
    list.add(new User("efg", "456", 25));
    list.add(new User("789", "888", 24));
    request.setAttribute("list1", list);
	%>
	${user.username}
	${user.password}
	${user.age}
	${list1[2].username}

7. <h5>EL访问参数:URL中的参数</h5>
	${param.name}  <%--URL地址中的参数,如果为null,不显示--%>
            <%--等价于--%>
	<%=request.getParameter("name")%>

8. <h5>EL获取虚拟主机</h5>
	${pageContext.request.contextPath}
	<%--获取当前web页面的context-path:/jsp--%>

9. <%--导入已有的jsp文件--%>
	<%@ include file="index.jsp"%>

10. 在jsp文件中的路径只推荐使用 基于虚拟主机的URL路径。而目录路径不推荐      

5. JSTL

5.1 简介

JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。如**迭代,条件判断,**XML文档操作,SQL标签。

根据JSTL标签所提供的功能,可以将其分为5个类别。

  • 核心标签
  • 格式化标签
  • sql标签
  • xml标签
  • jstl函数

5.2 语法格式

  • 作用:简化jsp页面编写代码

使用方式:

  1. 下载 jakarta-taglibs-standard-1.1.2.zip 包并解压,将jstl-1.2.jar文件放在WEB-INF/lib下
  2. 在JSP页面中引入<%@ taglib prefix=”页面使用的名称” uri=”功能范围的路径”%>
功能范围uri前缀
corehttp://java.sun.com/jsp/jstl/corec
il8nhttp://java.sun.com/jsp/jstl/fmtfmt
sqlhttp://java.sun.com/jsp/jstl/sqlsql
xmlhttp://java.sun.com/jsp/jstl/xmlx
functionshttp://java.sun.com/jsp/jstl/functionfn

5.3 核心标签

使用核心标签的语法为<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

核心标签的分类

  • 表达式操作out、set、remove、catch
  • 流程控制 if choose when otherwise
  • 迭代操作 forEach forTokens
  • URL操作 import param url redirect
案例演示
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>   
1. <h5>forEach标签的使用</h5>  循环控制    item:被迭代的集合对象  varStatus:存放相关成员信息  step:每次迭代的间隔数
<c:forEach begin="1" end="10" var="i">
    ${i}
</c:forEach>
<hr>
<c:forEach items="${userList}" var="u" varStatus="s">
    ${s.count} --- ${s.index} :: ${u.username} --- ${u.password} ---${u.age}<br>
</c:forEach>

<%
    User user = new User("tomcat", "1234", 22);
    request.setAttribute("userKey", user);
%></
>
2. <h5>if标签</h5>   test:表达式的结果为true,则执行体内容,false则相反   var:结果(true或false)  
<c:if test="${!userKey.username.equals(\"1234\")}" var="b1" scope="request">
    user password=1234
</c:if>
${b1}

3. <h5>choose标签</h5>   作用相当于if-else
<c:choose>
    <c:when test="${2 == 2}">
        确实:2== 2
    </c:when>
    <c:otherwise>
        确实不等于
    </c:otherwise>
</c:choose>

4. <h5>out标签</h5>  输出(不重要)
<c:out value="${userKey.age}"></c:out><br>
${userKey.age}

5. <h5>set标签</h5>  value:要被存储的值  var:存入的变量名称  Scope:var变量的JSP范围
<c:set var="name1" value="${requestScope.userKey.username.substring(3,6)}" scope="request"></c:set>
${name1}
<%--等价于:request.setAttribute("name1",${requestScope.userKey.username.substring(3,6)})--%>

6. <h5> redirect重定向</h5>
<%--  <c:redirect url="/index.jsp"></c:redirect>--%>
</body>
</html>

5.4 格式化标签

  • fmt:formatDate作用:将日期类型格式化为指定模式的字符串
    • value:将要被格式化的数据
    • pattern:格式化的模式,与SimpleDateFormat的参数设置一样
    • var:格式化后的字符串所要存放的变量,若不指定var,则会将格式化的结果直接显示在页面
    • scope:变量存放的域属性空间,默认page
  • fmt:formatNumbe 按照指定格式对数字进行格式化
    • var:存储格式化结果的变量
    • scope:var属性的作用域
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%
    Date date = new Date();
    request.setAttribute("date", date);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS");
    out.print(sdf.format(date));
%>
1. <h5>formatDate</h5>
<%--等价于>--%>
<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH-mm-ss.SSS" var="fdate" scope="request">
</fmt:formatDate>
${fdate}

2. <h5>formatNumber</h5>
<%
    double money = 123456.789;
    request.setAttribute("balance", money);
    DecimalFormat df = new DecimalFormat("#,###.##");
    out.print(df.format(money));
%>
<%--等价于:下面的表达式--%>
<fmt:formatNumber value="${balance}" pattern="#,###.##" var="fbalance" scope="request"></fmt:formatNumber>
${fbalance}
</body>
</html>

Cookie

1. 简介

  1. Cookie 翻译过来是饼干的意思。

  2. Cookie 是服务器通知客户端保存键值对的一种技术。

  3. 客户端有了 Cookie 后, 每次请求都发送给服务器

  4. 每个 Cookie 的大小不能超过 4kb

2. 创建Cookie

  1. 服务器(Tomcat)创建Cookie对象 Cookie cookie = new Cookie("key","value");
  2. 服务器通知客户端(浏览器)保存Cookies response.addCookie(cookie);
  3. 传输时通过响应头Set-Cookie通知客户端保存Cookie Set-Cookie : key = value
  4. 客户端收到响应后发现有Set-Cookie响应头,就去看有没有这个Cookie,没有就去创建有就修改
@WebServlet("/cookie")
public class CookieServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws 
ServletException, IOException {
		response.setContentType("text/html; charset=UTF-8");//设置浏览器字符集
		Cookie c1 = new Cookie("key1", "value1");//创建Cookie对象
		Cookie c2 = new Cookie("key2", "value2");
		response.addCookie(c1);//通知浏览器
		response.addCookie(c2);
		response.getWriter().print("Cookie添加成功");
	}
}   
  • 浏览器存储的Cookie
    在这里插入图片描述

3 . 服务器获取Cookie

  • 服务器将Cookie对象传给浏览器后,浏览器会将Cookie随着请求一起发送给服务器,Cookie则在请求头中。

  • 服务器通过request.getCookies()方法获取Cookies,但这是一个数组。需要我们自己去筛选我们需要的Cookie

//获取Cookie并打印Cookie在相应上
@WebServlet("/getcookie")
public class GetCookie extends HttpServlet {
   
   //筛选Cookie的工具类
    private Optional<Cookie> getCookie(String name, Cookie[] cookie) {
        return Arrays.stream(cookie).filter(ck -> name.equals(ck.getName())).findFirst();
    }
    /*解析:
         1. 因为request.getCookies()返回所有的Cookie数组,所以需要我们自己去 获取我们想要的
         2. 获取数组流对象-->进行筛选(根据我们想要的Cookie名) -->获取第一个Option<Cookie>
         3.
     */
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
       
       //获取指定的Cookie方法
//        Optional<Cookie> key1 = getCookie("key1", request.getCookies());
//        Optional<Cookie> key2 = getCookie("key2", request.getCookies());
//        System.out.println(key1.get().getName() + " | " + key1.get().getValue());
//        System.out.println(key2.get().getName() + " | " + key2.get().getValue());
//        Cookie key3 = getCookie("key3", request.getCookies()).orElse(new Cookie("key3", "空"));
//        System.out.println(key3.getName() + " | " + key3.getValue());

       //获取所有的Cookie
        PrintWriter out = response.getWriter();
        if (null != request.getCookies()) {
            Arrays.stream(request.getCookies()).forEach(ck -> {
                out.print(ck.getName() + " | " + ck.getValue() + "<br>");
            });
        }
    }
}

4. Cookie值修改

  1. Cookie值的修改 = Cookie对象的创建
  2. Cookie key1 = new Cookie("key1","value0");
  3. response.addCookie(key1);
  4. 此时浏览器中有该值就进行覆盖。

5. Cookie字段

5.1 常用字段

field描述
namekey-value键值对中的 key
valuekey-value键值对中的 value值
expirescookie过期日期,过期后就会在自动删除
pathcookie的访问路径, 访问路径的值一般设为“/” ,表示所有页面都可以访问这个cookie
domaincookie的访问域名, 此属性设置指定域名下的页面才可以访问该cookie。
securecookie的安全属性,只有使用了HTTPS协议才可以被页面访问
httponly只读,所有脚本无法获取Cookie的信息
  • 为什么要设置HttpOnly和Secure?
当设置了HttpOnly属性时, 通过脚本将无法获取到Cookie信息,主要用于防止XSS攻击。 而一旦设置了Secure属性时,
前后端之间只能在HTTPS协议通信情况下浏览器才能访问Cookie,使用HTTP协议时浏览器无法取到Cookie信息,同样是对Cookie信息的保护。

5.2 expires字段

  • 作用:管理 Cookie 什么时候被销毁(删除)

  • 方法:setMaxAge()

    • 大于0 表示在指定的秒数后过期

    • 小于0 表示浏览器一关, Cookie 就会被删除(默认值是-1)

    • 等于0 表示直接删除 Cookie

//Cookie的生命周期
Cookie c3 = new Cookie("key3","value3");
c3.setMaxAge(3600 * 24);//经过24 * 3600s后删除
Cookie c4 = new Cookie("key4", "value4");
c4.setMaxAge(-1);//关闭浏览器后删除
Cookie c5 = new Cookie("key5", "value5");
c5.setMaxAge(0);//直接删除,相当于不存在

response.addCookie(c3);
response.addCookie(c4);
response.addCookie(c5);

5.3 Path字段

  • Cookie的path默认值是request.getContextPath 即:/cookie
//Cookie的Path注意事项:访问/cookie/getcookie
Cookie c6 = new Cookie("key6", "value6");
c6.setPath("/cookie/a.jsp");//在/cookie/getcookie中没有,因为该cookie是在/cookie/a.jsp及其后面的才有

Cookie c7 = new Cookie("key7", "value7");
c7.setPath("/cookie/b.jsp");		//同理
Cookie c8 = new Cookie("key8", "value8");
c8.setPath("/");		//都获取到
Cookie c9 = new Cookie("key9", "value9");
c9.setPath("/timao");	//在/cookie/getcookie中获取不到
  • 匹配规则 -->前缀匹配
path = /;
path = /cookie-demo;
path = /cookie-demo/a.jsp;
以上的cookie访问/cookie-demo/a.jsp,会被随请求一起访问;
/path = /cookie/b.jsp的cookie访问/cookie-demo/a.jsp,不会被随请求一起访问;

5.4 Domain字段

  • Cookie的domain默认值是request.getServletName 即:/localhost 或 /a.file.com 这里使用后者

  • 配置方法

    1. 打开 c:\Windows\System32\drivers\etc\hosts
    2. 添加如下内容:
    127.0.0.1 file.com
    127.0.0.1 a.file.com
    127.0.0.1 b.file.com
    
    127.0.0.1 image.com
    其中file.com 为顶级域
    a.file.com和b.file.com为子域
    
PS: 1. 访问http://a.file.com:8080/cookie/createcookie产生cookie 
	2. 访问http://b.file.com:8080/cookie/getcookie 
   
Cookie c10 = new Cookie("key10", "value10");
c10.setDomain("file.com");		//c10为a.file.com 和b.file.com的顶级域,所以在b.file.com中会显示

Cookie c11 = new Cookie("key11", "value11");
c11.setDomain("a.file.com");//无法显示,不同域之间不共享

Cookie c12 = new Cookie("key12", "value12");
c12.setDomain("b.file.com");	//无法显示,浏览器在创建时自动过滤

Cookie c13 = new Cookie("key13", "value13");
c13.setDomain("image.com");  //无关项与c12相同

response.addCookie(c10);
response.addCookie(c11);
response.addCookie(c12);
response.addCookie(c13);
  • 结论
    • 只有c10这个顶级域能被子域共享
    • cookie中设置当前域和当前域的顶级域,在当前域中都能访问,但在顶级域的另一个子域中只能访问顶级域
    • 顶级域在子域中共享

6. JS访问Cookie

PS: 1.  http://a.file.com:8080/cookie/c.html 
2.  http://b.file.com:8080/cookie/d.html
<body>
c.html
<script>
    console.log(Cookies.get("key10"));//a.file.com 访问,c10是顶级域
    Cookies.set("key21", "value21", {expires: 7, path: "cookie"})
    Cookies.set("key22", "value22", {expires: 7, path: "cookie", domain: ".file.com"})//可以访问
    Cookies.set("key23", "value23", {expires: 7, path: "cookie", domain: ".image.com"})//无关项无法访问
    console.log(Cookies.get())
</script>
</body>
       
       
<body>
d.html
<script>
    console.log(Cookies.get());//只有key10和key22可以访问
</script>
</body>       
  • 结论:JS中访问cookie无法共享,只有共同的顶级域才能共享顶级域的cookie

Session

1. 简介

  1. “Session”(会话)是计算机中的一个概念,用于描述在一段时间内用户与系统之间的交互过程。

  2. 在网络应用程序中,"session"通常指 在打开网页或登录到应用程序 直到关闭网页或注销账户时结束整个时间段。

  3. session的作用:维护用户的状态信息。在一个会话中,用户可以执行多个操作,浏览不同的页面,提交表单数据,与其他用户进行交互等。系统会使用会话ID来区分不同用户的操作,并保持各个操作之间的关联性。

  4. 应用场景:常见的应用场景是购物网站中的购物车功能。当用户将商品添加到购物车时,系统会使用会话来跟踪用户选择的商品和数量,以便在结算时提供准确的信息。

2. 登录案例

2.1 登录界面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/session/login" method="post">   向login发送请求
    用户名:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>

2.2 验证请求

@WebServlet("/login")
public class LoginDemo extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
        String username = request.getParameter("username");//获取参数
        String password = request.getParameter("password");
       //进行表单验证
        if ("Tomcat".equals(username) && "123456".equals(password)) {
            //匹配成功,使用Session来保存登录信息
            HttpSession session = request.getSession(true);//同过JSESSIONID在域中找到session
            session.setAttribute("loginUser", "Tomcat");
            //跳转到打印界面
            response.sendRedirect("/session/getsession");//重定向到getsession
        } else {
            response.sendRedirect("/session/login.html");//密码错误:跳转到登录界面
        }
    }
}

2.3 做出响应

@WebServlet("/getsession")
public class GetSession extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        HttpSession session = request.getSession();//通过JSESSIONID在域中获取session
        response.getWriter().print("登录用户" + session.getAttribute("loginUser").toString());//做出响应
    }
}

3. Cookie-Session原理

3.1 运行原理

  1. 第一次请求,服务器创建session。并将session的id通过cookie的形式(在响应的响应头)中传送给浏览器
  2. 浏览器进行存储这个cookie
  3. 在发送请求时,该cookie 随着请求一同访问服务器
  4. 服务器通过该cookie在域中查找Session,并对该session进行操作

3.2 参数

HttpSession session = request.getSession(boolean b);

  • b == true(默认):如果当前会话有session就使用当前session;没有就产生新的session

  • b == false:有session就得到当前会话中的session,没有session就返回null

4. Session的生命周期

4.1 API方法

public void setMaxInactiveInterval(int interval)设置 Session 的超时时间( 以秒为单位)。过时就会销毁

  • public void invalidate() 让当前 Session 会话马上超时无效。
  • public int getMaxInactiveInterval()获取 Session 的超时时间

4.2 设置方法

  1. Tomcat默认超时时间:在 Tomcat 服务器的配置文件 web.xml中有默认的配置, 它就表示配置了当前 Tomcat 服务器下所有的 Session超时配置默认时长为: 30 分钟。

  2. 项目超时时间:你可以在你自己项目的 web.xml配置文件中配置。 就能修改项目中所有session的超时时间

<!--表示当前 web 工程。 创建出来 的所有 Session 默认是 20 分钟 超时时长-->
<session-config>
<session-timeout>20</session-timeout>
</session-config>
  1. 某个session的超时时间
使用上面的API方法:session.setMaxInactiveInterval(int interval)
   如:session.setMaxInactiveInterval(10); //10s后失效
  1. 立即失效
使用API方法:session.invalidate()//立即失效

Filter

过滤器

1. 简介

  • Filter 过滤器它是 JavaWeb 的三大组件之一。 三大组件分别是: Servlet 程序、 Listener 监听器、 Filter 过滤器

  • 作用: 拦截请求, 过滤响应。

  • 需要拦截的场景:

    • 权限检查
    • 日记操作
    • 事务管理

2. 过滤器链

3. 登录验证

3.1 准备工作

  • 要求:目标下的所有资源(html 页面、 jpg 图片、 jsp 文件、 等等) 都必须是用户登录之后才允许访问。

  • 原理:根据之前我们学过内容。 我们知道, 用户登录之后都会把用户登录的信息保存到 Session 域中。 所以要检查用户是否登录, 可以判断 Session 中否包含有用户登录的信息即可! ! !

// 如果等于 null, 就跳转到登录界面有登录
Object user = session.getAttribute("user");
if (user == null) {
	request.getRequestDispatcher("/login.jsp").forward(request,response);
	return;
}
  • 原理图:

3.2 过滤器

  • 配置文件
1. Filter1配置
<filter>
   <filter-name>filter1</filter-name>
   <filter-class>com.wzx.demo.filter.Filter1</filter-class>
</filter>
<filter-mapping>
   <filter-name>filter1</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

2. AdminFilter配置
<filter>
   <filter-name>admin</filter-name>
   <filter-class>com.wzx.demo.filter.AdminFilter</filter-class>
   <init-param>
      <param-name>passUrls</param-name>
      <param-value>/filter/login;/filter/css;/filter/img</param-value> //放行css、js、img、以及校验界面
   </init-param>
</filter>
<filter-mapping>
   <filter-name>admin</filter-name>
   <url-pattern>/*</url-pattern>  //拦截所有
</filter-mapping>
  1. 过滤器1
public class Filter1 implements Filter { -->过滤敏感词
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {//初始化方法
    }
   
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, //过滤方法
FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
       
       //使用自定义包装模式 -->完成过滤敏感词汇
        CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper(request);
        filterChain.doFilter(requestWrapper, servletResponse);
  /*原理:1. 自定义类作用:在HttpServletRequest的基础上添加业务
       	2. 先继承HttpServletRequestWrapper,并实现CustomHttpServletRequestWrapper()构造函数
       	3. 这里重写getParameter()方法,先使用原本的getParameter()方法获得value值,并对该值进行处理
       	4. if(name.equals("key"))并且key的值等于李佳琦-->则修改value值。最后返回value值。
       	5. 使用时,将reques传进去,进行包装,并将包装对象代替原来的request对象
       	6. 包装模式的作用:在不改变源代码的基础上增加业务。
  */    }                               
    @Override
    public void destroy() {//销毁方法
    }
}
//自定义包装类
class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {//
    public CustomHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (name.equals("key") && "李佳琦".equals(value)) {
            return "XXX";//更改value值
        }
        return value;
    }
}
  1. 过滤器2
public class AdminFilter implements Filter {
    String[] s;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
        s = filterConfig.getInitParameter("passUrls").split(";");//根据“;”分割数据到数组中
  /*解读:1. 上面代码 -- > 读取WEB-INF下的web.xml配置
  			2. filterConfig.getInitParameter()方法获取web.xml参数
       	3. 与servlet读取web.xml配置的方法相同
       	4. 与servlet之间的不同:filter中只能在初始化时读取,其它位置没有this关键字
	*/}
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
FilterChain filterChain) throws IOException, ServletException {

        //将ServletRequest转为HttpservletRequest,Response同理
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession session = request.getSession();

        String path = request.getRequestURI(); //相对路径 /filter/...
        //放行, 登录成功的界面
        for (int i = 0; i < s.length; i++) {//如果相等则可以访问资源。
            if (path.startsWith(s[i])) {
                filterChain.doFilter(request, response);
                return;
            }
        }

        //如果等于null表示还未登录 --> 需要跳转到 登录界面
        if (session.getAttribute("username") == null) {
            request.setAttribute("loginError", "请先登录");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
            return;
        }
       
        //已登录,则可以随意访问
        filterChain.doFilter(request, response);
    }
    @Override
    public void destroy() {
    }
}

3.3 登录界面

  1. 表单登录login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>
<c:set value="${pageContext.request.contextPath}" var="ctx"></c:set>
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" href="${ctx}/css/main.css" >
</head>
<body>
<h5 id="h5">${loginError}</h5>

<form action="${ctx}/login" method="post">    <!--向${ctx}/login = /filter/login发送请求-->
    用户名:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
    <input type="submit" value="提交">
</form>
<img src="${ctx}/img/man00.jpg">
</body>
</html>
  1. 校验登录login
@WebServlet("/login")
public class LoginDemo extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
       
        String username = request.getParameter("username");//获取表单传值的参数“username”
        String password = request.getParameter("password");//获取表单传值的参数“password”
        if ("Tomcat".equals(username) && "123456".equals(password)) {//进行校验
            //匹配成功,使用Session来保存登录信息
            HttpSession session = request.getSession(true);//session对话,
            session.setAttribute("username", "Tomcat");
            session.setAttribute("loginError",session.getAttribute("username"));//修改其值表示 已登陆 
            response.getWriter().print("登陆成功!");
        }
    }
}

3.4 目标资源

servlet顺序:1. 在web.xml配置的资源 > 使用注解配置的资源

程序访问顺序:在浏览器中想要访问servlet1

  1. 访问Filter1:因为filter1在web.xml中配置在前面
  2. 访问AdminFilter: 拦截所有
  3. 访问 login.jsp 第一次访问未登录,需要先登录 --> 跳转到 login 界面 显示登陆成功
  4. 访问目标资源:servlet1,此时就没有限制了。在访问时URL上添加:?key=李佳琦 -->会屏蔽该值.
@WebServlet("/servlet1")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
        response.setContentType("text/html; charset=UTF-8");
        response.getWriter().print( request.getParameter("key") + "execute servlet1");
        System.out.println("execute servlet1");
    }
}

4 Filter生命周期

Filter 的生命周期包含几个方法:与servlet大体相同

  1. 构造器方法

  2. init 初始化方法 :第 1, 2 步, 在 web 工程启动的时候执行(Filter 已经创建)

  3. doFilter 过滤方法,每次拦截到请求, 就会执行

  4. destroy 销毁, 停止 web 工程的时候, 就会执行(停止 web 工程, 也会销毁 Filter 过滤器)

5 FilterConfig

  • FilterConfig 类是 Filter的配置文件类。Tomcat 创建 Filter 时,也会同时创建 FilterConfig 类,该类包含 Filter 配置文件的信息。

  • FilterConfig 类的作用:获取 filter 过滤器的配置内容

    • 获取 Filter 的名称 filter-name 的内容

    • 获取在 Filter 中配置的 init-param 初始化参数

    • 获取 ServletContext 对象

  • 使用方法与servlet相同

  • PS:Filter 过滤器它只关心请求的地址是否匹配, 不关心请求的资源是否存在! ! !

Listener

监听器(了解即可)

1. 监听器简介

  • 监听器(Listener)是一种特殊的组件,用于监听Web应用程序中的事件,并在事件发生时执行相应的操作。

  • 监听器可以用于捕获和响应各种事件,从而实现对应用程序的控制和管理

  • 监听器的相关概念:

    • 事件源:被监听的对象(三个域对象 request、session、servletContext)

    • 监听器:监听事件源对象事件源对象的状态的变化都会触发监听器

    • 注册监听器:将监听器与事件源进行绑定

    • 响应行为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)

2. 分类

第一维度按照被监听的对象划分:ServletRequest域、HttpSession域、ServletContext域

第二维度按照监听的内容分:监听域对象的创建与销毁的、监听域对象的属性变化(了解

  • ServletContextAttributeListener
  • HttpSessionAttributeListener
  • ServletRequestAttributeListener

3. 案例演示

3.1 web.xml

<listener>
	<listener-class>com.wzx.demo.MyListener</listener-class>
</listener>
<listener>
   <listener-class>com.wzx.demo.MyHttpSessionListener</listener-class>
</listener>
PS:推荐使用web.xml,不建议使用注解

3.2 代码演示

1. 演示ServletContextListener  --->当创建web项目和销毁web项目时被检测到并进行打印操作
public class MyListener implements ServletContextListener {
   
	@Override
	public void contextInitialized(ServletContextEvent servletContextEvent){//监测创建web项目
		System.out.println("contextInitialized");
	}

   @Override
	public void contextDestroyed(ServletContextEvent servletContextEvent) {//监测销毁web项目
		System.out.println("contextDestroyed");
	}
}

2. 演示HttpSessionListener ---> 当创建和销毁session时被检测到并进行打印操作  
public class MyHttpSessionListener implements HttpSessionListener {
    // 实现接口方法
    @Override
    public void sessionCreated(HttpSessionEvent event) {
        // 在 HttpSession 对象创建时执行的代码
        HttpSession session = event.getSession();
        // 执行创建逻辑
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        // 在 HttpSession 对象销毁时执行的代码
        HttpSession session = event.getSession();
        // 执行销毁逻辑
    }
   /*如果你还想监听 HttpSession 属性的添加、修改和删除事件,
   可以实现 attributeAdded、attributeRemoved 和 attributeReplaced 方法。
   */
}   

件源:被监听的对象(三个域对象 request、session、servletContext)

  • 监听器:监听事件源对象事件源对象的状态的变化都会触发监听器

  • 注册监听器:将监听器与事件源进行绑定

  • 响应行为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值