JavaWeb之Servlet

12、XML

12.1、XML概述

概念:Extensible Markup Language 可扩展标记语言

  • 可扩展:标识都是自定义的。如:

功能:

  • 存储数据
    1. 配置文件
    2. 在网络中传输

XML与HTML的区别

  1. xml标签都是自定义的,html标签是预定义
  2. xml的语法严格,html语法松散
  3. xml是存储数据的,html是展示数据

12.2、XML快速入门

基本语法:

  1. xml文档的后缀名 .xml
  2. xml第一行必须定义为文档声明
  3. xml文档中有且仅有一个根标签
  4. 属性值必须使用引号(单双都可)引起来
  5. 标签必须正确关闭
  6. xml标签名称区分大小写

快速入门


<users>
	<user id = '1'>
		<name>zhangsanname>
    <age>23age>
    <gender>malegender>
    <br/>
	user>
  <user id = '2'>
    <name>lisiname>
    <age>24age>
    <gender>femalegender>
  user>
users>

12.3、XML的组成部分

文档声明

  1. 格式:
  2. 属性列表:
    • version:版本号,必须得属性
    • encoding:编码方式。告知解析引擎当前文档使用的字符集,默认值:ISO-8859-1
    • standalone:是否独立
      • 取值:
        • yes:不依赖其他文件
        • no:依赖其他文件

指令(了解):结合css的


标签:标签名称自定义的

  • 规则:
    • 名称可以包含字母、数字以及其他字符
    • 名称不能以数字或者标点符号开始
    • 名称不能以字母 xml(或者 XML、Xml 等等)开始
    • 名称不能包含空格

属性:

​ id属性值唯一

文本:

  • CDATA区:在该区域中的数据会被原样展示
    • 格式:

12.4、约束

12.4.1、约束概述

约束:规定xml文档的书写规则

  • 作为框架的使用者(程序员):
    1. 能够在xml中引入约束文档
    2. 能够简单的读懂约束文档
  • 分类
    1. DTD:一种简单的约束技术
    2. Schema:一种复杂的约束技术

JavaWeb之Servlet_第1张图片

12.4.2、DTD约束

DTD:

  • 引入dtd文档到xml文档中
    • 内部dtd:将约束规则定义在xml文档中
    • 外部dtd:将约束规则定义到外部的dtd文件中
      • 本地:
      • 网络:
 
 






DOCTYPE students SYSTEM "student.dtd">
<students>
    <student number="s001">
        <name>zhangsanname>
        <age>20age>
        <sex>nansex>
    student>
students>

12.4.3、Schema约束

引入:

  1. 填写xml文档的根元素
  2. 引入xsi前缀 .xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. 引入xsd文件命名空间 .xsi:schemalocation="http://www.itcast.cn/xml student.xsd"
  4. 为每一个xsd约束声明一个前缀,作标识 xmlns="http://www.itcast.cn/xml"

<xsd:schema xmlns="http://www.itcast.cn/xml"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.itcast.cn/xml" elementFormDefault="qualified">
    
    <xsd:element name="students" type="studentsType"/>
    
    <xsd:complexType name="studentsType">
        <xsd:sequence>
            <xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded"/>
        xsd:sequence>
    xsd:complexType>
     
    <xsd:complexType name="studentType">
        <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:element name="age" type="ageType" />
            <xsd:element name="sex" type="sexType" />
        xsd:sequence>
        
        <xsd:attribute name="number" type="numberType" use="required"/>
    xsd:complexType>
    
    <xsd:simpleType name="sexType">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="male"/>
            <xsd:enumeration value="female"/>
        xsd:restriction>
    xsd:simpleType>
    
    <xsd:simpleType name="ageType">
        <xsd:restriction base="xsd:integer">
            <xsd:minInclusive value="0"/>
            <xsd:maxInclusive value="256"/>
        xsd:restriction>
    xsd:simpleType>
    
    <xsd:simpleType name="numberType">
        <xsd:restriction base="xsd:string">
            <xsd:pattern value="heima_\d{4}"/>
        xsd:restriction>
    xsd:simpleType>
xsd:schema> 


 <students   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 			 xmlns="http://www.itcast.cn/xml" 
 		   xsi:schemaLocation="http://www.itcast.cn/xml  student.xsd"
 		    >
 	<student number="heima_0001">
 		<name>tomname>
 		<age>18age>
 		<sex>malesex>
 	student>
		 
 students>

12.5、XML解析

解析:操作xml文档,将文档中的数据读取到内存中

  • 操作xml文档

    1. 解析(读取):将文档中的数据读取到内存中
    2. 写入:将内存中的数据保存到xml文档中。持久化的存储
  • 解析xml的方式:

    1. DOM:将标记语言文档一次性加载进内存,在内存中形成一颗dom树
      • 优点:操作方便,可以对文档进行CRUD的所有操作
      • 缺点:占内存
    2. SAX:逐行读取,基于事件驱动的
      • 优点:不占内存
      • 缺点:只能读取,不能增删改
  • xml常见的解析器:

    1. JAXP:sun公司提供的解析器,支持dom和sax两种思想
    2. DOM4J:一款非常优秀的解析器
    3. Jsoup:jsoup 是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,css以及类似于jQuery的操作方式来取出和操作数据
    4. PULL:Android操作系统内置的解析器,sax方式的。

12.5.1、Jsoup解析器

Jsoup:jsoup 是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,css

以及类似于jQuery的操作方式来取出和操作数据

快速入门:

  • 步骤:
    1. 导入jar包
    2. 获取Doument对象
    3. 获取对应的标签Element对象
    4. 获取数据
package com.xh.Jsoup;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.IOException;

