JSP 和 JSTL

  1. JSP
    简介
    JSP:Java Server Page SUN 公司提供的动态⽹⻚编程技术,是 Java Web 服务器端的动态资源。它相⽐ html ⽽⾔,html 只能为⽤户提供静态数据,⽽ Jsp 技术允许在⻚⾯中嵌套 java 代码,为⽤户提供动态数据。相⽐ servlet ⽽⾔,servlet 很难对数据进⾏排版,⽽ jsp 除了可以⽤ java 代码产⽣动态数据的同时,也很容易对数据进⾏排版。不管是 JSP 还是 Servlet,虽然都可以⽤于开发动态 web 资源。但由于这 2 ⻔技术各⾃的特点,在⻓期的软件实践中,⼈们逐渐把 servlet 作为 web 应⽤中的控制器组件来使⽤, ⽽把 JSP 技术作为数据显
    示模板来使⽤。其实 Jsp 就是⼀个 Servlet,当我们第⼀次访问 Jsp 的时候,Jsp 引擎都会将这个 Jsp 翻译 成⼀个Servlet,这个⽂件存放在tomcat(源码⽬录) 中的 work ⽬录中。
  2. JSP的指令标签
    使⽤包含操作,可以将⼀些重复的代码包含进来继续使⽤,从正常的⻚⾯组成来看,有时可能分为⼏
    个区域。⽽其中的⼀些区域可能是⼀直不需要改变的,改变的就其中的⼀个具体内容区域。现在有两种
    ⽅法可以实现上述功能。
    ⽅法⼀:在每个 JSP ⻚⾯(HTML)都包含⼯具栏、头部信息、尾部信息、具体内容
    ⽅法⼆:将⼯具栏、头部信息、尾部信息都分成各个独⽴的⽂件,使⽤的时候直接导⼊
    很明显,第⼆种⽅法⽐第⼀种更好,第⼀种会存在很多重复的代码,并且修改很不⽅便,在 JSP 中如
    果要想实现包含的操作,有两种做法:静态包含、动态包含,静态包含使⽤ include 指令即可,动态包
    含则需要使⽤ include 动作标签。
    第⼀种:<% %>: java 脚本段,可以定义局部变量、编写语句
    第⼆种:<%! %>:声明,可以定义全局(成员)变量、⽅法、类
    第三种:<%= %>:表达式,数据⼀个变量或具体内容
Scriptlet <% String str = "Hello JSP"; System.out.println(str); response.getWriter().write(str); %> <%! String memberStr = "a member String"; %> <%=memberStr%>

This is a JSP page!!

