学习javaweb时记录的笔记


互联网通信的流程:
背互联网通信的每一个细节。
涉及技术:
1.控制浏览器行为技术:html,css,JavaScript。
2.控制硬盘上数据库行为技术,mysql数据库服务器管理使用(sql重点),jdbc规范。–mybtis框架
3.控制服务器java行为技术:http服务器。servlet–升级springmvc,,jsp输出流
4.互联网通信开发流程开发规则:mvc
5、贯穿的项目–在线考试系统。

互联网的通信
两台计算机通过网络实现文件共享行为,就是互联网通信。

通过角色划分为:
客户端计算机:用于发送请求的叫做客户端
服务端计算机:用于接收请求,并提供服务资源文件的叫做服务端

互联网通信模型
1.c/s通信模型:
c,client software;客户端软件
1)客户端软件专门安装在客户端计算机上
2)帮助客户端计算机向指定服务端计算机发送请求,索要资源文件
3)帮助客户端计算机将服务端计算机发送回来(二进制数据)解析
为(文字,图片,影像)等。
网络传输的数据都以二进制形式存在,软件c去解析二进制。
s:server software;服务器软件。
1)服务器软件专门安装在服务端计算机上
2)服务器用于接收来自特定客户端软件发送请求。
3)服务器软件在接收到请求之后自动的在服务端计算机上定位被访问的资源文件。
4)服务器软件自动的将定位的文件内容解析为(二进制数据)通过网络发送回发起请求的客户端软件上。

使用场景:c/s通信模型普遍用于个人娱乐市场,例如微信,淘宝,视频类。网络游戏。
企业办公应用领域较少。
优缺点:
优点:
1.安全性较高,
2.有效降低服务端计算的压力。服务器压力小。
3.速度快:相对比bs架构,大量的数据存储在客户机上,只需要从服务器传输少量的数据,而bs架构是浏览器啥也没有,所有的数据都需要从服务器上传输。
界面酷炫,用户体验好。
4.安全:因为大量的数据集成在客户端软件当中,并且客户端有很多歌,服务器虽然只有一个,就算服务器受损了,问题也不大,因为大量的数据在多个客户端上有存储。
缺点:
1.增加客户获得服务的成本
2.升级维护,较为繁琐。一旦发生更新所有的客户端软件都需要更新。

B/s通信模型:
b:browse,浏览器
1)浏览器可以安装在客户端计算机软件
2)可以向任意的服务器发送请求,索要资源文件
3)可以将服务器返回的二进制数据解析为文字,图片,数字。
server software 服务器软件
1)服务器软件专门安装在服务端计算机上
2)可以接受任意浏览器发送请求
3)自动的在服务端计算机上定位被访问的资源文件。
4)自动将定位的资源文件内容以二进制形式发送回发起请求的浏览器上
适用于个人娱乐市场,又广泛使用玉企业日常活动。

优点:不会增加用户的成本,不需要安装特定的软件,用户操作及其方便,只需要打开浏览器,输入网址即可。
2.几乎不需要更新浏览器
升级维护方便,成本较低(只需要升级服务端即可)

缺点:1.几乎无法有效对服务端计算机资源进行保护
2.服务端计算机工作压力异常巨大—(B/S通信下高并发解决)。
速度慢:不是因为带宽的问题,因为所有的数据都在服务器上,用户发送的每一个请求都是需要服务器全身心的响应数据,所以B/S结构的系统在网络中的传送数据量比较大。
体验差:界面不那么炫酷,因为浏览器只支持HTML,CSS,JAVASCRIPT

娱乐性软件建议使用c/s架构
公司内部的一些业务软件建议使用b/s架构
公司内部使用的系统,需要维护成本低,
公司内部使用的系统不需要很酷炫
公司内部使用的企业级系统主要是能够进行数据的维护即可。
开发B/S结构的系统,其实就是开发网站,其实就是开发一个web

