web后端(javaWeb)

1.javaweb简介

javaweb是什么?可以做什么?

Java web ,是用Java技术来解决相关web互联网领域的技术的总称。web包括web服务器和web客户端两部分。从事Java web开发需要掌握以下技术:

基于页面的前端技术,如:HTML、CSS、JavaScript、JQuery;

动态语言技术,如:Java、JSP;

数据库技术,如:Oracle、MySQL、Sql Server;

工具与组件,如:服务器、SSM、SSH框架等。

javaweb的应用范围
1.开发网站(如淘宝,京东等大型网站)
2.ERP系统,财务系统,运营管理系统
3.游戏后台开发
4.手机app的后台开发
学习Javaweb之前需要做的事情
1.下载jdk,并且安装jdk配置好环境变量,因为只要java开发都需要用的jdk环境(如果不会的百度,会有很多安装办法的)。
2.Tomcat的安装
3.IntelliJ IDEA 软件的安装(java开发编辑器)当然也可以用其他的,只是这个比较好用,而且大多数企业开发都是用这。

2.XML

什么是 xml?
xml 是可扩展的标记性语言。

xml 的作用?
1、用来保存数据,而且这些数据具有自我描述性
2、它还可以做为项目或者模块的配置文件
3、还可以做为网络传输数据的格式(现在 JSON 为主)。

3、xml 语法

  1. 文档声明。 2. 元素(标签) 3. xml 属性 4. xml 注释 5. 文本区域(CDATA 区)
    文档声明

创建一个 xml 文件
在这里插入图片描述

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

version 是版本的意思 encoding 是编码

而且这个<?xml 要连在一起写,否则会有报错

属性 version :是版本号

encoding 是: xml 的文件编码

xml 注释
html 和 XML 注释 一样: <!-- 注释内容 -->

元素(标签)
标签名大小写不敏感 标签有属性,有基本属性和事件属性 标签要闭合(不闭合 ,html 中不报错。但我们要养成良好的书写习惯。闭合)

什么是 xml 元素
元素是指从开始标签到结束标签的内容。

XML 命名规则
名称可以含字母、数字以及其他的字符
名称不能以数字或者标点符号开始
名称不能以字符 “xml”(或者 XML、Xml)开始 (它是可以的)
名称不能包含空格

xml 中的元素(标签
也 分成 单标签和双标签:
单标签 格式: <标签名 属性=”值” 属性=”值”… />
双标签 格式:< 标签名 属性=”值” 属性=”值”…>文本数据或子标签</标签名>

xml 属性
xml 的标签属性和 html 的标签属性是非常类似的,属性可以提供元素的额外信息
在标签上可以书写属性: 一个标签上可以书写多个属性。每个属性的值必须使用 引号 引起来。 的规则和标签的书写规则一致。
属性必须使用引号引起来,不引会报错

语法规则:
所有 XML 元素都须有关闭标签(也就是闭合)
XML 标签对大小写敏感
XML 必须正确地嵌套
XML 文档必须有根元素
XML 的属性值须加引号

根元素就是顶级元素, 没有父标签的元素,叫顶级元素。 根元素是没有父标签的顶级元素,而且是唯一一个才行。

XML 中的特殊字符
在这里插入图片描述

文本区域(CDATA区)
CDATA 语法可以告诉 xml 解析器,我 CDATA 里的文本内容,只是纯文本,不需要 xml 语法解析

CDATA 格式: <![CDATA[ 这里可以把你输入的字符原样显示,不会解析 xml]]>
在这里插入图片描述

xml 解析技术介绍

xml 可扩展的标记语言。 不管是 html 文件还是 xml 文件它们都是标记型文档,都可以使用 w3c 组织制定的 dom 技术来解析。
document 对象表示的是整个文档(可以是 html 文档,也可以是 xml 文档)
早期 JDK 为我们提供了两种 xml 解析技术 DOM 和 Sax 简介(已经过时,但我们需要知道这两种技术)

dom 解析技术是 W3C 组织制定的,而所有的编程语言都对这个解析技术使用了自己语言的特点进行实现。 Java 对 dom 技术解析标记也做了实现

sun 公司在 JDK5 版本对 dom 解析技术进行升级:SAX( Simple API for XML ) SAX 解析,它跟 W3C 制定的解析不太一样。它是以类似事件机制通过回调告诉用户当前正在解析的内容。 它是一行一行的读取 xml 文件进行解析的。不会创建大量的 dom 对象。 所以它在解析 xml 的时候,在内存的使用上。和性能上。都优于 Dom 解析。
第三方的解析: jdom 在 dom 基础上进行了封装 、 dom4j 又对 jdom 进行了封装。 pull 主要用在 Android 手机开发,是在跟 sax 非常类似都是事件机制解析 xml 文件。
这个 Dom4j 它是第三方的解析技术。我们需要使用第三方给我们提供好的类库才可以解析 xml 文件。

dom4j 解析技术(重点***)**

由于 dom4j 它不是 sun 公司的技术,而属于第三方公司的技术,我们需要使用 dom4j 就需要到 dom4j 官网下载 dom4j 的 jar 包。
3.1、Dom4j 类库的使用

dom4j 目录的介绍:
docs 是 文 档 目 录
2如何查 Dom4j 的文档
Dom4j 快速入门
lib 目录
src 目录是第三方类库的源码目录:
在这里插入图片描述

dom4j 编程步骤:
第一步: 先加载 xml 文件创建 Document 对象 第二步:通过 Document 对象拿到根元素对象 第三步:通过根元素.elelemts(标签名); 可以返回一个集合,这个集合里放着。所有你指定的标签名的元素对象 第四步:找到你想要修改、删除的子元素,进行相应在的操作 第五步,保存到硬盘上
3.4、获取 document 对象
创建一个 lib 目录,并添加 dom4j 的 jar 包。并添加到类路径。
需要解析的 books.xml 文件内容

**遍历 标签 获取所有标签中的内容(***重点)

需要分四步操作:
第一步,通过创建 SAXReader 对象。来读取 xml 文件,获取 Document 对象
第二步,通过 Document 对象。拿到 XML 的根元素对象
第三步,通过根元素对象。获取所有的 book 标签对象
第四小,遍历每个 book 标签对象。然后获取到 book 标签对象内的每一个元素,再通过 getText() 方法拿到起始标签和结 束标签之间的文本内容
读取 xml 文件中的内容
需要分四步操作:
第一步,通过创建 SAXReader 对象。来读取 xml 文件,获取 Document 对象
第二步,通过 Document 对象。拿到 XML 的根元素对象
第三步,通过根元素对象。获取所有的 book 标签对象
第四小,遍历每个 book 标签对象。然后获取到 book 标签对象内的每一个元素,再通过 getText() 方法拿到
起始标签和结束标签之间的文本内容

代码示例:
books类:

package com.book.pojo;

import org.dom4j.Element;

public class books {
    
    
    private String sn;
    private String name;
    private String price;
    private  String author;


    //get和set方法
    public String getSn() {
    
    
        return sn;
    }

    public void setSn(String sn) {
    
    
        this.sn = sn;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getPrice() {
    
    
        return price;
    }

    public void setPrice(String price) {
    
    
        this.price = price;
    }

    public String getAuthor() {
    
    
        return author;
    }

    public void setAuthor(String author) {
    
    
        this.author = author;
    }

    //toString方法
    public String toString() {
    
    
        return "books{" +
                "sn='" + sn + '\'' +
                ", name='" + name + '\'' +
                ", price='" + price + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
 //无参构造方法
    public books() {
    
    
    }
//有参构造方法
    public books(String sn, String name, String price, String author) {
    
    
        this.sn = sn;
        this.name = name;
        this.price = price;
        this.author = author;
    }

}

Demo4jTest:

package com.book.pojo;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.util.List;

//使用Dom4j读取xml文件
public class Dom4jTest {
    
    
    public static void main(String[] args) throws DocumentException {
    
    
        Test1();
        Test2();
    }

    public static void Test1() throws DocumentException {
    
    
        //创建一个 SAXReader输入流对象,去读取xml配置文件,生成document对象
        SAXReader saxReader = new SAXReader();
       Document document= saxReader.read("src/books.xml");
        System.out.println(document);

    }
    //读取books生成的xml类
    public static  void Test2() throws DocumentException {
    
    
        //1.读取booksxml文件
        SAXReader reader = new SAXReader();
        //在测试中,相对路径是从模块名开始
        Document document = reader.read("src/books.xml");
        //2.通过文档对象获取根元素
        Element RootElement = document.getRootElement();
        System.out.println(RootElement);
        //3.通过根元素获取标签对象
        //element(访问一个)和elements(访问多个)都是通过标签名查找子元素
       List<Element >  books = RootElement.elements("book");
        //4.遍历,处理每个book标签转换为book类
        for(Element book : books){
    
    
//            asXML()把标签对象转换为字符串
            Element nameElement= book.element("name");
            System.out.println(nameElement.asXML());
            //getText()可以获取标签中的文本内容
            String nameText= nameElement.getText();
            System.out.println(nameText);
            //elementText方法直接获取指定标签名的元素内容
            String priceText = book.elementText("price");
            System.out.println(priceText);

            Element authorElement = book.element("author") ;

            String snValue =book.attributeValue("sn");
            System.out.println(new books(snValue,nameText,priceText, authorElement.asXML()));


        }

    }
}

3.Tomcat服务器

Web 资源的分类
web 资源按实现的技术和呈现的效果的不同,又分为静态资源和动态资源两种。

静态资源: html、css、js、txt、mp4 视频 ,jpg 图片
动态资源: jsp 页面、Servlet 程序

常用的 Web 服务器

Tomcat:由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它是一种轻量级的 javaWeb 容器(服务 器),也是当前应用最广的 JavaWeb 服务器(免费)。

Jboss:是一个遵从 JavaEE 规范的、开放源代码的、纯 Java 的 EJB 服务器,它支持所有的 JavaEE 规范(免费)。

GlassFish: 由 Oracle 公司开发的一款 JavaWeb 服务器,是一款强健的商业服务器,达到产品级质量(应用很少)。

Resin:是 CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了良好的支持, 性能也比较优良,resin 自身采用 JAVA 语言开发(收费,应用比较多)。

WebLogic:是 Oracle 公司的产品,是目前应用最广泛的 Web 服务器,支持 JavaEE 规范, 而且不断的完善以适应新的开发要求,适合大型项目(收费,用的不多,适合大公司)。

Tomcat 的使用

找到你需要用的 Tomcat 版本对应的 zip 压缩包,解压到需要安装的目录即可(不需要安装)。

目录介绍

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

如何启动 Tomcat 服务器

找到 Tomcat 目录下的 bin 目录下的 startup.bat 文件,双击,就可以启动 Tomcat 服务器。
测试Tomcat服务器是否启动成功

在这里插入图片描述如果出现该页面:说明启动成功
在这里插入图片描述常见的启动失败的情况有
双击 startup.bat 文件,就会出现一个小黑窗口一闪而来。 这个时候,失败的原因基本上都是因为没有配置好 JAVA_HOME 环境变量。

配置jdk环境变量注意点:

在这里插入图片描述另一种启动 tomcat 服务器的方式

在这里插入图片描述如何修改 Tomcat 的端口号
在这里插入图片描述如何部暑 web 工程到 Tomcat 中

在 webapps 目录下创建一个 book 工程
在这里插入图片描述

如何访问 Tomcat 下的 web 工程。
在这里插入图片描述
在这里插入图片描述
第二种部署方法
在这里插入图片描述abc.xml 配置文件内容如下:
在这里插入图片描述
输入访问地址访问的原因:

在这里插入图片描述ROOT 的工程的访问,以及 默认 index.html 页面的访问
在这里插入图片描述
IDEA 整合 Tomcat 服务器

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
IDEA 中动态 web 工程的操作
在这里插入图片描述2、选择你要创建什么类型的模块:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述Web 工程的目录介绍

在这里插入图片描述如何给动态 web 工程添加额外 jar 包

1、可以打开项目结构菜单操作界面,添加一个自己的类库
在这里插入图片描述

在这里插入图片描述2、添加你你类库需要的 jar 包文件。
在这里插入图片描述
3、选择你添加的类库,给哪个模块使用:

在这里插入图片描述
选择 Artifacts 选项,将类库,添加到打包部署中:

在这里插入图片描述
如何在 IDEA 中部署工程到 Tomcat 上运行

1、建议修改 web 工程对应的 Tomcat 运行实例名称:
在这里插入图片描述

2、确认你的 Tomcat 实例中有你要部署运行的 web 工程模块:

在这里插入图片描述
3、你还可以修改你的 Tomcat 实例启动后默认的访问地址:

在这里插入图片描述正常启动 Tomcat 实例
在这里插入图片描述

Debug 方式启动 Tomcat 运行实例
在这里插入图片描述

停止 Tomcat 运行实例:
在这里插入图片描述

重启 Tomcat 运行实例

在这里插入图片描述修改工程访问路径
在这里插入图片描述修改运行的端口号
在这里插入图片描述配置资源热部署

在这里插入图片描述

4.Servlet1

什么是 Servlet?

1、Servlet 是 JavaEE 规范之一。规范就是接口 2、Servlet 就 JavaWeb 三大组件之一。三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。 3、Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。

手动实现 Servlet 程序

1、编写一个类去实现 Servlet 接口
2、实现 service 方法,处理请求,并响应数据 3、到 web.xml 中去配置 servlet 程序的访问地址
Servlet 程序的示例代码:

在这里插入图片描述web.xml 中的配置:

在这里插入图片描述
url 地址到 Servlet 程序的访问原理

在这里插入图片描述Servlet 的生命周期
1、执行 Servlet 构造器方法
2、执行 init 初始化方法
第一、二步,是在第一次访问,的时候创建 Servlet 程序会调用。

3、执行 service 方法 第三步,每次访问都会调用。
4、执行 destroy 销毁方法 第四步,在 web 工程停止的时候调用。

GET 和 POST 请求的分发处理

package com.atguigu.servlets;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class HelloServlet  implements Servlet {
    
    
    public HelloServlet(){
    
    
        System.out.println("1.构造器方法");
    }
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
    
    
        System.out.println("2.初始化方法");

    }

    @Override
    public ServletConfig getServletConfig() {
    
    
        return null;
    }

    //service:专门用来处理请求和相应的
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    
    
        System.out.println("3.hello servlet 被访问了==每次执行都会调用");
//        System.out.println("get请求方法");
//        System.out.println("post请求方法");
        //类型转换
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        //获取请求方式
        String method = httpServletRequest.getMethod();
        System.out.println(method);//输出get
        if("GET".equals(method)){
    
    
           doGet();
        }
            else {
    
    
           doPost();
        }

}
//get请求处理方法
    public  void doGet(){
    
    
        System.out.println("get请求方法");
}
//post请求处理方法
    public  void doPost(){
    
    
        System.out.println("psot请求方法");
    }

    @Override
    public String getServletInfo() {
    
    
        return null;
    }

    @Override
    public void destroy() {
    
    
        System.out.println("4.销毁方法:web工程停止的时候调用");
    }
}

通过继承 HttpServlet 实现 Servlet 程序
一般在实际项目开发中,都是使用继承 HttpServlet 类的方式去实现 Servlet 程序。

1、编写一个类去继承 HttpServlet 类
2、根据业务需要重写 doGet 或 doPost 方法
3、到 web.xml 中的配置 Servlet 程序的访问地址

Servlet 类的代码:

package com.atguigu.servlets;

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 HelloServlet2 extends HttpServlet {
    
    


    //    doGet:在get请求方法时候调用
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        System.out.println("HelloServlet2的 get方法");
    }


    //    doGet:在post请求方法时候调用
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        System.out.println("HelloServlet2的 post方法");
    }


}

