Servlet

关于系统架构

​ 1.系统架构包括什么形式?

​ C/S 架构

​ Client/Server(客户端 /服务器)

​ 特点:需要安装特定的软件

​ 优点:

​ 速度快(软件中大部分都是集成到客户端软件中的,很少量从服务器端传送过来)

​ 体验好(速度快)

​ 界面酷炫(专门的语言实现,灵活)

​ 服务器压力小

​ 安全(在服务器上有缓存)

​ 缺点:

​ 升级维护差劲(每个客户端都要升级)

​ B/S架构(Browser,浏览器/服务器):

​ 实际上是一个特殊的C/S

​ 优点:

​ 升级维护方便,成本低(只需要升级服务器即可)

​ 不需要安装客户端软件,只需要打开浏览器,输入网址即可

​ 缺点:

​ 速度慢

​ 体验差(只有HTML语言等)

​ 不安全(数据都在服务器上)

BS架构通信原理(没有涉及到java程序)

​ 第一步:输入网址

​ 第二步:域名解析器进行域名解析:http://110.242.68.3:80/index.html

​ 第三步:浏览器软件在网络中搜索110.242.68.3这一台主机,直到找到这台主机

​ 第四步:定位110.242.68.3这台主机上的服务器软件,因为是80端口,可以很轻松的定位到80端口对应的服务器软件

​ 第五步:80端口对应的服务器软件得知浏览器资源想要的有域名是:index.html

​ 第六步:服务器软件找到index.html文件,并且将index.html文件的内容直接响应到浏览器上

​ 第七步:浏览器接收来自服务器的代码(HTML CSS JS)

​ 第八步:浏览器渲染,执行HTML CSS JS代码,展示效果

什么是请求?什么是响应?

​ 从browser端发送到server端,称为请求 request

​ 从server端发送到browser端,称为响应 response

servlet对象的生命周期

  • ​ 我们自己new的Servlet对象,是不受web容器影响的

    • web容器创建的集合对象都会被放到一个集合(hashmap)当中,只有放到这个集合当中的servlet才能够被WEB 容器管理
  • 怎么在服务器在启动的时候创建Servlet对象呢?

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

    • <servlet><servlet-name>aServlet</servlet-name><servlet-class>com.bjpowernode.javaweb.servlet.AServlet</servlet-class><load-on-startup>0</load-on-startup></servlet><servlet-mapping><servlet-name>aServlet</servlet-name><url-pattern>/a</url-pattern></servlet-mapping>
      
  • servlet生命周期

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

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

    • AServlet无参构造方法执行了
      AServlet init服务执行
      AServlet service服务执行
      
    • ​ 根据以上得出结论:

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

    • AServlet service服务执行
      
    • 得出结论

      • 第一:servlet对象是单例的
      • 第二:无参构造方法,init只在第一次用户发送请求的时候执行
      • 第三:只要用户发送一次请求:service方法必然会执行一次请求
    • 关于servlet类中的方法的调用次数:

      • 构造方法只执行一次
      • init方法只执行一次
      • service方法:用户发送一次请求执行一次请求,发送N次执行N次
      • destro方法只执行一次
    • 当我们在servlet中写一个有参构造时,会发生什么?

      • 报错:500
      • 500:服务器内部错误
    • 注意:无参构造方法不能代替init方法!!

      • 原因:Servlet规范中有要求,不建议手动编写构造方法,因为手动编写,容易让无参构造方法消失,可能会导致servlet对象无法实例化,因此init方法有存在的必要
    • 编写一个GenericServlet类,是抽象类,其中的抽象方法为service

      • GenericServlet实现Servlet接口
      • GenericServlet是一个适配器,就是说,后面的只需要去调用GenericServlet即可,不需要去重写方法
      • 以后编写的Servlet类,只需要继承GenericServlet,重写service方法即可

改造GenericServlet类

  • 提供了GenericServlet过后,init还会执行吗?

    • 会执行,会执行GenericServlet类中的init方法

​ !!!!白雪!!!可以直接继承GenericServlet类

ServletConfig

  • 是servlet规范中的一种

  • 谁去实现这个接口?

    • Tomcat服务器去实现
  • 一个Servlet对象中有一个ServletConfig对象

  • ServletConfig对象被翻译为:servlet对象的配置信息对象

    • 一个Servlet就有一个配置信息对象
    • 两个Servlet就有两个配置信息对象
  • ServletConfig对象中包含了那些信息?

    <servlet><servlet-name>configTest</servlet-name><servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class></servlet>
    
    • Tomcat将web.xml文件中的中的配置信息自动封装到ServletConfig对象中

    • ServletConfig接口中哪些方法?

       <servlet><servlet-name>configTest</servlet-name><servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>
      <!--        配置一个Servlet对象的初始化信息--><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><init-param><param-name>user</param-name><param-value>root</param-value></init-param><init-param><param-name>password</param-name><param-value>123123</param-value></init-param></servlet>
      
    • 以上标签中的是初始化参数,初始化参数信息会被Tomcat封装到ServletConfig对象当中

    • servleConfig中有四个方法:

      第一个:

​ public String getInitParameter(String name)

​ 第二个:

​ public Enumeration getInitParameterNames()

​ 第三个:

​ public ServletContext getServletContext()

​ 第四个:

​ public String getServletName();

​ 以上的四个方法,在自己编写的Servlet类当中可以使用this去调用。(这个Servlet继承了GenericServlet)

