Servlet
1、什么是Servlet
是sun公司制定的一种用来扩展web服务器功能的组建规范。 扩展web服务器功能: web服务器(比如apache,iis等)只能够处理静态资源的请求,(即,需要事先将html、图片等资源准备好,并且存放到web服务器上),不能够处理动态资源的请求(需要通过计算,生成相应的htmL),所以需要扩展其功能。可以使用servlet来扩展web服务器的功能。当请求到达web服务器,如果需要计算,则web服务器调用servlet来处理。 什么是组件:符合一定规范,实现部分功能,需要部署到相应的容器里面才能运行的软件模块。 servlet就是一个符合servlet规范的组件,需要部署到servlet容器里面才能运行。 servlet只需要关注业务逻辑,servlet容器会提供运行环境(包括网络相关的服务)。 什么是容器:符合一定规范,为组件提供运行环境的一种程序。如:Tomacat,就是一个servlet容器
2、如何写一个servlet
*Step1:写一个java类,实现Servlet接口或者继承HttpServlet类
(HttpServlet类实现了Servlet接口中的部分方法
)
*Step2:编译
(使用javac命令将
.java文件编译成
.class文件
)
*Step3:打包
注:建立一个具有如下结构的文件夹
(tomcat
/webapps
/examples
)
webapps
WEB
-INFO
classes
(放
.class文件
)
lib
(放
.jar文件,该文件可选
)
web
.xml
(部署描述文件
)
*Step4:将step3创建好的整个文件夹拷贝到servlet容器指定的位置
(可以将整个文件夹使用jar命令压缩成
.war 后缀的文件
)
*Step5:启动容器,访问servlet。
http
://ip
:port
/appname
/url
-pattern
(url
-pattern是一个字符串,在web
.xml中设置
)
3、安装并且配置Tomcat (www.apache.org)
下载压缩包,解压即可。 配置教程:https://www.cnblogs.com/dgj15222301178/p/7834815.html.
4、servlet是怎么运行的
比如输入:http://localhost:8080/dayo1/hello
step1:浏览器依据 ip 和port 建立连接。
step2:浏览器将相关数据添加到请求数据包里面,然后发送给服务器。
step3:服务器会解析请求数据包中的数据,并且将这些数据添加到request对象里面,同时,还会创建一个response对象。
注意: 开发人员可以通过request对象获得请求数据包中的数据,比如获得请求参数值。可以将处理结果写到response对象里面,容器会从response对象中获取处理结果,然后创建响应数据包并发送给浏览器。
step4:服务器创建servlet对象(实例化),然后调用该对象的service方法。
注意: 容器会将request对象和response对象作为参数传递过service方法。
step5:服务器从response对象中获取处理结果,然后创建响应数据包并发送给浏览器。
step6:浏览器解析响应数据包,依据解析到的数据生成相应的页面。
5、常见错误
404
404是一个状态码,表示服务器一依据请求路径找不到对应的资源
原因:请求路径写错
格式:http
://ip
:port
/appname
/url
-pattern
应用没有部署或者部署失败
500
500是一个状态码,表示服务器运行出错。
原因:代码没有严格遵守servlet规范
比如:没有实现servlet接口或者继承HttpServlet类。
web
.xml文件中将servlet
-class写错或者servlet
-name不一致
代码不严谨
比如:对请求参数没有做检查就做类型转换
405:
405是服务器找不到处理方法
service方法没有按照正确的格式来书写,即没有正确override HttpServlet的service方法
http协议
(1)什么是http协议
网络应用层协议,规定了浏览器与web服务器之间如何通信以及相应的数据包的格式。 注: TCP/IP 属于网络层和传输层协议,负责将数据可靠地从一台机器传递到另外一台机器。 Http 属于应用层协议,将数据打包之后会将数据包交给tcp/ip来传递这些数据包。 (1) 浏览器与web服务器之间是如何通信 step1:建立连接。 step2:发送请求。 step3:发送响应。 step4:关闭连接。 如果浏览器要发送新的请求,需要重新建立新的连接,即“一次请求一次连接。”这样做的好处是服务器可以利用有限的连接尽可能完成多的请求服务。 ==(2)==数据包的结构 请求数据包: 请求行->请求方式 请求资源路径 通信协议 消息头->键值对 使用“: ”隔开,通信双方可以利用消息头发送一些特定的消息。比如浏览器可以通过发送user-agent消息头来告诉服务器,浏览器的类型和版本号。 实体内容->消息正文 响应数据包: 状态行->协议和版本 状态码 状态描述 注:状态码是一个三位数字,表示服务器处理请求的一种状态。 消息头-> 注:服务器可以发送一些消息头给浏览器,比如:发送Content-Type消息头,告诉浏览器服务器返回的数据类型和编码方式。 实体类容-> 注:程序处理的结果,浏览器会解析出来,生成相应的页面.
(2)两种请求方式
*GET请求
:
哪些情况下,浏览器会发送get请求:
在浏览器地址栏输入某个地址
表单默认的提交方式
点击链接(超链接)
特点
:
会将请求参数显示在浏览器地址栏,不安全
注:某些网络设备会记录请求地址;会将请求参数添加到请求资源路径的后面,只能提交少量的数据给服务器。
注:请求行大约只能存放
2k左右的数据
*POST请求
:
哪些情况下,浏览器会发送post请求:
将表单的method属性设置为post。
特点:
不会将请求参数显示在地址栏,相对安全一些。
注:http协议并不会对数据包中数据进行加密,所以,对于敏感数据,一定要加密。
会将请求参数添加到实体内容里面,可以提交大量的数据给服务器。
(3)Servlet输出中文,如何处理乱码问题?
xxx
.println()方法默认会使用ISO
-8859-1这个字符集来编码。如果是中文,则会发生编码错误,产生乱码问题。
解决方法:
response
.setContentType("text/html;charset=UTF-8");
读取请求参数值
1、String weight
= request
.getParameter("weight").trim();
注:如果请求参数名与实际传递过来的请求参数名不一致,则会获得null值
2、String
[] line
= request
.getParameterValues(String paramName
);
注:有多个请求参数名相同时,使用此方法。对于多选框,如果没有选择任何选项,会获得null值,
处理流程中容易出现空指针异常。
处理空指针异常:
if(line
!=null
){
for (String value
: line
) {
System
.out
.println(value
);
}
}
表单包含有中文参数值,如何处理乱码问题
?
1、为什么会有乱码
表单提交时,浏览器会对中文参数值进行编码
(比如,使用utf
-8来编码
), 服务器端默认会使用ISO
-8859-1来解码,所以,会产生乱码。
注:
浏览器会使用打开该表单所在的页面时的字符集来进行编码
<!--
模拟Content
-Type消息头
相当于浏览器收到了一个Content
-Type消息头,
浏览器会按照指定的字符集进行解码。
-->
<meta charset
="UTF-8">
<%@ page language
="java" contentType
="text/html; charset=UTF-8" pageEncoding
="UTF-8"%>
2、如何解决
POST请求
:
request
.setCharacterEncoding("utf-8");
GET请求
:
修改server
.xml,
<Connector URIEncoding
="UTF-8"/>
注:如果是tomcat8
.0及以上版本,可以不用加
(只针对GET请求方式
)。
3、POST与GET没有提交性能(效率)之分
详细讲解:https://www.cnblogs.com/ljx20180807/p/10412427.html
实操:
访问数据库
*step1
:建表
create database jsd1808db
default character set utf8
;
use jsd1808db
;
create table
t_user(
id
int primary key auto_increment
,
username
varchar(50) unique
,
password
varchar(20),
email
varchar(30)
);
*step2
:导包
<dependencies>
<dependency>
<groupId>mysql
</groupId
>
<artifactId>mysql
-connector
-java
</artifactId
>
<version>5.1.6</version
>
</dependency
>
<dependency>
<groupId>commons
-dbcp
</groupId
>
<artifactId>commons
-dbcp
</artifactId
>
<version>1.4</version
>
</dependency
>
</dependencies
>
*step3
:添加jdbc
.properties文件
*step4
:添加DBUtils类并测试。
*step5
:使用jdbc api访问数据库。
练习:写一个Servlet
,以表格的形式显示所有用户的信息。
out
.println("<table border='1' width='60%'>");
while(rs
.next()){
int id
= rs
.getInt("id");
String username
= rs
...
String pwd
= ..
...
out
.println("<tr><td>" + id
+ "</td><td>" + username
+ "</td></tr>");
}
out
.println("</table>");
DAO (扩展)
(1)什么是
DAO(Data Access Object
)?
封装了数据访问逻辑的一个对象。
(2)如何写一个DAO
?
step1
. 写一个java类,一般称之为值对象。
注:
该类用于存放从数据库中查询出来的数据。
比如,要查询t_user表中的数据,就可以设计一个User类,该类的结构要与表的结构一致,也就说,表有哪些字段,类就会有对应的属性,属性类型要匹配。
step2
.写DAO类,提供一些访问数据库的方法。
(3)DAO的优点
方便测试
:
将数据访问逻辑写在DAO类里面,可以直接测试,如果将数据访问逻辑写在servlet里面,需要部署整个应用才能测试。
方便代码的维护
:
DAO封装了数据访问逻辑,调用者不用关心底层数据库相关的代码,比如,数据库访问逻辑发生了改变
(从jdbc换成了mybatis
),对调用者没有任何影响。
重定向<图redirect>
(1)什么是重定向
?
服务器通知浏览器向某个地址发送请求。
注:
服务器可以通过发送
302状态码及location消息头
(该消息头的值是一个地址,一般称之为重定向地址
)给浏览器,浏览器收到之后,会立即向重定向地址发送请求。
(2)如何重定向
?
response
.sendRedirect(String url
);
例:response
.sendRedirect("/WEB-INF/other.html");
注:
url就是重定向地址。
重定向之前,服务器会清空response对象上存放的所有数据。
该方法会自动设置状态代码
302
(3)重定向特点
A
.重定向的地址是任意的
response
.sendRedirect(String url
);
B
.重定向之后浏览器的地址栏会发生改变
地址变为从定向的的地址
JSP
什么是JSP
jsp是sun公司制定的一种服务器端的动态页面技术规范。 servlet也可以生成动态页面,但是过于繁琐,需要使用out.println语句来输出,并且不利于页面的维护,修改页面就需要修改java代码,所以sun公司才推出了jsp规范。 jsp是一个以.jsp为后缀的文件(主要内容是html和少量的java代码),容器会将这个文件转换成一个对应的servlet然后执行。也就是说jsp的本质就是一个servlet。 .jsp文件可以包含:html css js java 代码
如何书写JSP文件
step1
:添加一个以
.jsp为后缀的文件
step2
:在该文件里面添加如下内容:
1、html
,css
,js
直接写即可
2、java代码
语法一:java代码片段
<% javaCode
%>
直接使用隐含对象
在jsp文件里面可以直接使用的隐含对象
9个内置对象:
" page config out request response session application pageContext exception "
因为容器会自动添加获得这些对像的代码。
什么是指令
可以通过指令告诉容器,在将jsp转换成servlet时,做一些额外的处理,比如导包。
指令语法
<%@ 指令名 属性
=值 属性
=值
%>
注
:如果有多个属性用空格隔开。
page指令
import属性:指定要导的包名,如果有多个包,用
","号隔开。
比如
:
<%@ page
import="java.util.*,java.text.*"%>
contentType属性:设置response
.setContentType的内容。
pageEncoding属性:告诉容器,在读取jsp文件的内容时,使用指定的字符集来解码。
例:
contentType
="text/html; charset=UTF-8" pageEncoding
="UTF-8"
include指令
<%@ include file
="" %>
注
:
file属性用于指定被包含的文件名。
该指令用来告诉容器,在将jsp转换成servlet时,将file属性指定的文件的内容插入到该指令所在的位置。
被包含的文件可以是任何文件,包括html
,如果是jsp
,该jsp并不会执行!
taglib指令
<%@ taglib uri
="tagLibraryURI" prefix
="tagPrefix" %>
uri
="tagLibraryURI"指明标签库文件的存放位置。prefix
="tagPrefix"表示该标签使用时的前缀
如何书写java代码
第一种:
<%@ page 导入包
%>
例:
<%@ page
import="DAO.UserDAO,entity.User,java.util.*"%>
<% java代码
%>
例:
<%
Date date
=new Date();
String str
="yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf
=new SimpleDateFormat(str
);
String line
=sdf
.format(date
);
out
.println(line
);
%>
第二种
:
<%= java表达式
%>
例:
<%=user
.getId() %>
第三种:
<%! Java代码
%>
例:
<%!
String str
="<h2>JSP数据定义</h2>";
%>
JSP如何运行
阶段一:
容器先将jsp转换成一个servlet
.
html
,css
,js
-->在service方法里面,使用out
.write输出
<% %> -->在service方法里面,照搬
<%= %> -->在servlet方法里面,等效于使用out
.println输出
阶段二:
容器调用该servlet
,执行相应业务方法。
转发
*什么是转发:
(图forward
.png
)
一个web组件将未完成的处理交给另外一个web组件继续做。
注:
web组件指的是servlet和jsp的统称。
常见的情况是一个servlet获得数据之后,转发给一个jsp来展现这些数据。
*如何转发
step1
:绑定数据到请求对象上
request
.setAttribute(String name
,Object obj
);
注
:
name称之为绑订名,obj称之为绑订值。内部的实现,实际上是将数据放到了一个map对象里面。
step2
.获得转发器
RequestDispatcher rd
= request
.getRequestDispatcher(String uri
);
注
:
a
.RequestDispatcher是一个接口,该方法会返回一个实现了该接口的对象(即转发器)。
b
.uri是转发的目的地,通常是一个jsp的地址。
c
.RequestDispatcher可以理解为是一个媒介,web组件可以通过RequestDispatcher来通知容器去调用另外一个web组件。
d
.转发的本质是一个web组件通知容器去调用另外一个web组件。
step3
.转发
rd
.forward(request
,response
);
*转发的特点
a
.转发之后,浏览器地址栏的地址不变。
b
.转发的目的地有限制,要求属于同一个web应用。
例子:
List
<User> users
= dao
.findAll();
request
.setAttribute("users", users
);
RequestDispatcher rd
=request
.getRequestDispatcher("NewListUser.jsp");
rd
.forward(request
, response
);
转发与重定向比较
A:浏览器地址栏的地址有无变化? 重定向之后,浏览器地址栏的地址会发生变化; 转发之后,浏览器地址栏的地址不变。 B:目的地有无限制? 重定向地址没有任何限制,转发有限制(要求属于同一个web应用)。 C:能否共享request对象? 转发所涉及的各个web组件可以共享同一个request对象,重定向不行。 注: c1.容器收到请求之后,会立即创建request对象和response对象,一旦响应发送完毕,容器会立即删除这两个对象。 即request对象和response对象的生存时间很短暂(在一次请求与响应期间存在)。 c2.重定向是两次请求,上次请求创建的request对象和response对象已经被删除。 D:转发是一件事没有做完,让另外一个web组件继续做;而重定向是 一件事已经完成,去做另外一件独立的事。
Cookie && Session
Cookie:将状态保存在浏览器端
1、状态管理
什么是状态管理:
将浏览器与web服务器之间多次交互当做一个整体来处理,并且将多次交互所涉及到的数据(即状态)保存下来。
如何进行状态管理
方式一:将状态保存在浏览器端(使用cookie)
方式二:将状态保存在服务器端(使用session)
(
1)Cookie
:
什么是Cookie:服务器临时存放在浏览器端的少量数据,用于存放用户的状态。
注:当浏览器第一次访问服务器时,服务器会将少量数据以Set
-Cookie消息头的形式发送给浏览器,浏览器会将这些数据保存下来。当浏览器再次访问服务器时,会将这些数据以cookie消息头的形式发送给服务器。
"Cookie存放在内存中,当关闭浏览器之后,内存中的内容被清除,当再次打开浏览器直接请求findCookie,服务器返回not find Cookie!"
(
2)如何添加Cookie
Cookie cook
=new Cookie(String name
,String value
);
response
.addCookie(c
);
Cookie只能存放字符串
cookie都有一个名字,值也是一个字符串。
例子:
Cookie cook
=new Cookie("username","Sally");
response
.addCookie(cook
);
Cookie cook1
=new Cookie("City","BeiJing");
response
.addCookie(cook1
);
(
3)如何读取Cookie
方法:Cookie
[] request
.getCookies();
有可能该方法的返回值为null
获取Cookie的方法:
String name
= cook
.getName();
String value
= cook
.getValue();
例子:
Cookie
[] cookies
=request
.getCookies();
if(cookies
!=null
){
for(Cookie cook
: cookies
){
String name
=cook
.getName();
String value
=cook
.getValue();
out
.println("name="+name
+" value="+value
);
}
}else{
out
.println("Not find Cookie!");
}
(
4)Cookie的生存时间
默认情况下,浏览器会将Cookie存放到内存中里面,浏览器关闭,则Cookie会被删除。
cookie
.setMaxAge(int seconds
); 单位:秒
seconds
>0 时
:浏览器会将cookie保存在硬盘上
(一般是一个很小的文件
),超过指定时间,浏览器会将cookie删除。
seconds
<0 时
:缺省值
(浏览器会将cookie存放到内存里面
)
seconds
=0 时
:浏览器会删除该cookie
比如:要删除一个名称为username的cookie
:(同名替换原来的cookie
)
Cookie c
= new Cookie("username","");
c
.setMaxAge(0);
response
.addCookie(c
);
(
5)Cookie的编码问题
Cookie只能存放合法的ASCII字符,如果需要存放中文,需要将中文转换成对应的ASCII字符的形式
(即编码
)。
String str
=URLEncoder
.encode(String str
,String charset
);
建议在添加
/获取Cookie时统一做编码处理:
编码: Cookie cook1
=new Cookie("City",URLEncoder
.encode("北京","UTF-8"));
解码: String value
=URLDecoder
.decode(cook
.getValue(),"UTF-8");
(
6)Cookie的路径问题
什么是Cookie的路径问题:
浏览器在向服务器发请求时,会比较请求地址是否符合Cookie的路径,只要符合条件的cookie才会发送给服务器。
Cookie的默认路径
等于添加该Cookie的web组件的路径,比如:
/day06
/biz01
/addcookie
.jsp 则该jsp添加的cookie
,则该cookie的路径就是
"/day06/biz01"
(
7)匹配规则
请求地址要么等于cookie的路径,要么是其子路径,符合该要求的cookie会被发送。
比如,cookie的路径是
"/day06/biz01",则
"/day06/findCookie1.jsp" no
"/day06/biz01/findCookie2.jsp" yes
"/day06/biz01/sub/findCookie3.jsp" yes
"/day06"下的cookie都会被发送
(
8)修改Cookie路径
cookie
.setPath(String uri
);
"cookie的路径不一样时,可以出现名称相同"
(
9)Cookie的限制
Cookie可以被用户禁止。(在浏览器上设置)
Cookie不安全。(浏览器上可以查看)
cookie是一种客户端的状态管理技术,数据都保存在浏览器端,所以对于敏感数据,一定要加密处理。
Cookie只能保存少量数据。(
4k左右)
Cookie的数量也有限制。(大约几百个)
Cookie只能存放字符串。
Session:将状态保存在服务器端
什么是Session:
服务器端为了保存用户的状态而创建的一个特殊的对象。
注:
当浏览器第一次访问服务器时,服务器创建一个特殊的对象
(该对象一般称之为session对象,session对象有一个唯一的id
,一般称之为sessionId
)。
服务器会将sessionId以cookie的方式发送给浏览器。当浏览器再次访问服务器时,会将sessionId会送过来,服务器可以依据sessionId找到对应的session对象。
1、如何获得Session对象
(1)方式一
HttpSession session
= request
.getSession(boolean flag
)
注
:
HttpSession是一个接口。
当flag为
true时
:
先查看请求当中是否有sessionId
,如果没有,则创建一个session对象。如果有,
则依据sessionId查找对应的session对象,找到了则返回该对象,找不到,
则创建一个新的session对象。
session
.invalidate();
当flag为
false时
:
先查看请求当中是否有sessionId
,如果没有,返回null。如果有,
则依据sessionId查找对应的session对象,找到了则返回该对象,找不到,返回null。
(2)方式二
HttpSession session
= request
.getSession();
注:
等价于request
.getSession(true);
2、Session对象的常用方法
绑定数据
session
.setAttribute(String name
,Object obj
);
例子:
session
.setAttribute("count", "1");
session
.setAttribute("name", "Mr_Huang");
依据绑定名获得绑定值,如果绑定值不存在则返回null
Object session
.getAttribute(String name
);
例子:
Date date
=(Date
)session
.getAttribute("date");
Integer count
=(Integer
)session
.getAttribute("count");
解除绑定
session
.removeAttribute(String name
);
"练习"
显示用户上一次访问的时间,如果是第一次访问,显示“你是第一次访问”。
3、session 超时
服务器会将空闲时间过长的session对象删除掉。目的是为了节省内存空间。
注:大部分服务器默认的超时时间限制是
30分钟。
4、如何修改超时时间
方式一 修改服务器的配置文件
(web
.xml
)
<session
-config
>
<session
-timeout
>30</session
-timeout
>
</session
-config
>
方式二
session
.setMaxInactiveInterval(int seconds
);
设置两次请求之间的最大时间间隔,如果超过这个时间,服务器端的session对象会被销毁。
5、删除session
session
.invalidate();
6、session验证
step1
. 登录成功以后,在session对象上绑订一些数据。比如
:
session
.setAttribute("user",user
);
step2
. 当用户访问需要保护的资源时
(即只有登录之后的用户才能访问的 资源
),进行session验证
:
Object obj
= session
.getAttribute("user");
if(obj
== null
){
response
.sendRedirect("login.jsp");
return;
}
7、比较session 与 cookie
session 支持更丰富的数据类型,更安全,可以存放更多的数据;
但是session是将状态保存在服务器端,有可能会占用过多的内存。
cookie 只能存放字符串,数据保存在浏览器端,不安全,只能存放少量数据。
8、地址\路径问题
相对路径:
不以
"/"开头的都是相对路径。
绝对路径:
以
"/"开头的路径,就是绝对路径。
如何写绝对路径:
链接、表单提交、重定向:从应用名开始写
<a href
="<%=request.getContextPath() %>/a2.jsp">访问a2(使用request
.getContextPath())
</a
>
<form action
="<%=request.getContextPath() %>/path" method
="POST">
response
.sendRedirect(request
.getContextPath()+"/jsp03/sub/a4.jsp");
转发:从应用名之后开始写
(省略了应用名
)
request
.getRequestDispatcher("/jsp03/sub/a4.jsp").forward(request
, response
);
不建议将应用名直接写在路径里面,而应该使用下面这个
request
.getContextPath();
方法来获取应用名绝对路径。
建议使用绝对路径,容易写,而且利于维护。
Servlet生命周期
什么是servlet的生命周期:
指的是容器如何去创建servlet对象,如何对该对象进行初始化,如何调用该对象处理器请求,以及如何销毁该对象的整个过程。
即:Servlet容器是如何管理Servlet的。
创建、初始化、调用、销毁
生命周期分成那几个阶段:
1、实例化
什么是实例化:容器调用servlet的构造器创建servlet对象。
什么时候实例化:
1、默认情况下,容器收到请求之后才会创建。
注:容器只会创建一个实例
(对象
)
2、容器启动之后,立即创建
注:需要配置 load
-on
-startup 参数
例如:
<servlet>
<servlet
-name
>life_servlet
</servlet
-name
>
<servlet
-class>web
.LifeServlet
</servlet
-class>
<!-- 配置启动加载,容器启动之后会立即创建Servlet实例。
参数值要求大于等于
0的整数,容器会依据值从小到大的顺序加载,
即:优先级
(值越小优先级越高
)
-->
<load
-on
-startup
>1</load
-on
-startup
>
</servlet
>
2、初始化
什么是初始化
指的是容器在创建servlet实例之后,会调用该实例的init方法。
注:init方法只会执行一次。
GenericServlet类里面提供了init方法的实现。
该方法会将容器传递过来的ServletConfig对象保存下来,并且提供了
一个方法
(getServletConfig
)来获得该对象。
Config对象用于获取配置参数的值。
初始化参数。
<!-- 配置初始化参数 书写在servlet里面
-->
<servlet>
<init
-param
>
<param
-name
>company
</param
-name
>
<param
-value
>IBM
</param
-value
>
</init
-param
>
</servlet
>
String company
= config
.getInitParameter("company");
如何实现自已的初始化处理逻辑。
只需要重写
(override
) GenericServlet的
init()无参方法。
3、就绪
容器收到请求之后,调用servlet对象的service方法。
即:调用service方法处理请求。
GenericServlet类里面提供了init方法的实现。
该方法是这样实现的:
依据请求类型调用对应的doXXX方法,
比如:get请求会调用doGet方法,post请求会调用doPost方法。
doGet、doPost方法只是抛出了一个异常。
开发人员可以重写
(override
) HttpServlet的doXXX方法来实现
自定义业务逻辑的处理。也可以重写 HttpServlet的service方法。
4、销毁
什么是销毁
容器在删除servlet对象之前会调用该对象的destroy方法。
该方法只执行一次!
*相关的接口与类:
Servlet接口
该接口主要声明了三个方法:
init(ServletConfig config
);
service(ServletRequest req
,ServletResponse res
);
destroy();
GenericServlet抽象类
实现了Servlet接口中的部分方法(init
,destroy)
HttpServlet抽象类
继承了GenericServlet
,实现了service方法。
*容器如何处理请求资源路径
比如,在浏览器地址栏输入http
://ip
:port
/day08
-2/abc
.html
,
浏览器会将
"/day08-2/abc.html"作为请求资源路径发送给容器。
*step1
.容器默认认为访问的是一个servlet
,容器会从web
.xml中去查找对应的servlet。
将请求资源路径中的应用名除掉,然后去跟
<url
-pattern
>的值去做匹配。
url
-pattern有三种写法
:
1、精确匹配
:
即请求资源路径除掉应用名之后的值必须等于url
-pattern的值。
(比如这儿,请求资源路径除掉应用名之后是
"/count",url
-pattern的值正好也是
"/count",这样就匹配了
)
<url
-pattern
>/count
</url
-pattern
>
2、通配符匹配
:
使用
"*"匹配任意的零个或者多个字符。
比如
:
<url
-pattern
> /不能省略,用于匹配
/后面的任意内容
3、后缀匹配
:
使用
"*."开头,然后接一个后缀
(后缀就是一个字符串
).注意:后缀匹配前面没有
/ (反斜杠
)
比如
:
<url
-pattern
>*.do</url
-pattern
>
以上配置,会匹配所有以
.do 结尾的请求。
<url
-pattern
>*.do</url
-pattern
>
*step2
.如果没有匹配的servlet
,容器会从对应的位置去查找文件, 如果找不到,返回
404。
Filter && Listener
过滤器
作用:检测用户提交数据是否满足会定的要求。比如:用户名、密码、邮箱
....
什么是过滤器
servlet规范中定义的一种特殊组件,用于拦截servlet容器的调用过程。
注:
Servlet容器收到请求之后,会先调用过滤器,在调用servlet。
(执行顺序
)
如何写一个过滤器
*step1:写一个java类,实现Filter接口。
*step2:在doFilter方法当中,实现拦截处理逻辑
(同时重写init、destroy、doFilter方法
)
注意强制转换:
HttpServletRequest request
=(HttpServletRequest
)arg0
;
HttpServletResponse response
=(HttpServletResponse
)arg1
;
*step3:配置过滤器。
(web
.xml
)
过滤器的优先级
当有多个过滤器都满足拦截要求,则容器依据
<filter
-mapping
> 配置的先后顺序来执行。
例子:
public class CommentFilter implements Filter {
private FilterConfig config
;
public CommentFilter(){
System
.out
.println("CommentFilter's constructor!");
}
public void destroy() {
System
.out
.println("CommentFilter's destroy...");
}
public void doFilter(ServletRequest arg0
, ServletResponse arg1
, FilterChain chain
)throws IOException
, ServletException
{
HttpServletRequest request
=(HttpServletRequest
)arg0
;
HttpServletResponse response
=(HttpServletResponse
)arg1
;
System
.out
.println("CommentFilter's doFilter begin...");
request
.setCharacterEncoding("UTF-8");
response
.setContentType("text/html;charset=UTF-8");
if(CheckWords(request
)){
response
.getWriter().println("评论内容包含违禁字!");
}else{
chain
.doFilter(request
, response
);
}
System
.out
.println("CommentFilter's doFilter Over!");
}
public void init(FilterConfig arg0
) throws ServletException
{
System
.out
.println("CommentFilter's init ...");
config
=arg0
;
}
public boolean CheckWords(HttpServletRequest request
){
boolean flag
=false;
String content
=request
.getParameter("content");
String illegal
= config
.getInitParameter("illegal");
for(int i
=0;i
<content
.length();i
++){
if(illegal
.indexOf(content
.charAt(i
)) !=-1){
flag
=true;
}
}
return flag
;
}
}
过滤器的优点
1、可以在不修改原有代码的基础上,为应用添加一些简单的功能。 “开闭原则”:对修改关闭,对扩展开放 2、可以将多个组件相同的功能集中写在过滤器里面,方便代码的维护。
监听器
*什么是监听器
Servlet规范当中定义的一种特殊的组件,用于监听servlet容器产生的事件并进行相应的处理。
注:
容器会产生两大类事件:
1、生命周期相关的事件
当容器创建或者销毁 request、session 、servlet上下文时产生的事件。
2、绑定数据相关的事件
当调用了request
,session
,servlet上下文的setAttribute
,removeAttribute时产生的事件。
*Servlet上下文
什么是Servlet上下文
容器启动之后,会为每一个web应用创建一个唯一的一个符合ServletContext接口要求的对象,该对象我们一般称之为Servlet上下文。
该对象有两个特点
:
1、唯一性:一个web应用对应一个servlet上下文
2、持久性:只要容器不关闭,应用没被卸载,则ServletContext会一直存在。
*如何获得servlet上下文
可以通过ServletConfig
,FilterConfig
,GenericServlet
,HttpSession
提供的getServletContext方法来获得。
*作用
绑定数据
setAttribute(String name
,Object obj
);
Object
getAttribute(String name
);
removeAttribute(String name
);
注:
request session servletContext 都提供了绑定数据的相关方法,区别如下:
区别
1:绑定的数据生存时间不一样,从小到大一次是 request
< session
< servletContext
.在满足使用条件的情况下优先使用生命周期短的。
区别
2:绑定到session对象上的数据只有与之对应的用户才能够访问;绑定到servlet上下文上的数据所有用户都能访问到。
读取全局的初始化参数
<!-- 配置全局的初始化参数
-->
<context
-param
>
<param
-name
>company
</param
-name
>
<param
-value
>IBM
</param
-value
>
</context
-param
>
ServletContext sctext
=getServletContext();
String company
= sctx
.getInitParameter("company");
如何写一个监听器
1、写一个java类,实现相应的监听器接口
(8种监听事件
)
要依据监听的事件类型来选择实现对应的接口
比如:要监听session对象的创建和销毁,就需要实现HttpSessionListener接口
public class CacheListener implements ServletContextListener{
public void contextDestroyed(ServletContextEvent arg0
) {
System
.out
.println("CacheListener's contextDestroyed...删除servlet上下文");
ServletContext sctext
=arg0
.getServletContext();
sctext
.removeAttribute("users");
}
public void contextInitialized(ServletContextEvent arg0
) {
System
.out
.println("CacheListener's contextInitialized...servlet上下文绑定数据!");
ServletContext sctext
=arg0
.getServletContext();
@SuppressWarnings("unchecked")
List
<User> users
=(List
<User>)sctext
.getAttribute("users");
if(users
==null
){
try {
dataAccessObj dao
=new dataAccessObj();
users
= dao
.findAllData();
sctext
.setAttribute("users", users
);
System
.out
.println("绑定users数据成功!");
} catch (SQLException e
) {
e
.printStackTrace();
throw new RuntimeException(e
);
}
}
}
}
2、在监听器接口的方法当中,实现监听处理逻辑
3、配置监听器
(web
.xml
)
<!-- 配置监听器
-->
<listener>
<listener
-class>web
.CacheListener
</listener
-class>
</listener
>
异常抛出给容器处理
throw new RuntimeException(e
);
配置web
.xml文件
<!-- 配置抛出给容器的异常,状态码与异常类只能写一个
-->
<error
-page
>
<error
-code
>500</error
-code
>
<!-- <exception
-type
>java
.sql
.SQLException
;</exception
-type
> -->
<location>/throwerror
.jsp
</location
>
</error
-page
>
Servlet的线程安全问题
为什么说Servlet会有线程安全问题?
容器只会创建一个实例。
容器收到请求就会启动一个线程,由该线程来进行相应的处理。这样就有可能有多个线程同时去调用同一个Servlet对象的service方法,就有可能产生线程安全问题。
比如说:这些线程同时去修改servlet的某个属性。
如何解决线程安全问题?
synchronized(this){
count
++;
try {
Thread
.sleep(1000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
System
.out
.println(
Thread
.currentThread().getName()+":" + count
);
}
Servlet总结问题
(1)Servlet基础 1).什么是Servlet? 2).如何写一个Servlet? 3).Servlet是如何运行的? 4).Http协议(了解) a.http协议是什么? b.特点? c.数据包的结构(消息头、状态码) d.两种请求方式 (2)Servlet核心 1).如何获得请求参数值? 2).Servlet输出中文,如何处理? 3).表单包含有中文参数,如何处理? 4).Servlet容器如何处理请求资源路径? 5).如何让一个Servlet处理多种请求? 6).Servlet的线程安全问题 7).转发与重定向 a.什么是重定向? b.如何重定向? c.重定向的特点 d.什么是转发? e.如何转发? f.转发的特点 g.比较转发与重定向 8).Servlet的生命周期 a.什么是Servlet的生命周期? b.生命周期分成哪几个阶段? c.容器在什么时候创建Servlet对象?(load-on-startup) d.容器会创建几个Servlet实例?。 e.初始化方法会执行几次? g.如何配置初始化参数? h.如何实现自已的初始化处理逻辑? i.doGet,doPost方法的作用? j.Servlet接口,GenericServlet,HttpServlet的关系。 h.ServletConfig的作用? 9)路径问题 a.什么是相对路径? b.什么是绝对路径? c.如何写绝对路径? 10)Servlet上下文 a.什么是Servlet上下文? (唯一性、持久性) b.如何获得Servlet上下文? c.主要作用(绑订数据时与request,session的区别) d.全局的初始化参数。 (3)状态管理 1)什么是状态管理? 2)如何进行状态管理? 3)Cookie a.什么是Cookie? (set-cookie,cookie) b.如何添加Cookie? c.添加Cookie时需要考虑的三个问题(编码问题、生存时间、路径问题)。 d.如何读取Cookie? e.Cookie的限制 4)Session a.什么是Session? b.如何获得Session对象? c.常用方法。 d.Session超时 e.删除Session对象 f.比较Cookie与Session (4)过滤器与监听器 1)什么是过滤器? 2)如何写一个过滤器? 3)过滤器的优先级 4)初始化参数 5)过滤器的优点 6)什么是监听器? 7)如何写一个监听器? (5)数据访问 (扩展) 1)什么是DAO? 2)如何写一个DAO? 3)DAO的优点? (6)典型案例 用户管理 登录(session验证)
JSP详解
1.jsp基础
(1)什么是jsp
?
sun公司制订的一种服务器端的动态页面技术规范。
注
:
以
.jsp为后缀的文件
, 会被容器转换成一个对应的servlet。
jsp的本质就是一个servlet
!
(2)如何写一个jsp文件
?
1)html(css
,js
)
直接写即可
2)java代码
a
. java代码片断
<% java代码
%>
b
. jsp表达式
<%= java表达式
%>
c
. jsp声明
(a1
.jsp
)
<%! 声明一个变量或者方法
%>
例子:
<%! String str
="JSP数据定义测试";
public String
method(){
return str
;
}
int sum(int x
,int y
){
return x
+y
;
}
%>
<%=method()%>
<%="求和计算:"+sum(5,8) %>
(3)隐含对象
a
.什么是隐含对象
?
直接可以使用的对象。
b
.为什么可以直接使用这些隐含对象
?
容器会自动添加获得这些对象的代码。
c
.有哪些隐含对象
?
out
,request
,response
session
,application
"这些常用"
pageContext
:页面上下文
(a2
.jsp
,a3
.jsp
)
容器会为每一个jsp实例创建唯一的一个符合PageContext
接口要求的对象,该对象会一直存在,除非jsp实例被容器删除。
该对象的作用主要有两个
:
作用
1:绑订数据。
绑订到pageContext上的数据,只有对应的jsp实例
(当前页面JSP
)能够访问到。
作用
2:提供了一些方法,用来获得其它所有的隐含对象
例子:
<body>
<%
pageContext
.setAttribute("username","Mr_Huang");
%>
<%=pageContext
.getAttribute("username") %>
</body
>
config
: 即
:ServletConfig(a4
.jsp
)
可以为JSP配置初始化参数,然后通过config对象去获取。
<body>
<%=config
.getInitParameter("company") %>
</body
>
配置文件:
<servlet>
<servlet
-name
>a4
</servlet
-name
>
<jsp
-file
>/a4
.jsp
</jsp
-file
> "jsp-file 实现把jsp转换为servlet"
<init
-param
>
<param
-name
>company
</param
-name
>
<param
-value
>Mr_Huang
</param
-value
>
</init
-param
>
</servlet
>
<servlet
-mapping
>
<servlet
-name
>a4
</servlet
-name
>
<url
-pattern
>/a4
</url
-pattern
>
</servlet
-mapping
>
exception
:(a5
.jsp
,a6
.jsp
)
当page指令的isErrorPage属性值设置为
true时,可以使用该隐含对象,
该隐含对象可以用来获得jsp运行时产生的一些异常的简短的描述。
a5
.jsp:
<%@ page errorPage
="a6.jsp"%> "将异常处理转到a6.jsp页面处理"
<body>
传入参数:http
:ip
:port
/day11
/a5
.jsp
?number
=123
<%
String number
=request
.getParameter("number");
int num
=Integer
.parseInt(number
);
out
.println(num
);
%>
</body
>
a6
.jsp:
<%@ page isErrorPage
="true" %>
<body>
请输入合法的数值!
<br>
<%=exception
.getMessage() %><br>
<%=exception
.toString() %>
</body
>
page(了解
): jsp实例本身
(jsp对应的servlet实例
)。
(4)jsp是如何执行的
step1
. 容器要将jsp转换成一个servlet
html(css
,js
) ---> 在service方法里面,使用out
.write输出。
<% %> -----> 照搬到service方法里面。
<%= %> -----> 在service方法里面,使用out
.print输出。
(等效:out
.println())
<%! %> -----> 为servlet增加新的属性或者新的方法。
(5)指令
什么是指令:
可以通过指令告诉容器,在将JSP转换成servlet时,做一些额外的处理,比如导包。
有哪些指令:
page指令:
import属性:导包
<%@ page
import="java.util.Date" %>
pageEncoding属性:指定jsp文件的编码集
language属性:指定代码使用的语言种类
<%@ page language
="java" pageEncoding
="UTF-8"%>
contentType属性:response
.setContentType方法的内容
(文件类型,以及编码
)
<%@ page contentType
="text/html; charset=UTF-8" %>
errorPage属性:指定一个异常处理页面。当jsp运行发生异常时,容器会调用该异常处理页面。
<%@ page errorPage
="a6.jsp"%>
isErrorPage属性:默认值是
false,如果值为
true,就可以使用exception隐含对象。
<%@ page isErrorPage
="true" %>
<%=exception
.toString() %>
session属性
(a7
.jsp
):默认值是
true,如果值为
false,则
(页面
)不能够使用session隐含对象。
<%@ page session
="true" %>
include指令
:
file属性:指定被包含的文件
<%@ include file
="header.jsp" %>
taglib指令:
导入需要使用的jsp标签
<%@ taglib uri
="http://java.sun.com/jsp/jstl/core" prefix
="c"%>
uri
:是要导入的jsp标签的命名空间,指明标签库文件存放的路径
(如:域名
)
注:命名空间是为了区分同名的元素而在元素前添加的一段说明,通常是一个域名。
prefix
:前缀,命名空间的别名。
<short-name
>c
</short-name
>
<uri>http
://java
.sun
.com
/jsp
/jstl
/core
</uri
>
(6)注释
(a8
.jsp
)
<!-- 注释内容
-->
如果注释的内容是java代码,java代码会被执行
;但是同时也是html注释,会被浏览器忽略掉
.
<%-- 注释内容
--%>
如果注释的内容是java代码,java代码不会被执行
javaBean
是一个规范,满足如下几个条件就可以称之为javaBean:
public 类
public 构造器
实现Serializable接口
(最好
)
有一些属性以及对应的get
/set方法
2.JSP标签和el表达式
jsp标签是什么
jsp标签是sun公司推出的一个规范,目的是为了替换jsp中的java代码。
jsp标签语法类似于html标签
(比如说,有开始标记、结束标记、有一些属性、有标签体
)。
容器遇到jsp标签之后,会调用jsp标签对应的jsp标签类中的java代码。
使用jsp标签,好处是,jsp文件便于美工去修改,另外,也便于代码的复用
(jsp标签可以重用
)。
el表达式是什么
一套简单的运算规则,用于给jsp标签的属性赋值,也可以脱离jsp标签直接使用。
el表达式的使用
读取javaBean的属性值
方式一:
(e1
.jsp
)
$
{user
.username
} "等效:<%= 表达式 %>"
等效代码:
User user1
=(User
)request
.getAttribute("user");
out
.println(user1
.getUsername());
执行过程:容器依次从pageContext
-->request
-->session
-->application中查找绑定名为
"user"的对象
(getAttribute
),找到之后调用该对象的
"getUsername"方法,
来获取相对应的值,最后输出。
优点:
会将null转换成空字符串
""输出。
如果依据绑定名找不到对应的对象,不会报空指针异常。同时转换成
""输出。
"属性名不能写错,否则报错"
指定查找范围:
可以使用pageScope requestScope sessionScope applicationScope 来指定查找范围。
"一旦指定查找范围,那么在该范围内没有找到指定的绑定对象,不会再去其他区域中查找"
例子:
$
{sessionScope
.user
.username
}
方式二:
$
{user
["username"]}
执行过程和方式一相同;
[]里面可以出现绑定名
[]里面可以出现从
0开始的下标,用来访问数组中的某个元素。
<%
pageContext
.setAttribute("s1", "age");
%>
出现绑定数据名:$
{user
[s1
] }
Age
:$
{user
[requestScope
.s1
] } <!-- 找不到绑定的数据,打印空字符串
-->
Interest
:$
{user
.interest
[0] }
进行一些简单的运算
算术运算:
+ - * / %
$
{1+1 }
关系运算符:
> >= < <= == !=
<%request
.setAttribute("s1", "abc"); %>
$
{session
.Scope
.s1
== "abc" }
逻辑运算符:
&& || !
$
{2>0 && 2<3 }
empty运算符:用来判断一个字符串是否为空,或者一个集合是否为空,
以下四种情况为
true:
空字符串、空集合、值为null 、找不到对应的值
<%
List
<String> list
=new ArrayList<String>();
request
.setAttribute("list", list
);
%>
empty计算:$
{empty list
} <!-- true-->
" + 只能求和,不能连接字符串;会把字符串转换成对应的数值进行相加运算"
例如:$
{"a" + "b"} --> 500 报错
$
{"2" + "5"} --> 7
读取请求参数值
(e3
.jsp
)
"param"固定用法
$
{param
.username
}
等价于
-> request
.getParameter("username");
username1
: <%=request
.getParameter("username") %>
username2
: $
{param
.username
}
"paramValues"
$
{paramValues
.city
}
等价于
-> request
.getParameterValues("city");
<%
String
[] citys
=request
.getParameterValues("city");
if(citys
!=null
){
for(String city
:citys
){
out
.println(city
+"<br/>");
}
}
%>
citys:$
{paramValues
.city
}
citys
[0]:$
{paramValues
.city
[0] }
JSTL(jsp standard tag librariy)标签的引用
JSTL是什么
(jsp standard tag lib
):
注
:
apache开发的一套jsp标签,后来捐献给了sun
,sun将其命名为jstl。
jstl如何使用:
step1
:导包
<dependencies>
<dependency>
<groupId>jstl
</groupId
>
<artifactId>jstl
</artifactId
>
<version>1.2</version
>
</dependency
>
</dependencies
>
step2
:使用taglib指令导入需要使用的jsp标签库
<%@ taglib prefix
="c" uri
="http://java.sun.com/jsp/jstl/core" %>
3.JSP标签
if标签
用法:
<c
:if test
="" var
="" scope
="">
标签体
</c
:if>
b
.当test属性值为
true时,容器执行标签体的内容。
c
.test属性值可以使用el表达式进行计算。
var属性:指定一个绑定名称
scope属性:指定绑定范围
(page request session application
)
"var与scope配合使用"
例子:
性别:
<c
:if test
="${user.gender =='m' }" var
="rs" scope
="page">男
</c
:if>
<c
:if test
="${!rs}">女
</c
:if>
choose标签
用法:
<c
:choose
>
<c
:when test
="">
</c
:when
>
<c
:otherwise
>
</c
:otherwise
>
</c
:choose
>
when可以出一次或者多次,表示一个分支
(相当于一个
if语句
),
当test属性值为
true时,执行标签体的内容。test属性值可以使用el表达式来进行计算。
otherwise可以出现
0次或者
1次,表示例外
(相当于最那个
else语句
)
例子:
<c
:choose
>
<c
:when test
="${user.gender =='m' }">男
</c
:when
>
<c
:when test
="${user.gender =='f' }">女
</c
:when
>
<c
:otherwise
>保密
</c
:otherwise
>
</c
:choose
>
forEach
用法:
<c
:forEach items
="" var
="" varStatus
="">
</c
:forEach
>
items属性用来指定要遍历的集合或者数据,可以使用el表达式来赋值。
可以使用el表达式,从隐含对象中获取绑定数据。
var属性用来指定绑定名。
(绑定范围固定是pageContext,该标签每次从集合或者数组中
取一个元素,然后将其绑定到pageContext上
)
varStatus属性用来指定绑定名。
绑定范围固定是pageContext,绑订值是一个特殊的对象,该对象由该标签创建,
用来获得当前的遍历状态。
该对象提供了以下方法,用来获得当前遍历的状态
:
index:返回正在被迭代的下标,下标从
0开始
getIndex(): 获得当前正在被遍历的元素的下标
(从
0开始
)。
count:返回是第几次迭代,从
1开始。
getCount(): 获得当前正在被遍历的元素的序号
(从
1开始
)。
例子:
<c
:forEach items
="${users }" var
="u" varStatus
="s">
<tr
class="row${s.index % 2 +1}">
<td>$
{u
.username
}</td
>
<td> <!-- 嵌套choose标签,打印性别
-->
<c
:choose
>
<c
:when test
="${u.gender == 'm'}">男
</c
:when
>
<c
:when test
="${u.gender == 'f'}">女
</c
:when
>
</c
:choose
>
</td
>
<td>$
{u
.age
}</td
>
<td>$
{s
.index
}</td
>
<td>$
{s
.count
}</td
>
</tr
>
</c
:forEach
>
自定义JSP标签
step1
.写一个java类,继承SimpleTagSupport类。
(简单标签技术
)
step2
.重写doTag方法,在该方方法里面编写处理逻辑。
step3
.在
*.tld文件里面描述该标签。
public class HelloTag extends SimpleTagSupport {
private String msg
;
private int qty
;
public HelloTag() {
System
.out
.println("HelloTag 构造器运行了!");
}
public void setMsg(String msg
) {
System
.out
.println("Set msg!");
this.msg
= msg
;
}
public void setQty(int qty
) {
System
.out
.println("Set qty!");
this.qty
= qty
;
}
@Override
public void doTag() throws JspException
, IOException
{
System
.out
.println("Execute doTag method!");
PageContext pctext
=(PageContext
)getJspContext();
JspWriter out
= pctext
.getOut();
for(int i
=0;i
<qty
;i
++){
out
.println(msg
+"<br/>");
}
}
配置 xxx
.tld 文件
该文件可以放在WEB
-INF文件夹下面
也可以放在jar包的META
-INF文件夹下
<?xml version
="1.0" encoding
="UTF-8" ?>
<taglib xmlns
="http://java.sun.com/xml/ns/javaee"
xmlns
:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi
:schemaLocation
="http
://java
.sun
.com
/xml
/ns
/javaee
http
://java
.sun
.com
/xml
/ns
/javaee
/web
-jsptaglibrary_2_1
.xsd"
version
="2.1">
<description>自定义JSTL标签库
</description
>
<display
-name
>JSTL core
</display
-name
>
<tlib
-version
>1.0</tlib
-version
>
<short-name
>d
</short-name
>
<uri>http
://tedu
.cn
/mytag
</uri
>
<tag>
<description>描述你也看不懂
</description
>
<name>hello
</name
>
<tag
-class>tag
.HelloTag
</tag
-class>
<!--
body
-content 用来设置该标签体是否有标签体,如果有,标签体的内容允许出现哪些内容。
值:
empty
:该标签没有标签体
scriptless
:该标签有标签体,该标签体的内容不能任何出现java代码。
JSP:该标签有标签体,并且标签体的内容可以使java代码。
但是只有复杂的标签技术才支持该值。
-->
<body
-content
>empty
</body
-content
>
<attribute>
<description>描述你也看不懂
</description
>
<name>msg
</name
>
<!-- true表示该属性必选
false表示该属性可有可无
-->
<required>true</required
>
<!-- 值为
true:表示该属性值可以使用el表达式动态赋值;值为
false: 则相反
-->
<rtexprvalue>false</rtexprvalue
>
</attribute
>
<attribute>
<name>qty
</name
>
<required>true</required
>
<rtexprvalue>true</rtexprvalue
>
</attribute
>
</tag
>
</taglib
>
使用:
<%@ taglib uri
="http://tedu.cn/mytag" prefix
="d"%>
<d
:hello msg
="Hello Kitty" qty
="${2+8}"/>
*练习:写一个日期标签,可以按照指定的格式输出日期。
<d
:date timeFormat
="yyyy-MM-dd"/>
以上个人对Servlet以及JSP的知识整理,若有遗漏、疑问、或者不懂的地方欢迎留言;别忘了点赞哦!