Servlet学习笔记

一、程序开发体系结构

随着网络技术的不断发展,单机的软件程序不足以满足网络计算的需求。为此,各种各样的网络程序开发体系结构应运而生,这当中,运用最多的网络应用程序开发体系结构主要分为两种:一种是基于浏览器/服务器的B/S结构;另外一种是基于客户端/服务器的C/S结构。

1.1 C/S体系结构

(1)C/S(Client/Server,客户端/服务器)体系结构由美国Borland公司最早研发。

(2)特点:必须在客户端(用户设备上)安装特定的软件。

(3)优点:图像效果显示比较好(比如:3D游戏)。

(4)缺点:服务器的软件和功能进行升级,客户端也必须升级,否则使用不了新的功能,不利于维护。

(5)常见的C/S体系结构程序:QQ、微信等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.2 B/S体系结构

(1)B/S(Bowser/Server,浏览器/服务器)体系结构由美国微软公司研发。

(2)特点:只需要一个浏览器通过http协议就可以访问,不需要在客户端(用户设备上)安装特定的软件。

(3)优点:服务功能的升级只需要升级服务器端,浏览器中不需要做任何升级操作。

(4)缺点:图形显示效果不如C/S体系结构。

(5)常见的B/S体系结构:淘宝、京东、支付宝等。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二、Web服务器

2.1 概念

2.1.1 什么是Web

(1)Web(World Wide Web)称为万维网,简单理解就是一个网站,它是Internet主机上提供给外界访问的资源、

(2)Internet上提供给外界访问的资源大体上分为两种,即静态资源(静态网站)和动态资源(动态网站)。

​ 静态资源:指Web页面中提供给用户浏览的数据是固定不变的,页面使用HTML+CSS实现。

​ 动态资源:指Web页面中提供给用户浏览的数据是由程序产生的,具有交互性(交互性是指网页可以根据用户的要求动态改变或响应),内容可以自动更新,并且内容会根据访问的时间和访问者而改变,甚至不同设备访问Web页面看到的内容也各不相同。页面使用Servlet+JSP等技术实现。

(3)Java Web是用Java技术来解决Web领域的相关技术的总和。Web包括Web服务器和Web客户端两部分。

2.1.2 什么是Web服务器

Web服务器是发布Web应用、运行Web应用的容器。只有将开发好的Web项目部署在Web服务器中,才能使网络中的用户通过浏览器来访问Web应用。Web服务器的主要功能就是提供网上信息浏览服务。(将Web服务器理解成存储数据(项目)的容器)

2.2 常见Web服务器

开源的Web服务器:
1)Tomcat(主流Web服务器之一,非常适合初学者学习)。
2)jetty(淘宝使用,运行效率比Tomcat高)。
3)resin(新浪使用,所有开源服务器软件中,运行效率最高的)。
上面三个的用法从代码角度看完全相同,只是在开启、关闭服务软件时用的命令稍微有点区别。
收费的Web服务器:
1)WebLogic,Oracle公司开发的。
2)WebSphere,IBM公司开发的。
收费的Web服务器提供相应的服务与支持,软件比较大,资源消耗大。

2.3 Tomcat服务器

(1)Tomcat是Apache软件基金会开发的一个小型的轻量级应用服务器,技术先进,性能稳定,而且是免费的,占用系统资源小,运行速度快。

(2)Tomcat是一个运行Servlet和JSP Web应用软件。基于Java的Web应用软件容器。Tomcat Server是根据Servlet和JSP规范运行的,因此可以说Tomcat Server也实行了Apache规范,且比绝大多数商业应用软件服务器要好。

2.3.1 Tomcat的下载

进入Tomcat官网下载(https://tomcat.apache.org/),其安装文件有多种格式,其中zip文件是Windows系统下的压缩版本。

2.3.2 Tomcat的安装

Tomcat无需安装,只需要将压缩包下载后,将其解压到一个文件夹中就可以使用。

注意:
1)文件夹名称中不要特殊符号。
2)文件夹名称中不要包含中文字符。
3)不建议将Tomcat解压放在磁盘层次很多的文件夹中

2.3.3 Tomcat的目录结构

Tomcat压缩包解压后,其中的各个子文件夹说明如下:

文件夹作用说明
bin存放启动和关闭Tomcat的可执行脚本文件startup.bat启动Tomcat
shutdown.bat停止Tomcat
conf存放Tomact服务器的各种配置文件这是一个非常重要的目录,这个目录下的server.xml文件和web.xml文件最重要。
server.xml:配置整个服务器信息,例如修改端口号,设置编码格式等。
web.xml:项目部署描述文件,这个文件中注册了很多MIME类型,即文档类型
lib存放Tomcat服务器的支撑jar包Tomcat的类库,里面存放Tomcat运行时所需要的jar文件
logs存放Tomcat的日志文件该文件中记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,异常也会记录在日志文件中
temp存放Tomcat运行时产生的临时文件这个目录下的东西在停止Tomcat后删除
webapps存放各种Web应用存放Web项目的目录,其中每个文件夹都是一个项目,其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。
workTomcat的工作目录运行时生成的文件,最终运行的文件都在这个文件夹中。当客户端用户访问一个jsp文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java文件和class文件都会存放在这个目录下

2.3.4 Tomcat的启动

进入Tomcat服务器的安装目录bin文件中,双击startup.bat启动程序,出现如下界面。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

打开浏览器中,在地址栏中输入http://localhost:8080或者http://127.0.0.1:8080回车,会出现Tomcat的访问页面。说明Tomcat服务器启动成功。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3.5 Tomcat的停止

双击shutdown.bat即可关闭Tomcat启动窗口。

2.3.6 修改Tomcat端口号

8080是Tomcat默认的端口,有时候可能会被占用,这时可以通过conf文件夹下的server.xml文件修改端口号,已解决端口号冲突的问题。端口号修改完之后,要重新启动Tomcat并在浏览器的地址栏中使用新的端口号访问Tomcat服务器。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3.7 项目部署及静态资源访问

Tomcat是Web服务器,是一个容器(依然可以理解为装数据的容器),我们开发的项目应用需要部署在webapps文件夹下面,然后启动Tomcat服务器,在浏览器中通过特定的URL访问Web项目的页面。

2.3.7.1 创建项目

1)在webapps中建立项目文件夹,例如,webProject01

2)在webProject01文件中创建WEB-INF文件夹,存放项目的核心内容

3)在WEB-INF文件夹中,创建如下文件夹和文件:

​ -->创建classes文件夹,存放.class文件

​ -->创建lib文件夹,存放jar文件

​ -->创建web.xml项目配置文件(这个文件可以到ROOT项目向的WEB-INF中复制)

4)把你编写的helloTomcat.html页面复制到webProject01文件夹中,webProject01页面与WEB-INF在同级目录。如果你写的静态页面poetry.html中包含图片、样式文件、js文件,那么还需要把静态页面需要的图片文件(文件夹)、样式文件(文件夹)、js文件(文件夹)一起放入到webProject01文件夹中

2.3.7.2 通过URL访问项目

打开浏览器,在浏览器地址栏中输入URL:http://localhost:8080/webProject01/helloTomcat.html,或者在地址栏中输入URL:http://localhost:8080/webProject01/poetry.html,回车,即可访问

2.3.7.3 Tomcat响应流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3.8 Tomcat常见问题

2.3.8.1 Tomcat控制台闪退

闪退的问题是由JAVA_HOME配置导致的,检查JAVA_HOME配置是否正确。

2.3.8.2 404

出现404问题是因为访问资源不存在,也就是访问路径不对(文件名不对)。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3.8.3 500

出现500问题是服务器端的问题,一般是程序逻辑有问题。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

三、HTTP协议

3.1 HTTP协议简介

HTTP(HyperText Transfer Protocol),超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,运行于TCP协议基础之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。

3.2 HTTP协议特点

(1)支持客户端(浏览器)/服务器模式。

(2)简单快速:客户端只向服务器发送请求方法和路径,服务器即可响应数据,因而通信速度很快。请求方法常用的有get和post等。

(3)灵活:HTTP允许传输任意类型的数据,传输的数据类型由Content-Type标识。

(4)无连接:无连接指的是每次TC连接只处理一个或多个请求,服务器处理完客户的请求后,即断开连接。采用这种方式可以节省传输时间。

​ HTTP1.0版本一个请求响应之后,直接就断开了。称为短连接。

​ HTTP1.1版本不是响应之后直接就断开了,而是等几秒钟,这几秒钟之内有新的请求,那么还是通过之前的连接通道来收发消息,如果过了这几秒钟用户没有发送新的请求,就会断开连接。称为长连接。

(5)无状态:HTTP协议是无状态协议。

​ 无状态是指协议对于事务处理没有记忆能力。

3.3 HTTP协议通信流程(工作原理)

HTTP是基于客户/服务器模式,且面向连接的。典型的HTTP事务处理有如下的过程:

(1)客户端与服务器建立连接(三次握手)。

(2)客户向服务器发送请求。

(3)服务器接受请求,并根据请求返回响应的文件作为应答。

(4)客户与服务器关闭连接(四次挥手)。

客户与服务器之间的HTTP连接是一种一次性连接,它限制每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。这种一次性连接主要考虑到WWW服务器面向的是Internet中成千上万个用户,且只能提供有限个连接,故服务器不会让一个连接处于等待状态,及时地释放连接可以大大提高服务器的执行效率。

HTTP是一种无状态协议,即服务器不保留与客户交易时的任何状态。这就大大减轻了服务器记忆负担,从而保持较快的响应速度。HTTP是一种面向对象的协议。允许传送任意类型的数据对象。它通过数据类型和长度来标识所传送的数据内容和大小,并允许对数据进行压缩传送。当用户在一个HTML文档中定义了一个超文本链后,浏览器将通过TCP/IP协议与指定的服务器建立连接。

HTTP支持持久连接,在HTTP / 0.9和1.0中,连接在单个请求/响应对之后关闭。在HTTP / 1.1中,引入了保持活动机制,其中连接可以重用于多个请求。这样的持久性连接可以明显减少请求延迟,因为在发送第一个请求之后,客户端不需要重新协商TCP 3-Way-Handshake连接。另一个积极的副作用是,通常,由于TCP的缓慢启动机制,连接随着时间的推移而变得更快。

该协议的1.1版还对HTTP / 1.0进行了带宽优化改进。例如,HTTP / 1.1引入了分块传输编码,以允许流传输而不是缓冲持久连接上的内容。HTTP流水线进一步减少了延迟时间,允许客户端在等待每个响应之前发送多个请求。协议的另一项附加功能是字节服务,即服务器仅传输客户端明确请求的资源部分。

从技术上讲是客户在一个特定的TCP端口(端口号一般为80)上打开一个套接字。如果服务器一直在这个周知的端口上倾听连接,则该连接便会建立起来。然后客户通过该连接发送一个包含请求方法的请求块。

HTTP规范定义了9种请求方法,每种请求方法规定了客户和服务器之间不同的信息交换方式,常用的请求方法是GET和POST。服务器将根据客户请求完成相应操作,并以应答块形式返回给客户,最后关闭连接。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.4 HTTP报文格式

HTTP报文由从客户机到服务器的请求和从服务器到客户机的响应构成。

3.4.1 HTTP请求报文