ServletContext

  • 是什么?

    • ServletContext是接口,是Servlet规范中的一员。
  • 是谁实现的?

    • tomcat服务器实现
  • 谁创建的?什么时候创建的?

    • 在web服务器启动的时候创建
    • 对于一个webAPP来说 ServletContext对象只有一个
    • 在服务器关闭的时候销毁
  • 怎么理解?

    • Servlet对象的环境对象(上下文对象)
    • ServletContext对象其实对应的就是整个web.xml文件
    • 放在ServletContext对象当中的数据,所以Servlet一定是共享的
    • Tomcat是一个容器,一个容器当中可以放多个webapp,一个webAPP对应一个ServletContext对象
    • 一个应用一个webAPP只有一个
  • ServletContext接口中有哪些常用的方法?

    • public String getInitParameter(String name);//通过初始化参数的name获取value
      public Enumeration<String> getInitParameterName(); //获取所有的参数的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.2022-05-07.log  ServletContext对象的log方法记录日志信息存储到这个文件中
      //catalina.2022-05-07.log  服务器端的java程序运行的控制台信息
      //localhost_access_log.2022-05-07.txt 访问日志
      
    • //ServletContext对象还有一个名字(应用域,还有其他域 eg:请求域,会话域)
      //如果所有用户共享一份数据,并且这个数据很少被修改,数据量少可将其放到ServletContext这个应用域中
      //为什么是所有用户共享? 不然无意义
      //为什么是数据量要小? 数据量大会影响内存,性能//为什么说数据量很少修改,或者几乎不修改?
      //所有用户共享的数据必然存在线程安全问题,放在ServletConetext中的数据一般都只是可读的
      //可以大大提升效率//存
      public void setAttribute(String name,Object value); //map.put(k,y)
      //取
      public void getAttribute(String name); //map.get(k)
      //删
      public void remove Attribute(String name); //map.remove(k)
      
    • 注意:以后我们编写Servlet类的时候,实际上是不会去直接继承GenericServlet类的。使用HttpServlet处理协议会更方便

      • jakarta.servlet.Servlet //(接口)  【爷爷】
        jakarta.servlet.GenericServlet //(抽象类)【儿子】
        jakarta.servlet.http.HttpServlet //(抽象类)【孙子】//编写的Servlet要继承HttpServlet
  • 缓存机制

    • 堆内存中的字符常量池

    • 堆内存中的整型常量池

    • 连接池

      • JVM
      • java.sql.Connection
      • 最小连接池
      • 最大连接数
      • 提高访问效率,也可以保证数据库的安全性
    • 线程池

      • tomcat服务器本身支持多线程
      • 不是发一次请求就新建一个线程
    • redis

      • noSql,非关系型数据库,缓存数据库
    • 向ServletContext应用域中存储数据,也等于是将数据放到缓存cache里面去了

HTTP协议

  • 什么是协议?

    • 就是 一套标准的规范
  • 什么是HTTP协议?

    • HTTP协议:W3C制定的超文本传输协议
  • HTTP协议包括?

    • 请求协议

      • 浏览器 向 web服务器发送数据
    • 响应协议
      • web服务器 响应 浏览器发送的数据
  • ​ HTTP请求协议(B->S):

    • 包括四部分:

      • 请求行

        • 包括三部分:

          • 第一部分:请求方式

            • get(常用)
            • post(常用)
            • delete
            • put
            • head
            • options
            • trace
          • 第二部分:URI /servlet05/getServlet
            • 什么是URI:统一资源标识,代表网络中某个资源的名字,但是不能定位
            • 什么是URL:统一资源定位符 ,可以通过URL获得定位到的资源
            • 他俩的区别?
              • URL包括URI
              • http://localhost:8080/servlet05/index.html 这是URL
          • 第三部分:HTTP协议版本号
      • 请求头
        • 请求的主机
        • 请求的端口
        • 浏览器信息
        • 平台信息
        • cookie等的信息
      • 空白行
        • 用来分隔请求头和请求体的
      • 请求体
        • 向服务器发送具体数据
    • HTTP请求具体报文:

      • GET请求:

        • GET /servlet05/getServlet?username=zhangsan&password=123 HTTP/1.1                   请求行
          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
          Accept-Encoding: gzip, deflate, br
          Accept-Language: zh-CN,zh;q=0.9
          Connection: keep-alive
          Cookie: Idea-645b4828=22e7e245-a393-40d2-a134-ac9753082ab2
          Host: localhost:8080                                                                请求头
          Referer: http://localhost:8080/servlet05/
          Sec-Fetch-Dest: document
          Sec-Fetch-Mode: navigate
          Sec-Fetch-Site: same-origin
          Sec-Fetch-User: ?1
          Upgrade-Insecure-Requests: 1
          User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36
          sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"
          sec-ch-ua-mobile: ?0
          sec-ch-ua-platform: "Windows"
          
      • post请求:

        • POST /servlet05/postServlet HTTP/1.1
          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
          Accept-Encoding: gzip, deflate, br
          Accept-Language: zh-CN,zh;q=0.9
          Cache-Control: max-age=0
          Connection: keep-alive
          Content-Length: 40
          Content-Type: application/x-www-form-urlencoded
          Cookie: Idea-645b4828=22e7e245-a393-40d2-a134-ac9753082ab2
          Host: localhost:8080
          Origin: http://localhost:8080
          Referer: http://localhost:8080/servlet05/
          Sec-Fetch-Dest: document
          Sec-Fetch-Mode: navigate
          Sec-Fetch-Site: same-origin
          Sec-Fetch-User: ?1
          Upgrade-Insecure-Requests: 1
          User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36
          sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"
          sec-ch-ua-mobile: ?0
          sec-ch-ua-platform: "Windows"
          
  • HTTP响应协议(S->B):

    • 包括四部分:

      • 状态行

        • 第一部分:协议版本号 HTTP/1.1 200

          • 第二部分:状态码 200 404 405 500等
          • 第三部分:状态的描述信息
            • ok表示结束
            • not found 表示资源找不到
      • 响应头
      • 空白行
        • 用来分隔响应头和响应体的
      • 响应体
    • HTTP响应协议具体报文:

      • HTTP/1.1 200                                                状态行
        Content-Type: text/html;charset=UTF-8                      响应头
        Content-Length: 71
        Date: Sun, 08 May 2022 09:53:49 GMT
        Keep-Alive: timeout=20
        Connection: keep-alive空白行响应体(用"<br>"网页换行)
        wiwiwi         ttttttt     dochin   dfsd55fd5sf d             asd asd s
        
  • 怎么查看协议的内容:

    • 使用谷歌浏览器 :F12 ,找到network
  • GET请求和POST请求的区别?

    • get请求发送数据的时候,数据会挂在URI的后面,并在后面添加了个“?” 后面跟的是数据,发送的数据会回显到浏览器的地址上
    • http://localhost:8080/servlet05/getServlet?username=zhangsan&password=123
    • post发送数据的时候在请求体当中不会回显到浏览器的地址栏上
    • 他们的请求数据格式相同,只是位置不同而已
      • name=value&name=value
      • name是什么?
        • 以form表单为例:name就是form表单input标签当中的name
      • value是什么?
        • 以form表单为例:name就是form表单input标签当中的value
    • get请求只能发送普通的字符串给服务器,并且字符串受浏览器限制
    • post请求可以发送任何类型,包括普通字符串 eg:声音,视频,图片
    • get请求适合从服务器获取数据
    • post请求适合向服务器传送数据
    • get是安全 的
    • post是危险的,如果数据从后门进入到服务器,服务器就会危险
    • get请求支持缓存
      • 任何一个get请求最终的响应结果都会被浏览器缓存起来
    • post请求不支持缓存
  • 什么时候发送GET和POST请求?

    • form表单当中的method=“post‘ 用post
    • 其他所有情况都用GET