web前端(运行在浏览器上的程序)
html
css
js
web后端:web服务器端的程序
java (java做web开发称为javaweb开发,javaweb开发最核心的规范:servlet(server applet服务端的java小程序)
c语言
c++
python
php

java包括三大块:
javase
java标准版(一套类库,别人写好的一套类库,只不过类库是标准类库,走ee,或者me,这个se一定是基础,先学)。

javaee
java企业版(也是一套类库:也是别人写好的一套类库,只不过这套类库可以帮助我们完成企业级项目的开发,
专门为企业内部提供解决方案的一套(多套)类库。
别人写好的,用就行,开发企业级项目
可以开发web系统
java比较火爆的方向
javaee实际上包括多种规范,13种规范,其中servlet就是javaee规范之一,学servlet还是java语言。

javame
java微型版(还是一套类库,也是别人写好的一套类库,只不过这套类库帮助我们进行电子微型设备内核程序的开发)。
机顶盒内核程序,吸尘器内核程序,电冰箱内核程序。

B/S结构的系统通信原理
(没有涉及到Java小程序)
2.1域名
https://www.baidu.com/(网站),www.baidu.com 是一个域名
在浏览器地址栏上输入域名,回车之后,域名解析器会将域名解析出来一个具体的IP地址和端口号等。
解析结果也许是:http://110.242.68.3:80/index.html
IP地址: 一台主机的身份证号,在同一个网络中。ip地址是唯一的。
a计算机想访问b计算机,就必须要知道b计算的ip地址
端口号: 一个软件 一个端口代表一个应用。一个端口仅代表一个服务。
一个局算计中有很多阮籍,每一个软件启动之后都有一个端口号。
在同一个计算机上,端口号具有唯一性。
浏览器返回代码数据。浏览器对html,css,js等进行渲染,最终才是展现的数据。

2.2一个WEB系统的通信原理?
第一步:用户输入网址(URL)
域名解析器进行域名解析:110.242.68.3:80/index.html
浏览器软件在网络中搜索并找到110.242.68.3这一台主机
该台主机定位到80端口对应的服务器软件
80端口对应的服务器软件得知浏览器想要的资源名是:index.html
服务器软件找到index.html文件,并且将index.html文件中的内容直接输出响应到浏览器上。
浏览器接收并执行到来自服务器的代码(HTML CSS JS)

web服务器软件有哪些?
tomcat(web服务器)
jetty(web服务器)
JBOSS(应用服务器)
WebLogic(应用服务器)
websphare(应用服务器)
应用服务器实现了javaee的所有规范,13个规范
web服务器只实现了javaee中的servlet和jsp两个核心规范。
说明应用服务器包含web服务器
JBOSS服务器内嵌了一个Tomcat服务器

  • omcat下载

    • apache官网地址:https://www.apache.org/
    • tomcat官网地址:https://tomcat.apache.org
    • tomcat开源免费的轻量级WEB服务器。
    • tomcat还有另外一个名字:catalina(catalina是美国的一个岛屿,风景秀丽,据说作者是在这个风景秀丽的小岛上开发了一个轻量级的WEB服务器,体积小,运行速度快,因此tomcat又被称为catalina)
    • tomcat的logo是一只公猫(寓意表示Tomcat服务器是轻巧的,小巧的,果然,体积小,运行速度快,只实现了Servlet+JSP规范)
    • tomcat是java语言写的。
    • tomcat服务器要想运行,必须先又jre(Java的运行时环境)
  • Tomcat服务器要想运行,需要先有jre,所以要先安装JDK,配置java运行环境。

    • JAVA_HOME=C:\Program Files\Java\jdk-17.0.1
    • PATH=%JAVA_HOME%\bin
    • 目前JAVA_HOME没有配置,思考一个问题,这样行不行呢?目前只运行java程序是没问题的。真的没问题吗?
  • Tomcat服务器的安装:

    • 绿色版本的安装很简单,直接zip包解压即可。解压就是安装。
    • 我有一个好习惯,在C盘的根目录下新建一个dev目录,java开发所有相关的工具都安装到dev目录下,这样比较方便管理。(你随意)
    • 启动Tomcat
      • bin目录下有一个文件:startup.bat,通过它可以启动Tomcat服务器。
        • xxx.bat文件是个什么文件?bat文件是windows操作系统专用的,bat文件是批处理文件,这种文件中可以编写大量的windows的dos命令,然后执行bat文件就相当于批量的执行dos命令。
        • startup.sh,这个文件在windows当中无法执行,在Linux环境当中可以使用。在Linux环境下能够执行的是shell命令,大量的shell命令编写在shell文件当中,然后执行这个shell文件可以批量的执行shell命令。
        • tomcat服务器提供了bat和sh文件,说明了这个tomcat服务器的通用性。
        • 分析startup.bat文件得出,执行这个命令,实际上最后是执行:catalina.bat文件。
        • catalina.bat文件中有这样一行配置:MAINCLASS=org.apache.catalina.startup.Bootstrap (这个类就是main方法所在的类。)
        • tomcat服务器就是Java语言写的,既然是java语言写的,那么启动Tomcat服务器就是执行main方法。
          Bootstrap中main方法
      • 我们尝试打开dos命令窗口,在dos命令窗口中输入startup.bat来启动tomcat服务器。
      • 启动Tomcat服务器只配置path对应的bin目录是不行的。有两个环境变量需要配置:
        • JAVA_HOME=JDK的根
        • CATALINA_HOME=Tomcat服务器的根
          如果不配
          The CATALINA_HOME environment variable is not defined correctly
          This environment variable is needed to run this program
          配置这个是为了我们直接使用dos窗口开启命令时能找到
          jdk的配置也是一样的原理
          开启之后是一个jar程序,关闭窗口程序终止。
  • 关于Tomcat服务器的目录

    • bin : 这个目录是Tomcat服务器的命令文件存放的目录,比如:启动Tomcat,关闭Tomcat等。
    • conf: 这个目录是Tomcat服务器的配置文件存放目录。(server.xml文件中可以配置端口号,默认Tomcat端口是8080)
    • lib :这个目录是Tomcat服务器的核心程序目录,因为Tomcat服务器是Java语言编写的,这里的jar包里面都是class文件。
    • logs: Tomcat服务器的日志目录,Tomcat服务器启动等信息都会在这个目录下生成日志文件。
    • temp:Tomcat服务器的临时目录。存储临时文件。
    • webapps:这个目录当中就是用来存放大量的webapp(web application:web应用)
    • work:这个目录是用来存放JSP文件翻译之后的java文件以及编译之后的class文件。
  • 配置Tomcat服务器需要哪些环境变量?

    • JAVA_HOME=JDK的根
    • CATALINA_HOME=Tomcat服务器的根 C:\Program Files\Apache Software Foundation\Tomcat 9.0\bin
    • PATH=%JAVA_HOME%\bin;%CATALINA_HOME%\bin
  • 启动Tomcat: startup

  • 关闭Tomcat:stop (shutdown.bat文件重命名为stop.bat,为什么?原因是shutdown命令和windows中的关机命令冲突。所以修改一下。)

  • 怎么测试Tomcat服务器有没有启动成功呢?

    • 打开浏览器,在浏览器的地址栏上输入URL即可:

      • http://ip地址:端口号
      • ip地址是什么?端口号我知道,是8080
      • 本机的IP地址是:127.0.0.1,或者是localhost,都行。

      实现一个最基本的web应用(这个web应用中没有java小程序)

  • 第一步:找到CATALINA_HOME\webapps目录

    • 因为所有的webapp要放到webapps目录下。(没有为什么,这是Tomcat服务器的要求。如果不放到这里,Tomcat服务器找不到你的应用。)
  • 第二步:在CATALINA_HOME\webapps目录下新建一个子目录,起名:oa

    • 这个目录名oa就是你这个webapp的名字。
  • 第三步:在oa目录下新建资源文件,例如:index.html

    • 编写index.html文件的内容。
  • 第四步:启动Tomcat服务器

  • 第五步:打开浏览器,在浏览器地址栏上输入这样的URL:

  • http://127.0.0.1:8080/oa/index.html

  • 思考一个问题:

    • 我们在浏览器上直接输入一个URL,然后回车。这个动作和超链接一样吗?既然是一样的,我们完全可以使用超链接。
      但是必须要在浏览器上从ip地址加端口的路径中,如果从本地文件打开,会出错。

      <!--注意以下的路径,以/开始,带项目名,是一个绝对路径。不需要添加:http://127.0.0.1:8080-->
      <a href="/oa/login.html">user login2</a>
      
      <!--多个层级也没有关系,正常访问即可。-->
      <!--注意:我们目前前端上的路径都以“/”开始的,都是加项目名的。-->
      <a href="/oa/test/debug/d.html">d page</a>
      
  • http://127.0.0.1:8080/oa/userList.html

    • 访问这个地址,可以展示一个用户列表页面。但是这个用户列表页面是写死在HTML文件当中的。这种资源我们称为静态资源。怎么能变成动态资源。显然需要连接数据库。
    • 连接数据库需要JDBC程序,也就是说需要编写Java程序连接数据库,数据库中有多少条记录,页面上就显示多少条记录,这种技术被称为动态网页技术。(动态网页技术并不是说页面中有flash动画。动态网页技术是说页面中的数据是动态的,根据数据库中数据的变化而变化。)

对于一个动态的web应用来说,一个请求和响应的过程有多少个角色参与,角色和角色之间有多少个协议

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 有哪些角色(在整个BS结构的系统当中,有哪些人参与进去了)
    • 浏览器软件的开发团队(浏览器软件太多了:谷歌浏览器、火狐浏览器、IE浏览器…)
    • WEB Server的开发团队(WEB Server这个软件也是太多了:Tomcat、Jetty、WebLogic、JBOSS、WebSphere…)
    • DB Server的开发团队(DB Server这个软件也是太多了:Oracle、MySQL…)
    • webapp的开发团队(WEB应用是我们做为JavaWEB程序员开发的)
  • 角色和角色之间需要遵守哪些规范,哪些协议
    • webapp的开发团队 和 WEB Server的开发团队 之间有一套规范: JavaEE规范之一Servlet规范。
      • Servlet规范的作用是什么?
        • WEB Server 和 webapp解耦合。
    • Browser 和 WebServer之间有一套传输协议:HTTP协议。(超文本传输协议。)
    • webapp开发团队 和 DB Server的开发团队之间有一套规范:JDBC规范。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • Servlet规范是一个什么规范?
    • 遵循Servlet规范的webapp,这个webapp就可以放在不同的WEB服务器中运行。(因为这个webapp是遵循Servlet规范的。)
    • Servlet规范包括什么呢?
      • 规范了哪些接口
      • 规范了哪些类
      • 规范了一个web应用中应该有哪些配置文件
      • 规范了一个web应用中配置文件的名字
      • 规范了一个web应用中配置文件存放的路径
      • 规范了一个web应用中配置文件的内容
      • 规范了一个合法有效的web应用它的目录结构应该是怎样的。

模拟Servlet本质

  • 充当SUN公司的角色,制定Servlet规范

    • javax.servlet.Servlet接口
  • 充当Tomcat服务器的开发者

  • 充当Webapp的开发者

    • BankServlet implements Servlet
    • UserListServlet implements Servlet
    • UserLoginServlet implements Servlet
  • 通过我们的分析:

    • 对于我们javaweb程序员来说,我们只需要做两件事:

      • 编写一个类实现Servlet接口。

      • 将编写的类配置到配置文件中,在配置文件中:指定 请求路径 和 类名 的关系。
        System.out.println(“Tomcat服务器启动成功,开始接收用户的访问。”);

        // 简单的使用Scanner来模拟一下用户的请求
        // 用户访问服务器是通过浏览器上的“请求路径”
        // 也就是说用户请求路径不同,后台执行的Servlet不同。
        /*
        /userList UserListServlet
        /login UserLoginServlet
        /bank BankServlet

        */
        System.out.print(“请输入您的访问路径:”);
        Scanner s = new Scanner(System.in);

        // 用户的请求路径 /bbbb
        String key = s.nextLine(); // Tomcat服务器已经获取到了用户的请求路径了。

        // Tomcat服务器应该通过用户的请求路径找对应的XXXServlet
        // 请求路径和XXXServlet之间的关系应该由谁指定呢?
        // 对于Tomcat服务器来说需要解析配置文件
        FileReader reader = new FileReader(“web.properties”);
        Properties pro = new Properties();
        pro.load(reader);
        reader.close();

        // 通过key获取value
        String className = pro.getProperty(key);
        // 通过反射机制创建对象
        Class clazz = Class.forName(className);
        Object obj = clazz.newInstance(); // obj的类型对于Tomcat服务器开发人员来说不知道。

        // 但是Tomcat服务器的开发者知道,你写的XXXXServlet一定实现了Servlet接口
        Servlet servlet = (Servlet)obj;
        servlet.service();

      }

  • 注意:通过模拟tomcat可以发现,读取配置文件的路径和名字已经写死了。

    • 这个配置文件的文件名不能乱来。固定的。
    • 这个配置文件的存放路径不能乱来。固定的。
    • 文件名、文件路径都是SUN公司制定的Servlet规范中的明细。
  • 严格意义上来说Servlet其实并不是简单的一个接口:

    • Servlet规范中规定了:
      • 一个合格的webapp应该是一个怎样的目录结构。
      • 一个合格的webapp应该有一个怎样的配置文件。
      • 一个合格的webapp配置文件路径放在哪里。
      • 一个合格的webapp中java程序放在哪里。
      • 这些都是Servlet规范中规定的。
  • Tomcat服务器要遵循Servlet规范。JavaWEB程序员也要遵循这个Servlet规范。这样Tomcat服务器和webapp才能解耦合。

开发一个带有Servlet(Java小程序)的webapp(重点)

  • 开发步骤是怎样的?

    • 第一步:在webapps目录下新建一个目录,起名crm(这个crm就是webapp的名字)。当然,也可以是其它项目,比如银行项目,可以创建一个目录bank,办公系统可以创建一个oa。

      • 注意:crm就是这个webapp的根
    • 第二步:在webapp的根下新建一个目录:WEB-INF

      • 注意:这个目录的名字是Servlet规范中规定的,必须全部大写,必须一模一样。必须的必须。
    • 第三步:在WEB-INF目录下新建一个目录:classes

      • 注意:这个目录的名字必须是全部小写的classes。这也是Servlet规范中规定的。另外这个目录下一定存放的是Java程序编译之后的class文件(这里存放的是字节码文件)。
    • 第四步:在WEB-INF目录下新建一个目录:lib

      • 注意:这个目录不是必须的。但如果一个webapp需要第三方的jar包的话,这个jar包要放到这个lib目录下,这个目录的名字也不能随意编写,必须是全部小写的lib。例如java语言连接数据库需要数据库的驱动jar包。那么这个jar包就一定要放到lib目录下。这Servlet规范中规定的。
    • 第五步:在WEB-INF目录下新建一个文件:web.xml

      • 注意:这个文件是必须的,这个文件名必须叫做web.xml。这个文件必须放在这里。一个合法的webapp,web.xml文件是必须的,这个web.xml文件就是一个配置文件,在这个配置文件中描述了请求路径和Servlet类之间的对照关系。

      • 这个文件最好从其他的webapp中拷贝,最好别手写。没必要。复制粘贴

      • <?xml version="1.0" encoding="UTF-8"?>
        
        <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                              https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
          version="5.0"
          metadata-complete="true">
        
        
        </web-app>
        
        
    • 第六步:编写一个Java程序,这个小Java程序也不能随意开发,这个小java程序必须实现Servlet接口。

      • 这个Servlet接口不在JDK当中。(因为Servlet不是JavaSE了。Servlet属于JavaEE,是另外的一套类库。)
      • Servlet接口(Servlet.class文件)是Oracle提供的。(最原始的是sun公司提供的。)
      • Servlet接口是JavaEE的规范中的一员。
        javaee8:javax.servet.Servlet 我用的tomcat9 C:\Program Files\Apache Software Foundation\Tomcat 9.0\lib\servlet-api\javax\servlet|
        Servlet.class
        jakartaee0:jakarta.servlet.Servlet
      • Tomcat服务器实现了Servlet规范,所以Tomcat服务器也需要使用Servlet接口。Tomcat服务器中应该有这个接口,Tomcat服务器的CATALINA_HOME\lib目录下有一个servlet-api.jar,解压这个servlet-api.jar之后,你会看到里面有一个Servlet.class文件。
      • 重点:从JakartaEE9开始,Servlet接口的全名变了:jakarta.servlet.Servlet
      • 注意:编写这个Java小程序的时候,java源代码你愿意在哪里就在哪里,位置无所谓,你只需要将java源代码编译之后的class文件放到classes目录下即可。

关于JavaEE的版本

Welcome to the Apache Tomcat® 10.x software download page. This page provides download links
for obtaining the latest version of Tomcat 10.0.x software, as well as links to the archives of older releases.

Unsure which version you need? Specification versions implemented, minimum Java version required
and lots more useful information may be found on the ‘which version?’ page.

Users of Tomcat 10 onwards should be aware that, as a result of the move from Java EE to Jakarta EE
as part of the transfer of Java EE to the Eclipse Foundation, the primary package for all implemented APIs
has changed from javax.* to jakarta.*. This will almost certainly require code changes to enable applications
to migrate from Tomcat 9 and earlier to Tomcat 10 and later. A migration tool has been developed to aid this process.

  • JavaEE目前最高版本是 JavaEE8
  • JavaEE被Oracle捐献了,Oracle将JavaEE规范捐献给Apache了。
  • Apache把JavaEE换名了,以后不叫JavaEE了,以后叫做 jakarta EE。
  • 以后没有JavaEE了。以后都叫做Jakarta EE。
  • JavaEE8版本升级之后的"JavaEE 9",不再是"JavaEE9"这个名字了,叫做JakartaEE9
  • JavaEE8的时候对应的Servlet类名是:javax.servlet.Servlet
  • JakartaEE9的时候对应的Servlet类名是:jakarta.servlet.Servlet (包名都换了)
  • 如果你之前的项目还是在使用javax.servlet.Servlet,那么你的项目无法直接部署到Tomcat10+版本上。
    你只能部署到Tomcat9-版本上。在Tomcat9以及Tomcat9之前的版本中还是能够识别javax.servlet这个包。

五个方法:
Modifier and Type Method Description
void destroy()
Called by the servlet container to indicate to a servlet that the servlet is being taken out of service.
由servlet容器调用,以指示servlet即将退出服务。
ServletConfig getServletConfig()

Returns a ServletConfig object, which contains initialization and startup parameters for this servlet.
返回一个ServletConfig对象,该对象包含这个servlet的初始化和启动参数。
java.lang.String getServletInfo()
Returns information about the servlet, such as author, version, and copyright.
返回有关servlet的信息,例如作者、版本和版权
void init​(ServletConfig config)
void init​(ServletConfig config) throws ServletException
Called by the servlet container to indicate to a servlet that the servlet is being placed into service.
由servlet容器调用,以指示servlet将被放入服务中。
void service​(ServletRequest req, ServletResponse res)
void service​(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException
Parameters:
req - the ServletRequest object that contains the client’s request
res - the ServletResponse object that contains the servlet’s response
Throws:
ServletException - if an exception occurs that interferes with the servlet’s normal operation
java.io.IOException - if an input or output exception occurs
Called by the servlet container to allow the servlet to respond to a request.
由servlet容器调用,以允许servlet响应请求。

  • 第七步:编译我们编写的HelloServlet

    • 重点:你怎么能让你的HelloServlet编译通过呢?配置环境变量CLASSPATH

      CLASSPATH=.;C:\dev\apache-tomcat-10.0.12\lib\servlet-api.jar

    • 思考问题:以上配置的CLASSPATH和Tomcat服务器运行有没有关系?

      • 没有任何关系,以上配置这个环境变量只是为了让你的HelloServlet能够正常编译生成class文件。
  • 第八步:将以上编译之后的HelloServlet.class文件拷贝到WEB-INF\classes目录下。

  • 第九步:在web.xml文件中编写配置信息,让“请求路径”和“Servlet类名”关联在一起。

    • 这一步用专业术语描述:在web.xml文件中注册Servlet类。

    • <?xml version="1.0" encoding="UTF-8"?>
      
      <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                            https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
        version="5.0"
        metadata-complete="true">
      
      	<!--servlet描述信息-->
      	<!--任何一个servlet都对应一个servlet-mapping -->
      	<servlet>
      		<servlet-name>fdsafdsagfdsafdsa</servlet-name>
      		<!--这个位置必须是带有包名的全限定类名-->
      		<servlet-class>com.bjpowernode.servlet.HelloServlet</servlet-class>
      	</servlet>
      
      	<!--servlet映射信息-->
      	<servlet-mapping>
      		<!--这个也是随便的,不过这里写的内容要和上面的一样。-->
      		<servlet-name>fdsafdsagfdsafdsa</servlet-name>
      		<!--这里需要一个路径-->
      		<!--这个路径唯一的要求是必须以 / 开始-->
      		<!--当前这个路径可以随便写-->
      		<url-pattern>/fdsa/fd/saf/d/sa/fd/sa/fd</url-pattern>
      	</servlet-mapping>
      	
      </web-app>
      
      
  • 第十步:启动Tomcat服务器

  • 第十一步:打开浏览器,在浏览器地址栏上输入一个url,这个URL必须是:

    • http://127.0.0.1:8080/crm/fdsa/fd/saf/d/sa/fd/sa/fd
    • 非常重要的一件事:浏览器上的请求路径不能随便写,这个请求路径必须和web.xml文件中的url-pattern一致。
    • 注意:浏览器上的请求路径和web.xml文件中的url-pattern的唯一区别就是:浏览器上的请求路径带项目名:/crm
  • 浏览器上编写的路径太复杂,可以使用超链接。(非常重要:html页面只能放到WEB-INF目录外面。

  • 以后不需要我们编写main方法了。tomcat服务器负责调用main方法,Tomcat服务器启动的时候执行的就是main方法。我们javaweb程序员只需要编写Servlet接口的实现类,然后将其注册到web.xml文件中,即可。

  • 总结一下:一个合法的webapp目录结构应该是怎样的?

    webapproot
         |------WEB-INF
         		  |------classes(存放字节码)
         		  |------lib(第三方jar包)
         		  |------web.xml(注册Servlet)
         |------html
         |------css
         |------javascript
         |------image
         ....
    
  • 浏览器发送请求,到最终服务器调用Servlet中的方法,是怎样的一个过程?(以下这个过程描述的很粗糙。其中还有很多步骤我省略了。)

    • 用户输入URL,或者直接点击超链接:http://127.0.0.1:8080/crm/fdsa/fd/saf/d/sa/fd/sa/fd
    • 然后Tomcat服务器接收到请求,截取路径:/crm/fdsa/fd/saf/d/sa/fd/sa/fd
    • Tomcat服务器找到crm项目
    • Tomcat服务器在web.xml文件中查找/fdsa/fd/saf/d/sa/fd/sa/fd 对应的Servlet是:com.bjpowernode.servlet.HelloServlet
    • Tomcat服务器通过反射机制,创建com.bjpowernode.servlet.HelloServlet的对象。
    • Tomcat服务器调用com.bjpowernode.servlet.HelloServlet对象的service方法。

解决Tomcat服务器在DOS命令窗口中的乱码问题(控制台乱码)

将CATALINA_HOME/conf/logging.properties文件中的内容修改如下:

java.util.logging.ConsoleHandler.encoding = GBK

向浏览器响应一段HTML代码
public void service(ServletRequest request, ServletResponse response){
response.setContentType(“text/html”);
PrintWriter out = response.getWriter();
out.print(“

hello servlet!

”);
}

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;

//这是tomcat9的javaee写法,之后会改变为
public class HelloServlet9 implements Servlet{

// 5个方法
public void init(ServletConfig config) throws ServletException{

}

public void service(ServletRequest request,ServletResponse response)
	throws ServletException , IOException{

	// 向控制台打印输出
	System.out.println("My First Servlet, Hello Servlet");

	// 设置响应的内容类型是普通文本或html代码
	// 需要在获取流对象之前设置,有效。
	response.setContentType("text/html");

	// 怎么将一个信息直接输出到浏览器上?
	// 需要使用ServletResponse接口:response
	// response表示响应:从服务器向浏览器发送数据叫做响应。
	PrintWriter out = response.getWriter();
	
	// 设置响应的内容类型时不要在获取流之后设置。
	//response.setContentType("text/html");

	out.print("Hello Servlet, You are my first servlet!");

	// 浏览器是能够识别html代码的,那我们是不是应该输出一段HTML代码呢?
	out.print("<h1>hello servlet,你好Servlet</h1>");

	// 这是一个输出流,负责输出字符串到浏览器
	// 这个输出流不需要我们刷新,也不需要我们关闭,这些都由Tomcat来维护。
	/*
	out.flush();
	out.close();
	*/
}

public void destroy(){

}

public String getServletInfo(){
	return "";
}

public ServletConfig getServletConfig(){
	return null;
}

}

在Servlet中连接数据库,怎么做?

  • Servlet是Java程序,所以在Servlet中完全可以编写JDBC代码连接数据库。
  • 在一个webapp中去连接数据库,需要将驱动jar包放到WEB-INF/lib目录下。(com.mysql.cj.jdbc.Driver 这个类就在驱动jar包当中。)

在集成开发环境当中开发Servlet程序

  • 集成开发工具很多,其中目前使用比较多的是:

    • IntelliJ IDEA(这个居多,IDEA在提示功能方面要强于Eclipse,也就是说IDEA使用起来比Eclipse更加智能,更好用。JetBrain公司开发的。收费的。)
    • Eclipse(这个少一些),Eclipse目前还是有团队使用,只不过处于减少的趋势,自己从事工作之后,可能会遇到。Eclipse是IBM团队开发的。Eclipse寓意是“日食”。“日食”表示将太阳吃掉。太阳是SUN。IBM团队开发Eclipse的寓意是吞并SUN公司,但是2009年的时候SUN公司被Oracle公司并购了。IBM并没有成功并购SUN公司。
  • 使用IDEA集成开发工具开发Servlet

    • 第一步:New Project(我比较习惯先创建一个Empty Project【空工程】,然后在空工程下新建Module【模块】,这不是必须的,只是一种习惯,你可以直接新建非空的Project),这个Empty Project起名为:javaweb(不是必须的,只是一个名字而已。一般情况下新建的Project的名字最好和目录的名字一致。)
    • 第二步:新建模块(File --> new --> Module…)
      • 这里新建的是一个普通的JavaSE模块(这里先不要新建Java Enterprise模块)
      • 这个Module自动会被放在javaweb的project下面。
      • 这个Module起名:servlet01
    • 第三步:让Module变成JavaEE的模块。(让Module变成webapp的模块。符合webapp规范。符合Servlet规范的Module)
      • 在Module上点击右键:Add Framework Support…(添加框架支持)
      • 在弹出的窗口中,选择Web Application(选择的是webapp的支持)
      • 选择了这个webapp的支持之后,IDEA会自动给你生成一个符合Servlet规范的webpp目录结构。
      • 重点,需要注意的:在IDEA工具中根据Web Application模板生成的目录中有一个web目录,这个目录就代表webapp的根
    • 第四步(非必须):根据Web Application生成的资源中有index.jsp文件,这里我选择删除这个index.jsp文件。
    • 第五步:编写Servlet(StudentServlet)
      • class StudentServlet implements Servlet
      • 这个时候发现Servlet.class文件没有。怎么办?将CATALINA_HOME/lib/servlet-api.jar和jsp-api.jar添加到classpath当中(这里的classpath说的是IDEA的classpath)
        • File --> Project Structrue --> Modules --> + 加号 --> Add JARS…
      • 实现jakarta.servlet.Servlet接口中的5个方法。
    • 第六步:在Servlet当中的service方法中编写业务代码(我们这里连接数据库了。)
    • 第七步:在WEB-INF目录下新建了一个子目录:lib(这个目录名可不能随意,必须是全部小写的lib),并且将连接数据库的驱动jar包放到lib目录下。
    • 第八步:在web.xml文件中完成StudentServlet类的注册。(请求路径和Servlet之间对应起来)
    <?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>studentServlet</servlet-name>
            <servlet-class>com.bjpowernode.javaweb.servlet.StudentServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>studentServlet</servlet-name>
            <url-pattern>/servlet/student</url-pattern>
        </servlet-mapping>
        
    </web-app>
    
    • 第九步:给一个html页面,在HTML页面中编写一个超链接,用户点击这个超链接,发送请求,Tomcat执行后台的StudentServlet。

      • student.html

      • 这个文件不能放到WEB-INF目录里面,只能放到WEB-INF目录外面。

      • student.html文件的内容

      • <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>student page</title>
        </head>
        <body>
            <!--这里的项目名是 /xmm ,无法动态获取,先写死-->
            <a href="/xmm/servlet/student">student list</a>
        </body>
        </html>
        
    • 第十步:让IDEA工具去关联Tomcat服务器。关联的过程当中将webapp部署到Tomcat服务器当中。

      • IDEA工具右上角,绿色小锤子右边有一个:Add Configuration
      • 左上角加号,点击Tomcat Server --> local
      • 在弹出的界面中设置服务器Server的参数(基本上不用动)
      • 在当前窗口中有一个Deployment(点击这个用来部署webapp),继续点击加号,部署即可。
      • 修改 Application context为:/xmm
    • 第十一步:启动Tomcat服务器

      • 在右上角有绿色的箭头,或者绿色的小虫子,点击这个绿色的小虫子,可以采用debug的模式启动Tomcat服务器。
      • 我们开发中建议适用debug模式启动Tomcat
    • 第十二步:打开浏览器,在浏览器地址栏上输入:http://localhost:8080/xmm/student.html

Servlet对象的生命周期

  • 什么是Servlet对象生命周期?

    • Servlet对象什么时候被创建。
    • Servlet对象什么时候被销毁。
    • Servlet对象创建了几个?
    • Servlet对象的生命周期表示:一个Servlet对象从出生在最后的死亡,整个过程是怎样的。
  • Servlet对象是由谁来维护的?

    • Servlet对象的创建,对象上方法的调用,对象最终的销毁,Javaweb程序员是无权干预的。
    • Servlet对象的生命周期是由Tomcat服务器(WEB Server)全权负责的。
    • Tomcat服务器通常我们又称为:WEB容器。(这个叫法你要知道【WEB Container】)
    • WEB容器来管理Servlet对象的死活。
  • 思考:我们自己new的Servlet对象受WEB容器的管理吗?

    • 我们自己new的Servlet对象是不受WEB容器管理的。
    • WEB容器创建的Servlet对象,这些Servlet对象都会被放到一个集合当中(HashMap),只有放到这个HashMap集合中的Servlet才能够被WEB容器管理,自己new的Servlet对象不会被WEB容器管理。(自己new的Servlet对象不在容器当中)
    • web容器底层应该有一个HashMap这样的集合,在这个集合当中存储了Servlet对象和请求路径之间的关系
    • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  • 研究:服务器在启动的Servlet对象有没有被创建出来(默认情况下)?

    • 在Servlet中提供一个无参数的构造方法,启动服务器的时候看看构造方法是否执行。
    • 经过测试得出结论:默认情况下,服务器在启动的时候Servlet对象并不会被实例化。
    • 这个设计是合理的。用户没有发送请求之前,如果提前创建出来所有的Servlet对象,必然是耗费内存的,并且创建出来的Servlet如果一直没有用户访问,显然这个Servlet对象是一个废物,没必要先创建。
  • 怎么让服务器启动的时候创建Servlet对象呢?

    • 在servlet标签中添加子标签,在该子标签中填写整数,越小的整数优先级越高。

    • <servlet>
          <servlet-name>aservlet</servlet-name>
          <servlet-class>com.bjpowernode.javaweb.servlet.AServlet</servlet-class>
          <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
          <servlet-name>aservlet</servlet-name>
          <url-pattern>/a</url-pattern>
      </servlet-mapping>
      
  • Servlet对象生命周期

    • 默认情况下服务器启动的时候AServlet对象并没有被实例化

    • 用户发送第一次请求的时候,控制台输出了以下内容:

      AServlet无参数构造方法执行了
      AServlet's init method execute!
      AServlet's service method execute!
      
    • 根据以上输出内容得出结论:

      • 用户在发送第一次请求的时候Servlet对象被实例化(AServlet的构造方法被执行了。并且执行的是无参数构造方法。)
      • AServlet对象被创建出来之后,Tomcat服务器马上调用了AServlet对象的init方法。(init方法在执行的时候,AServlet对象已经存在了。已经被创建出来了。)
      • 用户发送第一次请求的时候,init方法执行之后,Tomcat服务器马上调用AServlet对象的service方法。
    • 用户继续发送第二次请求,控制台输出了以下内容:

      AServlet's service method execute!
      
    • 根据以上输出结果得知,用户在发送第二次,或者第三次,或者第四次请求的时候,Servlet对象并没有新建,还是使用之前创建好的Servlet对象,直接调用该Servlet对象的service方法,这说明:

      • 第一:Servlet对象是单例的(单实例的。但是要注意:Servlet对象是单实例的,但是Servlet类并不符合单例模式。我们称之为假单例。之所以单例是因为Servlet对象的创建我们javaweb程序员管不着,这个对象的创建只能是Tomcat来说了算,Tomcat只创建了一个,所以导致了单例,但是属于假单例。真单例模式,构造方法是私有化的。)
      • 第二:无参数构造方法、init方法只在第一次用户发送请求的时候执行。也就是说无参数构造方法只执行一次。init方法也只被Tomcat服务器调用一次。
      • 第三:只要用户发送一次请求:service方法必然会被Tomcat服务器调用一次。发送100次请求,service方法会被调用100次。
    • 关闭服务器的时候,控制台输出了以下内容:

      AServlet's destroy method execute!
      
    • 通过以上输出内容,可以得出以下结论:

      • Servlet的destroy方法只被Tomcat服务器调用一次。
      • destroy方法是在什么时候被调用的?
        • 在服务器关闭的时候。
        • 因为服务器关闭的时候要销毁AServlet对象的内存。
        • 服务器在销毁AServlet对象内存之前,Tomcat服务器会自动调用AServlet对象的destroy方法。
    • 请问:destroy方法调用的时候,对象销毁了还是没有销毁呢?

      • destroy方法执行的时候AServlet对象还在,没有被销毁。destroy方法执行结束之后,AServlet对象的内存才会被Tomcat释放。
    • Servlet对象更像一个人的一生:

      • Servlet的无参数构造方法执行:标志着你出生了。
      • Servlet对象的init方法的执行:标志着你正在接受教育。
      • Servlet对象的service方法的执行:标志着你已经开始工作了,已经开始为人类提供服务了。
      • Servlet对象的destroy方法的执行:标志着临终。有什么遗言,抓紧的。要不然,来不及了。
    • 关于Servlet类中方法的调用次数?

      • 构造方法只执行一次。
      • init方法只执行一次。
      • service方法:用户发送一次请求则执行一次,发送N次请求则执行N次。
      • destroy方法只执行一次。
    • 当我们Servlet类中编写一个有参数的构造方法,如果没有手动编写无参数构造方法会出现什么问题?

      • 报错了:500错误。
      • 注意:500是一个HTTP协议的错误状态码。
      • 500一般情况下是因为服务器端的Java程序出现了异常。(服务器端的错误都是500错误:服务器内部错误。)
      • 如果没有无参数的构造方法,会导致出现500错误,无法实例化Servlet对象。
      • 所以,一定要注意:在Servlet开发当中,不建议程序员来定义构造方法,因为定义不当,一不小心就会导致无法实例化Servlet对象。
    • 思考:Servlet的无参数构造方法是在对象第一次创建的时候执行,并且只执行一次。init方法也是在对象第一次创建的时候执行,并且只执行一次。那么这个无参数构造方法可以代替掉init方法吗?

      • 不能。
      • Servlet规范中有要求,作为javaweb程序员,编写Servlet类的时候,不建议手动编写构造方法,因为编写构造方法,很容易让无参数构造方法消失,这个操作可能会导致Servlet对象无法实例化。所以init方法是有存在的必要的。
    • init、service、destroy方法中使用最多的是哪个方法?

      • 使用最多就是service方法,service方法是一定要实现的,因为service方法是处理用户请求的核心方法。
      • 什么时候使用init方法呢?
        • init方法很少用。
        • 通常在init方法当中做初始化操作,并且这个初始化操作只需要执行一次。例如:初始化数据库连接池,初始化线程池…
      • 什么时候使用destroy方法呢?
        • destroy方法也很少用。
        • 通常在destroy方法当中,进行资源的关闭。马上对象要被销毁了,还有什么没有关闭的,抓紧时间关闭资源。还有什么资源没保存的,抓紧时间保存一下。

GenericServlet

  • 我们编写一个Servlet类直接实现Servlet接口有什么缺点?

    • 我们只需要service方法,其他方法大部分情况下是不需要使用的。代码很丑陋。
  • 适配器设计模式Adapter

    • 手机直接插到220V的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个适配器。手机连接适配器。适配器连接220V的电压。这样问题就解决了。
  • 编写一个GenericServlet类,这个类是一个抽象类,其中有一个抽象方法service。

    • GenericServlet实现Servlet接口。
    • GenericServlet是一个适配器。
    • 以后编写的所有Servlet类继承GenericServlet,重写service方法即可。
  • 思考:GenericServlet类是否需要改造一下?怎么改造?更利于子类程序的编写?

    • 思考第一个问题:我提供了一个GenericServlet之后,init方法还会执行吗?

      • 还会执行。会执行GenericServlet类中的init方法。
    • 思考第二个问题:init方法是谁调用的?

      • Tomcat服务器调用的。
    • 思考第三个问题:init方法中的ServletConfig对象是谁创建的?是谁传过来的?

      • 都是Tomcat干的。
      • Tomcat服务器先创建了ServletConfig对象,然后调用init方法,将ServletConfig对象传给了init方法。
    • 思考一下Tomcat服务器伪代码:

      • public class Tomcat {
            public static void main(String[] args){
                // .....
                // Tomcat服务器伪代码
                // 创建LoginServlet对象(通过反射机制,调用无参数构造方法来实例化LoginServlet对象)
                Class clazz = Class.forName("com.bjpowernode.javaweb.servlet.LoginServlet");
                Object obj = clazz.newInstance();
                
                // 向下转型
                Servlet servlet = (Servlet)obj;
                
                // 创建ServletConfig对象
                // Tomcat服务器负责将ServletConfig对象实例化出来。
                // 多态(Tomcat服务器完全实现了Servlet规范)
                ServletConfig servletConfig = new org.apache.catalina.core.StandardWrapperFacade();
                
                // 调用Servlet的init方法
                servlet.init(servletConfig);
                
                // 调用Servlet的service方法
                // ....
                
            }
        }
        

GenericServlet是Servlet规范中的一员,sum公司已经写好了,以后我们就不用去实现servlet接口了,
GenericServet是适配器模式,集成这个抽象类,我们的代码会更简洁美观。
Package jakarta.servlet
Interface Servlet
All Known Implementing Classes:
GenericServlet, HttpServlet
void destroy()
Called by the servlet container to indicate to a servlet that the servlet is being taken out of service.
java.lang.String getInitParameter​(java.lang.String name)
Returns a String containing the value of the named initialization parameter, or null if the parameter does not exist.
java.util.Enumeration<java.lang.String> getInitParameterNames()
Returns the names of the servlet’s initialization parameters as an Enumeration of String objects, or an empty Enumeration if the servlet has no initialization parameters.
ServletConfig getServletConfig()
Returns this servlet’s ServletConfig object.
ServletContext getServletContext()
Returns a reference to the ServletContext in which this servlet is running.
java.lang.String getServletInfo()
Returns information about the servlet, such as author, version, and copyright.
java.lang.String getServletName()
Returns the name of this servlet instance.
void init()
A convenience method which can be overridden so that there’s no need to call super.init(config).
void init​(ServletConfig config)
Called by the servlet container to indicate to a servlet that the servlet is being placed into service.
void log​(java.lang.String message)
Writes the specified message to a servlet log file, prepended by the servlet’s name.
void log​(java.lang.String message, java.lang.Throwable t)
Writes an explanatory message and a stack trace for a given Throwable exception to the servlet log file, prepended by the servlet’s name.
abstract void service​(ServletRequest req, ServletResponse res)
Called by the servlet container to allow the servlet to respond to a request.

ServletConfig

  • 什么是ServletConfig?

    • Servlet对象的配置信息对象。
    • ServletConfig对象中封装了标签中的配置信息。(web.xml文件中servlet的配置信息)
  • 一个Servlet对应一个ServletConfig对象。

  • Servlet对象是Tomcat服务器创建,并且ServletConfig对象也是Tomcat服务器创建。并且默认情况下,他们都是在用户发送第一次请求的时候创建。

  • Tomcat服务器调用Servlet对象的init方法的时候需要传一个ServletConfig对象的参数给init方法。

  • ServletConfig接口的实现类是Tomcat服务器给实现的。(Tomcat服务器说的就是WEB服务器。)

  • ServletConfig接口有哪些常用的方法?

    • public String getInitParameter(String name); // 通过初始化参数的name获取value
      public Enumeration<String> getInitParameterNames(); // 获取所有的初始化参数的name
      public ServletContext getServletContext(); // 获取ServletContext对象
      public String getServletName(); // 获取Servlet的name
      
      <init-param>
          <param-name>driver</param-name>
          <param-value>com.mysql.cj.jdbc.Driver</param-value>
      </init-param>
      <init-param>
          <param-name>url</param-name>
          <param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value>
      </init-param>
    
    • 以上方法在Servlet类当中,都可以使用this去调用。因为GenericServlet实现了ServletConfig接口。
      最后我们无需调用ServletConfig接口的方法,GenericServlet已经写好了方法调用ServletConfig接口

ServletContext

<context-param>
    <param-name>pageSize</param-name>
    <param-value>10</param-value>
</context-param>
<context-param>
    <param-name>startIndex</param-name>
    <param-value>0</param-value>
</context-param>

/**

  • ServletContext

    1. ServletContext是什么?
  • ServletContext是接口,是Servlet规范中的一员。

    1. ServletContext是谁实现的?
  • Tomcat服务器(WEB服务器)实现了ServletContext接口。

  • public class org.apache.catalina.core.ApplicationContextFacade implements ServletContext {}

    1. ServletContext对象是谁创建的?在什么时候创建的?
  • ServletContext对象在WEB服务器启动的时候创建。

  • ServletContext对象是WEB服务器创建的。

  • 对于一个webapp来说,ServletContext对象只有一个。

  • ServletContext对象在服务器关闭的时候销毁。

    1. ServletContext怎么理解?
  • context是什么意思?

  •  Servlet对象的环境对象。(Servlet对象的上下文对象。)
    
  • ServletContext对象其实对应的就是整个web.xml文件。

  • 50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室当中。那么这个教室就相当于ServletContext对象。

  • 放在ServletContext对象当中的数据,所有Servlet一定是共享的。

  • 比如:一个教室中的空调是所有学生共享的,一个教室中的语文老师是所有学生共享的。

  • Tomcat是一个容器,一个容器当中可以放多个webapp,一个webapp对应一个ServletContext对象。
    */
    public class AServlet extends GenericServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
    response.setContentType(“text/html”);
    PrintWriter out = response.getWriter();
    // 获取ServletContext对象
    ServletContext application = this.getServletContext();
    out.print(“ServletContext对象是:” + application + “
    ”);

    // 获取上下文的初始化参数
    Enumeration<String> initParameterNames = application.getInitParameterNames();
    while(initParameterNames.hasMoreElements()){
        String name = initParameterNames.nextElement();
        String value = application.getInitParameter(name);
        out.print(name + "=" + value + "<br>");
    }
    
    // 获取context path (获取应用上下文的根)
    String contextPath = application.getContextPath();
    out.print(contextPath + "<br>");
    
    // 获取文件的绝对路径
    // 后面的这个路径,加了一个“/”,这个“/”代表的是web的根
    //String realPath = application.getRealPath("/index.html"); // 可以
    // 你不加“/”,默认也是从根下开始找。
    //String realPath = application.getRealPath("index.html"); // 不加“/”也可以
    //out.print(realPath + "<br>");
    
    // C:\Users\Administrator\IdeaProjects\javaweb\out\artifacts\servlet04_war_exploded\common\common.html
    String realPath = application.getRealPath("/common/common.html");
    out.print(realPath + "<br>");
    
    // 准备数据
    User user = new User("jack", "123");
    // 向ServletContext应用域当中存储数据
    application.setAttribute("userObj", user);
    // 取出来
    //Object userObj = application.getAttribute("userObj");
    // 输出到浏览器
    //out.print(userObj + "<br>");
    

    }
    }
    response.setContentType(“text/html”);
    PrintWriter out = response.getWriter();
    // 获取ServletContext对象
    ServletContext application = this.getServletContext();
    out.print(“ServletContext对象是:” + application + “
    ”);

    // 取出来
    Object userObj = application.getAttribute("userObj");
    // 输出到浏览器
    out.print(userObj + "<br>");
    
    // log
    // 这个日志会自动记录到哪里呢?
    // CATALINA_HOME/logs目录下。
    //application.log("大家好,我是动力节点杜老师,欢迎大家和我一起学习Servlet规范!");
    
    int age = 17; // 17岁
    // 当年龄小于18岁的时候,表示非法,记录日志
    if(age < 18) {
        application.log("对不起,您未成年,请绕行!", new RuntimeException("小屁孩,快走开,不适合你!"));
    }
    
  • 一个Servlet对象对应一个ServletConfig。100个Servlet对象则对应100个ServletConfig对象。

  • 只要在同一个webapp当中,只要在同一个应用当中,所有的Servlet对象都是共享同一个ServletContext对象的。

  • ServletContext对象在服务器启动阶段创建,在服务器关闭的时候销毁。这就是ServletContext对象的生命周期。ServletContext对象是应用级对象。

  • Tomcat服务器中有一个webapps,这个webapps下可以存放webapp,可以存放多个webapp,假设有100个webapp,那么就有100个ServletContext对象。
    但是,总之,一个应用,一个webapp肯定是只有一个ServletContext对象。

  • ServletContext被称为Servlet上下文对象。(Servlet对象的四周环境对象。)

  • 一个ServletContext对象通常对应的是一个web.xml文件。

  • ServletContext对应显示生活中的什么例子呢?

    • 一个教室里有多个学生,那么每一个学生就是一个Servlet,这些学生都在同一个教室当中,那么我们可以把这个教室叫做ServletContext对象。
      那么也就是说放在这个ServletContext对象(环境)当中的数据,在同一个教室当中,物品都是共享的。比如:教室中有一个空调,所有的学生都可以操作。可见,空调是共享的。
      因为空调放在教室当中。教室就是ServletContext对象。
  • ServletContext是一个接口,Tomcat服务器对ServletContext接口进行了实现。

    • ServletContext对象的创建也是Tomcat服务器来完成的。启动webapp的时候创建的。
  • ServletContext接口中有哪些常用的方法?

    • public String getInitParameter(String name); // 通过初始化参数的name获取value
      public Enumeration<String> getInitParameterNames(); // 获取所有的初始化参数的name
      
    • <!--以上两个方法是ServletContext对象的方法,这个方法获取的是什么信息?是以下的配置信息-->
      <context-param>
          <param-name>pageSize</param-name>
          <param-value>10</param-value>
      </context-param>
      <context-param>
          <param-name>startIndex</param-name>
          <param-value>0</param-value>
      </context-param>
      <!--注意:以上的配置信息属于应用级的配置信息,一般一个项目中共享的配置信息会放到以上的标签当中。-->
      <!--如果你的配置信息只是想给某一个servlet作为参考,那么你配置到servlet标签当中即可,使用ServletConfig对象来获取。-->
      
    • // 获取应用的根路径(非常重要),因为在java源代码当中有一些地方可能会需要应用的根路径,这个方法可以动态获取应用的根路径
      // 在java源码当中,不要将应用的根路径写死,因为你永远都不知道这个应用在最终部署的时候,起一个什么名字。
      public String getContextPath();
      //String contextPath = application.getContextPath();
      
    • // 获取文件的绝对路径(真实路径)
      public String getRealPath(String path);
      
    • // 通过ServletContext对象也是可以记录日志的
      public void log(String message);
      public void log(String message, Throwable t);
      // 这些日志信息记录到哪里了?
      // localhost.2021-11-05.log
      
      // Tomcat服务器的logs目录下都有哪些日志文件?
      //catalina.2021-11-05.log 服务器端的java程序运行的控制台信息。
      //localhost.2021-11-05.log ServletContext对象的log方法记录的日志信息存储到这个文件中。
      //localhost_access_log.2021-11-05.txt 访问日志
      
    • // ServletContext对象还有另一个名字:应用域(后面还有其他域,例如:请求域、会话域)
      
      // 如果所有的用户共享一份数据,并且这个数据很少的被修改,并且这个数据量很少,可以将这些数据放到ServletContext这个应用域中
      
      // 为什么是所有用户共享的数据? 不是共享的没有意义。因为ServletContext这个对象只有一个。只有共享的数据放进去才有意义。
      
      // 为什么数据量要小? 因为数据量比较大的话,太占用堆内存,并且这个对象的生命周期比较长,服务器关闭的时候,这个对象才会被销毁。大数据量会影响服务器的性能。占用内存较小的数据量可以考虑放进去。
      
      // 为什么这些共享数据很少的修改,或者说几乎不修改?
      // 所有用户共享的数据,如果涉及到修改操作,必然会存在线程并发所带来的安全问题。所以放在ServletContext对象中的数据一般都是只读的。
      
      // 数据量小、所有用户共享、又不修改,这样的数据放到ServletContext这个应用域当中,会大大提升效率。因为应用域相当于一个缓存,放到缓存中的数据,下次在用的时候,不需要从数据库中再次获取,大大提升执行效率。
      
      // 存(怎么向ServletContext应用域中存数据)
      public void setAttribute(String name, Object value); // map.put(k, v)
      // 取(怎么从ServletContext应用域中取数据)
      public Object getAttribute(String name); // Object v = map.get(k)
      // 删(怎么删除ServletContext应用域中的数据)
      public void removeAttribute(String name); // map.remove(k)
      
      
      
  • 注意:以后我们编写Servlet类的时候,实际上是不会去直接继承GenericServlet类的,因为我们是B/S结构的系统,这种系统是基于HTTP超文本传输协议的,在Servlet规范当中,提供了一个类叫做HttpServlet,它是专门为HTTP协议准备的一个Servlet类。我们编写的Servlet类要继承HttpServlet。(HttpServlet是HTTP协议专用的。)使用HttpServlet处理HTTP协议更便捷。但是你需要直到它的继承结构:

    • jakarta.servlet.Servlet(接口)【爷爷】
      jakarta.servlet.GenericServlet implements Servlet(抽象类)【儿子】
      jakarta.servlet.http.HttpServlet extends GenericServlet(抽象类)【孙子】
      
      我们以后编写的Servlet要继承HttpServlet类。
      
  • 大家到目前为止都接触过哪些缓存机制了?

    • 堆内存当中的字符串常量池。
      • “abc” 先在字符串常量池中查找,如果有,直接拿来用。如果没有则新建,然后再放入字符串常量池。
    • 堆内存当中的整数型常量池。
      • [-128 ~ 127] 一共256个Integer类型的引用,放在整数型常量池中。没有超出这个范围的话,直接从常量池中取。
    • 连接池(Connection Cache)
      • 这里所说的连接池中的连接是java语言连接数据库的连接对象:java.sql.Connection对象。
      • JVM是一个进程。MySQL数据库是一个进程。进程和进程之间建立连接,打开通道是很费劲的。是很耗费资源的。怎么办?可以提前先创建好N个Connection连接对象,将连接对象放到一个集合当中,我们把这个放有Connection对象的集合称为连接池。每一次用户连接的时候不需要再新建连接对象,省去了新建的环节,直接从连接池中获取连接对象,大大提升访问效率。
      • 连接池
        • 最小连接数
        • 最大连接数
        • 连接池可以提高用户的访问效率。当然也可以保证数据库的安全性。
    • 线程池
      • Tomcat服务器本身就是支持多线程的。
      • Tomcat服务器是在用户发送一次请求,就新建一个Thread线程对象吗?
        • 当然不是,实际上是在Tomcat服务器启动的时候,会先创建好N多个线程Thread对象,然后将线程对象放到集合当中,称为线程池。用户发送请求过来之后,需要有一个对应的线程来处理这个请求,这个时候线程对象就会直接从线程池中拿,效率比较高。
        • 所有的WEB服务器,或者应用服务器,都是支持多线程的,都有线程池机制。
    • redis
      • NoSQL数据库。非关系型数据库。缓存数据库。
    • 向ServletContext应用域中存储数据,也等于是将数据存放到缓存cache当中了。

HTTP协议

  • 什么是协议?

    • 协议实际上是某些人,或者某些组织提前制定好的一套规范,大家都按照这个规范来,这样可以做到沟通无障碍。
    • 协议就是一套规范,就是一套标准。由其他人或其他组织来负责制定的。
    • 我说的话你能听懂,你说的话,我也能听懂,这说明我们之间是有一套规范的,一套协议的,这套协议就是:中国普通话协议。我们都遵守这套协议,我们之间就可以沟通无障碍。
  • 什么是HTTP协议?

    • HTTP协议:是W3C制定的一种超文本传输协议。(通信协议:发送消息的模板提前被制定好。)
    • W3C:
      • 万维网联盟组织
      • 负责制定标准的:HTTP HTML4.0 HTML5 XML DOM等规范都是W3C制定的。
      • 万维网之父:蒂姆·伯纳斯·李
    • 什么是超文本?
      • 超文本说的就是:不是普通文本,比如流媒体:声音、视频、图片等。
      • HTTP协议支持:不但可以传送普通字符串,同样支持传递声音、视频、图片等流媒体信息。
    • 这种协议游走在B和S之间。B向S发数据要遵循HTTP协议。S向B发数据同样需要遵循HTTP协议。这样B和S才能解耦合。
    • 什么是解耦合?
      • B不依赖S。
      • S也不依赖B。
    • B/S表示:B/S结构的系统(浏览器访问WEB服务器的系统)
    • 浏览器 向 WEB服务器发送数据,叫做:请求(request)
    • WEB服务器 向 浏览器发送数据,叫做:响应(response)
    • HTTP协议包括:
      • 请求协议
        • 浏览器 向 WEB服务器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
      • 响应协议
        • WEB服务器 向 浏览器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
    • HTTP协议就是提前制定好的一种消息模板。
      • 不管你是哪个品牌的浏览器,都是这么发。
      • 不管你是哪个品牌的WEB服务器,都是这么发。
      • FF浏览器 可以向 Tomcat发送请求,也可以向Jetty服务器发送请求。浏览器不依赖具体的服务器品牌。
      • WEB服务器也不依赖具体的浏览器品牌。可以是FF浏览器,也可以是Chrome浏览器,可以是IE,都行。
  • HTTP的请求协议(B --> S)

    • HTTP的请求协议包括:4部分

      • 请求行
      • 请求头
      • 空白行
      • 请求体
    • HTTP请求协议的具体报文:GET请求

      • GET /servlet05/getServlet?username=lucy&userpwd=1111 HTTP/1.1                           请求行
        Host: localhost:8080                                                                    请求头
        Connection: keep-alive
        sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
        sec-ch-ua-mobile: ?0
        sec-ch-ua-platform: "Windows"
        Upgrade-Insecure-Requests: 1
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
        Sec-Fetch-Site: same-origin
        Sec-Fetch-Mode: navigate
        Sec-Fetch-User: ?1
        Sec-Fetch-Dest: document
        Referer: http://localhost:8080/servlet05/index.html
        Accept-Encoding: gzip, deflate, br
        Accept-Language: zh-CN,zh;q=0.9
                                                                                                空白行
                                                                                                请求体
        
    • HTTP请求协议的具体报文:POST请求

      • POST /servlet05/postServlet HTTP/1.1                                                  请求行
        Host: localhost:8080                                                                  请求头
        Connection: keep-alive
        Content-Length: 25
        Cache-Control: max-age=0
        sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
        sec-ch-ua-mobile: ?0
        sec-ch-ua-platform: "Windows"
        Upgrade-Insecure-Requests: 1
        Origin: http://localhost:8080
        Content-Type: application/x-www-form-urlencoded
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
        Sec-Fetch-Site: same-origin
        Sec-Fetch-Mode: navigate
        Sec-Fetch-User: ?1
        Sec-Fetch-Dest: document
        Referer: http://localhost:8080/servlet05/index.html
        Accept-Encoding: gzip, deflate, br
        Accept-Language: zh-CN,zh;q=0.9
                                                                                              空白行
        username=lisi&userpwd=123                                                             请求体
        
    • 请求行

      • 包括三部分:
        • 第一部分:请求方式(7种)
          • get(常用的)
          • post(常用的)
          • delete
          • put
          • head
          • options
          • trace
        • 第二部分:URI
          • 什么是URI? 统一资源标识符。代表网络中某个资源的名字。但是通过URI是无法定位资源的。
          • 什么是URL?统一资源定位符。代表网络中某个资源,同时,通过URL是可以定位到该资源的。
          • URI和URL什么关系,有什么区别?
          • URI = Uniform Resource Identifier 统一资源标志符
          • URL = Uniform Resource Locator 统一资源定位符
          • URN = Uniform Resource Name 统一资源名称
            • URL包括URI
            • http://localhost:8080/servlet05/index.html 这是URL。
            • /servlet05/index.html 这是URI。
        • 第三部分:HTTP协议版本号
    • 请求头

      • 请求的主机
      • 主机的端口
      • 浏览器信息
      • 平台信息
      • cookie等信息
    • 空白行

      • 空白行是用来区分“请求头”和“请求体”
    • 请求体

      • 向服务器发送的具体数据。
  • HTTP的响应协议(S --> B)

    • HTTP的响应协议包括:4部分

      • 状态行
      • 响应头
      • 空白行
      • 响应体
    • HTTP响应协议的具体报文:

      • HTTP/1.1 200 ok                                     状态行
        Content-Type: text/html;charset=UTF-8               响应头
        Content-Length: 160
        Date: Mon, 08 Nov 2021 13:19:32 GMT
        Keep-Alive: timeout=20
        Connection: keep-alive
                                                            空白行
        <!doctype html>                                     响应体
        <html>
            <head>
                <title>from get servlet</title>
            </head>
            <body>
                <h1>from get servlet</h1>
            </body>
        </html>
        
    • 状态行

      • 三部分组成
        • 第一部分:协议版本号(HTTP/1.1)
        • 第二部分:状态码(HTTP协议中规定的响应状态号。不同的响应结果对应不同的号码。)
          • 200 表示请求响应成功,正常结束。
          • 404表示访问的资源不存在,通常是因为要么是你路径写错了,要么是路径写对了,但是服务器中对应的资源并没有启动成功。总之404错误是前端错误。
          • 405表示前端发送的请求方式与后端请求的处理方式不一致时发生:
            • 比如:前端是POST请求,后端的处理方式按照get方式进行处理时,发生405
            • 比如:前端是GET请求,后端的处理方式按照post方式进行处理时,发生405
          • 500表示服务器端的程序出现了异常。一般会认为是服务器端的错误导致的。
          • 以4开始的,一般是浏览器端的错误导致的。
          • 以5开始的,一般是服务器端的错误导致的。
        • 第三部分:状态的描述信息
          • ok 表示正常成功结束。
          • not found 表示资源找不到。
    • 响应头:

      • 响应的内容类型
      • 响应的内容长度
      • 响应的时间
    • 空白行:

      • 用来分隔“响应头”和“响应体”的。
    • 响应体:

      • 响应体就是响应的正文,这些内容是一个长的字符串,这个字符串被浏览器渲染,解释并执行,最终展示出效果。
  • 怎么查看的协议内容?

    • 使用chrome浏览器:F12。然后找到network,通过这个面板可以查看协议的具体内容。
  • 怎么向服务器发送GET请求,怎么向服务器发送POST请求?

    • 到目前为止,只有一种情况可以发送POST请求:使用form表单,并且form标签中的method属性值为:method=“post”。
    • 其他所有情况一律都是get请求:
      • 在浏览器地址栏上直接输入URL,敲回车,属于get请求。
      • 在浏览器上直接点击超链接,属于get请求。
      • 使用form表单提交数据时,form标签中没有写method属性,默认就是get
      • 或者使用form的时候,form标签中method属性值为:method=“get”
  • GET请求和POST请求有什么区别?

    • get请求发送数据的时候,数据会挂在URI的后面,并且在URI后面添加一个“?”,"?"后面是数据。这样会导致发送的数据回显在浏览器的地址栏上。(get请求在“请求行”上发送数据)
      • http://localhost:8080/servlet05/getServlet?username=zhangsan&userpwd=1111
    • post请求发送数据的时候,在请求体当中发送。不会回显到浏览器的地址栏上。也就是说post发送的数据,在浏览器地址栏上看不到。(post在“请求体”当中发送数据)
    • get请求只能发送普通的字符串。并且发送的字符串长度有限制,不同的浏览器限制不同。这个没有明确的规范。
    • get请求无法发送大数据量。
    • post请求可以发送任何类型的数据,包括普通字符串,流媒体等信息:视频、声音、图片。
    • post请求可以发送大数据量,理论上没有长度限制。
    • get请求在W3C中是这样说的:get请求比较适合从服务器端获取数据。
    • post请求在W3C中是这样说的:post请求比较适合向服务器端传送数据。
    • get请求是安全的。get请求是绝对安全的。为什么?因为get请求只是为了从服务器上获取数据。不会对服务器造成威胁。(get本身是安全的,你不要用错了。用错了之后又冤枉人家get不安全,你这样不好(太坏了),那是你自己的问题,不是get请求的问题。)
    • post请求是危险的。为什么?因为post请求是向服务器提交数据,如果这些数据通过后门的方式进入到服务器当中,服务器是很危险的。另外post是为了提交数据,所以一般情况下拦截请求的时候,大部分会选择拦截(监听)post请求。
    • get请求支持缓存。
      • https://n.sinaimg.cn/finance/590/w240h350/20211101/b40c-b425eb67cabc342ff5b9dc018b4b00cc.jpg
      • 任何一个get请求最终的“响应结果”都会被浏览器缓存起来。在浏览器缓存当中:
        • 一个get请求的路径a 对应 一个资源。
        • 一个get请求的路径b 对应 一个资源。
        • 一个get请求的路径c 对应 一个资源。
      • 实际上,你只要发送get请求,浏览器做的第一件事都是先从本地浏览器缓存中找,找不到的时候才会去服务器上获取。这种缓存机制目的是为了提高用户的体验。
      • 有没有这样一个需求:我们不希望get请求走缓存,怎么办?怎么避免走缓存?我希望每一次这个get请求都去服务器上找资源,我不想从本地浏览器的缓存中取。
        • 只要每一次get请求的请求路径不同即可。
        • https://n.sinaimg.cn/finance/590/w240h350/20211101/7cabc342ff5b9dc018b4b00cc.jpg?t=789789787897898
        • https://n.sinaimg.cn/finance/590/w240h350/20211101/7cabc342ff5b9dc018b4b00cc.jpg?t=789789787897899
        • https://n.sinaimg.cn/finance/590/w240h350/20211101/7cabc342ff5b9dc018b4b00cc.jpg?t=系统毫秒数
        • 怎么解决?可以在路径的后面添加一个每时每刻都在变化的“时间戳”,这样,每一次的请求路径都不一样,浏览器就不走缓存了。
    • post请求不支持缓存。(POST是用来修改服务器端的资源的。)
      • post请求之后,服务器“响应的结果”不会被浏览器缓存起来。因为这个缓存没有意义。
  • GET请求和POST请求如何选择,什么时候使用GET请求,什么时候使用POST请求?

    • 怎么选择GET请求和POST请求呢?衡量标准是什么呢?你这个请求是想获取服务器端的数据,还是想向服务器发送数据。如果你是想从服务器上获取资源,建议使用GET请求,如果你这个请求是为了向服务器提交数据,建议使用POST请求。
    • 大部分的form表单提交,都是post方式,因为form表单中要填写大量的数据,这些数据是收集用户的信息,一般是需要传给服务器,服务器将这些数据保存/修改等。
    • 如果表单中有敏感信息,还是建议适用post请求,因为get请求会回显敏感信息到浏览器地址栏上。(例如:密码信息)
    • 做文件上传,一定是post请求。要传的数据不是普通文本。
    • 其他情况都可以使用get请求。
  • 不管你是get请求还是post请求,发送的请求数据格式是完全相同的,只不过位置不同,格式都是统一的:

    • name=value&name=value&name=value&name=value
    • name是什么?
      • 以form表单为例:form表单中input标签的name。
    • value是什么?
      • 以form表单为例:form表单中input标签的value。

HttpServlet源码分析

  • HttpServlet类是专门为HTTP协议准备的。比GenericServlet更加适合HTTP协议下的开发。
  • HttpServlet在哪个包下?
    • jakarta.servlet.http.HttpServlet
  • 到目前为止我们接触了servlet规范中哪些接口?
    • jakarta.servlet.Servlet 核心接口(接口)
    • jakarta.servlet.ServletConfig Servlet配置信息接口(接口)
    • jakarta.servlet.ServletContext Servlet上下文接口(接口)
    • jakarta.servlet.ServletRequest Servlet请求接口(接口)
    • jakarta.servlet.ServletResponse Servlet响应接口(接口)
    • jakarta.servlet.ServletException Servlet异常(类)
    • jakarta.servlet.GenericServlet 标准通用的Servlet类(抽象类)
  • http包下都有哪些类和接口呢?jakarta.servlet.http.*;
    • jakarta.servlet.http.HttpServlet (HTTP协议专用的Servlet类,抽象类)
    • jakarta.servlet.http.HttpServletRequest (HTTP协议专用的请求对象)
    • jakarta.servlet.http.HttpServletResponse (HTTP协议专用的响应对象)
  • HttpServletRequest对象中封装了什么信息?
    • HttpServletRequest,简称request对象。
    • HttpServletRequest中封装了请求协议的全部内容。
    • Tomcat服务器(WEB服务器)将“请求协议”中的数据全部解析出来,然后将这些数据全部封装到request对象当中了。
    • 也就是说,我们只要面向HttpServletRequest,就可以获取请求协议中的数据。
  • HttpServletResponse对象是专门用来响应HTTP协议到浏览器的。
  • 回忆Servlet生命周期?
    • 用户第一次请求
      • Tomcat服务器通过反射机制,调用无参数构造方法。创建Servlet对象。(web.xml文件中配置的Servlet类对应的对象。)
      • Tomcat服务器调用Servlet对象的init方法完成初始化。
      • Tomcat服务器调用Servlet对象的service方法处理请求。
    • 用户第二次请求
      • Tomcat服务器调用Servlet对象的service方法处理请求。
    • 用户第三次请求
      • Tomcat服务器调用Servlet对象的service方法处理请求。
      • Tomcat服务器调用Servlet对象的service方法处理请求。
    • 服务器关闭
      • Tomcat服务器调用Servlet对象的destroy方法,做销毁之前的准备工作。
      • Tomcat服务器销毁Servlet对象。
  • HttpServlet源码分析:
public class HelloServlet extends HttpServlet {
	// 用户第一次请求,创建HelloServlet对象的时候,会执行这个无参数构造方法。
	public HelloServlet() {
    }
    
    //override 重写 doGet方法
    //override 重写 doPost方法
}

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
           
	// 用户第一次请求的时候,HelloServlet对象第一次被创建之后,这个init方法会执行。
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
	// 用户第一次请求的时候,带有参数的init(ServletConfig config)执行之后,会执行这个没有参数的init()
	public void init() throws ServletException {
        // NOOP by default
    }
}