webxml配置文件

<!--    HellpSevlet2配置文件-->
<servlet>
    <servlet-name>HellpSevlet2</servlet-name>
    <servlet-class>com.atguigu.servlets.HelloServlet2</servlet-class>
</servlet>

    <servlet-mapping>
        <servlet-name>HellpSevlet2</servlet-name>
        <url-pattern>/hello2</url-pattern>
    </servlet-mapping>

使用 IDEA 创建 Servlet 程序

在这里插入图片描述
在这里插入图片描述右键点击没有servlet属性的方法

在这里插入图片描述

Servlet 类的继承体系
在这里插入图片描述ServletConfig 类
ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类。

Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用。 Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对
象。
ServletConfig 类的三大作用

1、可以获取 Servlet 程序的别名 servlet-name 的值
2、获取初始化参数 init-param
3、获取 ServletContext 对象

在这里插入图片描述
Servlet 中的代码

在这里插入图片描述在这里插入图片描述
否则会发生空指针异常

ServletContext 类
什么是 ServletContext?

1、ServletContext 是一个接口,它表示 Servlet 上下文对象
2、一个 web 工程,只有一个 ServletContext 对象实例。
3、ServletContext 对象是一个域对象。
4、ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。

什么是域对象?
域对象,是可以像 Map 一样存取数据的对象,叫域对象。 这里的域指的是存取数据的操作范围,整个 web 工程。

在这里插入图片描述ServletContext 类的四个作用

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

ServletContext 像 Map 一样存取数据:

xml配置:
在这里插入图片描述ContextServlet1代码:

package servlets;

import javax.servlet.ServletContext;
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 ContextServlet1 extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
//获取servletcontext对象
        ServletContext servletContext = getServletContext();
        System.out.println(servletContext);

        System.out.println("未加入数据之前"+servletContext.getAttribute("value"));
       servletContext.setAttribute("key1","value");

        System.out.println("加入之后的数据是:"+servletContext.getAttribute("key1"));
    }
}

ContextServlet2代码:

package servlets;

import javax.servlet.ServletContext;
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 ContextServlet1 extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
//获取servletcontext对象
        ServletContext servletContext = getServletContext();
        System.out.println(servletContext);

        System.out.println("未加入数据之前"+servletContext.getAttribute("value"));
       servletContext.setAttribute("key1","value");

        System.out.println("加入之后的数据是:"+servletContext.getAttribute("key1"));
    }
}

5.1协议互联网通信模型

1.C/S通信模型:
C,client software;客户端软件
1.客户端软件专门安装在客户端计算机上
2.帮助客户端计算机向指定服务端计算机发送请求,索要资源文件
3.帮助客户端计算机将服务端计算机发送回来【二进制数据】解析
为【文字,数字,图片,视频,命令】

S,server software;服务器软件
1.服务器软件专门安装在服务端计算机上
2.服务器软件用于接收来自于特定的客户端软件发送请求
3.服务器软件在接收到请求之后自动的在服务端计算机上定位被访问的资源文件
4.服务器软件自动的将定位的文件内容解析为【二进制数据】通过网络发送回,发起请求的客户端软件上

适用场景:
C/S通信模型普遍用于个人娱乐市场,比如【微信,淘宝/京东,视频(优酷/B站),大型网络游戏(魔兽/英雄联盟)】
企业办公领域相对应用较少

优缺点:

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

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

2.B/S通信模型:

B:browser,浏览器
1.浏览器安装在客户端计算机软件
2.可以向任意服务器发送请求,索要资源文件
3.可以将服务器返回的【二进制数据】解析为
【文字,数字,图片,视频,命令】

S: server software 服务器软件
1.服务器软件专门安装在服务端计算机上
2.可以接收任意浏览器发送请求
3.自动的在服务端计算机上定位被访问的资源文件
4.自动的将定位的资源文件内容以二进制形式发送回发起请求浏览器上

适用场景: 既适用于个人娱乐市场,又广泛适用于企业日常活动

优缺点:

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

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

共享资源文件:

1.什么是共享资源文件:
可以通过网络进行传输的文件,都被称为共享资源文件
所有的文件内容都可以通过网络传输,所有文件都是共享资源文件

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

1.静态资源文件

1 .如果文件内容是固定,这种文件可以被称为【静态资源文件】
(文档,图片,视频)

2.如果文件存放不是内容而是命令,这些命令只能在浏览器编译与执行这种文件可以被称为【静态资源文件】.html,.css,.js)

2.动态资源文件:

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

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

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

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

5.2HTTP

简单理解HTTP协议:
HTTP协议是HyperText Transfer Protocol(超文本传输协议)的缩写,是用于从万维网。

在这里插入图片描述(www:World Wide Web)服务器传输超文本到本地浏览器的传送协议。
什么是 HTTP 协议?
协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议。

所谓 HTTP 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫 HTTP 协议。
HTTP 协议中的数据又叫报文。

请求的 HTTP 协议格式
客户端给服务器发送数据叫请求。
服务器给客户端回传数据叫响应。

HTTP协议的特点

  1. 简单快速 客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每 种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模 小,因而通信速度很快。 2. 灵活 HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

  2. 无连接 无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后, 即断开连接。采用这种方式可以节省传输时间。

  3. 无状态 HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续 处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服 务器不需要先前信息时它的应答就较快。 5. 支持B/S及C/S模式

    web——INF(此文件夹下的文件是不能通过浏览器直接访问的)
    web——INF(以外的文件可以通过浏览器访问)
    class:class文件放置的位置
    HTTP协议的组成:
    HTTP请求协议包括:请求行,请求头,请求体
    HTTP响应协议包括:响应行,响应头,响应体

    什么是请求行
    例如:POST /post.html HTTP /1.1
    请求格式:请求方式 资源路径 协议/版本

    get请求:
    1、请求行 (1) 请求的方式 GET
    (2) 请求的资源路径[+?+请求参数]
    (3) 请求的协议的版本号 HTTP/1.1 2、请求头 key:value 组成 不同的键值对,表示不同的含义。
    get和post区别
    get是读数据post是存数据
    在这里插入图片描述

    post请求:
    1、请求行 (1) 请求的方式 POST
    (2) 请求的资源路径[+?+请求参数]
    (3) 请求的协议的版本号 HTTP/1.1 2、请求头 1)
    key:value 不同的请求头,有不同的含义 空行
    3、请求体 (空行) ===>>> 就是发送给服务器的数据
    在这里插入图片描述
    常用请求头的说明
    Accept: 表示客户端可以接收的数据类型
    Accpet-Languege: 表示客户端可以接收的语言类型
    User-Agent: 表示客户端浏览器的信息
    Host: 表示请求时的服务器 ip 和端口号
    GET 请求有哪些:
    1、form 标签 method=get
    2、a 标签
    3、link 标签引入 css
    4、Script 标签引入 js 文件
    5、img 标签引入图片
    6、iframe 引入 html 页面
    7、在浏览器地址栏中输入地址后敲回车
    POST 请求有哪些:
    8、form 标签 method=post

HTTP响应

(1) 响应的协议和版本号
(2) 响应状态码
(3) 响应状态描述符
2、响应头 (1) key:value 不同的响应头,有其不同含义 空行 3、响应体 ---->>> 就是回传给客户端的数据
在这里插入图片描述常用的响应码说明:

HTTP响应码,也称http状态码(HTTP Status Code),反映了web服务器处理HTTP请求状态,每一个响应码都代表了一种服务端反馈的响应状态,标识了本次请求是否成功。我们应该了解常见的响应码代表的状态,通过响应码能够对错误进行排查和定位。

1XX——信息类(Information)

表示收到http请求,正在进行下一步处理,通常是一种瞬间的响应状态

100 (Continue):信息型状态响应码表示目前为止一切正常, 客户端应该继续请求, 如果已完成请求则忽略
101 (Switching Protocol):状态码表示服务器应客户端升级协议的请求(Upgrade请求头)正在进行协议切换。

2XX——成功类(Successful)

表示用户请求被正确接收、理解和处理

200(OK):请求成功。一般用于GET与POST请求
201(Created):已创建。成功请求并创建了新的资源
202(Accepted):表示服务器端已经收到请求消息,但是尚未进行处理。但是对于请求的处理确实无保证的,即稍后无法通过 HTTP 协议给客户端发送一个异步请求来告知其请求的处理结果。这个状态码被设计用来将请求交由另外一个进程或者服务器来进行处理,或者是对请求进行批处理的情形。

3XX——重定向类(Redirection)

表示没有请求成功,必须采取进一步的动作

301(Moved Permanently):资源被永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI
302(Found):资源临时移动。资源只是临时被移动,客户端应继续使用原有URI

304:用其他策略获取资源

4XX——客户端错误(Client Error)

表示客户端提交的请求包含语法错误或不能正确执行

400(Bad Requests):客户端请求的地址不存在或者包含不支持的参数
401(Unauthorized):未授权,或认证失败。对于需要登录的网页,服务器可能返回此响应
403(Forbidden):没权限。服务器收到请求,但拒绝提供服务
404(Not Found):请求的资源不存在。遇到404首先检查请求url是否正确

5XX——服务端错误(Server Error)

表示服务器不能正确执行一个正确的请求(客户端请求的方法及参数是正确的,服务端不能正确执行,如网络超时、服务僵死,可以查看服务端日志再进一步解决)