模板方法设计模式

  • 什么是设计模式?

    • 某个问题的固定的解决方案(可以被重复使用)
  • 有哪些设计模式?

    • Gof设计模式:

      • 常说的23种设计模式
      • 单例模式
      • 工厂模式
      • 代理模式
      • 门面模式
      • 责任链设计模式
      • 观察者模式
      • 模板方法设计模式
    • JavaEE设计模式:
      • DAO
      • DTO
      • VO
      • PO
      • pojo
  • 什么是模板方法设计模式?

    • 在模板类的模板方法当中定义核心算法骨架,具体的实现步骤延迟到子类当中完成
  • 模板类通常是一个抽象类,模板类当中的模板方法定义核心算法,这个方法通常是final的(也可以不是final类)

  • 模板类当中的抽象方法就是不确定实现的方法,这个不确定实现的事交给子类去做

HttpServlet源码分析

  • HttpServlet类是专门为HTTP协议准备的。比GenericServlet更加适合HTTP协议下的开发。

  • HttpServlet源码分析:

    • public class HelloServlet extends HttpServlet {//用户第一次请求,创建HelloServlet对象的时候,会执行这个无参数构造方法。public HelloServlet(){            }
      public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {}
      }
      //用户第一次请求的时候,HelloServlet对象对象第一次创建之后,这个init方法会执行
      public void init(ServletConfig config) throws ServletException {this.config = config;this.init();}public void init() throws ServletException {}
      
    • 如果前端发的是dopost,而后端是doget方法,那么会报405错误

      • 前后端必须执行同样的方法,也就是doget对应doget dopost对应dopost
    • 怎么避免405错误?

      • 前端发送doget方法,后端必须重写doget方法
      • 前端发送dopost方法,后端也必须重写dopost方法
      • 这两个方法由后端决定
    • 最终的servle类的开发步骤:

      • 第一步:编写一个servlet类,直接继承HttpServlet
      • 第二步:重写doGet方法或者doPost方法,到底重写谁,由程序员说了算。
      • 第三步:将Servlet类配置到web.xml路径当中
      • 第四步:准备前端(form表单),指定请求路径

