servlet入门

文章目录

1.Tomcat下载、安装、启动和关闭

1.下载

➢ apache 官网。www.apache.org

➢ tomcat 的产品页面: http://tomcat.apache.org

2.安装

找到一个目录解压就可安装

配置环境变量

3.目录结构
目录名作用
bin启动和关闭tomact可执行文件
conf配置文件夹,有些重要配置文件都在下面,如server.xml, web.xml 等
不建议乱改,可能会导致tomcat不能启动
libtomcat 使用时依赖的一些第三方 jar 包
logs日志记录文件,记录服务器运行过程中一些事件。包括运行过程中出现异常
temp临时文件,保存服务器进行过程中生成得一些垃圾文件
webapps我们做好的项目发布的目录,可以通过浏览器来直接访问
worktomcat 工作目录,所有已经发布项目,在这里生成中间文件执行
4.启动常见问题

1.Tomcat启动一闪而过

原因: 没有配置JAVA_HOME 或 JRE_HOME 环境变量

解决就是: 配置JAVA_HOME环境变量

2.Tomcat的端口号8080被其他程序占用

解决方法: 修改Tomcat端口号为其他:修改conf/server.xml文件的69行

解决方法: 找到占用8080端口号的程序,杀死即可。

5.启动和关闭
启动:进入bin目录双击startup.bat
关闭:进入bin目录双击shutdown.bat

2.Servlet入门案例

实例像浏览器输出:Hello Servlet

package com.xjggb.servlet;

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

@WebServlet(urlPatterns = "/hello",name = "servlet.HelloServlet")
public class HelloServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

          //向浏览器输出
        PrintWriter writer = response.getWriter();
        writer.print("Hello Servlet");

    }
}


3.Servlet生命周期

package com.xjggb.servlet;

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

@WebServlet(urlPatterns = "/life")
public class LifeCycleServlet implements Servlet {

    // 无参数构造:只会执行1次
    public LifeCycleServlet(){
        System.out.println("无参数构造方法...");
    }

    //初始化方法,只会执行一次
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

        System.out.println("初始化" );
    }


    //接收请求和响应数据  每次请求都执行一次
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

        System.out.println("service " );
    }
    //销毁方法
    @Override
    public void destroy() {

        System.out.println("来了老弟destroy");
    }

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

在这里插入图片描述

1.3 小结

  • Servlet是谁负责创建的:web服务器
  • 什么时候创建Servlet:浏览器第1次访问
  • 什么时候销毁Servlet:服务器关闭或重启
  • 一个Servlet在Tomcat中会生成几个对象:1个
与Servlet生命周期相关的方法作用运行次数
构造方法创建对象1次
void init(ServletConfig config)初始化资源1次
void service(ServletRequest req,
ServletResponse res)
处理请求并响应数据每次请求执行1次
void destroy()销毁资源1次

4Servlet运行原理-[理解]

<?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">

    <!--
        Tomcat启动时执行了如下操作:
            1. 解析web.xml文件
            2. 创建一个Map集合存储Servlet名称和类全名的对应关系
                Map<String,String> map01 = ...
                键:Servlet的名称  值:Servlet的类全名字符串
                map01.put("hello","com.xjggb.HelloServlet");
            3. 创建一个Map集合存储Servlet名称和访问路径的对应关系
                Map<String,String> map02 = ...
                键:访问路径  值:Servlet的名称
                map02.put("/hello","hello");

            4. 当浏览器输入地址访问servlet:http://localhost:8080/day24/hello
            5. 服务器会解析URL地址获得要访问的资源路径: /hello
            6. 将访问路径作为键从map02集合获得值:hello ==> servlet的名称
            7. 将servlet的名称作为键从map01集合获得值:com.xjggb.HelloServlet ==> servlet的类全名字符串
            8. 通过反射获得Class对象:Class c = Class.forName("com.xjggb.HelloServlet");
            9. 反射获得构造方法对象并创建对象:Object servlet = c.getConstructor().newInstance();
            10. 服务器会创建请求对象和响应对象并调用service方法:将request和response对象作为参数传递
    -->
    <servlet>
        <!--配置servlet名称:可以任意-->
        <servlet-name>hello</servlet-name>
        <!--配置Servlet的类全名:包名..类名-->
        <servlet-class>com.xjggb.HelloServlet</servlet-class>
    </servlet>

    <!--配置servlet访问路径-->
    <servlet-mapping>
        <!--配置servlet名称:必须和上面一直-->
        <servlet-name>hello</servlet-name>
        <!--配置servlet访问路径:必须以/开头
            访问地址:http://localhost:8080/day24/hello
        -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

5.Servlet体系结构

在这里插入图片描述

创建Servlet继承GenericServlet

package com.itheima;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

/**
 * 目标:继承GenericServlet
 */
@WebServlet(urlPatterns = "/two")
public class TwoServlet extends GenericServlet {

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("接收到了请求");
    }
}

小结

1. Servlet继承体系
  	Servlet -- 接口
  		-- GenericServlet 抽象类
  			-- HttpServlet  抽象类
	
2. 我们开发的Servlet类继承谁?
		因为现在浏览器和服务器进行通信使用的都是HTTP协议,所以我们开发的Servlet直接继承HttpServlet即可

6.HttpServlet源码分析-[了解]

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package javax.servlet.http;

import java.io.IOException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.ResourceBundle;
import javax.servlet.DispatcherType;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public abstract class HttpServlet extends GenericServlet {
    private static final long serialVersionUID = 1L;
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";
    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    private static final ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");

    public HttpServlet() {
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

	// 属性重载的service
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获得请求方式 method = GET或POST
        String method = req.getMethod(); 
    	// 如果GET请求,则调用doGet方法
        if (method.equals("GET")) {
             this.doGet(req, resp);
        } else if (method.equals("POST")) {
        	// 如果POST请求,则调用doPost方法
            this.doPost(req, resp);
        } 
    }
	
	// 重写Servlet接口的service方法
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }
		// 调用本来重置的service方法
        this.service(request, response);
    }
}

小结:

1. doPost和doGet方法如何调用执行的?
		当请求到Servlet时,会触发service方法的执行,在父类HttpServlet的servicve方法中根据请求方式决定调用doGet还是doPost方法
  	如果是get请求,则调用doGet方法
  	如果是post请求,则调用doPost方法
  	如果表单明确指定提交方式是post提交,则重写doPost方法,其他都是重写doGet方法

7.ServletConfig对象作用和演示-[了解]

1.作用:

用来封装Servlet初始化得时候得一些配置信息 ServletConfig 是一个接口

2.ServletConfig 对象哪个方法中见到过?

​ void init(ServletConfig config) 在 Servlet 一创建,就已经有这个对象了。

3.常用方法

​ String getInitParameter(“参数名”) 通过指定的参数名得到参数值

​ getInitParameterNames() 得到配置中所有的参数名

4.为什么要配置初始化参数?

​ 硬编码缺点:

​ 因为写源代码中,一旦写死,就很难修改,维护不方便

​ 建议把一些与 Servlet 有关的配置信息,写在 web.xml 中,后期可以方便修改和维护

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>config</servlet-name>
      <servlet-class>com.xjggb.servlet.ConfigServlet</servlet-class>

<!--      配置初始化参数-->

      <init-param>
          <param-name>username</param-name>
          <param-value>user</param-value>
      </init-param>
      <init-param>
          <param-name>age</param-name>
          <param-value>18</param-value>
      </init-param>
  </servlet>
    <servlet-mapping>
        <servlet-name>config</servlet-name>
        <url-pattern>/config</url-pattern>
    </servlet-mapping>
    
</web-app>

代码

package com.xjggb.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.PrintWriter;
import java.util.Enumeration;

public class ConfigServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //获取参数值
        String username = getInitParameter("username");
        String age = getInitParameter("age");
        //获得所有参数名
        Enumeration<String> initParameterNames = getInitParameterNames();
        while (initParameterNames.hasMoreElements()){
            String s = initParameterNames.nextElement();

            String initParameter = this.getInitParameter(s);
            System.out.println("initParameter = " + initParameter);
        }

        PrintWriter out = resp.getWriter();

        out.print(username);
        out.print(age);


    }
}

小结:

ServletConfig的作用:读取Servlet初始化配置信息

ServletConfig接口常用方法作用
String getInitParameter(“参数名”)根据初始化参数名获得参数值
Enumeration<String> getInitParameterNames()获得所有的初始化参数名
Enumeration是迭代器的前身
Enumeration接口的方法功能
boolean hasMoreElements()判断是否有下一个元素,有则返回true,否则falase
E nextElement()获得下一个元素

8.HTTP协议概述

1.HTTP 协议的概念:

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

​ 作用:用业务传输超文本。HTML 超文本标记语言

2.HTTP协议得特点:

​ 1.无状态:协议对客户端没有状态存储,对事务处理没有“记忆”能力。

​ 2.无连接:HTTP/1.1 之前,由于无状态特点,每次请求需要通过 TCP 三次握手四次挥手,和服务器重新建立

​ 连接。比如某个客户机在短时间多次请求同一个资源,服务器并不能区别是否已经响应过用户的请求,所以

​ 每次需要重新响应请求,需要耗费不必要的时间和流量。

​ 3.基于请求和响应:基本的特性,由客户端发起请求,服务端响应

​ 4.简单快速、灵活

​ 5.通信使用明文、请求和响应不会对通信方进行确认、无法保护数据的完整性。

3.HTTP 请求:

1.什么是http请求

用于封装浏览器发送给服务器的所有数据,称为请求对象。在 JavaEE 中接口名:HttpServletRequest

查看HTTP请求

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>webpack</title>
</head>
<body>


<h2>GET 提交</h2>
<form action="login" method="get">
    用户名:
    <input type="text" name="username"><br/>
    密码:
    <input type="password" name="pwd"><br/>
    <input type="submit" value="登录">