500(Internal Server Error):服务器内部错误,无法完成请求
503(Service Unavailable):由于超载或系统维护(一般是访问人数过多),服务器无法处理客户端的请求 ,通常这只是暂时状态

MIME 类型说明

MIME 是 HTTP 协议中数据类型。 MIME 的英文全称是"MultipurposeInternetMailExtensions" 多功能 Internet 邮件扩充服务。MIME 类型的格式是“大类型/小 类型”,并与某一种文件的扩展名相对应。

在这里插入图片描述在这里插入图片描述
火狐浏览器如何查看 HTTP 协议:

在这里插入图片描述

6.servlet2

HttpServletRequest 类

HttpServletRequest 类有什么作用?

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

HttpServletRequest 类的常用方法

  1. getRequestURI() 获取请求的资源路径

  2. getRequestURL() 获取请求的统一资源定位符(绝对路径)

  3. getRemoteHost() 获取客户端的 ip 地址 iv.getHeader() 获取请求头

  4. getParameter() 获取请求的参数

  5. getParameterValues() 获取请求的参数(多个值的时候使用)

  6. getMethod() 获取请求的方式 GET 或 POST

  7. setAttribute(key, value); 设置域数据

  8. getAttribute(key); 获取域数据 x. getRequestDispatcher() 获取请求转发对象
    常用 API 示例代码:

xml配置文件:

 <servlet>
       <servlet-name>RequestAPI</servlet-name>
       <servlet-class>com.servlet2.RequestAPI</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>RequestAPI</servlet-name>
    <url-pattern>/requestAPI</url-pattern>
    </servlet-mapping>

servlet文件:


package com.servlet2;

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 RequestAPI extends HttpServlet {
    
    

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

//        1.getRequestURL() 获取请求的统一资源定位符(绝对路径
        System.out.println("URI"+req.getRequestURI());
        //输出:URI/servlet07_war_exploded/requestAPI

//        2.getRemoteHost() 获取客户端的 ip 地址
        System.out.println("客户端IP地址"+req.getRemoteHost());
//            使 用 localhost访 问 时 , 得 到 的 客 户 端ip地 址 是===>>> 127.0.0.1<br/>
//            使 用 127.0.0.1访 问 时 , 得 到 的 客 户 ip地 址 是===>>> 127.0.0.1<br/>
//            使 用 真 实 ip访 问 时 , 得 到 的 客 户 端ip地 址 是===>>>真 实 的 客 户 端ip地 址

//        3.getHeader() 获取请求头 v. getParameter() 获取请求的参数
        System.out.println("请求头User-Agent地址:"+req.getHeader("User-Agent"));


//        4.getMethod() 获取请求的方式 GET 或 POST
        System.out.println("获取请求的方式:"+req.getMethod());

//        5.getRequestURI() 获取请求的资源路径
        System.out.println("URL"+req.getRequestURL());
        //输出:URLhttp://localhost/servlet07_war_exploded/requestAPI
    }
}

如何获取表单请求参数?

html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://localhost/servlet07_war_exploded/parametServlet" method="get">
     用户名:<input type="text" name="username" > <br>
      密码:<input type="text" name="password">
    兴趣爱好: <input type="checkbox" name="hobby" value="c++">c++
    <input type="checkbox" name="hobby" value="java">java
    <input type="checkbox" name="hobby" value="python">python <br>
    <input type="submit" value="提交">
</form>
</body>
</html>

servlet文件:

package com.servlet2;

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 RequestAPI extends HttpServlet {
    
    

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

//        1.getRequestURL() 获取请求的统一资源定位符(绝对路径
        System.out.println("URI"+req.getRequestURI());
        //输出:URI/servlet07_war_exploded/requestAPI

//        2.getRemoteHost() 获取客户端的 ip 地址
        System.out.println("客户端IP地址"+req.getRemoteHost());
//            使 用 localhost访 问 时 , 得 到 的 客 户 端ip地 址 是===>>> 127.0.0.1<br/>
//            使 用 127.0.0.1访 问 时 , 得 到 的 客 户 ip地 址 是===>>> 127.0.0.1<br/>
//            使 用 真 实 ip访 问 时 , 得 到 的 客 户 端ip地 址 是===>>>真 实 的 客 户 端ip地 址

//        3.getHeader() 获取请求头 v. getParameter() 获取请求的参数
        System.out.println("请求头User-Agent地址:"+req.getHeader("User-Agent"));


//        4.getMethod() 获取请求的方式 GET 或 POST
        System.out.println("获取请求的方式:"+req.getMethod());

//        5.getRequestURI() 获取请求的资源路径
        System.out.println("URL"+req.getRequestURL());
        //输出:URLhttp://localhost/servlet07_war_exploded/requestAPI
    }
}

xml配置文件

 <servlet>
        <servlet-name>ParametServlet</servlet-name>
        <servlet-class>com.servlet2.ParametServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ParametServlet</servlet-name>
        <url-pattern>/parametServlet</url-pattern>
    </servlet-mapping>

请求的转发
什么是请求的转发? 请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发

在这里插入图片描述

servlet1代码:

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

servlet2代码:

在这里插入图片描述xml配置文件:
在这里插入图片描述
base 标签的作用

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

Web 中的相对路径和绝对路径

在 web 中 / 斜杠 是一种绝对路径。
/ 斜杠 如果被浏览器解析,得到的地址是:http://localhost/
斜杠
/ 斜杠 如果被服务器解析
得到的地址是:http://ip:port/工程路径
1、/servlet1
2、servletContext.getRealPath(“/”);
3、request.getRequestDispatcher(“/”);

特殊情况: response.sendRediect(“/”);
把斜杠发送给浏览器解析。得到 http://ip:port/

HttpServletResponse 类

HttpServletResponse 类的作用?

HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传 递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息, 我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置
两个输出流的说明。
字节流 getOutputStream(); 常用于下载(传递二进制数据)

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

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

在这里插入图片描述如何往客户端回传数据?
要求 : 往客户端回传 字符串 数据(并且解决中文乱码的问题)。

servlet程序代码
在这里插入图片描述

xml配置文件
在这里插入图片描述
请求重定向

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些地址。你去新地址访问。叫请求 重定向(因为之前的地址可能已经被废弃)

在这里插入图片描述
servlet1代码:
在这里插入图片描述
servlet2代码:
在这里插入图片描述
XML配置文件:

在这里插入图片描述

在这里插入图片描述

javaEE的三层架构

在这里插入图片描述分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。

在这里插入图片描述

7.JDBC

JDBC是什么?
1.Java DataBse Connectivity (java语言连接数据库)

2.JDBC的本质是什么?
是sun公司制定的一套接口(interface),只要是接口都有调用者和实现者,面向接口调用,或者面向接口写实现类,这都是属于面向接口编程。
这个 java .sql.*;(这个软件包下有很多接口)

3.为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩张能力。
多态机制就是非常典型的:面向抽象编程(不要面向具体编程)
面向接口编程其实就是面向抽象编程

父类型引用指向子类型对象

Animal a =new Cat();
Animal a = new Dog ();

public void feed(Animal a)
{
//面向父类编程
}
不建议:
Cat a =new Cat();
Dog a = new Dog ();

面向对象的三大特征:封装,继承,多态

思考:为什么要指定JDBC接口?
因为每个数据库设计的底层原理都不一样,
Oracle有自己的原理
mysql有自己的原理
MS sqlserver数据库也有自己的原理

每一个数据库产品都有自己独特的实现原理
如果不定义JDBC接口的话,那就要每调用一种数据库,就需要用一种java语言。
在这里插入图片描述

导入数据库jar包并且测试是否导入成功

创建一个目录,用来放mysql的驱动包,类似eclipse的lib目录:

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

在这里插入图片描述文本编辑器开发配置mysql.jar包
在这里插入图片描述.:C:\Users\14823\IdeaProjects\JDBC\lib"C:\Users\14823\IdeaProjects\JDBC\lib\mysql-connector-java-5.1.49-bin.jar

JDBC编程六步:(重点记住这六个步骤,JDBC就是按照这六步骤写代码)

1.注册驱动(告诉java程序即将要链接那种类型的数据库)
2.获取链接(表示java程序和数据库进程之间的通道打开了,进程之间的通信,重量级别的,使用完之后一定要释放)
3.获取数据库操作对象(专门执行sql语句)
4.执行sql语句(DQL,DML)
5.处理查询结果集(当第四步执行的是select语句的时候,才有第五步)
6.释放资源(使用完资源之后一定要关闭资源,java和数据库之后属于进程之间的通信,开启之后一定要关闭)

import java.sql.*;

