Servlet

前言

开发工具专栏
上篇接tomcat

历史简单篇tomcat,servlet

1 Servlet简介

Servlet介绍
Servlet是Server Applet的简称,称为服务端小程序,是JavaEE平台下的技术标准,基于Java语言编写的服务端程序。Web容器或应用服务器实现了Servlet标准所以Servlet需运行在Web容器或应用服务器中。Servlet主要功能在于能在服务器中执行并生成数据。

Servlet技术特点
Servlet使用单进程多线程方式运行。
在这里插入图片描述

Servlet在应用程序中的位置
两个图来展示,帮助我们理解
在这里插入图片描述
在这里插入图片描述

静态资源和动态资源区分
静态资源:每次访问都不需要运算,直接就可以返回的资源,如HTML CSS JS多媒体文件等等,每次访问获得的资源都是一样的
动态资源:每次访问都需要运算代码生成的资源,如Servlet JSP ,每次访问获得的结果可能都是不一样的
Servlet作为一种动态资源技术,是我们后续学习框架的基础

Servlet在程序中到底处于一个什么地位?
Servlet是可以接受Http请求并作出相应的一种技术,是JAVA语言编写的一种动态资源
Servlet是前后端衔接的一种技术,不是所有的JAVA类都可以接收请求和作出相应,Servlet可以
在MVC模式中,Servlet作为Controller层(控制层)主要技术,用于和浏览器完成数据交互,控制交互逻辑

2 Servlet初识

2.1 Servlet开发流程

案例:

在后台随机生成一个整数当浏览器请求一个Servlet时 如果生成的是奇数,返回"happy new year"如果生成的是偶数,返回"happy birthday"

1创建一个JAVAWEB项目,并在项目中开发一个自己的Servlet ,继承HttpServlet类
在这里插入图片描述
一定要查看External Libraries中有Tomcat中的两个JAR jsp-api servlet-api

2在MyServlet类中重写service方法
在这里插入图片描述

在这里插入图片描述
如果我们想获得请求中的信息,就要通过HttpServetRequest对象获得
如果我们想给浏览器响应一些信息,就要通过HttpServletResponse对象响应

3在service方法中定义具体的功能代码
在这里插入图片描述

4在web.xml中配置Servlet的映射路径
在这里插入图片描述
上述图片我们设置的访问路径为localhost:/xxx

2.2 配置欢迎页

当我们访问项目名的时候为什么默认访问的是index.html呢?我们找到tomcat目录下conf/web.xml文件最后面可以看到,他帮我默认配置了输入了项目名访问的路径
在这里插入图片描述
假如我们想自定义默认路径可以在项目中的web.xml文件中进行配置
查找顺序是从上往下进行查找
在这里插入图片描述

3 Servlet案例开发!

案例开发需求
准备一个登录页,可以输入用户名和密码
输入完毕后向后台Servlet提交用户名和密码
Servlet接收到用户名和密码之后,校验是否正确
如果正确响应Success
如果不正确响应Fail

开发过程如下

3.1 开发登录页

在webapp文件夹下创建login.xml

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="get" action="loginServlet.do">
    <table style="margin: 0px auto" width="300px" cellpadding="0px" cellspacing="0px" border="1px">
        <tr><td>用户名</td><td><input type="text" name="username"></td></tr>
        <tr><td>密码</td><td><input type="password" name="pwd"></td></tr>
        <tr align="center"><td colspan="2"><input type="submit" value="登录"></td></tr>
    </table>
</form>
</body>
</html>

我们在web.xml文件中配置login.xml为根目录

    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>

3.2 开发后台Servlet

创建LoginServlet 类继承HttpServlet并重写service方法

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import java.io.IOException;

public class LoginServlet extends HttpServlet {
    @Override
    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.err.println("进入了servlet");
        //获取请求中的数据
        String username = req.getParameter("username");
        String pwd = req.getParameter("pwd");
        //判断数据
        String message = null;
        if(username.equals("123") && pwd.equals("123")){
            message = "Success";
        }else{
            message = "Fail";
        }
        //作出响应
        resp.getWriter().write(message);
    }
}

3.3 配置Servlet

from表单中的action属性需要配置访问路径
我们在web.xml中配置LoginServlet 访问路径"/loginServlet.do"

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>com.msr.demo_servlet.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <url-pattern>/loginServlet.do</url-pattern>
    </servlet-mapping>


    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
</web-app>

运行测试
http://localhost:9008/demo_servlet_war_exploded/

4 HttpServletRequest

4.1 回顾http请求

在这里插入图片描述
请求行
在这里插入图片描述
请求头
在这里插入图片描述
请求体

get方式提交的请求数据通过地址栏提交没有请求体
post方式提交请求数据单独放到请求体中,
请求时所携带的数据(post方式)

http支持的请求方式
在这里插入图片描述

post和get方式提交请求的差别(面试重要)

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行ur编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST则没有。对参数的数据类型GET只接受ASCI字符,而POST即可是字符也可是字节。
  • GETE比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中。

4.2 自定义servlet流程图

在这里插入图片描述

4.3 HttpServletRequest

HttpServletRequest对象代表客户端浏览器的请求,当客户端浏览器通过HTTP协议访问服务器时,HTTP请求中的所有信息都
会被Tomcat所解析并封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。

请求数据
在这里插入图片描述

4.4获取请求行信息

测试代码

System.out.println("完整的URL:"+req.getRequestURL());//返回客户端浏览器发出请求时的完整URL。
System.out.println("请求的指定资源:"+req.getRequestURI());//返回请求行中指定资源部分。
System.out.println("客户端的IP:"+req.getRemoteAddr());//返回发出清求的客户机的IP地址。
System.out.println("WEB服务器IP:"+req.getLocalAddr());//返回WEB服务器的IP地址。
System.out.println("服务器端处理HTTP请求的端口:"+req.getLocalPort());//返回WEB服务器处理Http协议的连接器所监听的端口。
System.out.println("主机名:"+req.getLocalName());
System.out.println("客户端PORT:"+req.getRemotePort());
System.out.println("当前项目部署名:"+req.getContextPath());
System.out.println("协议名:"+req.getScheme());
System.out.println("请求方式:"+req.getMethod());

打印结果

