JAVAWEB

本文深入讲解JavaWeb开发的核心技术,包括Servlet、JSP、HTTP协议、Tomcat服务器等内容。介绍了Servlet的工作原理、生命周期及配置方式,JSP的脚本、指令与内置对象,HTTP协议的请求与响应过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

一、 企业开发简介

1、 JavaEE规范

  • JavaEE(Java Enterprise Edition):Java 企业版

  • 它是由 SUN 公司领导、各个厂家共同制定并得到广泛认可的工业标准。

  • JavaEE 早期叫做 J2EE,但是没有继续采用其命名规则。J2EE 的版本从 1.0 开始到 1.4 结束。而 JavaEE 版本是从JavaEE 5 版本开始,目前最新的版本是 JavaEE 8。

  • JavaEE 规范是很多 Java 开发技术的总称。这些技术规范都是沿用自 J2EE 的。一共包括了 13 个技术规范。

  • 包括:JDBC,JNDI,EJB,RMI,IDL/CORBA,JSP,Servlet,XML,JMS,JTA,JTS,JavaMail,JAF。

详情请参考:JavaEE8规范概览

2、 Web概述

(1)WEB 概述

  • WEB 在计算机领域中代表的是网络。

  • 像我们之前所用的 WWW,它是 World Wide Web 三个单词的缩写,称为:万维网。

  • 网络相关技术的出现都是为了:让我们在网络的世界中获取资源,这些资源的存放之处,我们把它叫做网站。

  • 我们通过输入网站的地址(网址),就可以访问网站中提供的资源(不区分局域网或广域网)。

(2)资源分类

① 静态资源

​ 网站中提供给人们展示的资源是一成不变的,也就是说不同人或者在不同时间,看到的内容都是一样的。

​ 作为开发者来说,我们编写的 HTML、CSS、JavaScript 都属于静态资源。

② 动态资源

​ 网站中提供给人们展示的资源是由程序产生的,在不同的时间或不同的人由于身份的不同,所看到的内容是不一样的。

​ 作为开发者来说,我们编写的 JSP、Servlet 等都属于动态资源。

(3)广域网和局域网的划分

关于广域网和局域网的划分,广域网指的就是万维网,也就是我们说的互联网。局域网是指的是在一定范围之内可以访问的网络,出了这个范围,就不能再使用的网络。

3、 系统结构

(1) 系统结构简介

在我们前面课程的学习中,开发的都是Java工程。这些工程在企业中称之为项目或者产品。项目也好,产品也罢,它是有系统架构的,系统架构的划分有很多种方式。我们今天讨论的是基础结构上的划分。除此之外,还有技术选型划分,部署方式划分等等。

基础结构划分:C/S结构,B/S结构两类。

技术选型划分:Model1模型,Model2模型,MVC模型和三层架构+MVC模型。

部署方式划分:一体化架构,垂直拆分架构,分布式架构,流动计算架构,微服务架构。

(2) C/S结构

它指的是客户端——服务器的方式。其中C代表着Client,S代表着服务器。C/S结构的系统设计图如下:

在这里插入图片描述

(3) B/S结构

它指的是浏览器——服务器的方式。其中B代表着Browser,S代表着服务器。B/S结构的系统设计图如下:

在这里插入图片描述

(4) 两种结构的区别及优略

两种结构的区别

第一:硬件环境不同,C/S通常是建立在专用的网络或小范围的网络环境上(即局域网),且必须要安装客户端。而B/S是建立在广域网上的,适应范围强,通常有操作系统和浏览器就行。

第二:C/S结构比B/S结构更安全,因为用户群相对固定,对信息的保护更强。

第三:B/S结构维护升级比较简单,而C/S结构维护升级相对困难。

优点

C/S:对应的优点就是客户端响应速度快(充分发挥客户端PC的处理能力,很多工作可以在客户端处理后再提交给服务器)。

B/S:总体拥有成本低、维护方便、 分布性强、开发简单,可以不用安装任何专门的软件就能 实现在任何地方进行操作,客户端零维护,系统的扩展非常容易,只要有一台能上网的电脑就能使用。

二、 Tomcat

1、 Tomcat介绍

(1) 关于服务器

服务器的概念非常的广泛,它可以指代一台特殊的计算机(相比普通计算机运行更快、负载更高、价格更贵),也可以指代用于部署网站的应用。我们这里说的服务器,其实是web服务器,或者应用服务器。它本质就是一个软件,一个应用。作用就是发布我们的应用(工程),让用户可以通过浏览器访问我们的应用。

常见的应用服务器,请看下表:

服务器名称说明
weblogic实现了javaEE规范,重量级服务器,又称为javaEE容器
websphereAS实现了javaEE规范,重量级服务器。
JBOSSAS实现了JavaEE规范,重量级服务器。免费的。
Tomcat实现了jsp/servlet规范,是一个轻量级服务器,开源免费。

(2) Tomcat下载与安装

Tomcat官网下载地址

(3) Tomcat各版本所需支持

在这里插入图片描述

(4) Tomcat目录结构详解

在这里插入图片描述

(5) webapp项目部署

在这里插入图片描述

2、 Tomcat基本使用

(1) Tomcat启动和停止及问题分析解决

① 启动和停止

Tomcat服务器的启动文件在二进制文件目录中:startup.bat/startup.sh,这两个文件就是Tomcat的启动文件。

Tomcat服务器的停止文件也在二进制文件目录中:shutdown.bat/shutdown.sh,这两个文件就是Tomcat的停止文件。

其中.bat文件是针对windows系统的运行程序,.sh文件是针对linux系统的运行程序。

② 启动问题

第一个问题: 启动一闪而过。

原因:没有配置环境变量。

解决办法:配置上JAVA_HOME环境变量

第二个: Address already in use : JVM_Bind

原因:端口被占用

解决办法:找到占用该端口的应用

​ 方式1: 进程不重要:使用cmd命令:netstat -a -o 查看pid 在任务管理器中结束占用端口的进程。

​ 方式2:进程很重要:修改自己的端口号。修改的是Tomcat目录下\conf\server.xml中的配置。

69	<Connector port="8080" protocol="HTTP/1.1"
70           connectionTimeout="20000"
71           redirectPort="8443" />

第三个:启动产生很多异常,但能正常启动

原因:Tomcat中部署着很多项目,每次启动这些项目都会启动。而这些项目中有启动报异常的。

解决办法:

​ 能找到报异常的项目,就把它从发布目录中移除。

​ 不能确定报异常的项目,就重新解压一个新的Tomcat。

第四个:其它问题

例如:启动产生异常,但是不能正常启动。此时就需要解压一个新的Tomcat启动,来确定是系统问题,还是Tomcat的问题。

所以,此时就需要具体问题,具体分析,然后再对症解决。

第五个:解决控制台乱码

在这里插入图片描述

(2) IDEA集成Tomcat服务器

在这里插入图片描述

(3) Linux系统安装Tomcat

第一步:下载Tomcat。

第二步:上传到linux

在crt上 使用 alt+p
将windows上的软件拖进去即可(root目录)

第三步:在 /usr/local 新建一个文件夹tomcat

mkdir /usr/local/tomcat

第四步:移动 tomcat…tar.gz 到 /usr/local/tomcat

mv apache-tomcat-8.5.32.tar.gz /usr/local/tomcat/

第五步:进入/usr/local/tomcat目录,解压Tomcat

cd /usr/local/tomcat
tar -zxvf apache-tomcat-8.5.32.tar.gz

第六步:进入 /usr/local/tomcat/apache-tomcat-8.5.32/bin

cd /usr/local/tomcat/apache-tomcat-8.5.32/bin

第七步:启动tomcat

方式1:	sh startup.sh
方式2:	./startup.sh

**第八步:修改防火墙的规则 **

方式1:service iptables stop  关闭防火墙(不建议); 用到哪一个端口号就放行哪一个(80,8080,3306...)

方式2:放行8080 端口
	修改配置文件
		cd /etc/sysconfig
		vi iptables
			复制(yy , p)		-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
			改成				-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
		重启加载防火墙或者重启防火墙
			service iptables reload或者service iptables restart

3、 Tomcat发布应用-JavaWeb应用

(1) JavaWeb工程概述

一个web应用由多个静态web资源和动态web资源组成。Web应用开发好后,若想供外界访问,需要把web应用所在目录交给Web服务器管理,这个过程称之为虚似目录的映射。

(2) JavaWeb应用目录结构详解

在这里插入图片描述

(3) JavaWeb应用的创建

在这里插入图片描述

(4) JavaWeb应用的部署

① IDEA部署

在这里插入图片描述

② war包发布

war包:javaweb应用的压缩包(web目录下的所有东西)。

  • 静态资源
  • WEB-INF
    • classes
    • lib
    • web.xml

jar包:java应用的压缩包(classes目录下的压缩包)

第一步:使用jar -cvf war 包的名称 当前目录中哪些资源要打入war

第二步:把打好的war拷贝到tomcat的webapps目录中

第三步:启动服务时,tomcat会自动解压。

在这里插入图片描述

4、Tomcat的配置

(1) Tomcat配置虚拟目录

虚拟目录的配置,可以发布任意目录下的项目。第一种是通过在主配置文件中添加标签实现。第二种是通过写一个独立配置文件实现。