public class JDBCTest01 {
    
    
    public static void main(String[] args) throws SQLException {
    
    
        //JDBC的sql语句不需要写分号
        Statement statement = null;
        Connection connection = null;
        try {
    
    
            //        1.注册驱动
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            //       02.获取链接(链接到数据库)
            String url="jdbc:mysql://localhost:3306/book";
            String user = "root";
            String password ="2732195202huyu";
            connection = DriverManager.getConnection(url,user,password);
            System.out.println("数据库连接对象:"+connection);

            //3.获取数据库操作对象(专门执行sql语句)
             statement = connection.createStatement();

//            4.执行sql语句
            //专门执行DML语句的(insertdeleteupdate)
            //返回的是“影响数据库中的记录条数”
//        String sql = "insert into bookcategory(category_id,category,parent_id)values(8,'python',2)";//插入
        String sql = "update bookinfo set store = store -1 where book_id = 20150201;";//更新


            //5.处理查询结果
            int conut = statement.executeUpdate(sql);
            System.out.println(conut==1?"数据插入成功":"数据插入失败");

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally {
    
    
            //6.为了保证资源一定释放,在finally中关闭资源,而且遵循从小到大一次关闭
            //分别对其try...catch
            if (statement!=null)
            {
    
    
                try {
    
    
                    statement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if(connection!=null){
    
    

                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }

        }
    }
}
//  第四步:    PreparedStatement pstmt= connection.prepareStatement(sql);
//           pstmt.executeUpdate(sql);

URL:包括那几部分?

1.http:// 通信协议
2.ip地址
3.post(端口)
4.资源名

使用资源配置文件
在这里插入图片描述代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

public class JDBCTest04 {
    
    
    public static void main(String[] args) {
    
    
 //使用资源绑定属性配置文件
        ResourceBundle bundle =ResourceBundle.getBundle("jdbc");
        String dirver = bundle.getString("dirver");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        String url = bundle.getString("url");

        Statement statement = null;
        Connection connection = null;
            try {
    
    
                //        1.注册驱动

                Class.forName(dirver);
                //       02.获取链接(链接到数据库)

                connection = DriverManager.getConnection(url,user,password);
                System.out.println("数据库连接对象:"+connection);

                //3.获取数据库操作对象(专门执行sql语句)
                statement = connection.createStatement();

//            4.执行sql语句
                //专门执行DML语句的(insertdeleteupdate)
                //返回的是“影响数据库中的记录条数”
                String sql = "delete from course where id='C00003';";
                int conut = statement.executeUpdate(sql); //执行insert delete update 语句 返回int数据类型

                //5.处理查询结果
                System.out.println(conut>=1?"数据删除成功":"数据删除失败");

            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            } catch (ClassNotFoundException e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                //6.为了保证资源一定释放,在finally中关闭资源,而且遵循从小到大一次关闭
                //分别对其try...catch
                if (statement!=null)
                {
    
    
                    try {
    
    
                        statement.close();
                    } catch (SQLException throwables) {
    
    
                        throwables.printStackTrace();
                    }
                }
                if(connection!=null){
    
    

                    try {
    
    
                        connection.close();
                    } catch (SQLException throwables) {
    
    
                        throwables.printStackTrace();
                    }
                }

            }
        }


}

处理查询结果:
代码:
注意:JDBC数据库的下标都从1开始

遍历结果集图:
在这里插入图片描述

处理查询结果值

import javax.servlet.Servlet;
import java.sql.*;

public class JDBCTest05 {
    
    
    //处理查询结果值
    public static void main(String[] args) {
    
    
        Statement statement = null;
        Connection connection = null;
        ResultSet resultSet = null;
        try {
    
    
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取链接
          connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/book","root","2732195202huyu");
            //3.获取数据库操作对象
            statement =  connection.createStatement();
            System.out.println("数据库操作对象:"+ statement);
            //4.执行sql语句
            String sql = "select * from bookcategory;";
          resultSet =  statement.executeQuery(sql); //专门执行DQL语句的方法 返回ResultSet数据类型
            //5.处理查询结果 resultSet.next() 方法返回一个布尔值,如果返回true就代表还有数据

            // getString();方法不管数据库中的数据类型是什么都以String形式取出。返回String类型
            //JDBC所有的数据下标从1开始,1代表第一列 2代表第二列 3代表第三列
            //循环第一次 取第一行数据
           while (resultSet.next()){
    
    
               /*String category_id = resultSet.getString(1);
               String category = resultSet.getString(2);
               String parent_id = resultSet.getString(3);*/

                //以下方式更具有灵活性(不是以列的下标获取,而是以最终查询结果的列名称获取)
             /*  String category_id = resultSet.getString("category_id");
               String category = resultSet.getString("category");
               String parent_id = resultSet.getString("parent_id");
               System.out.println(category_id+","+category+","+parent_id); */

               //除了以String类型取出之外,还可以用其他数据类型取出,不过需要看数据库对应字段的数据类型进行操作
              int category_id = resultSet.getInt("category_id");
               String category = resultSet.getString("category");
               String parent_id = resultSet.getString("parent_id");
               System.out.println(category_id+","+category+","+parent_id);

           }




        }catch (Exception e){
    
    
            e.printStackTrace();
        }finally {
    
    
            //6.释放资源
            if (statement!=null)
            {
    
    
                try {
    
    
                    statement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if(connection!=null){
    
    

                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }

        }
    }
}

验证用户和密码(sql注入)

import java.sql.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class JDBCTest06 {
    
    
    public static void main(String[] args) {
    
    

      Map<String,String> userLogininfo=  initUI();
      // 验证用户和密码

        //登录验证
        boolean loginSucces= loin(userLogininfo);
        //最后输出结果
        System.out.println(loginSucces?"登录成功":"登录失败");
    }

    private static boolean loin(Map<String, String> userLogininfo) {
    
    
        //单独定义变量
        String logName =userLogininfo.get("loginName");
        String logPassword =userLogininfo.get("loginPasswd");
//        JDBC代码
        Connection connection = null;
        Statement statement = null;
        ResultSet  resultSet =null;

        try {
    
    
//            1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            try {
    
    
//            2.获取链接
             connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword","root","2732195202");
//            3.获取操作对象
                statement=connection.createStatement();
//            4.执行sql语句(此处出现bug,可能会被sql注入,这样输入fsda'or'1'='1也会导致登录成功   )
//              sql语句被注入的原因就是用户输入的信息中含有sql语句关键字,并且这些关键字参与了编译,从而导致原sql语句含义被扭曲了
//              解决办法:不让用户输入的关键字参与sql语句的编译
                String sql ="select * from tbl_user where loginname='"+logName+"' and loginpassword='"+logPassword +"'";
                resultSet = statement.executeQuery(sql); //此时正好编译,正好上当
//             5.处理查询结果
                boolean isexecute=false; //登录成功标志
                while (resultSet.next()){
    
    
                    //结果集里面有数据说明登录成功
                   isexecute=true;
               }
               if(isexecute==true){
    
    
                return true;
               }
                if(connection!=null){
    
    
                    connection.close();
                }
                if(statement!=null){
    
    
                    statement.close();
                }
                if (resultSet!=null){
    
    
                    resultSet.close();
                }
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }

        return false;
    }

    //初始化一个页面返回用户输入的用户名和密码等于登录信息
    private static Map<String ,String> initUI() {
    
    
        Scanner scanner = new Scanner(System.in);

        System.out.println("用户名:");
        String username = scanner.next();

        System.out.println("密码:");
        String password = scanner.next();

        Map<String ,String> userLoginfo =  new HashMap<>();
        userLoginfo.put("loginName",username);
        userLoginfo.put("loginPasswd",password);
        return  userLoginfo;

    }
}

验证用户登录(sql注入的解决办法)

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class JDBCTest07 {
    
    
//    sql语句注入的解决办法:

    /*  PreparedStatement是属于预编译数据库操作对象
    * PreparedStatement:的原理是现在对sql语句进行预编译,然后再进行传值
    * PreparedStatement:基础了java.sql.Statement;
    * */
    public static void main(String[] args) {
    
    
        Map<String,String> userLogininfo=  initUI();
        // 验证用户和密码

        //登录验证
        boolean loginSucces= loin(userLogininfo);
        //最后输出结果
        System.out.println(loginSucces?"登录成功":"登录失败");
    }
    private static boolean loin(Map<String, String> userLogininfo) {
    
    
        //单独定义变量(用户和密码)
        String logName =userLogininfo.get("loginName");
        String logPassword =userLogininfo.get("loginPasswd");

//        JDBC代码
        Connection connection = null;
        PreparedStatement ps= null;
        ResultSet resultSet =null;
        try {
    
    
//            1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            try {
    
    
//            2.获取链接
                connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword","root","2732195202");
//            3.获取预编译操作对象
                String sql ="select * from tbl_user where loginname= ? and loginpassword= ? ";//sql语句框架
//               其中一个?号代表一个占位符,代表一个值
                ps=connection.prepareStatement(sql);

                ps.setString(1,logName);//给?号占位符传值 ?:1 ?:2 ?:3
                ps.setString(2,logPassword);//给?号占位符传值 ?:1 ?:2 ?:3
//            4.执行sql语句(此处出现bug,可能会被sql注入,这样输入fsda'or'1'='1也会导致登录成功   )
//              sql语句被注入的原因就是用户输入的信息中含有sql语句关键字,并且这些关键字参与了编译,从而导致原sql语句含义被扭曲了
//              解决办法:不让用户输入的关键字参与sql语句的编译
                resultSet =ps.executeQuery();
//             5.处理查询结果
                boolean isexecute=false; //登录成功标志

                while (resultSet.next()){
    
    
                    //结果集里面有数据说明登录成功
                    isexecute=true;
                }
                if(isexecute==true){
    
    
                    return true;
                }
                //6.释放资源
                if(connection!=null){
    
    
                    connection.close();
                }
                if(ps!=null){
    
    
                   ps.close();
                }
                if (resultSet!=null){
    
    
                    resultSet.close();
                }
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }

        return false;
    }

    //初始化一个页面返回用户输入的用户名和密码等于登录信息
    private static Map<String ,String> initUI() {
    
    
        Scanner scanner = new Scanner(System.in);

        System.out.println("用户名:");
        String username = scanner.next();

        System.out.println("密码:");
        String password = scanner.next();

        Map<String ,String> userLoginfo =  new HashMap<>();
        userLoginfo.put("loginName",username);
        userLoginfo.put("loginPasswd",password);
        return  userLoginfo;
    }
}

Statement的用途

import java.sql.*;
import java.util.Scanner;

public class JDBCTest08 {
    
    
    public static void main(String[] args) {
    
    
/*//        Statement的用途(错误用法) 用于排序

*//*        对比一一下Statement和PreparedStatement的区别
            因为mysql语句如果都是一模一样的连空格都一样那就只会编译一次
*           Statement存在sql注入问题,(编译一次执行一次)执行效率会低一下
*           PreparedStatement解决sql注入问题,(编译一次执行n次,单用于传值)而且执行效率会更高,会在编译阶段做类型的安全检查
            PreparedStatement用的比较多,Statement用的极少,但是某些业务需要进行sql注入(sql语句拼接)的时候就需要Statement,

*//*             //用户在控制输入desc就是降序,asc就是升序
        Scanner in = new Scanner(System.in);
        System.out.println("请输入desc或asc:acs降序:desc:升序");
        System.out.println("请输入:");
        String keywords = in.next();
        //执行sql语句
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.链接数据库
            connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword","root","2732195202");
            // 3.获取数据库预编译操作对象
            String sql = "select ename from emp order by ename desc ? ";
            preparedStatement= connection.prepareStatement(sql);
            preparedStatement.setString(1,keywords);
            //4.执行sql语句
          resultSet=  preparedStatement.executeQuery();//返回结果值

            //5.处理查询结果,遍历结果集
            while (resultSet.next())    {
                System.out.println(resultSet.getString("ename"));
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            //6.释放资源
            if (resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (connection!=null){
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (preparedStatement!=null){
                try {
                    preparedStatement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }*/


            //   Statement的用途(正确用法)


        Scanner in = new Scanner(System.in);
        System.out.println("请输入desc或asc:acs降序:desc:升序");
        System.out.println("请输入:");
        String keywords = in.next();
        //执行sql语句
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
    
    
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.链接数据库
            connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword","root","2732195202");
            // 3.获取数据库操作对象
          statement= connection.createStatement();

            //4.执行sql语句
            String sql ="select ename from emp order by ename   "+keywords;
             resultSet = statement.executeQuery(sql);

            //5.处理查询结果,遍历结果集
            while (resultSet.next())    {
    
    
                System.out.println(resultSet.getString("ename"));
            }

        } catch (ClassNotFoundException | SQLException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            //6.释放资源
            if (resultSet!=null){
    
    
                try {
    
    
                    resultSet.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (connection!=null){
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (statement!=null){
    
    
                try {
    
    
                   statement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
        }


    }
}

PreparedStatement 完成:增删改查

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCTest09 {
    
    
    public static void main(String[] args) {
    
    
//        PreparedStatement 完成:增删改查
        Connection connection = null;
        PreparedStatement preparedStatement= null;

        try {
    
    
//            1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
//            2.获取数据库连接
            connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword","root","2732195202");
//            3.获取数据库预编译对象 (向数据库插入数据)
            /*String sql = "insert into dept (DEPTNO,DNAME,LOC) values(?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,40);
            preparedStatement.setString(2,"文学部");
            preparedStatement.setString(3,"北京");*/

             /*String sql = "update dept set dname=?,loc=? where  deptno=?"; //(更新数据库内容)
            preparedStatement = connection.prepareStatement(sql);
           preparedStatement.setString(1,"北京研发一部");
            preparedStatement.setString(2,"北京研究中心");
            preparedStatement.setInt(3,60);*/

            String sql = "delete from dept where deptno = ?"; //(删除数据库内容)
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,70);
//            4.执行sql语句
            int count = preparedStatement.executeUpdate();

//            5.处理查询结果
            System.out.println(count>=1?"成功操作数据库":"操作数据库失败");
        } catch (ClassNotFoundException | SQLException e) {
    
    
            e.printStackTrace();
        }finally {
    
     //释放资源
            if(connection!=null){
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }

            }
            if(preparedStatement!=null){
    
    
                try {
    
    
                    preparedStatement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }

            }

        }
    }
}

JDBC事务提交机制

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCTest10 {
    
    
    public static void main(String[] args) {
    
    
/*       JDBC事务提交机制
        1.JDBC中的事务是自动提交的:只要执行DML语句,则自动提交一次(这是JDBC默认的行为)
        但是在实际业务中,同城都是N条DML语句共同联合完成的,在同一事务中同时成功或者同时失败
        2.一下程序验证JDBC的事务提交机制
        测试结果:只要JDBC中执行任意一条DML语句就提交一次

        */
       // PreparedStatement 完成:增删改查
        Connection connection = null;
        PreparedStatement preparedStatement= null;

        try {
    
    
//            1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
//            2.获取数据库连接
            connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword","root","2732195202");
//            3.获取数据库预编译对象 (向数据库插入数据)
            String sql = "update dept set dname = ? where deptno=?";
            preparedStatement=connection.prepareStatement(sql);
            //第一次个占位符传值
            preparedStatement.setString(1,"x部门");
            preparedStatement.setInt(2,10);
            int count = preparedStatement.executeUpdate(); //执行第一条UPpate语句
            System.out.println(count>=1?"成功":"失败"); //count=1程序还没结束,但是数据库内容以及更新
            //重新传值
            preparedStatement.setString(1,"y部门");
            preparedStatement.setInt(2,20);
             count = preparedStatement.executeUpdate();//执行第二条UPpate语句
            System.out.println(count>=1?"成功":"失败");
//            4.执行sql语句



//            5.处理查询结果
           // System.out.println(count>=1?"成功操作数据库":"操作数据库失败");
        } catch (ClassNotFoundException | SQLException e) {
    
    
            e.printStackTrace();
        }finally {
    
     //释放资源
            if(connection!=null){
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }

            }
            if(preparedStatement!=null){
    
    
                try {
    
    
                    preparedStatement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }

            }

        }
    }
}

JDBC事务提交机制:银行转账演示

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCTest11 {
    
    
    public static void main(String[] args) {
    
    
      /* 银行转账演示:账户111给222转1万块钱,更新数据库中的内容
      *
      * */
        // PreparedStatement 完成:增删改查
        Connection connection = null;
        PreparedStatement preparedStatement= null;

        try {
    
    
//            1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
//            2.获取数据库连接
            connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword","root","2732195202");
//            3.获取数据库预编译对象 (向数据库插入数据)
            //将自动提交机制修改为手动提交
            connection.setAutoCommit(false);
              String sql = "update t_act set balance = ? where actno = ?";
              preparedStatement=connection.prepareStatement(sql);
              //传值
              preparedStatement.setDouble(1,10000);
              preparedStatement.setDouble(2,111);
              int count = preparedStatement.executeUpdate();
                //发生空指针异常,程序不再执行,但是上面的数据以及更新完成,但是下面的数据不会更新会丢掉10000块钱
//              String s=null;
//              s.toString();

              //再次给?号传值
            preparedStatement.setDouble(1,10000);
            preparedStatement.setDouble(2,222);
             count += preparedStatement.executeUpdate();
            System.out.println(count==2?"转账成功":"转账失败");
//            4.执行sql语句

//            5.处理查询结果
            //程序能够走到这里,说明事物没有异常,可以在此手动提交数据
            connection.commit(); //提交事务
        } catch (ClassNotFoundException | SQLException e) {
    
    
            //为了保证数据的安全性,回滚事务
            if(connection!=null){
    
    
                try {
    
    
                    connection.rollback();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
    
     //释放资源
            if(connection!=null){
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }

            }
            if(preparedStatement!=null){
    
    
                try {
    
    
                    preparedStatement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }

            }

        }
    }


}

模糊查询和测试JDBC工具包

JDBC工具包代码:

package JdbcUtils;

import java.sql.*;

public class DBUtil {
    
    
//    JDBC工具类:工具类中的方法都是私有的,静态的,不需要new对象,直接采用类名调用

    private  DBUtil(){
    
    

    }

    static {
    
    
        //注册驱动:静态代码块只在类加载时,执行一次
        try {
    
    
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws Exception {
    
    

        //链接数据库对象,返回链接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testpassword", "root", "2732195202");

   return conn;
    }
//    释放资源
    public  static  void  close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
    
    
        if (resultSet!=null){
    
    
            try {
    
    
                resultSet.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
        if (preparedStatement !=null){
    
    
            try {
    
    
               preparedStatement.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
        if (connection!=null){
    
    
            try {
    
    
                connection.close();
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }
        }
    }


}





使用工具包和模糊查询

import JdbcUtils.DBUtil;

import java.sql.*;

public class JDBCTest12 {
    
    
    public static void main(String[] args) {
    
    
        /*两个任务:
        1.测试DBUtil是否好用
        2.模糊查询怎么写*/
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
    
    
            //类加载时自动注册驱动
            //获取链接
          connection =  DBUtil.getConnection();
            //执行sql语句
            String sql = "select * from dept where uname like ?";
            //获取数据库预编译对象
            preparedStatement = connection.prepareStatement(sql);
            //传值
            preparedStatement.setString(1,"_A%");
            //执行sql语句
            resultSet=preparedStatement.executeQuery();
            //处理查询结果
            while(resultSet.next()){
    
    
                System.out.println(resultSet.getString("uname")); //uname:数据库中的字段
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();

        }finally {
    
      //   释放资源
            DBUtil.close(connection,preparedStatement,resultSet);
        }
    }
}

悲观锁和乐观锁的使用

锁住数据的程序:

import JdbcUtils.DBUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class JDBCTest13 {
    
    
    public static void main(String[] args) {
    
    
        /*悲观锁和乐观锁机制
                事务1:读取到的版本号为1.1
                事务2:读取到的版本号为1.2
            其中事务1先修改了,修改的版本号是1.1,于是提交数据,将版本号修改为1.2
            其中事务2后修改的,修改之后准备提交数据的时候发下版本本号为1.2,和他最初的版本号不一致,(回滚)

        悲观锁:事务必须排队执行,数据锁住了,不允许并发(行级锁:select后面添加 for update)
        乐观锁:支持并发,事务也不需要排队,只不过需要一个版本号 */
//        这个程序开启一个事务:这个事务专门进行查询,并且使用行级锁/悲观锁,锁住相关的记录

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
    
    
            //类加载时自动注册驱动
            //获取链接
            connection =  DBUtil.getConnection();
            //开启事务
            connection.setAutoCommit(false);
            //执行sql语句
            String sql = "select * from dept where uname like ? for update ";
            //获取数据库预编译对象
            preparedStatement = connection.prepareStatement(sql);
            //传值
            preparedStatement.setString(1,"_A%");
            //执行sql语句
            resultSet=preparedStatement.executeQuery();
            //处理查询结果
            while(resultSet.next()){
    
    
                System.out.println(resultSet.getString("uname")); //uname:数据库中的字段
            }
            //提交事务(再此设置断点 不提交事务,jdbctest14程序是不能去更新数据库里面的值的,只有等事务提交之后,jdbctest14程序才能更新数据库的值)
            connection.commit();
        } catch (Exception e) {
    
    
            e.printStackTrace();

        }finally {
    
      //   释放资源
            DBUtil.close(connection,preparedStatement,resultSet);
        }
    }
}

更新数据的程序

import JdbcUtils.DBUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class JDBCTest14 {
    
    
//    这个程序负责修改被锁住的记录

    public static void main(String[] args) {
    
    
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
    
    
            //类加载时自动注册驱动
            //获取链接
            connection =  DBUtil.getConnection();
            //执行sql语句
            connection.setAutoCommit(false); //开启事务
            String sql = "update dept set uname= ? where deptno  = ?";
            //获取数据库预编译对象
            preparedStatement = connection.prepareStatement(sql);
            //传值
            preparedStatement.setString(1,"剑圣");
            preparedStatement.setInt(2,10);



            //执行sql语句
                int count = preparedStatement.executeUpdate();
            //处理查询结果
            System.out.println(count);
            connection.commit();
        } catch (Exception e) {
    
    
            e.printStackTrace();

        }finally {
    
      //   释放资源
            DBUtil.close(connection,preparedStatement,null);
        }
    }
}

8.JSP

1.为什么要学习JSP技术?
在学习 jsp 技术之前,如果我们要往客户端输出一个页面。我们可以使用 Servlet 程序来实现。具体的代码如下:

在这里插入图片描述在浏览器中输入访问 Servlet 的程序地址得到以下结果:
在这里插入图片描述
上面的代码我们不难发现。通过 Servlet 输出简单的 html 页面信息都非常不方便。 那我们要输出一个复杂页面的时候,就更加的困难,而且不利于页面的维护和调试。 所以 sun 公司推出一种叫做 jsp 的动态页面技术帮助我们实现对页面的输出繁锁工作。
jsp 页面的访问千万不能像 HTML 页面一样。托到浏览器中。只能通过浏览器访问 Tomcat 服务器再访问 jsp 页面
如何创建一个 jsp 动态页面程序?
选中 WebContent 目录,右键创建一个 jsp 文件
**如何访问jsp文件?**其实跟html文件差不多,只是文件的后缀名为jsp而已
在这里插入图片描述
注意事项:
1、jsp 页面是一个类似于 html 的一个页面。 jsp 直接存放到 WebContent 目录下,和 html 一样 访问 jsp 的时候,也和访问 html 一样
2、jsp 的默认编码集是 iso-8859-1 修改 jsp 的默认编码为 UTF-8
2.jsp 的运行原理(JSp本质以及运行原理)

jsp 的本质 ,其实是一个 Servlet 程序。我们写的这个jsp文件会在下面这个文件夹内,被tomcat解析为.java和.class文件。
在这里插入图片描述
在这里插入图片描述index_jsp.class就是index_jsp.java原文件编译后的字节码文件
我们打开 index.java 文件查看里面的内容: 发现,生成的类继承于 HttpJspBase 类。这是一个 jsp 文件生成 Servlet 程序要继承的基类!!!
在这里插入图片描述

打开这个.java文件对应的就是被解析的jsp文件,打开这个文件其实就能看到jsp被翻译后的servlet程序。

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

小结:

从生成的文件我们不难发现一个规则。
a.jsp 翻译成 java 文件后的全名是 a_jsp.java 文件 b.jsp 翻译成 java 文件后的全名是 b_jsp.java 文件
那么 当我们访问 一个 xxx.jsp 文件后 翻译成 java 文件的全名是 xxx_jsp.java 文件 xxx_jsp.java 文件是一个 Servlet 程序。原来 jsp 中的 html 内容都被翻译到 Servlet 类的 service 方法中原样输出。
、jsp 的语法(重点掌握)

3.JSP语法

jsp 文件头部声明介绍(page 指令介绍)
在这里插入图片描述
这是 jsp 文件的头声明。表示这是 jsp 页面。
language :属性 值只能是 java。 表示翻译的得到的是 java 语言的
contentType :属性 设置响应头 contentType 的内容
pageEncoding :属性 设置当前 jsp 页面的编码
import :属性 给当前 jsp 页面导入需要使用的类包
autoFlush: 属性 设置是否自动刷新 out 的缓冲区,默认为 true
buffer :属性 设置 out 的缓冲区大小。默认为 8KB
errorPage :属性 设置当前 jsp 发生错误后,需要跳转到哪个页面去显示错误信息
isErrorPage: 属性 设置当前 jsp 页面是否是错误页面。是的话,就可以使用 exception 异常对象
session 属性 :设置当前 jsp 页面是否获取 session 对象,默认为 true
extends :属性 给服务器厂商预留的 jsp 默认翻译的 servlet 继承于什么类

jsp 中的三种脚本介绍

第一种,声明脚本:

在这里插入图片描述
在声明脚本块中,我们可以做 4 件事情

1.我们可以定义全局变量。
2.定义 static 静态代码块
3.定义方法
4.定义内部类 几乎可以写在类的内部写的代码,都可以通过声明脚本来实现
脚本中申明的代码被翻译为java代码

在这里插入图片描述
第二种,表达式脚本(重点,使用很多):

表达式脚本格式如下:

在这里插入图片描述
在这里插入图片描述
第三种,代码脚本(重点,使用最多):
在这里插入图片描述

在这里插入图片描述
jsp 中的注释:

在这里插入图片描述

4.jsp 九大内置对象

在这里插入图片描述
九大内置对象,都是我们可以在【代码脚本】中或【表达式脚本】中直接使用的对
象。

jsp 四大域对象:四大域对象经常用来保存数据信息。

JSP四大域对象context1.jsp文件
在这里插入图片描述
context2.jsp文件

在这里插入图片描述
测试步骤:
在这里插入图片描述
5.jsp 中 out 输出流 和 response.getwriter() 输出流
response表示响应,我们经常用于设置返回给客户端的内容输出(out也是给用户做输出的)
out 输出流 和 response.getwriter() 输出流的区别
response.getwriter() 会比out先输出,然后out和jsp中的内容是谁在前面谁先输出
在这里插入图片描述

jsp 中 out 和 response 的 writer 的区别演示
在这里插入图片描述
注意:由于jsp翻译后,底层源码都是用out进行输出,所以一般情况下,我们在jsp页面中使用out进行输出,避免打乱页面输出内容。

out.write();和out.print();区别

当输出的都是字符串的时候结果都一样
但是输出的是int型数字的时候,out.write();就会出现乱码的情况
out.print();不管输出什么类型输出的时候都会把需要输出的对象转换为字符串
out.write();输出字符没有问题,但是输出数字的时候会把该数据转为char类型,然后输出对应的ASCLL码值
所以建议都是使用out.print();进行输出。
演示结果:
在这里插入图片描述6.jsp 的常用标签(重点)
在这里插入图片描述

静态包含–很常用

静态包含是把包含的页面内容原封装不动的输出到包含的位置。
在这里插入图片描述
动态包含:实现原理和静态包含的底层原理不一样

动态包含的特点:
1.动态包含会把包含的jsp页面也翻译为java代码
2.动态包含底层代码使用如下代码去调用被包含的jsp页面进行输出
会在Staticlabel1中的.java文件中执行下面这行代码去调用Staticlabel2.jsp页面进行输出
在这里插入图片描述

演示结果:
在这里插入图片描述页面转发–常用

<jsp:forward page=""> </jsp:forward>

在这里插入图片描述静态包含和动态包含的区别:

1. <%@ include file=” ”%>是指令元素。<jsp:include page=” ”/>是行为元素最终编译成java文件的数目不同。

2. 静态包含在转换成为java文件的时候将包含文件的内容“复制”到主体文件,然后作为一个整体编译。最终编译为一个java文件。
动态包含是各个jsp文件分别转换,分别编译。最终编程成多个java文件。

3. 执行时间不同

静态包含发生在:JSP---->java文件阶段。

动态包含发生在:执行class文件阶段。动态加入。

4.静态包含在两个文件中不能有相同的变量,动态包含允许。

由于静态包含相当于将包含文件内容直接复制到主体文件中,如果出现相同的变量,就会出现覆盖等问题,导致文件出错。而动态包含相当于调用不同的jsp,变量所在的空间不同,自然不会出现覆盖等现象。

5.无论是动态包含还是静态包含,其request对象都是相同的。也就是同一个request对象。

静态包含最终编译成一个java文件,有一个request对象很好理解。而动态包含最终编译成多个jsp文件,为何会使用一个request对象呢?其实这些jsp组合的过程是一个请求转发的过程,自然也使用同一个request对象了。

6.静态包含和动态包含的使用

简单总结一下,就一句话:被包含的页面是静态页面就用静态包含,是动态页面就用动态包含。(当然,不是很绝对,但是这样用没有错。)

在这里需要补充说明一点:我们在工作中,几乎都是使用静态包含。理由很简单。因为 jsp 页面虽然可以写 java 代做其他的功能操作。但是由于 jsp 在开发过程中被定位为专门用来展示页面的技术。也就是说。jsp 页面中,基 本上只有 html,css,js。还有一些简单的 EL,表达式脚本等输出语句。所以我们都使用静态包含。

1、什么是 Listener 监听器
Listener监听器是javaweb三大组件之一(servlet程序,Listener监听器,Filter过滤器)
Listener是javaEE的规范接口
监听器的作用就是监听某些事物的变化,然后通过回调函数,返回给客户(程序)去做一些响应的处理。
javax.servlet.ServletContextListener ServletContext 监听器
监听器的使用步骤。
第一步:我们需要定义一个类。然后去继承生命周期的监听器接口。
第二步:然后在 Web.xml 文件中配置。
ServletContextListener 监听器,一定要在 web.xml 文件中配置之后才会生效
ServletContextListener 监听器:可以监听ServletContext对象的创建和销毁
ServletContex对象在工程启动的时候创建,在工程结束的时候销毁。

在这里插入图片描述
监听到销毁或者创建都会调用ServletContextListener监听器的反馈
在这里插入图片描述ServletContextListener监听器的使用

在这里插入图片描述web.xml配置文件

在这里插入图片描述
7.EL 表达式 &JSTL 标签库

什么是 EL 表达式,EL 表达式的作用?
EL 表达式的全称是:Expression Language。是表达式语言。 EL 表达式的什么作用:EL 表达式主要是代替 jsp 页面中的表达式脚本在 jsp 页面中进行数据的输出。 因为 EL 表达式在输出数据的时候,要比 jsp 的表达式脚本要简洁很多。

在这里插入图片描述

EL 表达式的格式是:${表达式}
EL 表达式在输出 null 值的时候,输出的是空串。
jsp 表达式脚本输出 null 值的时候,输出的是 null 字符串。

EL 表达式搜索域数据的顺序

EL 表达式主要是在 jsp 页面中输出数据。 主要是输出域对象中的数据,跟代码的先后顺序无关。
当四个域中都有相同的 key 的数据的时候,EL 表达式会按照四个域的从小到大的顺序去进行搜索,找到就输出。

EL 表达式输出 Bean 的普通属性,数组属性。List 集 合属性,map 集合属性

EL 表达式——运算

语法:${ 运算表达式 } , EL 表达式支持如下运算符:

在这里插入图片描述在这里插入图片描述 empty 运算
empty 运算可以判断一个数据是否为空,如果为空,则输出 true,不为空输出 false。
以下几种情况为空:
1、值为 null 值的时候,为空
2、值为空串的时候,为空
3、值是 Object 类型数组,长度为零的时候
4、list 集合,元素个数为零
5、map 集合,元素个数为零

三元运算符
表达式 1?表达式 2:表达式 3
如果表达式 1 的值为真,返回表达式 2 的值,如果表达式 1 的值为假,返回表达式 3 的值。
在这里插入图片描述(.)点运算 和 [] 中括号运算符
.点运算,可以输出 Bean 对象中某个属性的值。
[]中括号运算,可以输出有序集合中某个元素的值。
并且[]中括号运算,还可以输出 map 集合中 key 里含有特殊字符的 key 的值。

在这里插入图片描述
EL 表达式的 11 个隐含对象
在这里插入图片描述在这里插入图片描述代码示例:
在这里插入图片描述 pageContext 对象的使用
java代码:
在这里插入图片描述使用EL表达式输出:
在这里插入图片描述EL 表达式其他隐含对象的使用
param Map<String,String> 它可以获取请求参数的值
paramValues Map<String,String[]> 它也可以获取请求参数的值,获取多个值的时候使用。

在这里插入图片描述在这里插入图片描述在这里插入图片描述
cookie Map<String,Cookie> 它可以获取当前请求的 Cookie 信息

在这里插入图片描述
initParam Map<String,String> 它可以获取在 web.xml 中配置的上下文参数

在这里插入图片描述在这里插入图片描述
JSTL 标签库(次重点)
JSTL 标签库 全称是指 JSPStandardTagLibrary JSP 标准标签库。是一个不断完善的开放源代码的 JSP 标 签库。 EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个 jsp 页面 变得更佳简洁。
在这里插入图片描述
在 jsp 标签库中使用 taglib 指令引入标签库

在这里插入图片描述JSTL 标签库的使用步骤

1、先导入 jstl 标签库的 jar 包。 taglibs-standard-impl-1.2.1.jar taglibs-standard-spec-1.2.1.jar
2、第二步,使用 taglib 指令引入标签库。
引入以下这条标签库
在这里插入图片描述 <c:set/>(使用很少)
作用:set 标签可以往域中保存数据

在这里插入图片描述
<c:if/>

if 标签用来做 if 判断。

在这里插入图片描述
<c:choose><c:when><c:otherwise>标签

作用:多路判断。跟 switch…case…default 非常接近

在这里插入图片描述在这里插入图片描述 <c:forEach/>
作用:遍历输出使用。

  1. 遍历 1 到 10,输出
    代码示例:
    在这里插入图片描述2. 遍历 Object 数组
    代码示例:
    在这里插入图片描述3. 遍历 Map 集合
    代码示例:
    在这里插入图片描述4. 遍历 List 集合—list 中存放 Student 类,有属性:编号,用户名,密码,年龄,
    电话信息

Student 类:拥有get和set,toString,无参和有参构造方法

在这里插入图片描述jsp代码
在这里插入图片描述在这里插入图片描述

9.JSP中的文件下载和上传

文件的上传介绍(重点)

1、要有一个 form 标签,method=post 请求
2、form 标签的 encType 属性值必须为 multipart/form-data 值
3、在 form 标签中使用 input type=file 添加上传的文件
4、编写服务器代码(Servlet 程序)接收,处理上传的数据。

encType=multipart/form-data 表示提交的数据,以多段(每一个表单项一个数据段)的形式进行拼 接,然后以二进制流的形式发送给服务器

文件上传,HTTP 协议的说明。

在这里插入图片描述commons-fileupload.jar 常用 API 介绍说明

commons-fileupload.jar 需要依赖 commons-io.jar 这个包,所以两个包我们都要引入。

第一步,就是需要导入两个 jar 包: commons-fileupload-1.2.1.jar和 commons-io-1.4.jar

ServletFileUpload 类,用于解析上传的数据。
ileItem 类,表示每一个表单项。

boolean ServletFileUpload.isMultipartContent(HttpServletRequest request); 判断当前上传的数据格式是否是多段的格式。

publicListparseRequest(HttpServletRequestrequest) 解析上传的数据

boolean FileItem.isFormField() 判断当前这个表单项,是否是普通的表单项。还是上传的文件类型。 true 表示普通类型的表单项 false 表示
上传的文件类型
String FileItem.getFieldName() 获取表单项的 name 属性值

String FileItem.getString() 获取当前表单项的值。

String FileItem.getName(); 获取上传的文件名

void FileItem.write( file ); 将上传的文件写到 参数 file 所指向抽硬盘位置 。

fileupload 类库的使用:
注意需要用表单进行提交,而且是以post方式进行提交,而且在表单中需要加上:enctype="multipart/form-data"这个属性
上传文件类的表单:
在这里插入图片描述解析上传的数据的代码:

package com.atguigu.servlet;


import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class UploadServlet extends HttpServlet {
    
    
    /**
     * 用来处理上传的数据
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        //1 先判断上传的数据是否多段数据(只有是多段的数据,才是文件上传的)
        if (ServletFileUpload.isMultipartContent(req)) {
    
    
//           创建FileItemFactory工厂实现类
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            // 创建用于解析上传数据的工具类ServletFileUpload类
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
            try {
    
    
                // 解析上传的数据,得到每一个表单项FileItem
                List<FileItem> list = servletFileUpload.parseRequest(req);
                // 循环判断,每一个表单项,是普通类型,还是上传的文件
                for (FileItem fileItem : list) {
    
    

                    if (fileItem.isFormField()) {
    
    
                        // 普通表单项

                        System.out.println("表单项的name属性值:" + fileItem.getFieldName());
                        // 参数UTF-8.解决乱码问题
                        System.out.println("表单项的value属性值:" + fileItem.getString("UTF-8"));

                    } else {
    
    
                        // 上传的文件
                        System.out.println("表单项的name属性值:" + fileItem.getFieldName());
                        System.out.println("上传的文件名:" + fileItem.getName());

                        fileItem.write(new File("e:\\" + fileItem.getName()));
                    }
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }

    }

}

文件下载:
下载的常用 API 说明:
response.getOutputStream();
servletContext.getResourceAsStream();
servletContext.getMimeType(); response.setContentType();

response.setHeader(“Content-Disposition”, “attachment; fileName=1.jpg”); 这个响应头告诉浏览器。这是需要下载的。而 attachment 表示附件,也就是下载的一个文件。fileName=后面, 表示下载的文件名。
完成上面的两个步骤,下载文件是没问题了。但是如果我们要下载的文件是中文名的话。你会发现,下载无法正确
显示出正确的中文名。
原因是在响应头中,不能包含有中文字符,只能包含 ASCII 码。

附件中文名乱码问题解决方案:

URLEncoder 解决 IE 和谷歌浏览器的 附件中 文名问题。
如果客户端浏览器是 IE 浏览器 或者 是谷歌浏览器。我们需要使用 URLEncoder 类先对中文名进行 UTF-8 的编码 操作。 因为 IE 浏览器和谷歌浏览器收到含有编码后的字符串后会以 UTF-8 字符集进行解码显示。
在这里插入图片描述BASE64 编解码操作:
在这里插入图片描述文件下载1代码

import org.apache.commons.io.IOUtils;
import javax.servlet.ServletContext;
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.InputStream;
import java.io.OutputStream;

//文件下载
@WebServlet("/download1")
public class Download1 extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
       /* 1.获取需要下载的文件名*/
         String dowloadFileName ="default.jpg";

       /* 2.读取需要下载的文件内容(通过servletcontext对象可以读取)*/
        ServletContext context = getServletContext();

        //获取要下载的文件类型
        String mineTyoe =context.getMimeType("/file/"+dowloadFileName);
        System.out.println("下载的文件类型:"+mineTyoe);

        /*4.回传之前通过响应头告诉客户端回传的数据类型*/
        resp.setContentType(mineTyoe);

       /* 5.告诉客户端数据是用于下载还是使用与响应头*/
       /* attachment:附件 filename :指定下载的文件名*/ //URL编码是把汉字转化为%xx%xx的格式
        resp.setHeader("Content-Disposition","attachment;filename="+ dowloadFileName);
//        URLEncoder.encode("摩托车.jpg","UTF-8")
        InputStream resourceAsStream = context.getResourceAsStream("/file/"+dowloadFileName);

        /*3.把下载的内容回传给客户端*/
        /*获取响应的输出流*/
        OutputStream outputStream = resp.getOutputStream();

        /*读取输入流张总的全部数据,复制给输出流,输出给客户端*/
        IOUtils.copy(resourceAsStream,outputStream);



    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
       this.doPost(req,resp);
    }
}

文件下载2代码:解决了谷歌火狐IE中文文件名编码不一致乱码问题

import org.apache.commons.io.IOUtils;
import sun.misc.BASE64Encoder;
import javax.servlet.ServletContext;
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.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
@WebServlet("/download2")
public class Download2 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
//        1、获取要下载的文件名
        String downloadFileName = "default.jpg";
//        2、读取要下载的文件内容 (通过ServletContext对象可以读取)
        ServletContext servletContext = getServletContext();
        // 获取要下载的文件类型
        String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
        System.out.println("下载的文件类型:" + mimeType);
//        4、在回传前,通过响应头告诉客户端返回的数据类型
        resp.setContentType(mimeType);
//        5、还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
        // Content-Disposition响应头,表示收到的数据怎么处理
        // attachment表示附件,表示下载使用
        // filename= 表示指定下载的文件名
        // url编码是把汉字转换成为%xx%xx的格式
        if (req.getHeader("User-Agent").contains("Firefox")) {
    
    
            // 如果是火狐浏览器使用Base64编码
            resp.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" + new BASE64Encoder().encode("摩托车.jpg".getBytes("UTF-8")) + "?=");
        } else {
    
    
            // 如果不是火狐,是IE或谷歌,使用URL编码操作
            resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("摩托车国.jpg", "UTF-8"));
        }
        /**
         * /斜杠被服务器解析表示地址为http://ip:prot/工程名/  映射 到代码的Web目录
         */
        InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFileName);
        // 获取响应的输出流
        OutputStream outputStream = resp.getOutputStream();
        //        3、把下载的文件内容回传给客户端
        // 读取输入流中全部的数据,复制给输出流,输出给客户端
        IOUtils.copy(resourceAsStream, outputStream);
    }
}

10.请求重定向和请求转发的区别

深入(分析理解)

转发过程
客户首先发送一个请求到服务器端,服务器端发现匹配的servlet,并指定它去执行,当这个servlet执行完之后,它要调用getRequestDispacther()方法,把请求转发给指定的student_list.jsp,整个流程都是在服务器端完成的,而且是在同一个请求里面完成的,因此servlet和jsp共享的是同一个request,在servlet里面放的所有东西,在student_list中都能取出来,因此,student_list能把结果getAttribute()出来,getAttribute()出来后执行完把结果返回给客户端。整个过程是一个请求,一个响应。

重定向过程

客户发送一个请求到服务器,服务器匹配servlet,这都和请求转发一样,servlet处理完之后调用了sendRedirect()这个方法,这个方法是response的方法,所以,当这个servlet处理完之后,看到response.senRedirect()方法,立即向客户端返回这个响应,响应行告诉客户端你必须要再发送一个请求,去访问student_list.jsp,紧接着客户端受到这个请求后,立刻发出一个新的请求,去请求student_list.jsp,这里两个请求互不干扰,相互独立,在前面request里面setAttribute()的任何东西,在后面的request里面都获得不了。可见,在sendRedirect()里面是两个请求,两个响应。

浅出(表象)

转发

当用RequestDispatcher请求转发后,地址栏为http://localhost:8080/test/TestServlet
这真好应正了上面的分析,我们起初请求的就一个servlet,至于你服务器端怎么转,流程怎么样的,我客户端根本就不知道,我发了请求后我就等着响应,那你服务器那边愿意怎么转就怎么转,我客户端不关心也没法知道,所以当服务器端转发到jsp后,它把结果返回给客户端,客户端根本就不知道你这个结果是我真正访问的servlet产生的,还是由servlet转发后下一个组件产生的。

重定向

当用sendRedirect重定向后,地址栏为http://localhost:8080/test/student_list.jsp
因为这个时候,客户端已经知道了他第二次请求的是student_list.jsp,服务器已经告诉客户端要去访问student_list.jsp了,所以地址栏里会显示想要访问的结果。

总结

转发在服务器端完成的;重定向是在客户端完成的
转发的速度快;重定向速度慢

转发的是同一次请求;重定向是两次不同请求

转发不会执行转发后的代码;重定向会执行重定向之后的代码

转发地址栏没有变化;重定向地址栏有变化

转发必须是在同一台服务器下完成;重定向可以在不同的服务器下完成

Forward是在服务器端的跳转,就是客户端一个请求发给服务器,服务器直接将请求相关的参数的信息原封不动的传递到该服务器的其他jsp或servlet去处理,而sendredirect是在客户端的跳转,服务器会返回给客户端一个响应报头和新的URL地址,原来的参数什么的信息如果服务器端没有特别处理就不存在了,浏览器会访问新的URL所指向的servlet或jsp,这可能不是原先服务器上的webservce了。

11.Cookie 和 Session

什么是 Cookie?

1、Cookie 翻译过来是饼干的意思。
2、Cookie 是服务器通知客户端保存键值对的一种技术。
3、客户端有了 Cookie 后,每次请求都发送给服务器。
4、每个 Cookie 的大小不能超过 4kb
cookie的创建
在这里插入图片描述

  //1 创建Cookie对象
        Cookie cookie = new Cookie("key4", "value4");
        //2 通知客户端保存Cookie
        resp.addCookie(cookie);
        //1 创建Cookie对象
        Cookie cookie1 = new Cookie("key5", "value5");
        //2 通知客户端保存Cookie
        resp.addCookie(cookie1);

服务器如何获取 Cookie

创建一个查找cookie的工具类()
在这里插入图片描述
传入需要查找的cookie和cookie对象

在这里插入图片描述Cookie 值的修改

方案一:
1、先创建一个要修改的同名(指的就是 key)的 Cookie 对象
2、在构造器,同时赋于新的 Cookie 值。
3、调用 response.addCookie(Cookie);

在这里插入图片描述方案二:
1、先查找到需要修改的 Cookie 对象
2、调用 setValue()方法赋于新的 Cookie 值。
3、调用 response.addCookie()通知客户端保存修改

在这里插入图片描述谷歌浏览器查看 Cookie:
在这里插入图片描述
Cookie 生命控制

Cookie 的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)

setMaxAge()

正数,表示在指定的秒数后过期
负数:表示浏览器一关,Cookie 就会被删除(默认值是-1)
零:表示马上删除 Cookie
在这里插入图片描述Cookie 有效路径 Path 的设置

Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。 path 属性是通过请求的地址来进行有效的过滤。

在这里插入图片描述在这里插入图片描述Session 会话

什么是 Session 会话?
1、Session 就一个接口(HttpSession)。
2、Session 就是会话。它是用来维护一个客户端和服务器之间关联的一种技术。
3、每个客户端都有自己的一个 Session 会话。
4、Session 会话中,我们经常用来保存用户登录之后的信息。

如何创建 Session 和获取(id 号,是否为新)

如何创建和获取 Session。它们的 API 是一样的。 request.getSession() 第一次调用是:创建 Session 会话 之后调用都是:获取前面创建好的 Session 会话对象。

isNew(); 判断到底是不是刚创建出来的(新的) true 表示刚创建 false 表示获取之前创建

每个会话都有一个身份证号。也就是 ID 值。而且这个 ID 是唯一的。 getId() 得到 Session 的会话 id 值。

在这里插入图片描述
Session 域数据的存取

在这里插入图片描述Session 生命周期控制

publicvoidsetMaxInactiveInterval(intinterval) 设置 Session 的超时时间(以秒为单位),超过指定的时长,Session 就会被销毁。

值为正数的时候,设定 Session 的超时时长。
负数表示永不超时(极少使用)

publicintgetMaxInactiveInterval()获取 Session 的超时时间

publicvoidinvalidate() 让当前 Session 会话马上超时无效。

Session 默认的超时时长是多少!
Session 默认的超时时间长为 30 分钟。

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

<session-config>
 <session-timeout>30</session-timeout>
</session-config>

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
浏览器和 Session 之间关联的技术内幕

在这里插入图片描述

12.谷歌验证码的使用

验证码有什么用?
1.验证码可以有效的解决表单重复提交,导致向数据库多次插入数据。

2.验证码可以有效的,一把使用在登录注册,可以防止一些病毒恶意登录和注册,可以大大的减轻服务器的压力。

表单重复提交之----->验证码

表单重复提交有三种常见的情况:
一:提交完表单。服务器使用请求转来进行页面跳转。这个时候,用户按下功能键 F5,就会发起最后一次的请求。 造成表单重复提交问题。解决方法:使用重定向来进行跳转

二:用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候,用户以为提交失败, 就会着急,然后多点了几次提交操作,也会造成表单重复提交。

三:用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复 提交。

在这里插入图片描述谷歌验证码 kaptcha 使用步骤如下:
1、导入谷歌验证码的 jar 包 kaptcha-2.3.2.jar

2.在 web.xml 中去配置用于生成验证码的 Servlet 程序

xml中的配置文件如下:

在这里插入图片描述
3、在表单中使用 img 标签去显示验证码图片并使用它

在这里插入图片描述
4、在服务器获取谷歌生成的验证码和客户端发送过来的验证码比较使用。

在这里插入图片描述
5.验证码的切换

在这里插入图片描述

13.Filter过滤器

1、Filter 过滤器它是 JavaWeb 的三大组件之一。
三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器
2、Filter 过滤器它是 JavaEE 的规范。也就是接口
3、Filter 过滤器它的作用是:拦截请求,过滤响应。

拦截请求常见的应用场景有: 1、权限检查 2、日记操作 3、事务管理

2、Filter 的初体验

要求:在你的 web 工程下,有一个 admin 目录。这个 admin 目录下的所有资源(html 页面、jpg 图片、jsp 文件、等等)都必 须是用户登录之后才允许访问。

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

jsp中实现登录后才可以访问的实现原理
在这里插入图片描述Filter 过滤器实现原理
在这里插入图片描述Filter 实现登录后才可以访问目标资源
xml配置文件
在这里插入图片描述
public class AdminFilter implements Filter 类
在这里插入图片描述
loglin页面
在这里插入图片描述loginServlet程序
在这里插入图片描述
3、Filter 的生命周期
Filter 的生命周期包含几个方法
1、构造器方法
2、init 初始化方法 第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)
3、doFilter 过滤方法 第 3 步,每次拦截到请求,就会执行
4、destroy 销毁 第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)
在这里插入图片描述
4、FilterConfig 类

FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。 Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。
FilterConfig 类的作用是获取 filter 过滤器的配置内容
1、获取 Filter 的名称 filter-name 的内容
2、获取在 Filter 中配置的 init-param 初始化参数
3、获取 ServletContext 对象

web.xml 配置

在这里插入图片描述
public class AdminFilter implements Filter 类
在这里插入图片描述

5、FilterChain 过滤器链

Filter 过滤器 Chain 链,链条 FilterChain 就是过滤器链(多个过滤器如何一起工作)

在这里插入图片描述
6、Filter 的拦截路径

在这里插入图片描述执行过程:
filter1 class
在这里插入图片描述
filter2 class

在这里插入图片描述web.xml配置文件

在这里插入图片描述
target页面
在这里插入图片描述
执行结果:

在这里插入图片描述
多个filter执行特点
1.所有的filter过滤器和目标资源都在同一个线程中执行
2.多个filter共同执行的时候,他们使用的都是同一个Requset对象
3.在多个Filter过滤器执行的时候,他们的执行顺序是由web.xml中的配置文件从上到下的配置文件顺序决定的
4.如果在执行到第二个filter过滤器时,没有 filterChain.doFilter(servletRequest,servletResponse);语句,就会直接返回,不会去访问目标资源。
注释掉filter的
最终执行结果
在这里插入图片描述

14.ThreadLocal 的使用

ThreadLocal 的作用,它可以解决多线程的数据安全问题。

ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
ThreadLocal 的特点:

1、ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)

2、每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例。

3、每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型

4、ThreadLocal 中保存数据,在线程销毁后。会由 JVM 虚拟自动释放

ThreadLocal模仿

package com.atguigu.fiter;

import java.util.Hashtable;
import java.util.Map;
import java.util.Random;


/**
 * @ClassName : ThreadLocal  //类名
 * @Description : 事务管理  //描述
 * @Author : ${""} //作者
 * @Date: 2020/11/11  18:51
 */
public class ThreadLocal {
    
    
    public  final  static Map< String ,Object> data = new Hashtable<>();
    private  static Random random = new Random();
    public static class Task   implements  Runnable{
    
    

