Web(含小型項目)

web

文章資源:
链接:https://pan.baidu.com/s/18YhBiuRQzC7-hrdw3LtkjA
提取码:8888

文章目录

1.软件架构

​ 1.C/S:客户端/服务器端

​ 2.B/S:浏览器/服务器端

2.资源分类

​ 1.静态资源:所有用户访问后,得到的结果都是一样的,称为静态资源,静态资源可以直接被浏览器解析

​ 如:html、css、JavaScript

​ 2.动态资源:每个用户访问相同资源后,得到的结果可能不一样。称为动态资源。动态资源被访问后,需要先转换为静态资 源,在返回给流量器

​ 如:servlet/jsp、php、asp…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FgfW7Ykh-1659791971299)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731205300903.png)]

3.网络通讯三要素

​ 1.IP:电子设备(如:计算机)在网络中的唯一标识。

​ 2.端口:应用程序在计算机中的唯一标识。0~65536

​ 3.传输协议:规定了数据传输的规则。

​ 基础协议:

​ 1.tcp:安全协议,三次握手。速度慢

​ 2.upd:不安全协议。速度快

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8egbnmbo-1659791971300)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731205728070.png)]

4.web服务器软件

​ 1.服务器:按照了服务器软件的计算机。

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

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

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

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

​ 1.webLogic:Oracle公司的,大型的JavaEE服务器,支持所有的JavaEE规范,需要收费的

​ 2.webSphere:IBM公司的,大型的JavaEE服务器,支持所有的JavaEE规范,需要收费的

​ 3.JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,需要收费的

​ 4.Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范,开源免费的

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

Tomcat

1.概述

​ Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范,开源免费的

2.下载安装以及配置

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

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

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

3.卸载:删除目录即可

4.启动

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

​ 2.访问:浏览器输入:http:localhost:8080 回车访问

​ 3.可能遇到的问题

​ 1.命令行窗口一闪而过:

​ 原因:没有正确配置JAVA_HOME环境变量

​ 解决方案:正确配置JAVA_HOME环境变量

Tomcat的启动需要依赖于JDK

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uwQtxOs7-1659791971300)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731212133291.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JpWKxGRL-1659791971301)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731212158320.png)]

​ 2.启动报错

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VUj3Hhjy-1659791971301)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731213214668.png)]

​ 2.温柔:修改端口号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ghToS2YM-1659791971301)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731213359063.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y5k4WZ4b-1659791971302)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731213709314.png)]

5.关闭

​ 1.运行bin/shutdown.bat

​ 2.ctrl+c

6.配置

​ 部署项目的方式

​ 1.直接将项目放到webapps目录下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8UFhmDCn-1659791971302)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731214237455.png)]

​ 运行:localhost:8080/hello/hello.html

​ 2.简便方式,将运行的hello目录(里边有hello.html文件)先压缩,然后修改后缀名为*.war

​		[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AIThj7FK-1659791971302)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731214425061.png)]

​ 运行:localhost:8080/hello/hello.html

​ 3.配置conf/server.xml文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uNvaf9zL-1659791971303)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731214744416.png)]

​ 运行:localhost:8080/hehe/hello.html

​ 4.在conf\Catalina\localhost目录下创建任意名称的xml文件。在文件中编写图中内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tzw4jg5S-1659791971303)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220731215107168.png)]

​ 运行:localhost:8080/bbb/hello.html

Servlet

1.概率

​ Servlet:server applet

​ 运行在服务器端的小程序

​ Servlet就是一个接口,定义了Java类被浏览器访问到(Tomcat识别)的规则。

​ 将来我们自定义一个类,实现Servlet接口,复写方法。

2.快速入门

1.创建JavaEE项目

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

这里需要注意:使用Servlet需要导包

在pom.xml中进行导包

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
</dependencies>

测试代码

package com.kk.web.servlet;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : servlet快速入門
 */
public class Demo01 implements Servlet {
    
    
}

3.实现接口中的抽象方法

package com.kk.web.servlet;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : servlet快速入門
 */
public class Demo01 implements Servlet {
    
    
    @Override
    public void init(ServletConfig config) throws ServletException {
    
    

    }

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

    /**
     * 提供服務的方法
     * @param req
     * @param res
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    
    
        System.out.println("Hello Servlet");
    }

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

    @Override
    public void destroy() {
    
    

    }
}

4.配置Sservlet

在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>
        <servlet-name>demo01</servlet-name>
        <servlet-class>com.kk.web.servlet.Demo01</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>demo01</servlet-name>
        <url-pattern>/demo01</url-pattern>
    </servlet-mapping>


</web-app>

運行結果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RitWrtOT-1659791971303)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220801141257556.png)]

3.执行原理

​ 1.当服务器接收到客户端浏览器的请求后,会解析请求url路径,获取访问的Servlet的资源路径

​ 2.查找web.xml文件,是否有对应的标签体内容

​ 3.如果有,则再找到对应的全类名

​ 4.tomcat会将字节码文件加载进内存,并且创建其对象

​ 5.调用其方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3H2X3qEN-1659791971304)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220801142547500.png)]

4.Servlet中的生命周期方法

1.被创建:执行init方法,只执行一次

​ 1.Servlet什么时候被创建?

​ 默认情况下第一次被访问时,Servlet被创建。

​ 2.可以配置指定Serlvet的创建时机

在web.xml中的<servlet>标签下配置

​ 1.第一次被访问时,创建

​ 的值为负数
​ 2.在服务器启动时,创建

​ 的值为0或正整数

​ 3.Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的

​ 问题:多个用户同时访问时,可能存在线程安全问题。

​ 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量也不要对其修改值。``

2.提供服务:执行service方法,执行多次

​ 每次访问Serlvet时,service方法都会被调用一次。

3.被销毁:执行destroy,只执行一次

​ 1.Servlet被销毁时执行。服务器关闭时,Serlvet被销毁。

​ 2.只有服务器正常关闭时,才会执行destroy。

​ 3.destroy访问在Servlet被销毁之前执行,一般用于释放资源

代码

package com.kk.web.servlet;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : servlet的方法
 */
public class Demo02 implements Servlet {
    
    

    /**
     * 初始化方法
     * 在Servlet被创建时被执行,只会执行一次
     *
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
    
    
        System.out.println("init...");
    }


    /**
     * 获取ServletConfig对象
     * ServletConfig:Servlet的配置对象
     * @return
     */
    @Override
    public ServletConfig getServletConfig() {
    
    
        return null;
    }


    /**
     * 提供服务方法
     * 每一次Servlet被访问时就执行,执行多次
     *
     * @param req
     * @param res
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    
    
        System.out.println("service...");
    }


    /**
     * 获取Serlvet的一些信息 版本、作者等...
     * @return
     */
    @Override
    public String getServletInfo() {
    
    
        return null;
    }

    /**
     * 消费方法
     * 在服务器正常关闭时执行,只会执行一次
     */
    @Override
    public void destroy() {
    
    
        System.out.println("destroy...");
    }
}

4.Servlet 3.0以上

​ |>好处

​ 支持注解配置。可以不需要web.xml了。

​ |>步骤:

​ 1.创建JavaEE项目,选择Servlet的版本3.0以上,可以不选择web.xml

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

​ 3.复写方法

​ 4.在类上使用@WebServlet注解,进行配置

​ @WebServlet(“资源路径”)

代码演示

	package com.kk.web.servlet;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 注解配置访问路径
 */
//@WebServlet(urlPatterns = "/demo03")
@WebServlet("/demo03")
public class Demo03 implements Servlet {
    
    


    @Override	
    public void init(ServletConfig config) throws ServletException {
    
    

    }

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

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    
    
        System.out.println("Serlvet 3.0+++");
    }

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

    @Override
    public void destroy() {
    
    

    }
}

5.Servlet体系结构

​ 1.Servlet — 接口

​ |

​ 2.GenericServlet — 抽象类

​ |

​ 3.HttpServlet — 抽象类

​ |>GenericServlet:将Serlvet接口中的其他的方法做了默认空实现,只将service()方法作为抽象

​ 将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可

​ |>HttpServlet:对http协议的一种封装,简化操作

​ 1.定义类继承HttpServlet

​ 2.复写doGet/doPost方法

代码演示GenericServlet

package com.kk.web.servlet;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : Servlet体系结构
 */
@WebServlet("/demo05")
public class Demo05 extends GenericServlet {
    
    

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    
    
        System.out.println("GenericServlet--->service...");
    }
}

代码演示HttpServlet

package com.kk.web.servlet;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : Servlet体系结构
 */
@WebServlet("/demo06")
public class Demo06 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        System.out.println("doGet...");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        System.out.println("doPost...");
    }
}

在web目录下创建login.html

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

    <form action="/demo06" method="post">
        <label>
            <input name="username">
        </label>
        <input type="submit" value="提交">
    </form>

</body>
</html>

访问:http://localhost:8080/login.html

6.Servlet的相关配置

​ 1.urlpartten:Servlet的访问路径

​ 一个Servlet可以定义多个访问路径:@WebServlet({“/d07”,“/demo07”,“/de07”})

​ 2.路径定义规则

​ |> /xxx

​ |> /xxx/xxx

​ |> *.do

代码演示

package com.kk.web.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;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : Servlet的相关配置
 */
//@WebServlet({"/d07","/demo07","/de07"})
@WebServlet("/user/demo07")  
//@WebServlet("/user/*")
//@WebServlet("*.do")
public class Demo07 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        System.out.println("doGet--->Demo07...");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        System.out.println("doPost--->Demo07...");
    }
}

HTTP协议

1.概念

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

​ 传输协议:定义了客户端和服务器端通信时,发送数据的格式

​ 特点:

​ 1.基于tcp/ip的高级协议

​ 2.默认端口号:80

​ 3.基于请求/响应模型,一次请求一次响应

​ 4.无状态的:每次请求之间相互独立,不能交互数据

​ 历史版本:

​ 1.0:每一次请求都会建立新的连接

​ 1.1:复用连接

2.请求消息数据格式

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

1.请求行

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

​ GET /login.html HTTP/1.1

​ 请求方式:

​ HTTP协议中有7中请求方式,常用的有2种

​ |> GET

​ 1.请求参数在请求行中,即在url后

​ 2.请求的url长度是有限制的

​ 3.不太安全

​ |> POST

​ 1.请求参数在请求体中

​ 2.请求的url长度是没有限制的

​ 3.相对安全

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

​ 请求头名称:请求头值

​ 常见的请求头:

​ 1.User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息

​ 可以在服务器端获取该头的信息,解决浏览器的兼容性问题

​ 2.Referce:http://localhost/login.html

​ 告诉服务器,我(当前请求)从哪里来

​ 作用

防盗链:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A1ptqQ2E-1659791971304)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220801161157061.png)]

统计工作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOur7Kfb-1659791971304)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220801161310913.png)]

3.请求空行

​ |> 空行,用于分割POST请求的请求头和请求体的

4.请求体(正文)

​ |> 封装POST请求消息的请求参数的

3.响应消息数据格式

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

|> 数据格式:

1.响应行

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

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

​ 1.状态码都是3位数字

​ 2.分类:

​ |> 1xx:服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx多的状态吗。

​ |> 2xx:成功。代表:200

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

​ |> 4xx:客户端错误。代表:404(请求路径没有对应的资源),405(请求方式没有对应的doXxx方法)

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

2.响应头

​ 1.格式:头名称:值

​ 2.常见的响应头:

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

​ 2.Content-disposition:服务器告诉客户端以什么格式打开响应体数据

​ 值:

​ in-line:默认值,在当前页面内打开

​ attachment:以附件形式打开响应体。文件下载

3.响应空行

4.响应体

​ 传输的数据

Request

1.原理

​ |> request对象和response对象的原理

​ 1.request和response对象是由服务器创建的。我们来使用他们

​ 2.request对象是来获取请求消息,response对象是来设置响应消息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mFoHrHcK-1659791971305)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220801162140214.png)]

2.Request对象继承体系结构

​ |> ServletRequest – 接口

​ | 继承

​ |> HttpServletRequest – 接口

​ | 实现

​ |> org.apache.catalina.connector.RequestFacade 类(tomcat编写的)

3.Request获取请求消息

1.获取请求消息数据

​ 1.获取请求行数据

​ GET /user/demo01/username=zhangsan HTTP/1.1

​ 方法:

​ 1.获取请求方式:GET

​ String getMethod()

​ 2.获取虚拟目录:/user

​ String getContextPath()

​ 3.获取Servlet路径:/demo01

​ String getServletPath()

​ 4.获取get方式的请求方式:username=zhangsan

​ String getQueryString()

​ 5.获取请求的URI:/user/demo01

​ String getRequestRUI(): /user/demo01

​ StringBuffer getRequestURL():http://localhost:8080/user/demo01

​ 6.获取协议及版本:HTTP/1.1

​ String getProtocol()

​ 7.获取客户机的IP地址

​ String getRemoteAddr()

代码演示

package com.kk.web.request;


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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :  http://localhost:8080/requestDemo01?username=zhangsan
 */
@WebServlet("/requestDemo01")
public class Demo01 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        String method = request.getMethod();
        System.out.println(method);

        String contextPath = request.getContextPath();
        System.out.println(contextPath);

        String servletPath = request.getServletPath();
        System.out.println(servletPath);

        String queryString = request.getQueryString();
        System.out.println(queryString);

        String requestURI = request.getRequestURI();
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURI);
        System.out.println(requestURL);

        String protocol = request.getProtocol();
        System.out.println(protocol);

        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);


        /**
         * GET
         *
         * /requestDemo01
         * username=zhangsan
         * /requestDemo01
         * http://localhost:8080/requestDemo01
         * HTTP/1.1
         * 0:0:0:0:0:0:0:1
         */
    }

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

    }
}

2.获取请求头数据

​ 方法:

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

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

代码演示1

package com.kk.web.request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;
/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 获取请求头数据
 */

@WebServlet("/requestDemo02")
public class Demo02 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //获取所有的请求头名称
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
    
    
            String name = headerNames.nextElement();
            //根据名称获取请求头的值
            String value = request.getHeader(name);

            System.out.println(name +":" + value);
        }

    }

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

    }
}

代码演示2

package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 获取请求头数据
 */

@WebServlet("/requestDemo03")
public class Demo03 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
       //获取请求头数据 user-agent
        String agent = request.getHeader("user-agent");

        //判斷agent的浏览器版本
        if (agent.contains("Chrome")){
    
    
            System.out.println("谷歌");
        }else if (agent.contains("Firefox")){
    
    
            System.out.println("火狐");
        }


    }

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

    }
}

代码演示3

package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 获取请求头数据
 */

@WebServlet("/requestDemo04")
public class Demo04 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //获取请求头数据 referer
        String referer = request.getHeader("referer");
        System.out.println(referer); //http://localhost:8080/login.html

        //防盗链
        //若正版连接  http://localhost:8080/youku/login.html
        if (referer != null) {
    
    
            if (referer.contains("/youku")) {
    
    
                //正常访问
                System.out.println("正常播放电影中...");
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write("正常播放电影中...");
            } else {
    
    
                //盗链
                //当不是这个连接(http://localhost:8080/youku/login.html)去访问(http://localhost:8080/requestDemo04)的时候会进行防盗链
                System.out.println("想看电影? 来优酷吧...");
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write("想看电影? 来优酷吧...");
            }
        }
    }

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

    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form action="/demo06" method="post">
        <label>
            <input name="username">
        </label>
        <input type="submit" value="提交">
    </form>

    <a href="/requestDemo04">requestDemo04</a>

</body>
</html>

3.获取请求体数据

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

​ 步驟:

​ 1.获取流对象

​ BufferedReader getReader():获取字符输入流,只能操作字符数据

​ ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据

​ 2.再从流对象中拿数据

代码演示

package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 获取请求体数据
 */

@WebServlet("/requestDemo05")
public class Demo05 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    

    }

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

        //获取请求消息体 --- 请求参数
        //获取字符流
        BufferedReader br = request.getReader();
        //读取数据
        String line = null;
        while ((line = br.readLine())!=null){
    
    
            System.out.println(line);
        }


    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form action="/requestDemo05" method="post">
        <input type="text" placeholder="请输入用户名" name="username"> <br>
        <input type="text" placeholder="请输入密码" name="password"> <br>
        <input type="submit" value="注册">
    </form>
</body>
</html>

4.其他功能

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

​ 1.String getParameter(String name):根据参数名称获取参数值

​ 2.String[] getParameterValues(String name):根据参数名称获取参数值的数组

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

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

代码演示

package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 获取请求体数据
 */

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //post获取请求参数
        String username = request.getParameter("username");
        System.out.println(username);


        System.out.println("--------------------------------------");

        //根据参数名称获取参数值的数组
        String[] hobbies = request.getParameterValues("hobby");
        for (String hobby : hobbies) {
    
    
            System.out.println(hobby);
        }


        System.out.println("--------------------------------------");

        //获取所有请求参数名称
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()){
    
    
            String name = parameterNames.nextElement();
            System.out.println(name);
            String value = request.getParameter(name);
            System.out.println(value);
            System.out.println("......");
        }


        System.out.println("--------------------------------------");

        //获取所有参数的map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> keySet = parameterMap.keySet();
        for (String name : keySet) {
    
    
            //根据键获取值
            String[] values = parameterMap.get(name);
            System.out.println(name);
            for (String value : values) {
    
    
                System.out.println(value);
            }
            System.out.println("......");
        }
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/requestDemo06" method="post">
    <input type="text" placeholder="请输入用户名" name="username"> <br>
    <input type="text" placeholder="请输入密码" name="password"> <br>
    <input type="checkbox" name="hobby" value="game">游戏<br>
    <input type="checkbox" name="hobby" value="study">学习<br>
    <input type="submit" value="注册">
</form>

</body>
</html>

中文乱码问题

​ get方法:tomcat8以上已经将get方式乱码问题解决了

​ post方式:会乱码

​ 解决:

​ 在获取参数前,设置request的编码

package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 获取请求体数据
 */

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

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


        //设置流的字符集
        request.setCharacterEncoding("utf-8");

        //post获取请求参数
        String username = request.getParameter("username");
        System.out.println(username);


    }
}

​ 2.请求转发

​ |> 一种在服务器内部的资源跳转方式

​ |> 步骤

​ 1.通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path);

​ 2.使用RequestDispatcher这个对象来进行转换:forward(ServletRequest request, ServletResponse response)

​ |> 特点

​ 1.浏览器地址栏路径没有发生变化

​ 2.只能转发到当前服务器内部资源中

​ 3.转发是一次请求

代码演示

package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 请求转发
 */

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        System.out.println("Demo07被访问了...");

        //转发到demo8资源
        request.getRequestDispatcher("/requestDemo08").forward(request, response);
    }
}
package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 请求转发
 */

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        System.out.println("Demo08被访问了...");

    }
}

​ 3.共享数据

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

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

​ 方法:

​ 1.void setAttribute(String name,Object obj):存储数据

​ 2.Object getAttribute(String name):通过键获取值

​ 3.void removeAttribute(String name):通过键移除键值对

代码演示

package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 请求转发
 */

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        System.out.println("Demo07被访问了...");

        //存取数据到request域中
        request.setAttribute("message","hello");

        //转发到demo8资源
        request.getRequestDispatcher("/requestDemo08").forward(request, response);
    }
}
package com.kk.web.request;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 请求转发
 */

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        System.out.println("Demo08被访问了...");

        //获取数据
        Object message = request.getAttribute("message");
        System.out.println(message);

    }
}

​ 4.获取ServletContext

​ ServletContext getServletContext()

代码演示

package com.kk.web.request;

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;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc : 获取ServletContext
 */

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        ServletContext servletContext = request.getServletContext();
        System.out.println(servletContext);
    }
}

4.登录案例

​ 用户案例需求:

​ 1.编写login.html登录页面

​ username & password 两个输入框

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

​ 3.使用jdbcTemplate技术封装jdbc

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

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

分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6wmvgdpQ-1659791971305)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220801221329068.png)]

开发步骤