当浏览器向Web服务器发出请求时,它向服务器传送了一个数据块,也就是所谓的请求信息(请求报文),HTTP请求信息由4个部分组成,分别是:1、请求行 请求方法/地址/ URI协议/版本 2、请求头(Request Header) 3、空行 4、请求正文

3.4.2 HTTP响应报文

HTTP响应报文与HTTP请求报文相似,HTTP响应报文也由4个部分组成:1、状态行 2、响应头(Response Header) 3、空行 4、响应正文

3.4.3 HTTP状态消息

HTTP的状态消息有很多,在这里主要列举最常见的一些状态消息。

状态代码状态描述说明
200OK客户端请求成功
302Found临时重定向
403Forbidden服务器收到请求,但是拒绝提供服务。
服务器通常会在响应正文中给出不提供服务的原因
404Not Found请求的资源不存在,最常见的就是输入了错误的路径
500Internal Server Error服务器发生不可预期的错误,导致无法完成客户端的请求

四、Servlet基础(重要)

4.1 Servlet概念

(1)Servlet:Server Applet的简称,是运行在Web服务器端的Java程序,可交互式的处理客户端发送到服务器端的请求,并完成响应操作,它使用Java语言编写(Servlet是Java代码)。

(2)Servlet可实现动态网页。

(3)Servlet是JavaWeb开发程序的基础,是一个标准,由SUN定义,具体细节由Servlet容器进行实现,如Tomact、JBoss等。Servlet是JavaEE规范(一套接口)的一个组成部分。

4.2 Servlet作用

(1)接收客户端请求,完成相关操作

(2)动态生成网页(页面数据可变,不同用户页面数据不同)

(3)将包含操作结果的动态网页响应给客户端。

4.3 Servlet开发步骤

4.3.1 搭建开发环境

将Tomcat安装路径下lib文件夹中与Servlet相关的jar包(lib\servlet-api.jar)配置到classpath环境变量中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.3.2 创建项目

(1)在webapps中建立项目文件夹,例如,webProject02

(2)在webProject02文件中创建WEB-INF文件夹,存放项目的核心内容

(3)在WEB-INF文件夹中,创建如下文件夹和文件:

​ -->创建classes文件夹,存放.class文件

​ -->创建lib文件夹,存放jar文件

​ -->创建web.xml项目配置文件(这个文件可以到ROOT项目向的WEB-INF中复制)

(4)在classes中创建类的包文件夹,在文件夹中通过实现java.servlet.Servlet接口的方式编写ServletDemo01类。重写java.servlet.Servlet接口中的方法,在重写的核心方法service()中编写输出语句,打印访问结果。

package com.cxyzxc.www.servlet01;

import java.io.IOException;
import java.util.Date;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ServletDemo01 implements Servlet{
	
	@Override
	public void destroy() {
		
	}

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

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

	@Override
	public void init(ServletConfig arg0) throws ServletException {
		
	}

	@Override
	public void service(ServletRequest arg0, ServletResponse arg1)
			throws ServletException, IOException {
		
		System.out.println("My First Servlet!Very Good!");
		
	}
}

4.3.3 部署Servlet

1)编译ServletDemo01.java文件生成ServletDemo01.class字节码文件

2)将ServletDemo01.class文件(连同所在的文件夹)放在Web项目的WEB-INF文件里的classes文件夹中

4.3.4 配置Servlet

编写WEB-INF文件夹中的项目配置文件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_3_1.xsd"
  version="3.1"
  metadata-complete="true">
	
<!-- 1、添加Servlet节点-->
<servlet>
	<!-- 你的Servlet类名称-->
	<servlet-name>MyFirstServlet</servlet-name>
	<!-- 你的Servlet类的完整路径-->
	<servlet-class>com.cxyzxc.www.servlet01.ServletDemo01</servlet-class>
</servlet>

<!-- 2、 添加servlet-mapping节点-->
<servlet-mapping>
	<!--  这个地方的servlet-name值要和上面servlet-name值保持一致-->
	<servlet-name>MyFirstServlet</servlet-name>
	<!-- url-patter配置的内容是浏览器地址栏中URL里项目名称后的资源内容-->
	<url-pattern>/firstServlet</url-pattern>
</servlet-mapping>

</web-app>

4.3.5 测试运行

1)启动Tomcat

2)打开浏览器,在浏览器地址栏中输入http://localhost:8080/webProject02/firstServlet,可以在Tomcat窗口中看到输出“My First Servlet!Very Good!”内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

五、IDEA中创建Web项目

5.1 创建Web项目

5.1.1 创建项目

1、打开IDEA,单击“New Project”或者通过File–>new–>Project,在弹出的对话框中输入项目名称,其它的默认选择,点击finish按钮

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2、为项目添加Web框架支持,右键单击创建的项目,点击Add Framework Support,在弹出的对话框中勾选Web Application(4.0)及Create web.xml复选框,单击“OK”按钮,完成添加。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3、添加依赖包,右键单击WEB-INF文件夹,在弹出的对话框中选择New–>Directory命令,创建lib文件夹,将Tomcat安装目录下lib文件夹中的servlet-api.jar文件添加到lib文件夹中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4、在servlet-api.jar文件上右击鼠标,选择Add As Library,将jar包添加到Library中

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.1.2 编写Servlet类

1、在src上右击鼠标–>new–>package–>输入com.cxyzxc.www.servlet01包名(包名你可以自己取)–>回车

2、在包上右击鼠标–>new–>Java Class–>输入ServletDemo02类名–>回车

3、编写ServletDemo02类,实现Servlet接口,重写接口中的5个方法,在service()方法中输出内容

package com.cxyzxc.www.servlet01;

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

public class ServletDemo02 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("IDEA中的第一个Servlet案例");
    }

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

    @Override
    public void destroy() {

    }
}

4、编译ServletDemo02.java文件,生成ServletDemo02.class文件。在软件上面点击Build–>Build Project,等待片刻,生成out文件夹,里面包含编译后的class文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5、编写web.xml配置文件

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

5.2 手动部署项目

1)在Tomcat服务器的webapps文件中,创建一个项目文件夹,例如webProject03

2)将IDEA软件中WEB-INF文件夹整体复制到webProject03文件夹中

3)在WEB-INF文件夹中创建classes文件夹,将编译后生成的ServletDemo02.class文件所在的文件夹一起复制到classes文件夹中

4)启动Tomcat,打开浏览器,在浏览器地址栏输入http://localhost:8080/webProject03/secondServlet,可以在Tomcat窗口中看到输出“IDEA中的第一个Servlet案例,手动部署到Tomcat容器中”内容。

5.3 自动部署项目

上述操作中,虽然是在IDEA软件中完成了Servlet代码的编写以及编译,但是还需要手动将WEB-INF文件夹复制到Tomcat的项目文件夹中去,并需要手动在WEB-INF文件中创建classes文件夹,然后将IDEA中编译后的class文件复制到classes文件夹中,比较麻烦。另外,当你的Java文件改变后,你需要重新编译java文件生成class文件,然后再将class文件复制到classes文件夹中,再重新启动Tomcat服务器才能访问资源,非常的麻烦。所以,我们可以在IDEA中集成Tomact服务器,实现自动部署。

5.3.1 IDEA集成Tomcat

1、 点击File–>Settings…

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2、选择双击Build,Execution,Deployment–>Application Servers,点击+号,选择Tomcat Server

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3、选择Tomcat服务器的安装路径,点击ok,Tomcat服务器就集成到IDEA中了外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4、再次点击File–>Settings…–>Build,Execution,Deployment–>Application Servers,点击+号,选择Tomcat Server,可以看到Tomcat服务器在IDEA中

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.3.2 IDEA部署JavaWeb项目

1、点击Run或者软件右边绿色锤子旁边下拉框,选择Edit Configuration…

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2、点击图示中任意一个选项,进入添加运行配置界面

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3、配置Tomcat Server和运行项目的默认浏览器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4、添加项目到Tomcat中并设置访问名称

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5、在IDEA中启动启动项目

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6、浏览器中默认输出index.jsp中的内容

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

7、在浏览器地址栏中输入Servlet访问路径,Tomcat控制台中输出service()方法中的内容

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.4 war包部署

项目开发完成后,为了方便部署,我们需要将项目整体打包成war包去部署在Tomcat服务器中。war包可以直接放入Tomcat的webapps文件夹中,启动Tomcat后自动解压,即可在浏览器中输入URL进行访问。

5.4.1 导出war包

1、点击File->Project Structure菜单(或使用Shift+Ctrl+Alt+S快捷键),打开Project Structure窗口

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2、在ProjectStructure中选择左侧的Artifacts页签

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3、点击中间上面的“+”,选择WebApplication:Archive-> Empty

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4、点击上图中的①处的“+”,选择Directory Content菜单

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.4.2 部署war包

5.4.3 启东Tomcat服务器,访问项目

六、Servlet详解(重要)

6.1 Servlet核心接口和类

在Servlet体系结构中,除了第三节中讲的实现Servlet接口,还可以通过继承GenericServlet或HttpServlet类,完成自定义Servlet的编写。

6.1.1 Servlet接口

在Servlet API中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。该接口中包括以下5个方法:

destroy()
ServletConfig getServletConfig()
String getServletInfo()
void init(ServletConfig arg0)
void service(ServletRequest arg0, ServletResponse arg1)

6.1.2 GenericServlet抽象类

GenericServlet使编写Servlet变得更容易。它提生命周期方法init和destroy的简单实现,要编写一般的Servlet,只需要重写service方法即可。

6.1.3 HttpServlet类

1)HttpServlet是在继承GenericServlet的基础上进一步的扩展。提供将要被子类化以创建适用于Web站点的HTTP servlet的抽象类。

2)HTTPServlet的子类至少必须重写一个方法,该方法通常是:

  • doGet():用于HTTP GET请求
  • doPost():用于HTTP POST请求
  • doPut():用于HTTP PUT请求
  • doDelete():用于HTTP DELETE请求

6.2 Servlet三种创建方式

6.2.1 实现Servlet接口

使用这种方式创建Servlet类比较麻烦,需要重写Servlet接口中的所有方法

package com.cxyzxc.www.servlet01;

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

/**
 * 使用实现Servlet接口创建的MyServlet01类
 */

public class MyServlet01 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("使用实现Servlet接口创建的MyServlet类");
    }

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

    @Override
    public void destroy() {

    }
}

6.2.2 继承GenericServlet类

package com.cxyzxc.www.servlet01;

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

/**
 * 使用继承GenericServlet类创建的MyServlet02类,开发中推荐使用这种方式
 */

public class MyServlet02 extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("使用继承GenericServlet类创建的MyServlet类");
    }
}

6.2.3 继承HttpServlet类(推荐使用)

package com.cxyzxc.www.servlet01;

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;

/**
 * 使用继承HttpServlet类创建的MyServlet03类,开发中推荐使用这种方式
 */

@WebServlet("/servlet03")
public class MyServlet03 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("使用继承HttpServlet类创建的MyServlet类");
    }

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

6.3 Servlet两种配置方式

6.3.1 使用web.xml配置

这种配置是Servlet2.5之前使用的

<?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>myServlet01</servlet-name>
        <!-- Servlet的全称类名 -->
        <servlet-class>com.cxyzxc.www.servlet01.MyServlet01</servlet-class>
       <!-- 启动的优先级,数字越小越先起作用 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Servlet映射配置 -->
    <servlet-mapping>
        <!-- Servlet名称 -->
        <servlet-name>myServlet01</servlet-name>
        <!-- 资源的匹配原则:精确匹配 -->
        <url-pattern>/servlet01</url-pattern>
    </servlet-mapping>