        public void run() {
    
    
            //在run方法中随机生成一个变量(线程要关联的数据,当前线程名为key,保存到map中)
            //在run方法快结束之前,以当前线程名称取出数据并且打印,查看是否可以取出操作
            Integer i = random.nextInt(1000);
            String name = Thread.currentThread().getName(); //获取当前线程名
            System.out.println( "线程"+name+"生成的随机数是"+i);
            data.put(name,i);
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }


            System.out.println("线程"+name+"线程快结束时取出的关联的数据是"+data.get(name));
        }


    }
            //创建三个线程对象
    public static void main(String[] args) {
    
    
        for (int i= 0;i<3;i++){
    
    
            new Thread(new Task()).start();
        }
    }
    
}
  


Threadlocal的使用

package com.atguigu.fiter;

import java.util.*;
import  java.lang.ThreadLocal;

/**
 * @ClassName : ThreadLocal  //类名
 * @Description : 事务管理  //描述
 * @Author : ${"胡雨"} //作者
 * @Date: 2020/11/11  18:51
 */
public class ThreadLocalTest {
    
    
  public static ThreadLocal<Object> threadLocal= new ThreadLocal<Object>();

    private  static Random random = new Random();
    public static class Task   implements  Runnable{
    
    

        public void run() {
    
    
            //在run方法中随机生成一个变量(线程要关联的数据,当前线程名为key,保存到map中)
            //在run方法快结束之前,以当前线程名称取出数据并且打印,查看是否可以取出操作
            Integer i = random.nextInt(1000);
            String name = Thread.currentThread().getName(); //获取当前线程名
            System.out.println( "线程"+name+"生成的随机数是"+i);

            //设置threadLocal的值
            threadLocal.set(i);
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //获取threadLocal的值
            System.out.println("线程"+name+"线程快结束时取出的关联的数据是"+threadLocal.get() );
            //采用匿名对象的方式去调用createOrder()方法
            new OrderService().createOrder();
        }


    }
    //创建三个线程对象
    public static void main(String[] args) {
    
    
        for (int i= 0;i<3;i++){
    
    
            new Thread(new Task()).start();
        }
    }

}