第一种方式:在server.xml<Host>元素中加一个<Context path="" docBase=""/>元素。
path:访问资源URI。URI名称可以随便起,但是必须在前面加上一个/
docBase:资源所在的磁盘物理地址。

在这里插入图片描述

第二种方式:是写一个独立的xml文件,该文件名可以随便起。在文件内写一个<Context/>元素。该文件要放在Tomcat目录中的conf\Catalina\localhost\目录下。需要注意的是,在使用了独立的配置文件之后,访问资源URI就变成了/+文件的名称。而Contextpath属性就失效了。

(2) Tomcat配置虚拟主机

虚拟主机的作用:可以指定访问路径的名称。

编辑server.xml配置文件,在<Engine>元素中添加一个<Host name="" appBase="" unparkWARs="" autoDeploy="" />,其中:
name:指定主机的名称
appBase:当前主机的应用发布目录
unparkWARs:启动时是否自动解压war包
autoDeploy:是否自动发布

配置示例如下:

在这里插入图片描述

(3) Tomcat默认项配置

配置默认端口(主配置文件server.xml)

**8080端口:Tomcat服务默认端口号。访问url地址后必须手动写8080 **

**80端口:HTTP协议采用的端口号。访问URL地址后不用写80 **

配置方式如下:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />		

(4)配置默认主页

首先要明确的是,配置默认主页是针对应用说的。是应用的默认主页。
在应用的web.xml中配置:例如:依次往下找

<welcome-file-list>
    <welcome-file>默认主页</welcome-file>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

三、 HTTP协议

1、 HTTP协议概述

(1) HTTP协议概念

  • HTTP(Hyper Text Transfer Protocol):超文本传输协议。

  • HTTP 协议:通讯两方传输数据的规则,是基于 TCP/IP 协议的。

  • 超文本:比普通文本更加强大。

  • 传输协议:客户端和服务器端的通信规则(握手规则)。

(2) HTTP协议版本

目前HTTP协议主要是1.0版本和1.1版本。这两个版本的区别主要是两个方面。

第一:HTTP1.1版本比1.0版本多了一些消息头。

第二:HTTP1.1版本和1.0版本的执行过程不一样。执行过程如下:

HTTP1.0HTTP1.1
创建连接(TCP/IP)创建连接(TCP/IP)
发送请求发送请求1
得到响应得到响应1
关闭连接发送请求2
创建连接(TCP/IP)得到响应2
发送请求
得到响应
关闭连接连接超时或手动关闭连接

(3) HTTP协议相关说明

HTTP协议概念是客户浏览器和服务器一种一问一答的规则,那么必须要有问有答,而且要先问后答。
但是我们使用<script>,<link><img>标签,没有手动发起请求,但是仍然能从服务器端拿到数据,原因就是:在浏览器遇到<script>,<link>,<img>标签时会自动发出请求。

2、 HTTP协议组成

由HTTP协议的概念可知,它分请求部分和响应部分。

(1)请求部分

请求行: 永远位于请求的第一行。
请求消息头: 从第二行开始,到第一个空行结束。
请求空行
请求的正文: 从第一个空行后开始,到正文的结束。

在这里插入图片描述

(2) 响应部分

响应行: 永远位于响应的第一行
响应消息头: 从第二行开始,到第一个空行结束
响应的正文: 从第一个空行后开始,到正文的结束

在这里插入图片描述

3、 请求部分详解

(1) 请求行详解

请求行:GET /myapp/2.html HTTP/1.1

内容说明
GET请求的方式。(还有POST)
/myapp/2.html请求的资源。
HTTP/1.1使用的协议,及协议的版本。

(2) 请求消息头详解

内容说明
Accept告知服务器,客户浏览器所支持的MIME类型。
Accept-Encoding告知服务器,客户浏览器所支持的压缩编码格式。最常用的就是gzip压缩。
Accept-Language告知服务器,客户浏览器所支持的语言。一般都是zh_CN或en_US等。
Referer告知服务器,当前请求的来源。
只有当前请求有来源的时候,才有这个消息头。从地址栏输入的没有来源。
作用:1 投放广告 2 防盗链
Content-Type告知服务器,请求正文的MIME类型。
Content-Length告知服务器,请求正文的长度。
User-Agent浏览器相关信息
Connection: Keep-Alive连接的状态:保持连接
If-Modified-Since告知服务器,客户浏览器缓存文件的最后修改时间。
Cookie()会话管理相关,非常的重要。

(3) 请求正文详解

第一:只有post请求方式,才有请求的正文。get方式的正文是在地址栏中的。
第二:表单的输入域有name属性的才会被提交。不分get和post的请求方式。
第三:表单的enctype属性取值决定了请求正文的体现形式。概述的含义是:请求正文的MIME编码类型。

enctype取值请求正文体现形式示例
application/x-www-form-urlencodedkey=value&key=valueusername=test&password=1234
multipart/form-data此时变成了多部分表单数据。多部分是靠分隔符分隔的。-----------------------------7df23a16c0210
Content-Disposition: form-data; name="username"

test
-----------------------------7df23a16c0210
Content-Disposition: form-data; name="password"

1234
-----------------------------7df23a16c0210
Content-Disposition: form-data; name=“headfile”; filename="C:\Users\zhy\Desktop\请求部分.jpg"
Content-Type: image/pjpeg
-----------------------------7df23a16c0210

4、 响应部分详解

(1) 响应行详解

响应行:HTTP/1.1 200 OK

内容说明
HTTP/1.1使用协议的版本。
200响应状态码
OK状态码描述

常用状态码介绍:

状态码说明
200一切都OK>
302/307请求重定向(客户端行为,两次请求,地址栏发生改变)
304请求资源未发生变化,使用缓存
404请求资源未找到
500服务器错误

(2) 响应消息头详解

消息头说明
Location请求重定向的地址,常与302,307配合使用。
Server服务器相关信息。
Content-Type告知客户浏览器,响应正文的MIME类型。
Content-Length告知客户浏览器,响应正文的长度。
Content-Encoding告知客户浏览器,响应正文使用的压缩编码格式。常用的gzip压缩。
Content-Language告知客户浏览器,响应正文的语言。zh_CN或en_US等等。
Content-Disposition告知客户浏览器,以下载的方式打开响应正文。
Refresh定时刷新
Last-Modified服务器资源的最后修改时间。
Set-Cookie(*******)会话管理相关,非常的重要
Expires:-1服务器资源到客户浏览器后的缓存时间
Catch-Control: no-catch不要缓存,//针对http协议1.1版本
Pragma:no-catch不要缓存,//针对http协议1.0版本

(3) 响应正文详解

就和我们在浏览器上右键查看源文件看到的内容是一样的。

<html>
    <head>
        <link rel="stylesheet" href="css.css" type="text/css">
        <script type="text/javascript" src="demo.js"></script>
    </head>
    <body>
        <img src="1.jpg" />
    </body>
</html>

四、 Servlet

1、 Servlet概述

Servlet是SUN公司提供的一套规范,名称就叫Servlet规范,它也是JavaEE规范之一。目前在Oracle官网中的最新版本是JavaEE8

javax.servlet通过阅读API,我们得到如下信息:

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

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

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

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

第五:Servlet还支持配置

2、 Servlet入门

(1)Servlet编码步骤

第一步:前期准备-创建JavaWeb工程

第二步:编写一个普通类继承GenericServlet并重写service方法

public class Demo02Servlet_GenericServlet extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse)  {

        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String method = request.getMethod();
        if ("GET".equals(method)){
            //get逻辑
            //doGet(req,resp)

        }else if ("POST".equals(method)){
            //post逻辑
            //doPost(req,resp)
        }
    }
}

第三步:在web.xml配置Servlet

<servlet>
    <servlet-name>demo02</servlet-name>
    <servlet-class>com.itheima.Demo02Servlet_GenericServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>demo02</servlet-name>
    <url-pattern>/demo02</url-pattern>
</servlet-mapping>	

(2)Servlet执行过程分析【面试】

我们通过浏览器发送请求,请求首先到达Tomcat服务器,由服务器解析请求URL,然后在部署的应用列表中找到我们的应用。接下来,在我们的应用中找应用里的web.xml配置文件,在web.xml中找到Demo02Servlet_GenericServlet的配置,找到后执行service方法,最后由Demo02Servlet_GenericServlet响应客户浏览器。

(3)Servlet类视图

通过查阅servlet的类视图,我们看到Servlet接口的实现类GenericServlet还有一个子类HttpServlet。同时,在service方法中还有参数ServletRequest和ServletResponse,它们的关系如下图所示:

在这里插入图片描述

(4)Servlet编写的三种方式

① Servlet三种实现方式说明

第一种:实现 Servlet 接口,实现所有的抽象方法。该方式支持最大程度的自定义。

第二种:继承 GenericServlet 抽象类,必须重写 service 方法,其他方法可选择重写。该方式让我们开发 Servlet 变得简单。但是这种方式和 HTTP 协议无关。

第三种:继承HttpServlet,它是javax.servlet.http包下的一个抽象类,是GenericServlet的子类。如果我们选择继承HttpServlet时,只需要重写doGet和doPost方法,不要覆盖service方法。

此种方式,表示我们的请求和响应需要和HTTP协议相关。也就是说,我们是通过HTTP协议来访问的。那么每次请求和响应都符合HTTP协议的规范。请求的方式就是HTTP协议所支持的方式。