2.2.1. include 静态包含 例如: 静态包含就是将内容进⾏了直接的替换,就好⽐程序中定义的变量⼀样,是在 servlet 引擎转译时, 就把此⽂件内容包含了进去(两个⽂件的源代码整合到⼀起, 全部放到_jspService ⽅法中),所以只 ⽣成了⼀个 servlet,所以两个⻚⾯不能有同名的变量。 运⾏效率⾼⼀点点。耦合性较⾼,不够灵活。 2.2.2. include 动态包含 动态包含在代码的编译阶段,包含和被包含部分是两个独⽴的部分,只有当运⾏时,才会动态包含进 来,好⽐⽅法的调⽤。 注意:动态包含,中间不要加任何内容,包括空格,除⾮确认要使⽤参数,否则报错! 使⽤动态包含还可以通过在⻚⾯之间传参。 接收参数通过 request.getParameter(name); hello.jsp <%@ include file="要包含的⽂件路径" %> <%@include file="include.jsp" %> 或 <%@include file="include.html" %> <% String a = "hello.jsp"; %> <%=request.getParameter("uname")%> ⽅法 类型 描述 public void setAttribute(String name, Object o) 普通 设置属性的名称及内容 public Object getAttribute(String name) 普通 根据属性名称取属性 public void removeAttribute(String name) 普通 删除指定的属性 2.3. JSP的四⼤域对象 2.3.1. 四种属性范围 在JSP中提供了四种属性的保存范围,所谓的属性保存范围,指的就是⼀个设置的对象,可以再多少 个⻚⾯中保存并可以继续使⽤ 1. page范围 pageContext : 只在⼀个⻚⾯中保存属性,跳转之后⽆效 2. request范围 request : 只在⼀次请求中保存,服务器跳转后依然有效 3. session范围 session : 在⼀次会话范围中,⽆论何种跳转都可以使⽤ 4. application范围 application : 在整个服务器上保存 2.3.2. 验证属性范围的特点 1. page 本⻚⾯取得,服务器端跳转()后⽆效 2. request 服务器跳转有效,客户端跳转⽆效 如果是客户端跳转,则相当于发出了两次请求,那么第⼀次的请求将不存在了;如果希望不管是客 户端还是服务器跳转,都能保存的话,就需要继续扩⼤范围。 3. session ⽆论客户端还是服务器端都可以取得,但是现在重新开启⼀个新的浏览器,则⽆法取得之前设置的 session了,因为每⼀个session只保存在当前的浏览器当中,并在相关的⻚⾯取得。 对于服务器⽽⾔,每⼀个连接到它的客户端都是⼀个session 如果想要让属性设置⼀次之后,不管是否是新的浏览器打开都能取得则可以使⽤application 4. application 所有的application属性直接保存在服务器上,所有的⽤户(每⼀个session)都可以直接访问取得 只要是通过application设置的属性,则所有的session都可以取得,表示公共的内容,但是如果此 时服务器重启了,则⽆法取得了,因为关闭服务器后,所有的属性都消失了,所以需要重新设置。 问:使⽤哪个范围呢? 答:在合理范围尽可能⼩ 2.4. EL表达式的使⽤ 2.4.1. EL表达式的语法 EL(Expression Language) 是为了使 JSP 写起来更加简单。表达式语⾔的灵感来⾃于 ECMAScript 和 XPath 表达式语⾔,它提供了在 JSP 中简化表达式的⽅法,让 Jsp 的代码更加简化。 EL 表达式⼀般操作的都是域对象中的数据,操作不了局部变量。 域对象的概念在 JSP 中⼀共有四个:pageContext, request, session, application;范围依次是, 本⻚⾯,⼀次请求, ⼀次会话,整个应⽤程序。 当需要指定从某个特定的域对象中查找数据时可以使⽤四个域对象对应的空间对象,分别是: pageScope, requestScope, sessionScope, applicationScope。 ⽽ EL 默认的查找⽅式为从⼩到⼤查找,找到即可。当域对象全找完了还未找到则返回空字符串""。 2.4.2. EL表达式的使⽤ 2.4.2.1. 获取数据 设置域对象中的数据 获取域对象的值 语法结构⾮常简单: ${expression} <% pageContext.setAttribute("uname","zhangsan"); // page作⽤域 request.setAttribute("uname","lisi"); // request作⽤域 session.setAttribute("uname","wangwu"); // session作⽤域 application.setAttribute("uname","zaholiu"); // application %> <%-- 获取域对象中的数据:默认查找⽅式为从⼩到⼤,找到即⽌。若四个范围都未找到,则返回空字符 串。--%> ${uname} 获取指定域对象的值 ${pageScope.uname} ${requestScope.uname} ${sessionScope.uname} ${applicationScope.uname} 获取List <% List list = new ArrayList(); list.add("aaa"); list.add("bbb"); list.add("ccc"); request.setAttribute("list", list); %> <%-- 获取List中指定下标的数据 ${list[下标] } 获取集合的⻓度 ${list.size()} 注: list代表的是存在域对象中的变量名(限域变量名) --%> ${list[1] } 获取Map <% Map map = new HashMap(); map.put("aaa", "111"); map.put("bbb", 2222); map.put("ccc-a", 333); request.setAttribute("map", map); %> <%-- 获取Map中指定值 ${map["key"] } 或 ${map.key } 注: map代表的是存在域对象中的变量名(限域变量名) --%> ${map.aaa } ${map["bbb"]} 获取JavaBean对象 User.java public class User { private Integer userId; private String uname; private String upwd; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public String getUpwd() { return upwd; } public void setUpwd(String upwd) { this.upwd = upwd; } } 2.4.2.2. empty 2.4.2.3. EL运算 等值判断 <% User user = new User(); user.setUserId(1); user.setUname("zhangsan"); user.setUpwd("123456"); request.setAttribute("user",user); %> <%-- JavBean中的属性字段需要提供get⽅法 --%> ${user} <%-- 获取对象 --%> ${user.uname} <%--获取对象中的属性--%> <%-- empty 判断域对象是否为空。为空,返回true;不为空返回false; ${empty 限域变量名 } 判断对象是否不为空。 ${!empty 限域变量名 } --%> ${empty uname} ${empty list} ${empty map} ${empty user} <% request.setAttribute("a", 10); request.setAttribute("b", 2); request.setAttribute("c", "aa"); request.setAttribute("d", "bb"); %> 算术运算 ⼤⼩⽐较 3. JSTL 3.1. 标签的使⽤ Java Server Pages Standard Tag Libray(JSTL):JSP 标准标签库,是⼀个定制标签类库的集合,⽤于 解决⼀些常⻅的问题,例如迭代⼀个映射或者集合、条件测试、XML 处理,甚⾄数据库和访问数据库操 作等。 我们现在只讨论 JSTL 中最重要的标签,迭代集合以及格式化数字和⽇期⼏个标签。 核⼼标签库: <%-- ⽐较两个值是否相等,返回true或false == 或 eq --%> ${a == b } ${c == d } ${c eq d } ${a == 5 } ${c == 'aa' } <%-- 加法: + 减法: - 乘法: * 除法: / 或 div --%> ${a + b } ${a / b } 或 ${a div b } <%-- ⼤于:> ⼩于:< ⼤于等于:>= ⼩于等于:<= --%> ${a > b} ${a + 1 > 10 } ${a + b >= 10 } ${a > b && b > 5 } ${a + b > 10 || a - b > 5 } http://java.sun.com/jsp/jstl/core 包含 Web 应⽤的常⻅⼯作,⽐如:循环、表达式赋值、基本输⼊输出等。 格式化标签库: http://java.sun.com/jsp/jstl/fmt ⽤来格式化显示数据的⼯作,⽐如:对不同区域的⽇期格式化等。 为了在 JSP ⻚⾯使⽤ JSTL 类库,必须以下列格式使⽤ taglib 指令: 例如: 前缀可以是任意内容,遵循规范可以使团队中由不同⼈员编写的代码更加相似;所以,建议使⽤事先 设计好的前缀。 此时需要导⼊两个jar 包 从Apache的标准标签库中下载的⼆进包(jakarta-taglibs-standard-current.zip)。 官⽅下载地址:http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/ 下载 jakarta-taglibs-standard-1.1.2.zip 包并解压,将 jakarta-taglibs-standard-1.1.2/lib/ 下的 两个 jar ⽂件:standard.jar 和 jstl.jar ⽂件拷⻉到项⽬的指定⽬录下。 3.2. 条件动作标签 条件动作指令⽤于处理⻚⾯的输出结果依赖于某些输⼊值的情况,在 Java 中是利⽤ if、 if…else 和 switch 语句来进⾏处理的。在 JSTL 中也有 4 个标签可以执⾏条件式动作指令:if、 choose、when 和 otherwise。 3.2.1. if 标签 if 标签先对某个条件进⾏测试,如果该条件运算结果为 true, 则处理它的主体内容,测试结果保存在 ⼀个 Boolean 对象中,并创建⼀个限域变量来引⽤ Boolean 对象。可以利⽤ var 属性设置限域变量 名,利⽤ scope 属性来指定其作⽤范围。 3.2.1.1. 语法格式 <%@taglib uri="" prefix="" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 属性 描述 是否必要 默认值 test 条件 是 ⽆ var ⽤于存储条件结果的变量(限域变量名) 否 ⽆ scope var属性的作⽤域 可取值:page|request|session|application 否 page 3.2.1.2. 属性 if 标签有如下属性: 3.2.1.3. 示例 注: JSTL中没有else标签,为了模拟 else 的情景,需要使⽤两个 if 标签,并且这两个标签为相反的条 件。 3.2.2. choose、when 和 otherwise 标签 choose 和 when 标签的作⽤与 Java 中的 switch 和 case 关键字相似,⽤于在众多选项中做出选择。 也就是说:他们为相互排斥的条件式执⾏提供相关内容。 switch语句中有case,⽽choose标签中对应有when,switch语句中有default,⽽choose标签中有 otherwise。 3.2.2.1. 语法格式 ... <% request.setAttribute("flag",true); request.setAttribute("num",1); %>