</web-app>

6.3.2 资源配置属性

 url-pattern定义匹配规则,取值说明:
    精确匹配        /具体的名称  只有url路径是具体的名称的时候才会触发Servlet
    后缀匹配        *.xxx      只要是以xxx结尾的就匹配触发Servlet
    通配符匹配      /*         匹配所有请求,包含服务器的所有资源
    通配符匹配      /          匹配所有请求,包含服务器的所有资源,不包括.jsp

 load-on-startup
    1)元素标记容器是否应该在web应用程序启动的时候就加载这个servlet。
    2)它的值必须是一个整数,表示servlet被加载的先后顺序。
    3)如果该元素的值为负数或者没有设置,则容器会当servlet被请求时再加载。
    4)如果值为整数或0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。

6.3.3 使用注解配置

这种配置是Servlet3.0之后使用的,推荐使用这种方式

package com.cxyzxc.www.servlet01;

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;

/**
 * 使用继承HttpServlet类创建的MyServlet03类,开发中推荐使用这种方式
 */

@WebServlet("/servlet03")
public class MyServlet03 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("使用继承HttpServlet类创建的MyServlet类");
        resp.getWriter().println("Servlet is very funny ");
    }

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

6.3.4 @WebServlet注解常用属性

  • name:Servlet名字(可选)
  • value:配置url路径,可以配置多个
  • urlPatterns:配置url路径,和value作用一样,不能同时使用
  • loadOnStartup:配置Servlet的创建的时机,如果是0或者正数,启动程序时创建,如果是负数,则访问时创建。数字越小优先级越高。

七、Servlet生命周期

7.1 生命周期四个阶段

7.1.1 实例化

当用户第一次访问Servlet时,由容器调用Servlet的构造器创建具体的Servlet对象。也可以在容器启动之后立刻创建实例。使用如下代码可以设置Servlet是否在服务器启动时就创建。

实例化只执行一次。

7.1.2 初始化

在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数

init()方法只被执行一次

7.1.3 服务

当客户端有一个请求时,容器就会将请求ServletRequest与响应ServletResponse对象转给Servlet,以参数的形式传给service方法。

service()方法会执行多次

7.1.4 销毁

当Servlet容器停止或者重新启动都会引起销毁Servlet对象并调用destroy方法

destroy()方法执行一次

7.1.5 Servlet执行流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

package com.cxyzxc.www.servlet01;

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

/**
 * 演示Servlet的生命周期
 * 1、实例化
 * 2、init:初始化
 * 3、service:服务
 * 4、destory:销毁
 */

@WebServlet("/LifeServlet01")
public class LifeServlet01 implements Servlet {
    public LifeServlet01() {
        System.out.println("1、完成实例化");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("2、完成初始化");
    }

    @Override
    public ServletConfig getServletConfig() {
        System.out.println("getServletConfig()");
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3、就绪中");
    }

    @Override
    public String getServletInfo() {
        System.out.println("getServletInfo()");
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("4、销毁了");
    }
}
package com.cxyzxc.www.servlet01;

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

/**
 * 演示Servlet的生命周期
 * 1、实例化
 * 2、init:初始化
 * 3、service:服务
 * 4、destory:销毁
 */

@WebServlet("/LifeServlet02")
public class LifeServlet02 extends HttpServlet {

    public LifeServlet02() {
        System.out.println("1、完成实例化");
    }

    @Override
    public void init() throws ServletException {
        super.init();
        System.out.println("2、完成初始化");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("3、就绪中");
    }

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

    @Override
    public void destroy() {
        super.destroy();
        System.out.println("4、销毁了");
    }
}

八、Servlet特性

8.1 线程安全问题

Servlet在访问之后,会执行实例化操作,创建一个Servlet对象。而我们Tomcat容器可以同时多个线程并发访问同一个Servlet,如果在方法中对成员变量做修改操作,就会有线程安全问题。

8.2 如何保证线程安全

  1. synchronize

    • 将存在线程安全问题的代码放到同步代码块中
  2. 实现SingleThreadModel接口

    • servlet实现SingleThreadMode接口后。每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端的效率太低,所以已经淘汰。
  3. 尽可能使用局部变量


九、 Servlet应用

9.1 Request对象

在Servlet中用来处理客户端请求需要用doGet或doPost方法中的request对象。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.1.1 get和post区别

get请求

  • get提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
  • get方式明文传递,数据量小,不安全
  • 效率高,浏览器默认请求方式为get请求
  • 对应的Servlet的方法是doGet()

post请求

  • post方法是把提交的数据放在HTTP包的body中
  • 密文传递数据,数据量大,安全
  • 效率没有get高
  • 对应的Servlet的方法是doPost()

9.1.2 request主要方法

方法名方法说明
String getParameter(String name)根据表单组件名称获取提交的数据
void setCharacterEncoding(String charset)指定每个请求的编码

9.1.3 request应用

9.1.3.1 编写HTML页面
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>欢迎页面</title>
    </head>
    <body>
        <h1>欢迎你</h1>
        <form action="WelcomeServlet" method="post">
            <label>姓名:</label><input type="text" name="username"/><br/>
            <label>年龄:</label><input type="text" name="userage"/><br/>
            <input type="submit" value="提交"/>
        </form>
    </body>
</html>
9.1.3.2 编写Servlet类
package com.cxyzxc.www.demo01;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/WelcomeServlet")
public class WelcomeServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取表单提交的姓名
        String username = req.getParameter("username");
        //获取表单提交的年龄
        String userage = req.getParameter("userage");
        //服务器端输出获取到的数据
        System.out.println("客户端发来的信息:姓名:"+username+",年龄:"+userage);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
9.1.3.4 浏览器提交

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.1.5 后台获取数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.1.4 get请求收参问题

get请求发送后,在服务器端获取中文数据产生乱码,是因为服务器和客户端沟通的编码不一致造成的,所以解决办法是在客户端和服务器之间设置一个统一的编码,之后就按照设置的编码进行数据的传输和接收。

9.1.5 get中文乱码

在Tomcat7及以下版本,客户端以UTF-8的编码传输数据到服务器端,而服务器端的request对象使用的是ISO8859-1这个字符编码来接收数据,服务器和客户端沟通的编码不一致,因此会产生中文乱码。

​ (1)解决办法:在接收到数据后,先获取request对象以ISO8859-1字符编码接收到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题。

​ (2)Tomcat8的版本中get不会出现乱码了,因为服务器对url的编码格式可以自动转换。

package com.cxyzxc.www.demo01;

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

@WebServlet("/GetServlet")
public class GetServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取表单提交的姓名
        String username = req.getParameter("username");
        username = new String(username.getBytes("ISO8859-1"), "UTF-8");
        //获取表单提交的年龄
        String userage = req.getParameter("userage");
        //服务器端输出获取到的数据
        System.out.println("客户端发来的信息:姓名:" + username + ",年龄:" + userage);
    }

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

9.1.6 post中文乱码

由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器端也需要设置以UTF-8字符编码进行接收。

解决方法:使用从ServletRequest接口继承而来的setCharacterEncoding(charset)方法进行统一的编码设置。

package com.cxyzxc.www.demo01;

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;

/**
 * Servlet中post请求中文乱码处理
 */
@WebServlet("/PostServlet")
public class PostServlet extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        req.setCharacterEncoding("UTF-8");
        //获取表单提交的姓名
        String username = req.getParameter("username");
        //获取表单提交的年龄
        String userage = req.getParameter("userage");
        //服务器端输出获取到的数据
        System.out.println("客户端发来的信息:姓名:" + username + ",年龄:" + userage);
    }
}

9.2 response对象

response对象用于响应客户请求并向客户端输出信息

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.2.1 response主要方法

方法名称方法作用
setHeader(name,value)设置响应信息头
setContenType(String)设置响应文件类型、响应式的编码格式
setCharacterEncoding(String)设置服务端响应内容编码格式
getWriter()获取字符输出流

9.2.2 response应用

响应输出内容中不包含中文

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果输出内容包含中文,则出现乱码,因为服务器默认采用ISO8859-1编码响应内容

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.2.3 解决输出中文乱码

方式一:设置服务器端响应的编码格式和设置客户端响应内容的头内容的文件类型及编码格式,这种方式不推荐

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

方式二:同时设置服务端的编码格式和客户端响应的文件类型及响应时的编码格式,推荐此方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

9.3 综合案例(Servlet+JDBC)

在MySQL中新建一个servletdatabase数据库,专门用来学习servlet操作数据库

9.3.1 案例需求

实现登录功能,登录成功后显示所有管理员信息,登录失败给出“账号或密码错误,无法登录”提示信息

9.3.2 创建表admin并添加数据

#创建表admin
CREATE TABLE IF NOT EXISTS `admin`(
`username` VARCHAR(20) PRIMARY KEY,
`password` VARCHAR(20) NOT NULL,
`phone` VARCHAR(11) UNIQUE NOT NULL,
`address` VARCHAR(20) NOT NULL
);

#向admin表中插入数据
INSERT INTO `admin`(`username`,`password`,`phone`,`address`)
VALUES('张三','123456','13112345678','安徽合肥蜀山区');

INSERT INTO `admin`(`username`,`password`,`phone`,`address`)
VALUES('李四','123456','13822334455','安徽合肥高新区');

9.3.3 创建Web项目

创建Web项目adminProject01,在项目下创建包目录结构如下,并导入相关jar包及配置文件

  • com.cxyzxc.www.dao包:数据访问层接口
  • com.cxyzxc.www.dao.impl包:数据访问层接口实现类
  • com.cxyzxc.www.entity包:实体类
  • com.cxyzxc.www.service包:业务逻辑层接口
  • com.cxyzxc.www.service.impl包:业务逻辑层接口实现类
  • com.cxyzxc.www.servlet包:Servlet类
  • com.cxyzxc.www.utils包:工具类
  • database.properties:数据库连接及连接池配置文件

9.3.4 database.properties文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/servletdatabase
username=root
password=123456

initialSize=10

maxActive=30

maxIdle=5

maxWait=3000

9.3.5 DBUtils类代码

package com.cxyzxc.www.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

public class DBUtils {

	// 声明一个连接池对象
	private static DruidDataSource druidDataSource;