1.创建项目导入html页面,配置文件以及导包

html

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

</body>
</html>

配置文件

放置在resources目录下

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db1?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
characterEncoding=utf-8
username=root
password=123456

initialSize=5

maxActive=10

maxWait=3000

validationQuery=SELECT 1

testWhileIdle=true

导包

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.27</version>
    </dependency>
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.4</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.11</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.20</version>
    </dependency>

    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.20</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

2.创建数据库环境

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 80027
 Source Host           : localhost:3306
 Source Schema         : db1

 Target Server Type    : MySQL
 Target Server Version : 80027
 File Encoding         : 65001

 Date: 01/08/2022 22:20:13
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'admin', '123456');
INSERT INTO `user` VALUES (2, 'test', '123456');

SET FOREIGN_KEY_CHECKS = 1;

3.创建domain包在里边创建User实体类

package com.kk.web.domain;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */
public class User {
    
    
    private Integer id;
    private String username;
    private String password;


    public User() {
    
    
    }

    public User(Integer id, String username, String password) {
    
    
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

​ 4.创建dao包,创建接口UserDao,提供login方法,创建实现类UserDaoImpl实现UserDao方法

UserDao

package com.kk.web.dao;

import com.kk.web.domain.User;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */
public interface UserDao {
    
    

    /**
     * 登录方法
     * @param user
     * @return
     */
    User login(User loginUser);
}

UserDaoImpl

package com.kk.web.dao;


import com.kk.web.domain.User;

import com.kk.web.util.jdbcUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */
public class UserDaoImpl implements UserDao {
    
    

    //声明JdbcTemplate对象共用

    private JdbcTemplate template = new JdbcTemplate(jdbcUtils.getDataSource());

    @Override
    public User login(User loginUser) {
    
    
        //编写sql
        String sql = "select * from user where username = ? and password = ?";

        //调用template方法
        User user = template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),loginUser.getUsername(),loginUser.getPassword());
        return user;
    }
}

​ 5.测试UserDaoImpl

import com.kk.web.dao.UserDao;
import com.kk.web.dao.UserDaoImpl;
import com.kk.web.domain.User;
import org.junit.Test;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */
public class test {
    
    


    @Test
    public void test1() {
    
    
        UserDao userDao = new UserDaoImpl();
        User loginUser = new User();
        loginUser.setUsername("admin");
        loginUser.setPassword("123456");
        User user = userDao.login(loginUser);

        System.out.println(user);
    }
}

6.编写LoginSerlvet类继承HttpServlet

package com.kk.web.servlet;

import com.kk.web.dao.UserDao;
import com.kk.web.dao.UserDaoImpl;
import com.kk.web.domain.User;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //设置编码
        req.setCharacterEncoding("utf-8");

        //获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        //封装User对象
        User loginUser = new User();
        loginUser.setUsername(username);
        loginUser.setPassword(password);

        //调用UserDao的login方法
        UserDao userDao = new UserDaoImpl();
        User user = userDao.login(loginUser);

        //判断user
        if (user == null) {
    
    
            req.getRequestDispatcher("/failServlet").forward(req, resp);
        } else {
    
    
            req.setAttribute("user", user);
            req.getRequestDispatcher("/successServlet").forward(req, resp);
        };
    }
}
package com.kk.web.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;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */

@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
    
    

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //设置编码
        resp.setContentType("text/html;charset=utf-8");
        //输出
        resp.getWriter().write("登录失败,用户名或密码错误");
    }
}
package com.kk.web.servlet;

import com.kk.web.domain.User;

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

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */

@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
    
    

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

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //获取req域中共享数据
        User user = (User) req.getAttribute("user");

        if (user != null) {
    
    
            //设置编码
            resp.setContentType("text/html;charset=utf-8");
            //输出
            resp.getWriter().write("登录成功" + user.getUsername() + ",欢迎您");
        }

    }
}

7.login.html中的form表单的action路径写法

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

</body>
</html>

9.BeanUtils工具类,简化数据封装

导包

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.4</version>
</dependency>

代碼演示

package com.kk.web.servlet;

import com.kk.web.dao.UserDao;
import com.kk.web.dao.UserDaoImpl;
import com.kk.web.domain.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.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Objects;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //设置编码
        req.setCharacterEncoding("utf-8");

//        //获取请求参数
//        String username = req.getParameter("username");
//        String password = req.getParameter("password");
//
//        //封装User对象
//        User loginUser = new User();
//        loginUser.setUsername(username);
//        loginUser.setPassword(password);

        //获取所有请求参数
        Map<String, String[]> map = req.getParameterMap();
        //创建User对象
        User loginUser = new User();
        //使用BeanUtils封装
        try {
    
    
            BeanUtils.populate(loginUser, map);
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        } catch (InvocationTargetException e) {
    
    
            e.printStackTrace();
        }

        //调用UserDao的login方法
        UserDao userDao = new UserDaoImpl();
        User user = userDao.login(loginUser);

        //判断user
        if (user == null) {
    
    
            req.getRequestDispatcher("/failServlet").forward(req, resp);
        } else {
    
    
            req.setAttribute("user", user);
            req.getRequestDispatcher("/successServlet").forward(req, resp);
        };
    }
}

BeanUtils工具类,简化数据封装

​ 用于封装JavaBean

​ 1.JavaBean:标准的Java类

​ 1.要求:

​ 1.类必须被public修饰

​ 2.必须提供空参的构造器

​ 3.成员变量必须使用private修饰

​ 4.提供公共setter和getter方法

​ 2.功能:封装数据

​ 2.概念:

​ 成员变量:

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

​ 3.方法:

​ 1.setProperty()

​ 2.getProperty()

​ 3.populate(Object obj,Map map):将map集合的键值信息封装到对应的JavaBean对象中

代码演示

import com.kk.web.dao.UserDao;
import com.kk.web.dao.UserDaoImpl;
import com.kk.web.domain.User;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import org.springframework.context.annotation.Bean;

import java.lang.reflect.InvocationTargetException;

/**
 * @author : k
 * @Date : 2022/8/1
 * @Desc :
 */
public class TestDome {
    
    


    @Test
    public void test() {
    
    
        User user = new User();
        try {
    
    
            BeanUtils.setProperty(user, "username","zhangsan");
            System.out.println(user);

            String username = BeanUtils.getProperty(user, "username");
            System.out.println(username);
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        } catch (InvocationTargetException e) {
    
    
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
    
    
            e.printStackTrace();
        }
    }

}

Response

1.功能

設置响应消息

1.设置响应行

​ 1.格式:HTTP/1.1 200 ok

​ 20设置响应码:setStatus(int sc);

2.设置响应头

​ setHeader(String name,String value)

3.设置响应体

​ 使用步骤:

​ 1.获取输出流

​ 1.字符输出流:PrintWrite getWriter()

​ 2.字节输出流:ServletOutputStream getOutputStream()

​ 2.使用输出流,将数据输出到客户端浏览器或控制台

2.重定向

​ |> 重定向:资源跳转的方式

​ |> 代码实现:

​ //访问 /responseDemo01 会自动跳转到 /responseDemo02 资源
​ 设置状态码为302
​ resp.setStatus(302);
​ //设置响应头
​ resp.setHeader(“location”,“/responseDemo02”);

​ //简单的重定向方法

​ resp.sendRedirect(“/responseDemo02”);

​ |> 转发的特点:forward

​ 1.转发地址栏路径不变

​ 2.转发只能访问当前服务器下的资源

3.转发只能一次请求,可以使用request对象来共享数据

​ |> 重定向的特点:redirect

​ 1.地址栏发生变化

​ 2.重定向可以访问其他站点(服务器)的资源

3.重定向是两次请求,不能使用response对象来共享数据

​ |> 路径写法:

​ 1.路径分类

​ 1.相对路径:通过相对路径不可以确定唯一资源

​ 如:./index.html

​ 不以 / 开头, 以 . 开头路径

​ 规则:找到访问当前资源和目标资源之间的相对位置关系

​ ./:代表当前目录

​ …/:代表后退一级目录

​ 2.绝对路径:通过绝对路径确定唯一资源

​ 如:http://localhost:8080/responseDemo01 /responseDemo01

​ 以 / 开头的路径

​ 规则:判断定义的路径是给誰用的?判断请求将来从哪发出

​ 给客户端浏览器用的:需要虚拟目录(项目的访问路径)如:重定向

​ 建议虚拟目录动态获取:req.getContextPath();

​ 、 、重定向

​ 给服务器使用:不需要加虚拟目录。如:转发

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KYGE1HlI-1659791971306)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220802164530492.png)]

代码演示

package com.kk.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;

/**
 * @author : k
 * @Date : 2022/8/2
 * @Desc : 重定向
 */
@WebServlet("/responseDemo01")
public class Demo01 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

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

        System.out.println("Demo01...");

        //动态获取虚拟目录
        String contextPath = req.getContextPath();


        //访问 /responseDemo01 会自动跳转到 /responseDemo02 资源
        //设置状态码为302
        //resp.setStatus(302);
        //设置响应头
        //resp.setHeader("location","/responseDemo02");

        //简单的重定向方法
        resp.sendRedirect(contextPath+"/responseDemo02");
        //resp.sendRedirect("https://www.baidu.com");
    }
}

package com.kk.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;

/**
 * @author : k
 * @Date : 2022/8/2
 * @Desc : 重定向
 */
@WebServlet("/responseDemo02")
public class Demo02 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        System.out.println("Demo02...");
    }
}

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

​ 步骤:

​ 1.获取字符输出流

​ 2.输出数据

​ 注意:

​ 乱码问题

​ 1.PrintWriter pw = resp.getWriter();获取的流的默认编码是IOS-8859-1

​ 2.设置该流的默认编码

​ 3.告诉浏览器响应体的编码

​ 注意是需要在获取流之前设置:

​ resp.setContentType(“text/html;charset=utf-8”);

代码演示

package com.kk.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;

/**
 * @author : k
 * @Date : 2022/8/2
 * @Desc : 
 */