</form>
<hr>
<h2>POST 提交</h2>
<form action="login" method="post">
    用户名:
    <input type="text" name="username"><br/>
    密码:
    <input type="password" name="pwd"><br/>
    <input type="submit" value="登录">
</form>

</body>
</html>

查看浏览器和服务器通讯

在这里插入图片描述

查看请求头和请求行请求体

在这里插入图片描述

小结:

1、什么是HTTP请求:浏览器发数据给服务器的过程则称为请求
	
2、HTTP请求的组成:
	请求行
  	请求头
  	请求体
1.请求行概述

由上图小结:

请求行格式:
  Post请求:POST /day25/login HTTP/1.1
  Get请求:GET /day25/login?username=jack&pwd=111 HTTP/1.1
  	
请求行组成:请求方式 请求地址 协议和版本
2.请求头概述

常见请求头

常见请求头作用
Referer服务器获取浏览器上一次访问的页面地址
If-Modified-Since服务器获得浏览器缓存页面的时间
User-Agent服务器获得客户端系统类型和浏览器类型
Connection服务器端获得连接状态
1.1 保存连接 keep alive
1.0 断开连接 closed
Host获得服务器地址和端口号

3.请求体概述

什么是请求体?

请求体就是用户输入得参数

注意post才有请求体

9.HttpServletRequest对象概述-[掌握]

HttpServletRequest对象是谁创建的?
  	由web容器负责创建
 HttpServletRequest对象的作用?
  	用来封装浏览器发送给服务器所有数据:请求行,请求头,请求体(请求参数)
1.获取请求行得相关方法[掌握]
HttpServletRequest对象方法功能描述
String getMethod()得到请求的方式 GET 或 POST
String getRequestURI()Uniform Resource Identifier 统一资源标识符,代表一个资源名字
StringBuffer getRequestURL()Uniform Resource Locator 统一资源定位符,代表一个可以访问地址
String getProtocol()得到协议和版本
package com.xjggb.servlet;


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(urlPatterns = "/demo01")
public class Demo01Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取请求方式
        String method = req.getMethod();
        System.out.println("请求方式 = " + method);

        //获取同一资源标识符
        String requestURI = req.getRequestURI();
        System.out.println("同一资源标识符" + requestURI);

        //同一资源定位符
        StringBuffer requestURL = req.getRequestURL();
        System.out.println("同一资源定位符 = " + requestURL);

        //得到协议和版本
        String protocol = req.getProtocol();
        System.out.println("得到协议和版本 = " + protocol);


        //客户端ip地址
        String remoteAddr = req.getRemoteAddr();
        System.out.println("客户端id地址 " + remoteAddr);

        String path = req.getContextPath();
        System.out.println("项目访问路径 = " + path);


    }
}

请求行信息

!(H:\学习笔记\java笔记\图片文件\servlet图片\请求行信息.jpg)

2.获取请求头信息

在这里插入图片描述

小结:

HttpServletRequest对象的方法功能说明
String getMethod() 常用获得请求方式
String getRequestURI()获得统一资源标识符
StringBuffer getRequestURL()获得统一资源定义符
String getProtocol()获得协议和版本
String getContextPath() 常用获得项目访问路径
String getRemoteAddr()获得浏览器客户端的IP地址
2.获取请求头相关方法-[掌握]

获取请求头方法

HttpServletRequest对象的方法功能描述
String getHeader(String headName)根据请求头名获得值
Enumeration getHeaderNames()获得所有请求头名称:返回迭代器对象
package com.xjggb.servlet;


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

@WebServlet(urlPatterns = "/demo01")
public class Demo01Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

      //设置内容编码
        resp.setContentType("text/html;charset=utf-8");

        //获得字符打印流
        PrintWriter out = resp.getWriter();


        //获取请求头
        String header = req.getHeader("user-agent");
        out.println("user-agent = " + header + "<hr>");

        // 获得所有请求头名称:迭代器
        Enumeration<String> it = req.getHeaderNames();
        // 遍历所有请求头名称
        while(it.hasMoreElements()) {
            // 获得请求头名称
            String headerName = it.nextElement();
            // 根据名称获得请求头的值
            String headerValue = req.getHeader(headerName);
            out.println(headerName + " = " + headerValue + "<br>");
        }

    }
}

3.获取请求参数相关方法-[掌握]

获取请求参数得方法

HttpServletRequest对象的方法描述
String getParameter(String name)根据参数名获得值
String[] getParameterValues(String name)根据参数名获得多个参数值
Enumeration getParameterNames()获得所有参数名:迭代器
Map<String,String[]> getParameterMap()获得所有参数信息:map集合
键:参数名
值:参数值

准备表单数据

<h2>用户注册</h2>
<form action="register" method="post">
    用户名: <input type="text" name="name"><br/>
    性别: <input type="radio" name="gender" value="" checked="checked"/><input type="radio" name="gender" value=""/><br/>
    城市:
    <select name="city">
        <option value="广州">广州</option>
        <option value="深圳">深圳</option>
        <option value="珠海">珠海</option>
    </select>
    <br/>
    爱好:
        <input type="checkbox" name="hobby" value="上网"/>上网
        <input type="checkbox" name="hobby" value="上学"/>上学
        <input type="checkbox" name="hobby" value="上车"/>上车
        <input type="checkbox" name="hobby" value="上吊"/>上吊
    <br/>
    <input type="submit" value="注册"/>
</form>
package com.xjggb.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet(urlPatterns = "/register")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        //设置内容编码
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        //获得字符打印流
        PrintWriter out = resp.getWriter();

        //获取用户名
        String username = req.getParameter("name");
        out.println("username = " + username + "<br>");

        //获取性别
        String gender = req.getParameter("gender");
        out.println("gender = " + gender + "<br>");



        //获得所有得爱好
        String[] hobbies = req.getParameterValues("hobby");
       out.print("所有得爱好"+ Arrays.toString(hobbies)+"<br>");




       //获取所有的参数

        Enumeration<String> parameterNames = req.getParameterNames();

        while (parameterNames.hasMoreElements()){

            String name = parameterNames.nextElement();

            //根据相关得参数获取参数值
            String[] parameterValues = req.getParameterValues(name);

            System.out.println("Arrays.toString(parameterValues) = " + Arrays.toString(parameterValues));



        }



      // 获得所有请求参数信息:Map集合  键:参数名  值:值


        Map<String, String[]> map = req.getParameterMap();

        Set<String> strings = map.keySet();

        for (String string : strings) {
            // 根据参数名获得参数值
            String[] values = req.getParameterValues(string);
            System.out.println(string  + " = " + Arrays.toString(values) + "<br>");
        }


    }
}

小结

获取参数得方法

HttpServletRequest对象的方法描述
String getParameter(String name)根据参数名获得值
String[] getParameterValues(String name)根据参数名获得多个参数值
Enumeration getParameterNames()获得所有参数名:迭代器
Map<String,String[]> getParameterMap()获得所有参数信息:map集合
键:参数名
值:参数值

10.BeanUtils工具使用-封装参数-[掌握]

导入依赖

在这里插入图片描述

实体类

package com.xjggb.entity;

import java.util.Arrays;

public class User {

    // 成员变量
    private String name;
    private String gender;
    private String[] hobby;
    private String city;


    public User() {
    }

    public User(String name, String gender, String[] hobby, String city) {
        this.name = name;
        this.gender = gender;
        this.hobby = hobby;
        this.city = city;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return gender
     */
    public String getGender() {
        return gender;
    }

    /**
     * 设置
     * @param gender
     */
    public void setGender(String gender) {
        this.gender = gender;
    }

    /**
     * 获取
     * @return hobby
     */
    public String[] getHobby() {
        return hobby;
    }

    /**
     * 设置
     * @param hobby
     */
    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }

    /**
     * 获取
     * @return city
     */
    public String getCity() {
        return city;
    }

    /**
     * 设置
     * @param city
     */
    public void setCity(String city) {
        this.city = city;
    }

    public String toString() {
        return "User{name = " + name + ", gender = " + gender + ", hobby = " + Arrays.toString(hobby) + ", city = " + city + "}";
    }
}


利用BeanUtils将表单参数封装到User对象中

package com.xjggb.servlet;

import com.xjggb.entity.User;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet(urlPatterns = "/register")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        //设置内容编码
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
      // 获得所有请求参数信息:Map集合  键:参数名  值:值

        User user = new User();

        Map<String, String[]> map = req.getParameterMap();


        try {
            System.out.println("封装前" + user);
            BeanUtils.populate(user, map);

            System.out.println("封装后" + user);

            /*
            * 封装前User{name = null, gender = null, hobby = null, city = null}
              封装后User{name = 小果哥, gender = 女, hobby = [上网, 上学, 上车, 上吊], city = 广州}
            * */
            


        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }


    }
}


小结

void populate(Object bean, Map<String, Object> properties)将Map集合的数据封装到bean对象中
map集合的key和bean对象的成员变量名相同。
BeanUtils常用方法作用

注意实体类得字段必须和接收得字段一样

11.参数的乱码问题-[掌握]

乱码原因:Tomcat默认使用欧洲码表:ISO-8859-1 不支持中文
解决方法:
  	1. 设置请求参数的编码为:utf-8
  		 request.setCharacterEncoding("utf-8");
	  2. 注意实现:必须在获取参数之前设置。
          
          
    2.设置响应乱码
            response.setContentType("text/html;charset=utf-8");

12.转发和重定向概述-[掌握]

1.转发和重定向得作用

​ 用于页面跳转,从一个页面跳到另一个页面

2.什么是转发

​ 概念:在在服务器进行页面跳转

​ 原理图

在这里插入图片描述

转发方法

request.getRequestDispatcher("/要跳转到的地址").forward(request, response);

1.转发特点

  1. 地址栏不会发生变化,显示的还是上一个地址。

  2. 请求次数:只有一次

  3. 根目录:表示服务器端的根目录。http://localhost:8080/项目的访问地址/

  4. 请求域中的数据不会丢失

