互联网通信流程

互联网通信流程

1.概述

  • 什么是互联网通信?

    1. 两台计算机通过网络实现文件共享行为,就是【互联网通信】
    2. 客户端计算机:用于发送请求,来索要资源文件的计算机。
    3. 服务端计算机:用于接受请求,并提供对应资源文件的计算机。
  • 分为哪几种,各自优缺点?

    1. C/S通信模型:

      image-20201006101251848

      适用场景:个人娱乐市场(微信,淘宝,视频(优酷//B站),游戏(LOL))

      优缺点:

      ​ 优点:1.安全性较高,2.有效降低服务端计算机工作压力。

      ​ 缺点:1.增加客户获得服务成本 2.更新较为频繁

    2. B/S通信模型:

      image-20201006101651456

      适用场景:个人娱乐市场(微信,淘宝,视频(优酷//B站)),有广泛用于企业日常活动。

      优缺点:

      ​ 优点:1.不会增加客户获得服务成本 2.几乎不需要更新浏览器

      ​ 缺点:1.几乎无法有效对服务端计算机资源文件进行保护,2.服务端计算机工作压力巨大【B/S通信模型高并发解决方案】。

  • 互联网通信模型原理?

    1. 共享文件:可通过网络传输的文件。所有文件都可网络传输,故都为共享文件

    2. Http服务器下共享资源文件分类

      • 静态资源文件:1.文件内容固定(文档,图片,视频)2.文件存放是命令且只能在浏览器编译执行(html,css,js)

      • 动态资源文件:文件存放是命令,不能在浏览器编译执行,只能在服务端计算机编译执行(.class)

    3. 静态资源文件与动态资源文件调用区别:

      • 静态资源文件:静态文件被索要,Http服务器直接通过【输出流】将内容或命令以【二进制形式】推送给发起请求的浏览器。

      • 动态资源文件:动态文件被索要,Http服务器需要创建当前class文件的实例对象,通过实例对象调用对应方法处理用户请求,通过【输出流】将运行结果以【二进制形式】推送给发起请求的浏览器。

      • class Student{
            public int add(int num1,int num2){
                return num1+num2;
            }
        }
        //Http服务器自动
        Student stu = new Student();
        //调用方法处理用户请求
        int 结果 = stu.add(10,10);
        //以流形式返回结果
        out.print(结果);
        
    4. 通信流程图:

      开发人员:1.控制浏览器行为 2.开发动态资源文件解决用户请求

image-20201006130806091
  • 涉及技术
    1. 控制浏览器行为:HTML,css,JS
    2. 控制数据库行为:Mysql(sql命令)
    3. 控制服务端Java行为技术:Http服务器:servlet,JSP
    4. 互联网通信开发原则:MVC

2.Web服务器之HTTP协议与Tomcat服务器

2.1.Http网络协议包

  1. 网络协议包:

    • 网络中传递信息都是以【二进制】形式存在。
    • 接收方【浏览器/服务器】在接受信息后,第一件事就是将【二进制数据】进行编译【文字,图片,视频,命令】
    • 传递信息数据量比较巨大,导致接收方很难在一段连续的二进制得到对应数据。比如:浏览器发送一个请求:http://192.168.100.2:8080/index.html这个请求以二进制形式【0101010101011001】发送给Http服务器很难从二进制数据得到相关信息。
    • 网络协议包:一组有规律的二进制数据,存在固定空间,每个空间专门存放特定信息,这样接收方在接收网络协议包之后就可以得到固定空间对应信息,极大降低了接收方对二进制数据编译难度。如【0000 (ip地址)0000(端口号) 0000(资源文件名) 0000】
  2. 常见网络协议:FTP网络协议包,Http网络协议包

  3. Http网络协议包:

    • 基于B/S结构下互联网通信过程中,所有网络中传递信息都是保存在Http网络协议包

    • 分类:Http请求协议包 Http响应协议包

    • Http请求协议包:

      ​ 在浏览器准备发送请求时,负责创建一个Http请求协议包,浏览器将请求信息以二进制形式保存在Http请求协议包各个空间由浏览器负责将Http请求协议包推送到指定服务端计算机。

    • Http响应协议包:

      ​ Http服务器在定位到被访问的资源文件之后,负责创建一个 Http响应协议包,Http服务器将定位文件内容或者文件命令以【二进制】形式写入到 Http响应协议包各个空间,由Http服务器负责将 Http响应协议包推送到发起请求的浏览器上。

    • Http请求协议包内部空间(背)

      image-20201006125247044

      自上而下,分为4个空间:

      ​ 请求行:url请求地址,method请求方式:get/post

      ​ 请求头: 请求参数信息【get]

      ​ 空白行:无内容,隔离作用

      ​ 请求体:请求参数信息【Post】

    • **Http响应协议包内部空间**(背)

      image-20201006130401040

      自上而下,分为4个空间:

      ​ 状态行:http状态码

      ​ 响应头: conyent-type。。。

      ​ 空白行:无内容,隔离作用

      ​ 响应体:二进制形式存在内容

2.2.Http服务器

  1. 分类:JBOSS服务器 ,Glassfish服务器,Jetty服务器,Websphere服务器(电子商务,linux系统),Tomcat服务器

  2. Tomcat服务器:

    • 内部文件结构:bin(管理命令),conf(核心配置server.xml),lib(jar包),logs(日志),temp(临时文件),webapps(资源文件,默认找),work(工作空间)

    • 模拟一次网络通信:

      URL格式:网络协议包://服务端计算机ip地址:http服务器端口号/网站名/资源文件名称

      (http://localhost:8080/myWeb/index.html)

3.面试模拟

  1. 重写与重载的区别?

    重载:

    ​ 在Java同一个类文件中,允许出现多个方法名相同,但参数列表不同的方法,这叫做方法重载。

    ​ 特点:方法名必须相同,但参数列表必须不同,包括(参数个数不同,参数类型不同,参数类型顺序不同)

    ​ 目的:让方法在接受不同参数时实现不同功能。

    重写:

    ​ 在继承过程中,子类对父类方法实现细节进行重新定义,叫做方法重写。

    ​ 特点:1.子类重写父类方法时,不能降低方法访问权限,只能不变或者扩大访问权限。

    ​ 2.在重写时,子类方法不能比父类方法抛出更多异常,只能是父类方法异常的全集,子集,空集。

    ​ 3.子类重写方法返回时,可以缩小返回类型范围,但不能增加返回类型范围。如父类返回父类对象, 子类返回类型可以是父类对象,也可是子类对象。但若父类返回子类对象,那么子类返回值类型不 能是父类对象,可以是子类对象或子类对象的子类对象。

    ​ 4.private和final修饰的方法,不能被重写。

  2. throw和throws的区别:

    ​ throws:

    ​ 声明位置:声明在方法名后。

    ​ 作 用:通知开发人员,当前方法运行时,可能会抛出异常。

    ​ 携带数据:throws后面携带【异常类型】,throws后面可以携带多个异常类型。

    ​ 调 用:被throws修饰的方法,调用时必须考虑捕获异常问题

    ​ throw:

    ​ 声明位置:声明在方法体中。

    ​ 作 用:是一个命令,执行时抛出一个指定异常对象。

    ​ 携带数据:throw后面携带【异常对象】,一个throw一次只能携带一个异常对象。

    ​ 调 用:当一个方法内部存在throw命令时,调用时可以不考虑捕获异常问题。

    3.接口和抽象类区别:

    ​ 接 口:

    ​ 是一个特殊类文件

    ​ 作 用:制定规则,降低耦合度

    ​ 使用规则:接口中属性,默认静态常量属性。static final xxx;

    ​ 方法都是抽象(不能有方法体),如需定义具体方法实现,需要default修饰。

    ​ 方法访问权限不能是private(是private修饰的话,没法实现类实现,只能接口中实现)

    ​ 接口与接口之间可以实现多继承,但是接口之间不能互相实现。

    ​ 接口不能出现构造方法。

    //接口也可以实现多态
    interface Fu {
     public abstract void method();
    }
    class Zi implements Fu {
        public void method(){
         System.out.println(“重写接口抽象方法”);
        }
    }
    //接口的多态使用
    Fu fu = new Zi();
    

    ​ 抽象类:

    ​ 抽象类由abstract修饰

    ​ 作 用:降低接口实现类 与 接口之间的实现难度。

    ​ 使用规则:抽象类可以声明抽象方法,也可声明具体方法。

    ​ 抽象类声明抽象方法,必须由其子类实现重写。

    ​ 抽象类实现接口时,不需要对接口方法重写。

    ​ 抽象类有构造方法,但不能使用(不能new)。

抽象类作用实例:

//====定义Cat接口============
public interface Cat {
    public void eatFish();//吃鱼
    public void eatGutou();//吃骨头
}
//=====实现Cat接口,所有方法必须重写=====
public class CatImp implements Cat {
    @Override
    public void eatFish() {

    }

    @Override
    public void eatGutou() {

    }
}
/*======定义抽象类Animal实现Cat接口=========
* 抽象类实现接口时,可以不对接口方法重写
* 抽象类中,没有重写的方法,必须由抽象类子类实现
* */
public abstract class Animal implements Cat {
    @Override
    public void eatGutou() {

    }
}
//========定义CatExtend类继承抽象类Animal====
public class CatExtend extends Animal {
    @Override
    public void eatFish() {
        System.out.println("我只喜欢吃鱼");
    }
}

4. Servlet规范

4.1 简介

  1. servlet规范来自于JAVAEE规范中的一种
  2. 作用:
    1. 在servlet规范中,指定【动态资源文件】开发步骤
    2. 在servlet规范中,指定Http服务器调用动态资源文件规则
    3. 在servlet规范中,指定Http服务器管理动态资源文件实例化对象规则。

4.2 Servlet接口实现类

  1. Servlet接口来自于Servlet规范下一个接口,这个接口存在Http服务器提供jar包下。

  2. Tomcat服务器下lib文件有一个servlet-api.jar存放Servlet接口(javax.servlet.Servlet接口)。

  3. Servlet规范中认为,Http服务器能调用的【动态资源文件】必须是一个Servlet接口实现类

    例子:

    class Student{
        //不是动态资源文件,tomcat无权调用
    }
    class teacher implements Servlet{
        //合法动态资源,tomcat有权调用
    }
    
  4. Servlet接口实现类开发步骤

    1. 创建一个Java类继承与HttpServlet父类,使之成为一个Servlet接口实现类。

    2. 重写HttpServlet父类两个方法。doGet()和doPost()。

      浏览器–get–>onservlet.doGet()

      浏览器–post–>oneservlet.doPost()

    3. 将Servlet接口实现类信息【注册】到Tomcat服务器

      【网站】—>【web】—>【WEB-INF】—>web.xml

      <!------------将Servlet类路径地址交给Tomcat----------->
      <servlet>
      <!--声明一个变量存储Servlet接口实现类类路径-->    
          <servlet-name>美女</servlet-name>
       <!--声明Servlet接口实现类类路径-->  
          <servlet-class>com.codesing.controller.OneServlet</servlet-class>
      </servlet>
      
      <!--此时Tomcat做的事:String 美女 = “com.codesing.controller.OneServlet”;-->
      
      <!--w为了降低用户访问Servlet接口实现类难度,(此时浏览器向Tomcat服务器索要OneServlet时地址:http://localhost:8080/myWeb/com.codesing.controller.OneServlet.class)
      需要设置动态资源文件请求别名-->
      <servlet-mapping>
          <!--变量存储Servlet接口实现类类路径-->
          <servlet-name>美女</servlet-name>
          <!--设置简洁请求别名,书写时必须以“/”开头-->
          <url-pattern>/one</url-pattern>
      </servlet-mapping>
      

      此时浏览器向Tomcat服务器索要OneServlet时地址:

      http://localhost:8080/myWeb/one

      package com.codesing.controller;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      
      /**
       *                       extends                          extends                          implements
       * 1.理清关系:OneServlet---------->(abstract)HttpServlet----------->(abstract)GenericServlet----------->Servlet
       *             doGet()                   doGet()                              destroy()                init()
       *             doPost()                  doPost()                             getServletConfig()       getServletConfig()
       *                                       service(){                           getServletInfo()         service()
       *                                        doGet()                             init()                   getServletInfo()
       *                                        doPost() }                          abstract void service()  destroy()
       *
       * 2。GenericServlet这个抽象类重写了除service()外的Servlet中的其它方法,而在HttpServlet类中,重写了service()方法,其中service()
       * 方法又调用了doGet()和doPost()方法,故我们OneServlet类只需要重写doGet()和doPost()方法来处理Get和Post请求即可。
       * 3. Tomcat 根据Servlet规范调用Servlet接口实现类规则:
       *      1.Tomcat有权创建Servlet接口实现类实例化对象  Servlet oneServlet = new OneServlet();
       *      2.Tomcat根据实例对象自动调用service()方法处理当前请求  oneServlet.service();此时service方法中this====>oneServlet
       * 4. 通过父类决定在何种情况下调用子类中方法-----【设计模式】--
       *
       * */
      public class OneServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              System.out.println("处理Get请求");
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              System.out.println("处理Post请求");
          }
      }
      

4.3 Servlet对象生命周期

  1. 网站中所有的Servlet接口实现类的实例化对象,只能由Http服务器负责创建,开发人员不能手动创建Servlet接口实现类的实例化对象。

  2. 在默认情况下,Http服务器接收到对于当前Servlet接口实现类**第一次请求时**,自动创建这个Servlet接口实现类的实例化对象。

    在手动配置下,要求http服务器在启动时 自动创建某个Servlet接口实现类实例对象。

    <!------------将Servlet类路径地址交给Tomcat----------->
    <servlet>
    <!--声明一个变量存储Servlet接口实现类类路径-->    
        <servlet-name>美女</servlet-name>
     <!--声明Servlet接口实现类类路径-->  
        <servlet-class>com.codesing.controller.OneServlet</servlet-class>
        <load-on-startup>30</load-on-startup><!--填写一个大于0整数-->
    </servlet>
    
  3. 在Http服务器运行期间,一个Servlet接口实现类**只能被创建出一个实例化对象**。

  4. 在Http服务器关闭时,自动将所有Servlet实例对象销毁。

    //==============================OneServlet==========================================
    package com.codesing.controller;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class OneServlet extends HttpServlet {
        public OneServlet(){
            System.out.println("OneServlet实例化对象被创建");
        }
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("OneSevlet doGet is run....");
        }
    }
    //=============================TwoServlet===========================================
    package com.codesing.controller;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class TwoServlet extends HttpServlet {
        public TwoServlet(){
            System.out.println("TwoServlet 实例化对象被创建");
        }
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("TwoServlet doGet is run....");
        }
    }
    
    <!--==========================web.xml================================-->
    <?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>OneServlet</servlet-name>
            <servlet-class>com.codesing.controller.OneServlet</servlet-class>
        </servlet>
        <servlet>
            <servlet-name>TwoServlet</servlet-name>
            <servlet-class>com.codesing.controller.TwoServlet</servlet-class>
            <!--告知服务器,在启动时就自动创建TwoServlet实例化对象-->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>OneServlet</servlet-name>
            <url-pattern>/one</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>TwoServlet</servlet-name>
            <url-pattern>/two</url-pattern>
        </servlet-mapping>
    </web-app>
    

    image-20201006235903575

    操作顺序:

    1. 发布完成,启动tomcat服务器,tomcat服务器自动创建TwoServlet实例化对象
    2. 在浏览器输入:http://localhost:8080/myWeb/one,OneServlet实例化对象被创建,doGet方法执行。
    3. 在浏览器输入:http://localhost:8080/myWeb/two TwoServlet的doGet方法执行。
    4. 在浏览器输入:http://localhost:8080/myWeb/two TwoServlet的doGet方法执行,未再次创建TwoServlet实例化对象
    5. 在浏览器输入:http://localhost:8080/myWeb/one,doGet方法执行,未再次创建OneServlet实例化对象。

4.4 HttpServletResponse接口

  1. 介绍:存在于Tomcat中的servlet-api.jar包。

  2. HttpServletResponse接口实现类由Http服务器负责提供。

  3. HttpServletResponse接口负责将doGet/doPost方法执行结果写入到【响应体】交给浏览器。

  4. 开发人员将HttpServletResponse接口修饰对象叫【响应对象】

  5. 主要功能:

    1. 将执行结果以二进制形式写入到【响应体】

    2. 设置响应头中【content-type】属性值,从而控制浏览器使用对应的编译器将响应体二进制数据编译为【文字,图片,视频,命令】

    3. 设置响应头【location】属性,将一个请求地址赋值给location,从而控制浏览器向指定服务器发送请求。

      具体实现

      package com.codesing.controller;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.PrintWriter;
      
      public class OneServlet extends HttpServlet {
      
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              //=====================write()方法================
              //String result = "hello world";//假设这是执行结果
              //--------响应对象将结果写入响应体------------------start
              1.通过响应对象,向tomcat服务器获取输出流
              //PrintWriter writer = response.getWriter();
              2.通过输出流,将执行结果以【二进制形式】写入到响应体
              //writer.write(result);
              //----------------响应对象将结果写入响应体----------start
              /**
       * 问题:money = 50;最终在浏览器写入的是 2?
       * 原因:write()方法再写的时候写入的是【字符,字符串,ASCII码】到响应体,
       	50---ACSII码-->2
       * 解决:实际开发,都是以print()写入到响应体中。
       * * * */
              //int money = 50;
              //writer.write(money);//2
              //writer.write(97);//a
              //================================print()方法==========
              //print()
              //writer.print("\n");
              //writer.println(money);
              //writer.print(97);
              //========================设置content-type属性===========
              //String html = "西红柿鸡蛋面<br>香菇三鲜面<br>红烧排骨面<br>";
              ------默认content-type="text"。如何将文本和html标签都能正确输出-------//
              //response.setContentType("text/html");
              //response.setCharacterEncoding("utf-8");
              //====》 response.setContentType("text/html;charset=utf-8");
              在获取输入对象前设置。
              //PrintWriter writer1 = response.getWriter();
              写入东西
              //writer1.print(html);
              //==============================设置location值===========
              //---------通过响应对象,给响应头location赋值-------------//
              String result = "http://www.baidu.com?username=meiko";
              response.sendRedirect(result);
              //【响应头:location:http://www.baidu.com】
              //结果:https://www.baidu.com/?username=meiko
              
              //-浏览器收到响应包,如果存在locatin属性,自动通过地址栏向location指定网站发送请求----//
          }//doGet执行完毕,Tomcat将响应包推送给浏览器
      }	
      