@WebServlet("/responseDemo04")
public class Demo04 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //获取流对象之前,设置流的默认编码(IOS-8859-1),将其设置为GBK
        //resp.setCharacterEncoding("utf-8");

        //告诉浏览器,服务器发送的消息体数据的编码,建议浏览器使用该编码解码
        //resp.setHeader("content-type","text/html;charset=utf-8");

        //简单的形式设置编码
        resp.setContentType("text/html;charset=utf-8");

        //获取字符输出流
        PrintWriter pw = resp.getWriter();
        //输出数据
        pw.write("hello responseDemo04 ");
        pw.write("<h1>hello responseDemo04</h1>");
        pw.write("<h1>你好 responseDemo04</h1>");
    }
}

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

代码演示

package com.kk.servlet;

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

/**
 * @author : k
 * @Date : 2022/8/2
 * @Desc : 服务器输出字节数据到浏览器
 */
@WebServlet("/responseDemo05")
public class Demo05 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //简单的形式设置编码
        resp.setContentType("text/html;charset=utf-8");

        //获取字节输出流
        ServletOutputStream sos = resp.getOutputStream();
        //输出数据
        sos.write("hello".getBytes());
        sos.write("你好".getBytes("utf-8"));

    }
}

5.验证码

​ 1.本质:图片

​ 2.目的:防止恶意表单注册

代码演示

package com.kk.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

/**
 * @author : k
 * @Date : 2022/8/2
 * @Desc : 验证码
 */
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        int width = 100;
        int height = 50;


        //创建一对象,在内存中图片(验证码图片对象)
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);


        //美化图片
        //填充背景色
        Graphics g = image.getGraphics();  //画笔对象
        g.setColor(Color.PINK);  //设置画笔颜色
        g.fillRect(0, 0, width, height);

        //画边框
        g.setColor(Color.BLUE);
        g.drawRect(0, 0, width - 1, height - 1);

        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvuvwxyz0123456789";

        //生产随机角标
        Random ran = new Random();
        for (int i = 1; i <= 4; i++){
    
    
            int index = ran.nextInt(str.length());
            //获取字符
            char ch = str.charAt(index);  //随机字符

            //写验证码
            g.drawString(ch+"", width/5*i, height/2);

        }

        //画干扰线
        g.setColor(Color.GREEN);
        //随机生成坐标点
        for (int i = 0; i < 10; i++) {
    
    
            int x1 = ran.nextInt(width);
            int x2 = ran.nextInt(width);
            int y1 = ran.nextInt(width);
            int y2 = ran.nextInt(width);
            g.drawLine(x1,y1,x2,y2);
        }










        //将图片输出到页面展示
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>


    <script>
        /*
        分析:
            点击超链接或者图片,需要换一张
            1.给超链接和图片绑定单击事件
            2.重新设置图片的src属性值
         */

        window.onload = function (){
      
      
            //获取图片
            var img = document.getElementById("checkCode")
            //绑定单击事件
            img.onclick = function () {
      
      
                //加时间戳
                var date =  new Date().getTime();
                img.src = "/checkCodeServlet?"+date;
            }


            //获取a标签
            var a = document.getElementById("change")
            a.onclick = function (){
      
      
                //加时间戳
                var date =  new Date().getTime();
                img.src = "/checkCodeServlet?"+date;
            }

        }
    </script>


</head>
<body>
    <img id="checkCode" src="/checkCodeServlet" >
    <a id="change" href="javascript:;">看不清,换一张</a>
</body>
</html>

ServletContext

1.概念

​ |> 代表整個web應用,可以和程序的容器(服務器)來通信

2.获取

​ 1.通過request對象獲取

​ |> request.getServletContext();

​ 2.通過HttpServlet獲取

​ |> this.getServletContext();

代碼演示

package com.kk.servletcontext;

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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc :
 */
@WebServlet("/servletContextDemo01")
public class Demo01 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //ServletContext對象獲取

        ServletContext context1 = req.getServletContext();

        ServletContext context2 = this.getServletContext();

        System.out.println(context1==context2);//true
        System.out.println(context1);
        System.out.println(context2);
    }
}

3.功能

​ 1.獲取MIME類型

​ MIME類型:在互聯網通信過程中定義的一種文件數據類型

​ 格式:大類型/小類型 text/html image/jpeg

​ 獲取:String getMimeType(String file)

代碼演示

package com.kk.servletcontext;

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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : 獲取MIME類型
 */
@WebServlet("/servletContextDemo02")
public class Demo02 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //ServletContext功能
        ServletContext context = this.getServletContext();

        //定義文件名稱
        String fileName = "a.jpg";

        //獲取MIME類型
        String mimeType = context.getMimeType(fileName);

        System.out.println(mimeType);

    }
}

​ 2.域對象:共享數據

​ 1.setAttribute(String name,Object value)

​ 2.getAttribute(String name)

​ 3.removeAttribute(String name)

​ 該ServletContext对象范围:所有用戶請求的數據

代码演示

package com.kk.servletcontext;

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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : 域對象:共享數據
 */
@WebServlet("/servletContextDemo03")
public class Demo03 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //ServletContext功能
        ServletContext context = this.getServletContext();

        //設置數據
        context.setAttribute("message","hello");

    }
}
package com.kk.servletcontext;

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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : 域對象:共享數據
 */
@WebServlet("/servletContextDemo04")
public class Demo04 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //ServletContext功能
        ServletContext context = this.getServletContext();

        //獲取數據
        Object message = context.getAttribute("message");

        System.out.println(message);

    }
}

​ 3.獲取文件的真實(服務器)路徑

​ 方法:String getRealPath(“”)

代码演示

package com.kk.servletcontext;

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

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : 獲取文件的真實(服務器)路徑
 */
@WebServlet("/servletContextDemo05")
public class Demo05 extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //ServletContext功能
        ServletContext context = this.getServletContext();

        //獲取文件的真實(服務器)路徑
        String realPath = context.getRealPath("/pro.properties");
        System.out.println(realPath);
        File file = new File(realPath);

        String pro = context.getRealPath("/WEB-INF/classes/pro.properties"); //src目錄下的資源(resources)下的路徑
        System.out.println(pro);


    }   
}

4.文件下载

文件下载需求

​ 1.页面显示超链接

​ 2.点击超链接后弹出下载提示框

​ 3.完成图片文件下载

分析

​ 1.超链接指向的资源如果能被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。不满足需求

​ 2.任何资源都必须弹出下载提示框

​ 3.使用响应头设置资源的打开方式:

​ content-disposition:attachment;filename=xxx

步骤

​ 1.定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename

​ 2.定义Servlet

​ 1.获取文件得名称

​ 2.使用字节输入流加载文件进内存

​ 3.指定response的响应头:content-disposition:attachment;filename=xxx

​ 4.将数据写出到response输出流

代碼演示

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

    <a href="/downLoadServlet?filename=011.jpeg">图片</a>

</body>
</html>
package com.kk.download;

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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc :
 */
@WebServlet("/downLoadServlet")
public class downLoadServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //获取请求参数,即文件名称
        String filename = req.getParameter("filename");

        //使用字节输出流加载文件进内存
        //找到文件服务器路径
        ServletContext context = this.getServletContext();
        String realPath = context.getRealPath("/img/" + filename);

        //用字节流关联
        FileInputStream fis = new FileInputStream(realPath);

        //设置response的响应头
        //设置响应头类型 content-type
        String mimeType = context.getMimeType(filename); //获取文件的mime类型
        resp.setHeader("content-type", mimeType);

        //设置响应头打开方式 content-disposition
        resp.setHeader("content-disposition", "attachment;filename=" + filename);

        //将输入流的数据写出响应输出流中
        ServletOutputStream sos = resp.getOutputStream();
        byte[] buff = new byte[1024 * 8];
        int len = 0;
        while ((len = fis.read(buff)) != -1) {
    
    
            sos.write(buff, 0, len);
        }

        fis.close();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6cll3TLe-1659791971306)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220803165942167.png)]

問題

​ 中文文件問題

​ 解決思路:

​ 1.獲取客戶端使用的瀏覽器版本信息

​ 2.根據不用的版本信息,設置filename的編碼方式不同

代碼演示

package com.kk.download;

import com.kk.utils.DownLoadUtils;

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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc :
 */
@WebServlet("/downLoadServlet")
public class downLoadServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //获取请求参数,即文件名称
        String filename = req.getParameter("filename");

        //使用字节输出流加载文件进内存
        //找到文件服务器路径
        ServletContext context = this.getServletContext();
        String realPath = context.getRealPath("/img/" + filename);

        //用字节流关联
        FileInputStream fis = new FileInputStream(realPath);

        //设置response的响应头
        //设置响应头类型 content-type
        String mimeType = context.getMimeType(filename); //获取文件的mime类型
        resp.setHeader("content-type", mimeType);


        //解決中文文件名問題
        //獲取user-agent請求頭
        String agent = req.getHeader("user-agent");
        //使用工具類方法編碼文件名即可
        filename = DownLoadUtils.getFileName(agent, filename);
        
        //设置响应头打开方式 content-disposition
        resp.setHeader("content-disposition","attachment;filename="+filename);

        //将输入流的数据写出响应输出流中
        ServletOutputStream sos = resp.getOutputStream();
        byte[] buff = new byte[1024 * 8];
        int len = 0;
        while ((len = fis.read(buff)) != -1) {
    
    
            sos.write(buff, 0, len);
        }

        fis.close();
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <a href="/downLoadServlet?filename=011.jpeg">图片</a>

    <hr>

    <a href="/downLoadServlet?filename=风景.jpeg">图片</a>


</body>
</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PvpjB1J7-1659791971306)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220803172405862.png)]

会话技术

1.会话技术

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

2.Cookie

1.概念

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

2.快速入门

  • 使用步骤:
    1. 创建Cookie对象,绑定数据
      • new Cookie(String name, String value)
    2. 发送Cookie对象
      • response.addCookie(Cookie cookie)
    3. 获取Cookie,拿到数据
      • Cookie[] request.getCookies()

代碼演示

package com.kk.cookie;

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

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : Cookie快速入門
 */

