Loading

JavaWeb

Servlet入门

img

HTTP请求结构

img

响应结构

img

HTTP常见状态码

img

软件架构

  • C/S:客户端/服务器端
  • B/S:浏览器/服务器端

资源分类

  •   1. 静态资源:所有用户访问后,得到的结果都是一样的,称为静态资源.静态资源可以直接被浏览器解析如: html,css,JavaScript
  •   2. 动态资源:每个用户访问相同资源后,得到的结果可能不一样。称为动态资源。动态资源被访问后,需要先转换为静态资源,在返回给浏览器 如:servlet/jsp,php,asp....

网络通信三要素

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

web服务器软件:
* 服务器:安装了服务器软件的计算机
* 服务器软件:接收用户的请求,处理请求,做出响应
* web服务器软件:接收用户的请求,处理请求,做出响应。
* 在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目
* web容器

* 常见的java相关的web服务器软件:
* webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
* webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
* JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
* Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。

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

B/s模式开发Web应用就是J2EE的核心功能

img

Tomcat

* Tomcat:web服务器软件

* Tomcat:web服务器软件

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

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

注意:安装目录建议不要有中文和空格

*环境变量:

CATALINA_HOME D:\Apache\apache-tomcat-9.0.50
CATALINA_BASE D:\Apache\apache-tomcat-9.0.50
Path %CATALINA_HOME%\lib;%CATALINA_HOME%\bin

3.卸载:删除目录就行了

4.启动:

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

访问:浏览器输入:http://localhost:8080 回车访问自己
http://别人的ip:8080 访问别人

启动报错:

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

netstat -ano

温柔:修改自身的端口号

conf/server.xml

一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。
好处:在访问时,就不用输入端口号

5.关闭:

  1. 正常关闭:

  • bin/shutdown.bat
    • ctrl+c

  2. 强制关闭:

点击启动窗口的×

6.配置:

** 部署项目的方式:**

  1. 直接将项目放到webapps目录下即可。
  • /hello:项目的访问路径-->虚拟目录
  • 简化部署:将项目打成一个war包,再将war包放置到webapps目录下。
  • war包会自动解压缩
  1. 配置conf/server.xml文件
      在标签体中配置
      
  • docBase:项目存放的路径
  • path:虚拟目录
  1. 在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写
      
  • 虚拟目录:xml文件的名称

  • 静态项目和动态项目:

  • 目录结构

  • java动态项目的目录结构:
      -- 项目的根目录
          -- WEB-INF目录:
          -- web.xml:web项目的核心配置文件
          -- classes目录:放置字节码文件的目录
          -- lib目录:放置依赖的jar包

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

Servlet

第一:Servlet是一个运行在web服务端的java小程序

第二:它可以用于接收和响应客户端的请求

第三:要想实现Servlet功能,可以实现Servlet接口,继承GenericServlet或者HttpServlet

第四:每次请求都会执行service方法

img

Servlet的体系结构

Servlet -- 接口
|
GenericServlet -- 抽象类
|
HttpServlet -- 抽象类

* GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
* 将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可

* HttpServlet:对http协议的一种封装,简化操作
\1. 定义类继承HttpServlet
\2. 复写doGet/doPost方法

第一个web程序

img

创建完需要添加Servlet包

D:\apache-tomcat-9.0.48\lib\servlet-api.jar

在src在新建包 com.imooc.Servlet

新建类 继承HttpServlet

点击查看代码

package com.imooc.servlet;


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

public class MyServlet extends HttpServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        String name=request.getParameter("name");//接受请求发来的参数
        String html="<h1 style='color:red'>hello " +name+"</h1>";
        PrintWriter out=response.getWriter(); //服务器向浏览器返回的输出流

        out.println(html);
    }
}

在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>Servlet</servlet-name>                         Servlet的别名
        <servlet-class>com.imooc.servlet.MyServlet</servlet-class>   Servlet的类
    </servlet>
    <servlet-mapping>
        <servlet-name>Servlet</servlet-name>               映射 Servlet和URL绑定
        <url-pattern>/h</url-pattern>
    </servlet-mapping>
</web-app>

在run中编辑配置服务器

img

运行之后在浏览器访问

localhost:8080/first/h?name=liu

url后一般加入项目名称

请求与响应

从浏览器发给服务器的数据包成为 请求request

服务器发送给浏览器的结果成为 响应response

img

HTTP协议:

  1. 请求消息:客户端发送给服务器端的数据

数据格式:

  • 请求行
  • 请求头
  • 请求空行
  • 请求体
  • 响应消息:服务器端发送给客户端的数据

数据格式:

  • 响应行

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

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

    1. 状态码都是3位数字

    2. 分类:

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

      2xx:成功。代表:200

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

      4xx:客户端错误。4(请求路径没有对应的资源)405:请求方式没有对应的doXxx方法

      5xx:服务器端错误。代表:500(服务器内部出现异常)

  • 响应头:

    格式:头名称: 值

    常见的响应头:

    Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式

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

  3. 响应空行
  4. 响应体:传输的数据

* 响应字符串格式

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

<html>
<head>
<title>$Title$</title>
</head>
<body>
hello , response
</body>
</html>