// HttpServlet模板类。
public abstract class HttpServlet extends GenericServlet {
    // 用户发送第一次请求的时候这个service会执行
    // 用户发送第N次请求的时候,这个service方法还是会执行。
    // 用户只要发送一次请求,这个service方法就会执行一次。
    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;

        try {
            // 将ServletRequest和ServletResponse向下转型为带有Http的HttpServletRequest和HttpServletResponse
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        // 调用重载的service方法。
        service(request, response);
    }
    
    // 这个service方法的两个参数都是带有Http的。
    // 这个service是一个模板方法。
    // 在该方法中定义核心算法骨架,具体的实现步骤延迟到子类中去完成。
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        // 获取请求方式
        // 这个请求方式最终可能是:""
        // 注意:request.getMethod()方法获取的是请求方式,可能是七种之一:
        // GET POST PUT DELETE HEAD OPTIONS TRACE
        String method = req.getMethod();

        // 如果请求方式是GET请求,则执行doGet方法。
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            // 如果请求方式是POST请求,则执行doPost方法。
            doPost(req, resp);

        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);

        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);

        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);

        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
    
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException{
        // 报405错误
        String msg = lStrings.getString("http.method_get_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        // 报405错误
        String msg = lStrings.getString("http.method_post_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }
    
}

/*
通过以上源代码分析:
	假设前端发送的请求是get请求,后端程序员重写的方法是doPost
	假设前端发送的请求是post请求,后端程序员重写的方法是doGet
	会发生什么呢?
		发生405这样的一个错误。
		405表示前端的错误,发送的请求方式不对。和服务器不一致。不是服务器需要的请求方式。
		从源码可知,如果没有重写odget方法,服务器调用了HttpServlet的方法就会报405错误,这是HttpServlet专属的,使用GenericServlet不会报这样的错误,所以HttpServlet更符合程序员编写。
		重写service方法可不可以?可以!但是就无法享受到405错误。
		
	 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException{
        // 报405错误
        String msg = lStrings.getString("http.method_get_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }
	通过以上源代码可以知道:只要HttpServlet类中的doGet方法或doPost方法执行了,必然405.

怎么避免405的错误呢?
	后端重写了doGet方法,前端一定要发get请求。
	后端重写了doPost方法,前端一定要发post请求。
	这样可以避免405错误。
	
	这种前端到底需要发什么样的请求,其实应该后端说了算。后端让发什么方式,前端就得发什么方式。
	
有的人,你会看到为了避免405错误,在Servlet类当中,将doGet和doPost方法都进行了重写。
这样,确实可以避免405的发生,但是不建议,405错误还是有用的。该报错的时候就应该让他报错。
如果你要是同时重写了doGet和doPost,那还不如你直接重写service方法好了。这样代码还能
少写一点。
*/


  • 我们编写的HelloServlet直接继承HttpServlet,直接重写HttpServlet类中的service()方法行吗?

    • 可以,只不过你享受不到405错误。享受不到HTTP协议专属的东西。
  • 到今天我们终于得到了最终的一个Servlet类的开发步骤:

    • 第一步:编写一个Servlet类,直接继承HttpServlet
    • 第二步:重写doGet方法或者重写doPost方法,到底重写谁,javaweb程序员说了算。
    • 第三步:将Servlet类配置到web.xml文件当中。
    • 第四步:准备前端的页面(form表单),form表单中指定请求路径即可。
  • 什么是一个web站点的欢迎页面?

    • 对于一个webapp来说,我们是可以设置它的欢迎页面的。
    • 设置了欢迎页面之后,当你访问这个webapp的时候,或者访问这个web站点的时候,没有指定任何“资源路径”,这个时候会默认访问你的欢迎页面。
    • 我们一般的访问方式是:
      • http://localhost:8080/servlet06/login.html 这种方式是指定了要访问的就是login.html资源。
    • 如果我们访问的方式是:
      • http://localhost:8080/servlet06 如果我们访问的就是这个站点,没有指定具体的资源路径。它默认会访问谁呢?
      • 默认会访问你设置的欢迎页面。
  • 怎么设置欢迎页面呢?

    • 第一步:我在IDEA工具的web目录下新建了一个文件login.html

    • 第二步:在web.xml文件中进行了以下的配置

      • <welcome-file-list>
                <welcome-file>login.html</welcome-file>
            </welcome-file-list>
        
      • 注意:设置欢迎页面的时候,这个路径不需要以“/”开始。并且这个路径默认是从webapp的根下开始查找。

    • 第三步:启动服务器,浏览器地址栏输入地址

      • http://localhost:8080/servlet07
  • 如果在webapp的根下新建一个目录,目录中再给一个文件,那么这个欢迎页该如何设置呢?

    • 在webapp根下新建page1

    • 在page1下新建page2目录

    • 在page2目录下新建page.html页面

    • 在web.xml文件中应该这样配置

      • <welcome-file-list>
            <welcome-file>page1/page2/page.html</welcome-file>
        </welcome-file-list>
        
      • 注意:路径不需要以“/”开始,并且路径默认从webapp的根下开始找。

  • 一个webapp是可以设置多个欢迎页面的

    • <welcome-file-list>
          <welcome-file>page1/page2/page.html</welcome-file>
          <welcome-file>login.html</welcome-file>
      </welcome-file-list>
      
    • 注意:越靠上的优先级越高。找不到的继续向下找。

  • 你有没有注意一件事:当我的文件名设置为index.html的时候,不需要在web.xml文件中进行配置欢迎页面。这是为什么?

    • 这是因为小猫咪Tomcat服务器已经提前配置好了。

    • 实际上配置欢迎页面有两个地方可以配置:

      • 一个是在webapp内部的web.xml文件中。(在这个地方配置的属于局部配置)

      • 一个是在CATALINA_HOME/conf/web.xml文件中进行配置。(在这个地方配置的属于全局配置)

        • <welcome-file-list>
              <welcome-file>index.html</welcome-file>
              <welcome-file>index.htm</welcome-file>
              <welcome-file>index.jsp</welcome-file>
          </welcome-file-list>
          
        • Tomcat服务器的全局欢迎页面是:index.html index.htm index.jsp。如果你一个web站点没有设置局部的欢迎页面,Tomcat服务器就会以index.html index.htm index.jsp作为一个web站点的欢迎页面。

      • 注意原则:局部优先原则。(就近原则)

  • 欢迎页可以是一个Servlet吗?

    • 当然可以。

    • 你不要多想,欢迎页就是一个资源,既然是一个资源,那么可以是静态资源,也可以是动态资源。

    • 静态资源:index.html welcome.html …

    • 动态资源:Servlet类。

    • 步骤:

      • 第一步:写一个Servlet

        • public class WelcomeServlet extends HttpServlet {
              @Override
              protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                  response.setContentType("text/html");
                  PrintWriter out = response.getWriter();
                  out.print("<h1>welcome to bjpowernode!</h1>");
              }
          }
          
      • 第二步:在web.xml文件中配置servlet

        •     <servlet>
                  <servlet-name>welcomeServlet</servlet-name>
                  <servlet-class>com.bjpowernode.javaweb.servlet.WelcomeServlet</servlet-class>
              </servlet>
              <servlet-mapping>
                  <servlet-name>welcomeServlet</servlet-name>
                  <url-pattern>/fdsa/fds/a/fds/af/ds/af/dsafdsafdsa</url-pattern>
              </servlet-mapping>
          
      • 第三步:在web.xml文件中配置欢迎页

        •     <welcome-file-list>
                  <welcome-file>fdsa/fds/a/fds/af/ds/af/dsafdsafdsa</welcome-file>
              </welcome-file-list>
          

          关于WEB-INF目录

  • 在WEB-INF目录下新建了一个文件:welcome.html

  • 打开浏览器访问:http://localhost:8080/servlet07/WEB-INF/welcome.html 出现了404错误。

  • 注意:放在WEB-INF目录下的资源是受保护的。在浏览器上不能够通过路径直接访问。所以像HTML、CSS、JS、image等静态资源一定要放到WEB-INF目录之外。

HttpServletRequest接口详解

  • HttpServletRequest是一个接口,全限定名称:jakarta.servlet.http.HttpServletRequest

  • HttpServletRequest接口是Servlet规范中的一员。

  • HttpServletRequest接口的父接口:ServletRequest

    • public interface HttpServletRequest extends ServletRequest {}
      
  • HttpServletRequest接口的实现类谁写的? HttpServletRequest对象是谁给创建的?

    • 通过测试:org.apache.catalina.connector.RequestFacade 实现了 HttpServletRequest接口

      • public class RequestFacade implements HttpServletRequest {}
        
    • 测试结果说明:Tomcat服务器(WEB服务器、WEB容器)实现了HttpServletRequest接口,还是说明了Tomcat服务器实现了Servlet规范。而对于我们javaweb程序员来说,实际上不需要关心这个,我们只需要面向接口编程即可。我们关心的是HttpServletRequest接口中有哪些方法,这些方法可以完成什么功能!!!!

  • HttpServletRequest对象中都有什么信息?都包装了什么信息?

    • HttpServletRequest对象是Tomcat服务器负责创建的。这个对象中封装了什么信息?封装了HTTP的请求协议。
    • 实际上是用户发送请求的时候,遵循了HTTP协议,发送的是HTTP的请求协议,Tomcat服务器将HTTP协议中的信息以及数据全部解析出来,然后Tomcat服务器把这些信息封装到HttpServletRequest对象当中,传给了我们javaweb程序员。
    • javaweb程序员面向HttpServletRequest接口编程,调用方法就可以获取到请求的信息了。
  • request和response对象的生命周期?

    • request对象和response对象,一个是请求对象,一个是响应对象。这两个对象只在当前请求中有效。
    • 一次请求对应一个request。
    • 两次请求则对应两个request。
  • HttpServletRequest接口中有哪些常用的方法?

    • 怎么获取前端浏览器用户提交的数据?

      • Map<String,String[]> getParameterMap() 这个是获取Map
        Enumeration<String> getParameterNames() 这个是获取Map集合中所有的key
        String[] getParameterValues(String name) 根据key获取Map集合的value
        String getParameter(String name)  获取value这个一维数组当中的第一个元素。这个方法最常用。
        // 以上的4个方法,和获取用户提交的数据有关系。
        
      • 思考:如果是你,前端的form表单提交了数据之后,你准备怎么存储这些数据,你准备采用什么样的数据结构去存储这些数据呢?

        • 前端提交的数据格式:username=abc&userpwd=111&aihao=s&aihao=d&aihao=tt

        • 我会采用Map集合来存储:

          • Map<String,String>
                key存储String
                value存储String
                这种想法对吗?不对。
                如果采用以上的数据结构存储会发现key重复的时候value覆盖。
                key         value
                ---------------------
                username    abc
                userpwd     111
                aihao       s
                aihao       d
                aihao       tt
                这样是不行的,因为map的key不能重复。
            Map<String, String[]>
                key存储String
                value存储String[]
                key				value
                -------------------------------
                username		{"abc"}
                userpwd			{"111"}
                aihao			{"s","d","tt"}
            
        • 注意:前端表单提交数据的时候,假设提交了120这样的“数字”,其实是以字符串"120"的方式提交的,所以服务器端获取到的一定是一个字符串的"120",而不是一个数字。(前端永远提交的是字符串,后端获取的也永远是字符串。)

    • 手工开发一个webapp。测试HttpServletRequest接口中的相关方法。

      • 先测试了4个常用的方法,获取请求参数的四个方法。

        • Map<String,String[]> parameterMap = request.getParameterMap();
           	Enumeration<String> names = request.getParameterNames();
           	String[] values = request.getParameterValues("name");
           	String value = request.getParameter("name");//如果是数组,只获得数组的第一个元素。
          
      • request对象实际上又称为“请求域”对象。

        • 应用域对象是什么?

          • ServletContext (Servlet上下文对象。)

          • 什么情况下会考虑向ServletContext这个应用域当中绑定数据呢?

            • 第一:所有用户共享的数据。
            • 第二:这个共享的数据量很小。
            • 第三:这个共享的数据很少的修改操作。
            • 在以上三个条件都满足的情况下,使用这个应用域对象,可以大大提高我们程序执行效率。
            • 实际上向应用域当中绑定数据,就相当于把数据放到了缓存(Cache)当中,然后用户访问的时候直接从缓存中取,减少IO的操作,大大提升系统的性能,所以缓存技术是提高系统性能的重要手段。
          • 你见过哪些缓存技术呢?

            • 字符串常量池
            • 整数型常量池 [-128~127],但凡是在这个范围当中的Integer对象不再创建新对象,直接从这个整数型常量池中获取。大大提升系统性能。
            • 数据库连接池(提前创建好N个连接对象,将连接对象放到集合当中,使用连接对象的时候,直接从缓存中拿。省去了连接对象的创建过程。效率提升。)
            • 线程池(Tomcat服务器就是支持多线程的。所谓的线程池就是提前先创建好N个线程对象,将线程对象存储到集合中,然后用户请求过来之后,直接从线程池中获取线程对象,直接拿来用。提升系统性能)
            • 后期你还会学习更多的缓存技术,例如:redis、mongoDB…
          • ServletContext当中有三个操作域的方法:

            • void setAttribute(String name, Object obj); // 向域当中绑定数据。
              Object getAttribute(String name); // 从域当中根据name获取数据。
              void removeAttribute(String name); // 将域当中绑定的数据移除
              
              // 以上的操作类似于Map集合的操作。
              Map<String, Object> map;
              map.put("name", obj); // 向map集合中放key和value
              Object obj = map.get("name"); // 通过map集合的key获取value
              map.remove("name"); // 通过Map集合的key删除key和value这个键值对。
              
        • “请求域”对象

          • “请求域”对象要比“应用域”对象范围小很多。生命周期短很多。请求域只在一次请求内有效。

          • 一个请求对象request对应一个请求域对象。一次请求结束之后,这个请求域就销毁了。

          • 请求域对象也有这三个方法:

            • void setAttribute(String name, Object obj); // 向域当中绑定数据。
              Object getAttribute(String name); // 从域当中根据name获取数据。
              void removeAttribute(String name); // 将域当中绑定的数据移除
              
          • 请求域和应用域的选用原则?

            • 尽量使用小的域对象,因为小的域对象占用的资源较少。
        • 跳转
          /**
          这个方法在ServletRequest接口里边

  • Returns a {@link RequestDispatcher} object that acts as a wrapper for the

  • resource located at the given path. A RequestDispatcher

  • object can be used to forward a request to the resource or to include the

  • resource in a response. The resource can be dynamic or static.

  • The pathname specified may be relative, although it cannot extend outside

  • the current servlet context. If the path begins with a “/” it is

  • interpreted as relative to the current context root. This method returns

  • null if the servlet container cannot return a

  • RequestDispatcher.

  • The difference between this method and

  • {@link ServletContext#getRequestDispatcher} is that this method can take

  • a relative path.

  • @param path

  •        a <code>String</code> specifying the pathname to the resource.
    
  •        If it is relative, it must be relative against the current
    
  •        servlet.
    
  • @return a RequestDispatcher object that acts as a wrapper for

  •     the resource at the specified path, or <code>null</code> if the
    
  •     servlet container cannot return a <code>RequestDispatcher</code>
    
  • @see RequestDispatcher

  • @see ServletContext#getRequestDispatcher
    */
    public RequestDispatcher getRequestDispatcher(String path);

     - 转发(一次请求)
    
       - ```java
         // 第一步:获取请求转发器对象Dispatcher调度转发
         RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
         // 第二步:调用转发器的forward方法完成跳转/转发
         dispatcher.forward(request,response);
         
         // 第一步和第二步代码可以联合在一起。
         request.getRequestDispatcher("/b").forward(request,response);
         
         ```
    

// 这样做可以吗?
// 在AServlet当中new一个BServlet对象,然后调用BServlet对象的doGet方法,把request对象传过去。
// 这个代码虽然可以实现功能,但是Servlet对象不能自己由程序员来new。自己new的Servlet对象生命周期不受Tomcat服务器的管理。
/BServlet bServlet = new BServlet();
bServlet.doGet(request, response);
/

    // 使用Servlet当中的转发机制。
    // 执行了AServlet之后,跳转到BServlet。(这个资源跳转可以使用转发机制来完成。)
    // 怎么转发?代码怎么写?
    // 第一步:获取请求转发器对象
    // 相当于把"/b"这个路径包装到请求转发器当中,实际上是把下一个跳转的资源的路径告知给Tomcat服务器了。
    //RequestDispatcher dispatcher = request.getRequestDispatcher("/b");

    // 第二步:调用请求转发器RequestDispatcher的forward方法。进行转发。
    // 转发的时候:这两个参数很重要。request和response都是要传递给下一个资源的。
    //dispatcher.forward(request, response);

    // 一行代码搞定转发。
    //request.getRequestDispatcher("/b").forward(request, response);

    // 转发到一个Servlet,也可以转发到一个HTML,只要是WEB容器当中的合法资源即可。
    request.getRequestDispatcher("/test.html").forward(request, response);

  - 两个Servlet怎么共享数据?

    - 将数据放到ServletContext应用域当中,当然是可以的,但是应用域范围太大,占用资源太多。不建议使用。
    - 可以将数据放到request域当中,然后AServlet转发到BServlet,保证AServlet和BServlet在同一次请求当中,这样就可以做到两个Servlet,或者多个Servlet共享同一份数据。

  - 转发的下一个资源必须是一个Servlet吗?

    - 不一定,只要是Tomcat服务器当中的合法资源,都是可以转发的。例如:html....
    - 注意:转发的时候,路径的写法要注意,转发的路径以“/”开始,不加项目名。

  - 关于request对象中两个非常容易混淆的方法:

    - ```java
      // uri?username=zhangsan&userpwd=123&sex=1
      String username = request.getParameter("username");
      
      // 之前一定是执行过:request.setAttribute("name", new Object())
      Object obj = request.getAttribute("name");
      
      // 以上两个方法的区别是什么?
      // 第一个方法:获取的是用户在浏览器上提交的数据。
      // 第二个方法:获取的是请求域当中绑定的数据。
      ```

  - HttpServletRequest接口的其他常用方法:

    - ```java
      // 获取客户端的IP地址
      String remoteAddr = request.getRemoteAddr();
      
      // get请求在请求行上提交数据。
      // post请求在请求体中提交数据。
      // 设置请求体的字符集。(显然这个方法是处理POST请求的乱码问题。这种方式并不能解决get请求的乱码问题。)
      // Tomcat10之后,request请求体当中的字符集默认就是UTF-8,不需要设置字符集,不会出现乱码问题。
      // Tomcat9前(包括9在内),如果前端请求体提交的是中文,后端获取之后出现乱码,怎么解决这个乱码?执行以下代码。
      request.setCharacterEncoding("UTF-8");
      
      // 在Tomcat9之前(包括9),响应中文也是有乱码的,怎么解决这个响应的乱码?
      response.setContentType("text/html;charset=UTF-8");
      // 在Tomcat10之后,包括10在内,响应中文的时候就不在出现乱码问题了。以上代码就不需要设置UTF-8了。
      
      // 注意一个细节
      // 在Tomcat10包括10在内之后的版本,中文将不再出现乱码。(这也体现了中文地位的提升。)
      
    // 设置请求体的字符集
    //低于10版本的tomcat服务器,请求穿过来的数据,获取之后会乱码
    //request.setCharacterEncoding("UTF-8");

    // 获取用户提交的用户名
    String username = request.getParameter("username");

    // 输出username
    System.out.println(username);


    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.print("大家好,我是一名Java软件工程师");

      // get请求乱码问题怎么解决?
      // get请求发送的时候,数据是在请求行上提交的,不是在请求体当中提交的。
      // get请求乱码怎么解决
      // 方案:修改CATALINA_HOME/conf/server.xml配置文件
      <Connector URIEncoding="UTF-8" />这个配置不可见,但是默认就是utf-8
  外webapps 下的docs 的html可以查看
      // 注意:从Tomcat8之后,URIEncoding的默认值就是UTF-8,所以GET请求也没有乱码问题了。
          
      1、GBK是在国家标准GB2312基础上扩容后兼容GB2312的标准(好像还不是国家标准)。GBK编码专门用来解决中文编码的,是双字节的。不论中英文都是双字节的。

2、UTF8 编码是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。对于英文字符较多的论坛则用UTF-8 节省空间。另外,如果是外国人访问你的GBK网页,需要下载中文语言包支持。访问UTF-8编码的网页则不出现这问题。可以直接访问。
  
  3、GBK包含全部中文字符;UTF8则包含全世界所有国家需要用到的字符。

      // 获取应用的根路径
      String contextPath = request.getContextPath();
      
      // 获取请求方式
      String method = request.getMethod();
      
      // 获取请求的URI
      String uri = request.getRequestURI();  // /aaa/testRequest
      
      // 获取servlet path
      String servletPath = request.getServletPath(); //   /testRequest
      
      ```

使用纯Servlet做一个单表的CRUD操作

  • 使用纯粹的Servlet完成单表【对部门的】的增删改查操作。(B/S结构的。)

  • 实现步骤

    • 第一步:准备一张数据库表。(sql脚本)

      • # 部门表
        drop table if exists dept;
        create table dept(
        	deptno int primary key,
            dname varchar(255),
            loc varchar(255)
        );
        insert into dept(deptno, dname, loc) values(10, 'XiaoShouBu', 'BEIJING');
        insert into dept(deptno, dname, loc) values(20, 'YanFaBu', 'SHANGHAI');
        insert into dept(deptno, dname, loc) values(30, 'JiShuBu', 'GUANGZHOU');
        insert into dept(deptno, dname, loc) values(40, 'MeiTiBu', 'SHENZHEN');
        commit;
        select * from dept;
        
    • 第二步:准备一套HTML页面(项目原型)【前端开发工具使用HBuilder】

      • 把HTML页面准备好
      • 然后将HTML页面中的链接都能够跑通。(页面流转没问题。)
      • 应该设计哪些页面呢?
        • 欢迎页面:index.html
        • 列表页面:list.html(以列表页面为核心,展开其他操作。)
        • 新增页面:add.html
        • 修改页面:edit.html
        • 详情页面:detail.html
    • 第三步:分析我们这个系统包括哪些功能?

      • 什么叫做一个功能呢?
        • 只要 这个操作连接了数据库,就表示一个独立的功能。
      • 包括哪些功能?
        • 查看部门列表
        • 新增部门
        • 删除部门
        • 查看部门详细信息
        • 跳转到修改页面
        • 修改部门
    • 第四步:在IDEA当中搭建开发环境

      • 创建一个webapp(给这个webapp添加servlet-api.jar和jsp-api.jar到classpath当中。)

      • 向webapp中添加连接数据库的jar包(mysql驱动)

        • 必须在WEB-INF目录下新建lib目录,然后将mysql的驱动jar包拷贝到这个lib目录下。这个目录名必须叫做lib,全部小写的。
      • jar包置放在WEB-IN
        "lib"属于项目的一部分,如果jar是放在“lib”下一般就会默认引入。
        “build path”下可以从任何位置引入jar包,所以比较灵活。但是有很明显的缺点,就是移植性没有那么灵活。一般构架项目的话都倾向于放lib,这样更方便安全。
        主要的步骤才是build path!意思是,即使你的包没放在lib目录下,比如我放在桌面,那么我同样可以通过build path把桌面上的jar包通过路径引用到项目中。而我们之所以一般创建lib目录存放jar包的原因是,防止项目在其他电脑上不能运行(因为其他电脑上的桌面不一定存在我需要引用的jar包,即build path中的路径找不到对应的jar包),在项目下创建lib目录之后,那么无论工程在哪个环境下运行,都能找到该jar包。

        简而言之,就是lib目录下是跟项目绑着走的,不用担心部署缺少jar的问题,但是build path是把当前本地的jar引入项目中,在本地跑当然没问题,但是部署到其他地方的话不会缺失jar而导致项目不能正确运行。

      • JDBC的工具类

      • 将所有HTML页面拷贝到web目录下。

    • 第五步:实现第一个功能:查看部门列表

      • 我们应该怎么去实现一个功能呢?

        • 建议:你可以从后端往前端一步一步写。也可以从前端一步一步往后端写。都可以。但是千万要记住不要想起来什么写什么。你写代码的过程最好是程序的执行过程。也就是说:程序执行到哪里,你就写哪里。这样一个顺序流下来之后,基本上不会出现什么错误、意外。
      • 从哪里开始?

        • 假设从前端开始,那么一定是从用户点击按钮那里开始的。
      • 第一:先修改前端页面的超链接,因为用户先点击的就是这个超链接。

        • <a href="/oa/dept/list">查看部门列表</a>
          
      • 第二:编写web.xml文件

        • <servlet>
              <servlet-name>list</servlet-name>
            <servlet-class>com.bjpowernode.oa.web.action.DeptListServlet</servlet-class>
          </servlet>
          <servlet-mapping>
              <servlet-name>list</servlet-name>
              <!--web.xml文件中的这个路径也是以“/”开始的,但是不需要加项目名-->
              <url-pattern>/dept/list</url-pattern>
          </servlet-mapping>
          
      • 第三:编写DeptListServlet类继承HttpServlet类。然后重写doGet方法。

        • package com.bjpowernode.oa.web.action;
          
          import jakarta.servlet.ServletException;
          import jakarta.servlet.http.HttpServlet;
          import jakarta.servlet.http.HttpServletRequest;
          import jakarta.servlet.http.HttpServletResponse;
          
          import java.io.IOException;
          
          public class DeptListServlet extends HttpServlet {
            @Override
              protected void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
              }
          }
          
      • 第四:在DeptListServlet类的doGet方法中连接数据库,查询所有的部门,动态的展示部门列表页面.

        • 分析list.html页面中哪部分是固定死的,哪部分是需要动态展示的。

        • list.html页面中的内容所有的双引号要替换成单引号,因为out.print(“”)这里有一个双引号,容易冲突。

        • 现在写完这个功能之后,你会有一种感觉,感觉开发很繁琐,只使用servlet写代码太繁琐了。

        • while(rs.next()){
              String deptno = rs.getString("a");
              String dname = rs.getString("dname");
              String loc = rs.getString("loc");
          
              out.print("			<tr>");
              out.print("				<td>"+(++i)+"</td>");
              out.print("				<td>"+deptno+"</td>");
              out.print("				<td>"+dname+"</td>");
            out.print("				<td>");
              out.print("					<a href=''>删除</a>");
            out.print("					<a href='edit.html'>修改</a>");
              out.print("					<a href='detail.html'>详情</a>");
            out.print("				</td>");
              out.print("			</tr>");
          }
          
    • 第六步:查看部门详情。

      • 建议:从前端往后端一步一步实现。首先要考虑的是,用户点击的是什么?用户点击的东西在哪里?

        • 一定要先找到用户点的“详情”在哪里。找了半天,终于在后端的java程序中找到了

          • <a href='写一个路径'>详情</a>
            
          • 详情 是需要连接数据库的,所以这个超链接点击之后也是需要执行一段java代码的。所以要将这个超链接的路径修改一下。

          • 注意:修改路径之后,这个路径是需要加项目名的。“/oa/dept/detail”

        • 技巧:

          • out.print("<a href='"+contextPath+"/dept/detail?deptno="+deptno+"'>详情</a>");
            
          • 重点:向服务器提交数据的格式:uri?name=value&name=value&name=value&name=value

          • 这里的问号,必须是英文的问号。不能中文的问号。

      • 解决404的问题。写web.xml文件。

        • <servlet>
            <servlet-name>detail</servlet-name>
              <servlet-class>com.bjpowernode.oa.web.action.DeptDetailServlet</servlet-class>
          </servlet>
          <servlet-mapping>
              <servlet-name>detail</servlet-name>
              <url-pattern>/dept/detail</url-pattern>
          </servlet-mapping>
          
      • 编写一个类:DeptDetailServlet继承HttpServlet,重写doGet方法。

        • package com.bjpowernode.oa.web.action;
          
          import jakarta.servlet.ServletException;
          import jakarta.servlet.http.HttpServlet;
          import jakarta.servlet.http.HttpServletRequest;
          import jakarta.servlet.http.HttpServletResponse;
          
          import java.io.IOException;
          
          public class DeptDetailServlet extends HttpServlet {
              @Override
              protected void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  //中文思路(思路来源于:你要做什么?目标:查看部门详细信息。)
                  // 第一步:获取部门编号
                  // 第二步:根据部门编号查询数据库,获取该部门编号对应的部门信息。
                  // 第三步:将部门信息响应到浏览器上。(显示一个详情。)
              }
          }
          
      • 在doGet方法当中:连接数据库,根据部门编号查询该部门的信息。动态展示部门详情页。

    • 第七步:删除部门

      • 怎么开始?从哪里开始?从前端页面开始,用户点击删除按钮的时候,应该提示用户是否删除。因为删除这个动作是比较危险的。任何系统在进行删除操作之前,是必须要提示用户的,因为这个删除的动作有可能是用户误操作。(在前端页面上写JS代码,来提示用户是否删除。)

        • <a href="javascript:void(0)" onclick="del(30)" >删除</a>
          <script type="text/javascript">
          	function del(dno){
          		if(window.confirm("亲,删了不可恢复哦!")){
          			document.location.href = "/oa/dept/delete?deptno=" + dno;
          		}
          	}
          </script>
          
      • 以上的前端程序要写到后端的java代码当中:

        • DeptListServlet类的doGet方法当中,使用out.print()方法,将以上的前端代码输出到浏览器上。
      • 解决404的问题:

        • http://localhost:8080/oa/dept/delete?deptno=30

        • web.xml文件

          • <servlet>
                <servlet-name>delete</servlet-name>
                <servlet-class>com.bjpowernode.oa.web.action.DeptDelServlet</servlet-class>
            </servlet>
            <servlet-mapping>
                <servlet-name>delete</servlet-name>
                <url-pattern>/dept/delete</url-pattern>
            </servlet-mapping>
            
        • 编写DeptDelServlet继承HttpServlet,重写doGet方法。

        • package com.bjpowernode.oa.web.action;
          
          import jakarta.servlet.ServletException;
          import jakarta.servlet.http.HttpServlet;
          import jakarta.servlet.http.HttpServletRequest;
          import jakarta.servlet.http.HttpServletResponse;
          
          import java.io.IOException;
          
          public class DeptDelServlet extends HttpServlet {
              @Override
              protected void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  // 根据部门编号,删除部门。
                  
              }
          }
          
        • 删除成功或者失败的时候的一个处理(这里我们选择了转发,并没有使用重定向机制。)

          • // 判断删除成功了还是失败了。
            if (count == 1) {
                //删除成功
                //仍然跳转到部门列表页面
                //部门列表页面的显示需要执行另一个Servlet。怎么办?转发。
                request.getRequestDispatcher("/dept/list").forward(request, response);
            }else{
                // 删除失败
                request.getRequestDispatcher("/error.html").forward(request, response);
            }
            
    • 第八步:新增部门

      • 注意:最后保存成功之后,转发到 /dept/list 的时候,会出现405,为什么?
        • 第一:保存用的是post请求。底层要执行doPost方法。
        • 第二:转发是一次请求,之前是post,之后还是post,因为它是一次请求。
        • 第三:/dept/list Servlet当中只有一个doGet方法。
        • 怎么解决?两种方案
          • 第一种:在/dept/list Servlet中添加doPost方法,然后在doPost方法中调用doGet。
          • 第二种:重定向。
    • 第九步:跳转到修改部门的页面

    • 第十步:修改部门