@WebServlet("/cookieDemo01")
public class CookieDemo01 extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //創建Cookie對象
        Cookie cookie = new Cookie("msg", "hello");

        //發送Cookie
        resp.addCookie(cookie);

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }
}
package com.kk.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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : Cookie快速入門
 */

@WebServlet("/cookieDemo02")
public class CookieDemo02 extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //獲取Cookie
        Cookie[] cs = req.getCookies();

        //獲取數據,遍歷Cookies
        if (cs != null) {
    
    
            for (Cookie c : cs) {
    
    
                String name = c.getName();
                String value = c.getValue();
                System.out.println(name + ":" + value);
            }
        }

    }

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

3.实现原理

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jX2Ioa4H-1659791971307)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220803224143552.png)]

4.cookie的细节

  1. 一次可不可以发送多个cookie?

    • 可以
    • 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
    package com.kk.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;
    
    /**
     * @author : k
     * @Date : 2022/8/3
     * @Desc : 一次可不可以发送多个cookie?
     */
    
    @WebServlet("/cookieDemo03")
    public class CookieDemo03 extends HttpServlet {
          
          
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
          
            //創建Cookie對象
            Cookie c1 = new Cookie("msg", "hello");
            Cookie c2 = new Cookie("name", "zhangsan");
    
            //發送Cookie
            resp.addCookie(c1);
            resp.addCookie(c2);
    
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
          
            this.doPost(req, resp);
        }
    }
    
  2. cookie在浏览器中保存多长时间?

  3. 默认情况下,当浏览器关闭后,Cookie数据被销毁

  4. 持久化存储:

* setMaxAge(int seconds)
	1. 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
	2. 负数:默认值
	3. 零:删除cookie信息
package com.kk.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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : cookie在浏览器中保存多长时间?
 */

@WebServlet("/cookieDemo04")
public class CookieDemo04 extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //創建Cookie對象
        Cookie c1 = new Cookie("msg", "setMaxAge");


        //設置將cookie的存活時間
        c1.setMaxAge(30); //將cookie持久化到硬盤,30秒后會自動刪除cookies
        //c1.setMaxAge(-1); //默认值
        //c1.setMaxAge(0); //删除cookie信息
        //發送Cookie
        resp.addCookie(c1);

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }
}
  1. cookie能不能存中文?
  • 在tomcat 8 之前 cookie中不能直接存储中文数据。
    • 需要将中文数据转码—一般采用URL编码(%E3)
  • 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
  1. cookie共享问题?

    1. 假设在同一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
    • 默认情况下cookie不能共享

    • setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录

      • 如果要共享,则可以将path设置为"/"
    1. 不同的tomcat服务器间cookie共享问题?
    • setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
      • setDomain(“.baidu.com”),那么tieba.baidu.comnews.baidu.com中cookie可以共享
    package com.kk.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;
    
    /**
     * @author : k
     * @Date : 2022/8/3
     * @Desc : cookie能不能存中文?
     */
    
    @WebServlet("/cookieDemo05")
    public class CookieDemo05 extends HttpServlet {
          
          
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
          
            //創建Cookie對象
            Cookie c1 = new Cookie("msg", "你好");
    
            c1.setPath("/");
    
    
            //發送Cookie
            resp.addCookie(c1);
    
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
          
            this.doPost(req, resp);
        }
    }
    

5.Cookie的特点和作用

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

6.案例:记住上一次访问时间

  1. 需求:

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

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

代碼演示

package com.kk.cookie;

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

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc :
 * 需求:
 * <p>
 * 1. 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
 * 2. 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
 */
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //设置响应的消息体的数据格式以及编码
        resp.setContentType("text/html;charset=utf-8");

        //獲取所有的cookie
        Cookie[] cookies = req.getCookies();

        boolean flag = false; //沒有cookie為lastTime

        //遍歷cookies數組
        if (cookies != null && cookies.length > 0) {
    
    
            for (Cookie cookie : cookies) {
    
    
                //獲取cookies的名稱
                String name = cookie.getName();

                //判斷名稱是否是lastTime
                if ("lastTime".equals(name)) {
    
    
                    //有該cookie不是第一次訪問
                    flag = true; //有lastTime的cookie

                    //设置cookie的 value
                    //获取当前时间的字符串,重新设置cookie的值,并且重新发送cookie
                    Date date = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String str_date = sdf.format(date);


                    System.out.println("編碼前的数据" + str_date);
                    //URL编码
                    str_date = URLEncoder.encode(str_date, "utf-8");
                    System.out.println("編碼后的数据" + str_date);


                    cookie.setValue(str_date);

                    //設置cookie的存活時間
                    cookie.setMaxAge(60 * 60 * 24 * 30); //一個月
                    resp.addCookie(cookie);

                    //响应数据
                    //获取cookie的value 时间
                    String value = cookie.getValue();


                    System.out.println("解码前:" + value);
                    //URL解码
                    value = URLDecoder.decode(value, "utf-8");
                    System.out.println("解码后:" + value);

                    resp.getWriter().write("<h1>欢迎回来,您上次访问时间为:" + value + "</h1>");
                    break;

                }
            }
        }


        if (cookies == null || cookies.length == 0 || flag == false) {
    
    
            //沒有 第一次訪問
            //设置cookie的 value
            //获取当前时间的字符串,重新设置cookie的值,并且重新发送cookie
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String str_date = sdf.format(date);


            System.out.println("編碼前的数据" + str_date);
            //URL编码
            str_date = URLEncoder.encode(str_date, "utf-8");
            System.out.println("編碼后的数据" + str_date);


            Cookie cookie = new Cookie("lastTime", str_date);
            cookie.setValue(str_date);

            //設置cookie的存活時間
            cookie.setMaxAge(60 * 60 * 24 * 30); //一個月
            resp.addCookie(cookie);



            resp.getWriter().write("<h1>您好,欢迎您首次访问</h1>");
        }


    }

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

3.Session

1.概念

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

2.快速入门

  1. 获取HttpSession对象:
    HttpSession session = request.getSession();
  2. 使用HttpSession对象:
    Object getAttribute(String name)
    void setAttribute(String name, Object value)
    void removeAttribute(String name)

代码演示

package com.kk.session;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc :
 */
@WebServlet("/sessionDemo01")
public class SessionDemo01 extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //使用session共享数据

        //获取session
        HttpSession session = req.getSession();
        session.setAttribute("msg","hello session");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }
}
package com.kk.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;

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc :
 */
@WebServlet("/sessionDemo02")
public class SessionDemo02 extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //使用session共享数据

        //获取session
        HttpSession session = req.getSession();
        Object msg = session.getAttribute("msg");
        System.out.println(msg);
    }

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

3.原理

  • Session的实现是依赖于Cookie的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4x6X5WZI-1659791971307)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220804000127524.png)]

4.细节

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

    • 默认情况下。不是。
    • 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
      Cookie c = new Cookie(“JSESSIONID”,session.getId());
      c.setMaxAge(60*60);
      response.addCookie©;
    package com.kk.session;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    
    /**
     * @author : k
     * @Date : 2022/8/3
     * @Desc : 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
     */
    @WebServlet("/sessionDemo03")
    public class SessionDemo03 extends HttpServlet {
          
          
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
          
    
            //获取session
            HttpSession session = req.getSession();
            //期望客户端关闭后,session也能相同
            Cookie cookie = new Cookie("JSESSIONID",session.getId());
            cookie.setMaxAge(60*60);
            resp.addCookie(cookie);
    
            System.out.println(session);
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
          
            this.doPost(req, resp);
        }
    }
    
  2. 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?

  • 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
    • session的钝化:
      * 在服务器正常关闭之前,将session对象系列化到硬盘上
    • session的活化:
      * 在服务器启动后,将session文件转化为内存中的session对象即可。
package com.kk.session;

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

/**
 * @author : k
 * @Date : 2022/8/3
 * @Desc : 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
 */
@WebServlet("/sessionDemo04")
public class SessionDemo04 extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        //获取session
        HttpSession session = req.getSession();

        System.out.println(session);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        this.doPost(req, resp);
    }
}
  1. session什么时候被销毁?
  2. 服务器关闭
  3. session对象调用invalidate() 。
  4. session默认失效时间 30分钟
选择性配置修改	
<session-config>
      <session-timeout>30</session-timeout>
  </session-config>

5.session的特点

  1. session用于存储一次会话的多次请求的数据,存在服务器端
  2. session可以存储任意类型,任意大小的数据
  • session与Cookie的区别:
    1. session存储数据在服务器端,Cookie在客户端
    2. session没有数据大小限制,Cookie有
    3. session数据安全,Cookie相对于不安全

6.案例:验证码

  1. 案例需求:

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ik6PAhLF-1659791971307)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220804153917041.png)]

代码演示

生成二维码

package com.kk.servlet;

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

@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    


        int width = 100;
        int height = 50;

        //1.创建一对象,在内存中图片(验证码图片对象)
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);


        //2.美化图片
        //2.1 填充背景色
        Graphics g = image.getGraphics();//画笔对象
        g.setColor(Color.PINK);//设置画笔颜色
        g.fillRect(0,0,width,height);

        //2.2画边框
        g.setColor(Color.BLUE);
        g.drawRect(0,0,width - 1,height - 1);

        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
        //生成随机角标
        Random ran = new Random();

        StringBuffer sb = new StringBuffer();

        for (int i = 1; i <= 4; i++) {
    
    
            int index = ran.nextInt(str.length());
            //获取字符
            char ch = str.charAt(index);//随机字符

            sb.append(ch);

            //2.3写验证码
            g.drawString(ch+"",width/5*i,height/2);
        }


        String checkCode_session = sb.toString();

        //将验证码存入session
        request.getSession().setAttribute("checkCode_session",checkCode_session);


        //2.4画干扰线
        g.setColor(Color.GREEN);

        //随机生成坐标点

        for (int i = 0; i < 10; i++) {
    
    
            int x1 = ran.nextInt(width);
            int x2 = ran.nextInt(width);

            int y1 = ran.nextInt(height);
            int y2 = ran.nextInt(height);
            g.drawLine(x1,y1,x2,y2);
        }


        //3.将图片输出到页面展示
        ImageIO.write(image,"jpg",response.getOutputStream());


    }

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