完整的URL:http://localhost:9008/demo_servlet_war_exploded/loginServlet.do
请求的指定资源:/demo_servlet_war_exploded/loginServlet.do
客户端的IP:0:0:0:0:0:0:0:1
WEB服务器IP:0:0:0:0:0:0:0:1
服务器端处理HTTP请求的端口:9008
主机名:0:0:0:0:0:0:0:1
客户端PORT:49648
当前项目部署名:/demo_servlet_war_exploded
协议名:http
请求方式:GET

4.5获取请求头信息

测试代码

String headerValue = req.getHeader("accept-encoding");//根据请求头中的key获取对应的value。
System.out.println(headerValue);
//早期的Iterator
Enumeration<String> headerNames = req.getHeaderNames();//获取请求头中所有的key,该方法返回枚举类型。
while(headerNames.hasMoreElements()){
	String headerName = headerNames.nextElement();
	System.out.println(headerName+":"+req.getHeader(headerName));
	}

打印结果

gzip, deflate, br
host:localhost:9008
connection:keep-alive
pragma:no-cache
cache-control:no-cache
sec-ch-ua:"Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
sec-ch-ua-mobile:?0
sec-ch-ua-platform:"Windows"
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
sec-fetch-site:same-origin
sec-fetch-mode:navigate
sec-fetch-user:?1
sec-fetch-dest:document
referer:http://localhost:9008/demo_servlet_war_exploded/
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9
进入了servlet

4.6获取请求数据

在Servlet获取请求数据的方式
req.getParameter(“key” );//根据key获取指定value。
String str = req.getParameter(“key”);
获取复选框(checkbox组件)中的值
eq.getParameterValues("checkboxkey );//获取复选框(checkbox组件)中的值,返回- -个String[I。
String[] userlikes = req.getParameterValues(“checkboxkey”);
获取所有提交数据的key
req.getParameterNames0);//获取请求中所有数据的key,该方法返回一个枚举类型。
Enumeration parameterNames = req.getParameterNames()
使用Map结构获取提交数据
req.getParameterMap0://获取请求中所有的数据并存放到一 个Map结构中,该方法返回一个Map,其中key为String类
型value为String[]类型。
Map<String, String[]> parameterMap = req.getParameterMap(;
设置请求编码
req.setCharacterEncoding(“utf-8”)
请求的数据包基于字节在网络上传输,Tomcat接收到请求的数据包后会将数据包中的字节转换为字符。在Tomcat中使用的
是ISO-8859-1的单字节编码完成字节与字符的转换,所以数据中含有中文就会出现乱码,可以通req.setCharacterEncoding(“utf-8” )方法来对提交的数据根据指定的编码方式重新做编码处理。

测试代码
前段

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
开发form表单注意事项
1.form 不是from
2.form表单内部不是所有的标签信息都会提交  一些输入信息 input  select  textarea ...
3.要提交的标签必须具备name属性 name属性的作用是让后台区分数据 id属性是便于在前端区分数据
4.要提交的标签一般都要具备value属性 value属性确定我们要提交的具体的数据
5.get  post
    get方式数据是通过URL携带
     提交的数据只能是文本
     提交的数据量不大
     get方式提交的数据相对不安全
    post 将数据单独打包方法请求体中
     提交的数据可以是文本可以是各种文件
     提交的数据量理论上没有上线
     post方式提交数据相对安全

    当一个表单标签
    readonly只读 也是会提交数据的
    hidden隐藏 也是会提交数据
    disabled不可用 显示但是不提交
-->
<form method="get" action="myServlet">
    <table style="margin: 0px auto" width="300px" cellpadding="0px" cellspacing="0px" border="1px">
        <tr><td>用户名</td><td><input type="text" name="username"></td></tr>
        <tr><td>密码</td><td><input type="password" name="pwd"></td></tr>
        <tr><td>性别</td>
            <td><input type="radio" name="gender" value="1" checked><input type="radio" name="gender" value="0">
            </td>
        </tr>
        <tr><td>爱好</td>
            <td>
                <input type="checkbox" name="hobby" value="1">篮球
                <input type="checkbox" name="hobby" value="2">足球
                <input type="checkbox" name="hobby" value="3">羽毛球
                <input type="checkbox" name="hobby" value="4">乒乓球
            </td>
        </tr>
        <tr><td>个人简介</td>
            <td>
                <!--文本域 双标签 页面上显示的文字是双标签中的文本  不是value属性

                文本域提交的数据不是value属性值,是双标签中的文本
                -->
                <textarea name="introduce"></textarea>
            </td>
        </tr>
        <tr>
            <td>籍贯</td>
            <td>
                <select name="provience">
                    <option value="1"></option>
                    <option value="2"></option>
                    <option value="3"></option>
                </select>
            </td>
        </tr>
        <tr align="center"><td colspan="2"><input type="submit" value="提交数据"></td></tr>
    </table>
</form>
</body>
</html>

web.html

    <servlet>
        <servlet-name>myServlet</servlet-name>
        <servlet-class>com.msr.demo_servlet.servlet.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>myServlet</servlet-name>
        <url-pattern>/myServlet</url-pattern>
    </servlet-mapping>

后端

public class MyServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // req获取参数
        //如果前端发过米的数据由教构名但是没有值,getParameter 返回的是一个空字符申 ""
        //获取的参数在提交的数据中名都没有,getParameter返回的是null
        String username = req.getParameter("username");
        System.out.println("username:"+username);
        System.out.println("password:"+req.getParameter("pwd"));
        System.out.println("gender:"+req.getParameter("gender"));
        //hobby=1&hobby=2&hobby=3 想要获得多个同名的参数 getParameterValues返回的是一个String数组
        //获取的参数在提交的数据中名都没有,getParameterValues返回的是null
        String[] hobbies = req.getParameterValues("hobby");
        System.out.println("hobbies:"+ Arrays.toString(hobbies));
        //textarea
        System.out.println("introduce:"+req.getParameter("introduce"));
        //select
        System.out.println("provience:"+req.getParameter("provience"));
        System.out.println("-----------------------------------------");
        //如果不知道参数的名字?
        //获取所有的参数名
        Enumeration<String> parameterNames = req.getParameterNames();
        while (parameterNames.hasMoreElements()){
            String pname = parameterNames.nextElement();
            String[] parameterValues = req.getParameterValues(pname);
            System.out.println(pname+":"+Arrays.toString(parameterValues));
        }
        System.out.println("---------------------------------------");
        Map<String, String[]> parameterMap = req.getParameterMap();
        Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
        for (Map.Entry<String, String[]> entry : entries) {
            System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue()));
        }
    }
}