jar包置放在WEB-IN
"lib"属于项目的一部分,如果jar是放在“lib”下一般就会默认引入。
“build path”下可以从任何位置引入jar包,所以比较灵活。但是有很明显的缺点,就是移植性没有那么灵活。
一般构架项目的话都倾向于放lib,这样更方便安全。
主要的步骤才是build path!意思是,即使你的包没放在lib目录下,比如我放在桌面,那么我同样可以通过build path把桌面上的jar
包通过路径引用到项目中。而我们之所以一般创建lib目录存放jar包的原因是,防止项目在其他电脑上不能运行
(因为其他电脑上的桌面不一定存在我需要引用的jar包,即build path中的路径找不到对应的jar包),在项目下创建lib目录之后,
那么无论工程在哪个环境下运行,都能找到该jar包。

简而言之,就是lib目录下是跟项目绑着走的,不用担心部署缺少jar的问题,但是build path是把当前本地的jar引入项目中,
在本地跑当然没问题,但是部署到其他地方的话不会缺失jar而导致项目不能正确运行。
我们需要将servlet.jar添加路径中,因为编译的时候我们就需要用到,而mysqljar是运行的时候需要用到的,在lib程序可以找到。
lib是servlet对象去管理的。是tomcat是启动了tomcat程序之后管理的。而要启动tomcatservlet是必须的,启动了之后lib下放
servlet包就没有了意义。

!Lin571273545

在一个web应用中应该如何完成资源的跳转

  • 在一个web应用中通过两种方式,可以完成资源的跳转:

    • 第一种方式:转发
    • 第二种方式:重定向
  • 转发和重定向有什么区别?

    • 代码上有什么区别?

      • 转发

        • // 获取请求转发器对象
          RequestDispatcher dispatcher = request.getRequestDispatcher("/dept/list");
          // 调用请求转发器对象的forward方法完成转发
          dispatcher.forward(request, response);
          
          // 合并一行代码
          request.getRequestDispatcher("/dept/list").forward(request, response);
          // 转发的时候是一次请求,不管你转发了多少次。都是一次请求。
          // AServlet转发到BServlet,再转发到CServlet,再转发到DServlet,不管转发了多少次,都在同一个request当中。
          // 这是因为调用forward方法的时候,会将当前的request和response对象传递给下一个Servlet。
          
      • 重定向

        • // 注意:路径上要加一个项目名。为什么?
          // 浏览器发送请求,请求路径上是需要添加项目名的。
          // 以下这一行代码会将请求路径“/oa/dept/list”发送给浏览器
          // 浏览器会自发的向服务器发送一次全新的请求:/oa/dept/list
          response.sendRedirect("/oa/dept/list");
          

          // 重定向(重新定方向)
          // 重定向时的路径当中需要以项目名开始,或者说需要添加项目名。
          // response对象将这个路径:"/servlet10/b"响应给浏览器了。
          // 浏览器又自发的向服务器发送了一次全新的请求:http://localhost:8080/servlet10/b
          // 所以浏览器一共发送了两次请求:
          // 第一次请求:http://localhost:8080/servlet10/a
          // 第二次请求:http://localhost:8080/servlet10/b
          // 最终浏览器地址栏上显示的地址当然是最后那一次请求的地址。所以重定向会导致浏览器地址栏上的地址发生改变。

    • 形式上有什么区别?

      • 转发(一次请求)
        • 在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终请求结束之后,浏览器地址栏上的地址还是这个。没变。
      • 重定向(两次请求)
        • 在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终在浏览器地址栏上显示的地址是:http://localhost:8080/servlet10/b
    • 转发和重定向的本质区别?

      • 转发:是由WEB服务器来控制的。A资源跳转到B资源,这个跳转动作是Tomcat服务器内部完成的。
      • 重定向:是浏览器完成的。具体跳转到哪个资源,是浏览器说了算。
    • 使用一个例子去描述这个转发和重定向

      • 借钱(转发:发送了一次请求)
        • 杜老师没钱了,找张三借钱,其实张三没有钱,但是张三够义气,张三自己找李四借了钱,然后张三把这个钱给了杜老师,杜老师不知道这个钱是李四的,杜老师只求了一个人。杜老师以为这个钱就是张三的。
      • 借钱(重定向:发送了两次请求)
        • 杜老师没钱了,找张三借钱,张三没有钱,张三有一个好哥们,叫李四,李四是个富二代,于是张三将李四的家庭住址告诉了杜老师,杜老师按照这个地址去找到李四,然后从李四那里借了钱。显然杜老师在这个过程中,求了两个人。并且杜老师知道最终这个钱是李四借给俺的。
  • 转发和重定向应该如何选择?什么时候使用转发,什么时候使用重定向?

    • 如果在上一个Servlet当中向request域当中绑定了数据,希望从下一个Servlet当中把request域里面的数据取出来,使用转发机制。
    • 剩下所有的请求均使用重定向。(重定向使用较多。)
  • 跳转的下一个资源有没有要求呢?必须是一个Servlet吗?

    • 不一定,跳转的资源只要是服务器内部合法的资源即可。包括:Servlet、JSP、HTML…
  • 转发会存在浏览器的刷新问题。

  • 删除之后,重定向

  • 修改之后,重定向

  • 保存之后,重定向

  • 重定向:

    • 成功
    • 失败

**

    1. 一个普通的javabean
    1. 什么是javabean?
  • java是咖啡。
  • bean是豆子。
  • javabean:咖啡豆。
  • 咖啡是由咖啡豆研磨而成。寓意是Java程序是由一个一个的Javabean组成的。
    1. 一个JavaBean一般是有规范的:
  •  有无参数的构造方法
    
  •  属性私有化
    
  •  对外提供setter和getter方法
    
  •  重写toString()
    
  •  重写hashCode + equals
    
  •  实现java.io.Serializable接口。
    

*/

Servlet注解,简化配置

  • 分析oa项目中的web.xml文件

    • 现在只是一个单标的CRUD,没有复杂的业务逻辑,很简单的一丢丢功能。web.xml文件中就有如此多的配置信息。如果采用这种方式,对于一个大的项目来说,这样的话web.xml文件会非常庞大,有可能最终会达到几十兆。
    • 在web.xml文件中进行servlet信息的配置,显然开发效率比较低,每一个都需要配置一下。
    • 而且在web.xml文件中的配置是很少被修改的,所以这种配置信息能不能直接写到java类当中呢?可以的。
  • Servlet3.0版本之后,推出了各种Servlet基于注解式开发。优点是什么?

    • 开发效率高,不需要编写大量的配置信息。直接在java类上使用注解进行标注。
    • web.xml文件体积变小了。
  • 并不是说注解有了之后,web.xml文件就不需要了:

    • 有一些需要变化的信息,还是要配置到web.xml文件中。一般都是 注解+配置文件 的开发模式。
    • 一些不会经常变化修改的配置建议使用注解。一些可能会被修改的建议写到配置文件中。
  • 我们的第一个注解:

    • jakarta.servlet.annotation.WebServlet
      
    • 在Servlet类上使用:@WebServlet,WebServlet注解中有哪些属性呢?

      • name属性:用来指定Servlet的名字。等同于: 这个name属性在web是用来关联指定的url,如果不知道默认是类的全限定名称
      • urlPatterns属性:用来指定Servlet的映射路径。可以指定多个字符串。,这个不可以省略
      • loadOnStartUp属性:用来指定在服务器启动阶段是否加载该Servlet。等同于:
      • value属性:当注解的属性名是value的时候,使用注解的时候,value属性名是可以省略的。
      • 注意:不是必须将所有属性都写上,只需要提供需要的。(需要什么用什么。)
      • 注意:属性是一个数组,如果数组中只有一个元素,使用该注解的时候,属性值的大括号可以省略。
  • 注解对象的使用格式:

    • @注解名称(属性名=属性值, 属性名=属性值, 属性名=属性值…)
      @WebServlet(name = “hello”,
      urlPatterns = {“/hello1”, “/hello2”, “/hello3”},
      //loadOnStartup = 1,
      initParams = {@WebInitParam(name=“username”, value=“root”), @WebInitParam(name=“password”, value=“123”)})
      public class HelloServlet extends HttpServlet {

      // 无参数构造方法

      public HelloServlet() {
      System.out.println(“无参数构造方法执行,HelloServlet加载完成”);
      }

      /@WebServlet
      private String name;
      /

      @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
      response.setContentType(“text/html;charset=UTF-8”);
      PrintWriter out = response.getWriter();
      // 获取Servlet Name
      String servletName = getServletName();
      out.print("servlet name = " + servletName + “
      ”);

      // 获取servlet path
      String servletPath = request.getServletPath();
      out.print("servlet path = " + servletPath + "<br>");
      
      // 获取初始化参数
      Enumeration<String> names = getInitParameterNames();
      

      //以上方法实际上还是调用了ServletConfig的方法
      // public Enumeration getInitParameterNames() {
      // return getServletConfig().getInitParameterNames();
      // }

      while (names.hasMoreElements()) {
          String name = names.nextElement();
          String value = getInitParameter(name);
          out.print(name + "=" + value + "<br>");
      }
      

      }
      }
      servlet name = hello
      servlet path = /hello1
      password=123
      username=root

没有指定name属性时:
servlet name = com.bjpowernode.javaweb.servlet.HelloServlet
默认是这个类的全限定名称
//@WebServlet(urlPatterns = {“/welcome1”, “/welcome2”})
// 注意:当注解的属性是一个数组,并且数组中只有一个元素,大括号可以省略。
//@WebServlet(urlPatterns = “/welcome”)
// 这个value属性和urlPatterns属性一致,都是用来指定Servlet的映射路径的。
//@WebServlet(value = {“/welcome1”, “/welcome2”})
// 如果注解的属性名是value的话,属性名也是可以省略的。
//@WebServlet(value = “/welcome1”)
//@WebServlet({“/wel”, “/abc”, “/def”})
@WebServlet(“/wel”)
public class WelcomeServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.print("欢迎学习Servlet。");
}

}
// 使用反射机制将类上面的注解进行解析。
// 获取类Class对象
Class<?> welcomeServletClass = Class.forName(“com.bjpowernode.javaweb.servlet.WelcomeServlet”);

    // 获取这个类上面的注解对象
    // 先判断这个类上面有没有这个注解对象,如果有这个注解对象,就获取该注解对象。
    //boolean annotationPresent = welcomeServletClass.isAnnotationPresent(WebServlet.class);
    //System.out.println(annotationPresent);
    if (welcomeServletClass.isAnnotationPresent(WebServlet.class)) {
        // 获取这个类上面的注解对象
        WebServlet webServletAnnotation = welcomeServletClass.getAnnotation(WebServlet.class);
        // 获取注解的value属性值。
        String[] value = webServletAnnotation.value();
        for (int i = 0; i < value.length; i++) {
            System.out.println(value[i]);
        }
    }

使用模板方法设计模式优化oa项目

  • 上面的注解解决了配置文件的问题。但是现在的oa项目仍然存在一个比较臃肿的问题。
    • 一个单标的CRUD,就写了6个Servlet。如果一个复杂的业务系统,这种开发方式,显然会导致类爆炸。(类的数量太大。)
    • 怎么解决这个类爆炸问题?可以使用模板方法设计模式。
  • 怎么解决类爆炸问题?
    • 以前的设计是一个请求一个Servlet类。1000个请求对应1000个Servlet类。导致类爆炸。
    • 可以这样做:一个请求对应一个方法。一个业务对应一个Servlet类。
    • 处理部门相关业务的对应一个DeptServlet。处理用户相关业务的对应一个UserServlet。处理银行卡卡片业务对应一个CardServlet。

分析使用纯粹Servlet开发web应用的缺陷

  • 在Servlet当中编写HTML/CSS/JavaScript等前端代码。存在什么问题?
    • java程序中编写前端代码,编写难度大。麻烦。
    • java程序中编写前端代码,显然程序的耦合度非常高。
    • java程序中编写前端代码,代码非常不美观。
    • java程序中编写前端代码,维护成本太高。(非常难于维护)
      • 修改小小的一个前端代码,只要有改动,就需要重新编译java代码,生成新的class文件,打一个新的war包,重新发布。
  • 思考一下,如果是你的话,你准备怎么解决这个问题?
    • 思路很重要。使用什么样的思路去做、去解决这个问题
      • 上面的那个Servlet(Java程序)能不能不写了,让机器自动生成。我们程序员只需要写这个Servlet程序中的“前端的那段代码”,然后让机器将我们写的“前端代码”自动翻译生成“Servlet这种java程序”
        。然后机器再自动将“java”程序编译生成"class"文件。然后再使用JVM调用这个class中的方法。

JSP

解决idea中jsp使用内置对象标红的问题
使用session的方法会标红报错,session所在的包已经导入 不是jar包的问题,网上的方法大部分都是导入jar包 其实这不是问题所在

本人本来使用的是JDK8+tomcat10

tomcat 10中提供的severlet api 与jdk 8不匹配 下载tomcat9 导入tomcat9中的jar包即可
换了之后需要清除缓存并重启。

  • 我的第一个JSP程序:

    • 在WEB-INF目录之外创建一个index.jsp文件,然后这个文件中没有任何内容。
      jsp.java源码
      public void _jspService(final jakarta.servlet.http.HttpServletRequest request, final jakarta.servlet.http.HttpServletResponse response)
      throws java.io.IOException, jakarta.servlet.ServletException {

      if (!jakarta.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      final java.lang.String _jspx_method = request.getMethod();
      if (“OPTIONS”.equals(_jspx_method)) {
      response.setHeader(“Allow”,“GET, HEAD, POST, OPTIONS”);
      return;
      }
      if (!“GET”.equals(_jspx_method) && !“POST”.equals(_jspx_method) && !“HEAD”.equals(_jspx_method)) {
      response.setHeader(“Allow”,“GET, HEAD, POST, OPTIONS”);
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, “JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS”);
      return;
      }
      }

      final jakarta.servlet.jsp.PageContext pageContext;
      jakarta.servlet.http.HttpSession session = null;
      final jakarta.servlet.ServletContext application;
      final jakarta.servlet.ServletConfig config;
      jakarta.servlet.jsp.JspWriter out = null;
      final java.lang.Object page = this;
      jakarta.servlet.jsp.JspWriter _jspx_out = null;
      jakarta.servlet.jsp.PageContext _jspx_page_context = null;

  • 将上面的项目部署之后,启动服务器,打开浏览器,访问以下地址:

    • http://localhost:8080/jsp/index.jsp 展现在大家面前的是一个空白。

    • 实际上访问以上的这个:index.jsp,底层执行的是:index_jsp.class 这个java程序。
      D:\tomcat10\apache-tomcat-10.0.12\work\Catalina\localhost\jsp\org\apache\jsp

    • 这个index.jsp会被tomcat翻译生成index_jsp.java文件,然后tomcat服务器又会将index_jsp.java编译生成index_jsp.class文件

    • 访问index.jsp,实际上执行的是index_jsp.class中的方法。

  • JSP实际上就是一个Servlet。

    • index.jsp访问的时候,会自动翻译生成index_jsp.java,会自动编译生成index_jsp.class,那么index_jsp 这就是一个类。
    • index_jsp 类继承 HttpJspBase,而HttpJspBase类继承的是HttpServlet。所以index_jsp类就是一个Servlet类。
    • jsp的生命周期和Servlet的生命周期完全相同。完全就是一个东西。没有任何区别。
    • jsp和servlet一样,都是单例的。(假单例。)
  • jsp文件第一次访问的时候是比较慢的,为什么?

    • 为什么大部分的运维人员在给客户演示项目的时候,为什么提前先把所有的jsp文件先访问一遍。
    • 第一次比较麻烦:
      • 要把jsp文件翻译生成java源文件
      • java源文件要编译生成class字节码文件
      • 然后通过class去创建servlet对象
      • 然后调用servlet对象的init方法
      • 最后调用servlet对象的service方法。
    • 第二次就比较快了,为什么?
      • 因为第二次直接调用单例servlet对象的service方法即可。
  • JSP是什么?

    • JSP是java程序。(JSP本质还是一个Servlet)
    • JSP是:JavaServer Pages的缩写。(基于Java语言实现的服务器端的页面。)
    • Servlet是JavaEE的13个子规范之一,那么JSP也是JavaEE的13个子规范之一。
    • JSP是一套规范。所有的web容器/web服务器都是遵循这套规范的,都是按照这套规范进行的“翻译”
    • 每一个web容器/web服务器都会内置一个JSP翻译引擎。
  • 对JSP进行错误调试的时候,还是要直接打开JSP文件对应的java文件,检查java代码。

  • 开发JSP的最高境界:

    • 眼前是JSP代码,但是脑袋中呈现的是java代码。
  • JSP既然本质上是一个Servlet,那么JSP和Servlet到底有什么区别呢?

    • 职责不同:
      • Servlet的职责是什么:收集数据。(Servlet的强项是逻辑处理,业务处理,然后链接数据库,获取/收集数据。)
      • JSP的职责是什么:展示数据。(JSP的强项是做数据的展示)
  • JSP的基础语法

    • 在jsp文件中直接编写文字,都会自动被翻译到哪里?

      • 翻译到servlet类的service方法的out.write(“翻译到这里”),直接翻译到双引号里,被java程序当做普通字符串打印输出到浏览器。
      • 在JSP中编写的HTML CSS JS代码,这些代码对于JSP来说只是一个普通的字符串。但是JSP把这个普通的字符串一旦输出到浏览器,浏览器就会对HTML CSS JS进行解释执行。展现一个效果。
    • JSP的page指令(这个指令后面再详细说,这里先解决一下中文乱码问题),解决响应时的中文乱码问题:

      • 通过page指令来设置响应的内容类型,在内容类型的最后面添加:charset=UTF-8
        • <%@page contentType=“text/html;charset=UTF-8”%>,表示响应的内容类型是text/html,采用的字符集UTF-8
        • <%@page import=“java.util.List,java.util.ArrayList”%>
    • 怎么在JSP中编写Java程序:

      • <% java语句; %>
        • 在这个符号当中编写的被视为java程序,被翻译到Servlet类的service方法内部。
        • 这里你要细心点,你要思考,在<% %>这个符号里面写java代码的时候,你要时时刻刻的记住你正在“方法体”当中写代码,方法体中可以写什么,不可以写什么,你心里是否明白呢?
        • 在service方法当中编写的代码是有顺序的,方法体当中的代码要遵循自上而下的顺序依次逐行执行。
        • service方法当中不能写静态代码块,不能写方法,不能定义成员变量。。。。。。
        • 在同一个JSP当中 <%%> 这个符号可以出现多个。
      • <%! %>
        • 在这个符号当中编写的java程序会自动翻译到service方法之外。
        • 这个语法很少用,为什么?不建议使用,因为在service方法外面写静态变量和实例变量,都会存在线程安全问题,因为JSP就是servlet,servlet是单例的,多线程并发的环境下,这个静态变量和实例变量一旦有修改操作,必然会存在线程安全问题。
      • JSP的输出语句
        • 怎么向浏览器上输出一个java变量。
        • <% String name = “jack”; out.write("name = " + name); %>
        • 注意:以上代码中的out是JSP的九大内置对象之一。可以直接拿来用。当然,必须只能在service方法内部使用。
        • 如果向浏览器上输出的内容中没有“java代码”,例如输出的字符串是一个固定的字符串,可以直接在jsp中编写,不需要写到<%%> 这里。
        • 如果输出的内容中含有“java代码”,这个时候可以使用以下语法格式:
          • <%= %> 注意:在=的后面编写要输出的内容。
          • <%= %> 这个符号会被翻译到哪里?最终翻译成什么?
            • 翻译成了这个java代码: out.print();
            • 翻译到service方法当中了。
          • 什么时候使用<%=%> 输出呢?输出的内容中含有java的变量,输出的内容是一个动态的内容,不是一个死的字符串。
            如果输出的是一个固定的字符串,直接在JSP文件中编写即可。
            ========================================================
            打印流和输出流的区别, print不支持public void write(char[] buf, int off, int len)这种方法。 不能输出数据的一部分,write可以
            由于前后端传递值的时候会通过流的方式进行传递,这就不得不涉及到这方面的知识了

PrintWrite out=response.getWrite;

而流输出的时候有两种方法

out.write()和out.print()

out.write()是字节输出流的方法
out.print()是字符输出流的方法
一、区别
public abstract class JspWriter
extends java.io.Writer
abstract void print​(char c)
Print a character.
abstract void println​(int x)
Print an integer and then terminate the line.
abstract void println​(java.lang.String x)
Print a String and then terminate the line.

java.io
Class PrintWriter
java.lang.Object
java.io.Writer
java.io.PrintWriter

void print(char c)
打印一个字符。
print(String s)
打印一个字符串。

void write(char[] buf)
void write(String s)
写一个字符串。

print方法是子类JspWriter,write是Writer类中定义的方法;
其实就是说print是jspwrite里面的方法,writer是jspwrite父类java.io/writer里面的方法。

Methods inherited from class java.io.Writer
append, append, append, nullWriter, write, write, write, write, write

write():仅支持输出字符类型数据,字符、字符数组、字符串等
print():可以将各种类型(包括Object)的数据通过默认编码转换成bytes字节形式,这些字节都通过write(int c)方法被输出
JspWriter类型的out对象使用print方法和write方法都可以输出字符串,但是,如果字符串对象的值为null时,
print方法将输出内容为“null”的字符串,而write方法则是抛出NullPointerException异常。
因此传输数据时,write,print都可以使用
java.io
Class Writer
java.lang.Object
java.io.Writer

1.PrintWriter可以直接调用write()或print()方法,把字符串作为参数写入,这样就可以写入json格式的数据了。如:
通过这种方式,客户端就可以接受到数据了。客户端读取数据有多种方式,可以通过ajax读,也可以通过GetPostUtil来读取返回的数据。
2.print方法和write方法是有区别的,最大的区别就是上述提到的,print可以写入对象,而write不行。
write只能是字符和字符串

3.print和write都可以写入html代码,来进行页面的跳转,并在一段时间后跳回到原来的页面,以此来达到提醒的作用。
4.PrintWriter不能PrintWriter out = new PrintWriter(),因为这样,out不能找到输出的对象,导致输出失败。