目前我们只知道GET和POST,而实际HTTP协议支持7种请求方式,GET POST PUT DELETE TRACE OPTIONS HEAD 。

② HttpServlet的使用细节

第一步:在入门案例的工程中创建一个Servlet继承HttpServlet 注意:不要重写任何方法

第二步:部署项目并测试访问

当我们在地址栏输入ServletDemo2的访问URL时,出现了访问错误,状态码是405。提示信息是:方法不允许。

第三步:分析原因 得出HttpServlet的使用结论: 我们继承了HttpServlet,需要重写里面的doGet和doPost方法来接收get方式和post方式的请求。为了实现代码的可重用性,我们只需要在doGet或者doPost方法中一个里面提供具体功能即可,而另外的那个方法只需要调用提供了功能的方法。

//servlet3.0以后引入注解配置,此时不需要web.xml配置文件
@WebServlet("/demo03")
public class Demo03Servlet_HttpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  {
        System.out.println("Demo03Servlet_HttpServlet.doGet");
    }

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

(5)注解详解

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

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

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

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

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

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

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

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

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

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

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

3、 Servlet使用细节

(1) Servlet的生命周期

**① 对象的生命周期:**就是对象从生到死的过程,就是对象创建到销毁的过程。

② servlet的声明周期

  • 出生:第一次访问Servlet时,调用init方法,用于初始化资源,该方法被执行一次。
  • 活着:每次执行Servlet时,service方法都会被执行。用于提供服务,该方法被执行多次。
  • 死亡:当服务器停止时,调用destory方法,用于释放资源,只会被执行一次。

③ Servlet单例问题引入?

**结论:**Servlet 对象只会创建一次,销毁一次。所以 Servlet 对象只有一个实例。如果一个对象实例在应用中是唯一的存在,那么我们就称它为单例模式。

(2) Servlet的线程安全

单例:一个Servlet的类,在Tomcat容器中只会存在一个对象。故而我们称Servlet是单例的。

  • 对象的成员变量被多个线程共享。存在线程安全问题。不要在Servlet中定义成员变量!!!
  • 如果要定义,不要修改其值。

演示Servlet的线程安全问题:

//示例需求:模拟网上看书的翻页功能。(类似的有浏览商品的翻页,浏览论坛帖子的翻页)
public class ServletDemo4 extends HttpServlet {
    private int currentPage = 1;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  {
        //1.获取当前要看的书名(此处我们今天先来用以下,明天来着重讲解请求和响应对象)
        String bookName = req.getParameter("bookName");
        //2.输出书名和当前页码
        System.out.println("您看的是:"+bookName+",当前页码是:"+currentPage);
        //3.执行翻页
        currentPage++;
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)  {
        doGet(req,resp);
    }
}
//不同用户共享了页码
您看的是:"笑傲江湖",当前页码是:0
您看的是:"笑傲江湖",当前页码是:1
您看的是:"笑傲江湖",当前页码是:2
您看的是:"笑傲江湖",当前页码是:3
您看的是:"笑傲江湖",当前页码是:4
您看的是:大笑江湖,当前页码是:5

(3) Servlet的注意事项

① 映射方式
  • /访问路径
  • /目录/路径:为了分模块开发
  • *.后缀
② 创建时机
/*
    loadOnStartup:当数值为正整数时,会在服务器启动时创建该Servlet,数值越小优先级越高。
 */
@WebServlet(value = "/demo05",loadOnStartup=1)
③ 默认Servlet

默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat的conf目录下的web.xml中。如下图所示:

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>default</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

它的映射路径是<url-pattern>/<url-pattern>,我们在发送请求时,首先会在我们应用中的web.xml中查找映射配置,找到就执行,这块没有问题。但是当找不到对应的Servlet路径时,就去找默认的Servlet,由默认Servlet处理。所以,一切都是Servlet。

4、 ServletConfig

(1) ServletConfig概述

  • ServletConfig 是 Servlet 的配置参数对象,在 Servlet 的规范中,允许为每一个 Servlet 都提供一些初始化的配置。所以,每个 Servlet 都有一个自己的 ServletConfig。

  • 作用:在 Servlet 的初始化时,把一些配置信息传递给 Servlet。

  • 生命周期:和 Servlet 相同。

(2) ServletConfig的使用

返回值方法名说明
StringgetInitParameter(String name)根据参数名称获取参数的值
EnumerationgetInitParameterNames()获取所有参数名称的枚举
StringgetServletName()获取Servlet的名称
ServletContextgetServletContext()获取ServletContext对象
public class ServletConfig01 extends HttpServlet {
    private ServletConfig config;
    @Override
    public void init(ServletConfig config) throws ServletException {
        //方式一:获取ServletConfig的对象
        this.config=config;
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        //方式二:获取ServletConfig的对象
        //ServletConfig config = super.getServletConfig();
        //org.apache.catalina.core.StandardWrapperFacade@f2a67de
        //System.out.println(getServletConfig());//org.apache.catalina.core.StandardWrapperFacade@f2a67de
        //System.out.println(getServletConfig()==config);//true

        //方法1.获取servlet的名称
        String servletName = config.getServletName();
        System.out.println("servletName:"+servletName);//servletName:ServletConfig01

        //方法2.获取指定参数及其值
        String username = config.getInitParameter("username");
        System.out.println("username:"+username);//username:zhangsan

        //方法3.获取所有参数名称的枚举
        Enumeration<String> params = config.getInitParameterNames();
        while (params.hasMoreElements()){
            String s = params.nextElement();
            System.out.println(s);//encoding   username
        }

        //方法4.获取servletContext对象
        ServletContext servletContext = config.getServletContext();
        System.out.println("servletContext:"+servletContext);
    }

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

<servlet>
    <servlet-name>ServletConfig01</servlet-name>
    <servlet-class>com.itheima.servlet03.ServletConfig01</servlet-class>
    <!--配置初始化参数-->
    <init-param>
        <param-name>username</param-name>
        <param-value>zhangsan</param-value>
    </init-param>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>ServletConfig01</servlet-name>
    <url-pattern>/demo06</url-pattern>
</servlet-mapping>

5、 ServletContext

(1) ServletContext概述

  • ServletContext 是应用上下文对象。每一个应用中只有一个 ServletContext 对象。

  • 作用:可以获得应用的全局初始化参数和达到 Servlet 之间的数据共享。

  • 生命周期:应用一加载则创建,应用被停止则销毁。

域对象

在 Servlet 规范中,一共有 4 个域对象。ServletContext 就是其中的一个。它也是 web 应用中最大的作用域,也叫 application 域。它可以实现整个应用之间的数据共享!

(2) ServletContext的使用

返回值方法名说明
voidsetAttribute(String name,Object value)向域对象中存储数据
ObjectgetAttribute(String name)通过名称获取域对象中的数据
EnumerationgetAttributeNames()获取域对象中所有数据的名称
voidremoveAttribute(String name)通过名称移除域对象中的数据
StringgetServletContextName()获取ServletContext的名称
StringgetContextPath()获取当前应用的访问虚拟目录
StringgetRealPath(String path)根据虚拟目录获取应用部署的磁盘绝对路径
StringgetServerInfo()获取服务器的名称和版本信息
StringgetInitParameter(String name)根据名称获取全局配置的值
EnumerationgetInitParamterNames()获取全局配置的所有名称
① 如何获取
public class ServletContext01 extends HttpServlet {
    private ServletContext servletContext1;
    @Override
    public void init(ServletConfig config) throws ServletException {
        //方式一:获取servletContext对象
        this.servletContext1 = config.getServletContext();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp){
        System.out.println("servletContext1:"+servletContext1);
        //servletContext1:org.apache.catalina.core.ApplicationContextFacade@6b87b2aa

        /*
         * 方式二:Servlet规范的定义中也为我们想到了这一点,所以它在GenericServlet中,
         *      已经为我们声明好了ServletContext获取的方法
         */
        //ServletContext servletContext2 = getServletContext();
        //System.out.println("servletContext2:"+servletContext2);
        ////servletContext3:org.apache.catalina.core.ApplicationContextFacade@6b87b2aa

        //方式三:使用request获取ServletContext
        //ServletContext servletContext3 = req.getServletContext();
        //System.out.println("servletContext3:"+servletContext3);
        //servletContext3:org.apache.catalina.core.ApplicationContextFacade@6b87b2aa


        //方法1.根据名称获取全局配置的参数
        String initParameter = servletContext1.getInitParameter("servletContextInfo");
        System.out.println(initParameter);//This is application scope
        //方法2.获取参数
        Enumeration<String> initParameterNames = servletContext1.getInitParameterNames();
        //方法3.获取当前应用的访问虚拟目录
        String contextPath = servletContext1.getContextPath();
        System.out.println("contextPath:"+contextPath);//contextPath:/day01
        //方法4.根据虚拟目录获取应用部署的磁盘绝对路径
        String realPath = servletContext1.getRealPath(contextPath);
        System.out.println("realPath:"+realPath);
        //realPath:I:\heima_idea1\day03Web\out\artifacts\day01_httpServlet_war_exploded\day01

        //应用1:获取/web目录下的a.txt的绝对路径
        System.out.println("a.txt:"+servletContext1.getRealPath("/a.txt"));
        //应用2:获取/web/WEB-INF目录下的c.txt的绝对路径
        System.out.println("c.txt:"+servletContext1.getRealPath("/WEB-INF/c.txt"));
        //应用3:获取src目录下的b.txt的绝对路径
        System.out.println("b.txt:"+servletContext1.getRealPath("/WEB-INF/classes/b.txt"));
        /**
         * a.txt:I:\heima_idea1\day03Web\out\artifacts\day01_httpServlet_war_exploded\a.txt
         * c.txt:I:\heima_idea1\day03Web\out\artifacts\day01_httpServlet_war_exploded\WEB-INF\c.txt
         * b.txt:I:\heima_idea1\day03Web\out\artifacts\day01_httpServlet_war_exploded\WEB-INF\classes\b.txt
         */

    }

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

配置web.xml

ServletContext既然被称之为应用上下文对象,所以它的配置是针对整个应用的配置,而非某个特定Servlet的配置。它的配置被称为应用的初始化参数配置。

配置的方式,需要在<web-app>标签中使用<context-param>来配置初始化参数。具体代码如下:

    <servlet>
        <servlet-name>ServletContext01</servlet-name>
        <servlet-class>com.itheima.servlet03.ServletContext01</servlet-class>
        <!--配置初始化参数-->
    </servlet>
    <servlet-mapping>
        <servlet-name>ServletContext01</servlet-name>
        <url-pattern>/demo07</url-pattern>
    </servlet-mapping>

    <!--配置应用初始化参数-->
    <context-param>
        <!--用于获取初始化参数的key-->
        <param-name>servletContextInfo</param-name>
        <!--初始化参数的值-->
        <param-value>This is application scope</param-value>
    </context-param>
    <!--每个应用初始化参数都需要用到context-param标签-->
    <context-param>
        <param-name>globalEncoding</param-name>
        <param-value>UTF-8</param-value>
    </context-param>
② ServletContext存值和取值
	@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  {
        
        //获取ServletContext对象
        ServletContext servletContext = getServletContext();
        
        //方法1:存值到ServletContext
        servletContext.setAttribute("username","zhangsan");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        //获取ServletContext对象
        ServletContext servletContext = getServletContext();

        //方法2:从ServletContext中删除值
        //servletContext.removeAttribute("username");

        //方法3:从ServletContext中取值
        String username = (String) servletContext.getAttribute("username");
        System.out.println("username:"+username);//username:zhangsan
    }

6、 Servlet应用案例-学生管理系统

在这里插入图片描述

(1) 案例需求

在昨天的课程讲解中,我们用Tomcat服务器替代了SE阶段的学生管理系统中自己写的服务器。今后我们进入企业肯定也会使用成型的产品,而不会自己去写服务器(除非是专门做应用服务器的公司)。

从今天开始案例正式进入了编码阶段,它是延续了JavaSE阶段课程的学生管理系统。并且分析了SE中系统的各类问题,在JavaWeb阶段学习,就是要通过每天的学习,逐步解决SE阶段学生管理系统中的遗留问题。

今天,我们将会去解决下面这个问题:保存学生。也就是让数据真正的动起来,本质就是通过html发送一个请求,把表单中填写的数据带到服务器端。因为每个使用者在表单填写的内容不一样,所有最终存起来的也就不一样了。

(2)技术选型

这是一个全新的案例,而不是在SE阶段的案例上进行改造。所以我们用项目的方式来去约束这个案例。

任何一个项目,在立项之初都会有技术选型,也就是定义使用的技术集,这里面包含很多。例如:表现层技术,持久层技术,数据库技术等等。

我们今天只针对表现层进行编码,所以就先来定义表现层技术。表现层技术的选型就是Servlet+HTML的组合。

由HTML中编写表单,Servlet中定义接收请求的方法,最终把表单数据输出到控制台即可。我们Servlet的配置方式仍然选择基于web.xml的配置方式。

创建一个 web 项目。
创建一个用于保存学生信息的 html 文件。
创建一个类,继承 HttpServlet。
重写 doGet 和 doPost 方法。
在 web.xml 文件中修改默认主页和配置 Servlet。
在 doGet 方法中接收表单数据保存到文件中,并响应给浏览器结果。
部署并启动项目。
通过浏览器测试。

五、会话技术

1、会话入门

(1)会话

  • 一次会话中包含多次请求和响应。

  • 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止。

在这里插入图片描述

(2)功能

  • 在一次会话的范围内的多次请求间,共享数据。

(3)方式

  • 客户端会话技术:Cookie
  • 服务器端会话技术:Session

2、Cookie

(1)概念

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

(2)快速入门(步骤)

(1) 创建Cookie对象,绑定数据
new Cookie(String name, String value)

(2)发送Cookie对象
response.addCookie(Cookie cookie)

(3)获取Cookie,拿到数据
Cookie[] request.getCookies()

//Servlet1
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.创建Cookie对象
    Cookie c = new Cookie("msg","hello");
    //2.发送Cookie
    response.addCookie(c);
}

//Servlet2
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     //1.获取Cookie
     Cookie[] cookies = request.getCookies();
     //2.遍历cookie
     for (Cookie cookie : cookies) {
         System.out.println(cookie.getName()+":"+cookie.getValue());
         /**
          * 同一个浏览器
          *      msg:hello
          *      Idea-ef96373b:17a23a37-8ccb-4843-a97f-d161a983aca1
          * 不同浏览器
          *      Idea-ef96373b:17a23a37-8ccb-4843-a97f-d161a983aca1
          */
     }
 }

(3)实现原理

**Cookie原理:**它是把要共享的数据保存到了客户端(也就是浏览器端)。每次请求时,把会话信息带到服务器,从而实现多次请求的数据共享。

**作用:**可以保存客户端访问网站的相关内容,从而保证每次访问时先从本地缓存中获取,以此提高效率!

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

在这里插入图片描述

(4)cookie的细节

① 一次可不可以发送多个cookie?
  • 可以,可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.创建Cookie对象
    Cookie c1 = new Cookie("username","zhangsan");
    Cookie c2 = new Cookie("password","123");
    //2.发送Cookie
    response.addCookie(c1);
    response.addCookie(c2);
}

在这里插入图片描述

② cookie在浏览器中保存多长时间?

① 默认情况下,当浏览器关闭后,Cookie数据被销毁
在这里插入图片描述
② 持久化存储:setMaxAge(int seconds)

  • 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效。
  • 负数:默认值
  • :删除cookie信息
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.创建Cookie对象
    Cookie c1 = new Cookie("username","zhangsan");
    //2.设置Cookie的存活时间
    c1.setMaxAge(30);
    //3.发送Cookie
    response.addCookie(c1);
}

在这里插入图片描述

③ cookie能不能存中文?

① 在tomcat 8 之前 cookie中不能直接存储中文数据。需要将中文数据转码—一般采用URL编码(%E3)

② 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析

在这里插入图片描述

④ cookie共享问题?

① 假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?

在这里插入图片描述

默认情况下cookie不能共享

  • setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
  • 如果要共享,则可以将path设置为"/"

在这里插入图片描述


② 不同的tomcat服务器间cookie共享问题?

setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
setDomain(".baidu.com"),那么tieba.baidu.comnews.baidu.com中cookie可以共享

(5)Cookie的特点和作用

① 特点

① cookie存储数据在客户端浏览器。
② 浏览器对于单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)。
在这里插入图片描述

在这里插入图片描述

② 作用

① cookie一般用于存出少量的不太敏感的数据
② 在不登录的情况下,完成服务器对客户端的身份识别

在这里插入图片描述

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

(1)需求

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

(2)分析

① 可以采用Cookie来完成
② 在服务器中的Servlet判断是否有一个名为lastTime的cookie

1. 有:不是第一次访问
	1. 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
	2. 写回Cookie:lastTime=2018年6月10日11:50:01
2. 没有:是第一次访问
	1. 响应数据:您好,欢迎您首次访问
	2. 写回Cookie:lastTime=2018年6月10日11:50:01

在这里插入图片描述

(3)代码实现:

@WebServlet("/cook2")
public class CookieTest2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();

        String lastTime = null;//用来存放第一次的登录信息
        boolean b = true;//是否是第一登录

        //获取请求的Cookie,遍历
        Cookie[] cookies = request.getCookies();
        System.out.println(cookies);
        if (cookies!=null){//火狐和ie浏览器第一次获取的cookie为null
            for (Cookie cookie : cookies) {
                if ("time".equals(cookie.getName())){
                    //不是第一次登录,设置b为false
                    b = false;
                    //获取上次访问时间
                    lastTime = cookie.getValue();
                }
            }
        }
        
        if (lastTime==null/* && cookies!=null && b==true*/){
            out.println("首次登录");
        }else{
            out.println("上次登录:"+lastTime);
        }

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss");
        String thisTime = format.format(new Date());
        Cookie cookie = new Cookie("time",thisTime);
        cookie.setMaxAge(5*60);
        response.addCookie(cookie);
    }

}

3、Session:主菜

(1)概念

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

(2)快速入门

返回值方法名说明
HttpSessiongetSession()获取HttpSession对象
HttpSessiongetSession(boolean create)获取HttpSession对象,未获取到是否自动创建
voidsetAttribute(String name,Object value)设置共享数据
ObjectgetAttribute(String name)获取共享数据
voidremoveAttribute(String name)移除共享数据
StringgetId()获取唯一标识名称
voidInvalidate()让session立即失效(自杀)

(3)原理

