文章目录
一、 企业开发简介
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下载与安装
(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就变成了/+文件的名称。而Context
的path
属性就失效了。
(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.0 | HTTP1.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-urlencoded | key=value&key=value | username=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的使用
返回值 | 方法名 | 说明 |
---|---|---|
String | getInitParameter(String name) | 根据参数名称获取参数的值 |
Enumeration | getInitParameterNames() | 获取所有参数名称的枚举 |
String | getServletName() | 获取Servlet的名称 |
ServletContext | getServletContext() | 获取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的使用
返回值 | 方法名 | 说明 |
---|---|---|
void | setAttribute(String name,Object value) | 向域对象中存储数据 |
Object | getAttribute(String name) | 通过名称获取域对象中的数据 |
Enumeration | getAttributeNames() | 获取域对象中所有数据的名称 |
void | removeAttribute(String name) | 通过名称移除域对象中的数据 |
String | getServletContextName() | 获取ServletContext的名称 |
String | getContextPath() | 获取当前应用的访问虚拟目录 |
String | getRealPath(String path) | 根据虚拟目录获取应用部署的磁盘绝对路径 |
String | getServerInfo() | 获取服务器的名称和版本信息 |
String | getInitParameter(String name) | 根据名称获取全局配置的值 |
Enumeration | getInitParamterNames() | 获取全局配置的所有名称 |
① 如何获取
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.com
和news.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)快速入门
返回值 | 方法名 | 说明 |
---|---|---|
HttpSession | getSession() | 获取HttpSession对象 |
HttpSession | getSession(boolean create) | 获取HttpSession对象,未获取到是否自动创建 |
void | setAttribute(String name,Object value) | 设置共享数据 |
Object | getAttribute(String name) | 获取共享数据 |
void | removeAttribute(String name) | 移除共享数据 |
String | getId() | 获取唯一标识名称 |
void | Invalidate() | 让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 是一个接口。如果想实现过滤器的功能,必须实现该接口!
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | init(FilterConfig config) | 初始化方法 |
void | doFilter(ServletRequest request,ServletResponse response,FilterChain chain) | 对请求资源和响应资源过滤 |
void | destroy() | 销毁方法 |
配置方法
-
注解方式
-
配置文件
FilterChain介绍
-
FilterChain 是一个接口,代表过滤器链对象。由 Servlet 容器提供实现类对象。直接使用即可。
-
过滤器可以定义多个,就会组成过滤器链。
-
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | doFilter(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 是一个接口。代表过滤器的配置对象,可以加载一些初始化参数。
-
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
String | getFilterName() | 获取过滤器对象名称 |
String | getInitParameter(String key) | 根据key获取value |
Enumeration | getInitParameterNames() | 获取所有参数的key |
ServletContext | getServletContext() | 获取应用上下文对象 |
(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 对象的创建和销毁
返回值 | 方法名 | 作用 |
---|---|---|
void | contextInitialized(ServletContextEvent sce) | 对象创建时执行该方法 |
void | contextDestroyed(ServletContextEvent sce) | 对象销毁时执行该方法 |
void | sessionCreated(HttpSessionEvent se) | 对象创建时执行该方法 |
void | sessionDestroyed(HttpSessionEvent se) | 对象销毁时执行该方法 |
void | requestInitialized(ServletRequestEvent sre) | 对象创建时执行该方法 |
void | requestDestroyed(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 请求域中属性的变化
返回值 | 方法名 | 作用 |
---|---|---|
void | attributeAdded(ServletRequestAttributeEvent srae) | 域中添加属性时执行该方法 |
void | attributeRemoved(ServletRequestAttributeEvent srae) | 域中移除属性时执行该方法 |
void | attributeReplaced(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:用于感知对象和会话域绑定的监听器
返回值 | 方法名 | 作用 |
---|---|---|
void | valueBound(HttpSessionBindingEvent event) | 数据添加到会话域中(绑定)时执行该方法 |
void | valueUnbound(HttpSessionBindingEvent event) | 数据从会话域中移除(解绑)时执行该方法 |
参数:HttpSessionBindingEvent 代表事件对象事件对象中封装了事件源,也就是 HttpSession真正的事件指的是添加、移除会话域中数据的操作。
(2)HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器
返回值 | 方法名 | 作用 |
---|---|---|
void | sessionWillPassivate(HttpSessionEvent se) | 会话域中数据钝化时执行该方法 |
void | sessionDidActivate(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方法体。 全局代码块在九大内置对象声明之前。 所以全局代码块不能使用内置对象。
变量名 | 真实类型 | 作用 |
---|---|---|
pageContext | PageContext | 当前页面共享数据,还可以获取其他八个内置对象 |
request | HttpServletRequest | 一次请求访问的多个资源(转发) |
session | HttpSession | 一次会话的多个请求间 |
application | ServletContext | 所有用户间共享数据 |
response | HttpServletResponse | 响应对象 |
page | Object | 当前页面(Servlet)的对象 this |
out | JspWriter | 输出对象,数据输出到页面上,带有缓冲区的响应对象 |
config | ServletConfig | Servlet的配置对象,也就是servletConfig |
exception | Throwable | 异常对象,存储了当前运行的异常信息。 |
一共有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
运算符 | 作用 |
---|---|
empty | 1.判断对象是否为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隐式对象 | 说明 |
---|---|---|
pageContext | pageContext | 功能完全相同 |
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 | 国际化 | 不同地域显示不同语言 |
functions | EL函数 | 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、使用
- 创建一个 web 项目。
- 在 web 目录下创建一个 WEB-INF 目录。
- 在 WEB-INF 目录下创建一个 libs 目录,将 JSTL 的 jar 包导入。
- 创建 JSP 文件,通过 taglib 导入 JSTL 标签库。
- 对流程控制和迭代遍历的标签进行使用。
- 部署并启动项目。
- 通过浏览器查看。
(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)技术选型: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)环境搭建
(2)创建数据库环境
(3)创建项目,导入需要的jar包
(4)编码 - 测试
- 部署运维