5.out.flush()表示强制将缓冲区中的数据发送出去,不必等到缓冲区满。所以一般先flush()再close(),否则容易导致数据丢失

  • 在JSP中如何编写JSP的专业注释

    • <%–JSP的专业注释,不会被翻译到java源代码当中。–%>
  • JSP基础语法总结:

    • JSP中直接编写普通字符串
      • 翻译到service方法的out.write(“这里”)
    • <%%>
      • 翻译到service方法体内部,里面是一条一条的java语句。
    • <%! %>
      • 翻译到service方法之外。
    • <%= %>
      • 翻译到service方法体内部,翻译为:out.print();
    • <%@page contentType=“text/html;charset=UTF-8”%>
      • page指令,通过contentType属性用来设置响应的内容类型。
  • 使用Servlet + JSP完成oa项目的改造。

    • 使用Servlet处理业务,收集数据。 使用JSP展示数据。

    • 将之前原型中的html文件,全部修改为jsp,然后在jsp文件头部添加page指令(指定contentType防止中文乱码),将所有的JSP直接拷贝到web目录下。

    • 完成所有页面的正常流转。(页面仍然能够正常的跳转。修改超链接的请求路径。)

      • <%=request.getContextPath() %> 在JSP中动态的获取应用的根路径。
    • Servlet中连接数据库,查询所有的部门,遍历结果集。

      • 遍历结果集的过程中,取出部门编号、部门名、位置等信息,封装成java对象。
      • 将java对象存放到List集合中。
      • 将List集合存储到request域当中。
      • 转发forward到jsp。
    • 在JSP中:

      • 从request域当中取出List集合。
      • 遍历List集合,取出每个部门对象。动态生成tr。
    • 思考一个问题:如果我只用JSP这一个技术,能不能开发web应用?

      • 当然可以使用JSP来完成所有的功能。因为JSP就是Servlet,在JSP的<%%>里面写的代码就是在service方法当中的,所以在<%%>当中完全可以编写JDBC代码,连接数据库,查询数据,也可以在这个方法当中编写业务逻辑代码,处理业务,都是可以的,所以使用单独的JSP开发web应用完全没问题。
      • 虽然JSP一个技术就可以完成web应用,但是不建议,还是建议采用servlet + jsp的方式进行开发。这样都能将各自的优点发挥出来。JSP就是做数据展示。Servlet就是做数据的收集。(JSP中编写的Java代码越少越好。)一定要职责分明。
    • JSP文件的扩展名必须是xxx.jsp吗?

      • jsp文件的扩展名是可以配置的。不是固定的。

      • 在CATALINA_HOME/conf/web.xml,在这个文件当中配置jsp文件的扩展名。

      • <servlet-mapping>
            <servlet-name>jsp</servlet-name>
            <url-pattern>*.jsp</url-pattern>
            <url-pattern>*.jspx</url-pattern>
        </servlet-mapping>
        
      • xxx.jsp文件对于小猫咪来说,只是一个普通的文本文件,web容器会将xxx.jsp文件最终生成java程序,最终调用的是java对象相关的方法,真正执行的时候,和jsp文件就没有关系了。

      • 小窍门:JSP如果看不懂,建议把jsp翻译成java代码,就能看懂了。

    • 同学问:包名bean是什么意思?

      • javabean(java的logo是一杯冒着热气的咖啡。javabean被翻译为:咖啡豆)
      • java是一杯咖啡,咖啡又是由一粒一粒的咖啡豆研磨而成。
      • 整个java程序中有很多bean的存在。由很多bean组成。
      • 什么是javabean?实际上javabean你可以理解为符合某种规范的java类,比如:
        • 有无参数构造方法
        • 属性私有化
        • 对外提供公开的set和get方法
        • 实现java.io.Serializable接口
        • 重写toString
        • 重写hashCode+equals
      • javabean其实就是java中的实体类。负责数据的封装。
      • 由于javabean符合javabean规范,具有更强的通用性。
    • 完成剩下所有功能的改造。

  • 当前的oa应用存在的问题:

    • 任何一个用户都可以访问这个系统,都可以对这个系统当中的数据进行增删改这些危险的操作。我只想让合法的用户去使用这个系统,不合法的用户不能访问这个系统,怎么办?
      • 加一个登录功能。登录成功的可以访问该系统,登录失败不能访问。
    • 实现登录功能:
      • 步骤1:数据库当中添加一个用户表:t_user
        • t_user表当中存储的是用户的登录信息,最基本的也包括:登录的用户名和登录的密码。
        • 密码一般在数据库表当中存储的是密文。一般不以明文的形式存储。(这里先使用明文方式。)
        • 向t_user表中插入数据。
      • 步骤2:再实现一个登录页面。
        • 登录页面上应该有一个登录的表单。有用户名和密码输入的框。
        • 用户点击登录,提交表单,提交用户名和密码。form是post方式提交。
      • 步骤3:后台要有一个对应的Servlet来处理登录的请求。
        • 登录成功:跳转到部门列表页面。
        • 登录失败:跳转到失败的页面。
      • 步骤4:再提供一个登录失败的页面。
  • 登录功能实现了,目前存在的最大的问题:

    • 这个登录功能目前只是一个摆设,没有任何作用。只要用户知道后端的请求路径,照样可以在不登录的情况下访问。
    • 这个登录没有真正起到拦截的作用。怎么解决?
  • JSP的指令

    • 指令的作用:指导JSP的翻译引擎如何工作(指导当前的JSP翻译引擎如何翻译JSP文件。)

    • 指令包括哪些呢?

      • include指令:包含指令,在JSP中完成静态包含,很少用了。(这里不讲)
      • taglib指令:引入标签库的指令。这个到JJSTL标签库的时候再学习。现在先不管。
      • page指令:目前重点学习一个page指令。
    • 指令的使用语法是什么?

      • <%@指令名 属性名=属性值 属性名=属性值 属性名=属性值…%>
    • 关于page指令当中都有哪些常用的属性呢?

      • <%@page session="true|false" %>
        true表示启用JSP的内置对象session,表示一定启动session对象。没有session对象会创建。
        如果没有设置,默认值就是session="true"
        session="false" 表示不启动内置对象session。当前JSP页面中无法使用内置对象session。
        
      • <%@page contentType="text/json" %>
        contentType属性用来设置响应的内容类型
        但同时也可以设置字符集。
        <%@page contentType="text/json;charset=UTF-8" %>
        
      • <%@page pageEncoding="UTF-8" %>
        pageEncoding="UTF-8" 表示设置响应时采用的字符集。
        
      • <%@page import="java.util.List, java.util.Date, java.util.ArrayList" %>
        <%@page import="java.util.*" %>
        import语句,导包。
        
      • <%@page errorPage="/error.jsp" %>
        当前页面出现异常之后,跳转到error.jsp页面。
        errorPage属性用来指定出错之后的跳转位置。
        
      • <%@page isErrorPage="true" %>
        表示启用JSP九大内置对象之一:exception
        默认值是false。
        

<%–在错误页面可以启用JSP九大内置对象之:exception–%>
<%–exception内置对象就是刚刚发生的异常对象。–%>
<%@page isErrorPage=“true” %>
<%–打印异常堆栈信息,输出到后台控制台。exception是九大内置对象之一。–%>
<%
exception.printStackTrace();
%>

  • JSP的九大内置对象

    • jakarta.servlet.jsp.PageContext pageContext 页面作用域

    • jakarta.servlet.http.HttpServletRequest request 请求作用域

    • jakarta.servlet.http.HttpSession session 会话作用域

    • jakarta.servlet.ServletContext application 应用作用域 Servetcontext全局作用域,关闭服务器才消失尽量少用

      • pageContext < request < session < application
      • 以上四个作用域都有:setAttribute、getAttribute、removeAttribute方法。
      • 以上作用域的使用原则:尽可能使用小的域。
    • java.lang.Throwable exception

    • jakarta.servlet.ServletConfig config

    • java.lang.Object page (其实是this,当前的servlet对象)

    • jakarta.servlet.jsp.JspWriter out (负责输出)

    • jakarta.servlet.http.HttpServletResponse response (负责响应)
      +++++++++++++++++++++++++++++++++++++++++

关于B/S结构系统的会话机制(session机制)

  • 什么是会话?import jakarta.servlet.http.HttpSession;这个类

    • 会话对应的英语单词:session

    • 用户打开浏览器,进行一系列操作,然后最终将浏览器关闭,这个整个过程叫做:一次会话。会话在服务器端也有一个对应的java对象,这个java对象叫做:session。

    • 什么是一次请求:用户在浏览器上点击了一下,然后到页面停下来,可以粗略认为是一次请求。请求对应的服务器端的java对象是:request。

    • 一个会话当中包含多次请求。(一次会话对应N次请求。)
      // request和session都是服务器端的java对象。都在JVM当中。
      // request对象代表了一次请求。(一次请求对应一个request对象。两次请求就会对应两个不同的request对象。)
      // session对象代表了一次会话。(一次会话对应一个session对象。)
      // 获取session对象
      // 从WEB服务器当中获取session对象,如果session对象没有,则新建。
      HttpSession session = request.getSession();
      //session销毁session.invalidate();
      String id = session.getId();
      long creationTime = session.getCreationTime();
      long lastAccessedTime = session.getLastAccessedTime();//Returns the last time the client sent a request associated with this session, as the number of milliseconds since midnight January 1, 1970 GMT, and marked by the time the container received the request.
      // 返回客户端最后一次发送与此会话相关联的请求的时间,以自1970年1月1日GMT午夜以来的毫秒数表示,并以容器接收请求的时间标记。
      Date date = new Date();
      SimpleDateFormat simpleDateFormat = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
      String format = simpleDateFormat.format(lastAccessedTime);
      int maxInactiveInterval = session.getMaxInactiveInterval();//返回servlet容器在客户端访问之间保持会话打开的最大时间间隔(秒)。
      // 向会话域当中绑定数据。
      // session.setAttribute();
      // 从会话域当中取数据。
      // Object obj = session.getAttribute()

      // 将session对象响应到浏览器。
      response.setContentType("text/html;charset=UTF-8");
      PrintWriter out = response.getWriter();
      out.print("会话对象:" + session); // 想看看对象的内存地址。会话对象:org.apache.catalina.session.StandardSessionFacade@480347c6
      

    第一次请求的时候服务器会发送一个sessionid和服务器的根路径保存在cookie中,Set-Cookie: JSESSIONID=E91D4FF3B24EA901DB6CFE96BA7FA879; Path=/session; HttpOnly
    第二次发送请求的时候浏览器会根据跟路径匹配cookie中对应session,如果找到了。就将cokkie中的session发送给服务器Cookie: JSESSIONID=E91D4FF3B24EA901DB6CFE96BA7FA879;
    Idea-5149ad49=ab375610-4505-4754-807f-d327a8938544。
    总而言之就是服务端有session,是在jvm中的对象,这个对象在第一次请求的时候服务器会将sessionid,path发送给浏览器,
    浏览器会通过cookie的方式保存在浏览器或者内存中,
    第二次请求的时候浏览器会将cookie中的sessionid发送给服务器,服务器可以通过这个id查找保存在jvm的session对象信息。
    如果浏览器关闭,保存在cookie中的sessionid会清除,但是如果不是保存在浏览器而是在内存中这个sessionid是不会消失的。
    浏览器关闭不代表服务器端的session消失了,服务器端的session的失效时间

  • 在java的servlet规范当中,session对应的类名:HttpSession(jarkata.servlet.http.HttpSession)

  • session机制属于B/S结构的一部分。如果使用php语言开发WEB项目,同样也是有session这种机制的。session机制实际上是一个规范。然后不同的语言对这种会话机制都有实现。

  • session对象最主要的作用是:保存会话状态。(用户登录成功了,这是一种登录成功的状态,你怎么把登录成功的状态一直保存下来呢?使用session对象可以保留会话状态。)

  • 为什么需要session对象来保存会话状态呢?

    • 因为HTTP协议是一种无状态协议。
    • 什么是无状态:请求的时候,B和S是连接的,但是请求结束之后,连接就断了。为什么要这么做?
      HTTP协议为什么要设计成这样?因为这样的无状态协议,可以降低服务器的压力。请求的瞬间是连接的,
      请求结束之后,连接断开,这样服务器压力小。
    • 只要B和S断开了,那么关闭浏览器这个动作,服务器知道吗?
      • 不知道。服务器是不知道浏览器关闭的。
  • 张三打开一个浏览器A,李四打开一个浏览器B,访问服务器之后,在服务器端会生成:

    • 张三专属的session对象
    • 李四专属的session对象
  • 为什么不使用request对象保存会话状态?为什么不使用ServletContext对象保存会话状态?

    • request.setAttribute()存,request.getAttribute()取,ServletContext也有这个方法。request是请求域。ServletContext是应用域。
    • request是一次请求一个对象。
    • ServletContext对象是服务器启动的时候创建,服务器关闭的时候销毁,这个ServletContext对象只有一个。
    • ServletContext对象的域太大。
    • request请求域(HttpServletRequest)、session会话域(HttpSession)、application域(ServletContext)
    • request < session < application
  • 思考一下:session对象的实现原理。

    • HttpSession session = request.getSession();
    • 这行代码很神奇。张三访问的时候获取的session对象就是张三的。李四访问的时候获取的session对象就是李四的。
  • session的实现原理:

    • JSESSIONID=xxxxxx 这个是以Cookie的形式保存在浏览器的内存中的。浏览器只要关闭。这个cookie就没有了。
    • session列表是一个Map,map的key是sessionid,map的value是session对象。
    • 用户第一次请求,服务器生成session对象,同时生成id,将id发送给浏览器。
    • 用户第二次请求,自动将浏览器内存中的id发送给服务器,服务器根据id查找session对象。
    • 关闭浏览器,内存消失,cookie消失,sessionid消失,会话等同于结束。
    • 访问jsp不生成session
  • <%@page session="false" %>
    
  • Cookie禁用了,session还能找到吗?

    • cookie禁用是什么意思?服务器正常发送cookie给浏览器,但是浏览器不要了。拒收了。并不是服务器不发了。
    • 找不到了。每一次请求都会获取到新的session对象。
    • cookie禁用了,session机制还能实现吗?
      • 可以。需要使用URL重写机制。
      • http://localhost:8080/servlet12/test/session;jsessionid=19D1C99560DCBF84839FA43D58F56E16
      • URL重写机制会提高开发者的成本。开发人员在编写任何请求路径的时候,后面都要添加一个sessionid,给开发带来了很大的难度,很大的成本。所以大部分的网站都是这样设计的:你要是禁用cookie,你就别用了。
    30

在tomcat的web.xml中有配置

  • 总结一下到目前位置我们所了解的域对象:

    • request(对应的类名:HttpServletRequest)
      • 请求域(请求级别的)
    • session(对应的类名:HttpSession)
      • 会话域(用户级别的)
    • application(对应的类名:ServletContext)
      • 应用域(项目级别的,所有用户共享的。)
    • 这三个域对象的大小关系
      • request < session < application
    • 他们三个域对象都有以下三个公共的方法:
      • setAttribute(向域当中绑定数据)
      • getAttribute(从域当中获取数据)
      • removeAttribute(删除域当中的数据)
    • 使用原则:尽量使用小的域。
  • session掌握之后,我们怎么解决oa项目中的登录问题,怎么能让登录起作用。

    • 登录成功之后,可以将用户的登录信息存储到session当中。也就是说session中如果有用户的信息就代表用户登录成功了。session中没有用户信息,表示用户没有登录过。则跳转到登录页面。
  • 销毁session对象:

    • session.invalidate();
      

Cookie

  • session的实现原理中,每一个session对象都会关联一个sessionid,例如:

    • JSESSIONID=41C481F0224664BDB28E95081D23D5B8
    • 以上的这个键值对数据其实就是cookie对象。
    • 对于session关联的cookie来说,这个cookie是被保存在浏览器的“运行内存”当中。
    • 只要浏览器不关闭,用户再次发送请求的时候,会自动将运行内存中的cookie发送给服务器。
    • 例如,这个Cookie: JSESSIONID=41C481F0224664BDB28E95081D23D5B8就会再次发送给服务器。
    • 服务器就是根据41C481F0224664BDB28E95081D23D5B8这个值来找到对应的session对象的。
  • cookie怎么生成?cookie保存在什么地方?cookie有啥用?浏览器什么时候会发送cookie,发送哪些cookie给服务器???????

  • cookie最终是保存在浏览器客户端上的。

    • 可以保存在运行内存中。(浏览器只要关闭cookie就消失了。)
    • 也可以保存在硬盘文件中。(永久保存。)
  • cookie有啥用呢?

    • cookie和session机制其实都是为了保存会话的状态。
    • cookie是将会话的状态保存在浏览器客户端上。(cookie数据存储在浏览器客户端上的。)
    • session是将会话的状态保存在服务器端上。(session对象是存储在服务器上。)
    • 为什么要有cookie和session机制呢?因为HTTP协议是无状态 无连接协议。
  • cookie的经典案例

    • 京东商城,在未登录的情况下,向购物车中放几件商品。然后关闭商城,再次打开浏览器,访问京东商城的时候,购物车中的商品还在,这是怎么做的?我没有登录,为什么购物车中还有商品呢?
      • 将购物车中的商品编号放到cookie当中,cookie保存在硬盘文件当中。这样即使关闭浏览器。硬盘上的cookie还在。下一次再打开京东商城的时候,查看购物车的时候,会自动读取本地硬盘中存储的cookie,拿到商品编号,动态展示购物车中的商品。
        • 京东存储购物车中商品的cookie可能是这样的:productIds=xxxxx,yyyy,zzz,kkkk
        • 注意:cookie如果清除掉,购物车中的商品就消失了。
    • 126邮箱中有一个功能:十天内免登录
      • 这个功能也是需要cookie来实现的。
      • 怎么实现的呢?
        • 用户输入正确的用户名和密码,并且同时选择十天内免登录。登录成功后。浏览器客户端会保存一个cookie,这个cookie中保存了用户名和密码等信息,这个cookie是保存在硬盘文件当中的,十天有效。在十天内用户再次访问126的时候,浏览器自动提交126的关联的cookie给服务器,服务器接收到cookie之后,获取用户名和密码,验证,通过之后,自动登录成功。
        • 怎么让cookie失效?
          • 十天过后自动失效。
          • 或者改密码。
          • 或者在客户端浏览器上清除cookie。
  • cookie机制和session机制其实都不属于java中的机制,实际上cookie机制和session机制都是HTTP协议的一部分。php开发中也有cookie和session机制,只要是你是做web开发,不管是什么编程语言,cookie和session机制都是需要的。

  • HTTP协议中规定:任何一个cookie都是由name和value组成的。name和value都是字符串类型的。

  • 在java的servlet中,对cookie提供了哪些支持呢?

    • 提供了一个Cookie类来专门表示cookie数据。jakarta.servlet.http.Cookie;
    • java程序怎么把cookie数据发送给浏览器呢?response.addCookie(cookie);
  • 在HTTP协议中是这样规定的:当浏览器发送请求的时候,会自动携带该path下的cookie数据给服务器。(URL。)

  • 关于cookie的有效时间

    • 怎么用java设置cookie的有效时间
      • cookie.setMaxAge(60 * 60); 设置cookie在一小时之后失效。
    • 没有设置有效时间:默认保存在浏览器的运行内存中,浏览器关闭则cookie消失。
    • 只要设置cookie的有效时间 > 0,这个cookie一定会存储到硬盘文件当中。
    • 设置cookie的有效时间 = 0 呢?
      • cookie被删除,同名cookie被删除。
    • 设置cookie的有效时间 < 0 呢?
      • 保存在运行内存中。和不设置一样。
        // 创建Cookie对象
        Cookie cookie = new Cookie(“productid”, “12345645623145612”);
        Cookie cookie2 = new Cookie(“username”, “zhangsan”);

        // 设置cookie在一小时之后失效。(保存在硬盘文件当中)
        //cookie.setMaxAge(60 * 60);
        // 设置cookie的有效期为0,表示该cookie被删除。主要应用在:使用这种方式删除浏览器上的同名cookie。
        //cookie.setMaxAge(0);
        // 设置cookie的有效期 < 0,表示该cookie不会被存储。(表示不会被存储到硬盘文件中。会放在浏览器运行内存当中。)
        cookie.setMaxAge(-1); // 和不调用sexMaxAge是同一个效果。
        cookie2.setMaxAge(-1);

        // 默认情况下,没有设置path的时候,cookie关联的路径是什么?
        //cookie.setPath(“/servlet13”);
        cookie.setPath(request.getContextPath());
        cookie2.setPath(request.getContextPath());

        // 将cookie响应到浏览器
        response.addCookie(cookie);
        response.addCookie(cookie2);

  • 关于cookie的path,cookie关联的路径:
    情况一:当cookie的path设置了值不为null的时候,以设置的值为准。
    情况二:当cookie的path为null时候,获取请求的URI的path值
    1、当URI的path值是以“/”结尾的时候,直接设置为cookie的path值
    2、当URI的path值不是以“/”结尾的时候,查看path里面是否有“/”
    (1)如果有“/”的话,直接截取到最后一个“/”,然后设置为cookie的path值。
    (2)如果没有“/”的话,将cookie的path设置为”/”。
    有路径的:

       https://www.baidu.com/test/a.html
    
      如果设置cookie没有设置path,那么path的默认值为 "/test"
    

无路径的:

    https://www.baidu.com/a.html

    如果设置cookie没有设置path,那么path的默认值为 "/"

原文链接:https://blog.csdn.net/qq_35699198/article/details/121417244

原文链接:https://blog.csdn.net/qq_35699198/article/details/121417244

  • 假设现在发送的请求路径是“http://localhost:8080/servlet13/cookie/generate”生成的cookie,如果cookie没有设置path,默认的path是什么?

    • 默认的path是:http://localhost:8080/servlet13/cookie 以及它的子路径。
    • 也就是说,以后只要浏览器的请求路径是http://localhost:8080/servlet13/cookie 这个路径以及这个路径下的子路径,cookie都会被发送到服务器。
  • 手动设置cookie的path

    • cookie.setPath(“/servlet13”); 表示只要是这个servlet13项目的请求路径,都会提交这个cookie给服务器。
  • 浏览器发送cookie给服务器了,服务器中的java程序怎么接收?

    • Cookie[] cookies = request.getCookies(); // 这个方法可能返回null
      if(cookies != null){
          for(Cookie cookie : cookies){
              // 获取cookie的name
              String name = cookie.getName();
              // 获取cookie的value
              String value = cookie.getValue();
          }
      }
      
      
  • 使用cookie实现一下十天内免登录功能。

    • 先实现登录功能
      • 登录成功
        • 跳转到部门列表页面
      • 登录失败
        • 跳转到登录失败页面
    • 修改前端页面
      • 在登录页面给一个复选框,复选框后面给一句话:十天内免登录。
      • 用户选择了复选框:表示要支持十天内免登录。
      • 用户没有选择复选框:表示用户不想使用十天内免登录功能。
    • 修改Servlet中的login方法
      • 如果用户登录成功了,并且用户登录时选择了十天内免登录功能,这个时候应该在Servlet的login方法中创建cookie,用来存储用户名和密码,并且设置路径,设置有效期,将cookie响应给浏览器。(浏览器将其自动保存在硬盘文件当中10天)
    • 用户再次访问该网站的时候,访问这个网站的首页的时候,有两个走向:
      • 要么跳转到部门列表页面
      • 要么跳转到登录页面
      • 以上分别有两个走向,这显然是需要编写java程序进行控制的。

EL表达式

  • EL表达式是干什么用的?

    • Expression Language(表达式语言)
    • EL表达式可以代替JSP中的java代码,让JSP文件中的程序看起来更加整洁,美观。
    • JSP中夹杂着各种java代码,例如<% java代码 %>、<%=%>等,导致JSP文件很混乱,不好看,不好维护。所以才有了后期的EL表达式。
    • EL表达式可以算是JSP语法的一部分。EL表达式归属于JSP。
  • EL表达式出现在JSP中主要是:

    • 从某个作用域中取数据,然后将其转换成字符串,然后将其输出到浏览器。这就是EL表达式的功效。三大功效:
      • 第一功效:从某个域中取数据。
        • 四个域:
          • pageContext
          • request
          • session
          • application
      • 第二功效:将取出的数据转成字符串。
        • 如果是一个java对象,也会自动调用java对象的toString方法将其转换成字符串。
      • 第三功效:将字符串输出到浏览器。
        • 和这个一样:<%= %>,将其输出到浏览器。
  • EL表达式很好用,基本的语法格式:

    • ${表达式}
  • EL表达式的使用:

    • <%
      	// 创建User对象
      	User user = new User();
      	user.setUsername("jackson");
      	user.setPassword("1234");
      	user.setAge(50);
      
      	// 将User对象存储到某个域当中。一定要存,因为EL表达式只能从某个范围中取数据。
      	// 数据是必须存储到四大范围之一的。
      	request.setAttribute("userObj", user);
      %>
      
      <%--使用EL表达式取--%>
      ${这个位置写什么????这里写的一定是存储到域对象当中时的name}
      要这样写:
      ${userObj}
      等同于java代码:<%=request.getAttribute("userObj")%>
      你不要这样写:${"userObj"}
      
      面试题:
      	${abc} 和 ${"abc"}的区别是什么?
      		${abc}表示从某个域中取出数据,并且被取的这个数据的name是"abc",之前一定有这样的代码: 域.setAttribute("abc", 对象);
      		${"abc"} 表示直接将"abc"当做普通字符串输出到浏览器。不会从某个域中取数据了。
      
      ${userObj} 底层是怎么做的?从域中取数据,取出user对象,然后调用user对象的toString方法,转换成字符串,输出到浏览器。
      
      <%--如果想输出对象的属性值,怎么办?--%>
      ${userObj.username} 使用这个语法的前提是:User对象有getUsername()方法。
      ${userObj.password} 使用这个语法的前提是:User对象有getPassword()方法。
      ${userObj.age} 使用这个语法的前提是:User对象有getAge()方法。
      ${userObj.email} 使用这个语法的前提是:User对象有getEmail()方法。
      EL表达式中的. 这个语法,实际上调用了底层的getXxx()方法。
      注意:如果没有对应的get方法,则出现异常。报500错误。
      
      ${userObj.addr222.zipcode}
      以上EL表达式对应的java代码:
      user.getAddr222().getZipcode()
      
    • EL表达式优先从小范围中读取数据。

      • pageContext < request < session < application
    • EL表达式中有四个隐含的隐式的范围:

      • pageScope 对应的是 pageContext范围。
      • requestScope 对应的是 request范围。
      • sessionScope 对应的是 session范围。
      • applicationScope 对应的是 application范围。
    • EL表达式对null进行了预处理。如果是null,则向浏览器输出一个空字符串。

    • EL表达式取数据的时候有两种形式:

      • 第一种:. (大部分使用这种方式)
      • 第二种:[ ] (如果存储到域的时候,这个name中含有特殊字符,可以使用 [ ])
        • request.setAttribute(“abc.def”, “zhangsan”);
        • ${requestScope.abc.def} 这样是无法取值的。
        • 应该这样:${requestScope[“abc.def”]}
          []这种方式主要用于变量名中有.
    • 掌握使用EL表达式,怎么从Map集合中取数据:

      • ${map.key}
    • 掌握使用EL表达式,怎么从数组和List集合中取数据:

      • ${数组[0]}
      • ${数组[1]}
      • ${list[0]}
    • page指令当中,有一个属性,可以忽略EL表达式

      • <%@page contentType="text/html;charset=UTF-8" isELIgnored="true" %>
        isELIgnored="true" 表示忽略EL表达式
        isELIgnored="false" 表示不忽略EL表达式。(这是默认值)
        
        isELIgnored="true" 这个是全局的控制。
        
        可以使用反斜杠进行局部控制:\${username} 这样也可以忽略EL表达式。
        
    • 通过EL表达式获取应用的根:

      • ${pageContext.request.contextPath}
    • EL表达式中其他的隐式对象:

      • pageContext
      • param
      • paramValues
      • initParam
    • EL表达式的运算符

      • 算术运算符
        • +、-、*、/、%
      • 关系运算符
        • == eq != > >= < <=
      • 逻辑运算符
        • ! && || not and or
      • 条件运算符
        • ? :
      • 取值运算符
        • [ ]和.
      • empty运算符
        • empty运算符的结果是boolean类型
        • ${empty param.username}
        • ${not empty param.username}
        • ${!empty param.password}

JSTL标签库

  • 什么是JSTL标签库?

    • Java Standard Tag Lib(Java标准的标签库)
    • JSTL标签库通常结合EL表达式一起使用。目的是让JSP中的java代码消失。
    • 标签是写在JSP当中的,但实际上最终还是要执行对应的java程序。(java程序在jar包当中。)
  • 使用JSTL标签库的步骤:

    • 第一步:引入JSTL标签库对应的jar包。

      • tomcat10之后引入的jar包是:

        • jakarta.servlet.jsp.jstl-2.0.0.jar
        • jakarta.servlet.jsp.jstl-api-2.0.0.jar
          或者

          jstl
          jstl
          1.2


          taglibs
          standard
          1.1.2
      • 在IDEA当中怎么引入?

        • 在WEB-INF下新建lib目录,然后将jar包拷贝到lib当中。然后将其“Add Lib…”
        • 一定是要和mysql的数据库驱动一样,都是放在WEB-INF/lib目录下的。
        • 什么时候需要将jar包放到WEB-INF/lib目录下?如果这个jar是tomcat服务器没有的。
    • 第二步:在JSP中引入要使用标签库。(使用taglib指令引入标签库。)

      • JSTL提供了很多种标签,你要引入哪个标签????重点掌握核心标签库。

      • <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
        这个就是核心标签库。
        prefix="这里随便起一个名字就行了,核心标签库,大家默认的叫做c,你随意。"
        
    • 第三步:在需要使用标签的位置使用即可。表面使用的是标签,底层实际上还是java程序。

  • JSTL标签的原理

    • <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      以上uri后面的路径实际上指向了一个xxx.tld文件。
      tld文件实际上是一个xml配置文件。
      在tld文件中描述了“标签”和“java类”之间的关系。
      以上核心标签库对应的tld文件是:c.tld文件。它在哪里。
      在jakarta.servlet.jsp.jstl-2.0.0.jar里面META-INF目录下,有一个c.tld文件。
      
    • 源码解析:配置文件tld解析

      • <tag>
            <description>对该标签的描述</description>
            <name>catch</name> 标签的名字
            <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class> 标签对应的java类。
            <body-content>JSP</body-content> 标签体当中可以出现的内容,如果是JSP,就表示标签体中可以出现符合JSP所有语法的代码。例如EL表达式。
            <attribute>
                <description>
                	对这个属性的描述
                </description>
                <name>var</name> 属性名
                <required>false</required> false表示该属性不是必须的。true表示该属性是必须的。
                <rtexprvalue>false</rtexprvalue> 这个描述说明了该属性是否支持EL表达式。false表示不支持。true表示支持EL表达式。
            </attribute>
          </tag>
        
        <c:catch var="">
        	JSP....
        </c:catch>
        
    • jstl中的核心标签库core当中有哪些常用的标签呢?

      • c:if

        • <c:if test=“boolean类型,支持EL表达式”></c: if>
      • c:forEach

        • <c:forEach items=“集合,支持EL表达式” var=“集合中的元素” varStatus=“元素状态对象”> ${元素状态对象.count} </c: forEach>
        • <c:forEach var=“i” begin=“1” end=“10” step=“2”> ${i} </c: forEach>
      • c:choose c:when c:otherwise

        • <c:choose>
              <c:when test="${param.age < 18}">
                  青少年
              </c:when>
              <c:when test="${param.age < 35}">
                  青年
              </c:when>
              <c:when test="${param.age < 55}">
                  中年
              </c:when>
              <c:otherwise>
                  老年
              </c:otherwise>
          </c:choose>
          

改造OA

  • 使用什么技术改造呢?

    • Servlet + JSP + EL表达式 + JSTL标签。进行改造。
  • 在前端HTML代码中,有一个标签,叫做base标签,这个标签可以设置整个网页的基础路径。

    • 这是Java的语法,也不是JSP的语法。是HTML中的一个语法。HTML中的一个标签。通常出现在head标签中。

    • < base href=“http://localhost:8080/oa/”>

    • 在当前页面中,凡是路径没有以“/”开始的,都会自动将base中的路径添加到这些路径之前。

      • < a href=“ab/def”></ a>
      • 等同于:< a href=“http://localhost:8080/oa/ab/def”></ a>
    • 需要注意:在JS代码中的路径,保险起见,最好不要依赖base标签。JS代码中的路径最好写上全路径。

    • <base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">
      

Filter过滤器

主要是用于解决乱码问题,在servelet执行之前执行。

  • 当前的OA项目存在什么缺陷?

    • DeptServlet、EmpServlet、OrderServlet。每一个Servlet都是处理自己相关的业务。在这些Servlet执行之前都是需要判断用户是否登录了。如果用户登录了,可以继续操作,如果没有登录,需要用户登录。这段判断用户是否登录的代码是固定的,并且在每一个Servlet类当中都需要编写,显然代码没有得到重复利用。包括每一个Servlet都要解决中文乱码问题,也有公共的代码。这些代码目前都是重复编写,并没有达到复用。怎么解决这个问题?
      • 可以使用Servlet规范中的Filter过滤器来解决这个问题。
  • Filter是什么,有什么用,执行原理是什么?

    • Filter是过滤器。
    • Filter可以在Servlet这个目标程序执行之前添加代码。也可以在目标Servlet执行之后添加代码。之前之后都可以添加过滤规则。
    • 一般情况下,都是在过滤器当中编写公共代码。
  • 一个过滤器怎么写呢?

    • 第一步:编写一个Java类实现一个接口:jarkata.servlet.Filter。并且实现这个接口当中所有的方法。

      • init方法:在Filter对象第一次被创建之后调用,并且只调用一次。
      • doFilter方法:只要用户发送一次请求,则执行一次。发送N次请求,则执行N次。在这个方法中编写过滤规则。
      • destroy方法:在Filter对象被释放/销毁之前调用,并且只调用一次。
    • 第二步:在web.xml文件中对Filter进行配置。这个配置和Servlet很像。

      • <filter>
            <filter-name>filter2</filter-name>
            <filter-class>com.bjpowernode.javaweb.servlet.Filter2</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>filter2</filter-name>
            <url-pattern>*.do</url-pattern>
        </filter-mapping>
        
      • 或者使用注解:@WebFilter({“*.do”})

      第一种方式使用注解:
      /@WebFilter(“/abc”)
      //@WebFilter(“/a.do”)
      //@WebFilter({“/a.do”, “/b.do”})