关于一个web站点的欢迎页面

  • 什么是一个web站点的欢迎页面?

    • 对于一个webapp来说是可以设置欢迎页面的,在没有指定任何资源路径访问的时候,这个时候回默认访问欢迎页面
  • 怎么设置欢迎页面?

    • 第一步: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目录

    • 在webapp的根下新建page2目录

    • 在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-list>
      
    • 注意:越靠上的优先级越高,找不到的继续向下找。都找不到就报404错

  • 为什么当文件名设置为index.html,并且没有在web.xml文件中配置欢迎页面时会默认index?

    • 因为tomcat服务器提前就已经配置好了

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

      • 一个是在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>
          
      • 注意原则:局部优先原则。(就近原则)

  • 欢迎页可以是一个servlet

    • 可以是静态资源,也可以是动态资源

    • 步骤

      • 第一步:写一个servlet:

      • public class WelcomeServlet extends HttpServlet {@Overrideprotected 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>/welcome/ssds/ssss</url-pattern></servlet-mapping>
          
      • 第三步:在web.xml文件中配置欢迎页

        •     <welcome-file-list><!--    路径不要以"/"开始--><welcome-file>welcome/ssds/ssss</welcome-file></welcome-file-list>
          

关于web-INF目录

  • 在WEB-INF下的文件打开浏览器访问会报404错误

    • 因为在WEB-INF目录下的资源是受保护的

HTTPServlet详解

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

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

  • HttpServlet接口的父接口:ServletRequest

    • 面向HttpServletRequest接口编程,调用方法就可以获取到请求的信息
  • request和response对象的生命周期?

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

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

      • String getParameter(String name); //获取这个一维数组当中的第一个元素,这个方法最常用!!!
        Map<String,String[]> getParameterMap();//获取map
        Enumeration<String> getParameterNames();//获取map集合当中所有的key
        String[] getParameterValues(java.lang.String name);//获取map集合当中所有的值
        //以上的四个方法,和获取用户提交的数据有关系
        
      • 注意:前端永远提交的是字符串,后端获取的永远也是字符串

    • request对象实际上又称为“请求域”对象

      • 应用域对象是什么?

        • ServletContext(servlet上下文对象)

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

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

          • 字符串常量池
          • 整数型常量池([-128~127],但凡是在这个范围当中的Integer对象不再创建新对象,直接从这个整数型常量池中获取。大大提升系统性能。)
          • 数据库连接池(提前创建好N个连接对象,将连接对象放到集合当中,使用连接对象的时候,直接从缓存中拿。省去了连接对象的创建过程。效率提升。)
          • 线程池(tomcat服务器支持多线程,提前创建好N个对象,将线程对象存储到集合中,然后用户请求过来,直接从线程池当中获取线程对象,直接拿来用,提升系统性能)
        • 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); // 将域当中绑定的数据移除
              
          • 请求域和应用域的选用原则

            • 尽量使用小的域对象,以为小的域对象占用的资源少
        • 跳转

          • 转发

            • //第一步,获取请求转发
              // 相当于把"/b"这个路径包装到请求转发器当中,实际上是把下一个跳转的资源路径告知给tomcat服务器RequestDispatcher dispatcher = request.getRequestDispatcher("/b");//        第二步,调用请求转发器RequestDispatcher的forward()方法,进行转发,
              //        转发的时候  request  response都要传递给这一个对象dispatcher.forward(request,response);   //两步代码可以连在一起
              request.getRequestDispatcher("/b").forward(request,response);
        • 两个Servlet怎么共享数据?

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

          • 不一定,只要是tomcat合法资源,都可以转发,eg:html
          • 注意:转发的时候,路径的写法要注意,转发的路径以“/”开始,不加项目名。
        • 关于request对象中两个非常容易混淆的方法:

          • //uri?username=zhangsan&userpwd=123&sex=1
            String name = request.getParameter("username");//之前一定是执行过:request.setAttribute("name",new Object())
            //然后才会取数据
            Object obj  =request.getAttribute("name");
            //这两个方法的区别是什么??//第一个方法:获取的是用户在浏览器上提交的数据//第二个方法:获取的是请求域当中绑定的数据
        • HttpServletRequest接口中的其他常用方法:

          • //获取客户端的IP地址String remoteAddr = request.getRemoteAddr();//get请求行上提交数据
            //设置请求体的字符集(post请求的乱码问题,这种方式并不能解决get请求乱码的问题)
            request.setCharacterEncoding("UTF-8");
            //tomcat10过后不用设置,默认就是UTF-8//服务器响应时的乱码问题解决方式
            //tomcat10过后就不需要
            response.setContentType("text/html;charset=utf-8");
            //get请求乱码问题
            //get请求发送请求的时候,数据是在请求行上提交的,不是在请求体上提交的
            //get请求乱码怎么解决?//在Tomcat10文件里面找到这个logging.properties文件进去修改解决java.util.logging.ConsoleHandler.encoding = GBK
            //获取应用的根路径
            String contextPath = request.getContextPath();
            //获取请求方式String method = request.getMethod();//获取请求的URI
            String requestURI = request.getRequestURI();//获取servlet path
            String servletPath = request.getServletPath();
            

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

  • 使用Servlet完成单表【对部门的】的增删改查的操作

  • 实现步骤:

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

      • #部门表
        drop table if exists dept;
        create table dept(
        deptno int primary key,dname varchar(100),loc varchar(100)
        );insert into dept(deptno,dname,loc) values(10,"销售部","北京");
        insert into dept(deptno,dname,loc) values(20,"研发部","上海");
        insert into dept(deptno,dname,loc) values(30,"技术部","广东");
        insert into dept(deptno,dname,loc) values(40,"媒体部","深圳");
        commit;
        select*from deptupdate dept set dname=?,loc=? where deptno=?
        
    • 第二步:准备一套项目页面(项目原型)

      • 将html页面准备好

      • 然后将HTML页面的链接都跑通。(页面流转完成)

      • 应该设计哪些页面?

        • 新增页面 add.html

        • 修改页面 edit.html

        • 详情页面 detail.html

        • 欢迎页面 index.html

        • 列表页面 list.html(以列表页面为核心,展开其他操作)

    • 第三步:分析这个系统包括哪些功能?

      • 什么叫功能?

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

      • 创建一个webapp(给这个webapp导相应要用的jar包)
      • 向webapp添加连接数据库的jar包(mysql驱动)
        • 在WEB-INF下新建lib包,然后将mysql驱动拷贝进去
      • 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;/*** @author:HuangC* @ClassName:DeptListServlet* @Package:com.bjpowernode.oa.web.action.DeptListServlet* @Description:* @CreateDate:2022年05月10日* @Version:1.8**/
          public class DeptListServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {}
          }
      • 第四:在DeptListServlet类中的doGet方法中连接数据库,查询所有的部门,动态的展示部门列表页面

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

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

        • 写完这个功能后的感悟:繁琐,用servlet开发很繁琐:

        •         while (rs.next()){String deptno=rs.getString("deptno");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 align='center'>");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>");}
          
    • ​ 第六步:查看部门详情:

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

        • 要先找到用户点的“详情”在哪里

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

            • <a href='/oa/dept/detail'>详情</a>  //前端发送请求要加项目名!!!!!!
              
          • 这个路径是要加项目名的!!!

      • 技巧:

        • out.print("<a href='"+contextPath+"/dept/detail?deptno="+deptno+"'>详情</a>");
          
        • 重点:向服务器提交数据的格式:url?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><!--        web.xml文件里的这个文件也是以"/"开始!!,但是不需要加项目名--><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;/*** @author:HuangC* @ClassName:DeptDetailServlet* @Package:com.bjpowernode.oa.web.action.DeptDetailServlet* @Description:* @CreateDate:2022年05月10日* @Version:1.8**/
            public class DeptDetailServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//中文思路(思路来源于:你要做什么?目标:查看部门信息)//第一步:获取部门编号//第二步:根据部门编号查询数据库,获取该部门的编号对应的部门信息//第三步:将部门信息响应到浏览器上。(显示一个详情)}
            }
        • 在doGet方法中:连接数据库,根据部门编号查询部门的信息,动态展示详情页。

    • 第七步:删除部门

      • 怎么开始?从哪里开始?从前端页面开始,用户点击删除按钮的操作,提示用户是否删除,避免误删,(在前端界面写js代码提示)

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

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

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

        • web.xml文件配置:

          • <!--    删除部门--><servlet><servlet-name>delete</servlet-name><servlet-class>com.bjpowernode.oa.web.action.DeptDeleteServlet</servlet-class></servlet><servlet-mapping><servlet-name>delete</servlet-name><!--        web.xml文件里的这个文件也是以"/"开始!!,但是不需要加项目名--><url-pattern>/dept/delete</url-pattern></servlet-mapping>
            
          • 编写DeptDeleteServlet类,重写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;/*** @author:HuangC* @ClassName:DeptDeleteServlet* @Package:com.bjpowernode.oa.web.action.DeptDeleteServlet* @Description:删除部门* @CreateDate:2022年05月11日* @Version:1.8**/
            public class DeptDeleteServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//根据部门编号删除部门}
            }
          • 删除成功或者失败的一个处理(这里选择了转发,并没有选择重定向机制)

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

      • 注意,最后保存成功过后会,转发到、dept/list的时候,会出现405,为什么?

        • 第一:保存用户的是post请求,底层要执行doPost方法
        • 第二:转发是一次请求,之前是post,之后是post,因为他是一次请求。
        • 第三:/dept/list Servlet当中只有一个doGet方法。
        • 怎么去解决?两种方法
          • 第一种:在/dept/list Servlet中添加doPost方法,然后在doPos方法中调用doGet
          • 第二种:重定向
    • 第九步:跳转到修改部门的页面(同前面的步骤)

    • 第十步:修改部门

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

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

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

    • 代码上有什么区别?

      • 转发:

        • //获取请求转发器对象
          RequestDispatcher dispatcher=request.getReqestDispatcher("/dept/list")//调用请求转发器对象的forward方法完成跳转dispaer.forward(request,response);
          //合并一行代码
          request.getReqestDispatcher("/dept/list").dispaer.forward(request,response);
          //转发的时候是一次请求,AServlet转发到BServlet,在转发到DServlet,不管转发了 多少次都在同一个request中
          //调用forward的时候,会将request和response转发到下一个servlet中
          
        • 重定向

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

      • 转发(一次请求)

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

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

      • 借钱(转发):

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

    • 如果在上一个servlet当中向request绑定了数据,希望下一个servlet当中把request域里面的数据取出来,使用转发机制
    • 剩下所有的请求均使用重定向(重定向使用较多)