4.5 HttpServletRequest接口

介绍:

  1. HttpServletRequest接口来自于Servlet规范中,存在于Tomcat中的servlet-api.jar包2

  2. HttpServletRequest接口实现类由Http服务器负责提供。

  3. HttpServletRequest接口负责在doGet/doPost运行时读取Http请求协议包中信息。

  4. 开发人员将HttpServletRequest接口修饰对象叫【请求对象】。

  5. 主要功能:

    可以读取Http请求协议包中【请求行】信息

    可以读取保存在Http请求协议包中【请求头】或则【请求体】中参数信息

    可以代替浏览器向Http服务器申请资源文件调用

具体实现:

三个例子:参考:E:\学习文档\数据库课程设计\IDE-Workspace\JavaWeb-Servlet\004-HttpServletRequest介绍

package com.codesing.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*问题:get请求方式时正常,post请求时中文乱码【username=è????????】???
* 原因:因为在浏览器发送请求中,请求协议包中【get请求参数在请求头中】,其默认是tomcat服务器来解码【二进制解码成文字图片等】
*       而tomcat服务器默认节码的字符集为【utf-8】。可以解析一切国家文字。
*       而【post请求参数在请求体中】,其默认为当前请求对象【request对象来解码】,
*       而request对象在解码时默认采用【ISO-8859-1】字符集,一个东欧语系字符集解码。故中文无法识别。
* 解决方案:在处理【post】请求时,在读取请求体内容前,设置其request对象解码字符集为utf-8。
* */