重定向

什么是重定向?

概念:浏览器端进行得页面跳转

原理图:

在这里插入图片描述

重定向方法

response.sendRedirect("要跳转的地址")

重定向的特点:

  1. 地址栏:会变化,显示新的地址

  2. 请求次数: 2 次

  3. 根目录:浏览器端的根目录:http://localhost:8080/

  4. 请求域:丢失,因为不是同一次请求

6.3.4 什么时候使用转发,什么时候使用重定向?

 如果需要保留请求域中的数据,使用转发,否则使用重定向。

1.转发

oen 跳转到 two

oen 得代码

package com.xjggb.servlet;


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(urlPatterns = "/oen")
public class OneServlet extends HttpServlet {

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

        //转发到two
        //获得转发器
        req.getRequestDispatcher("/two").forward(req,resp);
    }
}


two得代码

package com.xjggb.servlet;

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

@WebServlet(urlPatterns = "/two")
public class TwoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {


        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();

        out.print("我是two");


    }


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


2.重定向
package com.xjggb.servlet;


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(urlPatterns = "/oen")
public class OneServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//
//        //转发到two
//        //获得转发器
//        req.getRequestDispatcher("/two").forward(req,resp);


        //转发
        resp.sendRedirect("/two");




    }
}


package com.xjggb.servlet;

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

@WebServlet(urlPatterns = "/two")
public class TwoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {


        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();

        out.print("我是two");


    }


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

13.请求域有关的方法

1.什么是作用域?

  1. 什么是作用域: 用于 Servlet 之间数据共享的服务器内存区域,作用域结构是一个 Map<String, Object>
  2. 三个作用域:在 Servlet 中一共有三个作用域:请求域、会话域、上下文域
  3. 请求域的范围:只在同一次请求中起作用

在这里插入图片描述

作用域方法

request与域有关的方法作用
Object getAttribute(“键”)从请求域中获取一个值
void setAttribute(“键”,Object 数据)向请求域中放一个键值对
void removeAttribute(“键”)删除请求域中的一对键和值

作用域操作

package com.xjggb.servlet;


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(urlPatterns = "/oen")
public class OneServlet extends HttpServlet {

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


        ///向请求域中添加键和值
        req.setAttribute("key","values+ 我是oen哦");

        //转发到two
        //获得转发器

      //  req.getRequestDispatcher("/two").forward(req,resp);



        //重定向
        resp.sendRedirect("/two");




    }
}


package com.xjggb.servlet;

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

@WebServlet(urlPatterns = "/two")
public class TwoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {


        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();

        String  key = (String) req.getAttribute("key");


        out.print(key);


    }


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


小结:

请求域只能在同一个请求使用,

重定向使用就会失效

14.HTTP响应概述-[掌握]

在这里插入图片描述

小结

1. HTTP响应的组成内容有:
  	响应行
  	响应头
  	响应体

1.常见得响应码
状态码含义
302代表页面重定向
200服务器正常响应数据,没有问题
304服务器告诉浏览器使用本地缓存
404服务器告诉浏览器请求的资源不存在
405浏览器使用get或post请求时,服务器端没有对应的doGet或doPost方法
500服务器代码出现了异常

1.3 小结

1. 响应行的组成内容有: 协议和版本  状态码  状态描述信息

2.响应头概述

1.1 目标

掌握常见响应头的含义

1.2 小结

常见响应头信息说明
Location: http://www.baidu.com重定向的页面地址
Server:apache tomcat服务器的名称
Content-Encoding: gzip服务器告诉浏览器响应内容的压缩格式
Content-Length: 80服务器返回内容的长度,单位:字节
Content-Type: text/html; charset=utf-8服务器告诉浏览器返回内容的类型和编码
Refresh: 1;url=/day29/hello.html服务器告诉浏览器1秒进行页面跳转
Content-Disposition: attachment; filename=abc.zip用于文件下载
服务器告诉浏览器内容的处理方式
attachment:以附件形式处理
filename:文件名
3.设置响应体概述

响应体数据的格式

文本:字符串
二进制:图片,音频,视频等内容

服务器响应数据的方式描述
OutputStream getOutputStream()获得字节输出流
可以输出任意类型的数据
PrintWriter getWriter()获得字符输出流
只能文本内容的数据

小结:

什么是响应体:服务器返回给浏览器显示的数据

服务器响应数据的方式:
		字节输出流:可以输出任意类型的数据
		字符输出流:只能文本内容的数据

15.response设置响应行状态码-[掌握]

/**
 * 目标:通过response设置状态码
 */
@WebServlet(urlPatterns = "/status")
public class SetStatusServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // 设置内容类型和编码
         response.setContentType("text/html;charset=utf-8");
         // 获得字符打印流
         PrintWriter out = response.getWriter();
         out.println("设置了状态码为404");
         // 单独设置状态码没有意义,一般会结合具体的功能设置
         response.setStatus(404);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

1.3 小结

response对象设置状态码方法描述
void setStatus(int status)设置状态码

16.response设置响应头方法介绍-[掌握]

response对象与设置响应头相关方法描述
void setHeader(String name, String value)设置响应头
name:响应头名称
value:响应头的值
void setContentType(String type)专门用来设置响应头:Content-Type
response.setContentType(“值”) 和 response.setHeader(“Content-Type”,“值”)等价的

17.响应头使用演示01-refresh-[理解]

通过response设置响应头refresh实现3秒后进行页面跳转

1.2 需求说明

  • 过3秒跳转到另一个网站

1.3 实现步骤

  • 创建 RefreshServlet
  • 调用 setHeader,设置响应头:("refresh","3;url=http://www.itcast.cn")
  • 调用 setStatus,设置响应状态码 200(可选)。
/**
    目标:通过response设置响应头refresh实现3秒后进行页面跳转
 */
@WebServlet(urlPatterns = "/refresh")
public class RefreshServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // 设置内容类型和编码
         response.setContentType("text/html;charset=utf-8");
         // 获得字符打印流
         PrintWriter out = response.getWriter();
         out.println("<script src='js/outer.js'></script>");
         out.println("<span id='time'>3</span>秒后进行页面跳转");
        /**
            <script src='js/outer'></script>
            <body>
                <span id='time'>3</span>秒后进行页面跳转
             </body>
         */
        // 设置响应头refresh:实现3秒后进行页面跳转
         response.setHeader("refresh", "3;www.baidu.com");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

小结

服务器可以通过设置哪个响应头实现浏览器在指定的时间后进行页面跳转?
	通过设置refresh响应头:response.setHeader("refresh", "3;www.baidu.com");

18.响应头使用演示02-location-[理解]

不正确,是重定向,不是转发

19.响应头使用演示03-Content-Encoding-[理解]

1.3 GZIPOutputStream类的方法

构造方法说明
GZIPOutputStream(OutputStream out)对传入的输出流进行压缩
并且使用这个传入的输出流输出数据
GZIPOutputStream类的方法说明
public void write(byte[] b)输出字节数组内容
使用GZIP格式对内容进行压缩
void finish()告诉浏览器输出完成并关闭流释放资源

实现步骤

  1. 如果需要对数据进行压缩,需要使用压缩流,将响应的输出流做为参数。
  2. 使用压缩流的write方法:首先会对数据进行压缩处理,然后调用传递进去OutputStream对象的write方法把压缩的数据写出去。
  3. 完成将压缩数据写入输出流的操作,如果没有调用结束的方法,则浏览器上看不到东西。

注意事项

要设置相应响应头信息,告诉浏览器目前内容是以压缩包的形式传输的,不然就会以附件的方式下载下来了。

response.setHeader("Content-Encoding","gzip")

package com.xjggb.servlet;


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.zip.GZIPOutputStream;

@WebServlet(urlPatterns = "/ced")
public class ContentEncodingServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        // 1. 准备要压缩的数据
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 5000; i++) {
            sb.append("abcde"); // 25000
        }
        System.out.println("输出内容的长度:" + sb.toString().length());
        // 2. 设置响应头Content-Encoding:告诉浏览器返回内容的压缩格式
        resp.setHeader("Content-Encoding","gzip");
        // 3. 创建压缩输出流对象:GZIPOutputStream
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(resp.getOutputStream());
        // 4. 调用write方法输出数据
        gzipOutputStream.write(sb.toString().getBytes());
        // 5. 调用finish方法:告诉浏览器数据传输完毕并关闭流释放资源
       gzipOutputStream.finish();

    }

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


小结

服务器如何实现内容压缩返回给浏览器显示:
	1. 设置响应头Content-Encoding:告诉浏览器返回内容的压缩格式
	2. 通过响应对象获得字节输出流:OutputStream
	3. 创建压缩输出字节流:传递字节输出流
	4. 调用压缩输出流的write方法:输出数据:方法内部会对数据进行压缩
	5. 调用压缩输出流的finish方法:告诉浏览器数据传输完毕并关闭流释放资源

20.ServletContext上下文对象概述-[掌握]

ServletContext的概述

​ ServletContext对象又称上下文对象,服务器会为每一个工程创建一个ServletContext对象,ServletContext是一个容器(域对象)可以存储键值对数据,保存在ServletContext中的数据可以在整个项目中所有Servlet中共享。这个对象是全局唯一的(一个工程一个)。

小结

1. ServletContext对象的作用
  	* 用来操作web目录下的资源文件
  	* 用于项目中的所有Servlet共享数据
  	* 用来获得全局的配置参数

2. 如何获取ServletContext对象
		直接在Servlet方法中调用getServletContext方法获取

1.读取WEB-INF下的资源返回-[掌握]
package com.xjggb.servlet;


import javax.servlet.ServletContext;
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.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPOutputStream;

@WebServlet(urlPatterns = "/ced")
public class ContentEncodingServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