Session的实现是依赖于Cookie的。

在这里插入图片描述
在这里插入图片描述

(4)细节

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

​ ① 默认情况下。不是。
​ ② 如果需要相同。则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。

 Cookie c = new Cookie("JSESSIONID",session.getId());
 c.setMaxAge(60*60);
 response.addCookie(c);

(2)客户端不关闭,服务器关闭后,两次获取的session是同一个吗?

​ 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作

  • session的钝化: 在服务器正常关闭之前,将session对象系列化到硬盘上

  • session的活化: 在服务器启动后,将session文件转化为内存中的session对象即可。

(3)不关浏览器,不关服务器,session什么时候被销毁?

① 服务器关闭
② session对象调用invalidate() 。
③ session默认失效时间 30分钟

选择性配置修改
<session-config>
    <session-timeout>30</session-timeout>
</session-config>

(5)session的特点

(1)session用于存储一次会话的多次请求的数据,存在服务器端
(2)session可以存储任意类型,任意大小的数据

(6)session与Cookie的区别

(1)session存储数据在服务器端,Cookie在客户端
(2)session没有数据大小限制,Cookie有
(3)session数据安全,Cookie相对于不安全

4、案例:验证码

(1)案例需求

(1)访问带有验证码的登录页面login.jsp

(2)用户输入用户名,密码以及验证码。

  • 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
  • 如果验证码输入有误,跳转登录页面,提示:验证码错误
  • 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您

(2)分析

在这里插入图片描述

制作验证码

@WebServlet("/responseDemo06")
public class CheckCodeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.创建一对象,在内存中图片(验证码对象)
        int width = 100;
        int height = 50;
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);

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

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

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

        //记录验证码数字
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= 4; i++) {
            int index = ran.nextInt(str.length());
            //获取字符
            char ch = str.charAt(index);//随机字符
            //2.3写验证码
            g.drawString(ch+"",width/5*i,height/2);
            sb.append(ch);
        }
        String checkCode_session = sb.toString();
        request.getSession().setAttribute("checkCode_session",checkCode_session);

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

        //随机生成坐标点
        for (int i = 0; i < 10; i++) {
            int x1 = ran.nextInt(width);
            int x2 = ran.nextInt(width);

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

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

    }

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

登录界面

<head>
    <title>Title</title>
    <script>
        /**
         * 分析:
         *      点击超链接或者图片,需要换一张
         *      1.给超链接和图片绑定单击事件
         *
         *      2.重新设置图片的src属性
         *
         */
        window.onload = function () {
            //获取元素
            var img = document.getElementById("img");
            //绑定响应事件
            img.onclick =fun;
            //响应函数
            function fun(){
                img.src = "/day06/responseDemo06?"+new Date().getTime();
            }
        }
    </script>
</head>
<body>
<form action="/day06/loginServlet" method="post">

    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr><td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td>验证码:</td>
            <td><input type="text"  name="checkCode"></td>
        </tr>
        <tr>
            <td><img src="/day06/responseDemo06" id="img"></td>
        </tr>
        <tr>
            <td><input type="submit" value="登录"></td>
        </tr>

    </table>
</form>
<div  style="color: red"><%=request.getAttribute("cc_error")==null?"":request.getAttribute("cc_error")%></div>
<div  style="color: red"><%=request.getAttribute("login_error")==null?"":request.getAttribute("login_error")%></div>
</body>
</html>

处理登录Servlet

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置request编码格式
        request.setCharacterEncoding("utf-8");
        //2.获取参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String checkCode = request.getParameter("checkCode");

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

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

        //3.先判断验证码是否正确
        if (checkCode_session!=null && checkCode_session.equalsIgnoreCase(checkCode)){
            //或略大小写比较
            //存储提示信息存储到request
            //判断用户名密码是否一致
            if ("zhangsan".equals(username) && "123".equals(password)){
                session.setAttribute("user",username);
                //重定向到success.jsp
                response.sendRedirect(request.getContextPath()+"/success.jsp");

            }else{
                request.setAttribute("login_error","用户名或密码错误");
                //转发到登录页面
                request.getRequestDispatcher("/login.jsp").forward(request,response);
            }
        }else{
            //验证码不一致
            //存储提示信息到request
            request.setAttribute("cc_error","验证码错误");
            //转发到登录页面
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }

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

六、Filter:过滤器

1. 概念

web中的过滤器:在程序中访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源。如果没有则像之前那样直接请求资源了。响应也是类似的!

过滤器的作用:一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤~~~

2. 快速入门

**注意:**Filter 是一个接口。如果想实现过滤器的功能,必须实现该接口!

核心方法

返回值方法名作用
voidinit(FilterConfig config)初始化方法
voiddoFilter(ServletRequest request,ServletResponse response,FilterChain chain)对请求资源和响应资源过滤
voiddestroy()销毁方法

配置方法

  • 注解方式

  • 配置文件

FilterChain介绍

  • FilterChain 是一个接口,代表过滤器链对象。由 Servlet 容器提供实现类对象。直接使用即可。

  • 过滤器可以定义多个,就会组成过滤器链。

  • 核心方法

返回值方法名作用
voiddoFilter(ServletRequest request,ServletResponse response)放行方法

**注意:**如果有多个过滤器,在第一个过滤器中调用下一个过滤器,依次类推。直到到达最终访问资源。如果只有一个过滤器,放行时,就会直接到达最终访问资源。

(1)步骤

① 需求说明

​ 通过 Filter 过滤器解决多个资源写出中文乱码的问题。

② 最终目的

​ 通过本需求,最终掌握 Filter 过滤器的使用。

③ 实现步骤

  • 创建一个 web 项目。

  • 创建 Servlet 功能类,向客户端写出中文数据。

  • 创建一个 Filter 过滤器实现类,重写 doFilter 核心方法。

  • 在方法内解决中文乱码,并放行。

  • 部署并启动项目。

  • 通过浏览器测试。

(2)代码

@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
public class Demo01_setEncoding implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
                         FilterChain filterChain) throws IOException, ServletException {
        //转成HTTPServletResponse(此处不能转,报500)
        //HttpServletResponse response= (HttpServletResponse)servletRequest;
        //设置响应编码格式
        servletResponse.setContentType("text/html;charset=utf-8");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {}
}

(3)过滤器执行流程

​ 执行过滤器放行前的代码----执行资源----回来执行过滤器放行代码下边的代码

3. 过滤器细节

(1) web.xml配置

<!--配置过滤器-->
<filter>
    <filter-name>Demo01_setEncoding</filter-name>
    <filter-class>com.itheima.filter.Demo01_setEncoding</filter-class>
</filter>
<filter-mapping>
    <filter-name>Demo01_setEncoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

(2)过滤器生命周期方法

(1)init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
(2)doFilter:每一次请求被拦截资源时,会执行。执行多次
(3)destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源。

(3)过滤器配置详解