	static {
		// 实例化配置文件对象
		Properties properties = new Properties();

		try {
			// 加载配置文件内容
			InputStream is = DBUtils.class
					.getResourceAsStream("/database.properties");
			properties.load(is);
			// 创建连接池
			druidDataSource = (DruidDataSource) DruidDataSourceFactory
					.createDataSource(properties);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//返回一个数据源
	public static DataSource getDataSource(){
		return druidDataSource;
	}

}

9.3.6 Admin实体类

package com.cxyzxc.www.entity;

public class Admin {

    private String username;
    private String password;
    private String phone;
    private String address;

    public Admin() {
    }

    public Admin(String username, String password, String phone, String address) {
        this.username = username;
        this.password = password;
        this.phone = phone;
        this.address = address;
    }

    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;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Admin{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", phone='" + phone + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

9.3.7 AdminDao接口

package com.cxyzxc.www.dao;

import com.cxyzxc.www.entity.Admin;

import java.util.List;

public interface AdminDao {

    //查询用户(查询单个)
    Admin selectOneByUsernameAndPassword(String username, String password);

    //查询所有用户
    List<Admin> selectAll();
}

9.3.8 AdminDaoImpl实现类

package com.cxyzxc.www.dao.impl;

import com.cxyzxc.www.dao.AdminDao;
import com.cxyzxc.www.entity.Admin;
import com.cxyzxc.www.utils.DBUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;

public class AdminDaoImpl implements AdminDao {
    // 创建QueryRunner对象,并传递一个数据源对象
    private final QueryRunner QUERYRUNNER = new QueryRunner(DBUtils.getDataSource());

    @Override
    public Admin selectOneByUsernameAndPassword(String username, String password) {
        String sql = "SELECT * FROM `admin` WHERE `username` = ? AND `PASSWORD`=?;";
        Object[] args = {username, password};
        try {
            return QUERYRUNNER.query(sql, new BeanHandler<Admin>(Admin.class), args);
        } catch (SQLException e) {
            e.printStackTrace();

        }

        return null;
    }


    @Override
    public List<Admin> selectAll() {
        String sql = "SELECT * FROM `admin`;";
        try {
            return QUERYRUNNER.query(sql, new BeanListHandler<Admin>(Admin.class));
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;
    }

}

9.3.9 AdminService接口

package com.cxyzxc.www.service;

import com.cxyzxc.www.entity.Admin;

import java.util.List;

public interface AdminService {

    Admin login(String username, String password);

    List<Admin> selectAllAdmin();
}

9.3.10 AdminServiceImpl实现类

package com.cxyzxc.www.service.impl;

import com.cxyzxc.www.service.AdminService;
import com.cxyzxc.www.dao.AdminDao;
import com.cxyzxc.www.dao.impl.AdminDaoImpl;
import com.cxyzxc.www.entity.Admin;

import java.util.List;

public class AdminServiceImpl implements AdminService {
    private final AdminDao ADMINDAO = new AdminDaoImpl();

    @Override
    public Admin login(String username, String password) {
        return ADMINDAO.selectOneByUsernameAndPassword(username, password);
    }

    @Override
    public List<Admin> selectAllAdmin() {
        return ADMINDAO.selectAll();
    }
}

9.3.11 HTML页面

9.3.11.1 login.html页面
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
        <link type="text/css" rel="stylesheet" href="css/login.css"/>
    </head>

    <body>
        <div>
            <form action="LoginServlet" method="post">
                <p>
                    账号:<input type="text" name="username"/>
                </p>
                <p>
                    密码:<input type="password" name="password"/>
                </p>
                <p>
                    <input type="submit" value="登录"/>
                </p>
            </form>
        </div>
    </body>
</html>
9.3.11.2 login.css
* {
    margin: 0;
    padding: 0;
}

div {
    width: 400px;
    height: 100px;
    background-color: #ccc;
    margin: 30px auto;
    padding-top: 30px;
    text-align: center;
}

p {
    margin-top: 10px;
}

input {
    outline: none;
}
9.3.11.3 table.css
*{
    margin: 0;
    padding: 0;
}

table{
    margin: 20px auto;
    width: 500px;
    height: 100px;
    text-align: center;
}

9.3.12 LoginServlet

package com.cxyzxc.www.servlet;

import com.cxyzxc.www.service.AdminService;
import com.cxyzxc.www.service.impl.AdminServiceImpl;
import com.cxyzxc.www.entity.Admin;

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

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    private final AdminService ADMINSERVICE = new AdminServiceImpl();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        req.setCharacterEncoding("UTF-8");
        //获取数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        Admin admin = ADMINSERVICE.login(username, password);

        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter printWriter = resp.getWriter();

        if (admin != null) {
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<title>登录成功</title>");
            printWriter.println("</head>");
            printWriter.println("<body>");
            printWriter.println("<h2>登录成功</h2>");
            printWriter.println("</body>");
            printWriter.println("</html>");
        } else {
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<title>登录失败</title>");
            printWriter.println("</head>");
            printWriter.println("<body>");
            printWriter.println("<h2>账号或密码错误,无法登录</h2>");
            printWriter.println("</body>");
            printWriter.println("</html>");

        }

    }

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

9.3.13 ShowAllAdminServlet

package com.cxyzxc.www.servlet;

import com.cxyzxc.www.service.AdminService;
import com.cxyzxc.www.service.impl.AdminServiceImpl;
import com.cxyzxc.www.entity.Admin;

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

@WebServlet("/ShowAllAdminServlet")
public class ShowAllAdminServlet extends HttpServlet {
    private final AdminService ADMINSERVICE = new AdminServiceImpl();

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

        PrintWriter printWriter = resp.getWriter();
        List<Admin> adminList = ADMINSERVICE.selectAllAdmin();
        if (adminList.size() != 0) {
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<title>所有admin</title>");
            printWriter.println("<link type=\"text/css\" rel=\"stylesheet\" href=\"css/table.css\" />");
            printWriter.println("</head>");
            printWriter.println("<table border='1px' cellspacing='0'>");
            printWriter.println("<tr>");
            printWriter.println("<th>账号</th>");
            printWriter.println("<th>密码</th>");
            printWriter.println("<th>手机号码</th>");
            printWriter.println("<th>住址</th>");
            printWriter.println("<th>操作</th>");
            printWriter.println("</tr>");
            for (Admin admin : adminList) {
                printWriter.println("<tr>");
                printWriter.println("<td>" + admin.getUsername() + "</td>");
                printWriter.println("<td>" + admin.getPassword() + "</td>");
                printWriter.println("<td>" + admin.getPhone() + "</td>");
                printWriter.println("<td>" + admin.getAddress() + "</td>");
                printWriter.println("<td><a href=\"#\">修改</a> <a href=\"#\">删除</a></td>");
                printWriter.println("</tr>");
            }
            printWriter.println("</table>");
            printWriter.println("</html>");
        } else {
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<title>所有admin</title>");
            printWriter.println("</head>");
            printWriter.println("<body>");
            printWriter.println("<h2>当前没有用户</h2>");
            printWriter.println("</body>");
            printWriter.println("</html>");
        }

    }

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

十、转发与重定向

10.1 综合案例中问题与解决方法

10.1.1 综合案例中的问题

(1)在综合案例中,调用业务逻辑和显示结果页面都是在同一个Servlet里,就会产生设计问题:

  • 不符合单一只能原则和各司其职的思想
  • 不利于后续的维护

(2)如果我希望登录失败后,继续在登录页面进行登录,又该怎么实现呢?

(3)解决办法:应该将业务逻辑和显示结果分离

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.1.2 综合案例中问题的解决方法

将业务与显示分离,会产生两个问题:

1)业务逻辑和显示结果分离后,如何跳转到显示结果的Servlet?

2)业务逻辑得到的数据结果如何传递给显示结果的Servlet?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.2 转发

转发的作用在服务器端,将请求发送给服务器上的其它资源,以共同完成一次请求的处理。

10.2.1 页面跳转

在调用业务逻辑的Servlet中,编写以下代码:

request.getRequestDispatcher("/目标URL-pattern").forward(request,response);

使用forward跳转时,是在服务器内部跳转,地址栏不发生变化,属于同一次请求。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.2.1.1 AServlet类
package com.cxyzxc.www.servlet01;

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

@WebServlet("/a")
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取数据并做业务处理后进行转发,此处获取数据及业务处理省略,直接转发请求
        request.getRequestDispatcher("/b").forward(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
10.2.1.2 BServlet类
package com.cxyzxc.www.servlet01;

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

@WebServlet("/b")
public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //响应请求
        response.getWriter().println("BServlet响应的内容");
    }

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

    }
}
10.2.1.3 显示效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.2.2 数据传递

forward表示一次请求,是在服务器内部跳转,可以共享同一次request作用域中的数据。

  1. request作用域:拥有存储数据的空间,作用范围是一次请求有效(一次请求可以多次转发)
    • 可以将数据存入request后,在一次请求过程中的任何位置进行获取
    • 可传递任何数据类型(基本数据类型、对象、数组、集合等)
  2. 存数据:request.setAttribute(key,value);
    • 以键值对形式存储在request作用域中。key为String类型,value为Object类型
  3. 取数据:request.getAttribute(key);
    • 通过String类型的key获取Object类型的value
10.2.2.1 login.html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
        <link type="text/css" rel="stylesheet" href="css/login.css"/>
    </head>

    <body>
        <div>
            <form action="CServlet" method="post">
                <p>
                    账号:<input type="text" name="username"/>
                </p>
                <p>
                    密码:<input type="password" name="password"/>
                </p>
                <p>
                    <input type="submit" value="登录"/>
                </p>
            </form>
        </div>
    </body>
</html>
10.2.2.2 CServlet
package com.cxyzxc.www.servlet01;

import com.cxyzxc.www.entity.User;

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

@WebServlet(name = "CServlet", value = "/CServlet")
public class CServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取请求数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //将获取的数据封装成对象,存储在request对象中,request对象中可以存储任何数据类型(基本数据类型、对象、数组、集合等)
        User user = new User(username, password);
        request.setAttribute("user", user);

        //转发请求
        request.getRequestDispatcher("/DServlet").forward(request, response);

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
10.2.2.3 DServlet
package com.cxyzxc.www.servlet01;

import com.cxyzxc.www.entity.User;

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

@WebServlet(name = "DServlet", value = "/DServlet")
public class DServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取request对象中的数据,获取的都是Object类型,转换为实际的User类型
        User user = (User) request.getAttribute("user");
        //响应信息到客户端
        response.getWriter().println("<h2>欢迎你," + user.getUsername() + "</h2>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
10.2.2.4 显示效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.2.3 转发特点

1)转发是服务器行为

2)转发是浏览器只做了一次访问请求

3)转发两次跳转之间传输的信息不会丢失,多以可以通过request进行数据的传递

4)转发只能将请求转发给同一个Web应用中的组件

10.3 重定向

重定向作用在客户端,客户端将请求发送给服务器中,服务器响应给客户端一个新的请求地址,客户端重新发送新请求。

10.3.1 页面跳转

在调用业务逻辑的Servlet中,编写以下代码:

response.sendRedirect("目标URI");

URI:统一资源标识符(Uniform Resource Identifier),用来表示服务器中定位一个资源,资源在Web项目中的路径(、project/source)

使用redirect跳转时,是在客户端跳转,地址栏发生变化,属于多次请求

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.3.1.1 EServlet
package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "EServlet", value = "/EServlet")
public class EServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //客户端请求访问EServlet,服务器响应客户端重定向到FServlet
        response.sendRedirect("/webProject08_war_exploded/FServlet");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
10.3.1.2 FServlet
package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "FServlet", value = "/FServlet")
public class FServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        response.getWriter().println("这里是FServlet输出的内容");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
10.3.1.3 显示效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.3.2 数据传递

sendRedirect跳转时、地址栏改变,代表客户端重新发送的请求。属于两次请求。

  1. response没有作用域,两次request请求中的数据无法共享
  2. 传递数据:通过URI的拼接进行数据传递(“WebProject/b?username=zhangsan”);
10.3.2.1 register.html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册页面</title>
        <link type="text/css" rel="stylesheet" href="css/login.css"/>
    </head>

    <body>
        <div>
            <form action="GServlet" method="post">
                <p>
                    账号:<input type="text" name="username"/>
                </p>
                <p>
                    密码:<input type="password" name="password"/>
                </p>
                <p>
                    <input type="submit" value="注册"/>
                </p>
            </form>
        </div>
    </body>