/**
 目标:能够使用ServletContext对象读取资源文件数据并返回给浏览器

 实现步骤:
 1. 通过response对象:获得字节输出流对象:OutputStream
 2. 获得上下文对象:ServletContext对象
 3. 调用上下文对象的方法获得字节输入流关联资源文件:InputStream
 4. 使用循环读写文件
 4.1 创建字节数组:用来存储读取到的图片数据
 4.2 定义整形变量:接收实际读取到的字节个数
 4.3 循环读取图片数据
 4.4 使用字节输出流输出数据到浏览器端
 */


       //1. 通过response对象:获得字节输出流对象:OutputStream

        ServletOutputStream outputStream = resp.getOutputStream();

        //2. 获得上下文对象:ServletContext对象
        ServletContext context = getServletContext();
        //3. 调用上下文对象的方法获得字节输入流关联资源文件:InputStream

//        String realPath = context.getRealPath("WEB-INF/pt/aaa.jpg");
//        System.out.println("realPath = " + realPath);
//        FileInputStream fileInputStream = new FileInputStream(realPath);
//        System.out.println("fileInputStream = " + fileInputStream);

        InputStream resourceAsStream = context.getResourceAsStream("WEB-INF/pt/aaa.jpg");
        System.out.println("resourceAsStream = " + resourceAsStream);


        //4. 使用循环读写文件

        //4.1 创建字节数组:用来存储读取到的图片数据
        byte[] bytes = new byte[1024];

        int len;
        while ((len=resourceAsStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
        }

       //4.2 定义整形变量:接收实际读取到的字节个数
       //4.3 循环读取图片数据
       //4.4 使用字节输出流输出数据到浏览器端
    }

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


2.Utils工具类优化

在这里插入图片描述

IOUtils工具类的方法功能
copy(InputStream in, OutputStream out)将字节输入流写到字节输出流中
  • 优化后代码
package com.xjggb.servlet;


import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
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.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPOutputStream;

@WebServlet(urlPatterns = "/ced")
public class ContentEncodingServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {



        ServletOutputStream outputStream = resp.getOutputStream();

        ServletContext context = getServletContext();
        //3. 调用上下文对象的方法获得字节输入流关联资源文件:InputStream

        String realPath = context.getRealPath("WEB-INF/pt/aaa.jpg");
        System.out.println("realPath = " + realPath);
        FileInputStream fileInputStream = new FileInputStream(realPath);
        System.out.println("fileInputStream = " + fileInputStream);

     //   InputStream resourceAsStream = context.getResourceAsStream("WEB-INF/pt/aaa.jpg");

        // 4. 通过工具类的copy方法实现文件输出传输
        IOUtils.copy(fileInputStream,outputStream);

    }

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


1.4 小结

ServletContext与读取项目资源文件相关方法功能
InputStream getResourceAsStream(String path)根据资源文件路径获得字节输入流
String getRealPath(String path)获得资源文件部署到服务器上的真实路径
3.统计用户登录数量-[掌握]
<%--
  Created by IntelliJ IDEA.
  User: lenovo
  Date: 2021/8/7
  Time: 23:03
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <h2>用户注册</h2>
  <!--login 是一个 servlet-->
  <h2>用户登录</h2>
  <form action="http://localhost:8080/logins" method="post">
      用户名:
      <input type="text" name="username"><br/>
      密码:
      <input type="password" name="password"><br/>
      <input type="submit" value="登录">
  </form>
  </body>
</html>


package com.xjggb.servlet;


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

@WebServlet(urlPatterns = "/logins")
public class LoginServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        // 在init方法中往上下文域中存储键值对:count=0
        ServletContext servletContext = getServletContext();
        servletContext.setAttribute("count",0);

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        System.out.println(" 来了吗老四");

        // 1. 获取请求参数:用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 2. 判断用户名和密码是否正确(实际开发需要查询数据)
        if ("admin".equals(username) && "password".equals(password)){
            // 3. 如果正确
            // 3.1 获得上下文对象
            ServletContext context = this.getServletContext();
            // 3.2 从上下文域中获取在线人数,对人数加一,在存储到上下文域
            Integer count = (Integer) context.getAttribute("count");
            context.setAttribute("count", count+1);
            // 3.3 重定向跳转到欢迎页面:显示在线人数
            response.sendRedirect("/welcomel");
        }else {

            // 4. 如果不正确:则跳转登录页面
            request.getRequestDispatcher("/index.jsp").forward(request, response);
        }



    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

package com.xjggb.servlet;


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

@WebServlet(urlPatterns = "/welcomel")
public class CountServlet extends HttpServlet {


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

        // 设置内容类型和编码
        resp.setContentType("text/html;charset=utf-8");

        //获取输出流
        PrintWriter out = resp.getWriter();

        Object count = getServletContext().getAttribute("count");
        out.print(count);


    }

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


小结:

1. 上下文域的作用范围 : 在整个项目有效

2. 上下文域存取数据相关的方法
		setAttribute(String key,Object value)
  	getAttribute(String key)
  	removeAttribute(String key)
4.读取全局的配置参数-[了解]

1.2 相关方法

ServletContext获得全局参数的方法功能
String getInitParameter(String name)通过参数名得到全局的参数值
Enumeration<String> getInitParameterNames()得到所有全局参数的名字

1.3 需求说明

  • 在web.xml中设置2个全局的参数,username=pkxing, age=18
  • 在不同的Servlet中使用上面两个方法去获取这2个值。

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>config</servlet-name>
      <servlet-class>com.xjggb.servlet.ConfigServlet</servlet-class>



    <!--配置全局初始化参数-->
    <context-param>
        <param-name>username</param-name>
        <param-value>rose</param-value>
    </context-param>

    <context-param>
        <param-name>age</param-name>
        <param-value>20</param-value>
    </context-param>
    
    
    
    
</web-app>
package com.xjggb.txt;


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

@WebServlet(urlPatterns = "/pam")
public class ReadGlobalParamServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置内容类型和编码
        resp.setContentType("text/html;charset=utf-8");
        // 获得字符打印流
        PrintWriter out = resp.getWriter();

        //获取上下文
        ServletContext context = getServletContext();

        //根据初始化参数名获取值
        String username = context.getInitParameter("username");
        out.print("用户名"+username +"</br>");



        //获取所有得参数得参数名
        Enumeration<String> initParameterNames = context.getInitParameterNames();

        while (initParameterNames.hasMoreElements()){
            String s = initParameterNames.nextElement();

            //根据参数名获得值
            String initParameter = context.getInitParameter(s);
            out.print(initParameter);
        }


    }

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


1.5 小结

1.获取一个参数 : String getInitParameter(String name)

2.获取多个参数: Enumeration<String> getInitParameterNames()

3.判断是否还有元素: boolean hasMoreElements(); 有就是true 没有就是faluss

4.获取元素: E nextElement();

5.文件下载-使用超链接下载[了解]

在这里插入图片描述

下载页面

<!DOCTYPE html>
<html>
<head>
    <title>资源下载列表</title>
    <meta charset="utf-8">
</head>
<body>
<h2>文件下载页面列表</h2>
<h3>超链接的下载</h3>
<a href="download/file.txt">文本文件</a><br/>
<a href="download/file.jpg">图片文件</a><br/>
<a href="download/file.zip">压缩文件</a><br/>
<hr/>
<h3>手动编码的下载方式</h3>
<a href="down?filename=file.txt">文本文件</a><br/>
<a href="down?filename=file.jpg">图片文件</a><br/>
<a href="down?filename=file.zip">压缩文件</a><br/>
<a href="down?filename=美女.jpg">美女</a><br/>
</body>
</html>

小结:

1. 使用超链接下载文件存在的不足
	 1.1 不是所有文件都是下载,有些文件直接在浏览器上显示
   1.2 文件地址直接暴露在地址栏上,有可能会被盗链
   1.3 无法进行业务逻辑的判断,比如下载扣积分

6.文件下载-使用Servlet下载-[掌握]
  1. 从链接上得到文件名
  2. 设置 Content-disposition 头
  3. 得到文件的输入流
  4. 得到 response 的输出流
  5. 写出到浏览器端
package com.xjggb.txt;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

@WebServlet(urlPatterns = "/down")
public class DownloadServlet extends HttpServlet {

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

/**
 *  目标:使用Servlet实现文件下载

 实现步骤:
 1. 接收请求参数filename:要下载的文件名
 2. 获得上下文对象
 3. 设置响应头Content-Dispostion:告诉浏览器内容的处理方式
 4. 通过上下文对象的方法获得字节输入流:关联要下载的文件
 5. 通过响应对象获得字节输出流:用来返回数据给浏览器端
 6. 调用IOUtils工具类的copy方法完成文件输出的传输
 */


        //接收请求参数
        String filename = req.getParameter("filename");


        //获取上下文对象
        ServletContext context = this.getServletContext();
        // 3. 设置响应头Content-Dispostion:告诉浏览器内容的处理方式
        resp.setHeader("Content-Disposition", "attachment;filename="+filename);
        //通过上下文对象获得字节输入流,
        InputStream in = context.getResourceAsStream("download/" + filename);
        // 5. 通过响应对象获得字节输出流:用来返回数据给浏览器端
        OutputStream out = resp.getOutputStream();
        // 6. 调用IOUtils工具类的copy方法完成文件输出的传输
        IOUtils.copy(in, out);

    }

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


        this.doPost(req,resp);

    }
}


小结:

使用Servlet实现下载功能需要设置哪个响应头:
	设置Content-Disposition:response.setHeader("Content-Disposition", "attachment;filename="+filename);

7.下载文件名中文乱码问题分析-[理解]
URL编码相关方法描述
java.net.URLEncoder.encode(“字符串”, “utf-8”)使用UTF8对字符串进行编码
java.net.URLDecoder.decode(“字符串”, “utf-8”)使用UTF8对字符串进行解码

1.4 演示:对中文进行编码和解码文件名中文乱码问题分析-[理解]