public class JsoupDome {
    public static void main(String[] args) throws IOException {
        //获取xml文件地址
        String path = JsoupDome.class.getClassLoader().getResource("student.xml").getPath();
        //使用解析器获取Document对象
        Document parse = Jsoup.parse(new File(path),"utf-8");
        //获取元素对象
        Elements name = parse.getElementsByTag("name");
        System.out.println(name.size());
    }
}

12.5.2、Jsoup对象的使用

Jsoup:工具类,可以解析html或xml文档,返回Document对象

  • parse:解析html或xml文档,返回Document对象
    • parse(File in,String charsetName):解析xml或html文件的。第二个参数是字符集名称
    • parse(String html):解析xml或html字符串
    • parse(URL url,int timeoutMillis):通过网络路径获取指定的html或xml的文档对象

Document:文档对象。代表内存中的dom树

  • 获取Element对象
    • getElementbyId(String id):根据id属性值获取唯一的element对象
    • getElementsByTag(String tagName):根据标签名称获取元素对象集合
    • getElementsByAttribute(String key):根据属性名称获取元素对象集合
    • getElementsByAttributeValue(String key,String value):根据对应的属性名或属性值获取元素对象集合

Elements:元素Element对象的集合。可以当做ArrayList来使用

Element:元素对象

  1. 获取子元素对象
    • getElementbyId(String id):根据id属性值获取唯一的element对象
    • getElementsByTag(String tagName):根据标签名称获取元素对象集合
    • getElementsByAttribute(String key):根据属性名称获取元素对象集合
    • getElementsByAttributeValue(String key,String value):根据对应的属性名或属性值获取元素对象集合
  2. 获取属性值
    • String attr(String key):根据属性名称获取属性值
  3. 获取文本内容
    • String text():获取文本内容
    • String html():获取标签体的所有内容(包括字标签的字符串内容)

Node:节点对象

  • 是Document和Element的父类

12.5.3、XML快捷查询方式

selector:选择器

  • 使用的方法:Elements selet(String cssQuery)
    • 语法:参考Selector类中定义的语法(参数就是css选择器)

XPath:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某位置的语言

  • 使用JSoup的Xpath需要额外导入jar包
  • 查询w3cshool参考手册,使用xpath的语法完成查询
package com.xh.Jsoup;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.seimicrawler.xpath.JXDocument;
import org.seimicrawler.xpath.JXNode;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class XpathDome {
    public static void main(String[] args) throws IOException {
        Document parse = Jsoup.parse(new File("D:\\开发资源\\project\\JavaWeb\\JDBC_Druid\\src\\main\\resources\\student.xml"),"utf-8");
        JXDocument jxDocument = new JXDocument(parse.getAllElements());
        List<JXNode> jxNodes = jxDocument.selN("//student");
        for (JXNode jxNode : jxNodes) {
            System.out.println(jxNode);
        }
    }
}

13、Web

13.1、Web的相关概念

软件架构:

  1. C/S:Client/Server 客户端/服务端
  2. B/S:Browser/Server 浏览器/服务器端

资源分类:

  1. 静态资源:
    • 使用静态网页开发技术分布的资源
    • 特点:
      • 所有用户访问,得到的结果是一样的
      • 如:文本,图片,音频,视频,HTML,CSS,JavaScript
      • 如果用户请求的是静态资源,那么服务器会直接将静态资源发送给浏览器。浏览器中内置了静态资源的解析引擎,可以展示静态资源
  2. 动态资源:
    • 使用动态网页及时发布的资源
    • 特点:
      • 所有用户访问,得到的结果可能不一样
      • 如:jsp/servlet,php,asp…
      • 如果用户请求的是动态资源,那么服务器会执行动态资源,转换为静态资源,再发送给浏览器

网络通信三要素

  1. IP:电子设备(计算机)在网络中的唯一标识
  2. 端口:应用程序在计算机中的唯一标识。0~65536
  3. 传输协议:规定了数据传输的规则
    1. 基础协议:
      1. tcp:安全协议,三次握手。速度稍慢
      2. udp:不安全协议。速度快

JavaWeb之Servlet_第2张图片

13.2、web服务器软件

服务器:安装了服务器软件的计算机

服务器软件:接收用户的请求,处理请求,做出响应

  • 在web服务软件中,可以部署web项目,让用户通过浏览器来访问这些项目
  • web容器

常见的java相关的web服务器软件:

  • webLogic:oracle公司,大型的javaEE服务器,支持所有的JavaEE规范,收费的
  • webSpnere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • JBOSS:JBOSS公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。

JavaEE:Java语言在企业级开发中使用的技术规范的总和,一共规定了13项大的规范

13.3、Tomcat

Tomcat:web服务器软件

  1. 下载:http://tomcat.apache.org/

  2. 安装:解压缩压缩包即可

    • 注意:安装目录建议不要有中文和空格
  3. 卸载:删除目录就行了

  4. 启动:

    • bin/startup.bat,双击运行该文件即可

    • 访问:浏览器输入:http://localhost:8080 回车访问自己

      ​ http://别人的ip:8080 访问别人

    • 可能遇到的问题:

      1. 黑窗口一闪而过:

        • 原因:没有正确配置JAVA_HOME环境变量
        • 解决方案:正确配置JAVA_HOME环境变量
      2. 启动报错:

        1. 暴力:找到占用的端口号,并且肇东对应的进程,杀死该进程

          netstat -ano

        2. 温柔:修改自身的端口号

          conf/server.xml

          <Connector port="8888" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8445" />
          
          • 一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号
            • 好处:在访问时,就不用输入端口号
  5. 关闭:

    1. 正常关闭:
      • bin/shutdown.bat
      • ctrl + c
    2. 强制关闭:
      • 点击启动窗口的x
  6. 配置:

    • 部署项目的方式:

      1. 直接将项目放到webapps目录下即可。

        • /hello:项目的访问路径–>虚拟目录
        • 简化部署:将项目打成一个war包,再将war包放置到webapps目录下
          • war包会自动解压缩
      2. 配置conf/server.xml文件

        标签体中配置

        <Context docBase="D:\hello" path="/hehe" />
        
        • docBase:项目存放的路径
        • path:虚拟目录
      3. 在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写

        <Context docBase="D:\hello" />
        
        • 虚拟目录:xml文件的名称
    • 静态项目和动态项目:

      • 目录结构

        • java动态项目的目录结构:

          – 项目的根目录

          ​ – WEB-INF目录:

          ​ – web.xml:web项目的核心配置文件

          ​ – classes目录:放置字节码文件的目录

          ​ – lib目录:放置依赖的jar包

    • 将Tomcat集成到IDEA中,并且创建JavaEE的项目,部署项目

