想做网站找哪个公司好/时事新闻最新消息
一、EL表达式
-
EL表达式是干什么用的?
-
Expression Language(表达式语言)
-
EL表达式可以代替JSP中的java代码,让JSP文件中的程序看起来更加整洁,美观。
-
JSP中夹杂着各种java代码,例如<% java代码 %>、<%=%>等,导致JSP文件很混乱,不好看,不好维护。所以才有了后期的EL表达式。
-
EL表达式可以算是JSP语法的一部分。EL表达式归属于JSP。
-
-
EL表达式出现在JSP中主要是:
-
-
从某个作用域中取数据,然后将其转换成字符串,然后将其输出到浏览器。这就是EL表达式的功效。三大功效:-
第一功效:从某个域中取数据。
-
四个域:
-
pageContext
-
request
-
session
-
application
-
-
-
第二功效:将取出的数据转成字符串。
-
如果是一个java对象,也会自动调用java对象的toString方法将其转换成字符串。
-
-
第三功效:将字符串输出到浏览器。
-
和这个一样:<%= %>,将其输出到浏览器。
-
-
-
-
EL表达式很好用,基本的语法格式:
-
${表达式}
-
1.EL表达式的使用:
演示代码:
User类
package bean;/*** 符合javabean规范的一个java类。*/
public class User {private String username;private String password;private int age;private Address addr;public Address getAddr222() {return addr;}public void setAddr(Address addr) {this.addr = addr;}/*@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +'}';}*/public User() {}public User(String username, String password, int age) {this.username = username;this.password = password;this.age = age;}public String getUsername() {System.out.println("getUsername()方法执行了");return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {System.out.println("getPassword()方法执行了");return password;}public void setPassword(String password) {this.password = password;}// 或者getage()// java程序员给方法起名的时候,建议驼峰。public int getAge() {System.out.println("getAge()方法执行了");return age;}public void setAge(int age) {this.age = age;}/*** 这个方法只是一个get方法而已。类中并没有声明email属性。* 使用EL表达式可以获取Email吗?* @return*/public String getEmail(){return "dujubin@126.com";}
}
Address类
package bean;public class Address {private String city;private String street;private String zipcode;public Address() {}public Address(String city, String street, String zipcode) {this.city = city;this.street = street;this.zipcode = zipcode;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getStreet() {return street;}public void setStreet(String street) {this.street = street;}public String getZipcode() {return zipcode;}public void setZipcode(String zipcode) {this.zipcode = zipcode;}
}
7.jsp
<%@ page import="bean.User" %>
<%@ page import="bean.Address" %>
<%@page contentType="text/html;charset=UTF-8" %><%// 创建User对象User user = new User();user.setUsername("jackson");user.setPassword("1234");user.setAge(50);// 创建地址Address对象Address a = new Address();a.setCity("北京");a.setStreet("大兴区");a.setZipcode("11111111");user.setAddr(a);// 将User对象存储到request域当中request.setAttribute("userObj", user);
%><%--使用EL表达式,从request域当中,取出User对象,并将其输出到浏览器--%>
<%--1. EL表达式会自动从某个范围中取数据。2. 将其转成字符串。 3. 将其输出到浏览器。--%>
${userObj}<br>
<%--你想输出的是user对象的username属性--%>
${userObj.username}
<br>
<%--输出password--%>
${userObj.password}
<br>
<%--输出年龄age--%>
${userObj.age}
<br>
<%--输出email--%>
${userObj.email}<br>
<%--在EL表达式中不能添加双引号,如果添加了双引号,EL表达式就会将其当做普通的字符串输出到浏览器。--%>
${"userObj"}
userObj<br>
<%--取出User对象是哪个城市的?--%>
城市:${userObj.addr222.city}
街道:${userObj.addr222.street}
邮编:${userObj.addr222.zipcode}
2.EL表达式优先从小范围中读取数据。
-
-
pageContext < request < session < application
-
-
EL表达式中有四个隐含的隐式的范围:
-
pageScope 对应的是 pageContext范围。
-
requestScope 对应的是 request范围。
-
sessionScope 对应的是 session范围。
-
applicationScope 对应的是 application范围。
-
<%@page contentType="text/html;charset=UTF-8" %><%// 四个域都存储了数据,并且name相同。session.setAttribute("data", "session");request.setAttribute("data", "request");pageContext.setAttribute("data", "pageContext");application.setAttribute("data", "application");
%><%--在没有指定范围的前提下,EL表达式优先从小范围中取数据--%>
<%--pageContext < request < session < application --%>
${data}<hr>
<%-- 在EL表达式中可以指定范围来读取数据--%>
<%--EL表达式有4个隐含的隐式的范围对象--%>
<%--pageScope requestScope sessionScope applicationScope--%>
<%--以下是指定范围取数据。--%>
${pageScope.data}<br>
${requestScope.data}<br>
${sessionScope.data}<br>
${applicationScope.data}<br><%--在实际开发中,因为向某个域中存储数据的时候,name都是不同的。所以 xxxScope 都是可以省略的。--%>
3.EL表达式对null进行了预处理。如果是null,则向浏览器输出一个空字符串。
<%@page contentType="text/html;charset=UTF-8" %><%request.setAttribute("username", "zhangsan");
%><%--取出数据并且输出到浏览器--%>
<%=request.getAttribute("username")%><br>采用EL表达式:${username}<br><%=request.getAttribute("usernam")%><br><%--EL表达式主要任务是做页面展示,要求最终页面展示上是友好的。--%>
<%--所以EL表达式对null进行了处理。如果是null,则在浏览器上显示空白。--%>
采用EL表达式:${usernam}<hr>
<%--EL表达式表面上是这种写法,实际上运行的时候,还是要翻译生成java代码的。--%>
${usernam} 这个EL表达式等同于这一段java代码:<%=request.getAttribute("usernam") == null ? "" : request.getAttribute("usernam")%>
4.EL表达式取数据的时候有两种形式:
-
第一种:. (大部分使用这种方式)
-
第二种:[ ] (如果存储到域的时候,这个name中含有特殊字符,可以使用 [ ])
-
request.setAttribute("abc.def", "zhangsan");
-
${requestScope.abc.def} 这样是无法取值的。
-
应该这样:${requestScope["abc.def"]}
-
<%@ page import="bean.User" %>
<%@page contentType="text/html;charset=UTF-8" %><%// 创建user对象User user = new User();user.setUsername("zhangsan");// 存储到request域当中。request.setAttribute("fdsafdsafdsa", user);// 向request域当中存储数据。request.setAttribute("abc.def", "hello jsp el!!!");
%><%--使用EL表达式取出,并且输出到浏览器--%>
<%--从域当中取user--%>
${fdsafdsafdsa}<br><%--取user的username--%>
<%----%>
${fdsafdsafdsa.username}<br><%--取user的username,注意[]当中的需要添加 双引号--%>
<%--[] 里面的没有加双引号的话,会将其看做变量。如果是带双引号 "username",则去找user对象的username属性。--%>
${fdsafdsafdsa["username"]}<br><%--将数据取出并输出到浏览器--%>
${requestScope.abc.def}<br>
之前是空白滴:<br>
${requestScope["abc.def"]}
5.掌握使用EL表达式,怎么从Map集合中取数据:
-
${map.key}
-
掌握使用EL表达式,怎么从数组和List集合中取数据:
-
${数组[0]}
-
${数组[1]}
-
${list[0]}
-
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>EL表达式示例</title>
</head>
<body>
<%// 创建一个Map集合java.util.Map<String, String> map = new java.util.HashMap<>();map.put("key1", "Map中的值1");map.put("key2", "Map中的值2");request.setAttribute("map", map);// 创建一个数组String[] array = {"数组元素1", "数组元素2"};request.setAttribute("array", array);// 创建一个List集合java.util.List<String> list = new java.util.ArrayList<>();list.add("List元素1");list.add("List元素2");request.setAttribute("list", list);
%><h2>从Map集合中取数据</h2>
<p>key1对应的值: ${map.key1}</p>
<p>key2对应的值: ${map.key2}</p><h2>从数组中取数据</h2>
<p>数组第一个元素: ${array[0]}</p>
<p>数组第二个元素: ${array[1]}</p><h2>从List集合中取数据</h2>
<p>List第一个元素: ${list[0]}</p>
<p>List第二个元素: ${list[1]}</p>
</body>
</html>
6.page指令当中,有一个属性,可以忽略EL表达式
<%--<%@page contentType="text/html;charset=UTF-8" isELIgnored="false" %>--%>
<%--<%@page contentType="text/html;charset=UTF-8" %>--%>
<%@page contentType="text/html;charset=UTF-8" isELIgnored="true" %><%request.setAttribute("username", "zhangsan");
%><%-- isELIgnored="true" 表示忽略JSP中整个页面的所有EL表达式。如果想忽略其中某个,可以使用以下反斜杠。 --%>
\${username}
${username}
${username}
<%--<%@page contentType="text/html;charset=UTF-8" isELIgnored="false" %>--%>
<%@page contentType="text/html;charset=UTF-8" %>
<%--<%@page contentType="text/html;charset=UTF-8" isELIgnored="true" %>--%><%request.setAttribute("username", "zhangsan");
%><%-- isELIgnored="true" 表示忽略JSP中整个页面的所有EL表达式。如果想忽略其中某个,可以使用以下反斜杠。 --%>
\${username}
${username}
${username}
7.通过EL表达式获取应用的根:
1. JSP 内置对象
JSP 有九大内置对象,分别是
pageContext
、request
、session
、application
、response
、out
、config
、page
、exception
。其中pageContext
、request
、session
、application
为四个域对象,pageContext
是作用域最小的域对象,代表页面上下文。2.
pageContext
的使用
pageContext.getRequest()
方法可以获取request
对象,但在 JSP 中可以直接使用内置对象request
。pageContext
可用于获取其他内置对象和属性,是一个功能强大的上下文对象。3. EL 表达式隐式对象
- EL 表达式中没有
request
这个隐式对象,requestScope
仅代表 “请求范围”,不等同于request
对象。- EL 表达式中有隐式对象
pageContext
,它和 JSP 中的九大内置对象pageContext
是同一个对象。4. 获取应用根路径
- 在 JSP 中可以通过
((HttpServletRequest)pageContext.getRequest()).getContextPath()
获取应用的根路径。- 在 EL 表达式中可以使用
${pageContext.request.contextPath}
来获取应用的根路径。
-
${pageContext.request.contextPath}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="jakarta.servlet.http.HttpServletRequest" %>
<!DOCTYPE html>
<html>
<head><title>JSP 和 EL 表达式获取应用根路径示例</title>
</head>
<body>
<h2>使用 JSP 代码获取应用根路径</h2>
<p>应用根路径 (JSP 代码): <%=((HttpServletRequest)pageContext.getRequest()).getContextPath() %></p><h2>使用 EL 表达式获取应用根路径</h2>
<p>应用根路径 (EL 表达式): ${pageContext.request.contextPath}</p>
</body>
</html>
- 在 JSP 代码部分,通过
((HttpServletRequest)pageContext.getRequest()).getContextPath()
获取应用的根路径并输出。 - 在 EL 表达式部分,使用
${pageContext.request.contextPath}
获取应用的根路径并输出。
8.EL表达式中其他的隐式对象:
⑴. EL 表达式隐含对象概述
EL(Expression Language)表达式提供了多个隐含对象,这些对象可以简化 JSP 页面中对数据的访问,主要有 pageContext
、param
、paramValues
、initParam
等。
⑵. 各隐含对象的作用
pageContext
- 它代表 JSP 的页面上下文,可用于获取其他 JSP 内置对象和属性。例如,通过
pageContext.request.contextPath
可以获取应用的根路径。
param
- 用于获取请求参数的单个值。当请求中存在同名参数时,
param
只会获取该参数一维数组中的第一个元素。
param 获取的参数来源
param隐式对象用于获取请求参数,具体包括:
URL 中的查询参数(GET 请求):例如 http://localhost:8080/page.jsp?username=lisi 中的 username=lisi。
表单提交的参数(POST 请求):例如表单中 <input type="text" name="password"> 的值。
HTTP 请求头中的参数(较少见,需特殊处理)。
应用场景
param常用于以下场景:
用户登录:获取用户名和密码。
搜索功能:获取用户输入的关键词。
分页参数:获取当前页码或每页显示数量。
动态页面参数:通过 URL 传递 ID(如 http://localhost:8080/article.jsp?id=123)。
<%@page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
<body>
用户名(JSP):<%=request.getParameter("username")%><br>
用户名(EL):${param.username}
</body>
</html>
paramValues
- 用于获取请求参数的所有值,返回一个数组。可以通过索引访问数组中的具体元素。
<%@page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
<body>
<%--假设用户提交的数据:http://localhost:8080/jsp/test.jsp?aihao=smoke&aihao=drink&aihao=tangtou--%>
<%--以上提交的数据显然是采用checkbox进行提交的。同一组的checkbox的name是一样的。--%>
<%--param 获取的是请求参数一维数组当中的第一个元素。--%>
爱好:${param.aihao} <br>
爱好:<%=request.getParameter("aihao")%> <br>一维数组:${paramValues.aihao}<br>
一维数组:<%=request.getParameterValues("aihao")%><br><%--获取数组当中的元素:[下标]--%>
爱好:${paramValues.aihao[0]}、${paramValues.aihao[1]}、${paramValues.aihao[2]} <br>
</body>
</html>
initParam
- 用于获取在
web.xml
中配置的应用初始化参数。这些参数是应用级别的,可通过ServletContext
(在 JSP 中对应的是application
内置对象)获取。
<%@page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
<body>
每页显示记录数(JSP):<%=application.getInitParameter("pageSize")%><br>
每页显示记录数(EL):${initParam.pageSize}<br>
页码(JSP):<%=application.getInitParameter("pageNum")%><br>
页码(EL):${initParam.pageNum}
<br>
<br>
<br>
<%--EL表达式中的隐含对象:initParam--%>
<%--ServletContext是Servlet上下文对象,对应的JSP九大内置对象之一是:application --%>
<%String a = application.getInitParameter("pageSize");String b = application.getInitParameter("pageNum");
%>每页显示的记录条数:<%=a%> <br>
页码:<%=b%> <br>每页显示的记录条数:<%=application.getInitParameter("pageSize")%> <br>
页码:<%=application.getInitParameter("pageNum")%> <br>每页显示的记录条数:${initParam.pageSize} <br>
页码:${initParam.pageNum} <br>
</body>
</html>
⑶. 与 JSP 内置对象的对比
- JSP 有九大内置对象,如
request
、application
等。在获取请求参数和应用初始化参数时,既可以使用 JSP 内置对象的方法,也可以使用 EL 表达式的隐含对象,EL 表达式的使用更加简洁。
9.EL表达式的运算符
⑴. 算术运算符
在 EL 表达式中,算术运算符有 +
、-
、*
、/
、%
。其中 +
只能进行求和运算,不能用于字符串拼接。当 +
两边的数据不是数字时,会尝试将其转换为数字,如果转换失败则会抛出 NumberFormatException
。
⑵. 关系运算符
关系运算符包括 ==
、!=
、>
、>=
、<
、<=
,也可以使用 eq
替代 ==
。在 EL 表达式中,==
和 !=
会调用对象的 equals
方法来比较对象的值是否相等,而不是比较对象的引用。
⑶. 逻辑运算符
逻辑运算符有 !
(取反)、&&
(逻辑与)、||
(逻辑或),也可以使用 not
替代 !
,and
替代 &&
,or
替代 ||
。使用时需要注意逻辑优先级,必要时使用括号来明确运算顺序。
⑷ 条件运算符
条件运算符为 ? :
,其语法为 条件表达式 ? 表达式1 : 表达式2
。如果条件表达式为 true
,则返回表达式 1 的值;否则返回表达式 2 的值。
⑸ 取值运算符
取值运算符有 []
和 .
。[]
通常用于访问数组、列表或映射中的元素,.
用于访问对象的属性或方法。
⑹ empty 运算符
empty
运算符用于判断一个值是否为空,运算结果是 boolean
类型。如果值为空,则结果为 true
;否则为 false
。可以使用 !
或 not
对 empty
运算符的结果取反。
二、JSTL标签库
1.什么是JSTL标签库?
-
Java Standard Tag Lib(Java标准的标签库)
-
JSTL标签库通常结合EL表达式一起使用。目的是让JSP中的java代码消失。
-
标签是写在JSP当中的,但实际上最终还是要执行对应的java程序。(java程序在jar包当中。)
2.使用JSTL标签库的步骤:
-
第一步:引入JSTL标签库对应的jar包。
-
tomcat10之后引入的jar包是:
-
jakarta.servlet.jsp.jstl-2.0.0.jar
-
jakarta.servlet.jsp.jstl-api-2.0.0.jar
-
-
在IDEA当中怎么引入?
-
在WEB-INF下新建lib目录,然后将jar包拷贝到lib当中。然后将其“Add Lib...”
-
一定是要和mysql的数据库驱动一样,都是放在WEB-INF/lib目录下的。
-
什么时候需要将jar包放到WEB-INF/lib目录下?如果这个jar是tomcat服务器没有的。
-
-
maven就是将需要的工件放到WEB-INF/lib目录下
-
第二步:在JSP中引入要使用标签库。(使用taglib指令引入标签库。)
-
JSTL提供了很多种标签,你要引入哪个标签????重点掌握核心标签库。
-
第三步:在需要使用标签的位置使用即可。表面使用的是标签,底层实际上还是java程序。
3.JSTL标签的原理
源码解析:配置文件tld解析
演示代码:
Student类
package bean;import java.util.Objects;public class Student {private String id;private String name;@Overridepublic boolean equals(Object o) {System.out.println("equals方法执行了");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return Objects.equals(id, student.id) && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(id, name);}public Student() {}public Student(String id, String name) {this.id = id;this.name = name;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
17.jsp
<%@ page import="bean.Student" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@page contentType="text/html;charset=UTF-8" %><%--引入标签库。这里引入的是jstl的核心标签库。--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%--格式化标签库,专门负责格式化操作的。--%>
<%--<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>--%><%--sql标签库--%>
<%--<%@taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>--%><%// 创建List集合List<Student> stuList = new ArrayList<>();// 创建Student对象Student s1 = new Student("110", "经常");Student s2 = new Student("120", "救护车");Student s3 = new Student("119", "消防车");// 添加到List集合中stuList.add(s1);stuList.add(s2);stuList.add(s3);// 将list集合存储到request域当中request.setAttribute("stuList", stuList);
%><%--需求:将List集合中的元素遍历。输出学生信息到浏览器--%>
<%--使用java代码--%>
<%// 从域中获取List集合List<Student> stus = (List<Student>)request.getAttribute("stuList");// 编写for循环遍历list集合for(Student stu : stus){
%>id:<%=stu.getId()%>,name:<%=stu.getName()%><br>
<%}
%><hr><%--使用core标签库中forEach标签。对List集合进行遍历--%>
<%--EL表达式只能从域中取数据。--%>
<%--var后面的名字是随意的。var属性代表的是集合中的每一个元素。--%>
<c:forEach items="${stuList}" var="s">id:${s.id},name:${s.name} <br>
</c:forEach>
4.jstl中的核心标签库core当中有哪些常用的标签呢?
-
c:if
-
<c:if test="boolean类型,支持EL表达式"></c: if>
-
-
c:forEach
-
<c:forEach items="集合,支持EL表达式" var="集合中的元素" varStatus="元素状态对象"> ${元素状态对象.count} </c: forEach>
-
<c:forEach var="i" begin="1" end="10" step="2"> ${i} </c: forEach>
-
-
c:choose c:when c:otherwise
⑴.<c:if>
标签
- 功能:
<c:if>
标签用于根据条件判断是否执行标签体内容,类似于 Java 中的if
语句。 - 属性:
test
:必填属性,其值为布尔类型,可以使用 EL 表达式。当test
的值为true
时,执行标签体内容;为false
时,不执行。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>c:if 标签测试</title>
</head>
<body><%int num = 10;request.setAttribute("number", num);%><c:if test="${number > 5}"><p>数字 ${number} 大于 5。</p></c:if>
</body>
</html>
⑵<c:choose>
、<c:when>
和 <c:otherwise>
标签
- 功能:这三个标签组合使用,类似于 Java 中的
if - else if - else
语句,用于进行多条件判断。 - 使用方式:
<c:choose>
作为父标签,包裹<c:when>
和<c:otherwise>
标签。<c:when>
标签可以有多个,每个<c:when>
标签都有一个test
属性,用于指定条件。当某个<c:when>
的test
条件为true
时,执行该标签体内容,并且后续的<c:when>
和<c:otherwise>
标签不再执行。<c:otherwise>
标签是可选的,当所有<c:when>
的条件都为false
时,执行<c:otherwise>
标签体内容。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>c:choose、c:when 和 c:otherwise 标签测试</title>
</head>
<body>
<%int score = 85;request.setAttribute("score", score);
%>
<c:choose><c:when test="${score >= 90}"><p>成绩优秀!</p></c:when><c:when test="${score >= 80}"><p>成绩良好!</p></c:when><c:when test="${score >= 60}"><p>成绩及格!</p></c:when><c:otherwise><p>成绩不及格!</p></c:otherwise>
</c:choose>
</body>
</html>
三、改造OA
-
使用什么技术改造呢?
-
Servlet + JSP + EL表达式 + JSTL标签。进行改造。
-
-
在前端HTML代码中,有一个标签,叫做base标签,这个标签可以设置整个网页的基础路径。
-
这是Java的语法,也不是JSP的语法。是HTML中的一个语法。HTML中的一个标签。通常出现在head标签中。
-
< base href="http://localhost:8080/oa/">
-
在当前页面中,凡是路径没有以“/”开始的,都会自动将base中的路径添加到这些路径之前。
-
< a href="ab/def"></ a>
-
等同于:< a href="http://localhost:8080/oa/ab/def"></ a>
-
-
需要注意:在JS代码中的路径,保险起见,最好不要依赖base标签。JS代码中的路径最好写上全路径。
-
四、Filter过滤器
-
当前的OA项目存在什么缺陷?
-
DeptServlet、EmpServlet、OrderServlet。每一个Servlet都是处理自己相关的业务。在这些Servlet执行之前都是需要判断用户是否登录了。如果用户登录了,可以继续操作,如果没有登录,需要用户登录。这段判断用户是否登录的代码是固定的,并且在每一个Servlet类当中都需要编写,显然代码没有得到重复利用。包括每一个Servlet都要解决中文乱码问题,也有公共的代码。这些代码目前都是重复编写,并没有达到复用。怎么解决这个问题?
-
可以使用Servlet规范中的Filter过滤器来解决这个问题。
-
-
-
Filter是什么,有什么用,执行原理是什么?
-
Filter是过滤器。
-
Filter可以在Servlet这个目标程序执行之前添加代码。也可以在目标Servlet执行之后添加代码。之前之后都可以添加过滤规则。
-
一般情况下,都是在过滤器当中编写公共代码。
-
1.一个过滤器怎么写呢?
-
第一步:编写一个Java类实现一个接口:jarkata.servlet.Filter。并且实现这个接口当中所有的方法。
-
init方法:在Filter对象第一次被创建之后调用,并且只调用一次。
-
doFilter方法:只要用户发送一次请求,则执行一次。发送N次请求,则执行N次。在这个方法中编写过滤规则。
-
destroy方法:在Filter对象被释放/销毁之前调用,并且只调用一次。
-
-
第二步:在web.xml文件中对Filter进行配置。这个配置和Servlet很像。
-
-
-
或者使用注解:@WebFilter({"*.do"})
-
-
-
注意:
-
Servlet对象默认情况下,在服务器启动的时候是不会新建对象的。
-
Filter对象默认情况下,在服务器启动的时候会新建对象。
-
Servlet是单例的。Filter也是单例的。(单实例。)
-
-
目标Servlet是否执行,取决于两个条件:
-
第一:在过滤器当中是否编写了:chain.doFilter(request, response); 代码。
-
第二:用户发送的请求路径是否和Servlet的请求路径一致。
-
-
chain.doFilter(request, response); 这行代码的作用:
-
执行下一个过滤器,如果下面没有过滤器了,执行最终的Servlet。
-
-
注意:Filter的优先级,天生的就比Servlet优先级高。
-
/a.do 对应一个Filter,也对应一个Servlet。那么一定是先执行Filter,然后再执行Servlet。
-
-
关于Filter的配置路径:
-
/a.do、/b.do、/dept/save。这些配置方式都是精确匹配。
-
/* 匹配所有路径。
-
*.do 后缀匹配。不要以 / 开始
-
/dept/* 前缀匹配。
-
-
在web.xml文件中进行配置的时候,Filter的执行顺序是什么?
-
依靠filter-mapping标签的配置位置,越靠上优先级越高。
-
-
过滤器的调用顺序,遵循栈数据结构。
-
使用@WebFilter的时候,Filter的执行顺序是怎样的呢?
-
执行顺序是:比较Filter这个类名。
-
比如:FilterA和FilterB,则先执行FilterA。
-
比如:Filter1和Filter2,则先执行Filter1.
-
-
Filter的生命周期?
-
和Servlet对象生命周期一致。
-
唯一的区别:Filter默认情况下,在服务器启动阶段就实例化。Servlet不会。
-
-
Filter过滤器这里有一个设计模式:
-
责任链设计模式。
-
过滤器最大的优点:
-
在程序编译阶段不会确定调用顺序。因为Filter的调用顺序是配置到web.xml文件中的,只要修改web.xml配置文件中filter-mapping的顺序就可以调整Filter的执行顺序。显然Filter的执行顺序是在程序运行阶段动态组合的。那么这种设计模式被称为责任链设计模式。
-
-
责任链设计模式最大的核心思想:
-
在程序运行阶段,动态的组合程序的调用顺序。
-
-
-
使用过滤器改造OA项目。
五、Listener监听器
1.什么是监听器?
-
监听器是Servlet规范中的一员。就像Filter一样。Filter也是Servlet规范中的一员。
-
在Servlet中,所有的监听器接口都是以“Listener”结尾。
2.监听器有什么用?
-
监听器实际上是Servlet规范留给我们javaweb程序员的特殊时机。
-
特殊的时刻如果想执行这段代码,你需要想到使用对应的监听器。
3.Servlet规范中提供了哪些监听器?
-
HttpSessionListener
-
HttpSessionAttributeListener
-
该监听器需要使用@WebListener注解进行标注。
-
该监听器监听的是什么?是session域中数据的变化。只要数据变化,则执行相应的方法。主要监测点在session域对象上。
-
-
HttpSessionBindingListener
-
该监听器不需要使用@WebListener进行标注。
-
假设User类实现了该监听器,那么User对象在被放入session的时候触发bind事件,User对象从session中删除的时候,触发unbind事件。
-
假设Customer类没有实现该监听器,那么Customer对象放入session或者从session删除的时候,不会触发bind和unbind事件。
-
-
HttpSessionIdListener
-
session的id发生改变的时候,监听器中的唯一一个方法就会被调用。
-
-
HttpSessionActivationListener
-
监听session对象的钝化和活化的。
-
钝化:session对象从内存存储到硬盘文件。
-
活化:从硬盘文件把session恢复到内存。
-
-
实现一个监听器的步骤:以ServletContextListener为例。
-
第一步:编写一个类实现ServletContextListener接口。并且实现里面的方法。
-
void contextInitialized(ServletContextEvent event) void contextDestroyed(ServletContextEvent event)
-
-
第二步:在web.xml文件中对ServletContextListener进行配置,如下:
-
<listener><listener-class>com.bjpowernode.javaweb.listener.MyServletContextListener</listener-class> </listener>
-
当然,第二步也可以不使用配置文件,也可以用注解,例如:@WebListener
-
-
-
注意:所有监听器中的方法都是不需要javaweb程序员调用的,由服务器来负责调用?什么时候被调用呢?
-
当某个特殊的事件发生(特殊的事件发生其实就是某个时机到了。)之后,被web服务器自动调用。
-
-
思考一个业务场景:
-
请编写一个功能,记录该网站实时的在线用户的个数。
-
我们可以通过服务器端有没有分配session对象,因为一个session代表了一个用户。有一个session就代表有一个用户。如果你采用这种逻辑去实现的话,session有多少个,在线用户就有多少个。这种方式的话:HttpSessionListener够用了。session对象只要新建,则count++,然后将count存储到ServletContext域当中,在页面展示在线人数即可。
-
业务发生改变了,只统计登录的用户的在线数量,这个该怎么办?
-
session.setAttribute("user", userObj);
-
用户登录的标志是什么?session中曾经存储过User类型的对象。那么这个时候可以让User类型的对象实现HttpSessionBindingListener监听器,只要User类型对象存储到session域中,则count++,然后将count++存储到ServletContext对象中。页面展示在线人数即可。
-
-
-
实现oa项目中当前登录在线的人数。
-
什么代表着用户登录了?
-
session.setAttribute("user", userObj); User类型的对象只要往session中存储过,表示有新用户登录。
-
-
什么代表着用户退出了?
-
session.removeAttribute("user"); User类型的对象从session域中移除了。
-
或者有可能是session销毁了。(session超时)
-
-
六、oa案例
1.Dept类
package oa.bean;import java.util.Objects;/*** 一个普通的java类,这个java类可以封装零散的数据。代表了一个部门对象。*/
public class Dept {private String deptno;private String dname;private String loc;public Dept() {}public String getDeptno() {return deptno;}public void setDeptno(String deptno) {this.deptno = deptno;}public String getDname() {return dname;}public void setDname(String dname) {this.dname = dname;}public String getLoc() {return loc;}public void setLoc(String loc) {this.loc = loc;}@Overridepublic String toString() {return "Dept{" +"deptno='" + deptno + '\'' +", dname='" + dname + '\'' +", loc='" + loc + '\'' +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Dept dept = (Dept) o;return Objects.equals(deptno, dept.deptno) && Objects.equals(dname, dept.dname) && Objects.equals(loc, dept.loc);}@Overridepublic int hashCode() {return Objects.hash(deptno, dname, loc);}
}
2.User
package oa.bean;import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;public class User implements HttpSessionBindingListener {@Overridepublic void valueBound(HttpSessionBindingEvent event) {// 用户登录了// User类型的对象向session中存放了。// 获取ServletContext对象ServletContext application = event.getSession().getServletContext();// 获取在线人数。Object onlinecount = application.getAttribute("onlinecount");if (onlinecount == null) {application.setAttribute("onlinecount", 1);} else {int count = (Integer)onlinecount;count++;application.setAttribute("onlinecount", count);}}@Overridepublic void valueUnbound(HttpSessionBindingEvent event) {// 用户退出了// User类型的对象从session域中删除了。ServletContext application = event.getSession().getServletContext();Integer onlinecount = (Integer)application.getAttribute("onlinecount");onlinecount--;application.setAttribute("onlinecount", onlinecount);}private String username;private String password;public User() {}public User(String username, String password) {this.username = username;this.password = password;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
3.DBUtil
package oa.utils;import java.sql.*;
import java.util.ResourceBundle;/*** JDBC的工具类*/
public class DBUtil {// 静态变量:在类加载时执行。// 并且是有顺序的。自上而下的顺序。// 属性资源文件绑定private static ResourceBundle bundle = ResourceBundle.getBundle("resources.jdbc");// 根据属性配置文件key获取valueprivate static String driver = bundle.getString("driver");private static String url = bundle.getString("url");private static String user = bundle.getString("user");private static String password = bundle.getString("password");static {// 注册驱动(注册驱动只需要注册一次,放在静态代码块当中。DBUtil类加载的时候执行。)try {// "com.mysql.jdbc.Driver" 是连接数据库的驱动,不能写死。因为以后可能还会连接Oracle数据库。// 如果连接oracle数据库的时候,还需要修改java代码,显然违背了OCP开闭原则。// OCP开闭原则:对扩展开放,对修改关闭。(什么是符合OCP呢?在进行功能扩展的时候,不需要修改java源代码。)//Class.forName("com.mysql.jdbc.Driver");Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 获取数据库连接对象* @return conn 连接对象* @throws SQLException*/public static Connection getConnection() throws SQLException {// 获取连接Connection conn = DriverManager.getConnection(url, user, password);return conn;}/*** 释放资源* @param conn 连接对象* @param ps 数据库操作对象* @param rs 结果集对象*/public static void close(Connection conn, Statement ps, ResultSet rs){if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}
4.DeptServlet
package oa.web.action;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import oa.bean.Dept;
import oa.utils.DBUtil;import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;@WebServlet({"/dept/list", "/dept/detail", "/dept/delete", "/dept/save", "/dept/modify"})
public class DeptServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {/*// post请求乱码问题request.setCharacterEncoding("UTF-8");// 响应中文乱码问题response.setContentType("text/html;charset=UTF-8");*/// 获取session(这个session是不需要新建的)// 只是获取当前session,获取不到这返回null/*HttpSession session = request.getSession(false);if(session != null && session.getAttribute("username") != null){String servletPath = request.getServletPath();if("/dept/list".equals(servletPath)){doList(request, response);}else if("/dept/detail".equals(servletPath)){doDetail(request, response);}else if("/dept/delete".equals(servletPath)){doDel(request, response);}else if("/dept/save".equals(servletPath)){doSave(request, response);}else if("/dept/modify".equals(servletPath)){doModify(request, response);}}else{// 跳转到登录页面//response.sendRedirect("/oa/index.jsp");//response.sendRedirect("/oa");response.sendRedirect(request.getContextPath() + "/index.jsp"); // 访问web站点的根即可,自动找到欢迎页面。}*/String servletPath = request.getServletPath();if("/dept/list".equals(servletPath)){doList(request, response);}else if("/dept/detail".equals(servletPath)){doDetail(request, response);}else if("/dept/delete".equals(servletPath)){doDel(request, response);}else if("/dept/save".equals(servletPath)){doSave(request, response);}else if("/dept/modify".equals(servletPath)){doModify(request, response);}}/*** 保存部门信息* @param request* @param response* @throws ServletException* @throws IOException*/private void doSave(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取部门的信息// 注意乱码问题(Tomcat10不会出现这个问题)request.setCharacterEncoding("UTF-8");String deptno = request.getParameter("deptno");String dname = request.getParameter("dname");String loc = request.getParameter("loc");// 连接数据库执行insert语句Connection conn = null;PreparedStatement ps = null;int count = 0;try {conn = DBUtil.getConnection();String sql = "insert into dept(deptno, dname, loc) values(?,?,?)";ps = conn.prepareStatement(sql);ps.setString(1, deptno);ps.setString(2, dname);ps.setString(3, loc);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(conn, ps, null);}if (count == 1) {response.sendRedirect(request.getContextPath() + "/dept/list");}}/*** 根据部门编号删除部门* @param request* @param response* @throws ServletException* @throws IOException*/private void doDel(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取部门编号String deptno = request.getParameter("deptno");// 连接数据库,删除部门Connection conn = null;PreparedStatement ps = null;int count = 0;try {conn = DBUtil.getConnection();String sql = "delete from dept where deptno = ?";ps = conn.prepareStatement(sql);ps.setString(1, deptno);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(conn, ps, null);}if (count == 1) {// 删除成功// 重定向到列表页面String contextPath = request.getContextPath();response.sendRedirect(contextPath + "/dept/list");}}/*** 根据部门编号获取部门的信息。* @param request* @param response* @throws ServletException* @throws IOException*/private void doDetail(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 创建部门对象Dept dept = new Dept();// 获取部门编号String dno = request.getParameter("dno");// 根据部门编号获取部门信息,将部门信息封装成咖啡豆Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = DBUtil.getConnection();String sql = "select dname, loc from dept where deptno = ?";ps = conn.prepareStatement(sql);ps.setString(1, dno);rs = ps.executeQuery();// 这个结果集当中只有一条数据,不需要while循环if (rs.next()) {String dname = rs.getString("dname");String loc = rs.getString("loc");// 封装对象(创建豆子)dept.setDeptno(dno);dept.setDname(dname);dept.setLoc(loc);}} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(conn, ps, rs);}// 这个豆子只有一个,所以不需要袋子,只需要将这个咖啡豆放到request域当中即可。request.setAttribute("dept", dept);// 转发(不是重定向,因为要跳转到JSP做数据展示)//request.getRequestDispatcher("/detail.jsp").forward(request, response);/*String f = request.getParameter("f");if ("m".equals(f)) {// 转发到修改页面request.getRequestDispatcher("/edit.jsp").forward(request, response);} else if("d".equals(f)){// 转发到详情页面request.getRequestDispatcher("/detail.jsp").forward(request, response);}*/request.getRequestDispatcher("/" + request.getParameter("f") + ".jsp").forward(request, response);}/*** 连接数据库,查询所有的部门信息,将部门信息收集好,然后跳转到JSP做页面展示。* @param request* @param response* @throws ServletException* @throws IOException*/private void doList(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 准备一个容器,用来专门存储部门List<Dept> depts = new ArrayList<>();// 连接数据库,查询所有的部门信息Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {// 获取连接conn = DBUtil.getConnection();// 执行查询语句String sql = "select deptno,dname,loc from dept";ps = conn.prepareStatement(sql);rs = ps.executeQuery();// 遍历结果集while (rs.next()) {// 从结果集中取出。String deptno = rs.getString("deptno");String dname = rs.getString("dname");String loc = rs.getString("loc");// 将以上的零散的数据封装成java对象。Dept dept = new Dept();dept.setDeptno(deptno);dept.setDname(dname);dept.setLoc(loc);// 将部门对象放到list集合当中depts.add(dept);}} catch (SQLException e) {e.printStackTrace();} finally {// 释放资源DBUtil.close(conn, ps, rs);}// 将一个集合放到请求域当中request.setAttribute("deptList", depts);// 转发(不要重定向)request.getRequestDispatcher("/list.jsp").forward(request, response);}/*** 修改部门* @param request* @param response* @throws ServletException* @throws IOException*/private void doModify(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 解决请求体的中文乱码问题。request.setCharacterEncoding("UTF-8");// 获取表单中的数据String deptno = request.getParameter("deptno");String dname = request.getParameter("dname");String loc = request.getParameter("loc");// 连接数据库执行更新语句Connection conn = null;PreparedStatement ps = null;int count = 0;try {conn = DBUtil.getConnection();String sql = "update dept set dname = ?, loc = ? where deptno = ?";ps = conn.prepareStatement(sql);ps.setString(1, dname);ps.setString(2, loc);ps.setString(3, deptno);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(conn, ps, null);}if (count == 1) {response.sendRedirect(request.getContextPath() + "/dept/list");}}
}
5.EmpServlet
package oa.web.action;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;import java.io.IOException;/*** 员工管理的。* 员工管理的前提也是需要先登录。*/
public class EmpServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/*// post请求乱码问题request.setCharacterEncoding("UTF-8");// 响应中文乱码问题response.setContentType("text/html;charset=UTF-8");*/HttpSession session = request.getSession(false);if(session != null && session.getAttribute("username") != null){String servletPath = request.getServletPath();//...}else{response.sendRedirect(request.getContextPath() + "/index.jsp");}}
}
6.OrderServlet
package oa.web.action;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;import java.io.IOException;/*** 处理订单相关业务的类。* 订单处理的前提还是需要先登录,才能处理订单。*/
public class OrderServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/*// post请求乱码问题request.setCharacterEncoding("UTF-8");// 响应中文乱码问题response.setContentType("text/html;charset=UTF-8");*/HttpSession session = request.getSession(false);if(session != null && session.getAttribute("username") != null){String servletPath = request.getServletPath();//...}else{response.sendRedirect(request.getContextPath() + "/index.jsp");}}
}
7.UserServlet
package oa.web.action;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import oa.bean.User;
import oa.utils.DBUtil;import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;// Servlet负责业务的处理
// JSP负责页面的展示。
@WebServlet({"/user/login","/user/exit"})
public class UserServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String servletPath = request.getServletPath();if("/user/login".equals(servletPath)){doLogin(request, response);}else if("/user/exit".equals(servletPath)){doExit(request, response);}}protected void doExit(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取session对象,销毁sessionHttpSession session = request.getSession(false);if (session != null) {// 从session域中删除user对象session.removeAttribute("user");// 手动销毁session对象。session.invalidate();// 销毁cookie(退出系统将所有的cookie全部销毁)Cookie[] cookies = request.getCookies();if (cookies != null) {for (Cookie cookie : cookies) {// 设置cookie的有效期为0,表示删除该cookiecookie.setMaxAge(0);// 设置一个下cookie的路径cookie.setPath(request.getContextPath()); // 删除cookie的时候注意路径问题。// 响应cookie给浏览器,浏览器端会将之前的cookie覆盖。response.addCookie(cookie);}}// 换一种方案/*Cookie cookie1 = new Cookie("username","");cookie1.setMaxAge(0);cookie1.setPath(request.getContextPath());Cookie cookie2 = new Cookie("password", "");cookie2.setMaxAge(0);cookie2.setPath(request.getContextPath());response.addCookie(cookie1);response.addCookie(cookie2);*/// 跳转到登录页面response.sendRedirect(request.getContextPath());}}protected void doLogin(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {boolean success = false;// 你要做一件什么事儿?验证用户名和密码是否正确。// 获取用户名和密码// 前端你是这样提交的:username=admin&password=123String username = request.getParameter("username");String password = request.getParameter("password");// 连接数据库验证用户名和密码Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = DBUtil.getConnection();String sql = "select * from t_user where username = ? and password = ?";// 编译SQLps = conn.prepareStatement(sql);// 给?传值ps.setString(1, username);ps.setString(2, password);// 执行SQLrs = ps.executeQuery();// 这个结果集当中最多只有一条数据。if (rs.next()) { // 不需要while循环// 登录成功success = true;}} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(conn, ps, rs);}// 登录成功/失败if (success) {// 获取session对象(这里的要求是:必须获取到session,没有session也要新建一个session对象。)HttpSession session = request.getSession(); // session对象一定不是null//session.setAttribute("username", username);User user = new User(username, password);session.setAttribute("user", user);// 登录成功了,并且用户确实选择了“十天内免登录”功能。String f = request.getParameter("f");if("1".equals(f)){// 创建Cookie对象存储登录名Cookie cookie1 = new Cookie("username", username);// 创建Cookie对象存储密码Cookie cookie2 = new Cookie("password", password); // 真实情况下是加密的。// 设置cookie的有效期为十天cookie1.setMaxAge(60 * 60 * 24 * 10);cookie2.setMaxAge(60 * 60 * 24 * 10);// 设置cookie的path(只要访问这个应用,浏览器就一定要携带这两个cookie)cookie1.setPath(request.getContextPath());cookie2.setPath(request.getContextPath());// 响应cookie给浏览器response.addCookie(cookie1);response.addCookie(cookie2);}// 成功,跳转到用户列表页面response.sendRedirect(request.getContextPath() + "/dept/list");} else {// 失败,跳转到失败页面response.sendRedirect(request.getContextPath() + "/error.jsp");}}
}
8.WelcomeServlet
package oa.web.action;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import oa.bean.User;
import oa.utils.DBUtil;import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;@WebServlet("/welcome")
public class WelcomeServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取cookie// 这个Cookie[]数组可能是null,如果不是null,数组的长度一定是大于0的。Cookie[] cookies = request.getCookies();String username = null;String password = null;if (cookies != null) {for (Cookie cookie : cookies) {String name = cookie.getName();if("username".equals(name)){username = cookie.getValue();}else if("password".equals(name)){password = cookie.getValue();}}}// 要在这里使用username和password变量if(username != null && password != null){// 验证用户名和密码是否正确Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;boolean success = false;try {conn = DBUtil.getConnection();String sql = "select * from t_user where username = ? and password = ?";ps = conn.prepareStatement(sql);ps.setString(1,username);ps.setString(2,password);rs = ps.executeQuery();if (rs.next()) {// 登录成功success = true;}} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(conn, ps, rs);}if (success) {// 获取sessionHttpSession session = request.getSession();//session.setAttribute("username", username);User user = new User(username, password);session.setAttribute("user", user);// 正确,表示登录成功response.sendRedirect(request.getContextPath() + "/dept/list");}else{// 错误,表示登录失败response.sendRedirect(request.getContextPath() + "/index.jsp");}}else{// 跳转到登录页面response.sendRedirect(request.getContextPath() + "/index.jsp");}}
}
9.LoginCheckFilter
package oa.web.filter;import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;import java.io.IOException;public class LoginCheckFilter implements Filter {@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throws IOException, ServletException {/*** 什么情况下不能拦截?* 目前写的路径是:/* 表示所有的请求均拦截。** 用户访问 index.jsp的时候不能拦截* 用户已经登录了,这个需要放行,不能拦截。* 用户要去登录,这个也不能拦截。* WelcomeServlet也不能拦截。*/HttpServletRequest request = (HttpServletRequest)req;HttpServletResponse response = (HttpServletResponse) resp;// 获取请求路径String servletPath = request.getServletPath();HttpSession session = request.getSession(false);/*if("/index.jsp".equals(servletPath) || "/welcome".equals(servletPath) ||"/user/login".equals(servletPath) || "/user/exit".equals(servletPath)|| (session != null && session.getAttribute("username") != null)){*/if("/index.jsp".equals(servletPath) || "/welcome".equals(servletPath) ||"/user/login".equals(servletPath) || "/user/exit".equals(servletPath)|| (session != null && session.getAttribute("user") != null)){// 继续往下走chain.doFilter(request, response);}else{response.sendRedirect(request.getContextPath() + "/index.jsp");}}
}
10.add.jsp
<%@page contentType="text/html;charset=UTF-8"%><!DOCTYPE html>
<html><head><meta charset="utf-8"><title>新增部门</title></head><body><h3>欢迎${username},在线人数${onlinecount}人</h3><h1>新增部门</h1><hr ><form action="${pageContext.request.contextPath}/dept/save" method="post">部门编号<input type="text" name="deptno"/><br>部门名称<input type="text" name="dname"/><br>部门位置<input type="text" name="loc"/><br><input type="submit" value="保存"/><br></form></body>
</html>
11.detail.jsp
<%@page contentType="text/html;charset=UTF-8"%><!DOCTYPE html>
<html><head><meta charset="utf-8"><title>部门详情</title></head><body><h3>欢迎${username},在线人数${onlinecount}人</h3><h1>部门详情</h1><hr >部门编号:${dept.deptno} <br>部门名称:${dept.dname}<br>部门位置:${dept.loc}<br><input type="button" value="后退" onclick="window.history.back()"/></body>
</html>
12.edit.jsp
<%@page contentType="text/html;charset=UTF-8"%><!DOCTYPE html>
<html><head><meta charset="utf-8"><title>修改部门</title></head><body><h3>欢迎${username},在线人数${onlinecount}人</h3><h1>修改部门</h1><hr ><form action="${pageContext.request.contextPath}/dept/modify" method="post">部门编号<input type="text" name="deptno" value="${dept.deptno}" readonly /><br>部门名称<input type="text" name="dname" value="${dept.dname}"/><br>部门位置<input type="text" name="loc" value="${dept.loc}"/><br><input type="submit" value="修改"/><br></form></body>
</html>
13.error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录失败</title>
</head>
<body>
登录失败,请<a href="${pageContext.request.contextPath}/index.jsp">重新登录</a>
</body>
</html>
14.index.jsp
<%@page contentType="text/html;charset=UTF-8"%>
<%--访问jsp的时候不生成session对象。--%>
<%@page session="false" %><!DOCTYPE html>
<html><head><meta charset="utf-8"><title>欢迎使用OA系统</title></head><body><%-- 前端发送请求路径的时候,如果请求路径是绝对路径,要以 / 开始,加项目名。--%><%-- 以下这样写代码,oa项目名写死了。这种设计显然是不好的。--%><%--<a href="/oa/list.jsp">查看部门列表</a>--%><%--注意空格的问题。--%><%--<a href="<%=request.getContextPath() %>/list.jsp">查看部门列表</a>--%><%-- 执行一个Servlet,查询数据库,收集数据。--%><%--<a href="<%=request.getContextPath() %>/dept/list">查看部门列表</a>--%><%--<hr>--%><%--调用哪个对象的哪个方法,可以动态的获取一个应用的根路径。--%><%--<%=request.getContextPath() %>--%> <%-- out.print(request.getContextPath()); --%><h1>LOGIN PAGE</h1><hr><%--前端页面发送请求的时候,请求路径以“/”开始,带项目名。--%><form action="${pageContext.request.contextPath}/user/login" method="post">username: <input type="text" name="username" ><br>password: <input type="password" name="password"><br><input type="checkbox" name="f" value="1">十天内免登录<br><input type="submit" value="login"></form></body>
</html>
15.list.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html;charset=UTF-8"%><!DOCTYPE html>
<html><head><meta charset="utf-8"><title>部门列表页面</title><%--设置整个网页的基础路径是:http://localhost:8080/oa/ --%><%--<base href="http://localhost:8080/oa/">--%><base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"></head><body><h3>欢迎${username},在线人数${onlinecount}人</h3><a href="user/exit">[退出系统]</a><script type="text/javascript">function del(dno){var ok = window.confirm("亲,删了不可恢复哦!");if(ok){/*注意html的base标签可能对JS代码不起作用。所以JS代码最好前面写上"/oa" */document.location.href = "${pageContext.request.contextPath}/dept/delete?deptno=" + dno;}}
</script><h1 align="center">部门列表</h1><hr ><table border="1px" align="center" width="50%"><tr><th>序号</th><th>部门编号</th><th>部门名称</th><th>操作</th></tr><c:forEach items="${deptList}" varStatus="deptStatus" var="dept"><tr><td>${deptStatus.count}</td><td>${dept.deptno}</td><td>${dept.dname}</td><td><a href="javascript:void(0)" onclick="del(${dept.deptno})">删除</a><a href="dept/detail?f=edit&dno=${dept.deptno}">修改</a><a href="dept/detail?f=detail&dno=${dept.deptno}">详情</a></td></tr></c:forEach></table><hr ><a href="add.jsp">新增部门</a></body>
</html>