输出

username:aaa
password:123
gender:1
hobbies:[1, 2, 3]
introduce:111
provience:2
-----------------------------------------
username:[aaa]
pwd:[123]
gender:[1]
hobby:[1, 2, 3]
introduce:[111]
provience:[2]
---------------------------------------
username:[aaa]
pwd:[123]
gender:[1]
hobby:[1, 2, 3]
introduce:[111]
provience:[2]

5 HttpServletResponse

5.1回顾http响应

http响应部分可以分为三部分:响应行,响应头,响应体
在这里插入图片描述

响应行
在这里插入图片描述
响应状态码列表如下
在这里插入图片描述
响应头
Content-Type:响应内容的类型(MIME)
在这里插入图片描述响应实体
服务器响应回来的内容

5.2HttpServletResponse

HttpServletResponse对象代表服务器的响应。这个对象中封装了响应客户端浏览器的流对象,以及向客户端浏览器响应的响应头、响应数据、响应状态码等信息。

响应的设置

ContentType响应头

resp.setContentType(“MIME”);//该方法可通过MIME-Type设置响应类型。
MIME的全称是Multipurpose Internet Mail Extensions,即多用途互联网邮件扩展类型。
这是HTTP协议中用来定义文档性质及格式的标准。对HTTP传输内容类型进行了全面定义。
服务器通过MIME告知响应内容类型,而浏览器则通过MIME类型来确定如何处理文档。

代码

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //行相关信息
        resp.setStatus(500);
        //头相关信息
        resp.setHeader("Date","2022-2-2");
        resp.setHeader("aaa","xxx");
        //Content-Type响应头 响应给浏览器的MIME类型
        // 如果想知道都可以响应什么类型可以去tomcat的web.xml文件中查看 大概650行开始,有很多
        resp.setHeader("Content-Type","text/html");
        //体相关信息
        PrintWriter writer = resp.getWriter();
        writer.write("<h1>this is tag h1<h1/>");
    }

在这里插入图片描述

6 关于乱码问题

6.1控制台乱码

tomcat有三个打印日志的地方
Server乱码
在这里插入图片描述
修改
找到tomcat中的日志配置文件编码改为GBK
在这里插入图片描述

如果其他两个日志也是乱码
在这里插入图片描述
修改为GBK
在这里插入图片描述

6.2post请求乱码

通过HttpServletRequest设置请求编码
在这里插入图片描述

6.3get请求乱码

需要手动进行编码解码,或者设置tomcat中的server.xml中的URL编码,tomcat9已经解决了该问题
在这里插入图片描述

6.4响应乱码

通过HttpServletResponse设置响应编码
在这里插入图片描述

7 Servlet的继承结构

在这里插入图片描述

7.1 Servlet接口

1.init(),创建Servlet对象后立即调用该方法完成其他初始化工作。
2.getServletConfig(),ServletConfig是容器向servlet传递参数的载体。
3.service(),处理客户端请求,执行业务操作,利用响应对象响应客户端请求。
4.getServletlnfo(),获取servlet相关信息
5.destroy(),在销毁Servlet对象之前调用该方法,释放资源。

7.2 ServletConfig接口

Servlet运行期间,需要一些辅助信息,这些信息可以在web.xml文件中,使用一个或多个元素,进行配置。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息,封装到一个ServletConfig对象中,通过调用init(ServletConfig config)方法,将ServletConfig对称传递给Servlet

7.3 GenericServlet抽象类

GenericServlet是实现了Servlet接口的抽象类。在GenericServlet中进一步的定义了Servlet接口的具体实现,其设计的目的是为了和应用层协议解耦,在GenericServlet中包含一个Service抽象方法。我们也可以通过继承GenericServlet并实现Service方法实现请求的处理,但是需要将ServletReuqest和ServletResponse转为HttpServletRequest和HttpServletResponse。

7.4 HttpServlet

继承自GercSenvlt.针对于处理HTP协议的青求所定制。在Httpendeb的sevcel)方法中已经把Se veReucet和Se verRspone转为HtperveBleuest和Htpservrtrkesponse。直按使甲用HtoSenveEkeqest和HttpServletResponse,不再需要强转。实际开发中,直接继承HttpServlet,并根据请求方式复写doXx()方法即可。
在这里插入图片描述

在这里插入图片描述
在我们自定义的Servlet中,如果想区分请求方式不同的请求方式使用不同的代码处理,那么我么重写doGet doPost即可如果我们没有必要区分请求方式的差异,那么我们直接重写service方法即可

8 Servlet的生命周期

Servlet的生命周期是由容器管理的,分别经历四各阶段:

>阶段            次数     时机
>创建		     1次      第一次请求
>初始化          1次      实例化之后 
>执行服务        多次      每次请求
>销毁            一次     停止服务

在这里插入图片描述

当客户端浏览器第一次请求Servlet时,容器会实例化这个Servlet,然后调用一次init方法,并在新的线程中执行service方法处理请
求。service方法执行完毕后容器不会销毁这个Servlet而是做缓存处理,当客户端浏览器再次请求这个Servlet时,容器会从缓存中直接找到这个Servlet对象,并再一次在新的线程中执行Service方法。当容器在销毁Servlet之前对调用一次destory方法。

注意:
在Serlvet中我们一般不要轻易使用成员变量!!! 可能会造成线程安全问题
如果要使用的话,应该尽量避免对成员变量产生影响修改
如果要产生影响我们应该注意线程安全问题
如果我们自己添加线程安全编码处理,会严重影响效率
综上所述:原则,能不用成员变量就不用!!!

8.1 初始化时间问题

假如servlet的初始化时间比较长,这就会导致我们第一次访问页面的时候会等待较长的时间,这样我们可以在web.xml文件中配置servlet自动初始化,这样他就会在tomcat启动的时候进行初始化