14、Servlet

14.1、Servlet概述

servlet:server applet

  • 概述:运行在服务器端的小程序
    • Servlet就是一个接口,定义了Java类被浏览器访问到(Tomcat识别)的规则
    • 将来我们自定义一个类,实现Servlet接口,复写方法。

JavaWeb之Servlet_第3张图片

14.2、Servlet快速入门

  1. 创建JavaEE项目

  2. 定义一个类,实现Servlet接口

package com.example.Servlet;

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

public class ServletDome1 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    //执行业务逻辑方法
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("hello Tomcat....");
    }

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

    @Override
    public void destroy() {

    }
}
  1. 实现接口中的抽象方法
  2. 配置Servlet

<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>domeservlet-name>
        <servlet-class>com.example.Servlet.ServletDome1servlet-class>
    servlet>
    <servlet-mapping>
        <servlet-name>domeservlet-name>
        <url-pattern>/domeurl-pattern>
    servlet-mapping>
web-app>

14.3、Servlet执行原理

执行原理:

  1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
  2. 查找web.xml文件,是否有对应的标签体内容
  3. 如果有,则在找到对应的全类名
  4. tomcat会将字节码文件加载进内存,并且创造其对象
  5. 调用其方法

JavaWeb之Servlet_第4张图片

14.4、Servlet生命周期

Servlet中的生命周期方法:

  1. 被创建:执行init方法,只执行一次
    • Servlet什么时候被创建?
      • 默认情况下,第一次被访问时,Servlet被创建
      • 可以配置执行Servlet的创建时机。
        • 在web.xml文件下标签下配置
          1. 第一次被访问时,创建
            • 的值为负数
          2. 在服务器启动时,创建
            • 的值为0或正整数
    • Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet时单例的
      • 多个用户同时访问时,可能存在线程安全问题
      • 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对其修改值
  2. 提供服务:执行service方法,执行多次
    • 每次访问Servlet时,Service方法都会被调用一次
  3. 被销毁:执行destroy方法,只执行一次
    • Servlet被销毁时执行。服务器关闭时,Servlet被销毁
    • 只有服务器正常关闭时,才会执行destroy方法
    • destroy方法在Servlet被销毁之前执行,一般用于释放资源

14.5、Servlet3.0注解配置

Servlet3.0:

  • 好处:
    • 支持注解配置。可以不需要web.xml了
  • 步骤:
    1. 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
    2. 定义一个类,实现Servlet接口
    3. 复写方法
    4. 在类上使用@WebServlet注解,进行配置
      • @WebServlet(“资源路径”)
package javax.servlet.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
    String name() default "";//相当于dome配置

    String[] value() default {};//代表urlPatterns()属性配置

    String[] urlPatterns() default {};//相当于

    int loadOnStartup() default -1;//相当于

    WebInitParam[] initParams() default {};

    boolean asyncSupported() default false;

    String smallIcon() default "";

    String largeIcon() default "";

    String description() default "";

    String displayName() default "";
}

14.6、IDEA与tomcat的相关配置

IDEA会为每一个tomcat部署的项目单独建立一份配置文件

  • 查看控制台的log:Using CATALINA_BASE:C:\Users\Dell\AppData\Local\JetBrains\IntelliJIdea2021.1\tomcat\796a9df0-414d-4263-902d-b9cfe26122ab"

工作空间项目 和 tomcat部署的web项目

  • tomcat真正访问的是“tomcat部署的web项目“,”tomcat部署的web项目”对应着“工作空间项目“ 的web目录下的所有资源
  • WEB-INF目录下的资源不能被浏览器直接访问

断电调试:使用“小虫子”启动dubug启动

14.7、Servlet的体系结构

Servlet – 接口

​ |

GenericServlet – 抽象类

​ |

HttpServlet – 抽象类

  • GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
    • 将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可
  • HttpServlet:对http协议的一种封装,简化操作
    1. 定义类继承HttpServlet
    2. 复写doGet/doPost方法

14.8、Servlet相关配置

  1. urlpartten:Servlet访问路径
    1. 一个Servlet可以定义多个访问路径:@WebServlet({“/d4”,“/dd4”,“/ddd4”})
    2. 路径定义规则:
      1. /xxx
      2. /xxx/xxx:多层路径,目录结构
      3. *.do

15、HTTP

15.1、HTTP概述

概念:Hyper Text Transfer Protocol 超文本传输协议

  • 传输协议:定义了,客户端和服务器端通信时,发送数据的格式
  • 特点:
    1. 基于TCP/IP的高级协议
    2. 默认端口号:80
    3. 基于请求/响应模型的:一次请求对应一次响应
    4. 无状态的:每次请求之间相互独立,不能交互数据
  • 历史版本:
    • 1.0:每一次请求响应都会建立新的连接
    • 1.1:复用连接