/以下这个路径属于模糊匹配中的扩展匹配。以星号开始,注意这种路径不要以/开始。/
@WebFilter(“*.do”)

/属于前缀匹配。要以/开始。/
//@WebFilter(“/dept/*”)

// 匹配所有的路径。
//@WebFilter(“/*”)
public class Filter1 implements Filter {

/*public Filter1(){
    System.out.println("无参数构造方法执行");
}*/

@Override
public void init(FilterConfig filterConfig) throws ServletException {
    System.out.println("init方法执行。");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    // 在请求的时候添加过滤规则。
    System.out.println("Filter1 doFilter方法开始执行。");
    // 执行下一个过滤器,如果下一个不是过滤器了,则执行目标程序Servlet。
    // 向下走。没有它是不行滴。
    chain.doFilter(request, response);

    // 在响应的时候添加过滤规则。
    System.out.println("Filter1 doFilter方法执行结束。");
}

@Override
public void destroy() {
    System.out.println("destroy方法执行");
}

}
第二种xml方式:

<?xml version="1.0" encoding="UTF-8"?>

<!--Filter1-->
<!--<filter>
    <filter-name>filter1</filter-name>
    <filter-class>com.bjpowernode.javaweb.servlet.Filter1</filter-class>
</filter>-->
<!--<filter-mapping>
    <filter-name>filter1</filter-name>-->
    <!--<url-pattern>/a.do</url-pattern>
    <url-pattern>/b.do</url-pattern>-->
    <!--<url-pattern>*.do</url-pattern>-->
    <!--<url-pattern>/*</url-pattern>-->
<!--</filter-mapping>-->

<!--Filter2-->
<!--<filter>
    <filter-name>filter2</filter-name>
    <filter-class>com.bjpowernode.javaweb.servlet.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>-->
filter3 com.bjpowernode.javaweb.servlet.filter3 filter3 *.do public class Filter2 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    System.out.println("Filter2 doFilter begin");
    chain.doFilter(request, response);
    System.out.println("Filter2 doFilter end");
}

@Override
public void destroy() {
}

}
第三种继承httpfilter
public class filter3 extends HttpFilter {
@Override
public String getInitParameter(String name) {

    return super.getInitParameter(name);
}

@Override
public void init() throws ServletException {
    super.init();
}

@Override
public void destroy() {

}

public filter3() {
    super();
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    super.doFilter(request, response, chain);
}

@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
    super.doFilter(request, response, chain);
}

}

  • 注意:

    • Servlet对象默认情况下,在服务器启动的时候是不会新建对象的。
    • Filter对象默认情况下,在服务器启动的时候会新建对象。
    • Servlet是单例的。Filter也是单例的。(单实例。)
  • 目标Servlet是否执行,取决于两个条件:

    • 第一:在过滤器当中是否编写了:chain.doFilter(request, response); 代码。
    • 第二:用户发送的请求路径是否和Servlet的请求路径一致。
  • chain.doFilter(request, response); 这行代码的作用:

    • 执行下一个过滤器,如果下面没有过滤器了,执行最终的Servlet。
  • 注意:Filter的优先级,天生的就比Servlet优先级高。

    • /a.do 对应一个Filter,也对应一个Servlet。那么一定是先执行Filter,然后再执行Servlet。
  • 关于Filter的配置路径:

    • /a.do、/b.do、/dept/save。这些配置方式都是精确匹配。
    • /* 匹配所有路径。
    • *.do 后缀匹配。不要以 / 开始
    • /dept/* 前缀匹配。
  • 在web.xml文件中进行配置的时候,Filter的执行顺序是什么?

    • 依靠filter-mapping标签的配置位置,越靠上优先级越高。
  • 过滤器的调用顺序,遵循栈数据结构。

  • 使用@WebFilter的时候,Filter的执行顺序是怎样的呢?

    • 执行顺序是:比较Filter这个类名。
    • 比如:FilterA和FilterB,则先执行FilterA。
    • 比如:Filter1和Filter2,则先执行Filter1.
  • Filter的生命周期?

    • 和Servlet对象生命周期一致。
    • 唯一的区别:Filter默认情况下,在服务器启动阶段就实例化。Servlet不会。
  • Filter过滤器这里有一个设计模式:

    • 责任链设计模式。
    • 过滤器最大的优点:
      • 在程序编译阶段不会确定调用顺序。因为Filter的调用顺序是配置到web.xml文件中的,只要修改web.xml配置文件中filter-mapping的顺序就可以调整Filter的执行顺序。显然Filter的执行顺序是在程序运行阶段动态组合的。那么这种设计模式被称为责任链设计模式。
    • 责任链设计模式最大的核心思想:
      • 在程序运行阶段,动态的组合程序的调用顺序。
  • 使用过滤器改造OA项目。
    过滤器一般使用xml配置,因为修改调用顺序的时候只需要修改xml而不用修改java代码,修改java是一件繁琐的事情,而且不符合ocp原则。

Listener监听器

  • 什么是监听器?

    • 监听器是Servlet规范中的一员。就像Filter一样。Filter也是Servlet规范中的一员。
    • 在Servlet中,所有的监听器接口都是以“Listener”结尾。
  • 监听器有什么用?

    • 监听器实际上是Servlet规范留给我们javaweb程序员的特殊时机。
    • 特殊的时刻如果想执行这段代码,你需要想到使用对应的监听器。
  • Servlet规范中提供了哪些监听器?

    • jakarta.servlet包下:
      • ServletContextListener
      • ServletContextAttributeListener
      • ServletRequestListener
      • ServletRequestAttributeListener
    • jakarta.servlet.http包下:
      • HttpSessionListener
      • HttpSessionAttributeListener
        • 该监听器需要使用@WebListener注解进行标注。
        • 该监听器监听的是什么?是session域中数据的变化。只要数据变化,则执行相应的方法。主要监测点在session域对象上。
      • HttpSessionBindingListener
        • 该监听器不需要使用@WebListener进行标注。
        • 假设User类实现了该监听器,那么User对象在被放入session的时候触发bind事件,User对象从session中删除的时候,触发unbind事件。
        • 假设Customer类没有实现该监听器,那么Customer对象放入session或者从session删除的时候,不会触发bind和unbind事件。
      • HttpSessionIdListener
        • session的id发生改变的时候,监听器中的唯一一个方法就会被调用。
      • HttpSessionActivationListener
        • 监听session对象的钝化和活化的。
        • 钝化:session对象从内存存储到硬盘文件。
        • 活化:从硬盘文件把session恢复到内存。
  • 实现一个监听器的步骤:以ServletContextListener为例。

    • 第一步:编写一个类实现ServletContextListener接口。并且实现里面的方法。

      • void contextInitialized(ServletContextEvent event)
        void contextDestroyed(ServletContextEvent event)
        
    • 第二步:在web.xml文件中对ServletContextListener进行配置,如下:

      • <listener>
            <listener-class>com.bjpowernode.javaweb.listener.MyServletContextListener</listener-class>
        </listener>
        
      • 当然,第二步也可以不使用配置文件,也可以用注解,例如:@WebListener

  • 注意:所有监听器中的方法都是不需要javaweb程序员调用的,由服务器来负责调用?什么时候被调用呢?

    • 当某个特殊的事件发生(特殊的事件发生其实就是某个时机到了。)之后,被web服务器自动调用。
  • 思考一个业务场景:

    • 请编写一个功能,记录该网站实时的在线用户的个数。
    • 我们可以通过服务器端有没有分配session对象,因为一个session代表了一个用户。有一个session就代表有一个用户。如果你采用这种逻辑去实现的话,session有多少个,在线用户就有多少个。这种方式的话:HttpSessionListener够用了。session对象只要新建,则count++,然后将count存储到ServletContext域当中,在页面展示在线人数即可。
    • 业务发生改变了,只统计登录的用户的在线数量,这个该怎么办?
      • session.setAttribute(“user”, userObj);
      • 用户登录的标志是什么?session中曾经存储过User类型的对象。那么这个时候可以让User类型的对象实现HttpSessionBindingListener监听器,只要User类型对象存储到session域中,则count++,然后将count++存储到ServletContext对象中。页面展示在线人数即可。
  • 实现oa项目中当前登录在线的人数。

    • 什么代表着用户登录了?
      • session.setAttribute(“user”, userObj); User类型的对象只要往session中存储过,表示有新用户登录。
    • 什么代表着用户退出了?
      • session.removeAttribute(“user”); User类型的对象从session域中移除了。
      • 或者有可能是session销毁了。(session超时)

@WebListener
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {

// 向session域当中存储数据的时候,以下方法被WEB服务器调用。
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
    System.out.println("session data add");
}

// 将session域当中存储的数据删除的时候,以下方法被WEB服务器调用。
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
    System.out.println("session data remove");
}

// session域当中的某个数据被替换的时候,以下方法被WEB服务器调用。
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
    System.out.println("session data replace");
}

}
@WebListener
public class MyHttpSessionListner implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println(“session被创建了”);
}

@Override
public void sessionDestroyed(HttpSessionEvent se) {
    System.out.println("session被销毁了");
}

}
// ServletContextListener监听器主要监听的是:ServletContext对象的状态。
@WebListener
public class MyServletContextListener implements ServletContextListener {

/**
 * 监听器中的方法不需要程序员手动调用。是发生某个特殊事件之后被服务器调用。
 * @param sce
 */
@Override
public void contextInitialized(ServletContextEvent sce) { // 服务器启动时间点,想在这个时候执行一段代码,写就行了。
    // 现在这个特殊的时刻写代码,你写就是了。它会被服务器自动调用。
    // 这个方法是在ServletContext对象被创建的时候调用。
    System.out.println("ServletContext对象创建了。");
}

@Override
public void contextDestroyed(ServletContextEvent sce) { // 服务器关闭时间点。
    // 现在这个特殊的时刻写代码,你写就是了。它会被服务器自动调用。
    // 这个方法是在ServletContext对象被销毁的时候调用。
    System.out.println("ServletContext对象被销毁了。");
}

}
@WebListener
public class MyServletRequestListener implements ServletRequestListener {
// request对象销毁时间点
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println(“request对象销毁了”);
}

// request对象创建时间点
@Override
public void requestInitialized(ServletRequestEvent sre) {
    System.out.println("request对象初始化了");
}

}
@WebServlet(“/exit”)
public class ExitServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false);
if (session != null) {
// 销毁session
session.invalidate();
}
}
}

@WebServlet(“/session/attribute/test”)
public class HttpSessionAttributeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取session对象
HttpSession session = request.getSession();

    // 向session域中存储数据
    session.setAttribute("user", "zhangsan");

    // 替换
    session.setAttribute("user", "lisi");

    // 删除
    session.removeAttribute("user");
}

}
@WebServlet(“/session/bind”)
public class HttpSessionBindingListenerServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 获取session对象
    HttpSession session = request.getSession();

    // 准备两个对象:User1 User2
    User1 user1 = new User1("111", "zhangsan", "123");
    User2 user2 = new User2("111", "zhangsan", "123");

    // 将user1存储到session域
    session.setAttribute("user1", user1);
    session.setAttribute("user1", null);//解绑数据,实现了HttpSessionBindingListener的bean从session消失的时候解绑
    //servlet中的对象不能自己创建ServletContext servletContext = new ServletContext();
    ServletContext context = request.getServletContext();
    context.setAttribute("user3",user1);//HttpSessionBindingListener指的是session绑定对象
    ServletConfig servletConfig = this.getServletConfig();
    ServletContext servletContext = this.getServletContext();
    ServletContext configServletContext = servletConfig.getServletContext();

    // 将user2存储到session域
    session.setAttribute("user2", user2);
}

}

使用过滤器设置字符编码:
(一)过滤器
概念简述:

当web获得对资源请求时,web会判断该资源与过滤器是否相关,如果相关就交给过滤器处理,在过滤器中可以对请求的内容作出改变,然后再将请求转交给被请求的资源。当被请求的资源作出响应时,web同样会将响应先给过滤器,在过滤器中对响应处理之后再发送给客户端。
1
开发过滤器步骤
(1)定义过滤器类,实现javax.servlet.Filter接口;
(2)重写init(),doFilter(),destory()方法;
(3)配置过滤器:web.xml中。