OrderService类

package com.atguigu.fiter;

public class OrderService {
    
    

    public void createOrder(){
    
    
        String name = Thread.currentThread().getName();
        System.out.println("OrderService 当前线程[" + name + "]中保存的数据是:" + ThreadLocalTest.threadLocal.get());
        new OrderDao().saveOrder();
    }

}

使用 Filter 和 ThreadLocal 组合管理事务
1、使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成

在这里插入图片描述
使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch。来进行实现的管理。

在这里插入图片描述
将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息页面。在 web.xml 中我们可以通过错误页面配置来进行管理。

在这里插入图片描述
注意点:一定要从最内层,层层向外抛出异常,否则外层捕获不到异常,就无法执行回滚事务操作。

15.JSON和Ajax请求

1、什么是 JSON?

JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。JSON 采用完全独立于语言的文本格式,而且很多语言都提供了对 json 的支持(包括 C, C++, C#, Java, JavaScript, Perl, Python 等)。 这样就使得 JSON 成为理想的数据交换格式。

json 是一种轻量级的数据交换格式。

轻量级指的是跟 xml 做比较。

数据交换指的是客户端和服务器之间业务数据的传递格式。

应用场景?

1.用于更新部分页面内容,而不刷新页面
2.比如注册时,验证用户名是否可用
3.区块内容切换
等等…

2.JSON 在 JavaScript 中的使用。

json 是由键值对组成,并且由花括号(大括号)包围。每个键由引号引起来,键和值之间使用冒号进行分隔, 多组键值对之间进行逗号进行分隔。

1.json的定义
在这里插入图片描述2获取json数据

在这里插入图片描述
3.json的数据转换
在这里插入图片描述

15.1JSON 在 java 中的使用(相互转换)

需要用到jar包
在这里插入图片描述
1.javaBean 和 json 的互转
在这里插入图片描述
2.List 和json的互转

在这里插入图片描述
3.map 和json的互转
在这里插入图片描述

15.2 Ajax 请求

什么是 AJAX 请求?

AJAX 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发 技术。 ajax 是一种浏览器通过 js 异步发起请求,局部更新页面的技术。

Ajax 请求的局部更新,浏览器地址栏不会发生变化 局部更新不会舍弃原来页面的内容

1.原生 AJAX 请求的示例:

html请求页面
在这里插入图片描述

servlet程序
在这里插入图片描述
2.jQuery中的ajax请求

$.ajax 方法

url 表示请求的地址
type 表示请求的类型 GET 或 POST 请求

data 表示发送给服务器的数据 格式有两种:
一:name=value&name=value
二:{key:value} success 请求成功,响应的回调函数

dataType 响应的数据类型 常用的数据类型有:
text 表示纯文本
xml 表示 xml 数据
json 表示 json 对象

jquery Ajax请求

在这里插入图片描述servlet代码

BaseServlet

package atguigu.servlet;
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.lang.reflect.Method;

public abstract class BaseServlet extends HttpServlet {
    
    

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        doPost(req, resp);
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 解决post请求中文乱码问题
        // 一定要在获取请求参数之前调用才有效
        req.setCharacterEncoding("UTF-8");
        // 解决响应中文乱码
        resp.setContentType("text/html; charset=UTF-8");
        String action = req.getParameter("action");
        try {
    
    
            // 获取action业务鉴别字符串,获取相应的业务 方法反射对象
            Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
//            System.out.println(method);
            // 调用目标业务 方法
            method.invoke(this, req, resp);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            throw new RuntimeException(e);// 把异常抛给Filter过滤器
        }
    }

}