Get和Post处理方式

所有请求 service()

Get请求 doGet()

Post请求 doPost()

Get和Post请求方法

Get方式是将数据通过附加显性数据在URL 向服务器发送数据

Post方式会将数据存放在请求体中隐性向服务器发送数据

请求参数

浏览器通过请求向Tomcat提交的数据(用户输入的数据), 参数名1=值1&参数名2=值2&参数名n...

Servlet接受请求参数:

request.getParameter() 单个参数

request.getParameterValues()接受多个同名参数

http://localhost:8080/FirstServlet/sample

请求体:name=zhangsan

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>学员信息登记表</title>
</head>
<body>
    <h1>学员信息登记表</h1>
    <form action="/FirstServlet/sample" method="get" >
        姓名:<input name="name"/>
        <br/>
        电话:<input name="mobile"/>
        <br/>
        性别:
        <select name="sex" style="width:100px;padding:5px;">
            <option value="male" >男</option>
            <option value="female">女</option>
        </select>
        <br/>
        特长:
        <input type="checkbox" name="spec" value="English"/>英语
        <input type="checkbox" name="spec" value="Program"/>编程
        <input type="checkbox" name="spec" value="Speech"/>演讲
        <input type="checkbox" name="spec" value="Swimming"/>游泳
        <br/>
        <input type="submit" value="提交">
        <br/>
    </form>
</body>
</html>
public class RequestMethodServlet extends HttpServlet{
    //处理get请求
    public void doGet(HttpServletRequest request , HttpServletResponse response) throws IOException{
        String name = request.getParameter("name");
        response.getWriter().println("<h1 style='color:green'>" + name + "</h1>");
    }
    //处理post请求
    public void doPost(HttpServletRequest request , HttpServletResponse response) throws IOException{
        String name = request.getParameter("name");
        response.getWriter().println("<h1 style='color:red'>" + name + "</h1>");
    }
}

Request:

简介:

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

request对象继承体系结构:

ServletRequest -- 接口
  | 继承
HttpServletRequest -- 接口
  | 实现
org.apache.catalina.connector.RequestFacade 类(tomcat)

获取请求行数据

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

     1. 获取请求方式 :GET
+ String getMethod()

     2. 获取虚拟目录:/day14
+ String getContextPath()
     3. 获取Servlet路径: /demo1
+ String getServletPath()
     4. 获取get方式请求参数:name=zhangsan
+ String getQueryString()

      5. 获取请求URI:/day14/demo1
+ String getRequestURI()
+ SringBuffer getRequestURL()

      6. 获取协议及版本:HTTP/1.1
+ String getProtocol()

      7. 获取客户机的IP地址:
String getRemoteAddr()

获取请求头数据

  • String getHeader(String name):通过请求头的名称获取请求头的值

  • Enumeration getHeaderNames():获取所有的请求头名称

获取请求体数据:

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

获取流对象

  • BufferedReader getReader():获取字符输入流,只能操作字符数据
  • ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据

再从流对象中拿数据

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

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

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

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

    Map<String,String[]> getParameterMap():获取所有参数的map集合

  • 中文乱码问题:
    get方式:tomcat 8 已经将get方式乱码问题解决了
    post方式:会乱码
    • 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");

请求转发:

一种在服务器内部的资源跳转方式 浏览器地址栏路径不发生变化 只能转发到当前服务器内部资源中。转发是一次请求

  1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
  2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)

共享数据:

域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

  • void setAttribute(String name,Object obj):存储数据
  • object getAttitude(String name):通过键获取值
  • void removeAttribute(String name):通过键移除键值对

取ServletContext:

  • ServletContext getServletContext()

Response对象

功能:设置响应消息

设置响应行

格式:HTTP/1.1 200 ok

  • 设置状态码:setStatus(int sc)
  • 设置响应头:setHeader(String name, String value)

设置响应体:

获取输出流

  • 字符输出流:PrintWriter getWriter()

  • 字节输出流:ServletOutputStream getOutputStream()

使用输出流,将数据输出到客户端浏览器

完成重定向

* 重定向:资源跳转的方式
* 代码实现:

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


//简单的重定向方法
response.sendRedirect("/day15/responseDemo2");
redirect forward
地址栏发生变化 转发地址栏路径不变
重定向可以访问其他站点(服务器)的资源 转发只能访问当前服务器下的资源
重定向是两次请求。不能使用request对象来共享数据 转发是一次请求,可以使用request对象来共享数据

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

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

  • 注意:
  • 乱码问题:
  1. PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1 设置该流的默认编码

  2. 告诉浏览器响应体使用的编码

    //简单的形式,设置编码,是在获取流之前设置
    response.setContentType("text/html;charset=utf-8");

  3. 服务器输出字节数据到浏览器

    获取字节输出流
    输出数据

ServletContext对象:

概念:

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

获取:

  1. 通过request对象获取 request.getServletContext();
  2. 通过HttpServlet获取 this.getServletContext();

功能

获取MIME类型:在互联网通信过程中定义的一种文件数据类型

  • 格式: 大类型/小类型 text/html image/jpeg
  • 获取:String getMimeType(String file)