JavaWeb之Servlet_第5张图片

15.2、请求消息

15.2.1、请求行

请求方式 请求url 请求协议/版本

GET /login.html HTTP/1.1

  • 请求方式:
    • HTTP协议有7种请求方式,常用的有2种
      • GET:
        1. 请求参数在请求行中,在url后
        2. 请求的url长度有限制的
        3. 不太安全
      • POST:
        1. 请求参数在请求体中
        2. 请求的url长度没有限制
        3. 相对安全

15.2.2、请求头

请求头:客户端浏览器告诉服务器一些信息

请求头名称:请求头值

  • 常见的请求头:
    1. User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
      • 可以在服务端获取该头的信息,解决浏览器的兼容性问题
    2. Referer:http://localhost/login.html
      • 告诉服务器,我(当前请求)从哪里来?
        • 作用:
          1. 防盗链:
          2. 统计工作:

JavaWeb之Servlet_第6张图片

15.2.3、请求空行

请求空行

空行,就是用于分割POST请求的请求头,和请求体的

15.2.4、请求体

请求体(正文):

  • 封装POST请求消息的请求参数的

15.2.5、请求消息的字符串格式

POST /login.html        HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
	
username=zhangsan

15.3、响应消息

响应消息:服务器端发送给客户端的数据

15.3.1、响应行

组成:协议/版本 响应状态码 状态码描述

响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态

  1. 状态码都是3位数字

  2. 分类:

    1. 1xxx:服务器就收客户端消息,但没有接受完成,等一段时间后,发送1xx多状态码

    2. 2xx:成功。代表:200

    3. 3xx:重定向。代表:302(重定向),304(访问缓存)

      JavaWeb之Servlet_第7张图片

      JavaWeb之Servlet_第8张图片

    4. 4xx:客户端错误

      • 代表:
        • 404:(请求路径没有对应的资源)
        • 405:请求方式没有对应的doXxx方法
    5. 5xx:服务器端错误。代表:500(服务器内部出现错误)

15.3.2、响应头

格式:头名称:值

常见的响应头:

  1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
  2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据
    • 值:
      • in-line:默认值,在当前页面内打开
      • attachment;filename=xxx:以附件形式打开响应体。文件下载

15.3.3、响应空行

响应空行:空行

15.3.4、响应体

响应体:响应数据

15.3.5、响应字符串格式

HTTP/1.1 200 ОK
Content-Type: text/html;charset=UTF-8
Content-Length: 101
Date: Wed, 06 Jun 2018 07:08:42 GMTI

	
		$Title$
	
	
	hello, response
	

16、Request

16.1、request原理

request对象和response对象的原理

  1. request和response对象是由服务器创建的。我们来使用它们
  2. request对象是来获取请求消息,response对象是来设置响应消息

JavaWeb之Servlet_第9张图片

16.2、request继承体系

request对象继承体系结构:

ServletRequest – 接口

​ | 继承

HttpServletRequest – 接口

​ | 实现

org.apache.catalina.connector.RequestFacade 类(tomcat编写)

16.3、request功能

16.3.1、获取请求消息数据

  1. 获取请求行数据

    • GET /day14/demo1?name=zhangsan HTTP/1.1

    • 方法:

      1. 获取请求方式:GET

        • String getMethod()
      2. (*)获取虚拟目录:/day14

        • String getContextPath()
      3. 获取Servlet路径:/demo1

        • String getServletPath()
      4. 获取get方式请求参数:name = zhangsan

        • String getQueryString()
      5. (*)获取请求URI:/day14/demo1

        • String getRequestURI(): /day14/demo1
        • StringBuffer getRequestURL() :http://localhost/day14/demo1
      6. 获取协议及版本:HTTP/1.1

        • String getProtocol()
      7. 获取客户机的IP地址

        String getRemoteAddr()

package com.example.Request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "RequestDome1", value = "/RequestDome1")
public class RequestDome1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取请求方式:String getMethod()
        String method = request.getMethod();
        System.out.println("请求方式:"+method);
        System.out.println("---------------");
        //2.获取虚拟目录:String getContextPath()
        String contextPath = request.getContextPath();
        System.out.println("虚拟目录:"+contextPath);
        System.out.println("---------------");
        //3.获取Servlet路径:String getServletPath()
        String servletPath = request.getServletPath();
        System.out.println("Servlet路径"+servletPath);
        System.out.println("---------------");
        //4.获取get方式请求参数
        String queryString = request.getQueryString();
        System.out.println("get方式请求参数:"+queryString);
        System.out.println("---------------");
        //5.获取请求URI:String getRequestURI()
        //             StringBuffer getRequestURL()
        String requestURI = request.getRequestURI();
        String requestURL = request.getRequestURL().toString();
        System.out.println("请求URI"+requestURI);
        System.out.println("请求URI"+requestURL);
        System.out.println("---------------");
        //6.获取协议及版本:String getProtocol()
        String protocol = request.getProtocol();
        System.out.println("协议及版本"+protocol);
        System.out.println("---------------");
        //7.获取客户机的IP地址:String getRemoteAddr()
        String remoteAddr = request.getRemoteAddr();
        System.out.println("客户机的IP地址"+remoteAddr);
        System.out.println("---------------");
    }
}
  1. 获取请求头数据
    • 方法:
    • (*)String getHeader(String name):通过请求头的名称获取请求头的值
    • Enumeration getHeaderNames():获取所有的请求头名称
package com.example.Request;

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.util.Enumeration;