设置初始化顺序从6开始,前五个被tomcat使用了

<servlet>
	<servlet-name>myServlet</servlet-name>
	<servlet-class>com.msr.demo_servlet.servlet.MyServlet</servlet-class>
	<load-on-startup>6</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>myServlet</servlet-name>
	<url-pattern>/myServlet</url-pattern>
</servlet-mapping>

9 ServletContext和servletConfig

9.1 ServletContext 重要

ServletContext官方叫Servlet上下文。服务器会为每一个Web应用创建一个ServletContext对象。这个对象全局唯一,而且Web应用中的所有Servlet都共享这个对象。所以叫全局应用程序共享对象
在这里插入图片描述

9.1.1 ServletContext对象的作用

  • 相对路径转绝对路径
  • 获取容器的附加信息
  • 读取配置信息
  • 全局容器

9.1.2 ServletContext对象的使用

9.1.2.1 基本使用

获取项目的部署名
context.getContextPath()
相对路径转绝对路径(文件上传下载时需要注意)
context.getRealPath(“path”)
该方法可以将一个相对路径转换为绝对路径,在文件上传与下载时需要用到该方法做路径的转换。获取容器的附加信息
servletContext.getServerlnfo()
返回Servlet容器的名称和版本号
servletContext.getMajorVersion()
返回Servlet容器所支持Servlet的主版本号servletContext.getMinorVersion()
返回Servlet容器所支持Servlet的副版本号。

代码

public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //获取Servlet对象的方式
        //通过req对象
        ServletContext servletContext1 = req.getServletContext();
        //通过继承的方式
        ServletContext servletContext2 = this.getServletContext();
        System.out.println(servletContext1 ==servletContext2);

        //获取当前项目的部署名
        String contextPath= servletContext1.getContextPath();
        System.out.println("contextPath"+contextPath);
		//将一个相对路径转化为项目的绝对路径
        String fileupload = servletContext1.getRealPath( "fileupload");
        System.out.println(fileupload);
        String serverInfo = servletContext1.getServerInfo();
        System.out.println( "servletInfo"+serverInfo);
        int majorversion = servletContext1.getMajorVersion();
        int minorVersion = servletContext1.getMinorVersion();
        System.out. println(majorversion+":"+minorVersion);
	}
}

输出

true
contextPath/demo_servlet_war_exploded
D:\word\demo_servlet\target\demo_servlet-1.0-SNAPSHOT\fileupload
servletInfoApache Tomcat/8.5.45
3:1

web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>Servlet1</servlet-name>
        <servlet-class>com.msr.demo_servlet.servlet.Servlet1</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Servlet1</servlet-name>
        <url-pattern>/servlet1.do</url-pattern>
    </servlet-mapping>
</web-app>

9.1.2.2 获取web.xml文件中的信息

在这里插入图片描述
servletContext.getlnitParameter(“key”)
该方法可以读取web.xml文件中标签中的配置信息。servletContext.getInitParameterNames()
该方法可以读取web.xml文件中所有param-name标签中的值。

在web.xml中设置共享的数据

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>username</param-name>
        <param-value>123</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>456</param-value>
    </context-param>
</web-app>

通过servletContext获取web.xml中的数据
web.xml中数据会保存到ServletContext ,通过HttpServletRequest可以拿到上下文对象ServletContext

public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	ServletContext servletContext1 = req.getServletContext();
        String username = servletContext1.getInitParameter("username");
        String password = servletContext1.getInitParameter("password");
        System.out.println(username+":"+password);
        }
}

9.1.2.3全局容器

servletContext.setAttribute(“key” ,ObjectValue)向全局容器中存放数据。
servletContext.getAttribute(“key”)从全局容器中获取数据。
servletContext.removeAttribute(“key”)根据key删除全局容器中的value。

ArrayList<Object> data = new ArrayList<>();
Collections.addAll(data,"张三","李四","王五");
servletContext1.setAttribute("list",data);

然后可以通过不同的servlet进行读取

ServletContext servletContext2 = req.getServletContext();
String username = servletContext2.getInitParameter("username");
String password = servletContext2.getInitParameter("password");
System.out.println(username+":"+password);

List<String> list =(List<String>) servletContext2.getAttribute("list");
System.out.println(list);

9.2 SerlvetConfig对象

ServletConfig对象对应web.xml文件中的节点。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息,封个ServletConfia对象中。我们可以通过该对象读取节点中的配置信息
在这里插入图片描述
servletConfig.getlnitParameter(“key”);
该方法可以读取web.xml文件中标签中标签中的配置信息。servletConfig.getInitParameterNames();
该方法可以读取web.xml文件中当前标签中所有标签中的值。
web.xml文件

在这里插入图片描述
测试代码

 @Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	ServletConfig servletConfig = this.getServletConfig();       
	System.out.println(servletConfig.getInitParameter("brand"));
}

10 ur-pattern的匹配规则

10.1 精确匹配

精确匹配是指<url-pattern>中配置的值必须与url完全精确匹配。

在这里插入图片描述
http://localhost:8080/demo/demo.do 匹配
http://localhost:8080/demo/suibian/demo.do 不匹配

10.2 扩展名匹配

在允许使用统配符“”作为匹配规则,“”表示匹配任意字符。在扩展名匹配中只要扩展名相同都会被匹配和路径无关。注意,在使用扩展名匹配时在中不能使用“r”,否则容器启动就会抛出异常。
在这里插入图片描述
http://localhost:8080/demo/demo.do 匹配
http://localhost:8080/demo/suibian/demo.do 匹配

10.3 路径匹配

根据请求路径进行匹配,在请求中只要包含该路径都匹配。"*"表示任意路径以及子路径。
在这里插入图片描述
http://localhost:8080/demo/suibian/demo.do 匹配
http://localhost:8080/demo/suibian/hehe/demo.do 匹配
http://localhost:8080/demo/hehe/demo.do 不匹配

10.4 任意匹配

匹配"/".匹配所有但不包含JSP页面
在这里插入图片描述
http://localhost:8080/demo/suibian.do 匹配
http://localhost:8080/demo/suibian.html 匹配
http://localhost:8080/demo/123/suibian.css 匹配
http://localhost:8080/demo/123/suibian.jsp 不匹配