对中文进行编码和解码

package com.itheima._05文件下载;

import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * @Package com.itheima._05文件下载
 * @Author pkxing
 * @Date 2019-11-22 15:11
 * @Version 1.0
 */
public class Demo {
    public static void main(String[] args)throws Exception{
        // 定义字符串
        String str = "美女";
        // 对字符串进行URL编码
        String encode = URLEncoder.encode(str, "utf-8");
        System.out.println("编码结果:" + encode);

        // 对字符串进行URL解码
        String decode = URLDecoder.decode(encode, "utf-8");
        System.out.println("解码结果:"  + decode);
    }
}

小结:

1. 下载文件中文名乱码的原因
Http协议规定响应头的值不能包含中文,如果文件名包含中文,则Tomcat内部会对响应头的值进行处理:
    使用欧洲码表IS0-8859-1进行编码,浏览器接收到响应头时会对值进行解码:不同的浏览器解码使用码表是不一致的,chrome浏览器使用的码表是utf-8,所以乱码因为编码和解码的码表不一致导致的。
  
2. 如何解决下载中文名乱码问题
		1.1Servlet中手动对文件名进行URL编码
  	1.2 将编码后的结果添加到响应头中返回给浏览器
  	1.3 浏览器接收到响应头时会对内容进行URL解码


8.文件下载-Servlet代码-无乱码-[掌握]
package com.xjggb.txt;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Base64;

@WebServlet(urlPatterns = "/down")
public class DownloadServlet extends HttpServlet {

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

/**
 *  目标:使用Servlet实现文件下载

 实现步骤:
 1. 接收请求参数filename:要下载的文件名
 2. 获得上下文对象
 3. 设置响应头Content-Dispostion:告诉浏览器内容的处理方式
 4. 通过上下文对象的方法获得字节输入流:关联要下载的文件
 5. 通过响应对象获得字节输出流:用来返回数据给浏览器端
 6. 调用IOUtils工具类的copy方法完成文件输出的传输
 */


        //接收请求参数
        String filename = req.getParameter("filename");


        //获取上下文对象
        ServletContext context = this.getServletContext();
        //通过上下文对象获得字节输入流,
        InputStream in = context.getResourceAsStream("download/" + filename);


        // 获得请求头中的User-Agent
        String agent = req.getHeader("User-Agent");
        // 根据不同的客户端进行不同的编码
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            filename = "=?utf-8?B?" + Base64.getEncoder().encodeToString(filename.getBytes("utf-8"))+"?=";
        } else if(agent.contains("Safari") && !agent.contains("Chrome")){
            // Safari浏览器:Chrome头也包含safari,需要排除Chrome
            byte[] bytesName = filename.getBytes("UTF-8");
            filename = new String(bytesName, "ISO-8859-1");
        } else {
            // Chrome以及其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }




        // 3. 设置响应头Content-Dispostion:告诉浏览器内容的处理方式
        resp.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(filename, "utf-8"));


       


        // 5. 通过响应对象获得字节输出流:用来返回数据给浏览器端
        OutputStream out = resp.getOutputStream();


        // 6. 调用IOUtils工具类的copy方法完成文件输出的传输
        IOUtils.copy(in, out);

    }

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


        this.doPost(req,resp);

    }
}


解决下载中文乱码

如何解决下载中文名乱码
	  	   1.1Servlet中手动对文件名进行URL编码
         1.2 将编码后的结果添加到响应头中返回给浏览器
         1.3 浏览器接收到响应头时会对内容进行URL解码

21.会话概述-[理解]

会话技术的作用

用来保存会话过程产生的数据:比如验证码,购物车的数据

​ 每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,程序要想办法为每个用户保存这些数据。

HTTP是**"无状态"协议:服务器不记录上次请求的内容是什么用户是谁,因此如果判断两次连接是否是同一用户,就需要使用会话跟踪**技术来解决。

1.3 小结

会话技术概述
Cookie客户端会话技术:将数据保存浏览器端
Session服务器端会话技术:将数据保存服务器端

22.Cookie使用演示-[掌握]

需求:在Servlet中创建一个Cookie(“user”,“jack”),并且写到浏览器

package com.xjggb.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.io.PrintWriter;

@WebServlet(urlPatterns = "/save")
public class SaveCookiesServlet extends HttpServlet {



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


        //设置内容类型
        resp.setContentType("text/html;charset=utf-8");

        // 获得字符打印流
        PrintWriter out = resp.getWriter();
        out.println("往浏览器返回了一个Cookie对象");



        //创建Cookie对象
        Cookie cookie = new Cookie("user","jack");

        resp.addCookie(cookie);


    }
}


小结

1. 使用Cookie保存会话数据的步骤
	1. 创建Cookie对象:存储键值对数据
	2. 将cookie对象返回给浏览器端
	
2. Cookie类常用方法
	 Cookie c = new Cookie(String name,String value);
	 String name = c.getName(); 获得Cookie的名称
	 String value = c.getValue(); 获得Cookie的值
	 
3. 返回Cookie的方法
		response.addCookie(c);

23.设置Cookie过期时间-[掌握]

package com.xjggb.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.io.PrintWriter;

@WebServlet(urlPatterns = "/save")
public class SaveCookiesServlet extends HttpServlet {



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


        //设置内容类型
        resp.setContentType("text/html;charset=utf-8");

        // 获得字符打印流
        PrintWriter out = resp.getWriter();
        out.println("往浏览器返回了一个Cookie对象");

        //创建Cookie对象
        Cookie cookie = new Cookie("user","jack");
        // 设置cookie的过期时间:单位秒
        cookie.setMaxAge(1*24*60*60);

        resp.addCookie(cookie);


    }
}


小结

如何设置Cookie的过期时间
	调用setMaxAge方法设置:传递一个整数
		正数:代表在指定的秒数之后过期
		负数:无效,浏览器关闭就过期
		零:代表删除Cookie

24.服务器端读取Cookie数据-[掌握]

创建两个Servlet,一个往浏览器写入cookie,一个读取浏览器传递的cookie并显示页面上。

package com.xjggb.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.io.PrintWriter;

@WebServlet(urlPatterns = "/set")
public class SetCookieServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //设置内容编码
        resp.setContentType("text/html;charset=utf-8");

        // 获得字符打印流
        PrintWriter out = resp.getWriter();
        out.println("往浏览器端返回了cookie数据");
        // 创建Cookie对象
        Cookie c = new Cookie("product", "iPhone");
        // 设置过期时间
        c.setMaxAge(24*60*60);
        // 返回给浏览器端
        resp.addCookie(c);

    }

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


package com.xjggb.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.io.PrintWriter;

@WebServlet(urlPatterns = "/get")
public class GetCookieServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 设置内容类型和编码
        resp.setContentType("text/html;charset=utf-8");
        // 获得字符打印流
        PrintWriter out = resp.getWriter();

        Cookie[] cookies = req.getCookies();

        if (cookies!=null){

            for (Cookie cookie : cookies) {
                //获取key得名称
                String name = cookie.getName();

                //获得Cookie的值
                String value = cookie.getValue();
                out.println(name +"="+value+"</br>");


            }

        }



    }

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


25.设置Cookie的有效路径-[掌握]

package com.xjggb.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(urlPatterns = "/setPath")
public class SetCookiePathServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 创建Cookie对象
        Cookie cookie = new Cookie("username", "rose");

        System.out.println(" = " +req.getContextPath());
        // 设置有效路径:默认是当前项目的访问路径
        cookie.setPath(req.getContextPath() + "/login");
        // 返回给浏览器端
        resp.addCookie(cookie);


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}


26.Cookie案例-实现自动登录-[掌握]

/**
    目标:使用Cookie记录用户名和密码,实现自动登录功能

    实现步骤:
        1. 接收请求参数:用户名和密码,记住我
        2. 创建业务层对象
        3. 调用业务层登录方法执行登录并获得User对象
        4. 如果User对象不为null则代表登录成功
            判断是否勾选了记住我复选框,如果勾选了则执行以下代码:
            4.1 创建Cookie对象保存用户名
            4.2 设置Cookie对象的过期时间:一周
            4.3 返回Cookie对象给浏览器
            ...

            4.4 跳转到欢迎页面:显示用户名

        5. 如果User对象为null则代表登录失败
            5.1 跳转到登录页面即可

 */
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 接收请求参数:用户名和密码,记住我
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String remember = request.getParameter("remember");
        System.out.println("remember = " + remember); // null
        // 2. 创建业务层对象
        UserService us = new UserService();
        // 3. 调用业务层登录方法执行登录并获得User对象
        User user = us.login(username, password);
        // 4. 如果User对象不为null则代表登录成功
        if (user != null) {
            // 判断是否勾选了记住我复选框,如果勾选了则执行以下代码:
            if (remember != null) {
                // 4.1 创建Cookie对象保存用户名
                Cookie uCookie = new Cookie("username", username);
                // 4.2 设置Cookie对象的过期时间:一周
                uCookie.setMaxAge(7 * 24 * 3600);
                // 4.3 返回Cookie对象给浏览器
                response.addCookie(uCookie);

                // 4.4 创建Cookie对象保存密码
                Cookie pCookie = new Cookie("password", password);
                // 4.5 设置Cookie对象的过期时间:一周
                pCookie.setMaxAge(7 * 24 * 3600);
                // 4.6 返回Cookie对象给浏览器
                response.addCookie(pCookie);
            }
            // 4.4 跳转到欢迎页面
            response.sendRedirect("success.html");
            return;
        }
        // 5. 如果User对象为null则代表登录失败:跳转到失败页面即可
        response.sendRedirect("failure.html");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

27.Cookie中使用非法字符-[掌握]