</html>
10.3.2.2 GServlet
package com.cxyzxc.www.servlet01;

import com.cxyzxc.www.entity.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.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@WebServlet(name = "GServlet", value = "/GServlet")
public class GServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取请求数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //将获取的数据封装成对象,存储在request对象中,request对象中可以存储任何数据类型(基本数据类型、对象、数组、集合等)
        User user = new User(username, password);
        request.setAttribute("user", user);

        //response中没有setAttribute()方法,无法存储数据
        //response.setAttribute("user",user);

        //重定向请求,将数据拼接在URI后面,并对参数进行编码
        response.sendRedirect("/webProject08_war_exploded/HServlet?username=" + URLEncoder.encode(username, "UTF-8") + "&password=" + password + "");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
10.3.2.4 HServlet
package com.cxyzxc.www.servlet01;

import com.cxyzxc.www.entity.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.net.URLDecoder;
import java.nio.charset.StandardCharsets;

@WebServlet(name = "HServlet", value = "/HServlet")
public class HServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取request对象中的数据,获取的都是Object类型,转换为实际的User类型
        User user = (User) request.getAttribute("user");
        //获取请求后的地址参数,并解码
        String queryString = URLDecoder.decode(request.getQueryString(), "UTF-8");

        //响应信息到客户端
        response.getWriter().println("<h2>欢迎你," + user + "</h2>");
        response.getWriter().println("<h2>欢迎你," + queryString + "</h2>");

        //对queryString字符串进行相应处理,可以获取用户账号和密码信息,此处省略不写
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
10.3.2.5 显示效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.3.3 重定向特点

1)重定向是客户端行为
2)重定向是浏览器做了至少两次的访问请求
3)重定向浏览器地址改变
4)重定向两次跳转之间传输的信息会丢失(request范围)
5)重定向可以指向任何的资源,包括当前应用程序中的其它资源、同一个站点上的其它应用程序中的资源、其它站点的资源

10.4 转发和重定向总结

当两个Servlet需要传递数据时,选择forward转发。不建议使用sendRedirect进行传递

10.5 综合案例

完善9.3综合案例需求,登录成功后,显示所有管理员账号信息,登录失败继续回到登录页面

只需要在LoginServlet类中进行重定向和转发实现需求,其余页面不变

package com.cxyzxc.www.servlet;

import com.cxyzxc.www.service.AdminService;
import com.cxyzxc.www.service.impl.AdminServiceImpl;
import com.cxyzxc.www.entity.Admin;

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

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    private final AdminService ADMINSERVICE = new AdminServiceImpl();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        req.setCharacterEncoding("UTF-8");
        //获取数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        Admin admin = ADMINSERVICE.login(username, password);

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

        if (admin != null) {
            //账号和密码正确,显示所有管理员信息
            req.getRequestDispatcher("/ShowAllAdminServlet").forward(req,resp);
        } else {
            //账号或者密码错误,重定向到登录页面
            resp.sendRedirect("/adminProject02_war_exploded/login.html");
        }

    }

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

十一、状态管理

11.1 现有问题

HTTP协议是无状态的,不能保存每次提交的信息

如果用户发来一个新的请求,服务器无法知道它是否与上次的请求有联系

对于那些需要多次提交数据才能完成的Web操作,比如登录来说,就有问题了。

11.2 概念

将浏览器与Web服务器之间多次交互当做一个整体来处理,并且将多次交互所涉及到的数据(即状态)保存下来。

11.3 状态管理分类

客户端状态管理技术:将状态保存在客户端。代表性的是Cookie技术。

服务器状态管理技术:将状态保存在服务器端。代表性的是session技术(服务器传递sessionID时需要使用Cookie的方式)和application

十二、Cookie的使用

12.1 什么是Cookie

Cookie是在浏览器访问Web服务器的某个资源时,由Web服务器在HTTP响应消息头中附带传送给浏览器的一小段数据。

一旦Web浏览器保存了某个Cookie,那么它在以后每次访问该Web服务器时,都应在HTTP请求头中将这个Cookie回传给Web服务器。

一个Cookie主要有标识该信息的名称(name)和值(value)组成。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12.2 创建Cookie

//设置Cookie
 Cookie cookie = new Cookie("username", "zhangsan");

/*
*设置Cookie存活时间,在浏览器内存中的保存时间,单位为秒,
*   正数:将Cookie写入浏览器所在电脑的硬盘,持久化存储。到时间自动删除
*   负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则Cookie被销毁
*   零:删除对应Cookie
*/
cookie.setMaxAge(60);

//设置Cookie的访问路径
cookie.setPath("/webProject05_war_exploded/GetCookieValueServlet01");

//发送Cookie到客户端
response.addCookie(cookie);

12.3 浏览器查看Cookie

12.3.1 浏览器查看Cookie的第一种方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12.3.2 浏览器查看Cookie的第二种方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12.4 获取Cookie

//获取所有Cookie
Cookie[] cookies = request.getCookies();

//遍历数组,获取所有的Cookie
for (Cookie cookie : cookies) {
    System.out.println(cookie.getName() + "-" + cookie.getValue());
}

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

//遍历数组,获取指定的Cookie
for (Cookie cookie : cookies) {
   if (cookie.getName().equals("username")) {
      System.out.println(cookie.getName() + "-" + cookie.getValue());
   }
}

12.5 修改Cookie

只需要保证Cookie的名称和路径一致即可修改

注意:如果改变cookie的name和有效路径,会新建cookie,而改变cookie值、有效期会覆盖原有cookie

 //设置Cookie,如果改变cookie的name和有效路径,会新建cookie,而改变cookie值、有效期会覆盖原有cookie
Cookie cookie = new Cookie("username", "lisi");

/*
*设置Cookie存活时间,在浏览器内存中的保存时间,单位为秒,
*   正数:将Cookie写入浏览器所在电脑的硬盘,持久化存储。到时间自动删除
*   负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则Cookie被销毁
*   零:删除对应Cookie
*/
cookie.setMaxAge(30);

//设置Cookie的访问路径
 cookie.setPath("/webProject09_war_exploded/GetCookieValueServlet01");

//发送Cookie到客户端
response.addCookie(cookie);

12.6 Cookie编码与解码

Cookie默认不支持中文,只能包含ASCII字符,所以Cookie需要对Unicode字符进行编码,否则会出现乱码

  • 编码可以使用java.net.URLEncoder类的encode(String str,String encoding)方法
  • 解码可以使用java.net.URLDecoder类的decode(String str,String encoding)方法

12.6.1 创建带中文Cookie

package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "CookieServlet03", value = "/CookieServlet03")
public class CookieServlet03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //Cookie默认不支持中文,只能包含ASCII字符,所以Cookie需要对Unicode字符进行编码,否则会出现乱码
        Cookie cookie = new Cookie("姓名", "张三");

        //设置Cookie的访问路径
        cookie.setPath("/webProject09_war_exploded/GetCookieValueServlet03");

        //发送Cookie到客户端
        response.addCookie(cookie);
    }

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

12.6.2 读取带中文Cookie

package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "GetCookieValueServlet03", value = "/GetCookieValueServlet03")
public class GetCookieValueServlet03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取所有Cookie
        Cookie[] cookies = request.getCookies();

        //遍历数组,获取所有的Cookie
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName() + "-" + cookie.getValue());
        }

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

        //遍历数组,获取指定的Cookie
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("姓名")) {
                System.out.println(cookie.getName() + "-" + cookie.getValue());
            }
        }

    }

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

12.6.3 获取中文Cookie请求效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12.6.4 解决创建和获取中文Cookie

12.6.4.1 创建中文Cookie
package com.cxyzxc.www.servlet01;

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.URLEncoder;

@WebServlet(name = "CookieServlet04", value = "/CookieServlet04")
public class CookieServlet04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //Cookie默认不支持中文,只能包含ASCII字符,所以Cookie需要对Unicode字符进行编码,否则会出现乱码
        Cookie cookie = new Cookie(URLEncoder.encode("姓名","UTF-8"),URLEncoder.encode("张三","UTF-8"));

        //设置Cookie的访问路径
        cookie.setPath("/webProject09_war_exploded/GetCookieValueServlet04");

        //发送Cookie到客户端
        response.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
12.6.4.2 获取中文Cookie
package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "GetCookieValueServlet04", value = "/GetCookieValueServlet04")
public class GetCookieValueServlet04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取所有Cookie
        Cookie[] cookies = request.getCookies();

        //遍历数组,获取指定的Cookie
        for (Cookie cookie : cookies) {
            if (URLDecoder.decode(cookie.getName(),"UTF-8").equals("姓名")) {
                System.out.println(URLDecoder.decode(cookie.getName(),"UTF-8") + "-" + URLDecoder.decode(cookie.getValue(),"UTF-8"));
            }
        }

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
12.6.4.3 获取中文Cookie请求效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

12.7 Cookie优点和缺点

12.7.1 Cookie优点

  • 可配置到期规则
  • 简单性:Cookie是一种基于文本的轻量结构,包含简单的键值对
  • 数据持久性:Cookie默认在过期之前是可以一直存在客户端浏览器上的

12.7.2 Cookie缺点

  • 大小受到限制:大多数浏览器对Cookie的大小有4K、8K字节的限制
  • 用户配置为禁用:有些用户禁用了浏览器或客户端设备接收Cookie的能力,因此限制了这一功能
  • 潜在的安全风险:Cookie可能会被篡改。会对安全性造成潜在风险或者导致依赖于Cookie的应用程序失败

十三、 Session对象(重要)

13.1 Session概述

(1)Session用于记录用户的状态。Session指的是一段时间内,单个客户端与Web服务器的一连串相关的交互过程。

(2)在一个Session中,客户可能会多次请求访问同一个资源,也有可能请求访问各种不同的服务器资源。

(3)Session是由服务器端创建的

13.2 Session原理

(1)Session会为每一次会话分配一个Session对象

(2)同一个浏览器发起的多次请求,同属于一次会话(Session)

(3)首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId发送回客户端

13.3 Session使用

Session作用域:拥有存储数据的空间,作用范围是一次会话有效

  • 一次会话是使用同一浏览器发送的多次请求。一旦浏览器关闭,则结束会话
  • 可以将数据存入Session中,在一次会话的任意位置进行获取
  • 可传递任何数据(基本数据类型、对象、集合、数组)

13.3.1 获取Session

Session是服务器端自动创建的,通过request对象获取

package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "SessionServlet01", value = "/SessionServlet01")
public class SessionServlet01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象,首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId发送回客户端
        HttpSession session = request.getSession();
        System.out.println("ID:" + session.getId());//唯一标记

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.3.2 Session保存数据

使用setArrtibute(属性名,Object)保存数据到session中

package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "SessionServlet02", value = "/SessionServlet02")
public class SessionServlet02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象,首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId发送回客户端
        HttpSession session = request.getSession();

        //将数据存储以键值对的形式到session对象中,可传递任何数据(基本数据类型、对象、集合、数组)
        session.setAttribute("username","张三");

    }

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

13.3.3 Session获取数据

(1)使用getAttribute(“属性名”);获取session中数据。

(2)先访问SessionServlet02将数据存储到session对象中,然后通过GetSessionValueServlet01请求获取session中的数据