public class ThereServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置解码字符集
        request.setCharacterEncoding("utf-8");
        //获取get方式请求的【请求头】中参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("username="+username+","+"password="+password);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取post方式请求的【请求体】中参数
       String username = request.getParameter("username");
       String password = request.getParameter("password");
       System.out.println("username="+username+","+"password="+password);

    }
}

4.6请求对象和响应对象生命周期

  1. 在Http服务器收到一个浏览器发送的【Http请求协议包】后,自动为当前Http请求协议包生成一个【请求对象】和【响应对象】。

  2. 在Http服务器调用doGet和doPost方法时,负责将【请求对象】和【响应对象】作为实参传递到方法中,确保doGet和doPost方法正确执行

  3. 在Http服务器准备推送Http响应协议包前,负责将本次关联的【请求对象】和【响应对象】进行销毁。

    【请求对象】和【响应对象】生命周期贯穿一次请求的处理过程

    【请求对象】和【响应对象】相当于用户在服务端的代言人

image-20201007173651711


以下以一个登陆注册案例为起点,开始介绍,代码地址:E:\学习文档\数据库课程设计\IDE-Workspace\JavaWeb-Servlet\005-在线考试系统

4.7 用户注册流程图

image-20201007211246622

package com.codesing.controller;

import com.codesing.Entity.User;
import com.codesing.dao.UserDao;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author: JZQ
 * @Date: 2020/10/10 10:40
 * @Version 1.0
 */
