Servlet

Servlet简介

  • Servlet就是sun公司开发动态web的一门技术
  • Sun在这些API中提供一个接口叫做:Servlet
  • 开发一个Servlet的步骤:
    • 编写一个类,实现Servlet接口
    • 把开发好的Java类部署到web服务器中。

把实现了Servlet接口的Java程序叫做,Servlet

开发一个servlet

Serlvet接口Sun公司有两个默认的实现类:HttpServlet,GenericServlet

创建干净的maven项目

这个作为Maven的主程序,可以在里面创建带有Maven模板的子模块

  • 删除src文件夹

image-20210331201849276

去Maven仓库找必要的API

  1. https://mvnrepository.com/search?q=Java+servlet

image-20210331181056988

  1. https://mvnrepository.com/search?q=jsp+api

image-20210331181158363

  1. 导入Maven依赖

image-20210331181309731

  1. 将限定范围删除

image-20210331210126832

创建servlet项目的web子程序

创建子模块module

  1. 在当前大web项目里创建子工程

image-20210331203953811

  1. 带Maven模板的

  1. 子工程项目名

image-20210331204450020

  1. 创建成功

image-20210331204701793

  1. 更换最新的web.xml的版本
  • 老:

image-20210331204847339

  • 新:

image-20210331204953791

<?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"
         metadata-complete="true">
</web-app>

这里建议在大项目的文件夹里创建一个note_webXml文件,用于存放新版的xml,每次创建子程序的时候可以直接复制粘贴

image-20210404185033211

  1. 将Maven项目构建完整
  • 创建源码目录和资源目录

image-20210331205121531

  • ctrl + o 调出重写框

image-20210331210601834

package com.feifan.sevlet;

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

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();  //相应流
        writer.print("Hello, Servlet");

    }

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

编写Servlet的映射

  1. 在子模块的web.xml内编写

在下列文件内添加程序

image-20210331211924817

  • 编写程序
<servlet>
    <servlet-name>......</servlet-name>
    <servlet-class>......</servlet-class>   <!-- 注册的类-->
</servlet>

<!--Servlet的请求路径-->
<servlet-mapping>
    <servlet-name>......</servlet-name>   <!-- 与上面的name对应-->
    <url-pattern>......</url-pattern>         <!-- 请求路径-->
</servlet-mapping>
  • 编写完成

image-20210331212730605

配置Tomcat

  1. 增加配置 add Configuration
  • 注意add artifact

    • 一样的名字image-20210331215651115

    • 这个框中输入 / 或者 /所在子模块文件名

      image-20210331215953236

  • Tomcat成功

image-20210331220054763

  • Servlet成功!

image-20210401140828264

Servlet原理

image-20210401141557315

映射问题(Mapping)

  1. 一个Servlet指定一个映射路径
<servlet-mapping>
    <servlet-name>hello</servlet-name>        
    <url-pattern>/hello</url-pattern>    
</servlet-mapping>
  1. 一个Servlet指定多个映射路径
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

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

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello3</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello4</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello5</url-pattern>
</servlet-mapping>
  1. 一个Servlet可以指定通用映射路径