filterclassname com.xzz.myfilter.filterclassname filterclassname /* 注:过滤器doFilter()形参中的request和response是ServletRequest和ServletResponse的对象 servlet中的request和response是HttpServletRequest和HttpServletResponse的对象

开发过滤器链

(1)定义第二个、第二个过滤器类,实现javax.servlet.Filter接口;
(2)重写init(),doFilter(),destory()方法;
(3)配置过滤器:web.xml中。
注:(1)在第一个过滤器的doFilter()方法中,用chain(request,response),将请求与响应对象向后续过滤器传递。
(2)服务顺序:以web.xml中的配置顺序为主。

(二)设置字符编码过滤器

(1)定义过滤器类,实现javax.servlet.Filter接口;
(2)重写init(),doFilter(),destory()方法;
①在类中设置私有属性encode:
private String encode=“UTF-8”;
②重写init(FilterConfig filterConfig)方法:
//获取初始化参数的值
encode=filterConfig.getInitParamater(“encode”);
if(encode==null){
encode=“UTF-8”;
}
③重写doFilter(ServletRequest req, ServletResponse res, FilterChain chain)方法:
//将对象转换成http下的对象
HttpServletRequest request=(HttpServletRequest )req;
HttpServletResponse response=(HttpServletResponse )res;
//判断请求方式是否为post
if(“POST”.equalsIgnoreCase(request.getMethod())){
//设置字符编码
request.setCharacterEncoding(encode);
//设置响应类型
response.setCharacterEncoding(encode);
response.setContentType(“text/html;charset=”+encode);
//将请求与响应传递给下个过滤器
chain.doFilter(request,response);
//结束
return;
}
//将请求与响应传递给下个过滤器
chain.doFilter(request,response);
④重写destory()方法:
(3)配置字符编码过滤器:web.xml中。

filterclassname
com.xzz.myfilter.filterclassname


encode
UTF-8



filterclassname
/*

(4)测试字符编码
①创建jsp文件,内容为表单提交,方式为post;




②创建servlet文件,重写doget()方法:
String text=request.getParameter(“text”);
System.out.println(“>>>>>>>”+text);

共享资源文件:
1.什么共享资源文件:
可以通过网络进行传输的文件,都能被称为共享资源文件。
所有的文件内容都可以通过网络传输,所有文件都是共享资源文件。
2.http服务器下对共享资源文件分类
1)静态资源文件
2)动态资源文件。
1.静态资源文件:如果文件的内容是固定的,这种文件可以被称为(静态资源文件)。
文档,视频
2.如果文件存放的不是内容而是命令,这些命令只能再浏览器编译与执行,这种文件可以被称为静态资源文件。


动态资源文件:
如果文件存放命令,并且命令不能再浏览器编译与执行,只能再服务端计算机编译执行,这样的文件被称为动态资源文件。
(.class)

静态资源文件和动态文件资源的区别:
静态文件被索要时,HTTP服务器直接通过(输出流)将静态文件中内容或命令以(二进制形式)推送给发起请求浏览器
动态文件被索要时,http服务器需要创建当前class文件的实例对象()

通过实例对象调用对应的方法处理用户请求,通过(输出流)将运行结果以二进制形式推送给发起请求浏览器。
class student{
public int add (int num1,int num2)
int sum=num1+num2;
return sum;
}
http服务器(自动)
student stu =new student();
int 结果=stu.add(10,20);
out.print(结果)

开发人员在互联网中的作用:

客户端 服务端计算机
控制浏览器请求行为三要素:
1.控制浏览器发送的请求地址----------------》发送请求(http服务器,静态资源文件(文档,图片,视频(http,css,js)前段工程师。
2.控制浏览器发送请求方式 动态资源文件。
3.控制浏览器发送请求的参数。

控制浏览器结果行为。
1.控制(浏览器采用对应(编译器)将接收到的二进制数据解析为(文字,视频,图片,命令)
2.控制浏览器解析内容或命令进行执行与展示(全局刷新展示/局部刷新展示)
3.控制用户与浏览器之间交流(js。。jquery)

--------------HTML
html
1:HTML编程语言是一种在专门在浏览器编译与执行的编程语言。
2.HTML编程语言学称是超文本标记式编程语言,*图片,视频也可以)
二:作用:
1.html编程语言通知浏览器将接收的数据以指定方式在窗口展示;
2.控制浏览器请求行为(前后端)
三:HTML编程语言语法规范:
1.HTML编程语言所有命令都是声明在标签中,比如

2.HTML编程语言中所有命令都是预先定义好,不允许开发人员自行创建新的命令。
3.HTML编程语言中所有命令不区分英文大小写,
,

4.HTML编程语言中命令开发时通过对命令中属性进行赋值实现开发目的。
属性赋值内容可以包含一个“”中,也可以在‘ ’,也可以省略双引号与单引号,此时用空格隔离。
5.HTML编程语言中根据书写方式分为:双目标签与单目标签命令
6.双目标签命令书写命令分别出现开始标签和结束标签。比如
双目标签的结束标签不能省略
7.单目标签命令书写在一个标签内:
单目标签用于表示结束“/"可以省略不写。比如
,

段落标签

标题标签
  1. 有序标签 oreder label
    • 无序标签 unoreder label
    • 列表标签 --进行大量数据展示

2.HTMLtd标签
td 标签 – 代表HTML表格中的一个单元格

* td标签是成对出现的,以<td>开始,</td>结束
 * 属性
  Common -- 一般属性
  abbr -- 代表表头的简写
  axis -- 对单元格在概念上分类
  colspan -- 一行跨越多列
  headers -- 连接表格的数据与表头
  rowspan -- 一列跨越多行
  scope -- 定义行或列的表头
  align -- 代表水平对齐方式(left(左对齐) | center(居中对齐) | right(右对齐) | justify)(此属性应该使用CSS实现)
   valign -- 代表垂直对齐方式(top(顶部对齐) | middle(中部对齐) | bottom(下部对齐) | baseline(基线对齐))(此属性应该使用CSS实现)

 * td是table data cell的缩写
  1. 代表表格
    代表表格中的一行 代表表格中的一列 ' TR'与'TD'交成一个单元格 ...
    之间有多少个,就有多少行 ...之间有多少个,就有多少列

浏览器发送请求三要素:
1.控制浏览器发送请求地址
2.控制浏览器发送请求采用请求方式
3.控制浏览器发送请求携带请求参数
五:
控制浏览器发送请求地址
1.超链接标签命令:
1)格式 提示信息
2)工作原理:超链接标签命令不会被浏览器自动执行。
在用户使用鼠标单击超链接标签命令时
此时这个命令才会执行,执行要求浏览器立刻按照href属性地址发送请求。
百度
<a hreef"图片标签.html">我的恩师
表单标签命令
1)格式

2)工作原理: 表单标签命令不会被浏览器自动执行,在用户单击提交时,此时表单标签命令被触发执行。执行时要求浏览器立刻按照action属性地址发送请求

六:控制浏览器发送请求采用请求方式
1.请求方式:决定浏览器在发送请求时行为特征
2.浏览器可以选择请求方式:7种,目前只考虑(post请求方式)和(get请求方式)
3.get请求方式:
1)要求浏览器发送请求时,携带的请求参数数量不能超过4K
2)要求浏览器发送请求时,必须在浏览器地址上将请求参数信息展示出来,(在浏览器搜索框中)
比如搜索时搜美女就是发送请求参数
3)要求浏览器发送请求时,必须将请求参数信息保存在http请求协议包中(请求头)
4)要求浏览器在接收到服务器返回的资源文件内容后,必须将资源文件内容保存到浏览器的缓存中
(用户在再次对浏览器发送请求时从缓存中取得资源,降低相应时间和难点)
4.post请求方式:
要求浏览器发送请求时,可以携带任意数量的请求参数。(上传内容)
2)要求浏览器发送请求时,必须在浏览器地址栏上隐藏请求参数信息。
3)要求浏览器发送请求时,必须将参数信息保存在http请求协议包中(请求体)
4)实时变化的数据。。禁止浏览器将服务器返回资源内容进行保存(阅后即焚)

5.控制浏览器发送请求时采用get请求方式
1.超链接标签命令在执行时,要求浏览器采用get方式发送请求。
2.表单标签存在一个method属性,通过这个属性可以要求浏览器采用对应请求方式发送请求。

不区分大小写。 method属性的默认值是get

6.控制浏览器发送请求时采用post请求方式

7.请求方式适用场景
1.考虑到post请求方式下,用户可以将病毒文件内容发送到服务器上进行攻击,
因此绝大多数的网站拒绝接受post请求,日常开发过程绝大数请求都是get
2.在某些特殊场景下必须使用post
1)文件上传,必须使用post
2)发起登录验证请求必须使用post。
3)索要服务器实时变化数据时(股票价格),防止缓存欺骗。

8.控制浏览器发送请求携带请求参数
1.请求参数作用:
比如用户通过浏览器访问服务端计算机动态资源文件student.class
class student{
public int add(int n1,int n2){
int sum=n1+n2;
return sum;}
}
http服务器:
student stu=new student();
stu.add(?,?)//add方法运行时需要实参,需要用户通过浏览器以请求方式提供
浏览器发送请求时需要携带调用方法需要实参(请求参数)。
http://www.baidu.com?n1=100&n2=200 (n1=100&n2=200)就是浏览器发送请求参数

2.请求参数格式
浏览器发送请求时 请求地址?请求参数名1=值1&请求参数名2=值2
3.浏览器发送请求时携带的请求参数来源:
1)通过超链接标签命令指定请求参数
2)通过表单域标签命令指定请求参数

4.通过超链接标签命令指定请求参数
百度
5.表单域标签命令
1)一组声明在form标签内部的标签命令
2)提供用户填写对应(请求参数内容),用于提供相对灵活的请求参数内容。
3)所有的表单域标签都用于两个属性(name,value)
name属性声明(请求参数名),balue属性声明(请求参数内容)

当用户单击submit后,浏览器发送请求信息 http://www.baidu.com?userName=mike

6.表单域标签分类:
1)
2)下拉列表标签

表单域 7.value属性的默认值 大多数表单域标签value属性默认值是空字符串userName=' ' checkbox的默认值是'on' 提交按钮,属于表单域标签,但是用于触发form命令,不作为请求参数使用 单选框 复选框 文件选择框,将选中的文件内容作为请求参数 重置按钮, 备注信息 籍贯: 8.表单域标签作为请求参数条件 1)对于大多数表单域标签来说,只要同时满足以下两个条件,就可以作为请求参数。 声明在form标签内部 2.必须声明name属性 对于radio标签与checkbox标签来说在满足上述两个条件同时,还必须满足第三个条件才可以作为请求参数, 第三个条件radio与checkbox必须在被选中的情况下才可以作为请求参数 如果表单域标签使用disable来修饰时,失去作为请求参数条件 readonly和disable区别: readonle 要求当前标签中的value属性只能看不能修改:readonly不会影响表单域标签作为请求参数条件 disable 设置当前标签中的value属性不能修改,影响表单域标签作为请求参数条件, 不能用’ css***** 是一种专门在浏览器编译并执行的编程语言。 用于定位浏览器的html标签并定位的html标签中样式属性进行统一管理。 html标签属性分类 1.基本属性: 大多数HTML标签都拥有属性是一个非常庞大群体 比如 id属性,相当于身份证编码。用于区分html标签 比如name属性,相当于人名字,允许同一组标签用有name 2.样式属性: 是一个庞大群体,通知浏览器将HTML标签中数据在浏览器中以指定形态展示 div长方体
3.工作状态属性: 只存在于(表单域标签)中,用于表示(表单域标签)状态 托底测试: checked:存在radio域checkbox中,表示标签是否被选中, disbaled:表示标签处于不可用状态; readonly:表示标签处于只读状态 selected:尊重option标签,标签标签是否被选中。 4.监听属性: 监听属性用户与HTML标签之间通信通道,监听属性。用于监听用户在何时对当前标签进行如何操作, 当指定操作产生时,监听属性将会通知浏览器调用对应JavaScript方法处理当前请求

ID选择器:
1.介绍:根据HTML标签中ID属性进行定位
2.语法:

#one{
color:red
}

七:标签类型选择器:
1.介绍:根据HTML标签类型进行定位
2.语法:

**********mysql服务器
1.表文件 .frm的文件
2.表文件结构:标题行
数据行
3.数据库
开发人员用于存放表文件的文件夹叫数据库
4.数据库服务器
一种专门对表文件进行调用和管理的软件
sql命令:
struct query language,结构化查询编程语言。
sql命令向数据库方式请求,对表空间进行调用管理
特点:包含主谓宾
四。数据库服务器分类:
1.关系型数据库服务器
管理的表文件彼此之间往往具有隶属关系特征,可以完整描述一段数据,但是查询速度较慢。
2.非关系型数据库服务器:bashmap-value
管理表文件都是独立,无法描述一段完整的数据
查询速度快
甲骨文:oracle mysql
微软:sqlserver

**省略

JAR包

接口:
接口的作用:
1.规则制定
2.降低java工程类之间的耦合度,从而降低成本。
两个项目通过jar包实现类的复用。

二:
JAVAEE规范和JAVASE规范区别。
1、JAVASE:指java类在单独执行,在单独处理业务时需要遵守语法规则。
比如 继承,访问权限,接口实现,控制语句,标识符命名。。

2.JAVAEE:java在进行商业开发时遵守开发规则
在商业开发过程中,往往需要JAVA类与不同服务器进行沟通来解决当前业务,由于在商业开发过程中,JAVA需要与13
种不同服务器进行沟通,因此sun公司根据13种服务器特征指定13套接口,这13套接口统称为JAVAEE规范。
sun公司负责提供接口,但是不负责提供接口中的实现类。
接口中实现类由不同服务器厂商来提供。服务器厂商将完成接口实现类以JAR包形式提供。java程序员通过jar包得到接口中的实现类,从而实现与指定服务器之间交流。
(自己概况就是厂商提供接口,外公司提供实现类打包成jar包给厂商,厂商看不到具体如何实现,但是可以使用这些类。

三。规则
JDBC规范介绍:
1.JAVAEE中的一种规范
2.指定JAVA类与关系型数据库服务器(MYSQL,ORACLE,SQLServer)之间沟通。
3.JDBC规范提供接口存在JDKJAR。java.sql包
4.JDBC规范接口实现类由不同关系型数据库服务器厂商以JAR包形式提供。
。。。。拿JAR包去访问数据库服务器。。

四:JDBC规范调用流程
1.将MYSQL服务器厂商提供Driver接口实现类注册到JVM
2.通过JDBC规范中DRIVERmanager在java工程与mysql服务器之间建立一个连接通道
3.通过mysql服务器厂商提供connection接口实现类建立一个交通工具(preparedstatement接口实现类)
4.通过交通工具(preparedStatement)将sql命令从JAVA工程推送到mysql服务器上执行并带回执行结果。
5.销毁本次交易过程涉及的资源对象。

五.jdbc规范下接口介绍:
1.位置:JDBC规范下接口存在于JDK——1.8.jar下的java.sql包
2。分类:
1)java.sql.DriverManager类:这个类存在于JDK_1.8下,负责将数据库厂商提供Driver接口实现进行注册
负责在JAVA工程与MYSQL服务器之间建立一个连接通道
2) java.sql.

java工程新建model,model是一个具体的java工程。pject是工作空间,存放JAVA工程
jdk中有一个JAVA.sql包,

将实现类传入
两种不同的驱动注册方式:
第一种: Driver driver=new com.mysql.jdbc.Driver();
DriverManager.registerDrive(driver);/可以忽略不写。


//“jdbc:mysql:服务器我所在计算机IP地址:服务器端口号/数据库”
String sql="、“Insert Into dept(deptno,dname,loc)values(90,‘小额贷款’,‘上海’);
spring url=“jdbc:mysql://localhost:3306/bjpowernode”;
1.将mysql服务器提供的jar包中DRIVER接口实现类,注册到JVM
Driver driver=new com。mysql.jdbc.Driver();
DriverManager.registerDrive(driver);
//2.通过DriverManager在Java工程与Mysql服务器之间建立一个连续通道。
Connection con=DriverManager.getConnection(url,user:“root”,password:“123456”);
//在通道上建立一个交通工具
prepareStetemtnt ps=con.prepareStatement(sql:” “);
报错时用shfit+
//4.通过交通工具将sql命令推送到mysql服务器上来执行并带回结果
int result=ps.executeUpdate(sql);
//5.销毁相关数据
if(ps!=null){
ps.close();
}
url:访问数据库的 URL 路径。
info:是一个持久的属性集对象,包括 user 和 password 属性。
String url=“jdbc:mysql://localhost:3306/bjpowernode”;
String sql=“Insert into dept(DEPTNO,DNAME,LOC) values(100,‘小额贷款’,‘上海’)”;
//1.将mysql服务器提供的jar包中DRIVER接口实现类,注册到JVM
Driver driver=new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
//2.通过DriverManager在Java工程与Mysql服务器之间建立一个连续通道。
Connection con=DriverManager.getConnection(url,“root”,“123456”);
//在通道上建立一个交通工具
PreparedStatement ps=con.prepareStatement(” ");
//获取数据库操作对象(statement专门用来执行sql语句的)
statement stmt=conn.createstatement();
//4.通过交通工具将sql命令推送到mysql服务器上来执行并带回结果
专门用来执行DML语句的(insert delete update)
int result=ps.executeUpdate(sql);
//5.销毁相关数据
if(ps!=null){
ps.close();
}
if(con!=null){
con.close();
}
System.out.print(“本次交易中,添加了”+result+“行数据”);
}

第二种:Class.forName(“com.mysql.jdbc.Driver”);注意C是大写
Class.forName(“com.mysql.jdbc.Driver”);
作用是:将com.mysql.jdbc.Driver这个类装载到JVM当中,装载过程会自动执行静态代码完成驱动注册。

ps.executeUpdate与PS.executeQuery的区别:
1.ps.executeupdate:
1)负责推送插入命令(insert),更新命令(update),删除命令(delete)
返回结果对表进行操作时,受到影响行数,比如插入了多少行,
更新了多少行,删除了多少行。
2.ps.executeQuery:
1)负责推送查询命令(select * from 表名)
2)返回结果是查询命令得到(临时表),在JDBC规范中(临时表)交给Resultset接口实现类管理,
实际上返回ResultSet实例对象。
Resultset re=ps.executequery();
resultset对象_>指针,去查找临时表
re.next()方法。
next()方法每次执行时,要求指针向下移动一行
如果指针执行位置是一个具体数据行,此时next方法将返回ture,
如果指针指向的不是一个数据行,则返回flas

接口的最主要的作用是达到统一访问,就是在创建对象的时候用接口创建,
【接口名】 【对象名】=new 【实现接口的类】,这样你像用哪个类的对象就可以new哪个对象了
,不需要改原来的代码,就和你的USB接口一样,插什么读什么.
使用 接口 对象名 = new 类名 的方式实例化的对象只能调用接口中有的方法,而不能调用类中特有的方法。
而使用 类名对象名 = new 类名 的方式创建出来的对象可以调用所有的方法。

***批处理插入非常的麻烦,
字符串拼接。
“insert into dept (deptno,dname,loc) values(”+i+“,dept_”+i+“,‘北京’)”;
这种方法非常浪费时间,preparedstatement 对象只能推送一次sql命令
需要执行100次非常浪费时间

//预编译形式sql命令
//"?"占位符一个问号代替一个值
//预编译sql相当于使用一个模具,只要将数据填充到占位符,就可以得到一个全新sql。
insert into dept (deptno,dname,loc)vlaues(?,?,?)
preparedstatemnt ps=con.perparstatemnt(sql)
for(i=1;i<100;i++){
ps.setInt(1,i);
ps.addBatch();//在新的sql语句生成之后,将sql语句作为子弹添加到ps弹夹

}
//一次性通过ps将100条sql语句推送到mysql服务器。
ps.executeBatch;往返一次。

事务控制
try
{sql语句1
sql语句2
con.commit();
catch(SqlExeption{
con.rollback();//事务回滚
}
scanner sequest=new scanner(system.in).//用户在控制输入请求
同一生命周期只能有一个声明同名变量

JDBCutil包装类;
jvm注册:写在static中


DAO封装.
1.介绍:
1)Dao =database access object;数据库访问对象
2)作用:数据库访问对象在开发时提供对某张表的操作细节(增删改查)3)优点:
优点1:在管理开发系统时,通过数据库访问对象可以避免反复的sql命令书写
优点2,在管理系统开发时,通过数据库访问对象可以避免反复的JDBC开发步骤书写。
4)DAO类:提供数据库访问对象的类。
2.dao开发规则:
1)一个dao类封装的是一张表操作细节。
2)Dao类命名规则:表名+dao。比如封装emp表操作细节:empdao
3)Dao类名所在包含规则:公司网站,dao。com.BJPOWERNODE.dao

将光标定位到这段代码,按快捷键【CTRL+ALT+T】。生成catch语句

实体类:
一个实体类用于描述一张表的结构
2.实体列的类名应该与关联的表名保持一致,但是可以忽略大小写
DEPT.drm -----public class Dept()
3.实体类的属性应该与关联的表文件字段保持一致。
Dept.frm --------------------
DEPTNO INT

public class Dept{
private Integer deptNo
}
实体类的一个实例对象用于在存放中存储对应的表文件中一个数据行。
Dept dept1=new Dept(10," “,” ")

return 只能返回一个数据
想要返回多行就用list
作用是jdbc关闭资源后可以查询到数据。

浏览器
开发人员控制浏览器的请求行为(三要素)
1.请求地址控制

2.请求方式控制:post,get 3.请求参数的控制: 表单域

浏览器是不可以直接操作mysql数据库服务器的
必须借助dos窗口,idea,navcat等软件操作数据库
浏览器必须借助http服务器:8080
http服务器:
静态资源文件:
内容是固定的
1)文档
2)图片
3)视频
2.视频
2.存储专门在浏览器运行的命令
1)html
2)css
3)js
动态资源文件
java世界中,class文件才算动态资源文件
2.http服务器接收请求后负责创建类文件实例对象
Servlet=new Servlet():
3)http服务器通过实例对象调用方法处理用户请求
servletdoget(){
JDBC规范
}返回结果
4)http服务器负责将方法以二进制形式推送回发送请求浏览器。


Http网络协议包
一.网络协议包:
1.在网络中传递信息都是以二进制形式存在的。
2.接收方(浏览器/服务器)在接收信息后,要做第一件事就是讲二进制数据进行编译(文字,图片,视频,命令)
3.传递信息数据量往往比较巨大,导致接收方很难再一组连续二进制得到对应数据。
比如浏览器发送一个请求:
http://192.168.100.2:8080/index.html
这个请求信息以二进制形式发送010101010100
HTTP服务器很难从二进制数据得到相关信息。
4.网络协议包一组有规律二进制数据,在这组数据存在了固定空间,每一个空间专门存放特点信息,这样解释方在接收网络协议包之后就可以得到固定空间得到对
信息,网络协议包出现极大降低了接收方对接收二进制数据编译难度。
—相当于一个文件包裹,里面有若干空间,特定的数据。
将接收的二进制数据分为若干部门
0000ip地址0000端口号0000资源文件名0000
常见网络协议:
ftp网络协议包
2.http网络协议包

三。http网络协议包:
在基于B/S结构下互联网通信过程中都是保存在HTTP网络协议包
分类:http请求协议包
http响应协议包。
四:http请求协议包与HTTP响应协议包介绍:
1.http请求协议包:
在浏览器准备发送请求时,负责创建一个HTTP请求协议包,浏览器将请求信息以二进制形式
保存在http请求协议包中各个空间,由浏览器负责将HTTP请求协议包推送到指定服务端计算机。
2.http响应协议包:
http服务器在定位到被访问的资源文件之后,负责创建一个HTTP响应协议包。
http服务器将定位文件内容后置文件命令以二进制形式写到HTTP响应协议包各个空间由http服务器负责将http响应协议包推送回发起请求的浏览器上。

***********http请求协议包内部空间:(背)
1.按照自上而下分为四个空间:
2.空间划分:
请求行:{
url请求地址
method:请求方式(post/get)
}
请求头:{
请求参数信息(get)
}
空白行:{
没有任何内容,起到隔离作用
}
请求体:{
请求参数信息(post)看不到
并不是任何时候都有数据的,只有在post提交并且有参数的时候,请求体才有数据,其他情况没有.
}

*****http响应协议包内部结构
1.按照自上而下划分为四个空间。
2.空间划分:{
http状态码
}
响应头{
content-type:指定浏览器采用对应编译器(一般是text)
对响应实体二进制数据进行解析(文字,图片,视频,命令)
}
空白行{
没有任何内容,起到隔离的作用
}
响应体:{
可能被访问静态资源文件内容
可能被访问的静态资源文件命令
可能被访问的动态资源文件}

Http服务器
http服务器可以接收来自浏览器发送的HTTP请求协议包,并自动对HTTP请求协议包内容进行解析
解析后,自动定位内访问的文件,并将指定文件内容写到HTTP请求协议中
最后负责将HTTP响应协议包推送回发起请求的浏览器上。
HTTP服务器分类:
JBOSS服务器
GLASSflsh服务器
Jetty服务器
tomcat服务器–便于安装使用。在自己的电脑上模拟一次互联网的通信。

*tomcat使用
tomcat安装位置/bin C:\Program Files\Apache Software Foundation\Tomcat 9.0
启动命令 startup.bat
关闭命令:shutdown.bat
在系统环境变量中添加 JAVA_HOME 环境变量,变量的值为 JDK的安装目录。
C:\Program Files\Java\jdk1.8.0_131\bin


面试:重载和重写区别
概念:子类继承父类中的方法,想在原有的基础上作一定的修改。

格式特点:

1.方法名、参数列表必须完全一致

2.返回类型可以相同,也可以不同,不同必须是原来返回类型的子类型(可隐式转换即可)JAVA近期版本的新特性,在之前子类返回值类型必须和父类返回值类型保持一致

2.子类抛出的异常下不能超过父类相应方法抛出的异常(子类异常不能大于父类异常)

3.子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)

4.**静态只能重写静态。但是这种情况一般不会出现。

方法重载

概念:在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。

格式特点:

1.方法名相同。

2.方法的参数表必须不同

如果参数个数不同,就不管它的参数类型了!

如果参数个数相同,那么参数的类型必须不同。

3.方法的返回类型、修饰符可以相同,也可不同。
throw和throws的区别
抽象类和接口的区别有:

1、抽象类要被子类继承,接口要被类实现。

2、接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。

3、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

4、接口是设计的结果,抽象类是重构的结果。

5、抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。

6、抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。

7、抽象类主要用来抽象类别,接口主要用来抽象功能。
接口与抽象类区别

在java中还有另一种处理方式就是抛出异常,让调用者进行处理,自己就不再负责了
throws语句

throw是语句抛出一个异常

语法:throw(异常对象);
hrows是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常)

语法:(修饰符)(方法名)([参数列表])[throws(异常类)]{…}
1、throw用在方法体内,上面代码显示了,是直接在main方法体内

throws用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。这个看上面的代码就理解了

2、throw是具体向外抛异常的,抛出的是一个异常实例

throws声明了是哪种类型的异常,使它的调用者可以捕获这个异常

3、throw,如果执行了,那么一定是抛出了某种异常了,安生throws表示可能出现,但不一定。

4、同时出现的时候,throws出现在函数头、throw出现在函数体,两种不会由函数去处理,真正的处理由函数的上层调用处理

好的编程习惯

1、在写程序时,对可能会出现异常的部分通常要用try{…}catch{…}去捕捉它并对它进行处理;

2、如果是系统异常的话可以什么都不用做,也可以针对方法抛出一个异常,但是还是建议针对方法写一个throws
,因为这样在完成一个大型任务的时候可以让别的程序员知道这里会出现什么异常。

1.重载:(背)在JAVA中允许同一个类文件中出现多个方法名相同但是参数列表不同同名方法,这种参数列表不能相同
(个数不同,参数类型不同,参数类型出现顺序)。
重载目的,让方法在接收不同参数实现不同功能。
2.重写
发生在继承过程中子类对父类方法实现细节重新定义。
1)重写方法时,子类不能减低方法访问权限,可以扩大权限。
2)final或者private修饰方法都不能被重写
3)父类方法抛出异常,子类只能比父类的少,甚至可以没有。抛出异常可以是父类方法抛出异常全集,子集,空集
重写方法返回值,可以缩小类型范围,但是不能增加返回类型范围。

throws:声明位置:方法名之后
public void test1() throws NullpointerExeption{
}
2.作用:通知开发人员当前方法在运行时,有可能抛出的异常
3)携带数据 throws后面携带*异常类型),一个throws后面可以携带多个才、异常类型
4)调用:当一个方法被throws修饰时,调用方法必须考虑异常不在问题
2.throw
1)声明位置:方法执行体
public void test(){
throw new RuntimeException();
}
2)作用:throw是一个命令,执行抛出一个指定异常对象。
3)携带数据:throw后面携带(异常对象),一个throw一次只能携带一个异常对象。
4)调用:当一个方法内部在throw命令时,在调用可以不考虑异常捕捉问题。

三.接口与抽象类区别
1.接口:
1)是一个特殊类文件
2)作用:制定规则
降低耦合度
3)使用规则:
接口中属性,默认都是静态常量属性
接口中方法都是抽象,如果需要定义具体实现方法,此时方法需要使用default修饰
接口方法访问权限不能是private
接口与接口之间可以实现多继承,但是接口之间不能互相实现
接口中不存在构造方法
2.抽象类:
1)抽象类由abstract修饰
2)抽象类作用降低接口实现类与接口之间实现难度
抽象类在实现接口时,可以不对接口方法进行重写。
抽象类没有重写的方法必须由抽象类的子类负责实现
写一个接口–接口实现抽象类—类去调用抽象中的方法
3)使用规则:
抽象类可以声明抽象方法,也可以生成具体的方法
抽象类声明接口方法必须对子类进行重写
抽象类实现接口时,不需要对接口方法进行重写
抽象类由构造方法,但是不能使用。

****tomcat
1.安装地址/webapps创建一个网站(myweb)
2.在myweb里面添加一个文件。
3.启动tomcat
4.启动浏览器,命令浏览器向tomcat索要文件
url:(网络协议包://服务器计算机 ip地址:http 服务器端口号/网站名/资源文件名称
http://localhost:8080/myweb/car.jpg

网站内部结构:src文件夹:存放作为动态资源文件的java文件
web文件夹:存放作为静态资源文件(图片,html,css,js)
存放网站运行时依赖的jar,mysql驱动
web-inf :依赖的JAR(mysql驱动,核心配置文件(web.xml)
lib文件:依赖的JAR(mysql驱动)
web.xml通知tomcat当前网站那些java类是动态资源文件。
把网站交给tomcat管理叫做发布

servlet规范介绍:
1.Servet规范来自于javaee规范中的一种
2.作用:
1)在Servlet规范中,指定(动态资源文件)开发步骤–给开发者
2)在Servet规范中,指定HTTP服务器调用动态资源文件规则—给服务器
3)在Servlet规范中,指定HTTP服务器管理动态资源文件实例对象规则。–给服务器

IDEA有两个概念,一个是Project(工程),一个是Module(模块)。

其中,一个模块相当于MyEclipse中的一个项目,也就是一个包。而一个工程就是由多个包组成的整体。

在IDEA中,并没有对Project和Module进行强关联和强约束。主要起到一个项目定义、
范围约束、规范类型的效果。
比如,我接了一个供方系统的工程,这个工程有一个前端的项目包,一个后端的项目包
,也就是两个模块。那么我就会建一个文件夹叫做supplier(供方系统),
然后把前后端的两个项目包都放在这个文件夹中。项目包就叫模块,
整个文件夹就表示一个工程。

鼠标定位到类名称的任意位置,长按Alt+Enter,点击import class即可。

二:servlet接口实现类:
1.Servlet接口来自Servlet规范下一个接口,这个接口在HTTP服务器提供JAR包
2.tomcat服务器下lib文件有一个Servlet-api.jar存放Servlet接口。(javax.servelet.Servlet)
接口。
3.Serlet规范中任务,Http服务器能调用的动态资源文件必须是一个Servlet接口实现类。
三.Servlet接口实现类开发步骤:
第一步:创建一个JAVA类继承与HttpServlet父类,使之成为一个Servlet接口实现类。
第二步:重写HttpSerlet父类两个方法。doget或者dopost。
浏览器—get—oneServlet

接口不能被直接实例化,必须创建一个对象,通过这个对象去调用接口中的方法。
ctrl加O查看重写的方法。
this指向当前对象。new的谁就指谁,没有重写就是父类,重写了就是子类了。
当调用子类对象时,this就是调用子类对象。
通过父类决定在盒子情况下调用子类中的方法(设计模式)。–模板设计模式

父类是为了简化开发难度。

第三步:将servlet接口实现类信息,注册到tomcat服务器
网站->web–>web-inf–>web.xml
将servlet接口实现类类路径地址交给tomcat

mmm 声明一个变量存储servlet接口实现类类路径
com.bjpowernode.controller.oneServlet–声明servlet接口

tomcat string mm=“com.bjpowernode.controller.oneservlet”

mm /one设置简短请求别名,别名在书写时必须以"/"为开头-->]

2020版应该是Compact middle packages查看别叠起来的包。
implement实现接口,必须要实现接口里的所有方法,即重写很多方法,造成开发难度加大。
抽象类作用:降低接口实现类对接口实现过程难度
将接口中不需要使用抽象方法教给抽象类进行完成
这样接口实现类只需要对接口需要的方法进行重写
接口不可以实现接口的,这样会有语法错误的。这是Java语法规定,抽象类可以实现接口,但是接口不能实现接口。
每个类最多可以extends一个类,但可以implements多个接口。
接口最多可以extends一个接口,不可以implements接口。
extends是延伸的意思

extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,JAVA中不支持多重继承,但是可以用接口来实现,这样就要用到implements,继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了
比如
class A extends B implements C,D,E

对于class而言,extends用于(单)继承一个类(class),而implements用于实现
一个接口(interface)。
interface的引入是为了部分地提供多继承的功能。

在interface中只需声明方法头,而将方法体留给实现的class来做。
这些实现的class的实例完全可以当作interface的实例来对待。
在interface之间也可以声明为extends(多继承)的关系。
注意一个interface可以extends多个其他interface。

tomcat根据serlvet对象调用service方法处理当前请求。

oneServlet ---->abstract)httpswevlet–>(adstract)genericservelt implement servlet
init
destroy
getServletInfo
getServletconfig
servlet oneServlet=new oneServlet();
oneservlet.service();

抽象类帮助我们去简化开发。

servlet对象生命周期
1.网站所有的Servlet接口实现类的实例对象,只能由http服务器负责创建
开发人员不能收到创建servlet接口实现类的实例对象。
2.在默认的情况下,http服务器接收到对于当前servlet接口实现类第一次请求时自动创建
这个servlet接口实现类的实例对象。
在收到配置情况下,要求http服务器在启动时自动创建Servle接口实现类的实例对象。

mm
com.XXX.xXX
30
3.在HTTP服务器运行期间,一个Servlet接口实现类只能被创建出一个实例对象。
4.在http服务器关闭时刻,自动将网站中所有的Servlet对象进行销户。

四:HttpServleResponse接口
1.介绍:
1)HttpServletResponse接口来自于Servlet规范中,在Tomcat中存在servlet-api.jar
2)HttpServletResponse接口实现类由Http服务器负责提供
3)HttpServletResponse接口负责将doget/dopost方法
4)开发人员习惯于将HttpServletsponse接口修饰的对象称为(响应对象)

2.主要功能:
1)将执行结果以二进制形式写入到响应体
2.设置响应头中conetent-type属性值,从而控制浏览器使用对应编译器将响应头二进制数据编译为文字,
图片,视频,命令
3)设置响应头中(location)属性,请求一个地址赋值给location。从而控制浏览器向指定服务器发送请求。
off表示离开的

五。HttpServletRequest接口
1.介绍:
1)HttpServletRequest接口来自Servlet规范中,在Tomcat中存在servlet-api。jar
2)HttpServletRequest接口实现类由Http服务器负责提供。
3)HttpSerletRequest接口负责在doGet/doPost方法运行时读取Http请求协议包中信息。
4)开发人员习惯于将HttpServletRequest接口修饰的对象称为请求对象。

2.作用:
1)可以读取Http请求协议中(请求行)信息
2)可以读取保存在Http请求协议包中(请求头)或请求体中的信息。
3)可以代替浏览器向Http服务器申请资源文件调用。

String和StringBuffer他们都可以存储和操作字符串,即包含多个字符的字符串数据。
 String类是字符串常量,是不可更改的常量。而StringBuffer是字符串变量,它的对象是可以扩充和修改的。
URL:统一资源定位符 (URL是Uniform Resoure Locator(统一资源定位器)的缩写。就是WWW页的地址。)
URL一般由三个部分构成 :
1. 服务器标识符 通过选择服务器标识符能够确定将要访问的服务器的类型
2. 信息资源地址 信息资源地址是由两部分构成的,一是机器名称
3. 路径名 路径名是给出资源在所在机器上的完整文件名,一般情况下只有用户知道所要找的资源在什么地方时才会给出这个选项。
URI:通用资源标志符 (Web上可用的每种资源 - HTML文档、图像、视频片段、程序等 - 由一个通过通用资源标志符(Universal Resource Identifier, 简称"URI")进行定位。)
URI一般由三部分组成:
  访问资源的命名机制。
  存放资源的主机名。
  资源自身的名称,由路径表示。

public class Request implements HttpServletRequest {
//…请求对象的由来
}

如果浏览器以get方式发送请求,请求参数保存在请求头中,在http请求协议到达http服务器之后,进行解码,
请求体二进制内容由tomcat负责解码,默认使用utf-8
如果浏览器以post方式发送请求,请求参数保存在请求头中,在http请求协议到达http服务器之后,进行解码,
请求体二进制内容由request负责解码,默认使用iso-8859-1
解:在post请求下,在读取内容之前,应该通知请求对象使用utf-8字符集对请求体内进行解码

六:请求对象和响应对象生命周期
1.在Http服务器接收到浏览器发送的http请求协议包之后,自动为当前的(http请求协议包生成
一个请求对象和一个响应对象
2.在http服务器调用doget/dopost方法时,负责将请求对象和响应对象作为实参传递到方法,
确保doget/dopost正确执行。
在http服务器准备推送http响应协议包之前,负责将本次请求关联的请求对象和响应对象销毁
(请求对象)和(响应对象)生命周期贯穿一次请求的处理过程中。相当于用户在服务端的代言人。

*****建的如果是java项目,只需要引入mysql-connector-java-5.1.10-bin.jar就可以运行java项目。
建的如果是web工程,当Class.forName(“com.mysql.jdbc.Driver”);时,Eclipse是不会去查找字符串
,不会去查找驱动。所以需要把mysql-connector-java-5.1.10-bin.jar拷贝到tomcat下lib目录下,然后
键【工程】,点击【properties】,然后点击【Java Build Path】,点击【Add External Jars…】,
从tomcat下lib目录中选择对应的mysql-connector-java-5.1.10-bin.jar,然后点击【OK】即可。

浏览器三要素,请求地址,请求方式,请求参数。
登录:

用户名:(type=text,name=username) 密码:(type=password name=password)

2010-06-29 回答
实体类,主要是作为数据管理和业务逻辑处理层面上存在的类别。
它的主要职业是存储和管理系统内部的信息,它可以在抽象类的基础上进一步定义具体的类。
相当余数据的中转站!

登录流程:
浏览器:

发送请求包,三要素:url:/myweb/user/login 方法method="post",参数username=x,userassword=y 发送给tomcat服务器 tomcat对数据进行解析调用swrvlet 告诉提交到哪个servlet处理 登录有username,userpassword两个值 servlet设置两个变量 String username,userpassword; 用来接收浏览器值的语句: username=request.getParameter("username"); userpassword=request.getParameter("userpassword"); 调用userDao的login方法 result=dao.login(username,userpassword); 将处理结果返回给result userDao 的login方法获得这两个值之后 写sql语句 String sql="select count(*) from user where username=? and userpassword=?"; 然后和mysql服务器连接,形成一个通道 PreparedStatement ps=util.createStatement(sql); 对sql语句的?进行填充 ps.setString(1,username); ps.setString(2,userpassword); 将loginsvlet传过来的两个参数传进去 使用 rs=ps.executeQuery();语句将sql命令推送给mysql服务器 next语句对mysql表中的数据进行一次扫描并获得coun(*)的值返回给变量result while (rs.next()){ result=rs.getInt("count(*)"); util.close();断开与mysql的联系 return result;返回一个结果给调用这个方法的servlet servelt对获取的结果进行一次判断,跳转到不同的浏览器地址 if(result==1){ response.sendRedirect("/myweb/index.html"); } else { response.sendRedirect("/myweb/login_error.html"); }
servlet是Java Servlet的简称,称为小服务程序或服务连接器,
用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。

Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

七:欢迎资源文件
默认欢迎资源文件:
用户发送一个针对某个网站的默认请求时,由http服务器自动从当前网站返回的资源文件。
tomcat默认请求列表:
index.html,index.htm,index.jsp.
如果都没有那么就会返回一个404
设置当前网站的默认欢迎资源文件规则:
位置:网站/web/web-inf/web.xml

<welcome-file-list>

    <welcome-file>login.html</welcome-file>
    <welcome-file>user/find</welcome-file>
    <!--servlet作为默认资源文件时/要抹掉 -->
</welcome-file-list>

八:Http状态码
1.介绍:
1)由三位数字组成的一个符号。
2)Http服务器在推送响应包之前,根据本次请求处理情况
将Http状态码写入到响应包中(状态行)之上
3)如果Http服务器针对本次请求,返回了对应的资源文件。
通过Http状态码通知浏览器应该如何处理这个结果。
如果Http服务器针对本次请求,无法返回对应的资源文件
通过Http状态码向浏览器解释不能提供服务的原因
2.分类
1)组成 100---599,分为5个大类
2)1xx:最有特征100;通知浏览器本次返回的资源文件并不是一个独立的资源文件,
需要浏览器在接收响应包之后,继续向Http服务器索要依赖的其他资源文件
3)2xx:

最有特征200,通知浏览器本次返回的资源文件是一个完整独立资源文件,浏览器在接收到之后不需要其他关联文件
4)3xx:
最有特征302资源文件,通知浏览器本次返回的不是一个内容,而是一个资源文件地址,
需要浏览器根据这个地址自动发起请求索要这个资源文件
response.sendRedirect(“资源文件地址”)写入到响应头中location而这个行为导致tomcat将302状态码
String address=“http://www.baidu.com”;
respone.sendRedirect(address);
//tomcat在推送响应包之前,看到响应体是空,但是响应头location却存放了一个地址。
//此时Tomcat将302装药码写入到状态行
//在浏览器接收到响应包之后,因为302状态码,浏览器不会读取响应体内容,自动根据响应头
中location的地址发起第二次请求。
5)4xx:通知浏览器,由于在服务的没有定位到访问的资源文件,因此无法提供帮助
405:通知浏览器,在服务的已经定位到被访问的资源文件(servlet),但是这个servlet对于浏览器采用的请求方式不能处理。
6)5xx:
500:在服务的已经定位到被访问的资源文件(servlet),这个servlet可以结束浏览器采用请求方式
,但是servlet在处理请求期间,由于java异常导致处理失败。

就是一个指针是空指针,你还要去操作它,既然它指向的是空对象,它就不能使用这个对象的方法。比如上面的s假如为null,你还要用s的方法,比如s.equals( String x);那么就会产生空指针异常。
产生空指针异常的原因:
(1) 当一个对象不存在时又调用其方法会产生异常    obj.method() // obj对象不存在 
(2) 当访问或修改一个对象不存在的字段时会产生异常    obj.method()  // method方法不存在

Integer b=null;高级引用类型可以赋值为NULL
int b=null;不行
空指针异常

九:多个servlet的调用规则。
1.前提条件:
某些来自于浏览器发生请求,往往需要服务端中多个servlet协同处理。
但是浏览器一次只能访问一个Servlet,导致用户需要手动通过浏览发起多次请求才能得到服务。
这样增加用户获得服务难度,导致用户放弃访问当前网站。
2.无论本次请求涉及到多少和Servlet,用户只需要手动通知浏览器发起一次请求即可
3.多个servlet之间调用:
1)重定向解决方案
2)请求转发解决方案。

十:重定向解决方案:1.工作原理:用户第一次通过(手动方式)通知浏览器访问oneservlet。oneservlet工作完毕后,将Twoservlet地址
写入到响应头location属性中,导致tomcat将302状态码写入到状态行中。
在浏览器接收到响应头中location属性地址发起第二次请求,访问twoservlet去完成请求中剩余任务
2.实现命令:
resopnse.sendRedirect(“请求地址”)
将地址写入到响应包中响应头中location属性
3.特征:
1)请求地址:既可以把当前网站内部的资源文件地址发生给浏览器(/网站名/资源文件名)
也可以把其他网站资源文件地址发生给浏览器(“http://ip地址:端口号/网站名/资源文件名”)
2)请求次数
浏览器至少发送两次,但只有第一次请求是用户手动发送。后续请求都是浏览器自动发送的。
3)请求方式:
重定向解决方案中,通过地址栏通知浏览器发起下一次请求,因此通过重定向解决方案调用资源文件接收的请求
一定是get

缺点:重定向解决方案需要在浏览器与服务器之间进行多次往返
,大量时间消耗在往返次数上,增加用户的等待服务时间。

十一:请求转发解决方案:
1.原理:用户第一次通过手动方式要求浏览器访问哦呢Servlet。oneServlet工作完毕后,
通过当前的请求对象代替浏览器向tomcat发生请求,申请调用twoservlet。tomcat在接收到
这个请求之后,自动调用twoservlet来完成剩余任务。

2.实现命令:请求对象代替浏览器向tomcat发生请求
//1.通过当前请求对象生成资源文件申请报告对象
requestDispatcher report=request.getRequestDisqpatcher(“/资源文件名”)
//2.report.forward(当前请求对象,当前响应对象).

3.优点:1)无论本次请求涉及到多少个servlet,用户只需要手动通过浏览器发送一次请求。
2)servlet之间调用发生在服务端计算机上,节省服务端与浏览器之间往返次数,增加处理服务速度。

4.特征:
1)请求次数
在请求转发过程中,浏览器只发送一次请求。
2)请求地址
稚嫩向Tomcat服务器申请调用当前网站下资源文件地址
request。getRequestDispathcer(“资源文件名”)不能写网站名
3)请求方式:
在请求转发的过程中,浏览器只发送了一个Hyyp请求协议包。
参与本次请求的所有Servlet共享同意个请求协议包,
因此这些Servlet接收的请求方式与浏览器发送的请求方式保持一致。

面试:原理和流程。

十三:ServletContext接口:
1.介绍:
1)来自于Servlet规范中一个接口,在Tomcat中存在servlet-api.jar
在tomcat中负责提供这个接口实现类
2)如果两个Servlet来自于同一个网站,彼此之间通过ServletContext实例对象实现数据共享。
2.工作原理:
每一个网站都存在一个全局作用域对象,
这个全局作用域对象相当于一个map。在这个网站中oneservlet可以将一个数据存放到全局作用域对象,
当前网站中其他servlet此时都可以从全局作用域对象得到这个数据进行使用。
3.全局作用域对象生命周期:
1)在http服务器启动过程中,自动为当前网站在内存中创建一个全局作用域对象。
2)在Http服务器运行期间时,一个网站只有一个全局作用域对象
3)在Http服务器运行期间,全局作用域对象一直处于存活状态
4)在Http服务器准备关闭时,负责将当前网站中全局作用域对象进行销毁处理
全局作用域对象生命周期贯穿整个运行期间
4.命令实现:同一个网站oneservlet将数据共享给TWOservlet
oneservet{
public void doget(HttpServletRequest request,HttpServletResponse response){
//1.通过(请求对象)向tomcat索要当前网站中全局作用域对象
ServletContext application=request.get.ServletContext();
//2.将数据添加到全局作用域对象作为(共享数据)
application.setAttribute(“key1”,数据)
}
}
twoServlet{
public void doget(HttpServletRequest request,HttpServletResponse response){
//1.通过(请求对象)向tomcat索要当前网站中全局作用域对象
ServletContext application=request.get.ServletContext();
//2.从全局作用域对象得到指定关键字对应数据
Ovject 数据=application.getAttribute(“key1”);
}
}
java.util 中的集合类包含 Java 中某些最常用的类。最常用的集合类是 List 和 Map。
Map 提供了一个更通用的元素存储方法。Map 集合类用于存储元素对(称作“键”和“值”),
其中每个键映射到一个值。

十四。Cookie
1.介绍:
1)Cookie来自于Servlet规范中一个工具类,尊在域Tomcat提供servlet-api。jar中
2)如果两个Servlet来自于同一个网站,并且为用一个浏览器/哟过户提供服务
可借助与Cookie对象进行数据共享。
3)Cookie存放当前用户私人数据,在共享数据过程中提高服务质量。
4)在现实生活当中,Cookie就像用户在服务端得到一张会员卡。

2.用户通过浏览器第一次向Myweb网站发送请求申请OneServlet。
oneServlet在运行期间创建一个Cookie存储与当前用户相关数据,oneServlet工作完毕后,将Cookie写入到响应头交还给当前浏览器。
浏览器收到响应响应包之后,将Cookie存储在浏览器的缓存一段时间之后,用户通过同一个浏览器再次向myweb网站发送请求申请twoServlet
浏览器需要无条件的将myweb网站之前推送过来的Cookie。写入到请求头中发送过去
此时twoServlet在运行时,就可以通过读取请求头中Cookie中信息,得到oneservlet提供的共享数据。

3.实现命令:同一个网站oneserlvet与twoservlet借助于cookie实现数据共享
oneServlet{
public void doget(HttpServletRequest request,HttpServletResponse response){
//1.创建一个cookie对象,保存共享数据(当前用户数据)
Cookie card=new Cooke(“key1”,abc);
Cookie card=new Cooke(" key2"efg);
//cookie相当于一个MAP
//一个cookie中只能存放一个键值对
//这个键值对的key于value只能是String
//键值对中key不能是中文
//2.发卡,将cookie写入到响应头,交给浏览器。
resp.addCookie(card);
resp.addCookie(card1);
}
}

浏览器/用户 —响应包(200)
(cookie:key1=abc)
()
(处理结果)
浏览器向MYWEB发送请求访问TwoServlet–请i去包(url:/mtweb/two method:get)(请求参数:xx
cookie:xxx(key1=abc,key2=efg))
()
()
twoServlet{
public void doget(HttpServletRequest request,HttpServletResponse response){
//1.调用qin跪求对象从请求头得到浏览器返回的Cookie
Cookie cookieArray[]=request.getCookies();
//2.循环便利数据得到没医德cookie的key与value
for(Cookie card:cookieArray){
}
String key=card.getName();//读取key “key1"
String value= card.getValue();

提供较好的服务
}
}

4.cookie销毁时机:
1.在默认情况下,cookie对象存放在浏览器的缓存中,因此只要浏览器关闭就清空cookie。
2.在手动设置情况下,可以要求浏览器将接收的Cookie存放在客户端计算机硬盘上,同时需要指定Cookie在硬盘上存货时间。
在存活范围内,关闭浏览器关闭客户端计算机,关闭服务器,都不会导致Cookie被销毁。在存活时间到达时,Cookie自动从硬盘上被删除。
cookie.setMaxAge(60);
例如:card.cookie.setMaxAge(60);

十五:HttpSession接口:1.介绍:
1)HttpSession接口来自于Servlet规范下一个接口。存在于Tomcat中Servlet-api.jar
其实现类由Http服务器提供。Tomcat提供实现类存在于servlet-api.jar
2)如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时借助于HttpSession对象进行数据共享。

3)开发人员习惯于将HttpSession接口修饰对象称为会话对象。

2.HttpSession与Cookie区别:
1)存储位置不同:一个在天上,一个在地下
Cookie:存放在客户端计算机(浏览器内存/硬盘)
HttpSession:存放在服务端计算机内存
2)数据类型:
Cookie对象存储共享数据类型只能是String
HttpSession对象可以存储任意类型的共享数据Object
3)数据数量:一个Cookie对象只能存储一个共享数据
HttpSession使用map集合存储共享数据,所以可以存储任意数量共享数据。
4)参照物:Cookie相当于客户在服务端(会员卡)
HttpSession相当于客户在服务端(私人保险柜)

****使用 接口 对象名 = new 类名 的方式实例化的对象只能调用接口中有的方法,
而不能调用类中特有的方法。
而使用 类名对象名 = new 类名 的方式创建出来的对象可以调用所有的方法。


3.命令实现:同一个网站下OneServlet将数据传递给TwoServlet

oneServlet{
public void doGet(HttpServletRequest request, HttpServletResponse response){
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜;
HttpSession session=request.getSession();
//2.将数据添加到用户私人储物柜
session.setAttribute(“key1”,共享数据)
}
}

twoServlet{
public void doGet(HttpServletRequest request,HttpServletResponse reponse){
//1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜
HttpSession session=request.getSession();
//2.从会话做同于对象得到OneServlet提供的共享数据
Object 共享数据=session.getAttribute(“key1”);
}
}

类里面的方法是静态的,则不需要实例化,
若类里面的方法是普通的公有方法则需要先实例化类然后才可以调用方法

4.Http服务器如何将用户与HttpSession关联起来
Cookie,自动创建一个唯一ID

5.getSession()与getSession(false)
1)getSession():如果当前用户在服务端已经拥有了自己的私人储物柜。
要求tomcat将这个私人储物柜进行返回
如果当前用户在服务端尚未拥有自己的私人储物柜
要求Tomcat为当前用户创建一个全新的私人储物柜。
2)getSession(false):如果当前用户在服务端已经拥有了自己的私人储物柜。
要求tomcat将这个私人储物柜进行返回
如果当前用户在服务端尚未拥有自己的私人储物柜
Tomcat将返回NULL。

6.HttpSession销毁时机:
1.用户与HttpSession关联时使用的Cookie只能存放在浏览器缓存中。
2.在浏览器关闭时,以为着用户与呀的HttpSession关系被切断。
3.由于Tomcat无法检测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器关联的HttpSession进行销毁
4.为了解决这个问题,Tomcat为每一个HttpSession对象设置空闲时间
这个空闲时间默认30分钟,如果当前HttpSession,此时Tomcat就会销毁掉这个HttpSession

7.HttpSession空闲时间手动设置
在当前网站/web/WEB-INF/web.xml

5

Integer goodsNum=(Integer)session.getAttribute(goodsname);
System.out.println(goodsname);
//不能加"",不加=貌似没接收参数,就会报错,加了就表示输出或者赋值

十六.HttpServletRequest接口实现数据共享
1.介绍:
1)在同一个网站中,如果两个Servlet之间通过(请求转发)方式进行调用,
彼此之间共享同一个请求协议包,而一个请求协议包只对用一个请求对象
因此Servlet之间共享用一个请求对象,此时可以利用这个请求对象在两个Servlet之间实现数据共享
2)在请求对象实现Servelt之间数据共享功能时,开发人员将请求对象称为(请求作用于对象)

2.命令实现:
oneServlet通过请求转发申请调用TwoServlet时,需要给TwoServlet提供共享数据
OneServlet{
public void doGet(HttpServletrequest request,HttpServletresponse response){
//1.将数据添加到(请求作用域对象)中attribute属性
req.setAttribute(“key1”,数据);//数据类型可以任意类型object
//2.向Tomcat申请调用TwoServlet
req.getRequestDispatcher(“/two”).forward(req,response)
}
}
TwoServlet{
public void doGet(HttpServletrequest request,HttpServletresponse response){
//从当前请求对象得到OneServlet写入到共享数据
object 数据=req.getAttribute(“key1”);
}
}

十七。Servlet规范扩展----监听器接口

1.介绍:
1)一组来自于Servlet规范下接口。共有8个接口。在Tomcat存在servlet-api。jar包
2)监听器接口需要由开发人员亲自实现,Http服务器提供jar并没有对应实现类。
3)监听器接口用于监控(作用于对象生命周期变化时刻)以及(作用域对象共享数据变化时刻)

2.作用于对象:
1)在Servlet规范中,任务在服务端内存中可以在某些条件下为两个Servlet之间提供数据共享方案
的对象,被称为(作用于对象)
Cookie存在客户端不是作用域对象
2)Servlet规范下作用域对象:
ServletContext:全局作用域对象
HttpSession:会话作用域对象
HttpServletRequest:请求作用域对象。

3.监听器接口实现类开发规范:三步
1)根据监听的时机情况,选择对应监听器接口进行实现
2)重写监听器接口声明(监听事件处理方法)
3)在web.xml文件将监听器接口实现类注册到Http服务器

4.ServletContextListener接口:
1)作用:通过这个接口合法的检测全局作用域对象呗初始化时刻以及被销毁时刻
2)监听事件处理方法:
public void contextInitzed():在全局作用域对象被Http服务器除数化被调用
public void contextDestory():在全局作用域对象呗Http服务器销毁时触发调用

5.ServletContextAtterbuteListener接口:
1)作用:通过这个接口合法的检测全局作用域对象共享数据变化时刻
2)监听事件处理方法:
public void contextAdd();在全局作用域对象添加共享数据
public void contextReplaced();在全局做用域对象更新共享数据
public void contextRemove();在全局作用域对象删除共享数据

6.全局作用域对象共享数据变化时刻
ServletContext application=request.getServletContext();
application.setAttribute(“key1”,100);//新增共享数据
application.serAttribute(“key1”,200);//更新共享数据
application.removeAttribue(“key1”)//删除共享数据

十八:Servlet规范扩展—Filter接口(过滤器接口)
1.介绍:
1)来自于servlet规范下接口,在Tomcat中存在于servlet-api-jar包
2)Filter接口实现类由开发人员负责提供,Http服务器不负责提供
3)Filter接口在Http服务器调用资源文件之前,对Http服务器进行拦截。

2.具体作用:
1)拦截Http服务器,帮助Http服务器检测当前请求合法性
2)拦截Http服务器,对当前请求进行增加操作

3.Filter接口实现类开发步骤:三步
1)创建一个Java类实现Filter接口
2)重写Filter接口doFilter方法
3)web.xml将过滤器接口实现类注册到Http服务器。、
com.bjpowernode.Filter
来自于servletapi以javax开头。

关键字extends,表示对父类的继承,可以实现父类,也可以调用父类初始化。
而且会覆盖父类定义的变量或者函数。在 Java 中,类的继承是单一继承,也就是说,
一个子类只能拥有一个父类,所以 extends 只能继承一个类。
关键字implements是一个类,实现一个接口用的关键字,它是用来实现接口中定义的抽象方法。实现一个接口,必须实现接口中的所有方法。使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
还有几点需要注意:
(1)接口可以被多重实现(implements),抽象类只能被单一继承(extends)
(2)接口只有定义,抽象类可以有定义和实现
(3)接口的字段定义默认为:public static final, 抽象类字段默认是"friendly"(本包可见)

onefilter com.bjpowernode.filter.onefilter onefilter /vv.jpg /*通知tomcat在调用所有资源文件之前,都调用这个filter public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //1.通过拦截请求对象得到请求参数信息,从而得到来访问用户的真实年龄 String age= servletRequest.getParameter("age"); //2.根据年龄,帮助Http服务器判断本次请求的合法性 if(Integer.valueOf(age)<70){ filterChain.doFilter(servletRequest,servletResponse); } else{ servletResponse.setContentType("text/html;charset=utf-8"); PrintWriter out= servletResponse.getWriter(); out.print("年龄太大,拒绝访问"); }
   **拦截器可以对请求对象进行增强。
   网站发起一次默认请求时就调用这个过滤器,以post发送请求时
   、
   4.Filter拦截地址格式
   1)命令格式:<filter-mapping>
   <filter-name>oneFilter</filter-name>
   <url-pattern>拦截地址</url-pattern>
   </filter-mapping>
   2)命令作用:
   拦截地址通知Tomcat在调用何种资源文件之前需要调用OneFilter过滤进行拦截
   3)要求Tomcat在调用某一个具体文件之前,来调用OneFilter拦截
   <url-pattern>/img.jpg<url-pattern>

//练习使用
4)要求Tomcat在调用某一个文件夹下所有的资源文件之前来调用,来调用oneFilter拦截
/img/
5)要求Tomcat在调用任意文件夹下某种类型文件之前,来调用oneFilter拦截
.jpg
6)要求Tomcat在调用网站中任意文件时,来调用OneFilter拦截
/*

***过滤器防止用户恶意登录
1.采用令牌机制(有Session时给与访问后面的内容)
if(result==1){//用户存在
//判断用户身份合法后,用过请求对象向Tomcat申请为当前用户申请一个HttpSession
HttpSession session=request.getSession();

//所要当前用户在服务端HttpSession
HttpSession session=request.getSession(false);
if (session == null) {
response.sendRedirect(“/myweb/login_error.html”);
}
缺点:1.增加开发难度
2.不能对静态资源文件保护

强转
HttpServletRequest request=(HttpServletRequest)servletRequest;
HttpSession session=request.getSession();
if(session==null){
request。getRequestDispatecher(“/login_error.html”).forword(servletRequest,servletResponse);
return;
}else{
filterChain.dofilter(servletRequest,servletResponse);
}

//取消login的过滤
//1.调用请求对象读取请求包中请求行中uri,了解用户访问的资源文件是谁。
//String uri=request.getRequesURI();
/网站资源/资源文件名 /myweb/login.html or /myweb/login or…)
Httpsession session=null;
indexof(uri)//indexof返回字符串第一次出现的位置;
//2.如果本次请求资源文件与登录相关(login.html 或则(loginServlet)此时无条件放行
if(uri.indexOf(“login”)!=-1||“/myweb/”.equals(uri)){//判断有没有数据-1
filterChain.dofilter(servletrequest,sevletreponse);
return;
}
//3.如果本次请求访问的是其他资源文件,需要得到用户在服务端HttpSession
session=request.getSession(false);
if(session==null){
filterChain.dofilter(servletRequest,servletReponse);
return;
}
//4.拒绝请求
request。getRequestDispatcher("/login_error.html).forward(servletRequest,sevletReponse);

****jsp
jsp规范:javaee规范中的一种
jsp规范制定了如何开发jsp文件代替响应对象将处理结果写入到响应体的开发课程。
jsp规范制定了Http服务器应该如何调用管理JSP文件。

2.响应对象的弊端
适合将数据量较少的处理结果写入到响应体
如果处理结果数量过多,使用响应对象增加开发难度

3.jsp是响应对象的代替品
web文件夹下
在服务端自动执行,写入到响应体中,帮助写入响应头中
直接在jsp文件中写java命令,不能被jsp文件识别,只会被当做字符串写入到响应体中
//在jsp文件中,只有书写在执行标记中内容才会被当做java命令。
<%
//1.声明java变量
//2.声明运算表达式,是数学运算,关系运算,逻辑运算。
int num3=num1+num2;
int num4=num2>=num1?num2:num1;
boolen num5=num2>200 &&num1>=100;
//控制语句
%>

变量num1的值:<%=num1%>

alt加回车导包
<%@ page import=“java.util.List”%>
在jsp中所有的执行标记当作一个执行语句块。
嵌套的标签会被当作out.print
<%<if()>{
%>
xxx
<%}else
%>

jsp内置对象:
jsp文件内置对象:request
类型:HttpServletRequest
作用:在jsp文件运行时读取请求包信息
与servlet在请求转发过程中实现数据共享
浏览器:http://localhost:8080/myweb/request.jsp?useName=allen&password=1233
//在jsp文件执行时,借助于内置request对象读取请求包参数信息
<%String userName=request.getParameter(“useeName”);
String password=request.getparamater("password);
%>
来访用户姓名:<%=userName%>
来访用户密码:<%=password%>

session_1.jsp

<%//HttpSession session=request.getSession();
session.getAttribute(“key1”,200);
%>
session_2.jsp
session_1.jsp与session_2.jsp为同一个用户/浏览器提供服务
<%Integer value=(Integer)session.getAttribute(“key1”)
%>
session读取到的数据:<%=value%>

<ServletContext application:全局作用域对象
同一个网站中Servlet与JSP,都可以通过当前网站的全局作用域对象实现数据共享
jsp文件内置对象:application>
<%application.setAttribute(“key1”,“hello world”);

oneServleta
HttpContext application=request.getSevletContext();
String value=(String)application.getAttribute(“key1”);
System.out.println(“value”,value);

Servlet与jsp联合调用分工
Servlet 负责处理业务并得到结果 --厨师
jsp:不负责业务处理,主要任务将Servlet中处理结果写入到响应体–服务员
Servlet与jsp之间调用关系
Servlet工作完毕后,一般通过请求转发方式,向Tomcat申请调用JSP
***request.getRequestDispatcher(/user_show.jsp).fprword(request,response);
告知Tomcat将HttpRequest和HttpResponse交给jsp
Servlet与jsp之间如歌实现数据共享。
Servlet将处理结果添加到请求作用域对象
jsp文件在运行时从请求作用对象得到处理结果。

1、HttpServletRequest——请求对象
HttpServletRequest是生命周期最短的一个对象。
当一个请求送往tomcat时,这个请求就被创建了。当servlet处理完后,产生了响应并且返回给浏览器,则当前请求对象就会被销毁。
可以说request对象是一个瞬时对象,用完就抛弃。
2、HttpSession——用户会话对象
Session对象叫做用户会话对象,用于保存与浏览器窗口所对应的数据。
Session对象是用户第一次发来请求时被创建的,默认情况下如果Session有30分钟没有被访问,那么这个Session对象就会被销毁。
相对来说更加持久的就是HttpSession对象,保存与浏览器所对应的数据、生命周期比request大一些。
误解区:当我们直接关闭浏览器窗口时,Session对象依然存在,只是把浏览器中的Sessionid的cookie给抛弃了。其数据还在tomcat里,默认保留30分钟。
3、ServletContext——Web应用程序全局对象
ServletContext对象解释:Servlet上下文对象,是web应用程序的全局对象。
一个Web应用程序只会创建一个ServletContext对象。
ServletContext随着Web应用程序启动而自动创建、在web应用程序重启或者关闭时会被销毁。
可以说Java Web应用程序的三大作用域对象会伴随着我们的开发从始至终。
请求转发
request.getRequestDispatcher(“跳转路径”)。forward(request,response);
请求重定向
response.sendRedirect(“跳转路径”);


二、作用域对象
1.request作用域,作用范围限于一次请求
request.setAttribute(key, value);
request.getAttribute(key) // ${key}
request.removeAttribute(key);

session作用域,作用范围为一次会话(同一浏览器的多次请求之间)
session.setAttribute(key, value);
session.getAttribute(key) // ${key}
session.removeAttribute(key);

page作用域,作用范围限于当前页面
page.setAttribute(key, value);
page.getAttribute(key) // ${key}
page.removeAttribute(key);

application作用域,作用于整个应用程序
application.setAttribute(key, value);
application.getAttribute(key) // ${key}
application.removeAttribute(key);

${ key } 获取值会从小的作用域向大的作用域依次查找
page < request < session < application
也可以利用前缀精确找到某个作用域:
pageScope page 作用域
requestScope 请求作用域
sessionScope 会话作用域
applicationScope 应用程序作用域

//从请求作用域对象得到oneServlet添加进去的集合
集合用List
List stuList=(List)request.getAttribute(“key”);
for(stuent stu:stuList){
}

集合*
Collection有两个重要的子接口List和Set。List表达一个有序的集合,
List中的每个元素都有索引,使用此接口能够准确的控制每个元素插入的位置。
用户也能够使用索引来访问List中的元素,List类似于Java的数组。
Set接口的特点是不能包含重复的元素。对Set中任意的两个元素element1和element2都有
elementl.equals(element2)= false。另外,Set最多有一个null元素。此接口模仿了数学
上的集合概念。

  • Collection
  1. List

Arraylist:数组(查询快,增删慢 线程不安全,效率高 )
Vector:数组(查询快,增删慢 线程安全,效率低 )
LinkedList:链表(查询慢,增删快 线程不安全,效率高 )
2. Set

HashSet(无序,唯一):哈希表或者叫散列集(hash table)
LinkedHashSet:链表和哈希表组成 。 由链表保证元素的排序 , 由哈希表证元素的唯一性
TreeSet(有序,唯一):红黑树(自平衡的排序二叉树。)

  • Map

HashMap:基于哈希表的Map接口实现(哈希表对键进行散列,Map结构即映射表存放键值对)
LinkedHashMap:HashMap 的基础上加上了链表数据结构
HashTable:哈希表
TreeMap:红黑树(自平衡的排序二叉树)
// 初始化
List list = new ArrayList<>();
// 插入数据
list.add(“hello world 1”);
// 在指定位置插入数据
list.add(0, “hello world 2”);
// 查询数据
String s1 = list.get(0);
// 查询List是否包含指定对象
boolean isContain = list.contains(s1);
// 查询列表的元素个数
int size = list.size();
// 打印list内部元素:
String res = list.toString();

Http服务器调用JSP文件步骤:
1.Http服务器将jsp文件内容(编辑)为一个Servlet接口实现类(.java)
2.Http服务器将Servlet接口实现类编译为class文件(.class)
3.Http服务器负责创建这个class的实例对象,这个实例对象就是Servlet实例对象
4.Http服务器通过Servlet实例对象调用_jspService方法,将jsp文件内容写入到响应体。

Http服务器编辑与编译的jsp文件位置
c:\Users\work\Catalina***
在work文件夹下
C:\Users\安鱼.IntelliJIdea2018.2\system\tomcat
\Unnamed_untitled\work\Catalina\localhost\myweb\org\apache\jsp

int num=100相当于_jspService的局部变量
idea可能会偷懒,找不到文件,可以将jsp文件拖入文件夹中,也可以在Priject Settings
Artifacts中删除再创建

****idea有个datasource可以模拟连接数据库
有表就有实体类,用来存储参数信息。

*使用new关键字实际上做了三件事情:

  1. 与堆栈(栈)处分配一个存储空间保存引用(固定的指针)。
  2. 与堆区分配一片内存空间保存相应类的对象(引用数据类型的对象,如:数组、对象等)。
  3. 将堆区对象的首地址赋予栈区引用。
    注意:使用 new 关键字时会调用类中的构造方法,对于有父类的类会首先调用其父类的构造方法。
    我觉得当你明白new是干嘛的时候, 你就知道什么时候需要new一个对象。
    使用一个类的时候,或者使用类里面的方法、变量等。需要用new

首先,我们通过对实现语句接口的任何对象调用executeQuery()来检索ResultSet。
PreparedStatement和CallableStatement都是语句的子接口:
同样,可以将列的索引号与getX()方法一起使用,
而不是与列名一起使用。索引号是SQL select语句中的列索引编号
如果select语句没有列出列名,
则索引遍号是表中列的序列。列索引编号从1开始:

java.util.*与java.awt.都是java的标准库包,其中表示java.util和java.awt包里的所有类。 她们的不同之处在于java.util.*包含的是一些工具类,如集合类中List、Map、HashMap、Set等,而java.awt.*则封装的是和图形绘制相关的类,如点Point、线Line等。用到相应包里的类时,就会相应import相应的包。
java.awt.List是前台显示用的一个序列 只做显示用
java.util.list是用来存储数据的序列

类名做返回值意思是返回该类的实例对象。便于后续使用该类实例。

比如:

public class MyClass{//定义一个类MyClass
public MyClass getMC(){//方法返回类型是类名
return new MyClass();//返回该类实例
}
}
在使用时就可以
MyClass mc = new MyClass();
MyClass mc2 = mc.getMC();//这里相当于MyClass mc2 = new MyClass();

不同1:
execute可以执行查询语句
然后通过getResultSet,把结果集取出来
executeUpdate不能执行查询语句
不同2:
execute返回boolean类型,true表示执行的是查询语句,false表示执行的是insert,delete,update等等
executeUpdate返回的是int,表示有多少条数据受到了影响

*html
checked 属性规定在页面加载时应该被预先选定的 input 元素。
checked 属性 与 或 配合使用。
checked 属性也可以在页面加载后,通过 JavaScript 代码进行设置。

******EL表达式
EL工具包介绍
1.由java技术开发一个jar包
2.作用降低jsp文件开发时java命令开发难度
3.Tomcat服务器本身自带了EL工具包

当需要外jar包时可以扔到Tomcat jar包文件夹里面
tomcat会自动使用

文件作用:
代替响应对象将Servlet中doGet doPost的执行结果写入响应体中。
一、Object类型

ECMA中的对象其实就是一组数据和功能的集合。对象可以通过执行new操作符后跟要创建的对象类型的名
称来创建。而创建Object类型的实例并为其添加属性和(或)方法,就可以创建自定义对象,这个语法
与Java中创建对象的语法相似。但在ECMA中,如果不给构造函数传递参数,则可以省略后面的
那一对圆括号。

JSP文件中主要开发步骤:
将作用域存放的处理结果读取并写入到响应体
<%
String value=(String)request.getAttribue(“key”);
//无论是request还是response都是放在map集合里面都是Obiect数据类型,需要进行一个强转

%>
<%=value%>
第一步:从指定的作用域对象读取出来结果
第二步:将得到数据进行类型强转
第三步:将转换后的数据写入到响应体


一个横线 学员ID:${applicationScope.sid} 学员姓名:${sessionScope.sname} 学员地址:${requestScope.home}

EL表达式
1.命令格式:${作用域对象别名,共享数据}
2.命令作用:1)EL表达式是EL工具包提供一种特殊命令何时(表达式命令格式)
2)EL表达式在JSP文件上使用
3)负责在JSP文件上从作用域对象读取指定的共享数据并输出到响应体。

二:EL表达式-作用域对象别名
1.JSP文件可以使用的作用域对象
1)ServletContext application:全局作用域对象
2)HttpSession session:会话作用域对象
3)HttpServletRequest request:请求作用域对象
4)pageContext pageContext 当前页作用域对象,这是JSP文件独有的作用域对象,Servlet中不存在
在当前页作用域对象存放的共享数据仅能在在当前JSP文件中使用,不能共享给其他Servlet或者JSP文件中
,在真实开发过程中,主要用于JSTL标签与JSP文件之间数据共享
JSTL----->pageContext---->jsp

2.EL表达式提供作用域对象别名
JSP EL表达式
application ${applicationScope.共享数据名}
session $(sessionScope.共享数据名)
request $(requestScope.共享数据名)
pageContext ${pageScope.共享数据名}

其实类名不是作为数据类型,只能说将这个类的对象作为返回值。意思就是说
这个方法的返回值不是普通的数据类型,而是一个类对象。这样做可以避免一个方法要返回N多的数据,
比如说,你要同一个方法中得到name和age,但是java又不能返回多个值,
除了可以使用一个字符串或者字符串数组存放外,我们可以定义一个Student对象,
对象中包含name和age属性,这样就可以用这个对象把属性封装起来以及方法,一起返回。
//对象的数据类型:
//基本数据类型:int double bool …
//引用数据类型:数组、对象、string
在计算机中,简单类型数据存放在栈(Stack)中
,复杂类型的数据则存放在堆(Heap)中而其Heap地址存放在Stack里。
Stack存放规则是先进后出,就像装东西的桶一样,最后放入的物品取出操作时被最先取出。
Heap则是无序的,存放结构像二叉树。

三:*将引用对象属性写入响应体中
学院编号: r e q u e s t C c o p e . k e y . s i d s i d 来自于 S t u d e n t 类属性名,大小完全一致。 1. 命令格式 : {requestCcope.key.sid}sid来自于Student类属性名,大小完全一致。 1.命令格式: requestCcope.key.sidsid来自于Student类属性名,大小完全一致。1.命令格式:{作用域对象别名.共享数据名.属性名}
2.命令作用:从作用域对象读取指定共享数据管理的引用对象的属性值。
并自动将属性的结果写入到响应体
3.属性名:一定要去引用类型属性名完全一致(大小写)
EL表达式用的是范式机制。
4.EL表达式没有提供遍历集合方法,因此无法从作用域对象读取集合内容输出

四:EL表达式简化版
1.命令格式:${共享数据名}
2.命令作用:EL表达式运行开发人员开发时省略作用域对象别名
3.工作原理:EL表达式简化版由于没有指定作用域对象,索引在执行时采用猜算法
首先到pageContext定位共享数据,如果存在直接读取输出并接受执行
如果在pageContext没有定位成功,到requeset定位共享数据,如果存在直接读取输出并结束
如果在session没有定位成功就到application
如果application没有就返回null
pageContext-request-session-application

4.存在隐患:
容易降低程序执行速度
容易导致数据定位错误
5.应用场景:
设计目的:就是简化pageContext读取共享数据并输出难度

6.EL表达式简化版尽管存在很多隐患,但是在实际开发过程中,开发人员为了节省时间,一般都使用
简化版,拒绝标准版

五:EL表达式—支持运算表达式
1.前提:在JSP文件有时需要将读取共享数据进行一番运算之后,将运算结果写入到响应体

EL表达式计算后的结果: k e y 1 + k e y 2 1 ) 数学运算 2 )关系运算: > > = = = < < = ! = g t g e e q l t l e ! = E L 表达式输出关系运算 {key1+key2} 1)数学运算 2)关系运算:> >= == < <= != gt ge eq lt le != EL表达式输出关系运算 key1+key21)数学运算2)关系运算:>>===<<=!=gtgeeqltle!=EL表达式输出关系运算{age>=18?“欢迎光临”:“谢绝入内”}多个就嵌套
一般只做输出,一般不做负责的判断
3)逻辑运算 && || !

六:EL表达式提供内置对象
1.命令格式:${param.请求参数名}
2.命令作用:从通过请求对象读取当前请求包中请求参数内容并将请求参数内容写入到响应体
3.代替命令:index.jsp
发送请求 :Http://localhost:8080/myweb/index.jsp?userName=mike&password=123
<%
request.getParameter(“user:”)
%>

1.命令格式:${paramValues.请求参数名[下表]}
2.如果作用:如果浏览器发送的请求参数是(一个请求参数关联多个值)
此时可以通过paramValues读取请求参数下指定位置的值
3.代替命令:http://localhost:8080/myweb/index_2.jsp?pageNo=1&pageNo=2&pageNo=3
此时pageNo请求参数在请求包以数组形式存在
pageBo:[1,2,3]
<%
String array=request.getParameterValues(“pageNo”);
%>
第一个值:<%=array[01]%>

七:el表达式场景异常:
javax.el.propertyFoundException

***javaScript
一.介绍
1.JavaScript是一种专门在浏览器编译并执行的编程语言
2.JavaScript处理用户与浏览器之间请求问题
3.JavaScript采用(弱类型编程语言风格)对面向对象思想来进行实现的编程语言

二。弱类型编程语言风格vs 强类型编程语言风格
1.强类型编程语言风格,认为对象行为应该受到其修饰类型严格约束
java采用(强类型编程语言风格)对面向对象思想)来进行实现的编程语言
stu.sid=10;错误,修饰stu对象的student类型没有提供这个方法
2.弱类型编程语言风格:认为对象行为不应该受到其修饰类型约束,
可以根据实际需要来决定对象可以调用属性和方法。
维护麻烦

var stu=new Object();stu对象相当于(阿q)
stu.car=“劳斯莱斯”;合法
stu.play=function(){
return “天天打游戏”}
stu.play();

ar 定义变量!
如var aa=1;
var bb=“字符串”;
说的简单一点点就是定义一个变量.
在java-script中,变量可以用命令Var作声明:
比如 VAR mytest
var mytest=‘this is a book"
就是自定义变量的保留字啊
三:JavaScript中变量声明方式
1.命令格式:var修饰符
var 变量名;
var 变量名=值;
var 变量名1,变量名2=值;
2.注意:
在JavaScript变量/对象,在声明不允许指定修饰类型
只能通过var来进行修饰

radio根据name属性来确定是否为同一组

除了登录判断
获取session都有用getsession(false)

一、什么是泛型?Java泛型设计原则:只要在编译时期没有出现警告,那
么运行时期就不会出现ClassCastException异常.泛型:把类型明确的工作推迟到
创建对象或调用方法的时候才去明确的特殊的类型参数化类型:把类型当作是参数一
样传递<数据类型> 只能是引用类型相关术语:ArrayList中的E称为类型参数变量Arr
ayList中的Integer称为实际类型参数整个称为ArrayList泛型类型整个Array
List称为参数化的类型ParameterizedType二、为什么需要泛型早期Java是使用Ob
ject来代表任意类型的,但是向下转型有强转的问题,这样程序就不太安全首先,我们来试想一
下:没有泛型,集合会怎么样Collection、Map集合对元素的类型是没有任何限制的。本来
我的Collection集合装载的是全部的Dog对象,但是外边把Cat对象存储到集合中,是没有任
何语法错误的。把对象扔进集合中,集合是不知道元素的类型是什么的,仅仅
知道是Object。因此在get()的时候,返回的是Object。外边获取该对象,还需要
强制转换有了泛型以后:代码更加简洁【不用强制转换】程序更加健壮
【只要编译时期没有警告,那么运行时期就不会出现ClassCastException异
常】可读性和稳定性【在编写集合的时候,就限定了类型】2.1有了泛型后
使用增强for遍历集合在创建集合的时候,我们明确了集合的类型了,所以我们可以使用增强for来遍历集合!

遇到的面试题:说说接口中put,get,post

GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,
不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的。
DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。
POST请求同PUT请求类似,都是向服务器端发送数据的,但是该请求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。
几乎目前所有的提交操作都是用POST请求的。
与GET不同的是,PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,
用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。
POST、DELETE、PUT、GET 分别对应着 增----删----改----查

PUT和POST
PUT和POST都有更改指定URI的语义.但PUT被定义为idempotent的方法,POST则不是.idempotent的方法:如果一个方法重复执行

多次,产生的效果是一样的,那就是idempotent的。也就是说:

PUT请求:如果两个请求相同,后一个请求会把第一个请求覆盖掉。(所以PUT用来改资源)

Post请求:后一个请求不会把第一个请求覆盖掉。(所以Post用来增资源)

回到顶部
get和post
1、GET参数通过URL传递,POST放在Request body中。

2、GET请求会被浏览器主动cache,而POST不会,除非手动设置。

3、GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

4、Get 请求中有非 ASCII 字符,会在请求之前进行转码,POST不用,因为POST在Request body中,通过 MIME,也就可以传输非 ASCII 字符。

5、 一般我们在浏览器输入一个网址访问网站都是GET请求

6、HTTP的底层是TCP/IP。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。
但是请求的数据量太大对浏览器和服务器都是很大负担。所以业界有了不成文规定,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)
服务器最多处理64K大小的url。

7、GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

8、在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
但并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值