/**
    目标:使用Cookie记录用户名和密码,实现自动登录功能

    实现步骤:
        1. 接收请求参数:用户名和密码,记住我
        2. 创建业务层对象
        3. 调用业务层登录方法执行登录并获得User对象
        4. 如果User对象不为null则代表登录成功
            判断是否勾选了记住我复选框,如果勾选了则执行以下代码:
            4.1 创建Cookie对象保存用户名
            4.2 设置Cookie对象的过期时间:一周
            4.3 返回Cookie对象给浏览器
            ...

            4.4 跳转到欢迎页面:显示用户名

        5. 如果User对象为null则代表登录失败
            5.1 跳转到登录页面即可

 */
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 接收请求参数:用户名和密码,记住我
        String username = URLDecoder.decode(request.getParameter("username"), "utf-8");  // 对用户名进行URL解码
        String password = request.getParameter("password");
        String remember = request.getParameter("remember");
        System.out.println("remember = " + remember); // null
        // 2. 创建业务层对象
        UserService us = new UserService();
        // 3. 调用业务层登录方法执行登录并获得User对象
        User user = us.login(username, password);
        // 4. 如果User对象不为null则代表登录成功
        if (user != null) {
            // 判断是否勾选了记住我复选框,如果勾选了则执行以下代码:
            if (remember != null) {
                // 4.1 创建Cookie对象保存用户名
                // 对用户名进行URL编码
                String encode = URLEncoder.encode(username, "utf-8");
                Cookie uCookie = new Cookie("username", encode);
                // 4.2 设置Cookie对象的过期时间:一周
                uCookie.setMaxAge(7 * 24 * 3600);
                // 4.3 返回Cookie对象给浏览器
                response.addCookie(uCookie);

                // 4.4 创建Cookie对象保存密码
                Cookie pCookie = new Cookie("password", password);
                // 4.5 设置Cookie对象的过期时间:一周
                pCookie.setMaxAge(7 * 24 * 3600);
                // 4.6 返回Cookie对象给浏览器
                response.addCookie(pCookie);
            }
            // 4.4 跳转到欢迎页面
            response.sendRedirect("success.html");
            return;
        }
        // 5. 如果User对象为null则代表登录失败:跳转到失败页面即可
        response.sendRedirect("failure.html");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

1.3 小结

如何在Cookie中包含非法字符
	1. 先对包含非法字符的字符串进行URL编码
  2. 将编码后的结果存储到Cookie值中并返回给浏览器
  3. 服务器接收到Cookie值时需要进行URL解码

URL编码与解码相关方法说明
java.net.URLEncoder.encode(“字符串”,“utf-8”)使用utf-8对字符串进行编码
java.net.URLDecoder.decode(“字符串”,“utf-8”)使用utf-8对字符串进行解码

28_删除Cookie-[掌握]


/**
 * 目标:删除浏览器端保存的cookie数据

   步骤:
      没有直接删除的方法
        1. 创建一个Cookie对象:名称和有效路径必须和要删除的cookie相同,值无所谓
        2. 设置Cookie过期时间为0
        3. 返回Cookie给浏览器端
 */
@WebServlet(urlPatterns = "/delete")
public class DeleteCookiesServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // 设置内容类型和编码
         response.setContentType("text/html;charset=utf-8");
         // 获得字符打印流
         PrintWriter out = response.getWriter();
         out.println("删除了Cookie");
        // 1. 创建一个Cookie对象:名称和有效路径必须和要删除的cookie相同,值无所谓
        Cookie c = new Cookie("product", "");
        c.setPath(request.getContextPath());
        // 2. 设置Cookie过期时间为0
        c.setMaxAge(0);
        // 3. 返回Cookie给浏览器端
        response.addCookie(c);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

小结

如何删除浏览器端的Cookie信息
	1. 创建同名的Cookie对象:有效路径要一致
	2. 设置过期时间为0
	3. 返回给浏览器端
	
Cookie的基本使用
	Cookie的作用:保存服务器发送给浏览器的数据
	服务器返回Cookie数据给浏览器
		1. 创建Cookie对象:封装键值对数据
		   Cookie c = new Cookie("键","值");
		2. 设置过期时间
        c.setMaxAge(60);
    3. 设置有效路径
      	c.setPath("/项目访问路径/子路径");
		4. 返回给浏览器保存
      	response.addCookie(c);


	服务器读取浏览器发送的Cookie数据
    	1. 调用request对象的方法获得Cookie数据
    		Cookie[] cookies = request.getCookies();
		 	2. 遍历Cookie数组,获得每一个Cookie对象
      3. 调用Cooke对象的方法获得名称和值
        	String getName() 获得名称
        	String getValue() 获得值

29.session概述和应用场景-[理解]

1.session使用演示-[掌握]

1.使用session保存会话数据

/**
 *  目标:使用session保存会话数据
    需求:
     - 在一个 SetServlet 中,向Session 中添加一件商品名:洗衣机
        另一个GetServlet 从 Session 中取出商品并输出在网页上。
     - 使用一个浏览器存,另一个浏览器取,看能不能取出来。
 */
@WebServlet(urlPatterns = "/saveSession")
public class SetServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // 设置内容类型和编码
         response.setContentType("text/html;charset=utf-8");
         // 获得字符打印流
         PrintWriter out = response.getWriter();
         out.println("往会话域中存储了数据");
         // 获得会话域对象
         HttpSession session = request.getSession();
         // 往会话域中存储数据
         session.setAttribute("product", "洗衣机");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

2.使用session取会话数据

/**
 *  目标:从会话域中获取商品数据显示
 */
@WebServlet(urlPatterns = "/getSession")
public class GetServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // 设置内容类型和编码
         response.setContentType("text/html;charset=utf-8");
         // 获得字符打印流
         PrintWriter out = response.getWriter();

        // 获得会话域对象
        HttpSession session = request.getSession();
        // 从会话域中获得商品名称
        Object product = session.getAttribute("product");
        out.println("product = " + product); // 洗衣机
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

小结:

使用session保存会话数据的步骤
	1. 获得会话域对象:HttpSession session = request.getSession();
	2. 调用会话域对象的方法存储数据:session.setAttribute(String key,Object values);

2.session技术运行原理-[理解]

在这里插入图片描述

小结

1. 浏览器第1次访问服务器没有会话ID
2. 服务器端获取会话域对象并存储数据:服务器就将会话ID以Cookie形式返回给浏览器端
3. 浏览器接收到Cookie数据会保存起来
4. 浏览器再次访问服务器时会以请求头形式携带会话ID给服务器:服务器可以通过会话ID查找到对应的内存区域:从而进行数据的增删改查操作

3.session常用方法演示-[掌握]

方法展示

HttpSession接口方法作用
String getId()获得会话ID
long getCreationTime()获得会话的创建时间,毫秒值
long getLastAccessedTime()获得会话上次访问时间,毫秒值
boolean isNew()判断是否是新会话
ServletContext getServletContext()获得上下文对象
package com.xjggb.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;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

@WebServlet(urlPatterns = "/method")
public class SessionMethodServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {

        // 设置内容类型和编码
        response.setContentType("text/html;charset=utf-8");
        // 获得字符打印流
        PrintWriter out = response.getWriter();
        //获取会话域对象
        HttpSession session = req.getSession();
        //会话id
        out.println("会话ID"+session.getId()+"<hr>");
        // 会话创建时间
        long creationTime = session.getCreationTime();
        Date createDate = new Date(creationTime);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String createDateStr = sdf.format(createDate);
        out.println("会话创建时间:" + createDateStr + "<hr>");

        // 上次访问的时间
        Date lastAccessedDate = new Date(session.getLastAccessedTime());
        String lastAccessedDateStr = sdf.format(lastAccessedDate);
        out.println("上次访问的时间:" + lastAccessedDateStr + "<hr>");
        // 是否是新的会话
        out.println("是否是新的会话:" + session.isNew() + "<hr>");
        // 上下文对象
        out.println("上下文对象:" + session.getServletContext() + "<hr>");
        out.println("上下文对象:" + this.getServletContext() + "<hr>");


        //是否是新会话
        out.println("是否能是新会话"+session.isNew()+"<hr>");

        // 上下文对象
        out.println("上下文对象:" + session.getServletContext() + "<hr>");
        out.println("上下文对象:" + this.getServletContext() + "<hr>");


    }

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


小结:

方法展示

HttpSession接口方法作用
String getId()获得会话ID
long getCreationTime()获得会话的创建时间,毫秒值
long getLastAccessedTime()获得会话上次访问时间,毫秒值
boolean isNew()判断是否是新会话
ServletContext getServletContext()获得上下文对象
4.保存会话ID-[掌握]
/**
   目标:实现浏览器关闭还可以再访问服务器上没有过期的信息。

   保存会话ID实现步骤
    1. 创建Cookie对象:存储会话ID ==> Cookie名称必须是:JSESSIONID
    2. 设置Cookie过期时间
    3. 返回Cookie给浏览器
 */
@WebServlet(urlPatterns = "/saveId")
public class SaveSessionIdServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置内容类型和编码
        response.setContentType("text/html;charset=utf-8");
        // 获得字符打印流
        PrintWriter out = response.getWriter();
        out.println("保存了会话ID");
        // 获得会话域对象
        HttpSession session = request.getSession();
        // 1. 创建Cookie对象:存储会话ID ==> Cookie名称必须是:JSESSIONID
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        // 2. 设置Cookie过期时间
        cookie.setMaxAge(60);
        // 3. 返回Cookie给浏览器
        response.addCookie(cookie);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

小结:

如何实现浏览器关闭还可以再访问服务器上没有过期的信息?
	手动保存会话id,步骤如下:
    1. 创建Cookie对象:存储会话ID ==> Cookie名称必须是:JSESSIONID
    2. 设置Cookie过期时间
    3. 返回Cookie给浏览器

5.设置会话过期时间-[掌握]
/**
   目标:掌握设置会话过期时间的三种方式
 */