将oa项目中的资源跳转修改为合适的跳转方式

  • 删除之后重定向
  • 修改之后重定向
  • 保存之后重定向
  • 重定向
    • 成功
    • 失败

Servlet注解,简化配置

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

    • 现在只是一个单表的crud,没有复杂的业务逻辑,很简单的一丢丢功能,web.xml文件中就有很多的配置信息,如果采用这种方式,对于一个大项目来说,web.xml文件会非常庞大
    • 在web.xml文件中进行servlet配置。显然开发效率比较低,每一个都要配置一下
    • 而且web.xml文件中的配置很少被修改的,所以这种配置信息能不能写到java类当中呢,肯定可以
  • 在servlet3.0过后就出现了servlet基于注解式开发

    • 优点

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

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

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

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

    • @注解名称(属性名=属性值,属性名=属性值,属性名=属性值…)

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

  • 上面的注解解决了配置文件的问题,但是oa项目仍然存在一个比较臃肿的问题

    • 一个单表的crud,就写了六个Servlet,如果一个复杂的业务系统,这中打开方式,显然会导致类爆炸。(类的数量太大)
    • 怎么解决这个问题?可以用模板方法设计模式
  • 怎么解决类爆炸的问题?
    • 以前的设计是一个请求一个Servlet类,1000个请求就是1000个类,导致类爆炸。
    • 可以这样做:一个请求对应一个方法,一个业务对应一个Servlet类
    • 处理部门相关业务的对应一个DeptServlet,处理用户相关业务的对应一个UserServlet。处理卡片业务的对应一个cardServlet

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

  • 在servlet当中编写HTML/CSS/JavaScript等前端代码,存在什么问题

    • java程序中编写前端代码,编写难度大,麻烦
    • java程序中编写前端代码,显然程序的耦合度非常高
    • java程序中编写前端代码,代码不美观
    • java长须中编写前端代码,维护成本高
      • 修改一个前端代码,只要有改动,就需要重新编译代码

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

  • 什么是会话?

    • session
    • 用户打开浏览器进行一系列操作,然后将浏览器关闭的整个过程:叫做一次会话,会话在服务器端也有一个对应的对象:session
    • 什么是一次请求:用户在浏览器上点击了一下,然后到页面停下来,可以粗略认为是一次请求,请求对应的服务器端的java对象是request
    • 一个会话包含多次请求(一次对话对应多次请求。)
  • 在java的规范当中个,session规范的类名:HttpSession(jakarta.servlet.http.HttpSession)

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

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

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

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

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

    • request.setAttribute()方法(),request.setAttribute()方法(),ServletContext也有这个方法

      • request是请求域,ServletContext是应用域
    • ServletContext对象是服务器启动的时候创建,服务器关闭的时候销毁,这个ServletContext对象只有一个。
    • ServletContext的域太大
    • request请求域(HttpServletRequest),session会话域(HTTPSession),application应用域(ServletContext)
    • request<session<applcation
  • session的实现原理:

    • JSESSIONID=xxxxxxx 这个是以Cookie的形式保存在浏览器的内存当中的,浏览器只要关闭,这个cookie就没了
    • HttpSession session =request.getSession();
    • 没有获取到任何一个session对象就新建
    • 谁访问的时候就是谁获取这个对象
    • 在web服务器当中有一个session列表,类似map集合。
      • 这个map集合的key存储的是sessionId
      • 这个map集合的value值存储的是对应的session对象
      • 用户发送第一次请求的时候,服务器创建 一个新的session对象,同时给session生成一个id,然后web服务器会将session的id发送给浏览器,浏览器将session的id保存到浏览器的缓存当中
      • 用户发送第二次请求的时候,会自动将浏览器缓存当中的sessionId自动发送给服务器,服务器获取到sessionId。然后在session列表中找到对应的session对象
  • 为什么 关闭浏览器,会话结束?

    • 关闭浏览器后,浏览器中的session消失,下次重新打开浏览器之后,浏览器缓存中没有这个sessionId。自然找不到服务器中对应的额session对象,session对象找不到等同于会话结束
    • 关闭浏览器,内存消失,cookie消失,sessionId消失,会话等同结束
  • Cookie,session还能找到吗?

    • cookie禁用是什么意思?

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

    • 浏览器关闭的时候,服务器无法监测到浏览器关闭,所以session的销毁要依靠session超时机制,但也有一种可能:用户可以点击安全退出,用户可以点击这个按钮,这样浏览器就知道你退出了,服务器就监测到你退出了,服务器就自动销毁session对象
    • 一种销毁:超时销毁
    • 一种销毁:手动销毁
  • 到目前为止了解的域对象:

    • request(对应的类名:HttpServletRequest)

      • 请求域
    • session(对应的类名:HttpSession)

      • 会话域(用户级别的)
    • application(对应的类名:Servlet)

      • 作用域(项目级别的)
    • 这三个域对象的大小关系

      • request<session<application
    • 他们三个域对象都有以下公共的方法

      • setAttribute(向域当中绑定数据)
      • getAttribute(从域当中获取数据)
      • removeAttribute(删除域当中的数据)
    • 使用原则:尽量使用小的域

  • session掌握之后,我们怎么解决oa项目中的登录问题,怎么让登录起作用?

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

    • session.invalidate();
      