JqueryServlet
在这里插入图片描述
表单序列化 serialize()

serialize()可以把表单中所有表单项的内容都获取到。

并以 name=value&name=value 的形式进行拼接。

在这里插入图片描述
jQuerySerialize程序
在这里插入图片描述

结果:
在这里插入图片描述

16.i18n(国际化)

什么是 i18n 国际化?

1.国际化(Internationalization)指的是同一个网站可以支持多种不同的语言,以方便不同国家,不同语种的用户访问。  关于国际化我们想到的最简单的方案就是为不同的国家创建不同的网站,比如苹果公司,他的英文官网是: http://www.apple.com 而中国官网是 http://www.apple.com/cn

  1. 苹果公司这种方案并不适合全部公司,而我们希望相同的一个网站,而不同人访问的时候可以根据用户所在的区域显示 不同的语言文字,而网站的布局样式等不发生改变。
  2. 于是就有了我们说的国际化,国际化总的来说就是同一个网站不同国家的人来访问可以显示出不同的语言。但实际上这 种需求并不强烈,一般真的有国际化需求的公司,主流采用的依然是苹果公司的那种方案,为不同的国家创建不同的页 面。所以国际化的内容我们了解一下即可。
  3. 国际化的英文 Internationalization,但是由于拼写过长,老外想了一个简单的写法叫做 I18N,代表的是 Internationalization 这个单词,以 I 开头,以 N 结尾,而中间是 18 个字母,所以简写为 I18N。以后我们说 I18N 和国际化是一个意思。