public class UserAddServlet extends HttpServlet {

    private User user;
    private UserDao userDao;
    private PrintWriter out = null;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        userDao = new UserDao();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        String sex = request.getParameter("sex");
        user = new User(0,username,password,sex,email);
        int result = userDao.add(user);
        //设置响应头
        response.setContentType("text/html;charset=utf-8");
        out = response.getWriter();
        if (result == 1) {
            out.print("<font style='color:red;font-size:40'>注册成功</font>");
        }else{
            out.print("<font style='color:red;font-size:40'>注册失败</font>");
        }
    }
}

4.8用户登陆验证

image-20201010224450730

package com.codesing.controller;

import com.codesing.dao.UserDao;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author: JZQ
 * @Date: 2020/10/11 11:42
 * @Version 1.0
 */
public class UserLoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求体参数,记得修改【请求对象】编码
        request.setCharacterEncoding("utf-8");
        //获取【请求体】参数
        String loginName = request.getParameter("loginName");
        String loginPassword = request.getParameter("loginPassword");
        //调用Dao层数据库查询
        UserDao userDao = new UserDao();
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        int result = userDao.login(loginName,loginPassword);
        if (result == 1){
            response.sendRedirect("/myWeb/index.html");
        }else{
            response.sendRedirect("/myWeb/login_error.html");
        }
    }

}

4.9 欢迎资源文件

  1. tomcat默认配置欢迎资源文件规则如下:tomcat安装位置/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>
  1. 设置自定义默认欢迎资源

    <!--- 位置:网站/web/WEB-INF/web.xml->
    <!--规则命令-->
    <welcome-file-list>
    	<welcome-file>login.html</welcome-file>
    </welcome-file-list>
    <!--网站设置自定义默认文件定位规则,tomcat自带定位规则失效-->
    