Cookie

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

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

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

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

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

    • 京东商城:在未登录的情况下,向购物车中放几件商品,然后关闭商城,再次打开浏览器,访问京东商城的时候,购物车的商品还在,这是怎么做的?我没有登录,为什么购物车里面还有商品呢?

      • 将购物车中的商品编号放到cookie中,cookie保存到硬盘当中,硬盘中的cookie只要还在,下一次打开京东商城的时候,查看购物车的时候,会自动读写本地硬盘中存储的cookie,拿到商品编号,动态展示购物车中的商品

        • 京东存储购物车中商品的cookie可能是这样的 products=xxxx,yyyy,zzzz,kkkkkk
        • 注意: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)

  • 关于cookie的有效时间

    • 怎么用java设置cookie有效时间

      • cookie.setMax(60*60); 设置cookie在一小时之后失效
    • 没有设置有效时间,默认保存在浏览器的运行内存当中,浏览器关闭则cookie消失
    • 只要设置了cookie的有效时间>0,这个cookie一定会存储到硬盘文件当中。
    • 设置cookie的有效时间=0呢?
      • cookie被删除,同名cookie被删除
    • 设置cookie的有效时间<0呢?
      • 保存在运行内存中,和不设置是一样的
  • 关于cookie的path,cookie关联的路径:

    • 假设现在发送的请求是: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和valueString name = cookie.getName();String value = cookie.getValue();System.out.println(name + "=" + value);}}
      
  • 使用cookie实现十天免登录

    • 先实现登录功能

      • 登陆成功

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

JSP

  • 项目部署后,实际上访问的是:index.jsp,底层执行的是: index.jsp.class 这个java程序

    • 这个index.jsp被tomcat翻译成为index.jsp.java文件
  • jsp实际上就是个servlet

    • idnex.jsp访问的时候,会自动翻译生成index.jsp.java,自动编译生成index.jsp.class,那么index.jsp这就是一个类

    • jsp继承HttpBase,而HttpBase类继承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 Page的缩写(基于java语言实现的服务器前端的页面)
    • Servlet是JavaEE的13个子规范之一,那么jsp同样也是
    • jsp是一套规范,所有的web容器/web服务器都是遵循这套规范的,都是按照这套规范进行翻译
    • 每一个web容器/web服务器都会内置一个翻译引擎
  • 对jsp进行错误调试的时候,还是要直接打开jsp文件对应的java文件,检查java代码

  • 开发jsp的最高境界

    • 眼前是jsp代码,但是脑袋中呈现的是java代码
  • jsp本质上是servlet,那么他们的区别是什么?

    • 职责不同

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

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

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

      • 通过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语句的规范!!
      • <%! %>
        • 在这个符号当中编写的java程序会自动编译到service方法外
        • 这个语法很少用,为什么?不建议使用,在service方法外面写,都会有线程安全问题,jsp是servlet,servlet是单例的,多线程开发环境下,这个静态变量和实例变量一旦有修改操作,必然存在线程安全问题
      • jsp的输出语句
        • 怎么向浏览器输出一个java变量
        • <%String name=“jack”; out.write(“name”=name)%>
        • 注意以上代码中的out是九大内置对象之一,可以直接拿来用,只能在service内部才能用!!!!!!
        • 如果向浏览器上输出的内容中没有java代码 ,例如:输出的字符串是一个固定的字符串,可以直接在jsp中编写,不需要写到<%%>这里
        • 如果输出的内容中含有java代码,可以使用以下代码:
          • <%=%>在等号后面编写输出的内容
          • ,这个符号会被翻译到哪里,最终翻译成什么??
            • 翻译成这个java代码 out.print();
            • 翻译到service方法当中
    • 在jsp中如何编写jsp的专业注释

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

      • 直接编写普通字符串

        • 翻译到service方法的out.print() 里面去
      • <%%>
        • 翻译到service方法体内部,里面是一条条的java语句
      • <%!%>
        • 翻译到方法体之外
      • <%=%>
        • 翻译到方法体内部,翻译为:out.print()
      • <%@page %>
        • page指令:通过contextType属性来设置响应的内容类型
    • 使用servlet加jsp改造oa项目

      • 使用servlet处理业务,收集数据

      • 使用jsp展示数据

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

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

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

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

        • 从request域中取出list集合
        • 遍历list集合,取出每个部门对象,动态生成tr
      • 只用jsp一个技术能不能开发一个应用?

        • 可以使用完成所有的 功能,因为jsp就是servlet

        • 但是不建议,最好是一个负责收集数据,一个负责展示数据

        • jsp中编写 的java代码越少越好

      • 包名bean是什么意思?

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

    • 任何一个用户都可以访问这个系统,都可以对这个系统进行增删改查,这些危险的操作,我只想让合法的用户去使用,不合法的用户不能使用

      • 加一个登录功能,登录成功可以访问,登录失败不可以访问
    • 实现登录功能的步骤

      • 步骤1:实现一个登录页面

        • 登录的表单。有用户名和密码输入的框
        • 用户点击登录,提交表单,提交用户和密码,form表单是post方式提交
      • 步骤2:数据库当中添加一个用户表:t_user

        • t_user表当中存储的是用户的登录信息,最基本的包括:登录的用户名和登录的密码。
        • 密码一般在数据库中存储的是密文,一般不以明文的方式存储。(这里先使用明文的方式。)
        • 向t_user表中插入数据
      • 步骤3:后台要有一个对应的Servlet来处理登录的请求

        • 登陆成功:跳转到部门列表页面
        • 登录失败:跳转到失败的页面
      • 步骤4:再提供一个登录失败的页面

  • 登录功能实现了,目前存在的最大问题是:

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

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

    • 指令包括哪些?

      • include指令:包含指令,在jsp中完成静态包含,很少用。
      • taglib指令:引入标签库的指令,这个到JSTL学习
      • page指令:重点学习这个
    • 指令的使用语法是什么?

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

      • <%@page session="true/false" %>
        <%--  true表示启用jsp的内置对象session,表示一定启动session对象,没有session会创建,如果没有设置默认值就是TRUE,session="false"表示不启动内置对象session,当前jsp页面无法使用内置对象session--%><%@page contentType="text/html; ISO-8859-1" pageEncoding="utf-8" %>
        <%-- contentType专门用来设置响应的内容类型pageEncoding="utf-8" 表示设置响应时采用的字符集也可以这样设置字符集<%@page contentType="text/html;charset=UTF-8" %>--%>
        
      • <%@page import="java.util.*" %>导包
        
      • <%@page errorPage="/error.jsp" %>
        当前页面出现错误的时候,errorPage用来指定跳转到的错误界面
        
      • <%@page isErrorPage="true" %>
        表示启用九大内置对象之一:exception,默认值是FALSE
        

  • jsp的九大内置对象

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

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

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

    • jakarta.servlet.ServletContext application 应用作用域

      • 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(负责响应)

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("123456");user.setAge(65);
      //将user存储到某个域当中,因为EL 表达式只能从某个范围取数据request.setAttribute("userObj",user);
      %>
      //使用EL表达式取
      ${userObj}
      等同于java代码:<%=request.getAttribute("userObj")%>
      不能这样写:${"userObj"}面试题:
      ${obj}和${"obj"}的区别是啥?${obj}表示从某个域中取出数据,并且取得这个数据的name是“obj”,之前一定有这个代码:setAttribute("obj",对象);${"obj"}表示直接将"obj"当做普通字符串输出到浏览器,不会从某个域取数据
      ${obj}底层是怎么做的?从域中取数据,取出user对象,然后调用user对象的toString方法,转换成字符串,输出到浏览器<%-- 如果想输出对象的属性值,怎么办?--%><%--你想输出的是user对象的username属性--%>
      ${userObj.username} 使用这个语法的前提,user对象必须有getUsername()方法
      ${userObj.password} 使用这个语法的前提,user对象必须有getPassword()方法
      ${userObj.age}      使用这个语法的前提,user对象必须有getAge()方法
      ${userObj.email}    使用这个语法的前提,user对象必须有getEmail()方法
      EL表达式中,这个语法,实际上调用了底层的getxxx()方法城市:${userObj.addr.city}
      街道:${userObj.addr.street}
      邮编:${userObj.addr.zipcode}
      以上的EL表达式对应的java代码
      user.getAddr().getCity()
      user.getAddr().getStreet()
      user.getAddr().getZipcode()
      
    • EL表达式默认优先从小范围中读取数据

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

      • pageScope 对应的是pageContext
      • requestScope 对应的是 reques范围
      • 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" language="java" isELIgnored="true" %>
        isELIgnored="true"  表示忽略EL表达式
        isELIgnored="false"  表示不忽略EL表达式isELIgnored="true" 这个是全局控制可以使用“\”进行局部控制:\${username} 这样也可以忽略EL表达式
    • 通过EL表达式来获取应用的根:

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

      • param
      • paramValues
      • inParam
    • EL表达式的运算符:

      • <%--为空返回 null 不为空返回TRUE--%>
        ${empty a}<br>
        ${!empty a}<br>
        <hr>
        <%--结果为false 前半部分是Boolean型,后面是null--%>
        ${empty param.username == null} <br>
        ${empty param.password == null} <br>
        <hr>
        ${param.usernmae == null} <br>
        更多见,javaweb 中的jsp项目的 12.jsp文件
        