@WebServlet(name = "RequestDome2", value = "/RequestDome2")
public class RequestDome2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Enumeration getHeaderNames():获取所有的请求头名称
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            //String getHeader(String name):通过请求头的名称获取请求头的值
            String value = request.getHeader(name);
            System.out.println(name + "---" + value);
        }
    }
}
  1. 获取请求体数据:

    • 请求体:只有POST请求方式,才有请求体,在请求体封装了POST请求的请求参数

    • 步骤:

      1. 获取流对象

        • BufferedReader getReader():获取字符输入流,只能操作字符数据
        package com.example.Request;
        
        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.BufferedReader;
        import java.io.IOException;
        
        @WebServlet(name = "RequestDome4", value = "/RequestDome4")
        public class RequestDome4 extends HttpServlet {
            @Override
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        
            @Override
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //BufferedReader getReader():获取字符输入流,只能操作字符数据
                BufferedReader reader = request.getReader();
                String line;
                while ((line = reader.readLine())!=null){
                    System.out.println(line);
                }
                reader.close();
            }
        }
        
        • ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
          • 在文件上传知识点后讲解
      2. 再从流对象中拿数据

16.4、request其他功能

16.4.1、获取请求参数通用方式

获取请求参数的通用方式:不论get还是po请求方式都可以使用下列方法来获取请求参数

String getParameter(String name):根据参数名称获取参数值 username=zs&password=123

String[] getParameterValues(String name):根据参数名称获取参数值的数组 hobby=xx&hobby=game

Enumeration getParameterNames():获取所有请求的参数名称

Map getParameterMap():获取所有参数的map集合

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<form action="/Servlet_war_exploded/RequestDome3" method="post">
 用户名:<input type="text" name="username">
  密码:<input type="text" name="password">
  <input type="checkbox" name="habby" value="game">游戏
  <input type="checkbox" name="habby" value="study">学习
  <input type="submit">
form>
body>
html>
package com.example.Request;

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.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet(name = "RequestDome3", value = "/RequestDome3")
public class RequestDome3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //String getParameter(String name):根据参数名称获取参数值
        String username = request.getParameter("username");
        System.out.println(username);
        System.out.println("---------");
        //String[] getParameterValues(String name):根据参数名称获取参数值的数组
        String[] habbies = request.getParameterValues("habby");
        for (String habby : habbies) {
            System.out.println(habby);
        }
        System.out.println("---------");
        //Enumeration getParameterNames():获取所有请求的参数名称
        Enumeration parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            String parameter = request.getParameter(name);
            System.out.println(name);
            System.out.println(parameter);
            System.out.println("---------");
        }
        //Map getParameterMap():获取所有参数的map集合
        Map parameterMap = request.getParameterMap();
        Set strings = parameterMap.keySet();
        for (String string : strings) {
            System.out.println(string);
            String[] values = parameterMap.get(string);
            for (String value : values) {
                System.out.println(value);
            }
            System.out.println("-----------");
        }
    }
}
  • 中文乱码问题:
    • get方式:tomcat 8 已经将get方式乱码问题解决了
    • post方式:会乱码
      • 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");

16.4.2、请求转发

请求转发:一种在服务器内部的资源跳转方式

  1. 步骤:
    1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDuspatcher(String path)
    2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest rrequest,ServletResponse response)
  2. 特点:
    1. 浏览器地址栏路径不发生变化
    2. 只能转发到当前服务器内部资源中
    3. 转发是一次请求

JavaWeb之Servlet_第10张图片

16.4.3、共享数据

域对象:一个有作用范围的对象,可以在范围内共享数据

request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

方法:

  1. void setAttribute(String name,Object obj):存储数据
  2. Object getAttribute(String name):通过键获取值
  3. void removeAttribute(String name):通过键移除键值对

JavaWeb之Servlet_第11张图片

16.4.4、获取ServletContext

ServletContext getServletContext()

16.4.5、用户登录

用户登录案例需求:

  1. 编写login.html登录页面

    username & password 两个输入框

  2. 使用Druid数据库连接池技术,操作mysql,day14数据库中user表

  3. 使用JdbcTemplate技术封装JDBC

  4. 登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您

  5. 登录失败跳转到FailServlet展示:登录失败,用户名或密码错误

分析:

JavaWeb之Servlet_第12张图片

login页面

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<form method="post" action="/Servlet_war_exploded/login">
  用户名:<input type="text" name="username"><br>
  密码:<input type="text" name="password"><br>
  <input type="submit">
form>
body>
html>

JDBC工具类