4.10 http状态码

  1. 介绍:

    • 三位数字组成一个符号
    • Http服务器在推送响应包前,根据本次请求处理情况将Http状态码写入响应包【状态行】上。
    • 如果Http针对本次请求,【返回了对应资源文件】通过Http状态码通知浏览器如何处理这个结果。【但无法返回对应资源文件时】通过状态码告知原因。
  2. 分类:

    1. 组成100–599;分为5个大类

    2. 1xx:

      ​ 最有特征,100;通知浏览器本次返回资源文件不是一个独立资源文件,需要浏览器接收响应包后,继续向Http服务器索要依赖的资源文件。

    3. 2xx:

      ​ 最有特征,200;通知浏览器本次返回资源文件是一个独立资源文件,浏览器在接收到后不需要向Http服务器索要其他依赖的资源文件。

      image-20201011135334450

    4. 3xx:

      ​ 最有特征,302;通知浏览器本次返回资源文件不是一个资源文件内容,而是一个【资源文件地址】。需要浏览器根据此地址【自动向Http服务器发起请求】索要资源文件。

      response.sendRedirect("资源文件地址")写入响应头中location,这个行为导致Tomcat将302状态码写入到状态行。
      
      protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
      
          String add = "http://www.baidu.com";
          response.sendRedirect(add);//写入响应头location
          //响应体为空,但响应头location放入一个地址
          //tomcat返回302,浏览器不去读响应体,直接根据响应头地址发起二次请求
      }
      
    5. 4xx:

      ​ 404;服务端无法定位资源文件,通知浏览器无法找到资源文件。

      ​ 405;服务端定位到了资源文件(Servlet),但这个Servlet对于浏览器采用的请求方式不能处理。(比如get方式请求,没有doGet方法)

    6. 5xx:

      ​ 500:服务端定位到了资源文件(Servlet),这个Servlet可以处理浏览器采用的请求方式。但Servlet处理请求期间,java异常导致处理失败。

      protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
      
          Map map = new HashMap();
          //int num = (int)map.get("key1");//抛出NullPointerException
          Integer num = (Integer) map.get("key");//所有高级引用类型可以赋值null.
          System.out.println("hhhhh........");
          //int a = null;//null值不可能赋值给int。
          Integer b = null;
      }
      

4.11多个Servlet之间调用规则

  1. 规则:

    1. 重定向解决方案

      • image-20201011143601772

      • 工作原理:第一次手动发送请求,在oneServlet处理完后,重定向到twoServlet,自定请求。

      • response.sendRederict("/myWeb/two");
        
      • 特征:

        ​ 请求地址:1.当前网站内部资源文件地址【/网站名/资源文件名】2.其他网站资源文件【http://ip地址:端口号/网站名/资源文件名】

        ​ 请求次数:2-n次,第一次手动,其他自动。

        ​ 请求方式:重定向是通过地址栏发起请求,一定是get请求方式。

      • 缺点:重定向需要浏览器和服务器之间进行多次往返,增加用户等待时间。

    2. 请求转发解决方案

      • 原理:用户第一次手动发起请求访问OneServlet,OneServlet处理完后,通过当前请求对象代替浏览器向Tomcat发送请求,申请调用TwoServlet,Tomcat收到这个请求后,自动调用TwoServlet来完成剩余任务。

        image-20201011145017714

      • 实现命令:

        //1.通过当前对象生成资源文件申请报告对象
        RequestDispatcher report = request.getRequestDispatcher("/资源文件名");//一定以“/”开头
        //2.将报告对象发给Tomcat
        report.forward(当前请求对象,当前响应对象);
        
        protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
            System.out.println("打完麻醉,准备手术");
            //请求转发,获取资源文件请求报告对象
        RequestDispatcher report = request.getRequestDispatcher("/two");
            //将请求报告交给Tomcat
            report.forward(request,response);
        }
        
        
    