结果为true

num的值⽐0⼤

3.2.2.2. 属性 choose标签没有属性。 when标签只有⼀个test属性。 otherwise标签没有属性。 3.2.2.3. 示例 3.2.2.4. 注意点 choose标签和otherwise标签没有属性,⽽when标签必须设置test属性 choose标签中必须有⾄少⼀个when标签,可以没有otherwise标签 otherwise标签必须放在最后⼀个when标签之后 choose标签中只能有when标签和otherwise标签,when标签和otherwise标签可以嵌套其他标签 otherwise标签在所有的when标签不执⾏的情况下才会执⾏ 3.3. 迭代标签 ... ... ... ... ... <% request.setAttribute("score", 90); %>

你个⼩渣渣!

⾰命尚未成功,同志仍需努⼒!

你很棒棒哦!

属性 描述 是否必要 默认值 items 要被循环的数据 否 ⽆ begin 开始的元素(0=第⼀个元素,1=第⼆个元素) 否 0 end 最后⼀个元素(0=第⼀个元素,1=第⼆个元素) 否 Last element step 每⼀次迭代的步⻓ 否 1 var 代表当前条⽬的变量名称 否 ⽆ varStatus 代表循环状态的变量名称 否 ⽆ forEach 是将⼀个主体内容迭代多次,或者迭代⼀个对象集合。可以迭代的对象包括所有的 java.util.Collection 和 java.util.Map 接⼝的实现,以及对象或者基本类型的数组。他还可 以迭代 java.util.Iterator 和 java.util.Enumeration,但不能在多个动作指令中使⽤ Iterator 或者 Enumeration, 因为 Iterator 或者 Enumeration 都不能重置(reset)。 各属性含义如下: 3.3.1. forEach标签 3.3.1.1. 语法格式 3.3.1.2. 属性 forEach varStatus 属性 index: 当前这次迭代从 0 开始的迭代索引 count: 当前这次迭代从 1 开始的迭代计数 first: ⽤来表明当前这轮迭代是否为第⼀次迭代的标志 last: ⽤来表明当前这轮迭代是否为最后⼀次迭代的标志 3.3.1.3. 示例 1.遍历主体内容多次 相当于java的for循环: for(int i = 0; i < 10; i++) { } 如下: 标题${i }
2.循环