package com.example.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class DruidUtils {
    private static DataSource ds;
    static {
        //创建集合对象
        Properties properties = new Properties();
        //读取配置文件
        InputStream resourceAsStream = DruidUtils.class.getClassLoader().getResourceAsStream("Druid.properties");
        try {
            properties.load(resourceAsStream);
            try {
                ds = DruidDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取连接方法
    public static Connection getConnection()  {
        Connection connection = null;
        try {
            connection = ds.getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }
    //释放资源方法
    public static void close(Statement statement,Connection connection){
        if (statement!=null){
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    public static void close(ResultSet rs,Statement statement, Connection connection){
        if (rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement!=null){
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    //获取连接池对象
    public static DataSource getDataSource(){
        return ds;
    }
}

Dao层访问数据库

package com.example.Dao;

import com.example.domain.User;
import com.example.utils.DruidUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

public class userDao {
    //定义方法获取查询出的user对象
    public User getUser(User user){
        try {
            JdbcTemplate jdbcTemplate = new JdbcTemplate(DruidUtils.getDataSource());
            String sql = "select * from user where username = ? and password = ?";
            User user1 = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(User.class), user.getUsername(), user.getPassword());
            return user1;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}

LoginServlet获取数据调用数据层访问数据

package com.example.Request;

import com.example.Dao.userDao;
import com.example.domain.User;

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;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码格式
        req.setCharacterEncoding("utf-8");
        //获取数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //封装为一个对象
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        //调用方法查询数据
        userDao userDao = new userDao();
        User user1 = userDao.getUser(user);
        if (user1!=null){
            req.setAttribute("user",user1);
            req.getRequestDispatcher("/success").forward(req,resp);
        }else {
            req.getRequestDispatcher("/fail").forward(req,resp);
        }
    }
}

SuccessServlet接受共享数据响应信息

package com.example.Request;

import com.example.domain.User;

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;
@WebServlet("/success")
public class SuccessServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        User user = (User) req.getAttribute("user");
        resp.getWriter().print(user.getUsername()+"登录成功");
    }

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

FailServlet给出错误的提示信息

package com.example.Request;

import com.example.Servlet.HelloServlet;

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;

@WebServlet("/fail")
public class FailServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().print("登录失败");
    }
}

16.4.6、BeanUtils

BeanUtils工具类,简化数据封装

  • 用于封装JavaBean的
  1. JavaBean:标准的Java类

    1. 要求:
      1. 类必须被public修饰
      2. 必须变量空参的构造器
      3. 成员变量必须使用private修饰
      4. 提供公共setter和getter方法
    2. 功能:封装数据
  2. 概念:

    成员变量:

    属性:setter和getter方法截取后的产物

    例如:getUsername() --> Username --> username

  3. 方法:

    1. setProperty():设置指定变量名属性
    2. getProperty():获取指定变量名的值
    3. populate(Object obj,Map map):将map集合的键值对信息,封装到对应额JavaBean对象中

17、Response

17.1、Response功能介绍

功能:设置响应消息

  1. 设置响应行
    1. 格式:HTTP/1.1 200 ok
    2. 设置状态码:setStatus(int sc)
  2. 设置响应头:setHeader(String name,String value)
  3. 设置响应体:
    • 使用步骤:
      1. 获取输出流
        • 字符传输流:PrintWriter getWriter()
        • 字节输出流:ServletOutputStream getOutputStream()
      2. 使用输出流,将数据输出到客户端浏览器

17.2、重定向

重定向:资源跳转的方式

代码实现:

//1.设置状态码为302
response.setStatus(302);
//2.设置响应头localtion
response.setHeader("location","/day15/responseDemo2");

//简单的重定向方法
response.sendRedirect("/day15/responseDemo2");

重定向的特点:redirect

  1. 地址栏发生变化
  2. 重定向可以访问其他站点(服务器)的资源
  3. 重定向是两次请求。不能使用request对象来共享数据

转发的特点:forward

  1. 转发地址栏路径不变
  2. 转发只能访问当前服务器下的资源
  3. 转发是一次请求,可以使用request对象来共享数据

路径写法

  1. 路劲分类:
    1. 相对路径:通过相对路径不可以确定唯一资源
      • 如:./index.html
      • 不以/开头,以.开头路径
      • 规则:找到当前资源和目标资源之间的相对位置关系
        • ./:当前目录
        • ../:后退一级目录
    2. 绝对路径:通过绝对路径可以确定唯一资源

17.3、服务器输出字符数据到浏览器

步骤:

  1. 获取字符输出流
  2. 输出数据

注意:

  • 乱码问题:

    JavaWeb之Servlet_第13张图片

    1. Printwriter pw = response.getwriter(); 获取流的默认编码是ISO-8859-1
    2. 设置该流的默认编码
    3. 告诉浏览器响应体使用的编码
    //简单的形式,设置编码,是在获取流之前设置
    response.setContentType("text/html;charset=utf-8");
    
package com.example.Request;

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.BufferedReader;
import java.io.IOException;

@WebServlet(name = "RequestDome5", value = "/RequestDome5")
public class RequestDome5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //response.sendRedirect("/RequestDome4");
        response.getWriter().writer("模拟号");
    }
}

17.4、服务器输出字节数据到浏览器

步骤:

  1. 获取字节输出流
  2. 输出数据
package com.example.Request;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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.nio.charset.StandardCharsets;

@WebServlet(name = "RequestDome6", value = "/RequestDome6")
public class RequestDome6 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write("你好呀".getBytes("utf-8"));
    }
}

17.5、验证码

package com.example.Response;

import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/checkCodeServlet")
public class ResponseDome extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //宽度
        int width = 100;
        int height = 50;
        //创建对象,在内存中生成一个图片(验证码图片对象)
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //美化图片
        Graphics graphics = image.getGraphics();//画笔对象
        graphics.setColor(Color.PINK);
        graphics.fillRect(0,0,width,height);
        //画边框
        graphics.setColor(Color.blue);
        graphics.drawRect(0,0,width-1,height-1);
        //写验证码
        //定义验证码都有那些字符
        String s = "QWERTYUIOPASDFGHJKLZCXVBNMqwertyuiopasdfghjklzxcvbnm123456789";
        //创建随机数对象产生随机数作为角标获取字符串中的字符作为验证码
        Random r = new Random();
        for (int i = 1; i <=4; i++) {
            int index = r.nextInt(s.length());
            char c = s.charAt(index);
            graphics.drawString(c+"",width/5*i,height/2);
        }
        //画线
        graphics.setColor(Color.green);
        //生成坐标
        //画10条线循环10次
        for (int i = 0;i<10;i++){
            int w1 = r.nextInt(width);
            int w2 = r.nextInt(width);
            int h1 = r.nextInt(height);
            int h2 = r.nextInt(height);
            graphics.drawLine(w1,h1,w2,h2);
        }

        //将图片输出到页面
        ImageIO.write(image,"jpg",resp.getOutputStream());
    }
}
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
  <script>
    //点击图片就换一张
    window.onload = function (){
      //获取图片对象绑定单击事件
      let img = document.getElementById("img");
      img.onclick = function () {
        var date = new Date();
        let time = date.getTime();
        img.src = "/Servlet_war_exploded/checkCodeServlet?"+time;
      }
      //获取a标签的对象点击换一张图片
      let a = document.getElementById("code");
      a.onclick = function () {
        var date = new Date();
        let time = date.getTime();
        img.src = "/Servlet_war_exploded/checkCodeServlet?"+time;
      }
    }
  script>