① 拦截路径配置:

  • 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
  • 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
  • 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
  • 拦截所有资源:/* 访问所有资源时,过滤器都会被执行

② 拦截方式配置:资源被访问的方式,设置dispatcherTypes属性

注解配置:
	1. REQUEST:默认值。浏览器直接请求资源
	2. FORWARD:转发访问资源
	3. INCLUDE:包含访问资源
	4. ERROR:错误跳转资源
	5. ASYNC:异步访问资源
web.xml配置:设置<dispatcher></dispatcher>标签即可

(4) 过滤器链(配置多个过滤器)

① 执行顺序:如果有两个过滤器:过滤器1和过滤器2

  • 过滤器1---------过滤器2---------资源执行---------过滤器2---------过滤器1

② 过滤器先后顺序问题:

  • 如果有多个过滤器,取决于过滤器映射的顺序

(5)FilterConfig 介绍

  • FilterConfig 是一个接口。代表过滤器的配置对象,可以加载一些初始化参数。

  • 核心方法

返回值方法名作用
StringgetFilterName()获取过滤器对象名称
StringgetInitParameter(String key)根据key获取value
EnumerationgetInitParameterNames()获取所有参数的key
ServletContextgetServletContext()获取应用上下文对象

(6)过滤器的5中拦截行为

  • Filter 过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调用的全局错误页面。默认情况下过滤器是不参与过滤的,要想使用,就需要我们配置。

  • 拦截方式

<filter>
    <filter-name>filterDemo05</filter-name>
    <filter-class>com.itheima.filter.FilterDemo05</filter-class>
    <!--配置开启异步支持,当dispatcher配置ASYNC时,需要配置此行-->
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>filterDemo05</filter-name>
    <!--<url-pattern>/error.jsp</url-pattern>-->
    <url-pattern>/index.jsp</url-pattern>
    
    <!--过滤请求:默认值。-->
    <dispatcher>REQUEST</dispatcher>
    <!--过滤全局错误页面:当由服务器调用全局错误页面时,过滤器工作-->
    <dispatcher>ERROR</dispatcher>
    <!--过滤请求转发:当请求转发时,过滤器工作。-->
    <dispatcher>FORWARD</dispatcher>
    <!--过滤请求包含:当请求包含时,过滤器工作。它只能过滤动态包含,jsp的include指令是静态包含,过滤器不会起作用-->
    <dispatcher>INCLUDE</dispatcher>
    <!--过滤异步类型,它要求我们在filter标签中配置开启异步支持-->
    <dispatcher>ASYNC</dispatcher>   
</filter-mapping>

<!--配置全局错误页面-->
<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/error.jsp</location>
</error-page>
<error-page>
    <error-code>404</error-code>
    <location>/error.jsp</location>
</error-page>

4. 案例

(1)案例1_登录验证

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

(2)案例2_敏感词汇过滤

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

* 分析:
	1. 对request对象进行增强。增强获取参数相关方法
	2. 放行。传递代理对象


* 增强对象的功能:
	* 设计模式:一些通用的解决固定问题的方式
	1. 装饰模式
	2. 代理模式
		* 概念:
			1. 真实对象:被代理的对象
			2. 代理对象:
			3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
	 	* 实现方式:
		 	1. 静态代理:有一个类文件描述代理模式
		 	2. 动态代理:在内存中形成代理类
				* 实现步骤:
					1. 代理对象和真实对象实现相同的接口
					2. 代理对象 = Proxy.newProxyInstance();
					3. 使用代理对象调用方法。
					4. 增强方法

				* 增强方式:
					1. 增强参数列表
					2. 增强返回值类型
					3. 增强方法体执行逻辑	

七、Listener:监听器

1. 概念:web的三大组件之一。

  • 事件监听机制

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

  • 在程序当中,我们可以对:对象的创建销毁域对象中属性的变化会话相关内容进行监听

  • Servlet 规范中共计 8 个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成。

2. Listener监听对象监听器

(1)ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁

(2)HttpSessionListener:用于监听 HttpSession 对象的创建和销毁

(3)ServletContextListener:用于监听 ServletContext 对象的创建和销毁

返回值方法名作用
voidcontextInitialized(ServletContextEvent sce)对象创建时执行该方法
voidcontextDestroyed(ServletContextEvent sce)对象销毁时执行该方法
voidsessionCreated(HttpSessionEvent se)对象创建时执行该方法
voidsessionDestroyed(HttpSessionEvent se)对象销毁时执行该方法
voidrequestInitialized(ServletRequestEvent sre)对象创建时执行该方法
voidrequestDestroyed(ServletRequestEvent sre)对象销毁时执行该方法
@WebListener
public class MyListenerCreateDestory implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //可以获取servletContext对象
        ServletContext servletContext = servletContextEvent.getServletContext();
        System.out.println(servletContext);
        System.out.println("MyListenerCreateDestory.contextInitialized");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("MyListenerCreateDestory.contextDestroyed");
    }
}
<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">
    <!--配置监听器-->
    <listener>
        <listener-class>com.itheima.listener.MyListenerCreateDestory</listener-class>
    </listener>
</web-app>

3. Listener监听域对象属性变化的监听器


(1)ServletContextAttributeListener:用于监听 ServletContext 应用域中属性的变化

(2)HttpSessionAttributeListener:用于监听 HttpSession 会话域中属性的变化

(3)ServletRequestAttributeListener:用于监听 ServletRequest 请求域中属性的变化

返回值方法名作用
voidattributeAdded(ServletRequestAttributeEvent srae)域中添加属性时执行该方法
voidattributeRemoved(ServletRequestAttributeEvent srae)域中移除属性时执行该方法
voidattributeReplaced(ServletRequestAttributeEvent srae)域中替换属性时执行该方法

参数:ServletRequestAttributeEvent 代表事件对象事件对象中封装了事件源,也就是 ServletRequest真正的事件指的是添加、移除、替换请求域中属性的操作。

@WebListener
public class MyListenerAttribute implements ServletRequestAttributeListener {
    @Override
    public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("MyListenerAttribute.attributeAdded");
    }

    @Override
    public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("MyListenerAttribute.attributeRemoved");
    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
        System.out.println("MyListenerAttribute.attributeReplaced");
    }
}

4. 监听会话相关的感知型监听器

(1)HttpSessionBindingListener:用于感知对象和会话域绑定的监听器

返回值方法名作用
voidvalueBound(HttpSessionBindingEvent event)数据添加到会话域中(绑定)时执行该方法
voidvalueUnbound(HttpSessionBindingEvent event)数据从会话域中移除(解绑)时执行该方法

参数:HttpSessionBindingEvent 代表事件对象事件对象中封装了事件源,也就是 HttpSession真正的事件指的是添加、移除会话域中数据的操作。

(2)HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器

返回值方法名作用
voidsessionWillPassivate(HttpSessionEvent se)会话域中数据钝化时执行该方法
voidsessionDidActivate(HttpSessionEvent se)会话域中数据活化时执行该方法

参数:HttpSessionEvent 代表事件对象事件对象中封装了事件源,也就是 HttpSession真正的事件指的是会话域中数据钝化、活化的操作。

八、JSP入门

概念原理

(1)Java Server Pages: java服务器端页面
(2)可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码。
(3)用于简化书写!!!

原理:JSP本质上就是一个Servlet

在这里插入图片描述
jap转Servlet.java在这个文件查看Using CATALINA_BASE:

"C:\Users\userName\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Tomcat_8_day01_Servlet_5"

1、脚本

(1)JSP局部代码块(JSP小脚本)

特点: 局部代码快中声明的java代码会被原样转译到JSP对应的servlet文件的_jspService方法中,代码块中声明的都是局部变量。(转成方法)
使用: <% java代码 %>
缺点: 使用局部代码块在jsp中进行逻辑判断,书写麻烦,阅读困难。
开发: 使用servlet使用逻辑处理,使用jsp进行页面展现。


(2)JSP全局代码块(JSP声明)

特点: 声明的java代码作为全局代码转译到对应的servlet类中。(转成类)
使用:<%! 全局代码 %>
注意: 全局代码声明的代码,需要使用局部代码块调用。


(3)JSP的脚本段语句(JSP表达式)

特点: 帮助我们快速获取变量或者方法的返回值作为数据响应给浏览器。(转成输出语句)
使用: <%= 变量名或者方法 %>
注意: 不要再变量名或者方法名后面使用分号。


代码演示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>jsp脚本练习</title>
</head>
<body>
<%--1.局部代码块:转成service方法--%>
<%
    System.out.println("Hello JSP");
    System.out.println(str);
    method1();
%>

<%--2.全局代码块:转成类方法或者类变量--%>
<%!
    private String str="你好 JSP";
    public void method1(){
        int i=10;
        System.out.println("i="+i);
    }
%>

<%--3.jsp的脚本段语句:显示在页面,效果和写在外边一样。--%>
<%=str%></br>
<%=request.getMethod()%>

<p>我是HTML段落。</p>

</body>
</html>

2、指令

(1)作用:用于配置JSP页面,导入资源文件
(2)格式:<%@ 指令名称 属性名1=属性值1 属性名2=属性值2 ... %>
(3)分类:

① page指令:配置JSP页面的

属性名作用
contentType响应正文支持的类型和设置编码格式
language使用的语言,默认是java
errorPage当前页面出现异常后跳转的页面
isErrorPage是否抓住异常,如果为true则页面中就可以使用异常对象,默认是false
import导包 import=“java.util.ArrayList”
session是否创建HttpSession对象,默认是true
buffer设定JspWriter输出jsp内容缓存的大小,默认8kb
pageEncoding翻译jsp时所用的编码格式
isElgnored是否忽略EL表达式,默认是false

② include :(几乎不用) 页面包含的。导入页面的资源文件

<%@include file="top.jsp"%>

③ taglib指令:可以引入外部标签库

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%@ taglib uri=标签库的地址 prefix=前缀名称 %>

代码演示

<%--① page指令:配置JSP页面的--%>
<%@ page contentType="text/html;charset=UTF-8" 
        language="java" 
        import="java.util.ArrayList" %><!--使用集合需要导包-->
<%--② 包含的页面内容,在此页面内容之前显示--%>
<%@ include file="top.jsp"%>
<%--③ taglib指令:可以引入外部标签库--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>jsp脚本练习</title>
</head>
<body>
<%--1.局部代码块:转成service方法。--%>
<%
    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");
%>
<%=list.get(0)%>
<p>我是HTML段落。</p>
</body>
</html>

3、注释

(1)html注释: <!-- -->

  • 会被转译,也会被发送,但是不会被浏览器执行。

(2)jsp注释:<%-- --%>:可以注释所有(推荐使用)

  • 不会被转译。

(3)java注释://

  • 会被转译,但是不会被Servlet执行。

4、九大内置对象

(1)内置对象:jsp文件在转译成其对应的servlet文件的时候自动生成的并声明的对象。 我们在jsp页面时间使用即可。
**(2)注意:**内置对象在jsp页面中使用,使用局部代码块或脚本段语句使用,不能够在全局变量中使用。
(3)说明: jsp除全局代码块其他都是service方法体。 全局代码块在九大内置对象声明之前。 所以全局代码块不能使用内置对象。

变量名真实类型作用
pageContextPageContext当前页面共享数据,还可以获取其他八个内置对象
requestHttpServletRequest一次请求访问的多个资源(转发)
sessionHttpSession一次会话的多个请求间
applicationServletContext所有用户间共享数据
responseHttpServletResponse响应对象
pageObject当前页面(Servlet)的对象 this
outJspWriter输出对象,数据输出到页面上,带有缓冲区的响应对象
configServletConfigServlet的配置对象,也就是servletConfig
exceptionThrowable异常对象,存储了当前运行的异常信息。
一共有9个:在jsp页面中不需要创建,直接使用的对象

注意:<%@ page isErrorPage="true"%>使用exception对象需要在page指定中使用属性isErrorPage="true"开启。(默认false)

<%@ page contentType="text/html;charset=UTF-8"
         language="java"
         errorPage="error.jsp" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    
<!--下面三条按顺序执行-->    
我是html标签<br>
<%="我是%="%><br>
<% out.print("我是out.print");%><br>

<%
    //pageContext.forward("demo01_jsp.jsp");
    //pageContext.getRequest().getRequestDispatcher("demo02_page.jsp").forward(request,response);
    System.out.println("我是System.out.println");
    System.out.println(1/0);//测试error.jsp
%>
</body>
</html>

//错误页面error.jsp
<%@ page isErrorPage="true" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>ErrorPage!!!</h1>
</body>
</html>

5、四个作用域对象

作用:数据流转

域对象名称范围级别备注
PageContext页面范围最小,只能在当前页面用因范围太小,开发中用的很少
ServletRequest请求范围一次请求或当前请求转发用请求转发之后,再次转发时请求域丢失
HttpSession会话范围多次请求数据共享时使用多次请求共享数据,但不同的客户端不能共享
ServletContext应用范围最大,整个应用都可以使用尽量少用,如果对数据有修改需要做同步处理

6、 JSP的动作

(1)静态引入<%@include file="要引入的JSP文件的相对路径" %>

特点

​ 静态引入 不是动作 是指令

​ 会将引入的JSP文件和当前JSP文件转译成一个Java文件使用。在网页中也就显示了合并后的显示效果。

注意

​ 静态引入的JSP文件不会单独转译成Java(Servlet)文件。

​ 当前文件和静态引入的文件中不能够使用java代码声明同名变量。和类型无关int a和String a属于同名变量。

(2)动态引入<jsp:include page="要引入的JSP文件的相对路径"></jsp:include>

特点

​ 会将引入的JSP文件单独转译。 在当前文件转译好的java文件中调用引入的JSP文件的转译文件。 在网页中显示合并后的效果。

注意

​ 在当前文件引入其他文件,所以可以声明同名变量。

​ 动态静态选择依据之一:是根据需要同名变量多少。

(3)JSP的转发标签forward:

使用<jsp:forward page="要转发的jsp的相对路径"></jsp:forward>

特点:一次请求,地址栏信息不改变。

注意

​ 在转发标签的两个标签中间除了写<jsp:param value="b" name="username"/>字标签不会报错,其他任意字符都会报错。

<jsp:param value="b" name="username"/>name属性为附带数据的键名,value为附带数据的内容。

注意:会将数据以?的形式拼接在转发路径的后面。可以通过request.getParamter(“key”);获取。

代码演示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--静态引入--%>
<%@include file="top.jsp"%>

<%--动态引入--%>
<jsp:include page="demo01_jsp.jsp"></jsp:include>

<%--请求转发--%>
<jsp:forward page="error.jsp">
    <jsp:param name="username" value="zhangsan"/>
</jsp:forward>

7、 注意

请求一个jsp,真正执行的是他转译好的servlet文件,除全局代码块,其余部分相当于写_jspservice方法体。_jspservice转移过去的代码是从try开始的。 tomcat把request对象作为实参传给servlet,不请求转发request对象作用域就是当前的servlet,结束就销毁request。request作用域是一次请求内所有的servlet。请求转发可以把request对象传过去service一次执行完就会销毁。

九、MVC开发模式

1、jsp演变历史

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

2、MVC

  • M(Model):模型。用于封装数据,封装的是数据模型!

  • V(View):视图。用于显示数据,动态资源用 JSP 页面,静态资源用 HTML 页面!

  • C(Controller):控制器。用于处理请求和响应,例如 Servlet!

在这里插入图片描述

3、优缺点

(1)优点:耦合性低,方便维护,可以利于分工协作;重用性高;

(2)缺点:使得项目架构变得复杂,对开发人员要求高

十、EL表达式

1、 概念

  • Expression Language 表达式语言
  • 在 JSP 2.0 规范中加入的内容,也是 Servlet 规范的一部分。
  • 作用:在 JSP 页面中获取数据。让我们的 JSP 脱离 java 代码块和 JSP 表达式。
  • 书写格式:${表达式内容}

2、 注意

  • JSP默认支持EL表达式的。如果要忽略el表达式

(1)设置jsp中page指令中:isELIgnored="true"
(2)\${表达式内容} :忽略当前这个el表达式

3、使用

(1)运算
算数运算符: + - * / (div) %(mod)
关系运算符:

运算符作用示例结果
== 或 eq等于${5 == 5} 或 ${5 eq 5}true
!= 或 ne不等于${5 != 5} 或 ${5 ne 5}false
< 或 lt小于${3 < 5} 或 ${3 lt 5}true
> 或 gt大于${3 > 5} 或 ${3 gt 5}false
<= 或 le小于等于${3 <= 5} 或 ${3 le 5}true
>= 或 ge大于等于${3 >= 5} 或 ${3 ge 5}false

逻辑运算符:

运算符作用示例结果
&& 或 and并且${A && B} 或 ${A and B}true / false
|| 或 or或者${A || B} 或 ${A or B}true / false
! 或 not取反${ !A } 或 ${ not A }true / false

空运算符: empty

  • 功能:用于判断字符串、集合、数组对象是否为null或者长度是否为0
  • ${empty list}:判断字符串、集合、数组对象是否为null或者长度为0
  • ${not empty str}:表示判断字符串、集合、数组对象是否不为null 并且 长度>0
运算符作用
empty1.判断对象是否为null 2.判断字符串是否为空字符串 3.判断容器元素是否为0
条件 ? 表达式1 : 表达式2三元运算符

(2) 获取值

① EL 表达式能够获取四大域对象的数据,根据名称从小到大在域对象中查找。

② 还可以获取 JSP 其他八个隐式对象,并调用对象中的方法。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    pageContext.setAttribute("username","pageContext");
    request.setAttribute("username","request");
    request.getSession().setAttribute("username","session");
    application.setAttribute("username","application");
%>
<%--原样输出--%>
${"str"}<br>
${123}<br>
${1>2}<br>

<!--
    方式1:域名称.get("键名")
    方式2:域名称.键名
    方式3:直接键名
-->
${pageScope.get("username")}<br>
${requestScope.get("username")}<br>
${sessionScope.username}<br>
${applicationScope.username}<br><!--域名称.键名-->

<%--从小到大查找,找到输出,格式:直接键名--%>
${username}</br><%--找不到显示空串,不会报错--%>
</body>
</html>

(3) 语法:
格式1: ${域名称.键名}:从指定域中获取指定键的值

格式2: ${键名}:表示依次从最小的域中查找是否有该键对应的值,直到找到为止。

格式3: 获取对象、List集合、Map集合的值

对象:${域名称.键名.属性名} 本质上会去调用对象的getter方法	
List集合:${域名称.键名[索引]}
Map集合: 			
(1)${域名称.键名.key名称} 			
(2)${域名称.键名["key名称"]}
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.itheima.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    HashMap<String,Integer> map = new HashMap<>();
    map.put("a",1);
    map.put("b",2);
    map.put("c",3);
    request.setAttribute("map",map);

    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");
    list.add("bbb");
    list.add("ccc");
    request.setAttribute("list",list);

    User user = new User("wuwang",1234);
    request.setAttribute("user",user);
%>
<%--map     格式:作用域.map.key--%>
<%--map     格式:作用域.map["key"]--%>
${requestScope.map.a}
${requestScope.map["b"]}

<%--list    格式:作用域.列表[索引]--%>
${requestScope.list[2]}

<%--Object  格式:作用域.对象.属性名--%>
${requestScope.user.username}
${requestScope.user.age}
</body>
</html>

(4) 隐式对象

EL表达式中有11个隐式对象

隐式对象名称对应JSP隐式对象说明
pageContextpageContext功能完全相同
applicationScope没有操作应用域对象数据
sessionScope没有操作会话域对象数据
requestScope没有操作请求域对象数据
pageScope没有操作页面域对象数据
header没有获取请求头数据
headerValues没有获取请求头数据(多个值)
param没有获取请求参数数据
paramValues没有获取请求参数数据(多个值)
initParam没有获取全局配置参数数据
cookie没有获取Cookie对象

常用格式:获取jsp其他八个内置对象

<%--动态获取虚拟目录:/day04--%>
动态获取虚拟目录:${pageContext.request.contextPath}
<%--200--%>
${pageContext.response.status}

十一、概念

  • JSTL(Java Server Pages Standarded Tag Library):JSP 标准标签库。

  • 主要提供给开发人员一个标准通用的标签库。

  • 作用:开发人员可以利用这些标签取代 JSP 页面上的 Java 代码,从而提高程序的可读性,降低程序的维护难度。

组成作用说明
core核心标签库通用的逻辑处理
fmt国际化不同地域显示不同语言
functionsEL函数EL表达式可以使用的方法
sql操作数据库了解
xml操作XML了解

2、 使用步骤

(1)导入jstl相关jar包
(2)引入标签库:taglib指令: <%@ taglib %>
(3)使用标签

3、 常用的JSTL标签

标签名称功能分类属性作用
<标签名:if>流程控制核心标签库用于条件判断
<标签名:choose> <标签名:when> <标签名:otherwise>流程控制核心标签库用于多条件判断
<标签名:forEach>迭代遍历核心标签库用于循环遍历

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

​ ① test 必须属性,接受boolean表达式

​ 如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容

​ 一般情况下,test属性值会结合el表达式一起使用

​ ② 注意:c:if标签没有else情况,想要else情况,则可以在定义一个c:if标签

(2) choose:相当于java代码的switch语句

​ ① 使用choose标签声明 相当于switch声明
​ ② 使用when标签做判断 相当于case
​ ③ 使用otherwise标签做其他情况的声明 相当于default

(3) foreach:相当于java代码的for语句

4、使用

  1. 创建一个 web 项目。
  2. 在 web 目录下创建一个 WEB-INF 目录。
  3. 在 WEB-INF 目录下创建一个 libs 目录,将 JSTL 的 jar 包导入。
  4. 创建 JSP 文件,通过 taglib 导入 JSTL 标签库。
  5. 对流程控制和迭代遍历的标签进行使用。
  6. 部署并启动项目。
  7. 通过浏览器查看。

(1)jstl的选择标签

 <%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8" import="java.util.*"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%--
 	JSTL学习
 		作用:
 			提高在jsp中的逻辑代码编写,使用标签。
 		使用:
 			JSTL的核心标签库(重点)
 			JSTL的格式化标签库(讲解)
 			JSTL的SQL标签库(了解)
 			JSTL的函数标签库(了解)
 			JSTL的XML标签库(了解)
		JSTL的核心 标签库:
			1、导入jar包
			2、声明jstl标签库的引入(核心标签库)
				<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
			3、内容:
				基本标签:(1)cout:标签(2)c:set标签(3)c:remove标签
				逻辑标签:(1)c:if标签(2)c:choose----c:when---c:otherwise
  --%>

<!--基本标签-->
<!-- 
	基本标签:
		<c:out value="数据" default="默认值"></c:out>
			数据可以为常量也可以是EL表达式。
			作用:将数据输出给客户端。
		<c:set var="hello" value="hello.*"></c:set>	
			作用:存储数据到作用域对象中
			var:表示存储的键名
			value:表示存储的数据
			Scope:表示要存储的作用域对象page/application/session/request
		<c:remove var="hello" scope="request"/><br>
			作用:删除作用域中的指定键的数据。
			var:表示要删除的键的名字。
			scope:表示要删除的作用域(可选)
			注意:
				如果在不指定作用域的情况使用该标签删除数据,会将四个作用域对象中的符合要求的数据全删。
 -->
<%
	request.setAttribute("str1", "今天天气真哈!");
%>
(1)cout:标签
<c:out value="哈哈"></c:out>
-----哈哈------<%="哈哈" %></br>
<c:out value="${str1}"></c:out>
</br>
<c:out value="${str2}" default="我是str2"></c:out>
<hr>

(2)c:set标签
<c:set var="hello" value="hello.*"></c:set>
<!-- 默认存储在pageContext -->
<c:set var="hello" value="hello request" scope="request"></c:set>
<c:set var="hello" value="hello pageContext" scope="page"></c:set>
<c:set var="hello" value="hello session" scope="session"></c:set>
<c:set var="hello" value="hello application" scope="application"></c:set>

<c:out value="${hello} "></c:out>
<br>
<!-- 默认取pageContext -->
requ:------
<c:out value="${requestScope.hello}"></c:out>
<br>
sess:------
<c:out value="${sessionScope.hello}"></c:out>
<br>
page:------
<c:out value="${pageScope.hello}"></c:out>
<br>
appl:------
<c:out value="${applicationScope.hello}"></c:out>
<hr>

(3)c:remove标签
<c:remove var="hello" scope="request" />
<br>
remove1:----
<c:out value="${hello}"></c:out>
<br>
<!-- ------------------------------------------------------------------------------------- -->


<!-- 传统方式分支结构(逻辑标签): -->
<%-- 
	逻辑标签:
	  (1)<c:if test="${表达式}">
			前端代码(html)
		</c:if>
			作用:进行逻辑判断,相当于Java代码的单分支判断。
			注意:
				逻辑判断标签需要依赖于EL逻辑运算,
				表达式:涉及到的数据必须从作用域中获取。
	  (2)<c:choose>
			<c:when test="">执行内容</when>
			<c:when test="">执行内容</when>
			...
			<c:otherwise>执行内容</otherwise>
		</c:choose>
			作用:用来进行多条件的逻辑判断,类似Java多分枝语句
			注意:
				条件成立只会执行一次,都不成立则执行otherwise
				表达式:涉及到的数据必须从作用域中获取。
--%>

<!-- 传统方式if -->
<%
		int a=4;
		if(a>3){%>
<b>今天天气真不错!</b>
<br>
<%}
	%>

<!-- JSTL方式: -->

(1)if标签
<c:set var="a" value="4"></c:set>
<c:if test="${a>3}">
	<b>今天天气真的很热哦!</b>
</c:if>
<hr>

(2)choose(when,otherwise)标签
<c:set var="score" value="65"></c:set>
<c:choose>
	<c:when test="${score>90}">
		<b>奖励吃鸡装备一套。</b>
	</c:when>
	<c:when test="${score>80&&score<90}">
		<b>良好</b>
	</c:when>
	<c:when test="${score>60}">
		<b>及格</b>
	</c:when>
	<c:otherwise>不及格</c:otherwise>
</c:choose>
<hr>

(2)jstl的循环标签

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

<!----------------------------------------------------------------------------------------->
<!--  
	jstl的循环标签:
		<c:forEach begin="1" end="4" step="2">
			循环体
		</c:forEach>		
		作用:
			循环内容进行处理
		使用:
			begin:声明循环开始位置
			end:声明循环结束位置
			step:设置步长。
			varStatus:声明变量记录每次循环的数据(角标,次数,是否第一次循环,是否最后一次循环)
				注意:数据存储在作用域中,需要EL表达式获取
				例如:循环角标:${vs.index}
			items:声明要遍历的对象。结合EL表达式获取其对象。
			var:声明变量记录每次循环的结果。存储在作用域中需要使用EL表达式获取。
 -->
<!-- 传统方式循环 -->
<table border="1px">
	<tr>
		<td>课程名称</td>
		<td>教师</td>
		<td>价格</td>
	</tr>
	<%
		for(int i=0;i<3;i++){
			if(i==2){
	%>
	<tr>
		<td>python</td>
		<td>嵩天</td>
		<td>免费</td>
	</tr>
	<%}} %>
</table>
<!-- JSTL标签循环 -->
<%
	ArrayList<String> list= new ArrayList<String>();
	list.add("a");
	list.add("b");
	list.add("c");
	request.setAttribute("list", list);
	HashMap<String,String> map = new HashMap<String,String>();
	map.put("a1", "哈哈哈");
	map.put("b1", "嘿嘿");
	request.setAttribute("map", map);
	
	
%>
<!-- 使用jstl方式完成循环 -->

<!-- 常量循环 -->
<c:forEach begin="0" end="4" step="1" varStatus="vs">
			111---${vs.index}---${vs.count}---${vs.first}---${vs.last}<br>
</c:forEach>

<!-- 动态循环 -->
<!-- items获取对象存储在作用域对象中,var从作用于对象中取 -->
<c:forEach items="${list}" var="str">
			${str}</br>
</c:forEach>
<!-- 创建表格数据 -->
<h3>创建表格数据</h3>
<table border="1px">
	<tr>
		<td>课程名称</td>
		<td>教师</td>
		<td>价格</td>
	</tr>
	<c:forEach items="${list}" var="s">
		<tr>
			<td>${s}</td>
			<td>${s}</td>
			<td>${s}</td>
		</tr>
	</c:forEach>
</table>
<!-- 遍历map集合 -->
<c:forEach items="${map}" var="m">
	${m.key}--${m.value}<br>
</c:forEach>
<hr>
<hr>
<!-- ------------------------------------------------------------ -->
<!-- c:forTokens标签 -->
<%--
		c:forTokens标签(相当于str.split()的作用)
			<c:forTokens items="${str}" delims="," var="s" begin="1">
			作用:改标签用于在字符串中的令牌上迭代。
			使用:
				items:是一个作用域中的String对象。
				delims:是用来指定分隔符。
				var:声明变量记录每次循环的结果,存储在作用域中用EL表达式获取。
				
				begin:声明循环开始位置,0开始。
				end:声明循环结束位置
				step:设置步长。
	 --%>

<c:set var="str" value="song,qiang"></c:set>
c:fortokens:
<c:forTokens items="${str}" delims="," var="s" begin="1">
	---${s}
</c:forTokens>


5、练习需求

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

十二、案例(用户信息列表展示)

  1. 需求:用户信息的增删改查操作
  2. 设计:
    (1)技术选型:Servlet+JSP+MySQL+JDBCTempleat+Duird+BeanUtilS+tomcat
    (2)数据库设计:
create database day17; -- 创建数据库
use day17; 			   -- 使用数据库
create table user(   -- 创建表
	id int primary key auto_increment,
	name varchar(20) not null,
	gender varchar(5),
	age int,
	address varchar(32),
	qq	varchar(20),
	email varchar(50)
);
  1. 开发:
    (1)环境搭建
    (2)创建数据库环境
    (3)创建项目,导入需要的jar包
    (4)编码
  2. 测试
  3. 部署运维
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值