域对象:共享数据

  • setAttribute(String name,Object value)

  • getAttribute(String name)

  • removeAttribute(String name)

    • ServletContext对象范围:所有用户所有请求的数据

获取文件的真实(服务器)路径

方法:String getRealPath(String path)

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

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

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

乱码问题:

1.Tomcat中 日志输出乱码问题

打开“/apache-tomcat-9.0.20/conf/logging.properties”文件

把java.util.logging.ConsoleHandler.encoding = UTF-8改成java.util.logging.ConsoleHandler.encoding = GBK

2.Servlet乱码问题

请求:

在doPost方法义一行加入request.setCharacterEncoding("utf-8"); //请求体中的字符集转换为utf-8

doGet方法在tomcat server.xml中配置

<Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" 
    URIEncoding="utf-8"/> 
<Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" 
    URIEncoding="utf-8"/>

响应:

response.setContentType("text/html;charest=UTF-8");

img

@WebServlet("/ct")
public class ContentTypeServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String output = "<h1><a href='http://www.baidu.com'><span>百度</span></a></h1>";
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println(output);
    }

}

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>Servlet</servlet-name>                         Servlet的别名
        <servlet-class>com.imooc.servlet.MyServlet</servlet-class>   Servlet的类
    </servlet>
    <servlet-mapping>
        <servlet-name>Servlet</servlet-name>               映射 Servlet和URL绑定
        <url-pattern>/h</url-pattern>
    </servlet-mapping>
</web-app>

默认依次加载首页

<welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>

指定错误页面

<!-- 指定错误页面 -->
  <error-page>
      <error-code>404</error-code>
      <location>/error/404.html</location>
  </error-page>
  <error-page>
      <error-code>500</error-code>
      <location>/error/500.jsp</location>
  </error-page>

500.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    服务器内部错误,请联系管理员 ,错误信息如下:
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    资源不存在
</body>
</html>

500.jsp

<%@ page contentType="text/html;charset=utf-8" isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    服务器内部错误,请联系管理员 ,错误信息如下:
    <%
        String msg = exception.getMessage();
        out.print("<br>" + exception.getClass().getSimpleName() + ":" + msg);
    %>
</body>
</html>

Servlet生命周期

装载-web.xml

**创建-构造函数 **

初始化-init()

提供服务-service()

销毁-destroy()

public class FirstServlet extends HttpServlet{
    
    public FirstServlet(){
        System.out.println("正在创建FirstServlet对象");
    }
     
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("正在初始化FirstServlet对象");
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //接收请求发来的参数
        String name = request.getParameter("name");
        String html = "<h1 style='color:red'>hi," + name +"!</h1><hr/>";
        System.out.println("返回给浏览器的响应数据为:" + html);
        PrintWriter out = response.getWriter();
        out.println(html);//将html发送回浏览器
    }



    @Override
    public void destroy() {
        System.out.println("正在销毁servlet对象"); 
    }

    
}

只有一个Servlet对象,Tomcat关闭时销毁

使用注解配置Servlet

Servlet 3.x之后引入了注解Annotation特性

注解用于简化Web应用程序的配置过程

/**
 * WebServlet注解
 * @since Servlet 3.0 (Section 8.1.1)
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {

    /**
     * 指定Servlet的名称。
     * 相当于xml配置中<servlet>标签下的<servlet-name>
     */
    String name() default "";

    /**
     * 用于映射Servlet访问的url映射
     * 相当于xml配置时的<url-pattern>
     */
    String[] value() default {};

    /**
     * 相当于xml配置时的<url-pattern>
     */
    String[] urlPatterns() default {};

    /**
     * 用于配置Servlet的启动时机
     * 相当于xml配置的<load-on-startup>
     */
    int loadOnStartup() default -1;

    /**
     * 用于配置Servlet的初始化参数
     * 相当于xml配置的<init-param>
     */
    WebInitParam[] initParams() default {};

    /**
     * 用于配置Servlet是否支持异步
     * 相当于xml配置的<async-supported>
     */
    boolean asyncSupported() default false;

    /**
     * 用于指定Servlet的小图标
     */
    String smallIcon() default "";

    /**
     * 用于指定Servlet的大图标
     */
    String largeIcon() default "";

    /**
     * 用于指定Servlet的描述信息
     */
    String description() default "";

    /**
     * 用于指定Servlet的显示名称
     */
    String displayName() default "";
}

Servlet核心注解:@WebServlet

package com.imooc.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
@WebServlet("/anno")//映射的Servlet的Url     
public class AnnotationServlet extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("I am annotation");
    }
}
@WebServlet("/anno/*")//模糊匹配,之后可以用request.getResquestURL().toString()获取输入的url

启动时加载Servlet

web使用设置启动加载

0-99990最先执行

启动时加载常用于系统预处理

public class CreateServlet extends HttpServlet{

    @Override
    public void init() throws ServletException {
        System.out.println("正在创建数据库");
    }
    
}

注解:

@WebServlet(urlPatterns="/unused",loadOnStartup=2)    //注解必须设置urlPatterns

public class AnalysisServlet extends HttpServlet{

    @Override
    public void init() throws ServletException {
        System.out.println("正在分析结果");
    }
    
}

xml:

<servlet>
      <servlet-name>create</servlet-name>
      <servlet-class>com.imooc.servlet.CreateServlet</servlet-class>
      <load-on-startup>0</load-on-startup>
  </servlet>

请求转发与重定向

1.request.getRequsetDispatcher.forward()请求转发

请求分发器

参数:路径

跳转后浏览器网址栏是第一个URL

img

2.response.sendRedirect()响应重定向

跳转后浏览器网址栏是第二个URL(两次请求)

img

Servlet1 收到响应1会销毁,Servlet2收到请求2会重新创建对象

主页index

package com.imooc.direct;

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("/direct/index")
public class index extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.getWriter().println("this is a page");

    }
}

登录界面

package com.imooc.direct;

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("/direct/login")
public class ChackLogin extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("用户登录成功");
//        request.getRequestDispatcher("/direct/index").forward(request,response);//请求转发
//        response.sendRedirect("/frist/direct/index");//重定向需要加上下文路径(工程名字)
    }
}

设置请求自定义属性

设置请求属性:request.setAttribute("key","value");

获取请求属性:request.getAttribute("key");

会话技术

会话:一次会话中包含多次请求和响应。
一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
功能:在一次会话的范围内的多次请求间,共享数据
方式:

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

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

快速入门:

  1. 创建Cookie对象,绑定数据

  • new Cookie(String name, String value)

  2. 发送Cookie对象

  • response.addCookie(Cookie cookie)

  3. 获取Cookie,拿到数据

  • Cookie[] request.getCookies()
  1. 实现原理
  • 基于响应头set-cookie和请求头cookie实现
package com.imooc.servlet.cookie;

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

@WebServlet("/cookies/login")
public class ImoocLoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("用户登录成功");
        Cookie cookie = new Cookie("user" , "admin");
        cookie.setMaxAge(60 * 60 * 24 * 7);                    //七天有效
        response.addCookie(cookie);
        response.getWriter().println("login success");
    }

}
package com.imooc.servlet.cookie;

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

@WebServlet("/cookies/index")
public class ImoocIndexServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //request.getCookies()用户获取所有的Cookie
        Cookie[] cs = request.getCookies();
        if(cs == null) {
            response.getWriter().println("user not login");
            return;
        }
        String user = null;
        for(Cookie c : cs) {
            System.out.println(c.getName() + ":" + c.getValue());
            if(c.getName().equals("user")) {
                user = c.getValue();
                break;
            }
        }
        
        if(user == null) {
            response.getWriter().println("user not login");
        }else {
            response.getWriter().println("user:" + user);
        }
    }

}

Session

Session(用户回话)用于保存与浏览器对应的数据

Session的数据存储在Tomcat服务器的内存中,具有时效性

Session通过Cookie的SessionId的值提取用户数据

概念:

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

快速入门:

获取HttpSession对象:

  • HttpSession session = request.getSession();

使用HttpSession对象:

  • Object getAttribute(String name)
  • void setAttribute(String name, Object value)
  • void removeAttribute(String name)

Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。

Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份

@WebServlet("/session/login")
public class SessionLoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("用户登录成功");
        //获取到用户会话Session对象
        HttpSession session = request.getSession();
        String sessionId = session.getId();//打开每个浏览器ID值不一样
        System.out.println(sessionId);
        session.setAttribute("name", "张三");
        request.getRequestDispatcher("/session/index").forward(request, response);
    }

}

.

@WebServlet("/session/index")
public class SessionIndexServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        String sessionId = session.getId();
        System.out.println(sessionId);
        String name = (String)session.getAttribute("name");
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("这是首页,当前用户为:" + name);
    }

}

cookie和session理解

来自博客:https://blog.csdn.net/qq_33366098/article/details/82150417

会话机制

    Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

    一次会话指的是:就好比打电话,A给B打电话,接通之后,会话开始,直到挂断电话,该次会话就结束了,而浏览器访问服务器,就跟打电话一样,浏览器A给服务器发送请求,访问web程序,该次会话就已经接通,其中不管浏览器发送多少请求(就相当于接通电话后说话一样),都视为一次会话,直到浏览器关闭,本次会话结束。其中注意,一个浏览器就相当于一部电话,如果使用火狐浏览器,访问服务器,就是一次会话了,然后打开google浏览器,访问服务器,这是另一个会话,虽然是在同一台电脑,同一个用户在访问,但是,这是两次不同的会话。

    知道了什么是会话后,思考一个问题,一个浏览器访问一个服务器就能建立一个会话,如果别的电脑,都同时访问该服务器,就会创建很多会话,就拿一些购物网站来说,我们访问一个购物网站的服务器,会话就被创建了,然后就点击浏览商品,对感兴趣的商品就先加入购物车,等待一起付账,这看起来是很普通的操作,但是想一下,如果有很多别的电脑上的浏览器同时也在访问该购物网站的服务器,跟我们做类似的操作呢?服务器又是怎么记住用户,怎么知道用户A购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,不能放入用户B或用户C的购物车内的呢?所以就有了cookie和session这两个技术,就像第一行说的那样,cookie和session用来跟踪用户的整个会话,

Cookie和Session之间的区别和联系