@WebServlet(urlPatterns = "/setMaxTime")
public class SetSessionTimeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置内容类型和编码
        response.setContentType("text/html;charset=utf-8");
        // 获得字符打印流
        PrintWriter out = response.getWriter();

        // 获得会话域对象
        HttpSession session = request.getSession();

        // 获得会话的最大非获得间隔时间:单位秒
        int maxTime = session.getMaxInactiveInterval();
        out.println("最大非活动间隔时间:" + maxTime + "<hr>"); // 1800


        // 方式1:设置会话最大非活动间隔时间:10秒
        // session.setMaxInactiveInterval(10);

        // 方式3:立即销毁session:一般用于退出或注销功能
        session.invalidate();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

30.Servlet三个作用域总结-[掌握]

1.1 作用域的创建和销毁

作用域接口名作用范围生命周期
请求域HttpServletRequest request同一个请求从请求开始到请求结束
会话域HttpSession session同一个会话从会话开始到会话结束
上下文域ServletContext context同一个项目从服务器开启到服务器关闭

1.2 作用域共同的方法

功能方法名
存放数据void setAttribute(String key,Object value)
获取数据Object getAttribute(String key)
删除数据void removeAttribute(String key)

1.3 如何选择作用域

  • 如果小范围的作用域能够满足需求则使用小范围作用域
  • 请求域 < 会话域 < 上下文域

31.JavaWeb三大组件概述-[理解]

JavaWeb三大组件作用实现接口
Servlet接收浏览器请求并响应数据给浏览器javax.servlet.Servlet
Filter过滤器:对浏览器的请求和服务器的响应进行过滤javax.servlet.Filter
Listenner监听器:监听作用域发生各种事件javax.servlet…xxxListener

1.过滤器

过滤器是服务器与客户端请求与响应的中间层组件,在实际项目开发中过滤器主要用于对浏览器的请求进行

过滤处理,将过滤后的请求再转给下一个资源。与其他的 WEB 应用程序组件不同的是,过滤器是采用了“链”的

方式进行处理的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n8i2iTc6-1653214471303)(H:\学习笔记\java笔记\图片文件\JSP\过滤器概述.png)]

应用场景

  1. 修改请求和响应,解决乱码的问题本来 POST 方法是有乱码的,以前是每个 Servlet 去编码。只要编写一个

    过滤器,解决所有 POST 乱码问题。

  2. 可以对请求进行拦截,非法用户未登录访问一些需要登录才能访问资源。

  3. 发帖子,有不健康的内容,过滤。

过滤器的执行特点:

不是由用户直接输入地址取访问,而是由过滤器通过过滤器的地址来匹配,如果匹配过滤器地址,进行过滤器

1.过滤器编写入门

过滤器的编写步骤

  1. 写一个类,实现 javax.servlet.Filter 接口
  2. 重写接口中所有的方法,其中有 doFilter(request, response, filterChain)方法用于执行过滤功能
  3. filterChain 是一个过滤链,如果执行过滤键的方法,放行。执行下一个过滤器或 web 资源(Servlet)。
  4. 需要进行配置,方式 1:web.xml 配置。 方式 2:通过注解

方式一

<?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">

    <!--配置过滤器信息-->

    <filter>
        <filter-name>helloFilter</filter-name>
        <filter-class>com.xjggb.filter.HelloFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>helloFilter</filter-name>
        <url-pattern>/hello</url-pattern>
    </filter-mapping>





</web-app>

HelloFilter代码

package com.xjggb.filter;


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

public class HelloFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("过滤器,我是请求达到的时候执行的");
        //放行请求,将请求传递给下一个资源
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("过滤器,我是响应回来的的时候执行的");




    }

    @Override
    public void destroy() {

    }
}

HellServlet代码

package com.xjggb.servlet;

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(urlPatterns = "/")
public class HelloFilter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Web资源:到达了Servlet中");
    }
}

方式二

package com.xjggb.filter;


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

/**
 目标:掌握过滤器开发步骤
 开发步骤
 1. 创建一个类实现Filter接口
 2. 重写接口的所有方法,在doFilter方法中拦截请求和响应
 3. 配置过滤路径:使用web.xml配置 或 使用注解配置

 需求:创建一个过滤器HelloFilter,
 在运行HelloServlet(Web资源)前和后分别输出一句话,
 在HelloServlet中也输出一句话,观察控制台的运行效果。
 */
@WebFilter(urlPatterns = "/hello")
public class HelloFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("过滤器,我是请求达到的时候执行的");
        //放行请求,将请求传递给下一个资源
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("过滤器,我是响应回来的的时候执行的");




    }

    @Override
    public void destroy() {

    }
}

小结:

过滤器开发步骤小结
	1. 创建类实现Filter接口
	2. 重写接口的所有方法,在doFilter方法中拦截请求
	3. 在doFilter方法中根据需求决定是否需要将请求继续传递给下一个资源
	4. 配置Filter的过滤路径:使用web.xml配置 或 注解配置(推荐使用注解)

2.过滤器执行流程

在这里插入图片描述

小结

1.浏览器发送请求到web资源,所有的资源(静态资源(HTML/CSS/JS))和动态资源(Servlet))都可以被过滤的
2.当前web资源的访问路径和过滤器的过滤路径匹配,则会触发过滤器的执行
3. 会执行过滤器的doFilter方法:过滤请求并将请求传递给下一个资源
4. 当web资源响应数据给浏览器之前,响应也会经过过滤器处理。
3.过滤器的生命周期-[掌握]

回顾servlet声明周期

1.Servlet什么时候创建和销毁?第1次访问创建,服务器关闭或重启销毁

2.Servlet生命周期相关方法有哪个几个?无参数构造,init,service,destory

3.:Filter什么时候加载? 在服务器启动时创建,在服务器关闭或重启销毁

/**
 * 目标:演示过滤器生命周期方法
 * 访问地址: http://localhost:8080/day30/life
 */
@WebFilter(urlPatterns = "/life")
public class LifeCycleFilter implements Filter {

    // 无参数构造方法:服务器启动时执行
    public LifeCycleFilter(){
        System.out.println("无参数构造方法...");
    }

    // 初始化方法:执行初始化操作  执行1次
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init...");
    }

    // 拦截请求:每次拦截到请求都会执行
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter...");
    }

    // 销毁资源:执行1次
    @Override
    public void destroy() {
        System.out.println("destroy...");
    }
}

1.4 小结

Filter接口中的方法作用和调用次数
void init(FilterConfig filterConfig)初始化资源 调用1次
void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
过滤请求和响应
每次拦截到请求执行1次
public void destroy()销毁资源 执行1次

4.过滤器的映射路径-[掌握]
/**
    目标:掌握过滤器映射路径(过滤路径)的设置

    过滤器映射路径设置方法有两种
        精确路径映射
            过滤路径和要访问的资源路径要完成一致才会触发过滤器的执行

        模糊路径映射:使用通配符 * :代表当前项目下的所有资源
            前缀路径映射:
                必须以/开头,以*结尾的路径
                比如:
                    /*  过滤当前项目下的所有资源
                    /manager/*  过滤当前项目下manager目录下的所有资源

            后缀路径映射:
                必须以*开头,以后缀名结尾
                比如:
                    *.do      过滤.do结尾的资源(请求)
                    *.action  过滤.do结尾的资源(请求)

            注意:前缀路径和后缀路径不能一起使用,比如 /*.do 是不允许的

        目前:SSM  Spring Springmvc Mybatic
        早期:SSH Spring Struct Hibernate
 */
@WebFilter(urlPatterns = "/*.do")
public class UrlPatternsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行了UrlPatternsFilter过滤器");
    }

    @Override
    public void destroy() {

    }
}

小结

过滤器映射路径的配置方式
	1. 精确路径匹配
      特点:过滤的路径和要访问的资源路径完全相同
      须知:过滤器可以过滤任何资源:servlet,index.jsp,index.html,a.png

  2. 模糊路径匹配:使用通配符*,* 代表匹配所有资源
      前缀匹配:过滤路径必须以/开头,以*结尾
          比如:/* 过滤当前项目下所有资源
               /manager/*  过滤manager目录下的所有资源

      后缀匹配:过滤路径必须以*开头,以扩展名结尾
          比如:*.do 过滤所有以.do结尾的资源
               *.action 过滤所有以.action结尾的资源

          错误写法:/*.do
              不能同时出现/开头和扩展名结尾配置方式,
              导致整个web项目加载失败,所有资源都无法访问。

以/ 开关的匹配模式和以扩展名结尾的配置不能同时出现:比如:/manager/*.html

5.过滤器默认拦截方式-[掌握]

1.2 默认拦截方式演示

  • 需求说明:

    • 创建过滤器:DispatchTypeFilter,过滤路径:/two
    • 创建OneServlet,访问路径为:/one,在OneServlet中重定向到TwoServlet
    • 创建TwoServlet,访问路径为:/two
  • 代码如下:

    • DispatchTypeFilter代码
/**
  目标:学习过滤器默认的拦截方式

  默认的拦截方式:只会对浏览器直接发送的请求进行拦截

 需求说明:
 - 创建过滤器:DispatchTypeFilter,过滤路径:/two
 - 创建OneServlet,访问路径为:/one,在OneServlet中重定向到TwoServlet
 - 创建TwoServlet,访问路径为:/two
 */
@WebFilter(urlPatterns = "/two")
public class DispatchTypeFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("进来了DispatchTypeFilter...");
        // 放行请求
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

OneServlet代码

@WebServlet(urlPatterns = "/one")
public class OneServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 在OneServlet中重定向到TwoServlet
        response.sendRedirect("two");

        // 转发到TwoServlet
        // request.getRequestDispatcher("two").forward(request, response);
    }
}

TwoServlet代码

@WebServlet(urlPatterns = "/two")
public class TwoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
         // 设置内容类型和编码
         response.setContentType("text/html;charset=utf-8");
         // 获得字符打印流
         PrintWriter out = response.getWriter();
         out.println("TwoServlet返回数据");
    }
}