登录LoginServlet

package com.kk.servlet;

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

/**
 * @author : k
 * @Date : 2022/8/4
 * @Desc :
 */
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        //设置req编码
        req.setCharacterEncoding("utf-8");

        //获取参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String checkCode = req.getParameter("checkCode");

        //先获取生成的验证码
        HttpSession session = req.getSession();
        String checkCode_session = (String) session.getAttribute("checkCode_session");

        //删除session中存储的验证码
        session.removeAttribute("checkCode_session");

        //先判断验证码是否正确
        if (checkCode_session != null && checkCode_session.equalsIgnoreCase(checkCode)) {
    
    
            //验证码忽略大小写比较字符串
            //判断用户名和密码是否一致
            if ("admin".equals(username) && "123".equals(password)) {
    
    //需要调用UserDao查询数据库,这里省略
                //登录成功
                //存储用户信息
                session.setAttribute("username", username);
                //重定向到success.jsp
                resp.sendRedirect(req.getContextPath() + "/success.jsp");
            } else {
    
    
                //登录失败
                //存储提示信息到req
                req.setAttribute("login_error", "用户名或密码错误");
                //转发到登录页面
                req.getRequestDispatcher("/login.jsp").forward(req, resp);
            }
        } else {
    
    
            //验证码不一致
            //存储提示信息到req
            req.setAttribute("cc_error", "验证码错误");
            //转发到登录页面
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }

    }

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

jsp页面

<%--
  Created by IntelliJ IDEA.
  User: 30666
  Date: 2022/8/4
  Time: 15:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>login</title>

    <script>
        window.onload = function () {
            document.getElementById("img").onclick = function () {
                this.src = "${pageContext.request.contextPath}/checkCodeServlet?time=" + new Date().getTime();
            }
        }
    </script>


    <style>
        div {
            color: red;
        }
    </style>

</head>
<body>

<form action="${pageContext.request.contextPath}/loginServlet" method="post">
    <table>
        <tr>
            <td>用户名</td>
            <td>
                <input type="text" name="username">
            </td>
        </tr>

        <tr>
            <td>密码</td>
            <td>
                <input type="password" name="password">
            </td>
        </tr>


        <tr>
            <td>验证码</td>
            <td>
                <input type="text" name="checkCode">
            </td>
        </tr>


        <tr>
            <td colspan="2">
                <img id="img" src="${pageContext.request.contextPath}/checkCodeServlet">
            </td>
        </tr>

        <tr>
            <td colspan="2">
                <input type="submit" value="登录">
            </td>
        </tr>
    </table>
</form>


<div><%=request.getAttribute("cc_error") == null ? "" : request.getAttribute("cc_error")%>
</div>
<div><%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error") == null%>
</div>

</body>
</html>
<%--
  Created by IntelliJ IDEA.
  User: 30666
  Date: 2022/8/4
  Time: 16:01
  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>

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

</body>
</html>

JSP入门学习

1.概念

Java Server Pages: java服务器端页面

​ 可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码

​ 用于简化书写!!!

代码演示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <%
    System.out.println("hello jsp");
  %>

  <h1>hi jsp</h1>
  </body>
</html>

2.原理

JSP本质上就是一个Servlet

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R9YKmZIX-1659791971308)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220803233449874.png)]

3.JSP的脚本

JSP定义Java代码的方式

  1. <% 代码 %>:定义的java代码,在service方法中。service方法中可以定义什么,该脚本中就可以定义什么。
  2. <%! 代码 %>:定义的java代码,在jsp转换后的java类的成员位置。
  3. <%= 代码 %>:定义的java代码,会输出到页面上。输出语句中可以定义什么,该脚本中就可以定义什么。

代码演示

<%--
  Created by IntelliJ IDEA.
  User: 30666
  Date: 2022/8/3
  Time: 17:36
  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>
    <%
        System.out.println("hello jsp");
    %>

    <%!
        int i = 3;
    %>

    <%=i%>

    <h1>hi jsp</h1>
</body>
</html>

4.JSP的内置对象

  • 在jsp页面中不需要获取和创建,可以直接使用的对象
  • jsp一共有9个内置对象。
  • 今天学习3个:
    • request
    • response
    • out:字符输出流对象。可以将数据输出到页面上。和response.getWriter()类似
      • response.getWriter()和out.print()的区别:
        • 在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据。
        • response.getWriter()数据输出永远在out.print()之前

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HVGDfcWA-1659791971308)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220803234523243.png)]

5.案例:改造Cookie案例

<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="java.net.URLDecoder" %><%--
  Created by IntelliJ IDEA.
  User: 30666
  Date: 2022/8/3
  Time: 23:46
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>showTime</title>
</head>
<body>

<%

    //獲取所有的cookie
    Cookie[] cookies = request.getCookies();

    boolean flag = false; //沒有cookie為lastTime

    //遍歷cookies數組
    if (cookies != null && cookies.length > 0) {
        for (Cookie cookie : cookies) {
            //獲取cookies的名稱
            String name = cookie.getName();

            //判斷名稱是否是lastTime
            if ("lastTime".equals(name)) {
                //有該cookie不是第一次訪問
                flag = true; //有lastTime的cookie

                //设置cookie的 value
                //获取当前时间的字符串,重新设置cookie的值,并且重新发送cookie
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                String str_date = sdf.format(date);


                System.out.println("編碼前的数据" + str_date);
                //URL编码
                str_date = URLEncoder.encode(str_date, "utf-8");
                System.out.println("編碼后的数据" + str_date);


                cookie.setValue(str_date);

                //設置cookie的存活時間
                cookie.setMaxAge(60 * 60 * 24 * 30); //一個月
                response.addCookie(cookie);

                //响应数据
                //获取cookie的value 时间
                String value = cookie.getValue();


                System.out.println("解码前:" + value);
                //URL解码
                value = URLDecoder.decode(value, "utf-8");
                System.out.println("解码后:" + value);

                response.getWriter().write("<h1>欢迎回来,您上次访问时间为:" + value + "</h1>");
                break;

            }
        }
    }


    if (cookies == null || cookies.length == 0 || flag == false) {
        //沒有 第一次訪問
        //设置cookie的 value
        //获取当前时间的字符串,重新设置cookie的值,并且重新发送cookie
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        String str_date = sdf.format(date);


        System.out.println("編碼前的数据" + str_date);
        //URL编码
        str_date = URLEncoder.encode(str_date, "utf-8");
        System.out.println("編碼后的数据" + str_date);


        Cookie cookie = new Cookie("lastTime", str_date);
        cookie.setValue(str_date);

        //設置cookie的存活時間
        cookie.setMaxAge(60 * 60 * 24 * 30); //一個月
        response.addCookie(cookie);


        response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");

    }

%>

</body>
</html>

JSP进阶

1.指令

  • 作用:用于配置JSP页面,导入资源文件

  • 格式:
    <%@ 指令名称 属性名1=属性值1 属性名2=属性值2 … %>

  • 分类:

    1. page:配置JSP页面的

      • contentType:等同于response.setContentType()
        1. 设置响应体的mime类型以及字符集
        2. 设置当前jsp页面的编码(只能是高级的IDE才能生效,如果使用低级工具,则需要设置pageEncoding属性设置当前页面的字符集)
      • import:导包
      • errorPage:当前页面发生异常后,会自动跳转到指定的错误页面
      • isErrorPage:标识当前也是是否是错误页面。
        • true:是,可以使用内置对象exception
        • false:否。默认值。不可以使用内置对象exception

      代碼演示

      <%@ page import="java.util.ArrayList" %>
      <%@ page import="java.util.List" %>
      <%@ page contentType="text/html;charset=UTF-8" errorPage="500.jsp" language="java" %>
      <html>
      <head>
          <title>$Title$</title>
      </head>
      <body>
        <%
          List<String> strings = new ArrayList<>();
          int i = 3/0;
        %>
      </body>
      </html>
      
      <%@ page contentType="text/html;charset=UTF-8" isErrorPage="true" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
          <h1>服務器繁忙...</h1>
      
          <%
              String message = exception.getMessage();
              response.getWriter().write(message);
          %>
      </body>
      </html>
      
    2. include:页面包含的。导入页面的资源文件

    * <%@include file="top.jsp"%>
    
    > 代码演示
    
    ``top.jsp``
    
    ```java
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <h1>頁面logo 頁面標題</h1>
    ```
    
    ``home.jsp``
    
    ```jsp
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@include file="top.jsp"%>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    
    
        <h3>主题信息</h3>
    
    </body>
    </html>
    ```
    
    1. taglib:导入资源
      * <%@ taglib prefix=“c” uri=“http://java.sun.com/jsp/jstl/core” %>
      • prefix:前缀,自定义的

2.注释

  1. html注释:
    <! – – >:只能注释html代码片段
  2. jsp注释:推荐使用
    <%-- --%>:可以注释所有

3.内置对象

  • 在jsp页面中不需要创建,直接使用的对象
  • 一共有9个:
    变量名 真实类型 作用
    • pageContext PageContext 当前页面共享数据,还可以获取其他八个内置对象
    • request HttpServletRequest 一次请求访问的多个资源(转发)
    • session HttpSession 一次会话的多个请求间
    • application ServletContext 所有用户间共享数据
    • response HttpServletResponse 响应对象
    • page Object 当前页面(Servlet)的对象 this
    • out JspWriter 输出对象,数据输出到页面上
    • config ServletConfig Servlet的配置对象
    • exception Throwable 异常对象

MVC:开发模式

1.jsp演变历史

  1. 早期只有servlet,只能使用response输出标签数据,非常麻烦
  2. 后来又jsp,简化了Servlet的开发,如果过度使用jsp,在jsp中即写大量的java代码,有写html表,造成难于维护,难于分工协作
  3. 再后来,java的web开发,借鉴mvc开发模式,使得程序的设计更加合理性