假如一个咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:

1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。但是http协议本身是无状态的

2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。也就是cookie。 顾客就相当于浏览器

3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。

  由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择.

上面已经介绍了为什么要使用Cookie,以及Cookie的一些特点,比如保存在客户端,用来记录用户身份信息的,现在来看看如何使用Cookie。

借着上面会员卡的例子来说,采用的是第二种方案,其中还需要解决的问题就是:如何分发会员卡,会员卡的内容,客户如何使用会员卡,会员卡的有效日期,会员卡的使用范围

1、如何分发会员卡、会员卡的内容:也就是cookie是如何创建的?创建后如何发送给客户端?

由服务器进行创建,也就相当于咖啡店来创建会员卡,在创建会员卡的同时,就会将会员卡中的内容也给设置了

Cookie cookie = new Cookie(key,value);  //以键值对的方式存放内容,

response.addCookie(cookie);  //发送回浏览器端

注意:一旦cookie创建好了,就不能在往其中增加别的键值对,但是可以修改其中的内容,

cookie.setValue();  //将key对应的value值修改

2、客户如何使用会员卡,cookie在客户端是如何工作的,工作原理是什么?

        img

这个过程就相当于,咖啡店创建好了会员卡,并且已经设置了其中的内容,交到了客户手中,下次客户过来时,就带着会员卡过来,就知道你是会员了,然后咖啡店就拿到你的会员卡对其进行操作。

3、会员卡的有效日期?也就是cookie也是拥有有效日期的。

这个可以自由设置,默认是关闭浏览器,cookie就没用了。

cookie.setMaxAge(expiry);  //设置cookie被浏览器保存的时间。

expiry:单位秒,默认为-1,

expiry=-1:代表浏览器关闭后,也就是会话结束后,cookie就失效了,也就没有了。

expiry>0:代表浏览器关闭后,cookie不会失效,仍然存在。并且会将cookie保存到硬盘中,直到设置时间过期才会被浏览器自动删除,

expiry=0:删除cookie。不管是之前的expiry=-1还是expiry>0,当设置expiry=0时,cookie都会被浏览器给删除。

    

4、会员卡的使用范围?比如星巴克在北京有一个分店,在上海也有一个分店,我们只是在北京的星巴克办理了会员卡,那么当我们到上海时,就不能使用该会员卡进行打折优惠了。而cookie也是如此,可以设置服务器端获取cookie的访问路径,而并非在服务器端的web项目中所有的servlet都能访问该cookie。

cookie默认路径:当前访问的servlet父路径。

例如:http://localhost:8080/test01/a/b/c/SendCookieServlet

默认路径:/test01/a/b/c  也就是说,在该默认路径下的所有Servlet都能够获取到cookie,/test01/a/b/c/MyServlet 这个MyServlet就能获取到cookie。

修改cookie的访问路径

setPath("/");  //在该服务器下,任何项目,任何位置都能获取到cookie,

通途:保证在tomcat下所有的web项目可以共享相同的cookie

例如:tieba , wenku , beike 多个项目共享数据。例如用户名。

setPath("/test01/");  //在test01项目下任何位置都能获取到cookie。

5、总结Cookie:

工作流程:

  1. servlet创建cookie,保存少量数据,发送浏览器。

  2. 浏览器获得服务器发送的cookie数据,将自动的保存到浏览器端。

  3. 下次访问时,浏览器将自动携带cookie数据发送给服务器。

cookie操作

1.创建cookie:new Cookie(name,value)

2.发送cookie到浏览器:HttpServletResponse.addCookie(Cookie)

3.servlet接收cookie:HttpServletRequest.getCookies() 浏览器发送的所有cookie

cookie特点

  1. 每一个cookie文件大小:4kb , 如果超过4kb浏览器不识别

  2. 一个web站点(web项目):发送20个

  3. 一个浏览器保存总大小:300个

  4. cookie 不安全,可能泄露用户信息。浏览器支持禁用cookie操作。

  5. 默认情况生命周期:与浏览器会话一样,当浏览器关闭时cookie销毁的。---临时cookie

cookie api

getName() 获得名称,cookie中的key

getValue() 获得值,cookie中的value

setValue(java.lang.String newValue) 设置内容,用于修改key对应的value值。

setMaxAge(int expiry) 设置有效时间【】

setPath(java.lang.String uri) 设置路径【】  

setDomain(java.lang.String pattern) domain 属性决定运行访问Cookie的域名,而path属性决定允许访问Cookie的路径(ContextPath)。例如,如果只允许/session/下的程序使用Cookie,cookie.setPath("/session/");

注意:cookie不能发送中文,如果要发送中文,就需要进行特别处理。

JDK提供工具,进行编码

URLEncoder:编码

URLDecoder:解码

//发送cookie

            Cookie cookie = new Cookie(URLEncoder.encode("哈哈"),URLEncoder.encode("呵呵"));

            response.addCookie(cookie);

            //获得cookie中文内容

            URLDecoder.decoder(request.getCookie().getName);  //获取key

            URLDecoder.decoder(request.getCookie().getValue);  //获取value

6.cookie案例

6.1、记住用户名