10.5 匹配所有

在这里插入图片描述
http://localhost:8080/demo/suibian.do 匹配
http://localhost:8080/demo/suibian.html 匹配
http://localhost:8080/demo/123/suibian.css 匹配
http://localhost:8080/demo/123/suibian.jsp 匹配

10.6 优先顺序

当一个url与多个Servlet的匹配规则可以匹配时,则按照“精确路径>最长路径>扩展名”这样的优先级匹配到对应的Servlet。
案例分析
在这里插入图片描述

10.7 URL映射方式

在这里插入图片描述
方式一
在这里插入图片描述
方式二
在这里插入图片描述

11 注解模式开发Servlet

这里不做过多解释(与目录9.ServletContext和servletConfig原理一样)

//@WebServlet(urlPatterns = "Servlet1.do")
@WebServlet(urlPatterns = {"Servlet1.do","12.do"},
        	loadOnStartup = 6,
        	initParams = {@WebInitParam(name = "brand1",value = "123"),
                      	  @WebInitParam(name = "brand2",value = "321")
                     })
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

12 请求转发

12.1 forword处理流程

1清空Response存放响应正文数据的缓冲区。
2如果目标资源为Servlet或JSP,就调用它们的service()方法,把该方法产生的响应结果发送到客户端;如果目标资源文件系统中的静态HTML文档,就读取文档中的数据把它发送到客户端。
在这里插入图片描述
forword处理特点:
1由于forword()方法先清空用于存放响应正文的缓冲区,因此源Servlet生成的响应结果不会被发送到客户端,只有目标资源生成的响应结果才会被发送到客户端。
2如果源Servlet在进行请求转发之前,已经提交了响应结(flushBuffer(),close()方法),那么forward()方法抛出lllegalStateException。为了避免该异常,不应该在源Servlet中提交响应结果。

代码

Servlet1

@WebServlet(name = "servlet1", value = "/servlet1.do")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet1.do");
        String money = req.getParameter("money");
        System.out.println("money:"+money);

        resp.getWriter().println("asdasd");//响应无效 后边进行了转发

        //请求转发给另一个组件
        //获取请求转发器
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("servlet2.do");
        //由请求转发器作出转发
        requestDispatcher.forward(req,resp);

//在forward转发模式下,请求应该完全交给目标资源去处理,我们在源组件中,不要作出任何的响应处理
//在forward方法调用之后,也不要在使用req和resp对象做其他操作了
    }
}

Servlet2

@WebServlet(name = "servlet2", value = "/servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet2.do");

        String money = req.getParameter("money");
        System.out.println("money:"+money);

        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        PrintWriter writer = resp.getWriter();
        writer.println("支付宝到账:"+money+"元");
    }

}

访问接口:http://localhost:9008/demo_servlet_war_exploded/servlet1.do?money=100

12.2 include处理流程

1如果目标资源为Servlet或JSP,就调用他们的相应的service()方法,把该方法产生的响应正文添加到源Servlet的响应结果中;如果目标组件为HTML文档,就直接把文档的内容添加到源Servlet的响应结果中。
2返回到源Servlet的服务方法中,继续执行后续代码块。
在这里插入图片描述
include()处理特点
include与forward转发相比,包含有以下特点:
1源Servlet与被包含的目标资源的输出数据都会被添加到响应结果中。2在目标资源中对响应状态码或者响应头所做的修改都会被忽略。
代码
Servlet1

@WebServlet(name = "servlet1", value = "/servlet1.do")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet1.do");
        String money = req.getParameter("money");
        System.out.println("money:"+money);

        设置响应类型和编码(include模式下)
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        //增加响应内容(include)
        resp.getWriter().println("servlet1在转发之前做出相应内容");

        //请求转发给另一个组件
        //获取请求转发器
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("servlet2.do");
        //由请求转发器作出转发
        //equestDispatcher.forward(req,resp);
        requestDispatcher.include(req,resp);

        //继续增加响应内容(include)
        resp.getWriter().println("servlet1在转发之后做出相应内容");
    }
}

Servlet2

@WebServlet(name = "servlet2", value = "/servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet2.do");

        String money = req.getParameter("money");
        System.out.println("money:"+money);

        //设置响应类型和编码(forward模式下)
        // resp.setCharacterEncoding("UTF-8");
        // resp.setContentType("text/html;charset=UTF-8");

        resp.getWriter().println("支付宝到账:"+money+"元");
    }

}

访问接口:http://localhost:9008/demo_servlet_war_exploded/servlet1.do?money=100

12.3 总结

//在forward转发模式下,请求应该完全交给目标资源去处理,我们在源组件中,不要作出任何的响应处理
//在forward方法调用之后,也不要在使用req和resp对象做其他操作了
//在incLude较发模式下,设置响应可以在转发之前,也可以在转发之后
/*
*1请求转发是一种服务器的行为,是对浏览嚣器屏蔽
*2浏览器的地址栏不会发生变化
*3请求的参数是可以从源组件传递到目标组件的
*4请求对象和响应对象没有重新创建,而是传递给了目标组件*5请求转发可以帮助我们完成页面的跳转
*6请求转发可以转发至wEB-工NF里
*7请求转发只能转发给当前项目的内部资源,不能转发至外部资源
*8常用forward
**/

13 响应重定向

代码
Servlet3

@WebServlet(name = "servlet3", value = "/servlet3.do")
public class Servlet3 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet3");
        String money = req.getParameter("money");
        System.out.println("money:"+money);
        //响应重定向
        resp.sendRedirect("servlet4.do");
    }
}

Servlet4

@WebServlet(name = "servlet4", value = "/servlet4.do")
public class Servlet4 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet4");
    }
}

访问接口:http://localhost:9008/demo_servlet_war_exploded/servlet3.do?money=100

13.1 总结