JSTL标签库

  • 什么是JSTL标签库?

    • java Standard 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
      • 在idea中怎么导入
        • WEB-INF下新建lib目录,然后将jar包拷贝到lib当中,然后“add lib”
        • 什么时候需要将jar放到WEB-INF下的目录下?是这个tomcat本身没有的,就需要添加到lib目录下
    • 第二步:在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类”之间的关系
      以上核心标签库对应的是c.tld文件,它在哪儿?在jakarta.servlet.jsp.jstl-2.0.0.jar 里面的META-INF目录下的c.tld文件中
      
    • 源码解析

      • <tag><description>Catches any Throwable that occurs in its body and optionallyexposes it.     对标签的描述</description><name>catch</name>    标签名字<tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class> 标签对应的java类<body-content>JSP</body-content> 标签体当中可以出现的内容,就表示所有符合jsp所有语法的代码 eg:el表达式<attribute><description>  对这个属性的描述
        Name of the exported scoped variable for the
        exception thrown from a nested action. The type of the
        scoped variable is the type of the exception thrown.</description><name>var</name><required>false</required>  FALSE表示属性不是必须的<rtexprvalue>false</rtexprvalue> 这个描述说明了该属性是否支持EL表达式,FALSE表示不支持,TRUE表                                   示支持</attribute></tag>
        
    • jsp核心标签库当中有哪些常用的标签

      • c:if

        • <c:if test="布尔类型,支持EL表达式"> </c:if><%--没有else标签的话,可以搞两个if出来 --%>
          <%--if标签有var属性,不是必须得--%>
          <%--scope属性,用来指定var的存储域,也不是必须得--%>
          <%--scope有四个值可以选,page(pageContext域),request(request域),session(session域),application(application域)--%>
          <c:if test="${not empty param.username}" var="v" scope="request"><h1>欢迎你${param.username}。</h1>
          </c:if>
          <hr>
          <%--通过EL表达式将request域当中的v取出--%>
          <%--v变量中保存的是test的保存的值--%>
          ${v}
          
        • c:foreach

          • <c:forEach items=“集合,支持EL表达式 ” var=“集合中的元素 ” varStatus=“ 元素状态对象”>
            ${元素状态对象.count}
            </c:forEach>
            
          • <c:forEach var="i" begin="1"  end="10" step="1">${i}<br>
            </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>
          

改造OA

  • 使用什么技术改造?

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

    • 这不是java的语法,也不是jsp的语法,而是HTML中的一个标签,通常出现在head标签中说

    • <base href="http://localhost:8080/oa/">
      
    • 在当前页面中,凡是路径没有以“/”开始的,都会自动将base标签中的路径添加到这些路径之前

      • 等同于:
    • 需要注意,在jsp代码中的路径,最好不要依赖base标签,jsp代码中的路径最好使用全路径

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

Filter过滤器

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

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

      • 可以使用servlet规范中的filter过滤器来解决这个问题
  • 我们可以把servlet程序看做是一个最终要执行的目标,我们可以使用过滤器来添加过滤代码,这个过滤代码可以添加到servlet执行之前,也可以添加到servlet执行之后

  • Filter是什么?有什么用?执行原理是什么?

    • filter是过滤器。
    • filter可以在servlet这个类执行之前添加代码,也可以在servlet这个类执行之后添加代码,之前之后都可以添加过滤规则
    • 一般情况下,都是在过滤器当中编写公共代码
  • 一个过滤器怎么写呢

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

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

      •  <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>/abc</url-pattern>-->
        <!--        <url-pattern>/a.do</url-pattern>--><url-pattern>*.do</url-pattern></filter-mapping>
        
      • 或者使用注解:@WebFilter({“*.do”})

  • 注意:

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

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

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

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

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

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

  • 使用WebFilter的时候,Filter的执行顺序是在怎么样的

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

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

    • 责任链设计模式

    • 过滤器最大的优点

      • 在程序编译阶段不会确定调用顺序,因为filter的调用顺序是配置到web.xml文件中的,只要修改web.xml配置文件中filter-mapping就可以调整filter的执行顺序,显然filter的执行顺序是在程序运行阶段动态组合的,那么这种设计模式被称为责任链设计模式。
    • 责任链设计模式最大的核心思想:

      • 在程序运行阶段,动态的组合程序的调用顺序。
  • 使用过滤器改造oa