</c:forEach>
相当于java的foreach循环:
for(String str : list) {
}
如下:
<%
List list = new ArrayList();
for (int i = 1; i <= 10; i++) {
list.add(“A:” + i);
}
pageContext.setAttribute(“li”, list);
%>

<c:forEach items="${li }" var=“item”>
${item }
</c:forEach>


名称 当前成员下标 当前成员循环数 是否第⼀次被循环 是否最后⼀次被循环 ${item } ${itemp.index } ${itemp.count } ${itemp.first } ${itemp.last } <% List userList = new ArrayList(); User user = new User(1,"zhangsan","123456"); User user2 = new User(2,"lisi","123321"); User user3 = new User(3,"wangwu","654321"); userList.add(user); userList.add(user2); userList.add(user3); // 将数据设置到作⽤域中 request.setAttribute("userList", userList); %> 属性 描述 是否必要 默认值 value 要显示的数字 是 ⽆ type NUMBER,CURRENCY,或 PERCENT类型 否 Number var 存储格式化数字的变量 否 Print to page scope var属性的作⽤域 否 page 3.4. 格式化动作标签 JSTL 提供了格式化和解析数字和⽇期的标签,我们讨论⾥⾯有:formatNumber、formatDate、 parseNumber及parseDate。 3.4.1. formatNumber标签 formatNumber标签⽤于格式化数字,百分⽐,货币。该标签⽤指定的格式或精度来格式化数字。 (将数值型数据转换成指定格式的字符串类型。) 3.4.1.1. 语法格式 3.4.1.2. 属性 注意: 1. 如果设置了var属性,则格式化后的结果不会输出,需要通过el表达式获取var对应的限域变量名
⽤户编号⽤户名称⽤户密码⽤户操作
${user.userId }${user.uname }${user.upwd } 修改 删除
<% Map