//响应重定向
resp.sendRedirect(s:"servlet4.do?money="+money); 
//resp.sendRedirect("wEB-INF/bbb.htmL");
// resp.sendRedirect("https://www.baidu.com");
/*
*响应重定向总结
*1重定向是服务器给浏览器重新指定请求方向是一种浏览器行为地址栏会发生变化
* 2重定向时,请求对象和响应对象都会再次产生,请求中的参数是不会携带
*3重定向也可以帮助我们完成页面跳转
*4重定向不能帮助我们访问wEB-INF中的资源
*5重定向可以定向到外部资源

14 路径问题

14.1前段的路径问题

项目结构
在这里插入图片描述
a2.html和b1.html代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
this is a2/b1
</body>
</html>

a1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--
    2.
    base标签的作用是在相对路径之前自动补充base[href]中的值
    如果base标签不写,那么默认就是当前文件所在的路径
    -->
    <base href="http://127.0.0.1:9008//demo_servlet_war_exploded/">
</head>
<body>
this is a1
<!--
1.
相对(基准)路径:以当前文件本身的位置去定位其他文件,相对自己的路径,以当前文件所在的位置为基准位置
绝对(基准)路径:以一个固定的位置去定位其他文文件,以一个固定的路径作为定位文件的基准位置,和文件本身位置无关

相对路怪,不以/开头,就是相对路程..代表向上一层
绝对路径,以/开头―在页面上/代表从项目的部署目录开始找﹑从webapps中开始找
页面的绝对路径要有项目名,除非我们的项目没有设置项目名
-->

<a href="a2.html" target="_self">相对路径跳转a2</a>
<a href="../../b/b2/b1.html" target="_self">相对路径跳转b1</a>

<a href="a/a2/a2.html" target="_self">base相对路径跳转a2</a>
<a href="b/b2/b1.html" target="_self">base相对路径跳转b1</a>

<a href="/demo_servlet_war_exploded/a/a2/a2.html" target="_self">绝对路径跳转a2</a>
<a href="/demo_servlet_war_exploded/b/b2/b1.html" target="_self">绝对路径跳转b1</a>
</body>
</html>

14.2 请求转发的路径问题

在这里插入图片描述

14.3 响应重定向的路径问题

在这里插入图片描述

15 会话管理

15.1 认识Cookie和Session

Cookie对象与HttpSession对象简介
Cookie对象与HttpSession对象的作用是维护客户端浏览器与服务端的会话状态的两个对象,由于HTTP协议是一个无状态的协议,所以服务端并不会记录当前客户端浏览器的访问状态,但是在有些时候我们是需要服务端能够记录客户端浏览器的访问状态的,如获取当前客户端浏览器的访问服务端的次数时就需要会话状态的维持。在Servlet中提供了Cookie对象与Httpsession对象用于维护客户端与服务端的会话状态的维持。二者不同的是Cookie是通过客户端浏览器实现会话的维持,而HttpSession是通过服务端来实现会话状态的维持。

如何记录用户状态信息原理,举例:会员卡,银行卡
用户记录用户状态的技术
在这里插入图片描述

15.2 Cookie的使用

Cookie是一种保存少量信息至浏览器的一种技术,第一请求时,服务器可以响应给浏览器一些Cookie信息,第二次请求浏览器会携带之前的cookie发送给服务器,通过这种机制可以实现在浏览器端保留一些用户信息.为服务端获取用户状态获得依据

Cookie对象的特点

  • Cookie使用字符串存储数据
  • Cookie使用Key与Value结构存储数据单个
  • Cookie存储数据大小限制在4097个字节
  • Cookie存储的数据中不支持中文,Servlet4.0中支持
  • Cookie是与域名绑定所以不支持跨━级域名访问
  • Cookie对象保存在客户端浏览器内存上或系统磁盘中
  • Cookie分为持久化Cookie(保存在磁盘上)与状态Cookie(保存在内存上)
  • 浏览器在保存同一域名所返回Cookie的数量是有限的。不同浏览器支持的数量不同,Chrome浏览器为50个
  • 浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端。

Cookie对象的创建
Cookie cookie = new Cookie(“key” , “value”)
通过new关键字创建Cookie对象
response.addCookie(cookie)
通过HttpServletResponse对象将Cookie写回给客户端浏览器。

Cookie中数据的获取
通过HttpServletRequest对象获取Cookie,返回Cookie数组.
Cookie[] cookies = request.getCookies();

Cookie不支持中文解决方案
在Servlet4.0版本之前的Cookie中是不支持中文存储的,如果存储的数据中含有中文,代码会直接出现异常。我们可以通过对含有中文的数据重新进行编码来解决该问题。在Servlet4.0中的Cookie是支持中文存储的。
在这里插入图片描述
可以使用对中文进行转码处理
URLEncoder.encode(“content”,“code”)
将内容按照指定的编码方式做URL编码处理。URLDecoder.decode(“content” ,“code”)
将内容按照指定的编码方式做URL解码处理。

Cookie持久化和状态Cookie
状态Cookie:浏览器会缓存Cookie对象。浏览器关闭后Cookie对象销毁。
持久化Cookie:浏览器会对Cookie做持久化处理,基于文件形式保存在系统的指定目录中。在Windows10系统中为了安全问题不会显示Cookie中的内容。
当Cookie对象创建后默认为状态Cookie。可以使用Cookie对象下的cookie.setMaxAge(60)方法设置失效时间,单位为秒。一旦设置了失效时间,那么该Cookie为持久化Cookie,浏览器会将Cookie对象持久化到磁盘中。当失效时间到达后文件删除。

测试代码

存储cookie

@WebServlet(urlPatterns = "/servlet1.do")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过响应对象,向浏览器响应一些cookie
        Cookie c1 = new Cookie("age","10");
//        Cookie c2 = new Cookie("gender", URLEncoder.encode("男","GBK"));
        Cookie c2 = new Cookie("gender", "男");
        c2.setMaxAge(60);//秒钟  持久化cookie 让浏览器保留一分钟
        resp.addCookie(c1);
        resp.addCookie(c2);
    }
}

获取cookie

@WebServlet(urlPatterns = "/servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //读取请求中的cookie
        Cookie[] cookies = req.getCookies();
        //cookie不为null
        if(null != cookies){}
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName()+"="+cookie.getValue());
        }
    }
}

Cookie跨域问题
域名分类:
域名分为顶级域、顶级域名(一级域名)、 二级域名
在这里插入图片描述

域名等级的区别:
一级域名比二级域名更高级,二级域名是依附于一级域名之下的附属分区域名,即二级域名是一级域名的细化分级。例如: baidu.com为—级域名,news.baidu.com为二级域名。
Cookie不支持━级域名的跨域,支持二级域名的跨域。
1.访问zaomaibao.com
在这里插入图片描述
2.访问blog.zaomaibao.com
在这里插入图片描述
3.访问test.blog.zaomaibao.com
在这里插入图片描述

Cookie对象总结
Cookie对于存储内容是基于明文的方式存储的,所以安全性很低。不要在Cookie中存放敏感数据。在数据存储时,虽然在Servlet4.0中Cookie支持中文,但是建议对Cookie中存放的内容做编码处理,也可提高安全性。

Cookie案例开发
案例:通过Cookie判断用户是否访问过当前Servlet
需求:当客户端浏览器第一次访问Servlet时返回“您好,欢迎您第一次访问!”,第二次访问时返回“欢迎您回来!“

代码

@WebServlet(urlPatterns = "/servlet3.do")
public class Servlet3 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //如果是第一访问当前Servlet.向浏览器响应一个cookie ( "servLet3"" ""1"")
        // 如果是多次访问,就再次数上+1
        Cookie[] cookies = req.getCookies();

        boolean flag = false;

        if (null != cookies) {
            for (Cookie cookie : cookies) {
                String cookieName = cookie.getName();
                if (cookieName.equals("servlet3")) {
                    //创建cookie次数+1
                    Integer value = Integer.parseInt(cookie.getValue());
                    Cookie c = new Cookie("servlet3", String.valueOf(value + 1));
                    resp.addCookie(c);
                    System.out.println("欢迎您第" + value + "访问");
                    flag =true;
                }
            }
        }

        if(!flag){
            System.out.println("欢迎您第一次访问");
            Cookie servlet = new Cookie("servlet", "1");
            resp.addCookie(servlet);
        }

    }
}

15.3 HttpSession的使用

HttpSession是一种保存少量信息至服务器端的一种技术,第一请求时,服务器会创建HttpSession,我们可以HttpSession对象中保存一些关于用户的状态信息,并将HttpSession的JSESSIONID以Cookie形式响应给浏览器,第二次请求,浏览器会携带之前的JSESSIONID的Cookie,发送给服务器,服务器根据JSESSIONID获取对应的HttpSession对象.通过这种技术可以解决HTTP协议本身无法记录用户状态情况.

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

HttpSession对象的特点

HttpSession保存在服务端
HttpSession可以存储任何类型的数据
HttpSession使用Key与Value结构存储数据value是Object类型
HttpSession存储数据大小无限制

HttpSession对象的创建

HttpSession对象的创建是通过request.getSession()方法来创建的。客户端浏览器在请求服务端资源时,如果在请求中没
有JSESSIONID,getSession()方法将会为这个客户端浏览器创建一个新的HttpSession对象,并为这个HttpSession对象生成一个JSESSIONID,在响应中通过Cookie写回给客户端浏览器,如果在请求中包含了JSESSIONID,getSession()方法则根据这个ID返回与这个客户端浏览器对应的HttpSession对象。

getSession()方法还有一个重载方法getSession(truefalse)。当参数为true时与getSession()方法作用相同。当参数为false时则只去根据SessionIlD查找是否有与这个客户端浏览器对应的HttpSession,如果有则返回,如果没有SessionID则不会创建新的HttpSession对象。

HttpSession中数据的获取
session.setAttribute(“key” ,value)
将数据存储到HttpSession对象中
Object value = session.getAttribute(“key”)
根据key获取HttpSession中的数据,返回Object
Enumeration attributeNaes = session.getAttributeNames()
获取HttpSession中所有的key,返回枚举类型
session.removeAttribute(“key”)
根据key删除HttpSession中的数据String id = session.getld()
根据获取当前HttpSession的SessionlD,返回字符串类型测试代码:
servlet1创建HttpSession并存储数据

HttpSession的销毁方式
HttpSession的销毁方式有两种:

  • 通过web.xml文件指定超时时间(最大不活动时间)
  • 通过HttpSession对象中的invalidate()方法销毁当前HttpSession对象

我们可以在web.xml文件中指定HttpSession的超时时间,当到达指定的超时时间后,容器就会销该HttpSession对象,单位为分钟。该时间对整个web项目中的所有HttpSession对象有效。时间的计算方式是根据最后一次请求时间作为起始时间。如果有哪个客户端浏览器对应的HttpSession的失效时间已到,那么与该客户端浏览器对应的HttpSession对象就会被销毁。其他客户端浏览器对应
的HttpSession对象会继续保存不会被销毁。
在这里插入图片描述

我们也可以在Tomcat的web.xml文件中配置HttpSession的销毁时间。如果在Tomcat的web.xml文件中配置了HttpSession的超时时间对应的是Tomcat中所有的Web项目都有效。相当于配置了全局的HttpSession超时时间。如果我们在Web项目中配置了超时时间,那么会以Web项目中的超时时间为准。
在这里插入图片描述
测试代码
serlvet1

@WebServlet(urlPatterns = "/servlet1.do")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取HttpSession对象  是一种保存更多数据在服务器端的一种技术
        //一般保存当前登录的用户
        //用户的权限
        //用户的其它信息...
        /*
        getSession方法执行内容
        从request中尝试获取JSESSIONID的cookie

            A如果获取失败,
            认为上次会话已经结束,在这里要开启新的会话,创建一个新的HttpSession并返回
            将新的HttpSession对象的7SESSIONID以Cookie的形式放在Response对象,响应给浏览器

            B如果获取成功
                根据SEsSIONID在服务器内找对应HttpSession对象
                1)找到了,返回找到的Httpsession
                2)没找到,创建新的HTTPSession并将SESSIONID以Cookie的形式放在Response对象,响应给浏览器
         */
        HttpSession session = req.getSession();
        //向HttpSession中存放一些数据
        session.setAttribute("username","msr");
        session.setAttribute("password","123");
        session.setAttribute("level","A");

        session.invalidate();//手动设置HTTPSession不可用
    }
}