package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "GetSessionValueServlet01", value = "/GetSessionValueServlet01")
public class GetSessionValueServlet01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象
        HttpSession session = request.getSession();
        //获取session对象中的值,获取的值是Object类型,转换为其对应的类型
        String username = (String) session.getAttribute("username");
        System.out.println("session对象中存储的username值:" + username);
    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.3.4 Session移除数据

(1)使用removeAttribute(“属性名”);从session中删除数据

(2)向请求SessionServlet02向session对象中存储数据,然后访问GetSessionValueServlet01可以获取session对象中的值,再访问SessionServlet03移除session对象中存储的数据,最后访问GetSessionValueServlet01获取session对象中的值为null

package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "SessionServlet03", value = "/SessionServlet03")
public class SessionServlet03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象,首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId发送回客户端
        HttpSession session = request.getSession();

        //通过键移除session作用域中的值
        session.removeAttribute("username");

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.4 Session与Request应用区别

(1)request是一次请求有效,请求改变,则request改变

(2)session是一次会话有效,浏览器改变,则session改变

13.4.1 Session和request存储数据

package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "SessionServlet04", value = "/SessionServlet04")
public class SessionServlet04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象
        HttpSession session = request.getSession();

        //使用session存储数据
        session.setAttribute("username","zhangsan");
        //使用request存储数据
        request.setAttribute("password","123456");

        //重定向
        response.sendRedirect("/webProject10_war_exploded/GetSessionValueServlet01");

    }

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

13.4.2 获取session和request中的值

package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "GetSessionValueServlet01", value = "/GetSessionValueServlet01")
public class GetSessionAndRequestValueServlet01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象
        HttpSession session = request.getSession();
        //获取session对象中的值,获取的值是Object类型,转换为其对应的类型
        String username = (String) session.getAttribute("username");
        //获取request对象中的值,获取的值是Object类型,转换为其对应的类型
        String password = (String) request.getAttribute("password");

        System.out.println("session对象中存储的username值:" + username);
        System.out.println("request对象中存储的password值:" + password);
    }

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

13.4.3 session和request区别效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.5 Session的生命周期

  1. 开始

    第一次使用到Session的请求产生,则创建Session

  2. 结束

    • 浏览器关闭,则失效

    • Session超时,则失效

      session.setMaxInactiveInterval(seconds);//设置最大有效时间(单位:秒)

    • 手工销毁,则失效

      session.invalidate();//登录退出,销毁

13.5.1 Session有效时间设置

SessionServlet05类设置session有效期为20秒,先通过请求SessionServlet05类将session存储在,然后在20秒内第一次在GetSessionValueServlet02获取sessionID值,与SessionServlet05类中输出的id值一致,过20秒后在GetSessionValueServlet02类中输出的sessionID值不一致了

package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "SessionServlet05", value = "/SessionServlet05")
public class SessionServlet05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象,首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId发送回客户端
        HttpSession session = request.getSession();

        //设置session有效期,时间单位为秒
        session.setMaxInactiveInterval(20);

        //输出sessionid值
        System.out.println("SessionServlet05类中输出ID:"+session.getId());

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.5.2 session销毁

先使用GetSessionValueServlet03类获取session的id值,然后使用GetSessionValueServlet04类获取session的id值,两个类获取的id值一致,在GetSessionValueServlet04类中输出id值后销毁了session,然后再在GetSessionValueServlet03类中获取id值,就不一致了,就是服务器新建的session对象了

13.5.2.1 GetSessionValueServlet03类
package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "GetSessionValueServlet03", value = "/GetSessionValueServlet03")
public class GetSessionValueServlet03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象
        HttpSession session = request.getSession();

        //输出sessionid值
        System.out.println("GetSessionValueServlet03类中输出ID:"+session.getId());

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
13.5.2.2 GetSessionValueServlet04类
package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "GetSessionValueServlet04", value = "/GetSessionValueServlet04")
public class GetSessionValueServlet04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象
        HttpSession session = request.getSession();

        //输出sessionid值
        System.out.println("GetSessionValueServlet04类中输出ID:"+session.getId());

        //销毁session
        session.invalidate();

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.6 浏览器禁用Cookie解决方案(了解)

13.6.1 浏览器禁用Cookie的后果

服务器在默认情况下,会使用Cookie的方式将sessionID发送给浏览器,如果用户禁止Cookie,则sessionID不会被浏览器保存,此时,服务器可以使用URL重写这样的方式来发送sessionID

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

多次请求GetSessionValueServlet05类输出的session的id值都不相同,并且在网站的Cookie对象中没有session的id值存在

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.6.2 URL重写

浏览器在访问服务器上的某个地址时,不再使用原来的那个地址,而是使用经过改写的地址(即在原来的地址后面加上了sessionID)

13.6.3 实现URL重写

response.encodeRedirectURL(String url)生成重写的URL

13.6.3.1 重写URL
package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "GetSessionValueServlet06", value = "/GetSessionValueServlet06")
public class GetSessionValueServlet06 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象
        HttpSession session = request.getSession();

        //输出sessionid值
        System.out.println("GetSessionValueServlet06类中输出ID:"+session.getId());

        //重写URL追加session值
        String newURL = response.encodeURL("/webProject10_war_exploded/GetSessionValueServlet07");
        System.out.println("重写后的URL:"+newURL);
        //重定向
        response.sendRedirect(newURL);

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
13.6.3.1 获取session
package com.cxyzxc.www.servlet01;

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;

@WebServlet(name = "GetSessionValueServlet07", value = "/GetSessionValueServlet07")
public class GetSessionValueServlet07 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取Session对象
        HttpSession session = request.getSession();

        //输出sessionid值
        System.out.println("GetSessionValueServlet07类中输出ID:"+session.getId());


    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.7 Session实战权限验证

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.7.1 创建管理员表manager并添加数据

#创建表manager
CREATE TABLE IF NOT EXISTS `manager`(
`username` VARCHAR(20) PRIMARY KEY,
`password` VARCHAR(20) NOT NULL
);

# 向manager表中插入数据
INSERT INTO `manager`(`username`,`password`)VALUES('张三',123456);
INSERT INTO `manager`(`username`,`password`)VALUES('李四',123456);

13.7.2 创建Web项目

创建Web项目,导入相关jar包

  • commons-dbutils-1.7.jar
  • druid-1.1.5.jar
  • mysql-connector-java-5.1.25-bin.jar
  • servlet-api.jar

13.7.3 基础环境搭建

在项目下创建包目录结构如下

  • com.cxyzxc.www.controller包:调用业务逻辑Servlet
  • com.cxyzxc.www.dao包:数据访问层接口
  • com.cxyzxc.www.dao.impl包:数据访问层接口实现类
  • com.cxyzxc.www.entity包:实体类
  • com.cxyzxc.www.jsp包:打印显示页面Servlet
  • com.cxyzxc.www.service包:业务逻辑层接口
  • com.cxyzxc.www.service.impl包:业务逻辑层接口实现类
  • com.cxyzxc.www.utils包:工具类
  • database.properties:数据库连接及连接池配置文件

13.7.4 登录页面

13.7.4.1 login.html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>管理员登录页面</title>
        <link type="text/css" rel="stylesheet" href="css/login.css"/>
    </head>

    <body>
        <div>
            <form action="LoginMgrController" method="post">
                <p>
                    账号:<input type="text" name="username"/>
                </p>
                <p>
                    密码:<input type="password" name="password"/>
                </p>
                <p>
                    <input type="submit" value="登录"/>
                </p>
            </form>
        </div>
    </body>
</html>
13.7.4.2 login.css
* {
    margin: 0;
    padding: 0;
}

div {
    width: 400px;
    background-color: #ccc;
    margin: 30px auto;
    padding-top: 30px;
    text-align: center;
}

p {
    margin-top: 10px;
}

input {
    outline: none;
}

13.7.5 LoginMgrController

package com.cxyzxc.www.controller;

import com.cxyzxc.www.entity.Manager;
import com.cxyzxc.www.service.ManagerService;
import com.cxyzxc.www.service.impl.ManagerServiceImpl;

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

@WebServlet(name = "LoginMgrController", value = "/LoginMgrController")
public class LoginMgrController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1、处理乱码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //2、收参(获取客户端发送过来的请求数据)
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //3、调用业务方法
        ManagerService managerService = new ManagerServiceImpl();
        Manager manager = managerService.login(username, password);


        //4、处理结果,根据结果做不同的跳转
        if (manager != null) {//manager不为null,说明账号和密码正确,登录成功
            //将获取的账号和密码信息存储在session中
            HttpSession session = request.getSession();
            session.setAttribute("manager", manager);
            //跳转到显示所有管理员信息的Servlet
            response.sendRedirect("/managerProject01_war_exploded/ShowAllManagerController");
        } else {//manager为null。说明账号或者密码错误,登录失败
            response.sendRedirect("/managerProject01_war_exploded/login.html");
        }


    }

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

13.7.6 ShowAllManagerController

package com.cxyzxc.www.controller;

import com.cxyzxc.www.entity.Manager;
import com.cxyzxc.www.service.ManagerService;
import com.cxyzxc.www.service.impl.ManagerServiceImpl;

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

@WebServlet(name = "ShowAllManagerController", value = "/ShowAllManagerController")
public class ShowAllManagerController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1、处理乱码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //通过HttpSession完成权限控制
        HttpSession session =request.getSession();
        //获取session中存储的值
        Manager manager = (Manager)session.getAttribute("manager");
        //判断获取的值
        if(manager!=null){
            //调用业务,只做业务,业务与显示分离
            ManagerService managerService = new ManagerServiceImpl();
            List<Manager> managers =managerService.showAllManager();
            //将获取的数据存储在request作用域中
            request.setAttribute("managers",managers);
            //转发,跳转到显示结果的Servlet
            request.getRequestDispatcher("/ShowAllManagerJsp").forward(request,response);
        }else{
            //说明没有登录,要先去登录才能进行显示
            response.sendRedirect("/managerProject01_war_exploded/login.html");
        }
    }

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

13.7.7 ShowAllManagerJsp

package com.cxyzxc.www.jsp;

import com.cxyzxc.www.entity.Manager;

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

@WebServlet(name = "ShowAllManagerJsp", value = "/ShowAllManagerJsp")
public class ShowAllManagerJsp extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1、处理乱码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //2、获取数据
        List<Manager> managers = (List<Manager>) request.getAttribute("managers");

        //获取输出流
        PrintWriter printWriter = response.getWriter();
        if (managers.size() != 0) {
            printWriter.println("<html>");
            printWriter.println("<head>");
            printWriter.println("<title>所有管理员</title>");
            printWriter.println("<link type=\"text/css\" rel=\"stylesheet\" href=\"css/table.css\" />");
            printWriter.println("</head>");
            printWriter.println("<table border='1px' cellspacing='0'>");
            printWriter.println("<tr>");
            printWriter.println(" <th>序号</th>");
            printWriter.println(" <th>账号</th>");
            printWriter.println(" <th>密码</th>");
            printWriter.println(" <th>操作</th>");
            printWriter.println(" </tr>");
            for (int i = 0; i < managers.size(); i++) {
                printWriter.println("<tr>");
                printWriter.println("<td>" + (i + 1) + "</td>");
                printWriter.println("<td>" + managers.get(i).getUsername() + "</td>");
                printWriter.println("<td>" + managers.get(i).getPassword() + "</td>");
                printWriter.println("<td><a href=\"#\">修改</a> <a href=\"#\">删除</a></td>");
                printWriter.println("</tr>");
            }
            printWriter.println("</table>");
            printWriter.println("</html>");
        } else {
            printWriter.println("<h2>数据库中没有数据查询</h2>");
        }
    }

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