访问方式如下

  • 浏览器直接访问OneServlet,观察是否执行了过滤器?会
  • 浏览器直接访问TwoServlet,观察是否执行了过滤器?会

小结:

过滤器默认的拦截方式:只会对浏览器直接发送的请求进行拦截(包括重定向)

5.修改过滤器拦截方式-[掌握]

修改默认拦截方式并实现两种拦截方法一起使用。

1.2 拦截转发的请求演示

  • 需求说明:

    • 创建过滤器:ForwardRequestFilter,过滤路径:/second
    • 创建FirstServlet,访问路径为:/first,在FirstServlet中转发到SecondServlet
    • 创建SecondServlet,访问路径为:/second
  • 代码如下:

    • ForwardRequestFilter代码
FirstServlet代码/**
 *   目标:修改默认拦截方式并实现两种拦截方法一起使用。

     需求说明:

     - 创建过滤器:ForwardRequestFilter,过滤路径:/second
     - 创建FirstServlet,访问路径为:/first,在FirstServlet中转发到SecondServlet
     - 创建SecondServlet,访问路径为:/second

     访问方式如下
     - 浏览器直接访问FirstServlet,观察是否执行了过滤器? 不会
     - 浏览器直接访问SecondServlet,观察是否执行了过滤器? 会
 */
/*@WebFilter(
        urlPatterns = "/second",
        dispatcherTypes = {
                DispatcherType.FORWARD, // 对转发的请求进行拦截
                DispatcherType.REQUEST  // 默认的拦截方式:对浏览器发送的请求进行拦截
        }
 )*/
public class ForwardRequestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("进来了ForwardRequestFilter...");
        // 放行请求
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

FirstServlet代码

@WebServlet(urlPatterns = "/first")
public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 转发到SecondServlet
        request.getRequestDispatcher("second").forward(request, response);
    }
}

SecondServlet代码

@WebServlet(urlPatterns = "/second")
public class SecondServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // 设置内容类型和编码
         response.setContentType("text/html;charset=utf-8");
         // 获得字符打印流
         PrintWriter out = response.getWriter();
         out.println("SecondServlet响应数据");
    }
}

访问方式如下

  • 浏览器直接访问FirstServlet,观察是否执行了过滤器?
  • 浏览器直接访问SecondServlet,观察是否执行了过滤器?

修改默认拦截方式

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">

    <!--配置过滤器信息-->
    <filter>
        <!--设置过滤器名称-->
        <filter-name>helloFilter</filter-name>
        <!--设置过滤器的类全名字符串-->
        <filter-class>com.itheima._01过滤器._04拦截方式.ForwardRequestFilter</filter-class>
    </filter>

    <filter-mapping>
        <!--设置过滤器名称:必须和上面一致-->
        <filter-name>helloFilter</filter-name>
        <!--设置过滤器的过滤路径:必须以/开头-->
        <url-pattern>/second</url-pattern>
        <!--修改拦截方式-->
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

</web-app>

2.注解中添加

@WebFilter(
        urlPatterns = "/second",
        dispatcherTypes = {
                DispatcherType.FORWARD, // 对转发的请求进行拦截
                DispatcherType.REQUEST  // 默认的拦截方式:对浏览器发送的请求进行拦截
        }
 )

1.4 过滤器拦截类型小结

拦截方式说明
REQUEST默认拦截方式
只会对浏览器直接发送的请求拦截(包括重定向)
FORWARD转发拦截方式
对服务器转发的请求进行拦截
6.过滤器链概述和演示-[掌握]

在实际开发过程中,可能不只一个过滤器,同时存在多个过滤器。每个过滤器的功能各不相同。多个过滤器之 间就组成了一个过滤链。过滤链中每个过滤器会依次执行。

在这里插入图片描述

第一个过滤器:OneFilter

@WebFilter(urlPatterns = "/resource")
public class OneFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器1:请求");
        // 放行请求:将请求传递一个下一个资源(过滤器或web资源)
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤器1:响应");
    }

    @Override
    public void destroy() {

    }
}


第二个过滤器:TwoFilter

@WebFilter(urlPatterns = "/resource")
public class TwoFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器2:请求");
        // 放行请求:将请求传递一个下一个资源(过滤器或web资源)
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤器2:响应");
    }

    @Override
    public void destroy() {

    }
}

Web资源:ResourceServelt

@WebServlet(urlPatterns = "/resource")
public class ResourceServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("我是web资源Resource");
    }
}

7.用户权限的控制-[掌握]

在这里插入图片描述

LoginServlet代码

// 实现登录功能
/**
    实现步骤
        1. 获取请求参数:用户名和密码
        2. 判断用户名和密码是否是admin
        3. 是代表登录成功,将用户信息存储会话域中,跳转联系人列表页面
        4. 登录失败,将错误信息存储到请求域中并转发跳到登录页面
 */
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 获取请求参数:用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 2. 判断用户名和密码是否是admin
        if ("admin".equals(username) && "admin".equals(password)){
            // 3. 是代表登录成功,将用户信息存储会话域中,跳转联系人列表页面
            request.getSession().setAttribute("user", username);
            response.sendRedirect("list.jsp");
        } else {
            // 4. 登录失败,将错误信息存储到请求域中并转发跳到登录页面
            request.setAttribute("errorMsg","用户名或密码错误");
            request.getRequestDispatcher("login.jsp").forward(request, response);
        }


    }
}

AuthorFilter代码

@WebFilter(urlPatterns = "/manager/*")
public class AuthorFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 获取会话域对象
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession session = request.getSession();
        // 获得用户数据
        Object user = session.getAttribute("user");
        // 判断是否有用户数据
        if (user != null) {
            // 有用户数据,则代表登录了,则放行请求
            filterChain.doFilter(request, servletResponse);
        } else  {
            // 没有用户数据,则跳转登录页面
            // http://localhost:8080/day30/
            response.sendRedirect(request.getContextPath() + "/login.jsp");
        }
    }

    @Override
    public void destroy() {

    }
}

2.监听器

作用:

监听作用域(请求域,会话域,上下文域)中发生了的各种事件,并且对事件做出响应

  1. 域的创建和销毁
  2. 域中属性添加 setAttribute,删除 removeAttribute,修改 setAttribute()

监听器接口分类

事件源监听器接口时机
ServletContextServletContextListener上下文域创建和销毁
ServletContextServletContextAttributeListener上下文域属性增删改的操作
HttpSessionHttpSessionListener会话域创建和销毁
HttpSessionHttpSessionAttributeListener会话域属性增删改的操作
HttpServletRequestServletRequestAttributeListener请求域属性增删改的操作
HttpServletRequestServletRequestListener请求域创建和销毁

小结

1.监听器的作用
    1.监听作用域的创建和销毁
    2.监听作用域的属性的增删改操作

1.监听器编写入门

servlet代码

package com.xjggb.context;

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

@WebServlet(urlPatterns = "/listener")
public class ServletDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //获取上下文对象

        ServletContext context = getServletContext();

        //添加数据
        context.setAttribute("username","jack");

        //修改数据
        context.setAttribute("username", "rose");
        // 删除数据
        context.removeAttribute("username");


    }
}

监听器代码

package com.xjggb.context;


import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyServletContextAttributeListener implements ServletContextAttributeListener {

    // 当往上下文域添加属性时调用:context.setAttribute(key,value)
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {

        //获取属性名
        String name = servletContextAttributeEvent.getName();
        // 获得属性值:jack
        Object value = servletContextAttributeEvent.getValue();
        System.out.println("添加:" + name + " = " + value);
    }

    // 当从上下文域中删除属性时调用:context.removeAttribute(key)
    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
        //获取属性名
        String name = servletContextAttributeEvent.getName();
        // 获得属性值:jack
        Object value = servletContextAttributeEvent.getValue();
        System.out.println("删除" + name + " = " + value);

    }

    // 当修改上下文域属性时调用:context.setAttribute(key,value)
    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
        //获取属性名
        String name = servletContextAttributeEvent.getName();
        // 获得属性值:jack
        Object value = servletContextAttributeEvent.getValue();
        System.out.println("修改" + name + " = " + value);


// 获得修改后的值
        Object newValue = servletContextAttributeEvent.getServletContext().getAttribute(name);

        System.out.println("修改:" + name + " = " + value + ", 修改后的值newValue = " + newValue);

    }


}

xml配置

    <!--配置监听器-->
    <listener>
        <listener-class>com.xjggb.context.MyServletContextAttributeListener</listener-class>
    </listener>

1.5 小结

ServletContextAttributeListener接口中方法调用时机
void attributeAdded(ServletContextAttributeEvent event)往上下文域添加属性调用
void attributeRemoved(ServletContextAttributeEvent event)从上下文域删除属性调用
void attributeReplaced(ServletContextAttributeEvent event)修改上下文域属性调用
ServletContextAttributeEvent对象中的方法功能
String getName()获得属性名
Object getValue()获得属性值
修改前的值

2.ServletContextListener应用案例-[掌握]

ServletContextListener常见操作

1.加载第三方配置文件
2.开启定时人物(比如每天凌晨给过当天生日的用户发生日祝福邮件)
package com.xjggb.context;


import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

@WebListener
public class MyServletContextListener implements ServletContextListener {

    // 在上下文对象创建完毕之后调用:服务器启动调用
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // System.out.println("服务器启动了");
        // 创建定时器对象
        Timer timer = new Timer();
        // 开启一个定时任务:每隔3秒在控制台输出一句话
        // 参数1:task:要执行任务:需要传递TimerTask对象
        // TimerTask用来封装任务代码,
        // 参数2:firstTime:任务第1次执行的事件
        // 参数2:period:时间间隔,每隔指定的时间后执行1次指定的任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // 封装任务代码
                System.out.println("执行了任务....");
            }
        }, new Date(), 3000);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("服务器关闭了");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值