登录时,在服务器端获取到用户名,然后创建一个cookie,将用户名存入cookie中,发送回浏览器端,然后浏览器下次在访问登录页面时,先拿到cookie,将cookie中的信息拿出来,看是否保存了该用户名,如果保存了,那么直接用他,如果没有,则自己手写用户名。

6.2、历史记录

比如购物网站,都会有我们的浏览记录的,实现原理其实也是用cookie技术,每浏览一个商品,就将其存入cookie中,到需要显示浏览记录时,只需要将cookie拿出来遍历即可。  

同样,会员卡的例子的第三种方法,发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。 这就是session的用法,在服务器端来保持状态,保存一些用户信息。

     功能作用:服务器用于共享数据技术,

         

Session

img

首先,浏览器1发送一个全新的请求,tomcat发现没有见过这个请求,就在tomcat内存空间开辟一块空间,记录SessionId:7U809JP

之后当Servlet调用setAttribute,会在那块空间中保存自定义属性:name:张三

当Servlet处理完会返回结果,tomcat会把SessionId:7U809JP随着响应返回给浏览器,浏览器会把这个值保存在Cookie中

以后浏览器1在发送请求时,会把SessionId:7U809JP携带一并发给服务器,服务器得到SessionID后知道数据的存储位置

用户调用了getAttribute后就会返回值

Session操作

获取session:

request.getSession();  //如果没有将创建一个新的,等效getSession(true);有些人不理解,为什么是通过request来获取session,可以这样理解,在获取session时,需要检测请求中是否有session标识,所以需要用request来获取

request.getSession(boolean);  //true:没有将创建,false:没有将返回null

session属性操作:

用来存放一些信息,然后才能共享信息

setAttrubute(key,value);

getAttribute(key);     

session生命周期

常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session 

恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,一般是30分钟,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间

session的生命周期就是:

创建:第一次调用getSession()

销毁:

1、超时,默认30分钟

2、执行api:session.invalidate()将session对象销毁、setMaxInactiveInterval(int interval) 设置有效时间,单位秒

3、服务器非正常关闭

  自杀,直接将JVM马上关闭,

  如果正常关闭,session就会被持久化(写入到文件中,因为session默认的超时时间为30分钟,正常关闭后,就会将session持久化,等30分钟后,就会被删除)

位置: D:\java\tomcat\apache-tomcat-7.0.53\work\Catalina\localhost\test01\SESSIONS.ser

Filter:过滤器

概念:

  • 生活中的过滤器:净水器,空气净化器,土匪、
  • web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
  • 过滤器的作用:
  • 一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤...

快速入门:

  1. 定义一个类,实现接口Filter
  2. 复写方法
  3. 配置拦截路径
@WebFilter("/*")//访问所有资源之前,都会执行该过滤器            
public class FilterDemo1 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("filterDemo1被执行了....");                     
        //放行                   
        filterChain.doFilter(servletRequest,servletResponse);       
    }                          
    @Override    
    
    public void destroy() {           
    }         
}

过滤器-Filter

过滤器(Filter)是J2EE Servlet模块下的组件

Filter的作用是对URL进行统一的拦截处理

Filter通常用于应用程序层面进行全局处理

开发过滤器三要素

任何过滤器都要实现javax.servlet.Filter接口

在Filter接口的doFilter()方法中编写过滤器的功能代码

在web.xml中对过滤器进行配置,说明拦截URL的范围

package com.imooc.filter;import javax.servlet.*;import java.io.IOException;public class MyFristFilter 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);//过滤链传递    }    @Override    public void destroy() {    }}<filter>        <filter-name>Myfilter</filter-name>        <filter-class>com.imooc.filter.MyFristFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>Myfilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>

之后访问HTML或者Servlet都会拦截

img

过滤器生命周期

1.初始化-Filter.init()

2.提供服务-Filter.doFilter()

3.销毁-Filter.destroy()

package com.imooc.filter;


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

public class MyFristFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }

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

    @Override
    public void destroy() {
        System.out.println("过滤器已销毁");
    }
}

过滤器的特性

过滤器对象在Web应用启动时被创建且全局唯一

唯一的过滤器对象在并发环境中采用“多线程”提供服务

过滤器两种开发方式

1.过滤器的配置形式

配置形式维护性更好,适合应用全局过滤

<filter>
    <filter-name>MyFirstFilter</filter-name>
    <filter-class>com.imooc.filter.MyFirstFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFirstFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2.过滤器的注解形式

注解形式开发体验更好,适用于小型项目敏捷开发

@WebFilter (filterName="MyAnnoationFilter",urlPatterns="/*")public class MyAnnotationFilter implements Filter {...}

开发字符集过滤器

Web中文乱码的解决

GET请求-server.xml增加URIEncoding="UTF-8"
POST请求-使用request.setCharacterEncoding("UTF-8");
响应-response.setContentType("text/html; charset=UTF-8")

package com.imooc.filter;import javax.servlet.*;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebFilter(filterName ="CharseterEencodingFilter" ,urlPatterns = "/*")public class CharseterEencodingFilter implements Filter {    @Override    public void init(FilterConfig filterConfig) throws ServletException {    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        HttpServletRequest req= (HttpServletRequest)servletRequest;        HttpServletResponse resp=(HttpServletResponse)servletResponse;        req.setCharacterEncoding("UTF-8");        resp.setContentType("text/html;charset=UTF-8");        filterChain.doFilter(req,resp);    }    @Override    public void destroy() {    }}