2.MVC:

  1. M:Model,模型。JavaBean

    • 完成具体的业务操作,如:查询数据库,封装对象
  2. V:View,视图。JSP

    • 展示数据
  3. C:Controller,控制器。Servlet

  • 获取用户的输入

  • 调用模型

  • 将数据交给视图进行展示

  • 优缺点:

    1. 优点:

      1. 耦合性低,方便维护,可以利于分工协作
      2. 重用性高
    2. 缺点:

      1. 使得项目架构变得复杂,对开发人员要求高

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2C7jttqn-1659791971309)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220804171117463.png)]

EL表达式

1.概念

​ Expression Language 表达式语言

2.作用

​ 替换和简化jsp页面中java代码的编写

3.语法

​ ${表达式}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    ${3>4}

</body>
</html>

4.注意

  • jsp默认支持el表达式的。如果要忽略el表达式
    1. 设置jsp中page指令中:isELIgnored=“true” 忽略当前jsp页面中所有的el表达式

      <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="true" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      
          ${3>4}
      
      </body>
      </html>
      
    2. ${表达式} :忽略当前这个el表达式

      <%@ page contentType="text/html;charset=UTF-8" language="java"%>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      
          ${3>4}
      
          \${3>4}
      
      </body>
      </html>
      

5.使用

1.运算

  • 运算符:
    1. 算数运算符: + - * /(div) %(mod)
    2. 比较运算符: > < >= <= == !=
    3. 逻辑运算符: &&(and) ||(or) !(not)
    4. 空运算符: empty
      * 功能:用于判断字符串、集合、数组对象是否为null或者长度是否为0
      * ${empty list}:判断字符串、集合、数组对象是否为null或者长度为0
      * ${not empty str}:表示判断字符串、集合、数组对象是否不为null 并且 长度>0
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

${3>2}

\${3>2}

<hr>


<h3>算术运算符</h3>
${3+3} <br>
${3/3} <br>
${3 div 3} <br>
${3 % 3} <br>
${3 mod 3} <br>

<hr>
<h3>比较运算符</h3>
${3==3}<br>

<hr>
<h3>逻辑运算符</h3>
${3==3 && 3>2}<br>
${3==3 and 3>2}<br>

<hr>
<h3>empty运算符</h3>
<%
    String str = "abc";
    request.setAttribute("str",str);
%>
${empty str}<br>
${not empty str}<br>
</body>
</html>

2.获取值

  1. el表达式只能从域对象中获取值

  2. 语法:

  3. ${域名称.键名}:从指定域中获取指定键的值

* 域名称:
	1. pageScope		--> pageContext
	2. requestScope 	--> request
	3. sessionScope 	--> session
	4. applicationScope --> application(ServletContext)
* 举例:在request域中存储了name=张三
* 获取:${requestScope.name}

```jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>获取域中的数据</title>
</head>
<body>

<%
    //在域中存储数据
    request.setAttribute("name","zhangsan");

    session.setAttribute("age","22");
%>

<h3>el获取域中的数据</h3>
${requestScope.name}
${sessionScope.age}

</body>
</html>
```
  1. ${键名}:表示依次从最小的域中查找是否有该键对应的值,直到找到为止。

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>获取域中的数据</title>
    </head>
    <body>
    
    
    <%
        //在域中存储数据
        request.setAttribute("name","zhangsan");
    
        session.setAttribute("age","22");
    
        session.setAttribute("name","lisi");
    %>
    
    <h3>el获取域中的数据</h3>
    
    ${requestScope.name}
    ${sessionScope.age}
    
    <hr>
    ${name}
    ${sessionScope.name}
    
    </body>
    </html>
    
  2. 获取对象、List集合、Map集合的值

    1. 对象:${域名称.键名.属性名}
* 本质上会去调用对象的getter方法
	
	``User``
	
	```java
	package com.kk.domain;
	
	import java.text.SimpleDateFormat;
	import java.util.Date;
	
	/**
	 * @author : k
	 * @Date : 2022/8/4
	 * @Desc : JavaBean
	 */
	public class User {
	    private String name;
	    private Integer age;
	    private Date birthday;


​ public String getBirStr() {
​ if (birthday != null) {
​ //格式化日期对象
​ SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
​ //返回
​ return sdf.format(birthday);
​ } else {
​ return “”;
​ }

​ }


​ public String getName() {
​ return name;
​ }

​ public void setName(String name) {
​ this.name = name;
​ }

​ public Integer getAge() {
​ return age;
​ }

public void setAge(Integer age) {
this.age = age;
}

	    public Date getBirthday() {
	        return birthday;
	    }
	
	    public void setBirthday(Date birthday) {
	        this.birthday = birthday;
	    }
	}
	```
	
	``jsp``
	
	```jsp
	<%@ page import="com.kk.domain.User" %>
	<%@ page import="java.util.Date" %>
	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<html>
	<head>
	    <title>el获取對象中的数据</title>
	</head>
	<body>


​ <%
​ User user = new User();
​ user.setName(“张三”);
​ user.setAge(22);
​ user.setBirthday(new Date());

​ request.setAttribute(“user”,user);
​ %>


el获取对象中的值


​ ${requestScope.user}



​ <%–通过对象的属性来获取数据
​ setter或getter方法,去掉set或get,再将剩余部门,首字母变为小写
​ setName —> Name —> name
​ --%>
​ ${requestScope.user.name}

​ ${requestScope.user.age}

​ ${requestScope.user.birthday}

​ ${requestScope.user.birthday.month+1}


​ ${requestScope.user.birStr}




```

2. List集合:${域名称.键名[索引]}

   ```jsp
   <%@ page import="com.kk.domain.User" %>
   <%@ page import="java.util.Date" %>
   <%@ page import="java.util.ArrayList" %>
   <%@ page import="java.util.List" %>
   <%@ page contentType="text/html;charset=UTF-8" language="java" %>
   <html>
   <head>
       <title>el获取List集合中的数据</title>
   </head>
   <body>


​ <%

​ User user = new User();
​ user.setName(“张三”);
​ user.setAge(22);
​ user.setBirthday(new Date());

​ List list = new ArrayList<>();
​ list.add(“aaa”);
​ list.add(“bbb”);
​ list.add(user);

request.setAttribute(“list”,list);
%>

   <h3>el获取List集合中的数据</h3>
   ${requestScope.list} <br>
   ${requestScope.list[0]} <br>
   ${requestScope.list[1]} <br>
   ${requestScope.list[10]} <br>


​ ${requestScope.list[2].name}

​ ${requestScope.list[2].age}

​ ${requestScope.list[2].birthday}




​ ```

​ 3. Map集合:
​ * ${域名称.键名.key名称}
​ * ${域名称.键名[“key名称”]}

<%@ page import="com.kk.domain.User" %>
<%@ page import="java.util.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>el获取Map集合中的数据</title>
</head>
<body>


<%
    User user = new User();
    user.setName("张三");
    user.setAge(22);
    user.setBirthday(new Date());


    Map<Object, Object> map = new HashMap<>();
    map.put("username","李四");
    map.put("password","123456");
    map.put("user",user);
    request.setAttribute("map",map);
%>


<h3>el获取Map集合中的数据</h3>
${requestScope.map} <br>
${requestScope.map.username} <br>
${requestScope.map["username"]} <br>
${requestScope.map.password} <br>
${requestScope.map["password"]} <br>

${requestScope.map.user.name} <br>
${requestScope.map.user.age} <br>
${requestScope.map.user.birthday} <br>


</body>
</html>

3.隐式对象

  • el表达式中有11个隐式对象
  • pageContext:
    • 获取jsp其他八个内置对象
      * ${pageContext.request.contextPath}:动态获取虚拟目录
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>el的隐式对象</title>
</head>
<body>

${pageContext.request} <br>
<h4>在jsp中动态获取虚拟目录</h4>
${pageContext.request.contextPath} <br>


</body>
</html>

JSTL

1.概念

JavaServer Pages Tag Library JSP标准标签库

  • 是由Apache组织提供的开源的免费的jsp标签 <标签>

2.作用

用于简化和替换jsp页面上的java代码

3.使用步骤

  1. 导入jstl相关jar包

    <dependencies>
        <dependency>
             <groupId>org.glassfish.web</groupId>
             <artifactId>jstl-impl</artifactId>
             <version>1.2</version>
         </dependency>
    </dependencies>
    
  2. 引入标签库:taglib指令:<%@ taglib %>

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
  3. 使用标签

4.常用的JSTL标签

  1. if:相当于java代码的if语句

    1. 属性:

      • test 必须属性,接受boolean表达式
        • 如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
        • 一般情况下,test属性值会结合el表达式一起使用
    2. 注意:

      • c:if标签没有else情况,想要else情况,则可以在定义一个c:if标签
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page import="java.util.List" %>
    <%@ page import="java.util.ArrayList" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <html>
    <head>
        <title>if标签</title>
    </head>
    <body>
    
    <%--
        c:if标签
             1.属性
                 test必须属性,接收boolean表达式
                   如果表达式为true则显示if标签体内容,如果为false则不显示标签体内容
    
    
    --%>
    
        <c:if test="true">
            <h1>你好</h1>
        </c:if>
        <hr>
    
    
        <%
            //判斷request域中的一个list集合是否为空,如果不为空则显示遍历集合
            List<Object> list = new ArrayList<>();
            list.add("aaa");
            request.setAttribute("list",list);
    
            request.setAttribute("number",3);
        %>
    
        <c:if test="${not empty list}">
            遍历集合...
        </c:if>
        <br>
        <c:if test="${number % 2 != 0}">
            ${number}为奇数
        </c:if>
    
    </body>
    </html>
    
    
  2. choose:相当于java代码的switch语句

    1. 使用choose标签声明 相当于switch声明
    2. 使用when标签做判断 相当于case
    3. 使用otherwise标签做其他情况的声明 相当于default
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <html>
    <head>
        <title>choose标签</title>
    </head>
    <body>
    
    <%--
        完成数字编号对应星期几案例
            1.域中存储数字
            2.使用choose标签取出数字 相当于 switch声明
            3.使用when标签作数字判断 相当于 case
            4.otherwise标签作其他情况的声明 相当于 default
    
    --%>
    <%
        request.setAttribute("number", 3);
    %>
    
    <c:choose>
        <c:when test="${number==1}">星期一</c:when>
        <c:when test="${number==2}">星期二</c:when>
        <c:when test="${number==3}">星期三</c:when>
        <c:when test="${number==4}">星期四</c:when>
        <c:when test="${number==5}">星期五</c:when>
        <c:when test="${number==6}">星期六</c:when>
        <c:when test="${number==7}">星期七</c:when>
    
        <c:otherwise>数字输入有误</c:otherwise>
    
    </c:choose>
    
    
    </body>
    </html>
    
  3. foreach:相当于java代码的for语句