servlet

@WebServlet(urlPatterns = "/servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        String username = (String) session.getAttribute("username");
        String password =(String)  session.getAttribute("password");
        String level = (String) session.getAttribute("level");

        System.out.println(username);
        System.out.println(password);
        System.out.println(level);

        System.out.println("创建时间:"+session.getCreationTime());
        System.out.println("最后一次访问时间:"+session.getLastAccessedTime());
        System.out.println("最大不活动时间:"+session.getMaxInactiveInterval());

    }
}

session案例开发
需求:实现登录一次即可,在一次会话内,可以反复多次访问WEB-INF/ welcome.html如果没有登录过,跳转到登录页.登录成功后,可以访问
项目结构:

组件介绍:
index.html
登录信息页面

welcome.html
登录成功之后可以访问的资源

LoginServlet
用来校验登录的,登录成功将用户信息存户HttpSession,否则回到登录页

WelComeServlet
用来向welcome.html中跳转的,同时验证登录,登录过,可以直接跳转,否则回到登录页

User
用来存储一个用户的信息的实体类对象

测试代码

逻辑梳理:
访问login.html页面输入账号密码进行登录,
跳转到loginServlet类中,判断用户是否正确,如果正确重定向到mainServlet类中,如果错误跳转到登录页面
跳转到mainServlet类中,判断session,如果不是null转发到main.html页面,如果是null跳转到登录页面