过滤器参数化

过滤器为了增强灵活性,允许配置信息放在web.xml

在web.xml中配置设置过滤器参数

<filter>        <filter-name>CharseterEencodingFilter</filter-name>        <filter-class>com.imooc.filter.CharseterEencodingFilter</filter-class>        <init-param>            <param-name>encoding</param-name>            <param-value>UTF-8</param-value>        </init-param>    </filter>package com.imooc.filter;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;//@WebFilter(filterName ="CharseterEencodingFilter" ,urlPatterns = "/*")public class CharseterEencodingFilter implements Filter {    private String encoding;    @Override    public void init(FilterConfig filterConfig) throws ServletException {        encoding=filterConfig.getInitParameter("encoding");    }    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        HttpServletRequest req= (HttpServletRequest)servletRequest;        HttpServletResponse resp=(HttpServletResponse)servletResponse;        req.setCharacterEncoding(encoding);        resp.setContentType("text/html;charset="+encoding);        filterChain.doFilter(req,resp);    }    @Override    public void destroy() {    }}

url-pattern过滤写法

常用写法

/index.jsp - 执行资源精准匹配

/servlet/* - 以前缀进行模糊匹配

*.jsp - 以后缀进行模糊匹配

<filter>    <filter-name>MyFirstFilter</filter-name>    <filter-class>com.imooc.filter.MyFirstFilter</filter-class></filter><filter-mapping>    <filter-name>MyFirstFilter</filter-name>    <url-pattern>/*</url-pattern></filter-mapping>

/ 映射的问题

/ 指映射 Web应用根路径,且只对Servlet生效

默认首页index.jsp会让 失效

/ 与 /* 含义不同,前者指向根路径,后者代表所有

过滤链开发注意事项

每一个过滤器应具有单独职能

过滤器的执行顺序以为准,注解会按照类名排序

调用chain.doFilter()将请求向后传递

例:

新建3个过滤器A,B,C

package com.imooc.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@WebFilter(filterName="FilterA" , urlPatterns="/*")
public class FilterB implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("I'm Filter A");
        chain.doFilter(request, response);
        
    }
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
}
package com.imooc.filter;

        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("/hello")
public class hello extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("hello");
    }
}

浏览器访问hello时会输出

I'm Filter A

I'm Filter B

I'm Filter C

Hello

当把所有的System.out.println("I'm Filter A");和chain.doFilter(request, response);位置互换时会输出

Hello

I'm Filter C

I'm Filter B

I'm Filter A

chain.doFilter会先传递,之后才处理,所以一般放在最后一句

img

练习:

多终端识别

package com.imooc.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DeviceAdapterFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        /*
         /index.html
         PC: /desktop/index.html
         MOBILE: /mobile/index.html
         /test.html
         PC: /desktop/test.html
         MOBILE: /mobile/test.html
         */
        String uri = req.getRequestURI();
        System.out.println("URI:" + uri);
        if(uri.startsWith("/desktop") || uri.startsWith("/mobile")) {
            chain.doFilter(request, response);
        }else {
            String userAgent = req.getHeader("user-agent").toLowerCase();
            String targetURI="";
            if(userAgent.indexOf("android")!=-1 || userAgent.indexOf("iphone") != -1) {
                targetURI = "/mobile" + uri;
                System.out.println("移动端设备正在访问,重新跳转URI:" + targetURI);
                res.sendRedirect(targetURI);
            }else {
                targetURI = "/desktop" + uri;
                System.out.println("PC端设备正在访问,重新跳转URI:" + targetURI);
                res.sendRedirect(targetURI);
            }
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

}
<filter>
      <filter-name>DeviceAdapterFilter</filter-name>
      <filter-class>com.imooc.filter.DeviceAdapterFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>DeviceAdapterFilter</filter-name>
      <url-pattern>*.html</url-pattern>
  </filter-mapping>

Listener:监听器

监听器(Listener)是J2EE Servlet模块下的组件

Listener的作用对Web应用对象的行为进行监控

通过Listener监听自动触发指定的功能代码

过滤器与监听器的区别

过滤器(Filter)的职责是对URL进行过滤拦截,是主动的执行

监听器(Listener)的职责是对Web对象进行监听,是被动触发

开发监听器三要素

实现XxxListener接口,不同接口对应不同监听对象

实现每个接口中独有的方法,实现触发监听的后续操作

在web.xml中配置使监听器生效

package com.imooc.listener;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;import javax.servlet.annotation.WebListener;@WebListener   //注解方式配置public class FirstListener implements ServletContextListener {    @Override    public void contextInitialized(ServletContextEvent sce) {        System.out.println("ServletContext已初始化");    }    @Override    public void contextDestroyed(ServletContextEvent sce) {        System.out.println("ServletContext已销毁");    }}

配置

<listener>        <listener-class>com.imooc.listener.FirstListener</listener-class>    </listener>

三种监听对象