m y D a t e < b r / > < f m t : f o r m a t D a t e v a l u e = " {myDate } <br/> <fmt:formatDate value=" myDate<br/><fmt:formatDatevalue="{myDate }" />

<fmt:formatDate value=" m y D a t e " t y p e = " d a t e " / > < b r / > < f m t : f o r m a t D a t e v a l u e = " {myDate }" type="date"/><br/> <fmt:formatDate value=" myDate"type="date"/><br/><fmt:formatDatevalue="{myDate }" type=“time”/>

<fmt:formatDate value=" m y D a t e " t y p e = " b o t h " / > < b r / > < f m t : f o r m a t D a t e v a l u e = " {myDate }" type="both"/><br/> <fmt:formatDate value=" myDate"type="both"/><br/><fmt:formatDatevalue="{myDate }" type=“both” dateStyle=“full”/>

<fmt:formatDate value=" m y D a t e " t y p e = " b o t h " d a t e S t y l e = " l o n g " / > < b r / > < f m t : f o r m a t D a t e v a l u e = " {myDate }" type="both" dateStyle="long"/><br/> <fmt:formatDate value=" myDate"type="both"dateStyle="long"/><br/><fmt:formatDatevalue="{myDate }" type=“both” dateStyle=“short”/>

<fmt:formatDate value=" m y D a t e " t y p e = " b o t h " t i m e S t y l e = " f u l l " / > < b r / > < f m t : f o r m a t D a t e v a l u e = " {myDate }" type="both" timeStyle="full"/><br/> <fmt:formatDate value=" myDate"type="both"timeStyle="full"/><br/><fmt:formatDatevalue="{myDate }" type=“both” timeStyle=“long”/>

<fmt:formatDate value="${myDate }" pattern=“HH:mm yyyy/MM/dd”/>

属性 描述 是否必要 默认值
value 要解析的数字 否 Body
type NUMBER,,CURRENCY,或 PERCENT 否 number
var 存储待解析数字的变量 否 Print to page
scope var属性的作⽤域 否 page
3.4.3.2. 属性
3.4.3.3. 示例
3.4.4. parseDate标签
parseDate标签⽤于解析⽇期。(将指定格式的字符串转换成Date类型。)
3.4.4.1. 语法格式
3.4.4.2. 属性
<fmt:parseNumber
value=""
type=""
var=""
scope=""/>
<fmt:parseNumber value=“100” />
<fmt:parseNumber value=“100” type=“number” />
<fmt:parseNumber value=“100%” type=“percent” />
<fmt:parseNumber value=“¥10.00” type=“currency” />