head>
<body>
<img id="img" src="/Servlet_war_exploded/checkCodeServlet">
<a id="code" href="javascript:void(0)">看不清楚?换一张a>
body>
html>

18、ServletContext

18.1、ServletContext概述

概念:代表整个web应用,可以和程序的容器(服务器)来通信

获取:

  1. 通过request对象获取

    request.getServletContext();

  2. 通过HttpServlet获取

    this.getServletContext();

18.2、ServletContext功能

功能:

  1. 获取MIME类型:

    • MIME类型:在互联网通信过程中定义的一种文件数据类型
      • 格式:大类型/小类型 text/html image/jpeg
    • 获取:String getMimeType(String file);
  2. 域对象:共享数据

    1. setAttribute(String name,Object value):存储指定名称的数据
    2. getAttribute(String name):获取指定名称的数据
    3. removeAttribute(String name):删除指定名称的数据
    • ServletContext对象范围:所有用户所有请求的数据
  3. 获取文件的真实(服务器)路径

    1. 方法:String getRealPath(String path)
String b = context.getRealPath("/b.txt");//web目录下资源访问
System.out.println(b);

String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下资源访问
System.out.println(c);

String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下资源访问
System.out.println(a)

18.3、文件下载

文件下载需求:

  1. 页面显示超链接
  2. 点击超链接后弹出下载提示框
  3. 完成图片文件下载

分析:

  1. 超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。不满足需求
  2. 任何资源都必须弹出下载提示框
  3. 使用响应头设置资源的打开方式:
    • content-disposition:attachment;filename=xxx

步骤:

  1. 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
  2. 定义Servlet
    1. 获取文件名称
    2. 使用字节输入流加载文件进内存
    3. 指定response的响应头:content-disposition:attachment;filename=xxx
    4. 将数据写出到response输出流

问题:中文文件问题

  • 解决思路:
    1. 获取客户端使用的浏览器版本信息
    2. 根据不同的版本信息,设置filename的编码方式不同
package com.example.Response;

import com.example.utils.DownLoadUtils;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/fileServlet")
public class ResponseDome2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取文件名称
        String filename = req.getParameter("filename");
        //获取文件真实路径
        String realPath = this.getServletContext().getRealPath("/img/" + filename);
        String header = req.getHeader("user-agent");
        filename = DownLoadUtils.getFileName(header, filename);
        //创建字节输入流读数据
        FileInputStream fileInputStream = new FileInputStream(realPath);
        //获取字节输出流
        ServletOutputStream outputStream = resp.getOutputStream();
        //获取文件类型
        String mimeType = this.getServletContext().getMimeType(filename);
        //设置响应头
        resp.setHeader("content-type",mimeType);
        resp.setHeader("content-disposition","attachment;filename="+filename);
        //读取数据到页面
        byte[] bytes = new byte[1024];
        int len;
        while ((len=fileInputStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
        }
        fileInputStream.close();
    }
}

19、会话技术

19.1、会话技术概述

会话技术:一次会话中包含多次请求和响应

  • 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止

功能:在一次会话的范围内的多次请求间,共享数据

方式:

  1. 客户端会话技术:Cookie
  2. 服务器端会话技术:Session

JavaWeb之Servlet_第14张图片

19.2、Cookie

19.2.1、Cookie概述

概念:客户端会话技术,将数据保存到客户端

JavaWeb之Servlet_第15张图片

19.2.2、Cookie快速入门

使用步骤:

  1. 创建Cookie对象,绑定数据
    • new Cookie(String name,String value)
  2. 发送Cookie对象
    • response.addCookie(Cookie cookie)
  3. 获取Cookie,拿到数据
    • Cookie[] request.getCookies()
package com.example.Cookie;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/cookieDome1")
public class CookieDome extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //创建Cookie对象
        Cookie cookie = new Cookie("username","zhangsan");
        //发送Cookie
        resp.addCookie(cookie);
    }
}
package com.example.Cookie;

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

@WebServlet("/cookieDome2")
public class CookieDome2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取Cookie
        Cookie[] cookies = req.getCookies();
        //遍历Cookie
        if(cookies!=null){
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                String value = cookie.getValue();
                System.out.println(name + "---" + value);
            }
        }
    }
}

19.2.3、Cookie实现原理

实现原理:

  • 基于响应头set-cookie和请求头cookie实现

JavaWeb之Servlet_第16张图片

19.2.4、cookie的细节

  1. 一次可不可以发送多个cookie?
    • 可以
    • 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可
  2. cookie在浏览器中保存多长时间?
    1. 默认情况下,当浏览器关闭后,Cookie数据被销毁
    2. 持久化存储:
      • setMaxAge(int seconds)
        1. 正数:将Cookie数据写到硬盘的文件中。持久化存储。cookie存活时间。
        2. 负数:默认值
        3. 零:删除cookie信息
    3. cookie能不能存中文?
      • 在tomcat 8 之前 cookie中不能直接存储中文数据
        • 需要将中文数据转码—一般采用URL编码(%E3)
      • 在tomcat 8 之后,Cookie支持中文数据,特殊字符还是不支持,建议使用URL编码存储,URL解码解析
    4. cookie共享问题?
      1. 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
        • 默认情况下cookie不能共享
        • setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
          • 如果要共享,则可以将path设置为"/"
      2. 不同的tomcat服务器间cookie共享问题?
        • setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
          • setDomain(".baidu.com"),那么tieba.baidu.comnews.baidu.com中cookie可以共享