<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>foreach标签</title>
</head>
<body>
<%--
    foreach:相当于java代码的for语句
        1.完成重复的操作
            for(int i = 0; i<10; i++){

            }

            属性:
                begin:开始值
                end:结束值
                var:临时变量
                step:步长
                varStatus:循环状态对象
                    index:容器中元素的索引,从0开始
                    count:循环次数,从1开始


        2.遍历容器
        List<User> list;
        for(User user : list){

        }

        属性:
            items:容器对象  list
            var:容器中元素的临时变量  user

--%>


<c:forEach begin="1" end="10"  var="i" step="1">
    ${i} <br>
</c:forEach>

<hr>

<%
    List<Object> list  = new ArrayList<>();
    list.add("aaa");
    list.add("bbb");
    list.add("ccc");

    request.setAttribute("list",list);

%>


<c:forEach items="${list}"  var="str" varStatus="s">
    ${s.index} ${s.count} ${str} <br>
</c:forEach>



</body>
</html>

5.练习

  • 需求:在request域中有一个存有User对象的List集合。需要使用jstl+el将list集合数据展示到jsp页面的表格table中

User实体类

package com.kk.domain;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author : k
 * @Date : 2022/8/4
 * @Desc : JavaBean
 */
public class User {
    
    
    private String name;
    private Integer age;
    private Date birthday;


    public String getBirStr() {
    
    
        if (birthday != null) {
    
    
            //格式化日期对象
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //返回
            return sdf.format(birthday);
        } else {
    
    
            return "";
        }

    }


    public User() {
    
    
    }

    public User(String name, Integer age, Date birthday) {
    
    
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public Date getBirthday() {
    
    
        return birthday;
    }

    public void setBirthday(Date birthday) {
    
    
        this.birthday = birthday;
    }
}

jsp页面

<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page import="com.kk.domain.User" %>
<%@ page import="java.util.Date" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>test</title>
</head>
<body>



<%
    List<User> list  = new ArrayList<>();
    list.add(new User("张三",22,new Date()));
    list.add(new User("李四",21,new Date()));
    list.add(new User("王五",23,new Date()));
    request.setAttribute("list",list);
%>


<table border="1" width="500" align="center">

    <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>生日</th>
    </tr>

    <c:forEach items="${list}" var="user"  varStatus="s">

        <c:if test="${s.count % 2 != 0}">
            <tr bgcolor="#afb1b3">
                <td>${s.count}</td>
                <td>${user.name}</td>
                <td>${user.age}</td>
                <td>${user.birStr}</td>
            </tr>
        </c:if>


        <c:if test="${s.count % 2 == 0}">
            <tr>
                <td>${s.count}</td>
                <td>${user.name}</td>
                <td>${user.age}</td>
                <td>${user.birStr}</td>
            </tr>
        </c:if>


    </c:forEach>


</table>

</body>
</html>

三层架构:软件设计架构

  1. 界面层(表示层):用户看的得界面。用户可以通过界面上的组件和服务器进行交互
  2. 业务逻辑层:处理业务逻辑的。
  3. 数据访问层:操作数据存储文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L5A6Y4gC-1659791971309)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220804205556359.png)]

在这里插入图片描述

案例:用户信息列表展示

1.需求

​ 用户信息的增删改查操作

2.设计

  1. 技术选型:Servlet+JSP+MySQL+JDBCTempleat+Duird+BeanUtilS+tomcat

  2. 数据库设计:

    /*
     Navicat Premium Data Transfer
    
     Source Server         : localhost
     Source Server Type    : MySQL
     Source Server Version : 80027
     Source Host           : localhost:3306
     Source Schema         : db2
    
     Target Server Type    : MySQL
     Target Server Version : 80027
     File Encoding         : 65001
    
     Date: 04/08/2022 21:05:18
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user`  (
      `id` int NOT NULL AUTO_INCREMENT,
      `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `gender` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `age` int NULL DEFAULT NULL,
      `address` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `qq` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES (1, '张三', '男', 22, '广东省', '30666', '[email protected]');
    INSERT INTO `user` VALUES (2, '李四', '男', 25, '广东省', '3066688', '[email protected]');
    INSERT INTO `user` VALUES (3, '王晓', '女', 21, '广东省', '30666', '[email protected]');
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    

3.开发

1.环境搭建

  1. 创建数据库环境
  2. 创建项目,导入需要的jar包
<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.27</version>
    </dependency>
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.4</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.11</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.20</version>
    </dependency>

    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.20</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
        <version>1.9.4</version>
    </dependency>


    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>jstl-impl</artifactId>
        <version>1.2</version>
    </dependency>




</dependencies>

2.编码

1.列表查詢分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hh0FI2DW-1659791971310)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220804211250361.png)]

2.添加功能分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1RJxDSWJ-1659791971310)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220805163830976.png)]

3.刪除功能分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hOXMHTc2-1659791971310)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220805165553187.png)]

4.修改功能分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e3wQ7xCV-1659791971310)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220805171135504.png)]

5.刪除选中功能分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tHnKbW6K-1659791971311)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220805174405373.png)]

6.分页查询功能分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-px4y5hj9-1659791971311)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220805183521112.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0fVpKXtb-1659791971311)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220805184442717.png)]

7.复杂条件查询分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nkF1ice0-1659791971311)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220805221239042.png)]

代码地址

4.测试

5.部署运维

Filter:过滤器

1.概念

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

2.快速入门

  1. 步骤:
    1. 定义一个类,实现接口Filter
    2. 复写方法
    3. 配置拦截路径
      1. web.xml
      2. 注解
  2. 代码:
package com.kk.web.filter;

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

/**
 * @author : k
 * @Date : 2022/8/6
 * @Desc :快速入门
 */
@WebFilter("/*") //访问所有资源之前都会执行该过滤器
public class Demo01 implements Filter {
    
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    
    
        System.out.println("Demo01被執行了...");

        //放行
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    
    
        Filter.super.destroy();
    }
}

3.过滤器细节

  1. web.xml配置

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
              version="4.0">
    
    
        <filter>
            <filter-name>demo01</filter-name>
            <filter-class>com.kk.web.filter.Demo02</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>demo01</filter-name>
    <!--        拦截路径-->
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    </web-app>
    
  2. 过滤器执行流程

  3. 执行过滤器

  4. 执行放行后的资源

  5. 回来执行过滤器放行代码下边的代码

  6. 过滤器生命周期方法

  7. init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源

  8. doFilter:每一次请求被拦截资源时,会执行。执行多次

  9. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源

  10. 过滤器配置详解

  • 拦截路径配置:
    1. 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
    2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
    3. 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
    4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行
  • 拦截方式配置:资源被访问的方式
    • 注解配置:
      • 设置dispatcherTypes属性
        1. REQUEST:默认值。浏览器直接请求资源
        2. FORWARD:转发访问资源
        3. INCLUDE:包含访问资源
        4. ERROR:错误跳转资源
        5. ASYNC:异步访问资源
    • web.xml配置
      • 设置标签即可
  1. 过滤器链(配置多个过滤器)
  • 执行顺序:如果有两个过滤器:过滤器1和过滤器2

    1. 过滤器1
    2. 过滤器2
    3. 资源执行
    4. 过滤器2
    5. 过滤器1
  • 过滤器先后顺序问题:

    1. 注解配置:按照类名的字符串比较规则比较,值小的先执行
      • 如: AFilter 和 BFilter,AFilter就先执行了。
    2. web.xml配置: 谁定义在上边,谁先执行

4.案例

1.案例1_登录验证

  • 需求:
    1. 访问day17_case案例的资源。验证其是否登录
    2. 如果登录了,则直接放行。
    3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。

分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ybtjpvMD-1659791971312)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220806172335392.png)]

2.案例2_敏感词汇过滤

  • 需求:

    1. 对day17_case案例录入的数据进行敏感词汇过滤
    2. 敏感词汇参考《敏感词汇.txt》
    3. 如果是敏感词汇,替换为 ***
  • 分析:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDdSLGK1-1659791971312)(C:\Users\30666\AppData\Roaming\Typora\typora-user-images\image-20220806173907061.png)]

    1. 对request对象进行增强。增强获取参数相关方法
    2. 放行。传递代理对象
      • 增强对象的功能:
    • 设计模式:一些通用的解决固定问题的方式
    1. 装饰模式
    2. 代理模式
      • 概念:
        1. 真实对象:被代理的对象
        2. 代理对象:
        3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
    • 实现方式:
    1. 静态代理:有一个类文件描述代理模式

    2. 动态代理:在内存中形成代理类

      • 实现步骤:
        1. 代理对象和真实对象实现相同的接口
      1. 代理对象 = Proxy.newProxyInstance();
        3. 使用代理对象调用方法。
        4. 增强方法
      • 增强方式:
        1. 增强参数列表
        2. 增强返回值类型
        3. 增强方法体执行逻辑

Listener:监听器

1.概念

web的三大组件之一。

  • 事件监听机制

    • 事件 :一件事情
    • 事件源 :事件发生的地方
    • 监听器 :一个对象
    • 注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码
  • ServletContextListener:监听ServletContext对象的创建和销毁

    • 方法:
      • void contextDestroyed(ServletContextEvent sce) :ServletContext对象被销毁之前会调用该方法
      • void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法
    • 步骤:
      1. 定义一个类,实现ServletContextListener接口

      2. 复写方法

      3. 配置

        1. web.xml

        ​ cn.itcast.web.listener.ContextLoaderListener

​ * 指定初始化参数

2.注解

  • @WebListener

猜你喜欢

转载自blog.csdn.net/weixin_50569789/article/details/126201380