- 优点:1.无论设计多少个Servlet,用户只需手动发起一次请求。2.servlet之间调用发生在服务端计算机上,节省服务端与浏览器之间往返次数,增加处理服务速度。
          

    - 特征:

      ​		请求次数:浏览器只发送一次请求
    
        	请求地址:只能向Tomcat服务器申请调用内部资源文件地址【/资源文件名】***不写网站名***
    
        	请求方式:浏览器只发送一个Http请求协议包,所以根据第一次【请求方式】,后面多个Servlet共享一个请求协议包,[**只有一个请求方式]**
    
    - ```java
      System.out.println("打完麻醉,准备手术");
      //请求转发,获取资源文件请求报告对象
      RequestDispatcher report = request.getRequestDispatcher("/two");
            //将请求报告交给Tomcat
      report.forward(request,response);
        }

4.12多个Servlet之间数据共享

  1. 数据共享:OneServlet工作完毕后,将产生数据交给TwoServlet来使用。

  2. Servlet规范中提供四种数据共享方案

    1. ServletContext接口

      image-20201011203107883

      1.介绍:

      ​ -来自于Servlet规范中一个接口,在Tomcat下servlet-api.jar,在Tomcat中负责提供这个接口实现类。

      ​ -如果两个Servlet来自于同一个网站。那彼此之间通过网站的ServletContext实例对象实现数据共享。

      ​ -开发人员习惯于将ServletContext对象称为【全局作用域对象】

      2.工作原理:

      ​ -每一个网站都存在一个【全局作用域对象】,这个全局作用域相当于一个Map。在这个网站中,OneServlet可以将一个数据存放到全局作用域对象,当前网站中其他servlet此时都可以从全局作用域对象得到这个数据进行使用。

      3.全局作用域生命周期:

      ​ -在Httpf服务器启动过程中,自动为当前网站在内存中创建一个全局作用域对象。

      ​ -在Http服务器运行期间,一个网站只有一个全局作用域对象。

      ​ -在Http服务器运行期间,全局作用域对象一直处于存活状态。

      ​ -在Http服务器准备关闭时,负责将当前网站中全局作用域对象进行销毁处理。

      ​ ****全局作用域对象生命周期贯穿网站整个运行期间

      4.命令实现:【同一个网站】OneServlet将数据共享给TwoServlet

      //==================OneServlet============================
      protected void doGet(javax.servlet.http.HttpServletRequest request){
      
       //1.通过【请求对象】获得当前网站【全局作用域对象】
       ServletContext application = request.getServletContext();
       //2.向全局作用域中放置【共享数据】
       application.setAttribute("key1",100);
      }
      //======================TwoServlet================
      protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) {
      
       //1.通过【请求对象】获得当前网站【全局作用域对象】
       ServletContext application = request.getServletContext();
       //2.指定【关键字】获取当前全局作用域中对应的【共享数据】
       Integer key1 = (Integer)application.getAttribute("key1");
       Object key2 = application.getAttribute("key1");//这样也可获取到数据
       System.out.println(key1);
      }
      
      //这样会出现java.lang.NullPointerException异常
      Integer key1 = null;//高级引用可以为null。但原始数据类型 int key1 = null;出错
      int key2 = key1;
      int key1 =(int) application.getAttribute("key1");//这个方式不推荐,防止空指针异常
      

      5.【全局作用域只放关键数据【服务端】】,一般我们只需取数据即可。放数据有高级工程师来做

    2. Cookie接口

      image-20201011221110710

      1.介绍:

      • Cookie来自Servlet规范中一个工具类,存在于Tomcat中servlet-api.jar下
      • 如果两个Servlet[【来自同一个网站】,并且为【同一个浏览器/用户】服务,此时借助Cookie对象进行数据共享。
      • Cookie存放当前用户私人数据,提高服务质量
      • 现实中,相当于用户在服务端得到的【会员卡】

      2.原理:

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

      3.实现命令:同一个网站 OneServlet与TwoServlet借助于Cookie实现数据共享

      /*1.创建一个cookie对象,保存共享数据(当前用户)
      Cookie card = new Cookie("key1":"abc");
      ********Cookie相当于一个Map*********
      *****一个cookie只能存放一个键值对,且类型只能是String****
      *******key不能是中文******************
      2.【发卡】将cookie写道响应头,交给浏览器
      resp.addCookie(card);
      */
      

      image-20201011223945512

      /*
      1.调用请求对象从请求头得到浏览器返回的Cookie
      Cookie cookieArray[] = request.getCookies();
      //2.循环比例cookie数组
      for(Cookie card : cookieArray){
      	String key = card.getName();//键值
      	String value = card.getValue();//value值
      	。。。提供服务
      }
      
      */
      

      4.落地项目:点餐服务 E:\学习文档\数据库课程设计\IDE-Workspace\JavaWeb-Servlet\010-Cookie

      image-20201012135630297

      5.cookie生命周期

      • 默认情况下,Cookie存放在浏览器缓存中,只要浏览器关闭,则cookie对象被销毁

      • 手动设置,可以将cookie对象保存在客户端计算机硬盘上并指定存活时间。关闭服务器,计算机,客户端都不会导致被销毁。直到存活时间到达。

        cookie.setMaxAge(60);//cookie在硬盘存活时间为1分钟.

    3. HttpSession接口

      image-20201013144237595

      image-20201013144338069

      image-20201013144422785

      image-20201013144540813

      image-20201013144603085

      4.购物车项目:E:\学习文档\数据库课程设计\IDE-Workspace\JavaWeb-Servlet\011-HttpSession

      image-20201013144051061

      5.HttpSession与用户关联原理图

      image-20201013144846693

      6.getSession与getSession(false)

      image-20201013144951673

      7.HttpSession销毁时机:

      image-20201013145101219

      8.手动设置空闲时间(下图5分钟)

      image-20201013145303180

    4. HttpServletRequest接口实现共享

      1.介绍:

      • 在【同一个网站中】如果两个Servlet之间通过【请求转发】方式调用,彼此之间共享同一个【请求协议包】。而一个请求协议包只对应一个请求对象,因此servlet之间【共享同一个请求对象】。可以利用这个请求对象实现两个servlet之间数据共享。
      • 在请求对象实现servlet之间数据共享功能时,开发人员将请求对象称为【请求作用域对象】

      2.命令实现:(比较简单常用

      image-20201013151402470

4.13 Servlet扩展-----监听器接口

  1. 介绍:

    image-20201013151848609

  2. 监听器接口实现类开发规范:三步

    1. 根据监听实际情况,选择对应的监听器接口进行实现
    2. 重写监听器接口声明【监听事件处理方法】
    3. 在web.xml文件将监听器接口实现类注册到Http服务器。
  3. ServletContextListener接口:

    image-20201013152643270

  4. 代码实现:ServletContextListener接口

    public class OneservletListener implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            System.out.println("欢迎到来");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
    
            System.out.println("拜拜,不送");
        }
    }
    <!--将ServletCintextListener注册到Tomcat-->
        <listener>
        	<listener-class>com.codesing.listener.OneservletListener</listener-class>
        </listener>
    
  5. ServletContextAttributeListener接口:

    image-20201013153255650

  6. 全局作用域对象共享数据变化时刻

    image-20201013153412463

  7. 代码实现ServletContextAttributeListener接口:

    public class OneListener implements ServletContextAttributeListener {
        @Override
        public void attributeAdded(ServletContextAttributeEvent scae) {
            System.out.println("添加共享数据");
        }
    
        @Override
        public void attributeRemoved(ServletContextAttributeEvent scae) {
            System.out.println("删除共享数据");
        }
    
        @Override
        public void attributeReplaced(ServletContextAttributeEvent scae) {
            System.out.println("更新共享数据");
        }
    }
    //============OneServlet============
     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            ServletContext application = request.getServletContext();
            application.setAttribute("key1","共享数据");
            application.setAttribute("key1","更新共享数据");
            application.removeAttribute("key1");
        }
    //============web.xml====================
     <!--注册监听器-->
        <listener>
            <listener-class>com.codesing.listener.OneListener</listener-class>
        </listener>
        <servlet>
            <servlet-name>OneServlet</servlet-name>
            <servlet-class>com.codesing.controller.OneServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>OneServlet</servlet-name>
            <url-pattern>/one</url-pattern>
        </servlet-mapping>
    

4.14 监听器作用之-------》提高程序运行速度

E:\学习文档\数据库课程设计\IDE-Workspace\JavaWeb-Servlet\005-在线考试系统(只看注册功能。利用重载)

//======================监听器===================================
public class OneListener implements ServletContextListener {
    //Tomcat启动时事先创建好20个Connection,在userDao.add方法执行时将创建好的connection交给add方法
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        Map map = new HashMap();
        for (int i = 0; i < 20; i++) {
            try {
                Connection conn = JDBCUtil.getConnection();
                System.out.println("在Tomcat启动时创建connection"+i+":"+conn);
                map.put(conn,true);//true表示通道空闲,false表示通道正在使用
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //为了在Http服务器运行期间,一直都可以使用这20个connection,将其保存到【全局作用域对象中】
        ServletContext application = sce.getServletContext();//获取全局作用域对象
        application.setAttribute("key1",map);
    }
    //map被销毁
    //Http服务器关闭时,20个connection被销毁
    @Override
    public void contextDestroyed(ServletContextEvent sce) {

        ServletContext application = sce.getServletContext();
        Map map = (Map)application.getAttribute("key1");
        Iterator it = map.keySet().iterator();
        while (it.hasNext()){
            Connection conn = (Connection)it.next();
            if (conn != null){
                System.out.println("我"+conn+"先走一步");
            }
        }

    }
}

4.15 过滤器—Filter过滤器

image-20201013231417405

image-20201013231447440

4.16 过滤器接口检测请求合法性

public class OneFilter implements Filter {

    @Override
    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){//合法请求
            //将拦截请求对象和响应对象交还给Tomcat,由Tomcat继续调用资源文件
            filterChain.doFilter(servletRequest,servletResponse);//放行
        }else{
            //过滤器代替Http服务器拒绝本次请求
            servletResponse.setContentType("text/html;charset=utf-8");
            PrintWriter out = servletResponse.getWriter();
            out.print("<center><font style='color:red;font-size:40px'>大爷,珍惜生命</font></center>");
        }
    }
}
//============web.xml===================
<filter>
    <filter-name>OneFilter</filter-name>
    <filter-class>com.codesing.filter.OneFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>OneFilter</filter-name>
    <url-pattern>/mm.jpg</url-pattern>
 </filter-mapping>

4.17 过滤器对拦截请求增强操作

image-20201014000244276

public class OneFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //通知拦截请求对象,使用UTF-8对请求体对象进行一次重新编辑
        servletRequest.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }
    //===========================================
 <filter>
        <filter-name>OneFilter</filter-name>
        <filter-class>com.codesing.filter.OneFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>OneFilter</filter-name>
        <url-pattern>/*</url-pattern><!--所有请求资源都拦截-->
    </filter-mapping>

4.18 Filter拦截地址格式

image-20201014132125889

image-20201014132143734

4.19 恶意登录

  1. 令牌机制(靠session,但有缺点)

    image-20201014133740818

  2. 添加过滤器

    image-20201014134153133

  3. 过滤器防止恶意登录

    E:\学习文档\数据库课程设计\IDE-Workspace\JavaWeb-Servlet\005-在线考试系统

    package com.codesing.controller;
    
    import com.codesing.dao.UserDao;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    /**
     * @author: JZQ
     * @Date: 2020/10/11 11:42
     * @Version 1.0
     */
    public class UserLoginServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获取请求体参数,记得修改【请求对象】编码
            request.setCharacterEncoding("utf-8");
            //获取【请求体】参数
            String loginName = request.getParameter("loginName");
            String loginPassword = request.getParameter("loginPassword");
            //调用Dao层数据库查询
            UserDao userDao = new UserDao();
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out = response.getWriter();
            int result = userDao.login(loginName,loginPassword);
            if (result == 1){
                HttpSession session = request.getSession();//发放令牌
                response.sendRedirect("/myWeb/index.html");
            }else{
                response.sendRedirect("/myWeb/login_error.html");
            }
        }
    
    }
    

5.JDBC规范

5.1 JDBC简介

  1. Java DataBase Connectivity(Java 语言连接数据库)

  2. SUN公司制定的一套接口。java.sql.*

    为什么?每个数据库底层实现原理都不一样,为了方便开发统一接口。

    image-20201008101827077

  3. 接口都有调用者和实现者----》面向接口编程

  4. 面向接口作用:解耦合,降低耦合度,提高程序扩展力。

  5. 多态机制就是典型的面向抽象编程(不面向具体编程)

5.2 JDBC使用

  1. 模拟sun公司,数据库厂家,程序员三个角色设计JDBC.。代码:E:\Setup_Java\code\模拟JDBC

  2. JDBC编程六步曲:

    1.注册驱动(告诉java程序,将要连接哪个品牌数据库)

    2.获取连接 (JVM进程和数据库进程通道打开,进程间通信,重量级的,使用完记得关闭)

    3.获取数据库操作对象(专门执行SQL语句)

    4.执行SQl语句(DQL,DML…)

    5.处理查询结果集(第四步执行select操作时,才有查询结果集)

    6.释放资源(使用完一定要释放资源。)

    练习代码:

    **E:\Setup_Java\code\连接数据库mysql**以及

    E:\学习文档\数据库课程设计\IDE-Workspace\JavaWeb-Servlet\006-用户登录JDBC练习

  3. package com.codesing;
    
    import java.sql.*;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Scanner;
    /**
     * 问题:SQL注入,扭曲了原sql语句意思
     *      请输入用户名:fasd
     *      请输入密码:fasd' or '1'='1
     *      登录成功!
     *解决方案:Statement改为PreparedStatement对象。进行预编译sql语句,防止SQL注入。
     *      请输入用户名:fasd
     *      请输入密码:fasd' or '1'='1
     *      登录失败!
     */
    /**
     *Statement和PreparedStatement区别?
     *      1.Statement存在SQL注入问题,PreparedStatement不存在SQL注入问题
     *      2.Statement编译一次执行一次,PreparedStatement编译一次,执行N次,PreparedStatement效率较高。
     *      3.PreparedStatement会在编译阶段进行类型安全检查
     *     综上:大多数情况用PreparedStatement,只有业务要求可以SQL注入,需要进行SQL语句拼接的时候用Statement(比如商城价格升序降序展示时)。
     */
    public class JDBCTest01 {
        public static void main(String[] args) {
           Map<String,String> userInfo = InitUI();
           boolean loginsuccess = login(userInfo);
            System.out.println(loginsuccess?"登录成功!":"登录失败!");
           
        }
        /**
         * 用户登录认证
         *@param userInfo 用户登录信息
         *@return 登录结果
         */
        private static boolean login(Map<String, String> userInfo) {
            boolean flag = false;//登陆标记
            Connection conn = null;
            //Statement smt = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                //1.注册驱动
                Class.forName("com.mysql.cj.jdbc.Driver");//静态方法已经注册好了。
                //2.连接
               conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8",
                        "root","JZQjzq19960616");
                //3.获取数据库操作对象
                //smt = conn.createStatement();
                //3.获取数据库预编译操作对象
                ps = conn.prepareStatement("select* from user where username = ? and password = ?");//"?"占位符
                //4.执行sql语句
                String username = userInfo.get("username");
                String password = userInfo.get("password");
                //rs = smt.executeQuery("select* from user where username='"+username+"'and password='"+password+"'");
                ps.setString(1,username);//JDBC所有下标从1开始。给占位符位置给值。setInt(),setDouble()。。。。
                ps.setString(2,password);
                rs = ps.executeQuery();
                //5.处理结果集
                flag = rs.next();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {//6.释放资源
               try{
                   if(rs != null){
                       rs.close();
                   }
               }catch(SQLException e){
                   e.printStackTrace();
               }
                try{
                    if(ps != null)
                        ps.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
                try{
                    if(conn != null)
                        conn.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
            return flag;
        }
    
        /**
         * 初始化用户登录界面
         *@return 返回用户输入的用户名和密码信息
         */
        private static Map<String, String> InitUI() {
            Map<String,String> userinfo = new HashMap<>();
            Scanner sc = new Scanner(System.in);
            System.out.print("请输入用户名:");
            String username = sc.hasNextLine()? sc.nextLine():null;
            userinfo.put("username",username);
            System.out.print("请输入密码:");
            String password = sc.hasNextLine()? sc.nextLine():null;
            userinfo.put("password",password);
            return userinfo;  
        }
    }
    
package com.codesing;

/**
 * JDBC事务控制
 * @author: JZQ
 * @Date: 2020/10/9 14:18
 * @Version 1.0
 */

import java.sql.*;

/**
  *JDBC 默认执行一次DML操作,提交一次。这样会导致出现问题,比如银行转账,中间出现异常,则导致余额出现异常
 * 三行代码:
 *          conn.setAutoCommit(false);//开启事务(手动提交)
 *          conn.commit();//提交事务
 *          conn.rollback();//回滚事务
 */
public class JDBCTest02 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        int count = 0;
        try {
            /*=====================自动提交事务出问题================
            //1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");//静态方法已经注册好了。
            //2.连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8",
                    "root","JZQjzq19960616");
            //3.获取数据库预编译操作对象
            String sql = "update t_act set balance = ? where actno = ?";//"?"占位符
            ps = conn.prepareStatement(sql);
            //4.执行sql语句
            ps.setDouble(1,10000);//原先2000,转走10000.
            ps.setInt(2,111);
            count = ps.executeUpdate();

            //假设这里出现异常,则下面代码不执行,会进去catch模块。那么账号111会少10000元
            String str = null;
            str.toString();

            ps.setDouble(1,10000);//原先0,转进10000.
            ps.setInt(2,222);
            count += ps.executeUpdate();
            //5.处理结果集
            System.out.println(count == 2? "转账成功!":"转账失败!");
            ========================设置手动提交事务===============================*/
            //1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");//静态方法已经注册好了。
            //2.连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8",
                    "root","JZQjzq19960616");
            //关闭自动提交设置手动提交事务
            conn.setAutoCommit(false);//开启事务
            //3.获取数据库预编译操作对象
            String sql = "update t_act set balance = ? where actno = ?";//"?"占位符
            ps = conn.prepareStatement(sql);

            //4.执行sql语句
            ps.setDouble(1,10000);//原先2000,转走10000.
            ps.setInt(2,111);
            count = ps.executeUpdate();

            //假设这里出现异常,则下面代码不执行,会进去catch模块。那么账号111会少10000元
            String str = null;
            str.toString();

            ps.setDouble(1,10000);//原先0,转进10000.
            ps.setInt(2,222);
            count += ps.executeUpdate();
            //5.处理结果集
            System.out.println(count == 2? "转账成功!":"转账失败!");
            //执行到这里说明程序正常执行完毕,提交事务。
            conn.commit();//提交事务
        } catch (Exception e) {
            //如果出现异常,回滚事务。
            if(conn != null){
                try{
                    conn.rollback();//回滚事务
                }catch (SQLException e1){
                    e1.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {//6.释放资源
            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (ps != null)
                    ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

5.3 JDBC封装

package com.codesing.util;

import java.sql.*;

/**
 * JDBC工具类,简化JDBC编程
 * @author: JZQ
 * @Date: 2020/10/9 14:51
 * @Version 1.0
 */
public class JDBCUtil {

    private JDBCUtil(){}//构造方法私有化,防止别人new对象,所有方法直接类名调用。
    //静态代码块在类加载时执行,并且只执行一次
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取连接数据库连接对象
     *@return Connection 返回连接对象
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8",
                "root","JZQjzq19960616");
    }
    /**
     * 关闭资源
     * conn数据库连接对象
     * ps数据库操作对象
     * rs结果集
     */
    public static void close(Connection conn, Statement ps, ResultSet rs){
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (ps != null)
                ps.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null)
                conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
package com.codesing;

import com.codesing.util.JDBCUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//=============================================================
/**
 *  利用JDBC工具类
 *  模糊查询
 * @author: JZQ
 * @Date: 2020/10/9 15:13
 * @Version 1.0
 */
public class JDBCTest03 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            conn = JDBCUtil.getConnection();
            conn.setAutoCommit(false);
            String sql = "select * from user where username like ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,"j%");
            rs = ps.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("username"));
            }
            conn.commit();
        } catch (SQLException e) {
            if (conn != null){
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
            JDBCUtil.close(conn,ps,rs);
        }
    }
}

5.4 悲观锁和乐观锁

image-20201009173402122

6.互联网通信最终版

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值