国际化相关要素介绍

在这里插入图片描述
2.国际化资源 properties 测试

在这里插入图片描述java代码

package i18n;

import org.junit.Test;

import java.util.Locale;
import java.util.ResourceBundle;

public class I18nTest {
    
    

    @Test
    public void testLocale(){
    
    
        // 获取你系统默认的语言。国家信息
        Locale locale = Locale.getDefault();
        System.out.println("当前系统默认国家语言信息:"+locale);

//        for (Locale availableLocale : Locale.getAvailableLocales()) {
    
    
//            System.out.println(availableLocale);
//        }

        // 获取中文,中文的常量的Locale对象
        System.out.println(Locale.CHINA);
        // 获取英文,美国的常量的Locale对象
        System.out.println(Locale.US);

    }

    @Test
    public void testI18n(){
    
    
        // 得到我们需要的Locale对象
        Locale locale = Locale.CHINA;
        // 通过指定的basename和Locale对象,读取 相应的配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("i18n", locale);

        System.out.println("username:" + bundle.getString("username"));
        System.out.println("password:" + bundle.getString("password"));
        System.out.println("Sex:" + bundle.getString("sex"));
        System.out.println("age:" + bundle.getString("age"));
    }

}

国际化实战案例

1.通过请求头国际化页面
在这里插入图片描述

<center>
		<h1><%=i18n.getString("regist")%></h1>
		<table>
		<form>
			<tr>
				<td><%=i18n.getString("username")%></td>
				<td><input name="username" type="text" /></td>
			</tr>
			<tr>
				<td><%=i18n.getString("password")%></td>
				<td><input type="password" /></td>
			</tr>
			<tr>
				<td><%=i18n.getString("sex")%></td>
				<td>
					<input type="radio" /><%=i18n.getString("boy")%>
					<input type="radio" /><%=i18n.getString("girl")%>
				</td>
			</tr>
			<tr>
				<td><%=i18n.getString("email")%></td>
				<td><input type="text" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
				<input type="reset" value="<%=i18n.getString("reset")%>" />&nbsp;&nbsp;
				<input type="submit" value="<%=i18n.getString("submit")%>" /></td>
			</tr>
			</form>
		</table>
		<br /> <br /> <br /> <br />
	</center>

2.通过显示的选择语言类型进行国际化

<%@ page import="java.util.Locale" %>
<%@ page import="java.util.ResourceBundle" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%
		// 从请求头中获取Locale信息(语言)
		Locale locale = null;

		String country = request.getParameter("country");
		if ("cn".equals(country)) {
    
    
			locale = Locale.CHINA;
		} else if ("usa".equals(country)) {
    
    
			locale = Locale.US;
		} else {
    
    
			locale = request.getLocale(); //获取默认
		}

		System.out.println(locale);
		// 获取读取包(根据 指定的baseName和Locale读取 语言信息)
		ResourceBundle i18n = ResourceBundle.getBundle("i18n", locale);

	%>
	<a href="i18n.jsp?country=cn">中文</a>|
	<a href="i18n.jsp?country=usa">english</a>
	<center>
		<h1><%=i18n.getString("regist")%></h1>
		<table>
		<form>
			<tr>
				<td><%=i18n.getString("username")%></td>
				<td><input name="username" type="text" /></td>
			</tr>
			<tr>
				<td><%=i18n.getString("password")%></td>
				<td><input type="password" /></td>
			</tr>
			<tr>
				<td><%=i18n.getString("sex")%></td>
				<td>
					<input type="radio" /><%=i18n.getString("boy")%>
					<input type="radio" /><%=i18n.getString("girl")%>
				</td>
			</tr>
			<tr>
				<td><%=i18n.getString("email")%></td>
				<td><input type="text" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
				<input type="reset" value="<%=i18n.getString("reset")%>" />&nbsp;&nbsp;
				<input type="submit" value="<%=i18n.getString("submit")%>" /></td>
			</tr>
			</form>
		</table>
		<br /> <br /> <br /> <br />
	</center>
	国际化测试:
	<br /> 1、访问页面,通过浏览器设置,请求头信息确定国际化语言。
	<br /> 2、通过左上角,手动切换语言
</body>
</html>

3.JSTL 标签库实现国际化

<%–1使 用 标 签 设 置 Locale信 息 --%>
<fmt:setLocale value="" />

<%–2 使 用 标 签 设 置 baseName–%>
<fmt:setBundle basename=""/>

< %–3 输 出 指 定 k e y 的 国 际 化 信 息 --%>
<fmt:message key="" />

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%--1 使用标签设置Locale信息--%>
	<fmt:setLocale value="${param.locale}" />
	<%--2 使用标签设置baseName--%>
	<fmt:setBundle basename="i18n"/>


	<a href="i18n_fmt.jsp?locale=zh_CN">中文</a>|
	<a href="i18n_fmt.jsp?locale=en_US">english</a>
	<center>
		<h1><fmt:message key="regist" /></h1>
		<table>
		<form>
			<tr>
				<td><fmt:message key="username" /></td>
				<td><input name="username" type="text" /></td>
			</tr>
			<tr>
				<td><fmt:message key="password" /></td>
				<td><input type="password" /></td>
			</tr>
			<tr>
				<td><fmt:message key="sex" /></td>
				<td>
					<input type="radio" /><fmt:message key="boy" />
					<input type="radio" /><fmt:message key="girl" />
				</td>
			</tr>
			<tr>
				<td><fmt:message key="email" /></td>
				<td><input type="text" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
				<input type="reset" value="<fmt:message key="reset" />" />&nbsp;&nbsp;
				<input type="submit" value="<fmt:message key="submit" />" /></td>
			</tr>
			</form>
		</table>
		<br /> <br /> <br /> <br />
	</center>
</body>
</html>

经过一段时间的学习,javaweb阶段就告一段落了,javaweb阶段不要太大意,重点部分是一定要掌握好的,一句话,基础不牢地动山摇。初学阶段肯定会有很多不足,后期可能会继续修改此文章。

猜你喜欢

转载自blog.csdn.net/m0_46188681/article/details/108944820