ServletContext - 对全局ServletContext及其属性进行监听

HttpSession - 对用户会话及其属性操作进行监听

ServletRequest - 对请求及属性操作进行监听

六种常用监听接口

内置对象监听接口

ServletContextListener - 监听ServletContext对象创建、销毁等操作

HttpSessionListener - 监听HttpSession对象创建、销毁等操作

ServletRequestListener - 监听HttpServletRequest对象创建、销毁等

生命周期:

package com.imooc.listener;

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 HelloListener extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("hellolistener");
        req.getServletContext().setAttribute("sc--attr1","sc--attr-value");
        req.getSession().setAttribute("session-attr1","session-attr1-value");
        req.setAttribute("requset-attr1","requset-attr1-value");



    }
}
package com.imooc.listener;

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class MyWebListener implements ServletContextListener, HttpSessionListener, ServletRequestListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext已初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContex已销毁");
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("ServletRequest已销毁");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        HttpServletRequest request= (HttpServletRequest)sre.getServletRequest();
        System.out.println("ServletRequest已初始化"+request.getRequestURI());
    }

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        String id = se.getSession().getId();
        System.out.println("HttpSession已初始化"+id);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("HttpSession已销毁");
    }
}

点击查看代码

打开服务器
ServletContext已初始化
03-Aug-2021 19:13:58.478 信息 [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [D:\apache-tomcat-9.0.50\webapps\manager]
浏览器访问hellolistener
ServletRequest已初始化/second/hellolistener
HttpSession已初始化CE48666B45B3089FBC2FDE0BB350334C
ServletRequest已销毁
再次访问
ServletRequest已初始化/second/hellolistener
关闭服务器
ServletContext已销毁

  

属性监听接口

ServletContextAttributeListener - 监听全局属性操作

HttpSessionAttributeListener- 监听用户会话属性操作

ServletRequestAttributeListener - 监听请求属性操作

package com.imooc.listener;

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
@WebListener
public class WebAttribyteListener implements ServletContextAttributeListener, HttpSessionAttributeListener, ServletRequestListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext增加属性"+scae.getName()+scae.getValue());
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext删除属性"+scae.getName()+scae.getName());
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext替换属性"+scae.getName()+scae.getName());
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("ServletRequest删除属性");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("ServletRequest删除属性");
    }

    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("HttpSession添加属性"+se.getName()+se.getName());
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("HttpSession删除属性"+se.getName()+se.getName());
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        System.out.println("HttpSession替换属性"+se.getName()+se.getName());
    }
}

项目中监听器的应用场景

[Documentation - Apache ECharts](https://echarts.apache.org/zh/tutorial.html#5 分钟上手 ECharts)

到ECharts官网 的github下载支持包

或者引入bootsdn的链接  https://www.bootcdn.cn/

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.common.js"></script>
package com.imooc.total;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class RequestListener implements ServletContextListener, ServletRequestListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {

        List timelist=new ArrayList();
        List valuelist=new ArrayList();

        sce.getServletContext().setAttribute("timelist",timelist);
        sce.getServletContext().setAttribute("valuelist",valuelist);
    }
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        HttpServletRequest request=(HttpServletRequest)sre.getServletRequest();
        String url=request.getRequestURI();
        if(url.endsWith("/rtservlet")==true) {
            return;
        }
        List<String> timelist= (List)sre.getServletContext().getAttribute("timelist");
        List<Integer> valuelist= (List)sre.getServletContext().getAttribute("valuelist");
        Date date=new Date();
        SimpleDateFormat adf=new SimpleDateFormat("HH:mm");
        String time=adf.format(date);
        if(timelist.indexOf(time)==-1){
            timelist.add(time);
            valuelist.add(1);
        }
        else{
            int index=timelist.indexOf(time);
            int value=valuelist.get(index);
            valuelist.set(index,value+1);
        }
        sre.getServletContext().setAttribute("timelist",timelist);
        sre.getServletContext().setAttribute("valuelist",valuelist);

    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.common.js"></script>
    <title>Title</title>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        function showChart(){
            $.ajax({
                url:"/rt/rtservlet",
                type:"get",
                dataType:"json",
                success:function (json) {
                    console.log(json.timelist)
                    console.log(json.valuelist)
                    // 基于准备好的dom,初始化echarts实例
                    var myChart = echarts.init(document.getElementById('main'));

                    // 指定图表的配置项和数据
                    var option = {
                        title: {
                            text: '请求流量分析统计'
                        },
                        tooltip: {},
                        legend: {
                            data:['访问量']
                        },
                        xAxis: {
                            data:json.timelist
                        },
                        yAxis: {},
                        series: [{
                            name: '访问量',
                            type: 'line',
                            data: json.valuelist
                        }]
                    };

                    // 使用刚指定的配置项和数据显示图表。
                    myChart.setOption(option);
                }
            })
        }
        window.setInterval("showChart()",1000)

</script>
</div>
</body>
</html>

新建几个页面模拟访问

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>

    <title>Test page1</title>
</head>
<body>
<h1>Test page1</h1>
</body>
</html>
posted @ 2021-07-26 14:03  丨渍丨  阅读(107)  评论(0)    收藏  举报