在这里插入图片描述
login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="get" action="loginServlet.do">
  用户名:<input type="text" name="username"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit">
</form>

</body>
</html>

main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 this is main page
</body>
</html>

User类

public class User implements Serializable {
    private Integer uid;
    private String realname;
    private String username;
    private String password;
// get set
//toString
//hashCode equals
//无参构造  有参构造
}

LoginServlet

@WebServlet(urlPatterns = "/loginServlet.do")
public class LoginServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //如果用户名和密码为msr 1234

        if("msr".equals(username) && "1234".equals(password)){
            //将用户信息放在HTTPSession中
            User user = new User(null, null, "msr", "1234");
            HttpSession session = req.getSession();
            session.setAttribute("user",user);
            // 登录成功跳转至 main.html
            resp.sendRedirect(req.getContextPath()+"/mainServlet.do");

        }else{//登录失败,回到login.html
        resp.sendRedirect(req.getContextPath()+"/login.html");
        }
    }
}

MainServlet

@WebServlet(urlPatterns = "/mainServlet.do")
public class MainServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //跳转至main.html

        HttpSession session = req.getSession();
        User user =(User) session.getAttribute("user");

        if(null != user){
            //判断如果登陆过 允许跳转 HTTPSession中如果有登录过的信息
            req.getRequestDispatcher("/WEB-INF/main.html").forward(req,resp);
        }else{
            //如果没有登陆过 回到登录去登录 HTTPSession中如果有登陆过的信息
            resp.sendRedirect("/login.html");
        }
    }
}

16 域对象

什么是域对象?
那些能放数据并存储传递数据作为数据存放区域的对象
能够存储数据,获取数据,传递数据的对象

Servlet三大域对象
在这里插入图片描述
在这里插入图片描述

域一定有的三个方法
在这里插入图片描述

16.1 request域

有效范围
一次请求内有效,请求转发时数据可以传递,除此之外该域没有办法实现数据共享
生命周期
创建 每发生一次请求创建一个独立的请求域
使用service方法中或者请求转发有效
销毁 请求结束,已经向浏览器响应数据
测试代码
访问链接:http://localhost:9008/demo_servlet_war_exploded/servlet1.do?username=msr&password=123

Servlet1

@WebServlet(urlPatterns = "/servlet1.do")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //向request域中添加数据
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c");
        req.setAttribute("list",list);
        req.setAttribute("gender","boy");
        req.setAttribute("gender","girl");

        req.getRequestDispatcher("/servlet2.do").forward(req,resp);
        //resp.sendRedirect(req.getContextPath()+"/servlet2.do");
    }
}

Servlet2

@WebServlet(urlPatterns = "/servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
        List<String> list = (List<String>)req.getAttribute("list");
        System.out.println(list);
        System.out.println(req.getAttribute("gender"));

        System.out.println(req.getParameter("username"));
        System.out.println(req.getParameter("password"));
    }
}

16.2 Session域

有效范围

单次会话内有效,可以跨多个请求

生命周期

创建 会话的产生,第一次发生请求,会话的开始
使用 本次会话之内,浏览器和服务器之间发生多次请求和响应有效
销毁 会话结束,如:浏览器失去JSESSIONID、到达最大不活动时间、手动清除

测试代码
访问链接:http://localhost:9008/demo_servlet_war_exploded/servlet1.do?username=msr&password=123

Servlet1

@WebServlet(urlPatterns = "/servlet1.do")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //向request域中添加数据
        HttpSession session = req.getSession();
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c");
        session.setAttribute("list",list);
        session.setAttribute("gender","boy");
        session.setAttribute("gender","girl");

        req.getRequestDispatcher("/servlet2.do").forward(req,resp);
        //resp.sendRedirect(req.getContextPath()+"/servlet2.do");
    }
}

Servlet2

@WebServlet(urlPatterns = "/servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
        HttpSession session = req.getSession();
        List<String> list = (List<String>)session.getAttribute("list");
        System.out.println(list);
        System.out.println(session.getAttribute("gender"));

        System.out.println(req.getParameter("username"));
        System.out.println(req.getParameter("password"));
    }
}

16.3 Application域

有效范围
当前web服务内,跨请求,跨会话

生命周期
创建 项目启动
使用 项目运行任何时间有效
销毁 项目关闭

测试代码
访问链接:http://localhost:9008/demo_servlet_war_exploded/servlet1.do
访问链接:http://localhost:9008/demo_servlet_war_exploded/servlet2.do

Servlet1

@WebServlet(urlPatterns = "/servlet1.do")
public class Servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //向Application域中添加数据
        ServletContext application = req.getServletContext();
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c");
        application.setAttribute("list",list);
        application.setAttribute("gender","boy");
        application.setAttribute("gender","girl");
    }
}

Servlet2

@WebServlet(urlPatterns = "/servlet2.do")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
        ServletContext servletContext = req.getServletContext();

        List<String> list = (List<String>)servletContext.getAttribute("list");
        System.out.println(list);
        System.out.println(servletContext.getAttribute("gender"));
    }
}
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值