13.8 Session实战保存验证码

生成验证码的方式有很多种,可以使用随机数的方式实现,也可以使用ValidateCode类来实现(需要导入ValidateCode.jar包)。在这里,我们学习使用ValidateCode类来生成验证码

13.8.1 创建验证码

package com.cxyzxc.www.controller;

import cn.dsna.util.images.ValidateCode;

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

/**
 * 此Servlet的作用是生成验证码并将生成的验证码存储到session中、发送到页面中显示
 */
@WebServlet(name = "VerificationServlet", value = "/VerificationServlet")
public class VerificationServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置验证码规格
        ValidateCode validateCode = new ValidateCode(200, 20, 4, 10);
        //获取验证码
        String code = validateCode.getCode();
        //将验证码存储在session中
        HttpSession session = request.getSession();
        session.setAttribute("code",code);
        //将验证码输出到客户端
        validateCode.write(response.getOutputStream());
    }

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

13.8.2 登录页面

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>管理员登录页面</title>
        <link type="text/css" rel="stylesheet" href="css/login.css"/>
    </head>

    <body>
        <div>
            <form action="LoginMgrController" method="post">
                <p>
                    账号:<input type="text" name="username"/>
                </p>
                <p>
                    密码:<input type="password" name="password"/>
                </p>
                <p>
                    验证码:<input type="text" name="verification"/>
                    <img src="/managerProject02_war_exploded/VerificationServlet" />
                </p>
                <p>
                    <input type="submit" value="登录"/>
                </p>
            </form>
        </div>
    </body>
</html>

13.8.3 LoginMgrController

package com.cxyzxc.www.controller;

import com.cxyzxc.www.entity.Manager;
import com.cxyzxc.www.service.ManagerService;
import com.cxyzxc.www.service.impl.ManagerServiceImpl;

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;

@WebServlet(name = "LoginMgrController", value = "/LoginMgrController")
public class LoginMgrController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1、处理乱码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //2、收参(获取客户端发送过来的请求数据)
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String inputCodde = request.getParameter("verification");

        //获取session中的验证码
        HttpSession session = request.getSession();
        String codes = (String) session.getAttribute("code");

        if (!inputCodde.isEmpty() && inputCodde.equalsIgnoreCase(codes)) {
            //3、调用业务方法
            ManagerService managerService = new ManagerServiceImpl();
            Manager manager = managerService.login(username, password);

            //4、处理结果,根据结果做不同的跳转
            if (manager != null) {//manager不为null,说明账号和密码正确,登录成功
                //将获取的账号和密码信息存储在session中
                HttpSession session2 = request.getSession();
                session2.setAttribute("manager", manager);
                //跳转到显示所有管理员信息的Servlet
                response.sendRedirect("/managerProject02_war_exploded/ShowAllManagerController");
            } else {//manager为null。说明账号或者密码错误,登录失败
                response.sendRedirect("/managerProject02_war_exploded/login.html");
            }
        } else {//验证码不对,重新登录
            response.sendRedirect("/managerProject02_war_exploded/login.html");
        }


    }

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

13.8.4 ShowAllManagerController

package com.cxyzxc.www.controller;

import com.cxyzxc.www.entity.Manager;
import com.cxyzxc.www.service.ManagerService;
import com.cxyzxc.www.service.impl.ManagerServiceImpl;

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

@WebServlet(name = "ShowAllManagerController", value = "/ShowAllManagerController")
public class ShowAllManagerController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //通过HttpSession完成权限控制
        HttpSession session =request.getSession();
        //获取session中存储的值
        Manager manager = (Manager)session.getAttribute("manager");
        //判断获取的值
        if(manager!=null){
            //调用业务,只做业务,业务与显示分离
            ManagerService managerService = new ManagerServiceImpl();
            List<Manager> managers =managerService.showAllManager();
            //将获取的数据存储在request作用域中
            request.setAttribute("managers",managers);
            //转发,跳转到显示结果的Servlet
            request.getRequestDispatcher("/ShowAllManagerJsp").forward(request,response);
        }else{
            //说明没有登录,要先去登录才能进行显示
            response.sendRedirect("/managerProject02_war_exploded/login.html");
        }
    }

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

十四、ServletContext(重要)

14.1 ServletContext概述

(1)全局对象,也拥有作用域,对应一个Tomcat中的Web应用

(2)当Web服务器启动时,会为每一个Web应用程序创建一块共享的存储区域(ServletContext)

(3)ServletContext在Web服务器启动时创建,服务器关闭时销毁

14.2 获取ServletContext对象

  • GenericServlet提供了getServletContext(()方法。推荐使用this.getServletContext();
  • HttpServletRequest提供了getServletContext()方法。推荐使用
  • HttpSession提供了getServletContext()方法。
package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "ServletContextDemo01", value = "/ServletContextDemo01")
public class ServletContextDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取ServletContext对象的三种方式
        //方式一:
        ServletContext servletContext01 = this.getServletContext();
        System.out.println("servletContext01" + servletContext01);

        //方式二:
        ServletContext servletContext02 = request.getServletContext();
        System.out.println("servletContext02" + servletContext02);

        //方式三:
        HttpSession session = request.getSession();
        ServletContext servletContext03 = session.getServletContext();
        System.out.println("servletContext03" + servletContext03);
    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

14.3 ServletContext作用

14.3.1 获取项目真实路径

获取当前项目在服务器发布的真实路径

//获取项目真实路径
String projectRealPath = servletContext.getRealPath("/");
package com.cxyzxc.www.servlet01;

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 javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(name = "ServletContextDemo02", value = "/ServletContextDemo02")
public class ServletContextDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //获取项目真实路径
        String projectRealPath = servletContext.getRealPath("/");
        System.out.println("项目真实路径:" + projectRealPath);

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

14.3.2 获取项目上下文路径

获取当前项目上下文路径(应用程序名称)

//获取项目上下文路径
 String contextPath = servletContext.getContextPath();
package com.cxyzxc.www.servlet01;

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 javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(name = "ServletContextDemo03", value = "/ServletContextDemo03")
public class ServletContextDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //获取项目上下文路径
        String contextPath = servletContext.getContextPath();
        System.out.println("项目上下文路径:"+contextPath);

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

14.3.3 全局容器

ServletContext拥有作用域,可以存储数据到全局容器中。

  • 存储数据:servletContext.setAttribute(“name”,value);
  • 获取数据:servletContext.getAttribute(“name”);
  • 移除数据:servletContext.removeAttribute(“name”);

(1)先在ServletContextDemo04类中存储数据到ServletContext对象中,然后在ServletContextDemo05类中获取ServletContext对象中存储的数据。

package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "ServletContextDemo04", value = "/ServletContextDemo04")
public class ServletContextDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //存储数据
        servletContext.setAttribute("username","张三");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "ServletContextDemo05", value = "/ServletContextDemo05")
public class ServletContextDemo05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //获取数据
        String username = (String) servletContext.getAttribute("username");
        System.out.println("username:" + username);

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(2)先在ServletContextDemo06类中ervletContext对象中的数据,然后在ServletContextDemo05类中获取ServletContext对象中存储的数据。

package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "ServletContextDemo06", value = "/ServletContextDemo06")
public class ServletContextDemo06 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //移除数据
        servletContext.removeAttribute("username");

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

14.4 ServletContext特点

  • 唯一性:一个应用对应一个ServletContext
  • 生命周期:只要容器不关闭或者应用不卸载,ServletContext就一直存在

14.5 ServletContext应用场景

ServletContext统计当前项目访问次数

package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "ServletContextCount", value = "/ServletContextCount")
public class ServletContextCount extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //获取ServletContext
        ServletContext servletContext = request.getServletContext();

        //获取servletContext对象中用于统计网站被访问次数的变量
        Integer count = (Integer) servletContext.getAttribute("count");
        //对count值进行判断,如果count为null。说明servletContext对象中没有数据
        if (count == null) {
            count = 1;
            servletContext.setAttribute("count", count);
        } else {//count不为null,说明servletContext有数据,此时进行+1操作
            count++;
            servletContext.setAttribute("count", count);
        }

        response.getWriter().write("您是本网站的第" + count + "位访问者");

    }

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

14.6 作用域总结

  • HttpServletRequest:一次请求,请求响应之前有效
  • HttpSession:一次会话开始,浏览器不关闭或不超时之前有效
  • ServletContext:服务启动开始,服务器停止之前有效

十五、过滤器(重要)

15.1 现有问题

在之前的Servlet中,存在冗余的代码(相同的代码),多个Servlet都要进行编写。比如处理乱码问题的编码,在每个Servlet中都要写一遍。那么能不能只编写一次,其它的Servlet类就能使用呢?可以借助过滤器来实现。

15.2 概念

过滤器(Filter)是处于客户端与服务器目标资源之间的一道过滤技术。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

15.3 过滤器作用

(1)地位在Servlet之前,客户端发送请求时,会先经过Filter,再到达目标Servlet;响应时,会根据执行流程再次反向执行Filter

(2)可以解决多个Servlet共性代码的冗余问题(例如:乱码处理、登录验证)

15.4 编写过滤器

Servlet API中提供了一个Filter接口,开发人员编写一个Java类实现了这个接口即可,这个Java类称之为过滤器(Filter)

15.4.1 实现过程

(1)编写Java类实现Filter接口

(2)在doFilter()方法中编写拦截逻辑

(3)设置拦截路径

15.4.1.1 Filter代码
package com.cxyzxc.www.filter01;

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

//设置拦截路径:/ServletDemo01  访问/ServletDemo01的时候,会先执行该拦截器
@WebFilter(filterName = "FilterDemo01",value = "/ServletDemo01")
public class FilterDemo01 implements Filter {
    //初始化过滤
    public void init(FilterConfig config) throws ServletException {
        System.out.println("过滤器初始化方法init()开始执行:"+config);
    }

    //销毁过滤
    public void destroy() {
        System.out.println("过滤器销毁方法destroy()执行了......");
    }

    //执行过滤
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        //过滤前
        System.out.println("过滤前......doFilter");

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

        //过滤后
        System.out.println("过滤后......doFilter");

    }
}
15.4.1.2 Servlet代码
package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "ServletDemo01", value = "/ServletDemo01")
public class ServletDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //执行先关代码
        System.out.println("我是ServletDemo01中的代码");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
15.4.1.3 访问效果

在浏览器中请求ServletDemo01,会在执行ServletDemo01请求前先执行Filter拦截器代码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

15.5 过滤器配置

15.5.1 注解配置

在自定义的Filter类上使用注解@WebFilter(value=“/过滤目标资源”)

package com.cxyzxc.www.filter01;

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

//设置拦截路径:/ServletDemo01  访问/ServletDemo01的时候,会先执行该拦截器
@WebFilter(filterName = "FilterDemo01",value = "/ServletDemo01")
public class FilterDemo01 implements Filter {
    //初始化过滤
    public void init(FilterConfig config) throws ServletException {
        System.out.println("过滤器初始化方法init()开始执行:"+config);
    }

    //销毁过滤
    public void destroy() {
        System.out.println("过滤器销毁方法destroy()执行了......");
    }

    //执行过滤
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        //过滤前
        System.out.println("过滤前......doFilter");

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