19.2.5、Cookie的特点和作用

  1. cookie存储数据在客户端浏览器
  2. 浏览器对于单个cookie 的大小有限制(4kb)以及对同一个域名下的总cookie数量也有限制(20个)
  • 作用:
    1. cookie一般用于存储少量的不敏感的数据
    2. 在不登录的情况下,完成服务器对客户端的身份识别

19.2.6、记住上一次访问时间案例

需求:

  1. 访问一个Servlet,如果是第一次访问,则提示:“您好,欢迎您首次访问”
  2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串

分析:

  1. 可以采用Cookie来完成
  2. 在服务器中的Servlet判断是否有一个名为lastTime的cookie
    1. 有:不是第一次访问
      1. 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
      2. 写回Cookie:lastTime=2018年6月10日11:50:01
    2. 没有:是第一次访问
      1. 响应数据:您好,欢迎您首次访问
      2. 写回Cookie:lastTime=2018年6月10日11:50:01
package com.example.Cookie;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;

@WebServlet("/cookieDome3")
public class CookieDome3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        //获取cookie
        Cookie[] cookies = req.getCookies();
        boolean flag = false;
        //遍历cookie
        if (cookies!=null){
            for (Cookie cookie : cookies) {
                //获取cookie的名称进行比较
                String name = cookie.getName();
                if ("lastTime".equals(name)){
                    flag=true;
                    //给cookie重新赋值
                    Date date = new Date();
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String format = simpleDateFormat.format(date);
                    //编码
                    String encode = URLEncoder.encode(format, "utf-8");
                    cookie.setValue(encode);
                    resp.addCookie(cookie);
                    //解码
                    String decode = URLDecoder.decode(cookie.getValue(), "utf-8");
                    resp.getWriter().write("您上次访问时间为"+decode);
                }
            }
        }
        if (cookies==null||cookies.length<=0||flag==false){
            Date date = new Date();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String format = simpleDateFormat.format(date);
            //编码
            String encode = URLEncoder.encode(format, "utf-8");
            Cookie cookie = new Cookie("lastTime",encode);
            resp.addCookie(cookie);
            resp.getWriter().write("您好,欢迎您首次访问");
        }
    }
}

19.3、Session

19.3.1、Session概述

概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession

19.3.2、Session快速入门

获取HttpSession对象:

HttpSession session = request.getSession();

使用HttpSession对象:

Object getAttribute(String name)存储指定名称的数据

void setAttribute(String name,Object value)获取指定名称的数据

void removeAttribute(String name)删除指定名称的数据

19.3.3、Session原理

Session的实现是依赖于Cookie的

JavaWeb之Servlet_第17张图片

19.3.4、Session细节

  1. 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?

    • 默认情况下。不是

    • 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存

      Cookie c = new Cookie("JSESSIONID",session.getId());
      c.setMaxAge(60*60);
      response.addCookie(c);
      
  2. 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?

    • 不是同一个,但是要确保数据不丢失
      • session的钝化:
        • 在服务器正常关闭之前,将session对象序列化到硬盘上
      • session的活化:
        • 在服务器启动后,将session文件转化为内存中的session对象即可
  3. session什么时候被销毁?

    1. 服务器关闭

    2. session对象调用invalidate()

    3. session默认失效时间 30分钟

      选择性配置修改
      <session-config>
          <session-timeout>30session-timeout>
      session-config>
      

19.3.5、Session的特点

session用于存储一次会话的多次请求的数据,存在服务器端

session可以存储任意类型,任意大小的数据

  • session与Cookie的区别:
    1. session存储数据在服务器端,Cookie在客户端
    2. session没有数据大小限制,Cookie有
    3. session数据安全,Cookie相对于不安全

19.3.6、验证码

案例需求:

  1. 访问带有验证码的登录页面login.jsp
  2. 用户输入用户名,密码以及验证码
    • 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
    • 如果验证码输入有误,跳转登录页面,提示:验证码错误
    • 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您

分析:

JavaWeb之Servlet_第18张图片

代码实现:

  1. login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    login
    


/loginServlet method="post">
    用户名:
密码:
验证码:
/checkCodeServlet>
<%=request.getAttribute("mag")==null?"":request.getAttribute("mag")%>
  1. loginServlet代码实现
package com.example.session;

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 javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码格式
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //获取数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String code = req.getParameter("code");
        //获取session中的数据
        HttpSession session = req.getSession();
        String yzm = (String) session.getAttribute("yzm");
        session.removeAttribute("yzm");
        //判断验证码是否正确
        if (yzm!=null&&yzm.equalsIgnoreCase(code)){
            //判断用户名或密码是否正确
            if ("zhangsan".equals(username)&&"123".equals(password)){
                //存储用户名数据
                session.setAttribute("username",username);
                resp.sendRedirect(req.getContextPath()+"/success.jsp");
            }else{
                //存储数据并转发到页面
                req.setAttribute("mag","用户名或密码错误");
                req.getRequestDispatcher("/login.jsp").forward(req,resp);
            }
        }else {
            //存储数据并转发到页面
            req.setAttribute("mag","验证码错误");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }
    }
}
  1. 登录成功页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


<%=request.getSession().getAttribute("username")%>,欢迎您

你可能感兴趣的:(servlet,java)