<servlet-mapping>
    <servlet-name>hello</servlet-name>        
    <url-pattern>/hello/*</url-pattern>    
</servlet-mapping>
  1. 默认请求路径
<servlet-mapping>
    <servlet-name>hello</servlet-name>        
    <url-pattern>/*</url-pattern>    
</servlet-mapping>
  1. 指定一些后缀或者前缀等等
<!--可以自定义后缀实现请求映射
    注意点,*前面不能加项目映射的路径    
	hello/sajdlkajda.qinjiang    -->
<servlet-mapping>
   <servlet-name>hello</servlet-name>    <url-pattern>*.qinjiang</url-pattern> </servlet-mapping>
  1. 优先级问题
    指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;
<!--404-->
<servlet>
   <servlet-name>error</servlet-name>
   <servlet-class>com.kuang.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>error</servlet-name>
   <url-pattern>/*</url-pattern>
</servlet-mapping>

ServletContext

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的 web应用

作用:

共享数据

两个Servlet(Java文件)获取同样的信息

  1. 通过第三方读取文件(不推荐)

image-20210405090051700

  1. 用ServletContext对象

image-20210405090442896

1)创建两个Servlet

  • 写入数据的Servlet
package com.feifan.servlet;

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

public class GetServletContext extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext sc = this.getServletContext();
        String username = (String) sc.getAttribute("username");


        resp.getWriter().print("名字:" + username);
    }
}
  • 读取数据的Servlet
package com.feifan.servlet;

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

public class HelloServletContext extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext sc = this.getServletContext();

        String username = "pff";
        sc.setAttribute("username",username);   //用键值对的方式将用户名放入Servlet Context

    }
}

2)注意中文的编码格式

  • 没有先hello设置username
    也没有设置编码格式

    img

3)先访问/hello 设置uesrname

image-20210405092606214

4)然后再访问 /getC 获取ServletContext

image-20210405092947157

获取初始化参数

  1. 在子模版的web.xml内进行配置参数

image-20210405122655902

<!--  配置web的一些初始化参数-->
  <context-param>
    <param-name>url</param-name>
    <!--这里是数据库的一个参数,以后用得上-->
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
  </context-param>
  1. doGet方法中进行获取
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext sc = this.getServletContext();
        String url = sc.getInitParameter("url");
        resp.getWriter().print(url);
}
  1. 成功获取

image-20210405125601198

请求转发操作

进入一个Servlet时,转发到另外一个Servlet中去

  1. 在HelloServletContext类中(对应的是/hello)
    编写请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext sc = this.getServletContext();
    
    System.out.println("进入了HelloServletContext");
    //RequestDispatcher requestDispatcher = sc.getRequestDispatcher("/getC"); //声明请求的路径
    //requestDispatcher.forward(req,resp);    //进行转发的操作
    sc.getRequestDispatcher("/getC").forward(req,resp);

}

运行时还是先进的HelloServletContext

image-20210405125403281
  1. 运行完了输入 /hello
    跳转到 /get 的界面中去

image-20210405125448874

总结转发思路:

A要找C,转发 路径不发生改变

image-20210405143045245

重定向 路径发生改变

image-20210405143450199

读取资源文件

Properties

  • 在java目录下新建.properties文件
  • 在resources目录下新建.properties文件

结果:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath类路径

-->通过文件流的方式读取资源文件的信息

  1. 创建一个getProperties的Servlet
package com.feifan.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class GetProperties extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //通过context拿到properties,并把资源变成一个流
        //第一个 '/' 代表当前的web项目,不能省略
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");

        //将资源流进行加载,并获得其中的属性
        Properties prop = new Properties();
        prop.load(is);
        String user = prop.getProperty("username");
        String pwd = prop.getProperty("password");

        resp.getWriter().print(user + ":" + pwd);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  1. 增加映射
<servlet>
  <servlet-name>getP</servlet-name>
  <servlet-class>com.feifan.servlet.GetProperties</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>getP</servlet-name>
  <url-pattern>/getP</url-pattern>
</servlet-mapping>
  1. 运行成功,成功获取资源文件信息

image-20210406072058497

问题:无法获取Java文件下的
maven由于他的约定大于配置,所以我们写的配置文件,无法被导出或者生效

解决办法:在子模块的pom.xml里进行
build配置resources,来防止我们资源导出失败的问题

<build>
   <resources>
       <resource>
           <directory>src/main/resources</directory>
           <includes>
               <include>**/*.properties</include>
               <include>**/*.xml</include>
           </includes>
           <filtering>true</filtering>
       </resource>
       <resource>
           <directory>src/main/java</directory>
           <includes>
               <include>**/*.properties</include>
               <include>**/*.xml</include>
           </includes>
           <filtering>true</filtering>
       </resource>
   </resources>
</build>

进行测试:

  1. getProperties的Servlet文件
    注意这里路径一定要完整
public class GetProperties extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //通过context拿到properties,并把资源变成一个流
        //第一个 '/' 代表当前的web项目,不能省略
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/feifan/servlet/feifan.properties");

        //将资源流进行加载,并获得其中的属性
        Properties prop = new Properties();
        prop.load(is);
        String user = prop.getProperty("username");
        String pwd = prop.getProperty("password");

        resp.getWriter().print(user + ":" + pwd);
    }

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

  2. 运行成功

image-20210406073207776

请求、响应对象

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse;

  • 如果要获取客户端请求过来的参数:找HttpServletRequest
  • 如果要给客户端响应一些信息:找HttpServletResponse

HttpServletResponse类

结构

  1. 向浏览器发送数据的方法
// 输出一个流
ServletOutputStream getOutputStream() throws IOException; 

// 普通的字符串,如果是中文的话要配置编码格式
PrintWriter getWriter() throws IOException;
  1. 向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
  1. 响应 的状态码
int SC_OK = 200;
int SC_MULTIPLE_CHOICES = 300;
int SC_BAD_REQUEST = 400
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_BAD_GATEWAY = 502;

应用

通过浏览器输出消息

getOutputStream();
getWriter()

下载文件

1)获取下载文件的路径
2)设置下载后文件的名字
3)设置浏览器能够支持下载我们需要的东西
4)获取下载文件输入流
5)创建缓冲区
6)获取OutputStream的对象
7)将FileOutputStream流写入buffer缓冲区
8)使用OutputStream将缓冲的数据输出到客户端

Servlet文件:

public class FileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 要获取下载文件的路径,这里用绝对路径
        String realPath = "E:\\Programing\\Java\\Web\\Servlet\\kuangTest\\req_resp\\src\\main\\resources\\入海.png";
        System.out.println("下载文件的路径:" + realPath);

        // 2. 下载的文件名是啥?
        String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);

        // 3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西
        // 中文文件 名URLEncoder.encode编码,否则下载的文件名有可能乱码
        // 浏览器行为用resp对象
        resp.setHeader("Content-Disposition"," attachment; filename = "+ URLEncoder.encode(fileName,"UTF-8"));

        // 4. 获取下载文件的输入流
        // 将文件路径变成流
        FileInputStream in = new FileInputStream(realPath);

        // 5. 创建缓冲区
        int len = 0;
        byte[] buffer = new byte[1024];

        // 6. 获取OutputStream对象
        ServletOutputStream out = resp.getOutputStream();

        // 7. 将FileOutputStream流写入到buffer缓冲区
        // 8. 使用OutputStream将缓冲区中的数据 输出到客户端!
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
        in.close();
        out.close();
    }

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

映射:

<servlet>
  <servlet-name>reqresp</servlet-name>
  <servlet-class>FileServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>reqresp</servlet-name>
  <url-pattern>/down</url-pattern>
</servlet-mapping>
  • 运行成功
image-20210406190247427

验证码功能

  • 前端实现
    用JS去进行判断
  • 后台实现
    运用Java的图片类,生成一个图片

Servlet文件

public class ImageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //让浏览器5秒刷新一次
        resp.setHeader("refresh", "3");

        // 在内存中创建图片
        // BufferedImage.TYPE_INT_RGB是三原色
        BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);

        // 得到内存的图片
        Graphics2D gra = (Graphics2D) image.getGraphics(); // 画笔进行操作
        //设置图片背景颜色
        gra.setColor(Color.white);  //颜色填充,白色的背景
        gra.fillRect(0, 0, 80, 20);

        //给图片写数据
        gra.setColor(Color.BLUE);   // 选择蓝色的进行书写
        gra.setFont(new Font(null, Font.BOLD, 20)); // BOLD粗体
        gra.drawString(makeNum(), 0, 20);    // 在(0,20)的位置吧随机数画上去

        // 告诉浏览器这个请求用图片的方式打开
        resp.setContentType("image/jpeg");

        // 网站存在缓存,不让浏览器缓存
        resp.setDateHeader("expires", -1);  // 不让缓存
        resp.setHeader("Cache-Control", "no-cache");    // 缓存控制设置为不缓存
        resp.setHeader("Pragma", "no-cache");

        // 把图片写给浏览器
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }

    //生成随机数
    private String makeNum() {
        Random random = new Random();   //随机数对象
        String num = random.nextInt(9999999) + "";  // 转成字符串
        StringBuffer sb = new StringBuffer();   // 可变长的字符串

        // 如果不够7位数的  用0在前面进行填充
        for (int i = 0; i < 7 - num.length(); i++) {
            sb.append("0");
        }
        num = sb.toString() + num;  // 字符串连接

        return num;
    }

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

image-20210406201933458

重定向

概念:
一个web资源B收到客户端A请求后,B会通知A客户端去访问另外一个web资源C

图解:

image-20210406202450900

场景:
用户登录,成功之后会跳转

实现方法:

void sendRedirect(String var1) throws IOException;

简单实现:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/response/image");
    }

注意这里面的跳转之前的web地址应该和Tomcat中配置的一样

image-20210406204215387

重定向和转发的区别:

  • 相同点

    ​ 页面都会实现跳转

  • 不同点

    • 请求转发的时候,url不会产生变化
    • 重定向时候,url地址栏会发生变化

HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器
HTTP请求中的所有信息会被封装到HttpServletRequest,通过HttpServletRequest对象的方法,获得客户端的所有信息;

获取请求 行 信息的方法

访问 Servlet 时,所有请求消息将被封装到 HttpServletRequest 对象中,请求消息的请求行中包含 请求方法、请求资源名、请求路径 等信息

方法声明 功能描述
String getMethod() 该方法用于获取 HTTP 请求消息中的请求方式(如 GET、POST 等)
String getRequestURI() 该方法用于获取请求行中的资源名称部分即位于 URL 的主机和端门之后、参数部分之前的部分
String getQueryString() 该方法用于获取请求行中的参数部分,也就是资源路径后问号(?)以后的所有内容
String getContextPath() 该方法用于获取请求 URL 中属于 Web 应用程序的路径,这个路径以 / 开头,表示相对于整个 Web 站点的根目录,路径结尾不含 /。如果请求 URL 属于 Web 站点的根目录,那么返回结果为空字符串("")
String getServletPath() 该方法用于获取 Servlet 的名称或 Servlet 所映射的路径
String getRemoteAddr() 该方法用于获取请求客户端的 IP 地址,其格式类似于 192.168.0.3
String getRemoteHost() 该方法用于获取请求客户端的完整主机名,其格式类似于 pcl.mengma.com。需要注意的是,如果无法解析出客户机的完整主机名,那么该方法将会返回客户端的 IP 地址
int getRemotePort() 该方法用于获取请求客户端网络连接的端口号
String getLocaIAddr() 该方法用于获取 Web 服务器上接收当前请求网络连接的 IP 地址
String getLocalName() 该方法用于获取 Web 服务器上接收当前网络连接 IP 所对应的主机名
int getLocalPort() 该方法用于获取 Web 服务器上接收当前网络连接的端口号
String getServerName() 该方法用于获取当前请求所指向的主机名,即 HTTP 请求消息中 Host 头字段所对应的主机名部分
int gctServcrPort() 该方法用于获取当前请求所连接的服务器端口号,即 HTTP 请求消息中 Host 头字段所对应的端口号部分
StringBuffcr getRequestURL() 该方法用于获取客户端发出请求时的完整 URL,包括协议、服务器名、端口号、 资源路径等信息,但不包括后面的査询参数部分。注意,getRequcstURL() 方法返冋的结果是 StringBuffer 类型,而不是 String 类型,这样更便于对结果进行修改

获取请求消息头的方法

当浏览器发送 Servlet 请求时,需要通过请求消息头向服务器传递附加信息,例如,客户端可以接收的 数据类型、压缩方式、语言

方法声明 功能描述
String getHeader(String name) 该方法用于获取一个指定头字段的值,如果请求消息中没有包含指定的头字段,则 getHeader() 方法返回 null;如果请求消息中包含多个指定名称的头字段,则 getHeader() 方法返回其中第一个头字段的值
Enumeration getHeaders(String name) 该方法返回一个 Enumeration 集合对象,该集合对象由请求消息中出现的某个指定名称的所有头字段值组成。在多数情况下,一个头字段名在请求消息中只出现一次,但有时可能会出现多次
Enumeration getHeaderNames() 该方法用于获取一个包含所有请求头字段的 Enumeration 对象
int getIntHeader(String name) 该方法用于获取指定名称的头字段,并且将其值转为 int 类型。需要注意的是,如果指定名称的头字段不存在,则返回值为 -1;如果获取到的头字段的值不能转为 int 类型,则将发生 NumberFormatException 异常
long getDateHeader(String name) 该方法用于获取指定头字段的值,并将其按 GMT 时间格式转换为一个代表日期/时间的长整数,该长整数是自 1970 年 1 月 1 日 0 时 0 分 0 秒算起的以毫秒为单位的时间值
String getContentType() 该方法用于获取 Content-Type 头字段的值,结果为 String 类型
int getContentLength() 该方法用于获取 Content-Length 头字段的值,结果为 int 类型
String getCharacterEncoding() 该方法用于返回请求消息的实体部分的字符集编码,通常是从 Content-Type 头字段中进行提取,结果为 String 类型

应用(用户登录)

获取参数 + 请求转发

image-20210407072009050

Servlet文件

public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        String username = req.getParameter("username");
        String password = req.getParameter("password");

        // 通过getParameterValues获取多选框对应的多个值
        String[] hobbys = req.getParameterValues("hobbys");

        System.out.println("=============================");  //后台接收中文乱码问题
        System.out.println(username);
        System.out.println(password);

        // 打印数组
        System.out.println(Arrays.toString(hobbys));
        System.out.println("=============================");

        //通过请求转发
        //这里的  / 代表当前的web应用
        req.getRequestDispatcher("/success.jsp").forward(req, resp);
    }

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

index.jsp

<%--这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPath}代表当前的项目--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陆界面</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/login" method="post">
    用户名:<input type="text" name="username"> <br>
    密码:<input type="password" name="password"> <br>
    爱好:
    <input type="checkbox" name="hobby" value="看书">看书
    <input type="checkbox" name="hobby" value="代码">代码
    <input type="checkbox" name="hobby" value="游戏">游戏
    <br>
    <input type="submit">
</form>
</body>
</html>

success.jsp

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021-04-07
  Time: 7:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陆成功</title>
</head>
<body>
    <h1>登陆成功</h1>
</body>
</html>

web.xml里的映射

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>

Cookie

概述

Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息。

识别返回用户包括三个步骤:

  • 服务器脚本向浏览器发送一组 Cookie。例如:姓名、年龄或识别号码等。
  • 浏览器将这些信息存储在本地计算机上,以备将来使用。
  • 当下一次浏览器向 Web 服务器发送任何请求时,浏览器会把这些 Cookie 信息发送到服务器,服务器将使用这些信息来识别用户。

获得Cookie对象:

Cookie[] cookies = req.getCookies();
方法 描述
public void setDomain(String pattern) 该方法设置 cookie 适用的域
public String getDomain() 该方法获取 cookie 适用的域,例如 runoob.com。
public void setMaxAge(int expiry) 该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。
public int getMaxAge() 该方法返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示 cookie 将持续下去,直到浏览器关闭。
public String getName() 该方法返回 cookie 的名称。名称在创建后不能改变。
public void setValue(String newValue) 该方法设置与 cookie 关联的值。
public String getValue() 该方法获取与 cookie 关联的值。
public void setPath(String uri) 该方法设置 cookie 适用的路径。如果您不指定路径,与当前页面相同目录下的(包括子目录下的)所有 URL 都会返回 cookie。
public String getPath() 该方法获取 cookie 适用的路径。
public void setSecure(boolean flag) 该方法设置布尔值,表示 cookie 是否应该只在加密的(即 SSL)连接上发送。
public void setComment(String purpose) 设置cookie的注释。该注释在浏览器向用户呈现 cookie 时非常有用。
public String getComment() 获取 cookie 的注释,如果 cookie 没有注释则返回 null。

步骤:

  1. 创建一个 Cookie 对象
    调用带有 cookie 名称和 cookie 值的 Cookie 构造函数,cookie 名称和 cookie 值都是字符串。
Cookie cookie = new Cookie("key","value");

中文数据的传输:

// 编码
Cookie cookie = new Cookie("name", URLEncoder.encode("大帅哥","utf-8"));

// 解码
out.write(URLDecoder.decode(cookie.getValue(),"UTF-8"));
  1. 设置最大生存周期
    使用 setMaxAge 方法来指定 cookie 能够保持有效的时间(以秒为单位)。

设置一个最长有效期为 24 小时的 cookie:

cookie.setMaxAge(60*60*24); 
  1. 发送 Cookie 到 HTTP 响应头
    使用 response.addCookie 来添加 HTTP 响应头中的 Cookie
response.addCookie(cookie);

应用

通过cookie保存上一次访问浏览器的时间

  1. Servlet文件
import javax.servlet.ServletException;
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.io.PrintWriter;
import java.util.Date;

public class CookieOpera extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-16");
        req.setCharacterEncoding("utf-16");
        PrintWriter out = resp.getWriter();

        Cookie[] cookies = req.getCookies();
        if (cookies != null) {
            out.write("你上一次访问的时间是:");
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals("lastLoginTime")){
                    long lastLoginTime = Long.parseLong(cookie.getValue());
                    Date date = new Date(lastLoginTime);
                    out.write(date.toLocaleString());
                }
            }
        }else{
            out.write("这是你第一次访问");
        }

        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
        resp.addCookie(cookie);
    }

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

  1. web.xml里的映射
<servlet>
    <servlet-name>CookieOpera</servlet-name>
    <servlet-class>CookieOpera</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>CookieOpera</servlet-name>
    <url-pattern>/co</url-pattern>
</servlet-mapping>
  1. 第一次运行
    时间没有进行输出,而是先设置在cookie当中
    找到cookie,发现里面有请求的键值对
image-20210407124652875
  1. 进行刷新,出现时间
image-20210407124855640

Session

介绍

概念:

Servlet提供了 HttpSession 接口,该接口提供了一种跨多个页面请求或访问网站时 识别用户 以及 存储有关用户信息 的方式。

使用HttpSession 接口来创建一个 HTTP 客户端和 HTTP 服务器之间的 session 会话。
会话持续一个指定的时间段,跨多个连接或页面请求。

特点:

  • 服务器会给每一个用户(浏览器)创建一个Seesion对象
  • 一个Seesion独占一个浏览器,只要浏览器没有关闭,这个Session就存在
  • 用户登录之后,整个网站它都可以访问

Session和cookie的区别:

  • Cookie是把用户的数据写给用户的浏览器,浏览器保存 (可以保存多个)
  • Session把用户的数据写到用户独占Session中,服务器端保存 (保存重要的信息,减少服务器资源的浪费)
  • Session对象由服务器创建

方法

通过调用 HttpServletRequest 的公共方法 getSession() 来获取 HttpSession 对象

HttpSession session = request.getSession();
方法 描述
public Object getAttribute(String name) 该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null。
public Enumeration getAttributeNames() 该方法返回 String 对象的枚举,String 对象包含所有绑定到该 session 会话的对象的名称。
public long getCreationTime() 该方法返回该 session 会话被创建的时间,自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。
public String getId() 该方法返回一个包含分配给该 session 会话的唯一标识符的字符串。
public long getLastAccessedTime() 该方法返回客户端最后一次发送与该 session 会话相关的请求的时间自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。
public int getMaxInactiveInterval() 该方法返回 Servlet 容器在客户端访问时保持 session 会话打开的最大时间间隔,以秒为单位。
public void invalidate() 该方法指示该 session 会话无效,并解除绑定到它上面的任何对象。
public boolean isNew() 如果客户端还不知道该 session 会话,或者如果客户选择不参入该 session 会话,则该方法返回 true。
public void removeAttribute(String name) 该方法将从该 session 会话移除指定名称的对象。
public void setAttribute(String name, Object value) 该方法使用指定的名称绑定一个对象到该 session 会话。
public void setMaxInactiveInterval(int interval) 该方法在 Servlet 容器指示该 session 会话无效之前,指定客户端请求之间的时间,以秒为单位。

例子

获取Session的ID

在每次访问浏览器时,都会自动创建Session对象
里面包含了SessionID

  • Servlet文件
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;

public class GetSessionId extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");

        //得到Session
        HttpSession session = req.getSession();
        // 获取Session的ID
        String sessionId = session.getId();    //判断Session是不是新创建
        if (session.isNew()) {
            resp.getWriter().write("session创建成功,ID:" + sessionId);
        } else {
            resp.getWriter().write("session以及在服务器中存在 了,ID:" + sessionId);
        }
    }

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

  • web.xml映射
<servlet>
    <servlet-name>GetSessionId</servlet-name>
    <servlet-class>GetSessionId</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>GetSessionId</servlet-name>
    <url-pattern>/gsi</url-pattern>
</servlet-mapping>
  • 运行成功

image-20210407221103129

获取Session中的设置的参数

普通类型和对象都可以设置和接收

  1. 设置
  • Servlet文件
package com.feifan;

import com.pojo.Person;

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

public class SetSessionAttribute extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");

        //得到Session
        HttpSession session = req.getSession();

        //给Session中存东西
        // 1.普通类型
        session.setAttribute("name", "大帅哥");

        // 2.对象
        session.setAttribute("person", new Person("大帅哥", 666));
    }

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

  • web.xml映射
<servlet>
    <servlet-name>SetSessionAttribute</servlet-name>
    <servlet-class>com.feifan.SetSessionAttribute</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>SetSessionAttribute</servlet-name>
    <url-pattern>/ssa</url-pattern>
</servlet-mapping>
  1. 获取
  • Servlet文件
package com.feifan;

import com.pojo.Person;

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

public class GetSessionAttribute extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");

        //得到Session
        HttpSession session = req.getSession();

        //给Session中存东西
        String name = (String) session.getAttribute("name");// 得到name对应的大帅哥
        System.out.println(name);   // 在后台进行输出

        Person person = (Person) session.getAttribute("person");// 得到name对应的对象
        System.out.println(person.toString());  // 调用对象里重写过的toString方法


    }

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

  1. 进行操作
  • 设置

image-20210407223602108

  • 获取

image-20210407223920364

  • 成功获取

image-20210408073748806

删除Session

当您完成了一个用户的 session 会话数据,您有以下几种选择:

  • 移除一个特定的属性: public void removeAttribute(String name) 方法来删除与特定的键相关联的值。
  • 删除整个 session 会话:您可以调用 public void invalidate() 方法来丢弃整个 session 会话。

但是刷新后又会生成一个新的Session
因为每次访问浏览器时都会有一个Session对象

  • 设置 session 会话过期时间:您可以调用 public void setMaxInactiveInterval(int interval) 方法来单独设置 session 会话超时。
  • 注销用户:如果使用的是支持 servlet 2.4 的服务器,您可以调用 logout 来注销 Web 服务器的客户端,并把属于所有用户的所有 session 会话设置为无效。

【体验:】

  • Servlet文件
package com.feifan;

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

public class DelSessionAttribute extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        session.removeAttribute("name");    // 删除Session内的对应属性
        session.invalidate();      // 删除当前Session的ID
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • web.xml映射
<servlet>
    <servlet-name>DelSessionAttribute</servlet-name>
    <servlet-class>com.feifan.DelSessionAttribute</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>DelSessionAttribute</servlet-name>
    <url-pattern>/dsa</url-pattern>
</servlet-mapping>
  1. 先获取当前SessionID

image-20210408074607749

  1. 删除当前的Session

image-20210408074656868

  1. 再次获取当前SessionID

进行删除操作后
再次访问你的时候又获得了一个Session对象

image-20210408074754722

posted @ 2021-04-11 11:30  feifan666  阅读(69)  评论(0)    收藏  举报