<fmt:parseDate
value=""
type=""
dateStyle=""
timeStyle=""
pattern=""
var=""
scope=""/>
属性 描述 是否必要 默认值
value 要显示的⽇期 是 ⽆
type DATE, TIME, 或 BOTH 否 date
dateStyle FULL, LONG, MEDIUM, SHORT, 或 DEFAULT 否 default
timeStyle FULL, LONG, MEDIUM, SHORT, 或 DEFAULT 否 default
pattern ⾃定义格式模式 否 ⽆
var 存储格式化⽇期的变量名 否 显示在⻚⾯
scope 存储格式化⽇志变量的范围 否 ⻚⾯
3.4.4.3. 示例
<fmt:parseDate value=“2020-01-06” type=“date” />
<fmt:parseDate value=“2020/01/06” pattern=“yyyy/MM/dd” />

过滤器和监听器

2. 过滤器

2.1. 介绍

Filter 即为过滤,⽤于在 Servlet 之外对 Request 或者 Response 进⾏修改。它主要⽤于对⽤户请求

进⾏预处理,也可以对 HttpServletResponse 进⾏后处理。使⽤ Filter 的完整流程: Filter 对⽤户请求

进⾏预处理,接着将请求交给 Servlet 进⾏处理并⽣成响应,最后 Filter 再 对服务器响应进⾏后处理。

在⼀个 web 应⽤中,可以开发编写多个 Filter,这些 Filter 组合 起来称之为⼀个 Filter 链。

单个过滤器 多个过滤器

若是⼀个过滤器链:先配置先执⾏(请求时的执⾏顺序);响应时: 以相反的顺序执⾏。

在 HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest 。根据需要检查

HttpServletRequest,也可以修改 HttpServletRequest 头和数据。

在HttpServletResponse 到达客户端之前,拦截 HttpServletResponse。根据需要检查

HttpServletResponse,也可以修改 HttpServletResponse头和数据。2.2. 实现

可以通过实现⼀个叫做javax.servlet.Fileter的接⼝来实现⼀个过滤器,其中定义了 三个⽅法,init(),

doFilter(), destroy()分别在相应的时机执⾏。后期观察⽣命周期。

Filter 的实现只需要两步:

Step1: 编写 java 类实现 Filter 接⼝,并实现其 doFilter ⽅法。

Step2: 通过@WebFilter注解设置它所能拦截的资源。

Filter 接⼝中有⼀个 doFilter ⽅法,当开发⼈员编写好 Filter,并配置对哪个 web 资源进⾏拦截后,

Web 服务器每次在调⽤ web 资源的 service ⽅法之前,都会先调⽤⼀下 fifilter 的 doFilter ⽅法。因此可

以达到如下效果:

调⽤⽬标资源之前,让⼀段代码执⾏。

是否调⽤⽬标资源(即是否让⽤户访问 web 资源)。

web 服务器在调⽤ doFilter ⽅法时,会传递⼀个 fifilterChain 对象进来,fifilterChain 对象是 fifilter 接

⼝中最重要的⼀个对象,它提供了⼀个 doFilter ⽅法,开发⼈员可以根据需求决定 是否调⽤此⽅法,

调⽤该⽅法,则 web 服务器就会调⽤ web 资源的 service ⽅法,即 web 资源就会被访问,否则 web

资源不会被访问。(本质是放⾏,调⽤doFilter⽅法后,即请求可以到达资源)

2.3. 实例

2.3.1. 请求乱码处理

@WebFilter("/*")

public class Filter01 implements Filter {

@Override

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse

servletResponse, FilterChain filterChain) throws IOException, ServletException

{

}

@Override

public void destroy() {

}

}/**

* 字符乱码处理

* 乱码情况:

Tomcat8及以上版本 Tomcat7及以下版本

POST请求 乱码,需要处理 乱码,需要处理

request.setCharacterEncoding(“UTF-8”);

GET请求

不会乱码,不需要处理 乱码,需要处理

new String(request.getParameter(“参数名”).getBytes(“ISO-8859-1”),"UTF-

8");

如何处理:

1、处理POST请求

request.setCharacterEncoding(“UTF-8”);

2、处理GET请求且服务器版本在Tomcat8以下的

1> 得到请求类型 (GET请求)

2> 得到服务器的版本的信息

3> 判断是GET请求且Tomcat版本⼩于8

4> 处理乱码

new String(request.getParameter(“参数名”).getBytes("ISO-8859-

1"),“UTF-8”);

*/