        //过滤后
        System.out.println("过滤后......doFilter");

    }
}

15.5.2 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>FilterDemo02</filter-name>
        <!-- 过滤器类全称-->
        <filter-class>com.cxyzxc.www.filter01.FilterDemo02</filter-class>
    </filter>

    <!-- 映射路径配置-->
    <filter-mapping>
        <!-- 过滤器名称-->
        <filter-name>FilterDemo02</filter-name>
        <!-- 过滤URL的匹配规则,与Servlet类似-->
        <url-pattern>/ServletDemo02</url-pattern>
    </filter-mapping>
</web-app>

15.5.3 过滤器路径

过滤器的路径通常有三种形式:

精确过滤匹配:比如/index.jsp /myservlet1

后缀过滤匹配:比如*.jsp、.html、.jpg

通配符过滤匹配:/*表示拦截所有。注意过滤器不能使用/匹配,/aaa/bbb/*允许

15.5.3.1 Filter代码
package com.cxyzxc.www.filter01;

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

public class FilterDemo02 implements Filter {
    //初始化过滤
    public void init(FilterConfig config) throws ServletException {
        System.out.println("FilterDemo02过滤器初始化方法init()开始执行:"+config);
    }

    //销毁过滤
    public void destroy() {
        System.out.println("FilterDemo02过滤器销毁方法destroy()执行了......");
    }

    //执行过滤
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        //过滤前
        System.out.println("FilterDemo02过滤前......doFilter");

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

        //过滤后
        System.out.println("FilterDemo02过滤后......doFilter");

    }
}
15.5.3.2 Servlet代码
package com.cxyzxc.www.servlet01;

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

@WebServlet(name = "ServletDemo02", value = "/ServletDemo02")
public class ServletDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

        //执行先关代码
        System.out.println("我是ServletDemo02中的代码");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
15.5.3.3 访问效果

在浏览器中请求ServletDemo02,会在执行ServletDemo02请求前先执行Filter拦截器代码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

15.6 过滤器链和优先级

15.6.1 过滤器链

客户端对服务器请求之后,服务器调用Servlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。

每个过滤器实现某个特定的功能,当第一个Filter的doFilter方法被调用时,Web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter()方法,则Web服务器会检查FilterChain对象中是否还有Filter,如果有,则调用第2个Filter,如果没有,则调用目标资源。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

15.6.2 过滤器优先级

在一个Web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。优先级:

  • 如果为注解的话,是按照类全名称的字母顺序决定作用顺序。
  • 如果为web.xml,按照filter-mapping注册顺序,从上往下
  • web.xml配置高于注解方式
  • 如果注解和web.xml同时配置,会创建多个过滤器对象,造成过滤多次

15.7 过滤器典型应用

15.7.1 过滤器解决编码

编写一个过滤器,该过滤器拦截所有的请求(value=“/*”),过滤器做编码处理

15.7.1.1 Filter类代码
package com.cxyzxc.www.filter01;

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

@WebFilter(filterName = "EncodeFilter", value = "/*")
public class EncodeFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

        //统一处理请求和响应编码
        //设置请求参数的编码格式,这种方式对get请求方式无效
        request.setCharacterEncoding("UTF-8");
        //设置响应编码格式为UTF-8
        response.setContentType("text/html;charset=UTF-8");

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

    }
}
15.7.1.2 Servlet类代码

请求中不再处理乱码

package com.cxyzxc.www.servlet01;

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

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

        //执行先关代码
        response.getWriter().write("<h2>ServletDemo03类中没有处理乱码的代码,但是中文不乱码</h2>");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
15.7.1.3 访问效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

15.7.2 过滤器解决权限验证

15.7.2.1 CheckFilter类
package com.cxyzxc.www.filter;

import com.cxyzxc.www.entity.Manager;

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter(filterName = "CheckFilter",value = "/ShowAllManagerController")
public class CheckFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
        //向下转型
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        //权限验证,验证管理员是否登录
        HttpSession session = request.getSession();
        Manager manager = (Manager)session.getAttribute("manager");
        if(manager!=null){//管理员已经登录,放行
            chain.doFilter(request, response);
        }else{
            //说明没有登录,要先去登录才能进行显示
            response.sendRedirect(request.getServletContext().getContextPath()+"/login.html");
        }
        
    }
}
15.7.2.2 ShowAllManagerController类
package com.cxyzxc.www.controller;

import com.cxyzxc.www.entity.Manager;
import com.cxyzxc.www.service.ManagerService;
import com.cxyzxc.www.service.impl.ManagerServiceImpl;

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

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

            //调用业务,只做业务,业务与显示分离
            ManagerService managerService = new ManagerServiceImpl();
            List<Manager> managers =managerService.showAllManager();
            //将获取的数据存储在request作用域中
            request.setAttribute("managers",managers);
            //转发,跳转到显示结果的Servlet
            request.getRequestDispatcher("/ShowAllManagerJsp").forward(request,response);
    }

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

十六、综合案例(empProject)

16.1 项目说明

使用管理员账号登录系统,实现对员工信息的增删改查

16.2 数据库环境搭建

该案例是empProject员工管理系统。使用了两张表

  • 员工信息表emp
  • 系统管理员表empManager

16.2.1 创建员工信息表emp并添加数据

# 创建表emp
CREATE TABLE IF NOT EXISTS `emp`(
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`salary` DOUBLE NOT NULL,
`age` INT NOT NULL
);

# 向emp表中添加数据
INSERT INTO `emp`(`id`,`name`,`salary`,`age`)VALUES(1001,'张三',5200,26);
INSERT INTO `emp`(`id`,`name`,`salary`,`age`)VALUES(1002,'李四',7200,28);

16.2.2 创建系统管理员表empManager并添加数据

#创建表empManager
CREATE TABLE IF NOT EXISTS `empManager`(
`username` VARCHAR(20) NOT NULL,
`password` VARCHAR(20) NOT NULL
);

# 向empManager表中添加数据
INSERT INTO `empManager`(`username`,`password`)VALUES('如花','123456');
INSERT INTO `empManager`(`username`,`password`)VALUES('似玉','654321');

16.3 创建Web项目

创建Web项目,导入相关jar包

  • commons-dbutils-1.7.jar
  • druid-1.1.5.jar
  • mysql-connector-java-5.1.25-bin.jar
  • ValidateCode.jar

16.4 基础环境搭建

在项目下创建包目录结构如下

  • com.cxyzxc.www.controller包:调用业务逻辑Servlet
  • com.cxyzxc.www.dao包:数据访问层接口
  • com.cxyzxc.www.dao.impl包:数据访问层接口实现类
  • com.cxyzxc.www.entity包:实体类
  • com.cxyzxc.www.filter包:过滤器
  • com.cxyzxc.www.jsp包:打印显示页面Servlet
  • com.cxyzxc.www.service包:业务逻辑层接口
  • com.cxyzxc.www.service.impl包:业务逻辑层接口实现类
  • com.cxyzxc.www.utils包:工具类
  • database.properties:数据库连接及连接池配置文件

16.5 管理员登录功能


16.6 查询所有员工功能

16.6.1 调用业务逻辑Controller


16.6.2 显示页面JSP


16.6.3 权限验证过滤器


16.6.4 字符编码过滤器


16.7 删除员工功能

16.7.1 删除员工Controller


16.8 修改员工功能

16.8.1 查询单个员工Controller


16.8.2 显示修改页面JSP


16.8.3 修改员工信息Controller


vletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter(filterName = “CheckFilter”,value = “/ShowAllManagerController”)
public class CheckFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}

public void destroy() {
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
    //向下转型
    HttpServletRequest request = (HttpServletRequest)servletRequest;
    HttpServletResponse response = (HttpServletResponse)servletResponse;

    //权限验证,验证管理员是否登录
    HttpSession session = request.getSession();
    Manager manager = (Manager)session.getAttribute("manager");
    if(manager!=null){//管理员已经登录,放行
        chain.doFilter(request, response);
    }else{
        //说明没有登录,要先去登录才能进行显示
        response.sendRedirect(request.getServletContext().getContextPath()+"/login.html");
    }
    
}

}


#### 15.7.2.2 ShowAllManagerController类

package com.cxyzxc.www.controller;

import com.cxyzxc.www.entity.Manager;
import com.cxyzxc.www.service.ManagerService;
import com.cxyzxc.www.service.impl.ManagerServiceImpl;

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

@WebServlet(name = “ShowAllManagerController”, value = “/ShowAllManagerController”)
public class ShowAllManagerController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //调用业务,只做业务,业务与显示分离
        ManagerService managerService = new ManagerServiceImpl();
        List<Manager> managers =managerService.showAllManager();
        //将获取的数据存储在request作用域中
        request.setAttribute("managers",managers);
        //转发,跳转到显示结果的Servlet
        request.getRequestDispatcher("/ShowAllManagerJsp").forward(request,response);
}

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

}




# 十六、综合案例(empProject)

## 16.1 项目说明

使用管理员账号登录系统,实现对员工信息的增删改查

## 16.2 数据库环境搭建

该案例是empProject员工管理系统。使用了两张表

- 员工信息表emp
- 系统管理员表empManager

### 16.2.1 创建员工信息表emp并添加数据

创建表emp

CREATE TABLE IF NOT EXISTS emp(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
salary DOUBLE NOT NULL,
age INT NOT NULL
);

向emp表中添加数据

INSERT INTO emp(id,name,salary,age)VALUES(1001,‘张三’,5200,26);
INSERT INTO emp(id,name,salary,age)VALUES(1002,‘李四’,7200,28);


### 16.2.2 创建系统管理员表empManager并添加数据

#创建表empManager
CREATE TABLE IF NOT EXISTS empManager(
username VARCHAR(20) NOT NULL,
password VARCHAR(20) NOT NULL
);

向empManager表中添加数据

INSERT INTO empManager(username,password)VALUES(‘如花’,‘123456’);
INSERT INTO empManager(username,password)VALUES(‘似玉’,‘654321’);


## 16.3 创建Web项目

创建Web项目,导入相关jar包

- commons-dbutils-1.7.jar
- druid-1.1.5.jar
- mysql-connector-java-5.1.25-bin.jar
- ValidateCode.jar

## 16.4 基础环境搭建

在项目下创建包目录结构如下

- com.cxyzxc.www.controller包:调用业务逻辑Servlet
- com.cxyzxc.www.dao包:数据访问层接口
- com.cxyzxc.www.dao.impl包:数据访问层接口实现类
- com.cxyzxc.www.entity包:实体类
- com.cxyzxc.www.filter包:过滤器
- com.cxyzxc.www.jsp包:打印显示页面Servlet
- com.cxyzxc.www.service包:业务逻辑层接口
- com.cxyzxc.www.service.impl包:业务逻辑层接口实现类
- com.cxyzxc.www.utils包:工具类
- database.properties:数据库连接及连接池配置文件

## 16.5 管理员登录功能


## 16.6 查询所有员工功能

### 16.6.1 调用业务逻辑Controller


### 16.6.2 显示页面JSP


### 16.6.3 权限验证过滤器


### 16.6.4 字符编码过滤器


## 16.7 删除员工功能

### 16.7.1 删除员工Controller


## 16.8 修改员工功能

### 16.8.1 查询单个员工Controller


### 16.8.2 显示修改页面JSP


### 16.8.3 修改员工信息Controller




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值