Listener监听器

  • 什么是监听器?

    • 监听器是规范中的一员,就像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()
      void contextDestroyed()
      
    • 第二步:在web.xml文件中对ServletContextListener进行配置,如下:

      • <listener><listener-class>com.bjpowernode.javaWeb.listener.MyServletContextListener</listener-class>
        </listener>
        
      • 第二步也可以不使用配置文件,也可以使用注解

  • 注意:所有监听器中的方法都是不需要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超时)

javaWeb-第一版相关推荐

  1. 【JavaWeb】石家庄地铁搭乘系统——第一版(功能尚未完善)

    小组成员:高达,程超然 项目目的:能算出地铁搭乘的最优路线并显示在地图上 个人任务:调用队友写好的java代码,将结果显示在网页上 新的知识:百度地图API,使用JQuery的AJAX异步提交 进度: ...

  2. javaWeb——Servlet

    Servlet 系统架构 B/S结构的系统通信原理(没有涉及到Java小程序) 关于WEB服务器软件 实现一个最基本的web应用(这个web应用中没有java小程序) 对于一个动态的web应用来说,一 ...

  3. JavaWeb笔记01

    文章目录 JavaWeb(狂神说Java) 1.基本概念 1.1前言 1.2web应用程序 1.3静态web 1.4 动态web 2.web服务器 2.1技术讲解 2.2web服务器 3.Tomcat ...

  4. 使用maven搭建ssm框架的javaweb项目

    目前主流的javaweb项目,常会用到ssm(Spring+Spring MVC+Mybatis)框架来搭建项目的主体框架,本篇介绍搭建SSM框架的maven项目的实施流程.记之共享! 一.SSM框架 ...

  5. javaweb学习总结(二十三)——jsp自定义标签开发入门

    一.自定义标签的作用 自定义标签主要用于移除Jsp页面中的java代码. 二.自定义标签开发和使用 2.1.自定义标签开发步骤 1.编写一个实现Tag接口的Java类(标签处理器类) 1 packag ...

  6. javaWeb -- HTTP协议

    笔记摘要: 作为web开发的前奏,这里介绍了什么是HTTP协议,HTTP请求与HTTP响应信息的介绍 一.什么是HTTP协议 客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一 ...

  7. Java项目:个人博客系统(java+SSM+Mysql+Servlet+JavaWeb)

    源码获取:博客首页 "资源" 里下载! 一.项目简述 项目内容包括:首页,登陆,新建文章,搜索,登陆日志,登录次数,评论统计,相关信息,文章列表等其他相关功能 另外:系统采用MVC ...

  8. 在linux下部署安装Tomact并运行javaWeb工程

    1.下载并安装xftp5 2.上传Tomact服务器 3.安装Tomact服务器 3.1解压Tomact服务器压缩包 解压到当前目录下 3.2配置环境变量 tomcat服务器运行时是需要JDK支持的, ...

  9. 超详细的Java面试题总结(四 )之JavaWeb基础知识总结

    系列文章请查看: 超详细的Java面试题总结(一)之Java基础知识篇 超详细的Java面试题总结(二)之Java基础知识篇 超详细的Java面试题总结(三)之Java集合篇常见问题 超详细的Java ...

  10. JavaWeb学习笔记——DOM4J

    下载的地址为:http://www.dom4j.org/dom4j-1.6.1/ import java.io.File; import java.io.FileOutputStream; impor ...

最新文章

  1. win7/10 画图程序按宽度高度mm cm精确调整图片尺寸
  2. boost::rethrow_exception相关的测试程序
  3. Go聊天室的思路:一个拨号 一个监听
  4. tomcat8 安装|解决启动慢|进入管理|host-manager 403错误
  5. 在ATM取钱5000,查询余额却少了50000,怎么回事?
  6. 【WPF】关于XAML Parse Exception,无法创建XXX的实例异常的一点小心得
  7. 华为服务器设置iBMC管理网口IP地址,开启Monitor图文教程
  8. 手机logging什么意思_手机三轴稳定器的“三轴”是什么意思?
  9. Android 编码规范:(二)遇到多个构造器参数时要考虑用构建器
  10. 利用express启一个server服务
  11. html中怎么加入动态图片,视频加动态水印 怎么在视频画面中添加一个gif动态图片水印...
  12. TCP/IP协议栈详解
  13. 系统明文密码加密传输
  14. Open Gapps各版本介绍
  15. k8s(Kubernetes)实战(一)之部署etcd与flannel
  16. 例题5.23 蚂蚁 LA4043
  17. 使用HTML编写浣溪沙,《浣溪沙》版本+原文+拼音版+翻译+赏析+作者
  18. 青藤云——安全服务工程师面经(北京升鑫网络科技有限公司)
  19. ios Objective-c 获取省市区工具
  20. BeanDefinition使用方式

热门文章

  1. 全国计算机access二级真题,最新全国计算机二级access历年真题.doc
  2. 超链接 a标签 虚线框 虚线 去除虚线框
  3. MATLAB科学绘图-MATLAB画图技巧与实例(一):常用函数
  4. 计算机信息计量单位G的单位,计算机中的有些计量单位例如G、MB是表示什么意思?...
  5. 技术学校面试该说什么_我第一次现场技术面试后,香港专业教育学院学到了什么...
  6. 卡方检验x2检验(chi-square test)
  7. 2023 年 IEEE Fellow 名单公布!唐立新、姬水旺、宗成庆、朱军、宋厚冰等入选
  8. html中 videojs 播放m3u8文件【方式一】
  9. 寻找大学目标及行动步骤——记ITAEM团队第二期宣讲会(2014.05.14)
  10. Json对象和string之间的转换