@WebFilter("/*")

public class AEncodingFilter implements Filter {

public AEncodingFilter() {

}

public void destroy() {

}

public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain

chain) throws IOException, ServletException {

// 基于HTTP

HttpServletRequest request = (HttpServletRequest) arg0;

HttpServletResponse response = (HttpServletResponse) arg1;

// 处理请求乱码乱码 (处理POST请求)

request.setCharacterEncoding(“UTF-8”);

// 处理GET请求且服务器版本在Tomcat8以下的

String method = request.getMethod();

// 如果是GET请求

if (“GET”.equalsIgnoreCase(method)) { // 服务器版本在Tomcat8以下的 Apache Tomcat/8.0.45

String serverInfo = request.getServletContext().getServerInfo();

// 得到具体的版本号

String versionStr = serverInfo.substring(serverInfo.indexOf("/")+1,

serverInfo.indexOf("."));

// 判断服务器版本是否⼩于8

if (Integer.parseInt(versionStr) < 8) {

// 得到⾃定义内部类 (MyWapper继承了HttpServletRequestWapper对象,⽽

HttpServletRequestWapper对象实现了HttpServletRequest接⼝,所以MyWapper的本质也是

request对象)

HttpServletRequest myRequest = new MyWapper(request);

// 放⾏资源

chain.doFilter(myRequest, response);

return;

}

}

// 放⾏资源

chain.doFilter(request, response);

}

public void init(FilterConfig fConfig) throws ServletException {

}

/**

* 定义内部类,继承HttpServletRequestWrapper包装类对象,重写getParameter()⽅法

*/

class MyWapper extends HttpServletRequestWrapper {

// 定义成员变量,提升构造器 中的request对象的范围

private HttpServletRequest request;

public MyWapper(HttpServletRequest request) {

super(request);

this.request = request;

}

/**

* 重写getParameter()⽅法

*/

@Override

public String getParameter(String name) {

String value = request.getParameter(name);

if (value != null && !"".equals(value.trim())) {

try {

// 将默认ISO-8859-1编码的字符转换成UTF-82.3.2. ⽤户⾮法访问拦截

value = new String(value.getBytes(“ISO-8859-1”),“UTF-8”);

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

}

return value;

}

}

}

/**

* ⾮法访问拦截(当⽤户未登录时,拦截请求到登录⻚⾯)

* 拦截的资源:

* 拦截所有资源 /*

* 需要被放⾏的资源:

* 不需要登录即可访问的资源

* 1、放⾏指定⻚⾯,不需要登录可以访问的⻚⾯ (例如:登录⻚⾯、注册⻚⾯等)

* 2、放⾏静态资源(例如:css、js、image等资源)

* 3、放⾏指定操作,不需要登录即可执⾏的操作(例如:登录操作、注册操作等)

* 4、登录状态放⾏ (如果存在指定sessuin对象,则为登录状态)

*/

@WebFilter("/*")

public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain

chain) throws IOException, ServletException {

// 基于HTTP

HttpServletRequest request = (HttpServletRequest) arg0;

HttpServletResponse response = (HttpServletResponse) arg1;

// 得到请求的路径

String path = request.getRequestURI(); // 站点名/资源路径

// 1、放⾏指定⻚⾯,不需要登录可以访问的⻚⾯ (例如:登录⻚⾯、注册⻚⾯等)

if (path.contains("/login.jsp") || path.contains("/register.jsp")) {

chain.doFilter(request, response);

return;

}

// 2、放⾏静态资源(例如:css、js、image等资源)

if (path.contains("/js")) {

chain.doFilter(request, response);

return;

}

// 3、放⾏指定操作,不需要登录即可执⾏的操作(例如:登录操作、注册操作等)

if (path.contains("/loginServlet")) {

chain.doFilter(request, response);

return;

}3. 监听器

3.1. 介绍

web 监听器是Servlet 中⼀种的特殊的类,能帮助开发者监听 web 中的特定事件, ⽐如

ServletContext,HttpSession,ServletRequest 的创建和销毁;变量的创建、销毁和修改等。 可以在

某些动作前后增加处理,实现监控。例如可以⽤来统计在线⼈数等。

3.2. 实现

监听器有三类8种:

⑴ 监听⽣命周期:

ServletRequestListener

HttpSessionListener

ServletContextListener

⑵ 监听值的变化:

ServletRequestAttributeListener

HttpSessionAttributeListener

ServletContextAttributeListener

⑶ 针对 session 中的对象:

监听 session 中的 java 对象(javaBean) ,是 javaBean 直接实现监听器 的接⼝。

3.3. 示例

做⼀个对在线⼈数的监控。

// 4、登录状态放⾏ (如果存在指定sessuin对象,则为登录状态)

// 得到session域对象

String uname = (String) request.getSession().getAttribute(“user”);

// 如果session域对象不为空,则为登录状态,放⾏资源

if (uname != null && !"".equals(uname.trim())) {

chain.doFilter(request, response);

return;

}

// 若以上条件均不满⾜,拦截跳转到登录⻚⾯

response.sendRedirect(“login.jsp”);

return;

}实现步骤:

Step1:创建⼀个监听器,需要实现某种接⼝,根据需求选取 HttpSessionListener

Step2:通过@WebListener注解配置该监听器

创建⼀个类,并实现 HttpSessionListener 接⼝,⽤来检测 Session 的创建和销毁。

1.在类中定义⼀个成员变量⽤来存储当前的 session 个数。(OnlineListener.java)

/**

* 在线⼈数统计

* 当有新的session对象被创建,则在线⼈数+1;

* 有session对象被销毁,在线⼈数-1;

* @author Lisa Li

*/

@WebListener

public class OnlineListener implements HttpSessionListener {

// 默认在线⼈数

private Integer onlineNumber = 0;

/**

* 当有新的session对象被创建,则在线⼈数+1;

*/

@Override

public void sessionCreated(HttpSessionEvent se) {

// ⼈数+1

onlineNumber++;

// 将⼈数存到session作⽤域中

// se.getSession().setAttribute(“onlineNumber”, onlineNumber);

// 将⼈数存到application作⽤域中

se.getSession().getServletContext().setAttribute(“onlineNumber”,

onlineNumber);

}

/**

* 有session对象被销毁,在线⼈数-1;

*/

@Override

public void sessionDestroyed(HttpSessionEvent se) {

// ⼈数-1

onlineNumber–;

// 将⼈数存到session作⽤域中

// se.getSession().setAttribute(“onlineNumber”, onlineNumber);

// 将⼈数存到application作⽤域中

se.getSession().getServletContext().setAttribute(“onlineNumber”,

onlineNumber); }

}

2.做⼀个测试的 Servlet ⽤来登录,和显示当前在线⼈数。(OnlineServlet.java)

/**

* 在线⼈数统计

*/

public class OnlineServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void service(HttpServletRequest request, HttpServletResponse

response) throws ServletException, IOException {

// 得到参数

String key = request.getParameter(“key”);

// 判断是否为空 (不为空,且值为logout则为退出操作)

if (key != null && “logout”.equals(key)) {

// 传递了参数,表示要做⽤户退出操作

request.getSession().invalidate();

return;

}

// 创建session对象

HttpSession session = request.getSession();

// 获取sessio作⽤域中的在线⼈数

Integer onlineNumber = (Integer)

session.getServletContext().getAttribute(“onlineNumber”);

// 输出

response.setContentType(“text/html;charset=UTF-8”);

response.getWriter().write(“

在线⼈数:”+onlineNumber+"

<a

href=‘online?key=logout’>退出

");

}

}

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