EL和JSTL补充
EL表达式
- 测试代码
- 1.创建一 个web项目。
- 2.在web目录下创建el01.jsp.
- 3.在文件中向域对象添加数据。
- 4.使用三种方式获取域对象中的数据(java代码块、JSP表达式、 EL 表达式)。
- 5.部署并启动项目。
- 6.通过浏览器测试。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL测试</title>
</head>
<body>
<%-- 向域对象中添加数据---%>
<% request.setAttribute("username","zihas"); %>
<%--获取数据--%>
Java代码块:<% out.println(request.getAttribute("username"));%><br>
JSP表达式:<%= request.getAttribute("username")%><br>
<%-- 通过el表达式这种获取数据的方式,不需要去区分是哪一个域对象,
只要是四大域中有这个数据,叫做username的就能够获取出来。
获取数据也是根据作用域范围获取的,如果有就获取出来,如果没有就获取不到--%>
EL表达式:${username}
</body>
</html>
/*
Java代码块:zihas
JSP表达式:zihas
EL表达式:zihas
*/
通过上面的测试可以知道,通过el表达式获取数据最简单,el表达式获取数据的方式并不需要关心是哪一个域对象
El表达式获取数据
1.获取基本数据类型的数据。
2.获取自定义对象类型的数据。
3.获取数组类型的数据。
4.获取List集合类型的数据。
5.获取Map集合类型的数据。
基本数据类型
1.获取基本数据类型的数据。
<%--1.获取基本数据类型--%>
<% pageContext.setAttribute("num",10); %>
自定义对象类型
2.获取自定义对象类型的数据。
<%
Student1 stu = new Student1("王五",18,98);
pageContext.setAttribute("stu",stu);
%>
自定义数据对象数据:${sut}<br>
<%-- stu.username实现原理:它拿到的是username的成员变量,
根据username这个成员变量去调用getUsername()方法--%>
获取自定义对象的属性值:<br>
学生姓名:${stu.username}<br>
学生年龄:${stu.age}<br>
学生成绩:${stu.score}<br>
数组类型
3.获取数组类型的数据。
<%--3.获取数组类型--%>
<%
String[] arr = {"hello","jsp"};
pageContext.setAttribute("arr",arr);
%>
获取数组:${arr}<br>
获取数组元素:<br>
0索引元素:${arr[0]}<br>
1索引元素:${arr[1]}<br>
List集合类型
4.获取List集合类型的数据。
<%--4.获取List集合--%>
<%
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa1");
pageContext.setAttribute("list",list);
%>
<%-- 为什么list集合直接输出元素内容不是地址:因为list集合已经重写了toString方法--%>
List集合:${list}<br>
获取元素:<br>
0索引元素:${list[0]}<br>
1索引元素:${list[1]}<br>
Map集合类型
5.获取Map集合类型的数据。
<%--5.获取Map集合--%>
<%
HashMap<String,Student1> map = new HashMap<>();
map.put("stu01",new Student1("王五",18,98));
map.put("stu02",new Student1("赵六",16,8));
pageContext.setAttribute("map",map);
%>
Map集合:${map}<br>
<%-- 直接通过map加上键就行了,但是调用时键名的首字母不能是数字,因为这样会报错--%>
第一个学生对象:${map.stu01}<br>
第一个学生对象的具体属性值的名字:${map.stu01.username}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL测试</title>
</head>
<body>
<%--1.获取基本数据类型--%>
<% pageContext.setAttribute("num",10); %>
基本数据类型:${num}<br>
<%--2.获取自定义对象类型--%>
<%
Student1 stu = new Student1("王五",18,98);
pageContext.setAttribute("stu",stu);
%>
自定义数据对象数据:${sut}<br>
<%-- stu.username实现原理:它拿到的是username的成员变量,
根据username这个成员变量去调用getUsername()方法--%>
获取自定义对象的属性值:<br>
学生姓名:${stu.username}<br>
学生年龄:${stu.age}<br>
学生成绩:${stu.score}<br>
<%--3.获取数组类型--%>
<%
String[] arr = {"hello","jsp"};
pageContext.setAttribute("arr",arr);
%>
获取数组:${arr}<br>
获取数组元素:<br>
0索引元素:${arr[0]}<br>
1索引元素:${arr[1]}<br>
<%--4.获取List集合--%>
<%
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa1");
pageContext.setAttribute("list",list);
%>
<%-- 为什么list集合直接输出元素内容不是地址:因为list集合已经重写了toString方法--%>
List集合:${list}<br>
获取元素:<br>
0索引元素:${list[0]}<br>
1索引元素:${list[1]}<br>
<%--5.获取Map集合--%>
<%
HashMap<String,Student1> map = new HashMap<>();
map.put("stu01",new Student1("王五",18,98));
map.put("stu02",new Student1("赵六",16,8));
pageContext.setAttribute("map",map);
%>
Map集合:${map}<br>
<%-- 直接通过map加上键就行了,但是调用时键名的首字母不能是数字,因为这样会报错--%>
第一个学生对象:${map.stu01}<br>
第一个学生对象的具体属性值的名字:${map.stu01.username}
</body>
</html>
<%--
基本数据类型:10
自定义数据对象数据:
获取自定义对象的属性值:
学生姓名:王五
学生年龄:18
学生成绩:98
获取数组:[Ljava.lang.String;@6c16f64c
获取数组元素:
0索引元素:hello
1索引元素:jsp
List集合:[aaa, aaa1]
获取元素:
0索引元素:aaa
1索引元素:aaa1
Map集合:{stu02=Student1{username='赵六', age=16, score=8}, stu01=Student1{username='王五', age=18, score=98}}
第一个学生对象:Student1{username='王五', age=18, score=98}
第一个学生对象的具体属性值的名字:王五
--%>
El表达式注意事项
-
EL表达式没有空指针异常。
-
EL表达式没有索引越界异常
-
EL表达式没有字符串的拼接。
即通过+号可以实现拼接是不能实现的
EL表达式运算符
关系运算符
逻辑运算符
其他运算符
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL测试</title>
</head>
<body>
<%
String str1 =null;
String str2 = "";
int[] srr = {};
%>
${empty str1}<br>
${empty str2}<br>
${empty arr}<br>
</body>
</html>
<%--
true
true
true
--%>
<%-- 获取性别的数据,在对应的按钮上进行勾选---%>
<% pageContext.setAttribute("gender","men");%>
<input type="radio" name="gender" value="men" ${gender == "men"? "checked":""}>男<br>
<input type="radio" name="gender" value="women" ${gender == "women"? "checked":""}>女<br>
<%-- 页面上男被默认选中---%>
EL表达式细节
- EL表达式能够获取四大域对象的数据,根据名称从小到大在域对象中查找。
- 还可以获取JSP其他八个隐式对象,并调用对象中的方法。
EL表达式隐式对象
<%@ page import="com.yy.bean.Student1" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %><%--
Created by IntelliJ IDEA.
User: yyadmin
Date: 2021/8/31
Time: 8:17
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL测试</title>
</head>
<body>
<%-- pageContext对象 可以获取其他三个域对象和JSP中八个隐式对象--%>
${pageContext.request.contextPath}<br>
<%-- /demo--%>
<%-- applicationScope sessionScope requestScope pageScope 操作四大域对象中的数据--%>
<% request.setAttribute("username","yyds");%>
<%-- 从四大域对象中逐个获取 --%>
${username}<br>
<%-- 直接从请求域中获取属性 --%>
${requestScope.username}<br>
<%--
yyds
yyds
--%>
<%--header headerValues 获取请求头数据一--%>
<%-- 获取一个头数据对象--%>
${header["connection"]}<br>
<%-- 获取多个数据,数据保存在数组中--%>
${headerValues["connection"][0]}<br>
<%--
keep-alive
keep-alive
--%>
<%--param paramValues 获取请求参数数据--%>
<%-- 获取一个值--%>
${param.username}
<%-- 获取多个值--%>
${paramValues.hobby[0]}<br>
${paramValues.hobby[1]}<br>
<%--
http://localhost/demo/el01.jsp?username=hiasd&hobby=game&hobby=study
hiasd game
study
--%>
<%--initParam 获取全局配置参数- --%>
${initParam["pname"]}<br>
<%--cookie 获取cookie信息--%>
<%-- 直接获取cookie,输出的是一个map集合--%>
${cookie}<br>
<%--获取map集合中具体内容:第二个元素,这是一个内存地址值--%>
${cookie.JSESSIONID}<br>
<%--获取具体的值--%>
<%-- 获取name值--%>
${cookie.JSESSIONID.name}<br>
${cookie.JSESSIONID.value}<br>
<%--
{Idea-aafc89f8=javax.servlet.http.Cookie@42211397, JSESSIONID=javax.servlet.http.Cookie@33104a4a}
javax.servlet.http.Cookie@33104a4a
JSESSIONID
5827C2B2CAD405F91E72D153B4E1ACB2
--%>
</body>
</html>
JSTL
主要是通过一些标签对EL进行增强的使用
- JSTLJava Server Pages Standarded Tag Library) : JSP标准标签库。
- 主要提供给开发人员一个标准通用的标签库。
- 开发人员可以利用这些标签取代JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。
JSTL核心标签库
使用
-
1.创建–个web项目。
-
2.在web目录下创建一个WEB-INF 目录。
-
3.在WEB-INF目录下创建一 个libs眼,将JSTL的jar包导入。
-
4.创建JSP文件,通过taglib导入JSTL标签库。
-
5.对流程控制和迭代遍历的标签进行使用。
-
6.部署并启动项目。
-
7.通过浏览器查看。
-
单条件判断
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--4.创建JSP文件,通过taglib导入JSTL标签库。--%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>流程控制</title>
</head>
<body>
<%-- 像域对象中添加成绩数据--%>
${pageContext.setAttribute("score","A")}
<%--对成绩进行判断--%>
<c:if test="${score eq 'A'}">
优秀
</c:if>
</body>
</html>
- 多条件判断
<%-- 像域对象中添加成绩数据--%>
${pageContext.setAttribute("score","A")}
<%--对成绩进行判断--%>
<c:choose>
<c:when test="${score eq 'A'}">优秀1</c:when>
<c:when test="${score eq 'B'}">优秀2</c:when>
<c:when test="${score eq 'C'}">优秀3</c:when>
<c:when test="${score eq 'D'}">优秀4</c:when>
<c:otherwise>成绩不合法</c:otherwise>
</c:choose>
- 遍历
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--4.创建JSP文件,通过taglib导入JSTL标签库。--%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>流程控制</title>
</head>
<body>
<%-- 像域对象中添加集合数据--%>
<%
ArrayList<String> l = new ArrayList<>();
l.add("a1");
l.add("a2");
l.add("a3");
l.add("a4");
pageContext.setAttribute("list",l);
%>
<%--遍历集合--%>
<c:forEach items="${list}" var="str">
${str}<br>
</c:forEach>
</body>
</html>
<%--
a1
a2
a3
a4
--%>
Filter
过滤器
- 在程序中访问服务器资源时,当一个请求到来 ,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成些特定的功能,再由过滤器决定是否交给请求资源。如果没有则像之前那样直接请求资源了。响应也是类似的!
在程序中如果想要实现过滤器的功能,就要使用Filter,它是一个接口
核心功能:Filter是一个对象,这个对象可以过滤请求或者是想要的资源
实现Filter这个接口过后,如果想要执行一些核心的方法或者是过滤的功能,就需要在doFilter这个方法里面去实现过滤的功能,每一个过滤器都可以访问FilterConfig这样的一个对象,这是过滤器的一个配置对象,可以借助它去配置一些过滤器的初始化参数
在过滤器当中也可以去访问ServletContext,应用上下文对象
实现好过后,还需要去进行一次配置,有两种方式
总结:
-
Filter是一个接口。如果想实现过滤器的功能,必须实现该接口!
-
核心方法
-
配置方式
- 注解方式
- 配置文件
FilterChain
代表过滤器链对象,过滤器可以定义很多个,如果有多个过滤器对象就会组成过滤器链
它是一个接口,但是不需要我们去实现,真正的实现类对象是由Servlet容器了实现的
放行需要去调用FilterChain里面的doFilter()方法
总结
-
FilterChain是一个接口 ,代表过滤器链对象。由Servlet容器提供实现类对象。直接使用即可。
-
过滤器可以定义多个,就会组成过滤器链。
-
核心方法
如果有多个过滤器,在第一个过滤器中调用下一个过滤器,依次类推。直到到达最终访问资源。
如果只有一个过滤器,放行时,就会直接到达最终访问资源。
使用
- 需求说明
- 通过Filter 过滤器解决多个资源写出中文乱码的问题。
- 最终目的
- 通过本需求,最终掌握Filter过滤器的使用。
- 实现步骤
- 1.创建一个web项目。
- 2.创建两个Servlet功能类,都向客户端写出中文数据。
- 3.创建一个Filter过滤器实现类,写doFilter核心方法。
- 4.在方法内解决中文乱码,并放行。
- 5.部署并启动项目。
- 6.通过浏览器测试。
// /*:所有的请求都会被拦截下来
// /Fd1 具体的拦截路径,只有FiletDemo1这个Servlet会被拦截
// 里面的内容必须是正确@WebServlet里面的路径
@WebFilter("/*")
public class Filter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter1执行了。。。");
//处理乱码
servletResponse.setContentType("text/html;charset=UTF-8");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
@WebServlet("/Fd1")
public class FiletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo1执行了。。。");
resp.getWriter().write("demo1执行了");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
执行过程:
当浏览器访问这个资源路径,这个资源就会被过滤器所拦截下来,拦截下来过后执行doFilter方法,执行doFilter方法放行过后,就会把这个请求交给FiletDemo1,然后才会执行这个功能类里面相应的内容,在执行放行方法时,请求对象和响应对象进行传递了,所以在功能类中就能接收的请求和响应对象,而响应对象在过滤器中已经执行过中文乱码问题了,所以才不会出现乱码问题
处理一些通有的处理
过滤器使用细节
配置文件方式,是在web.xml文件配置
-
多个过滤器的使用
如果有多个过滤器,取决于过滤器映射的顺序
过滤器生命周期
- 创建
当应用加载时实例化对象并执行init初始化方法。 - 服务
对象提供服务的过程,执行doFilter方法。 - 销毁
当应用卸载时或服务器停止时对象销毁。执行destroy方法。
FilterConfig
初始化参数的配置对象,是一个接口
总结:
-
FilterConfig是一个接口。 代表过滤器的配置对象,可以加载-些初始化参数。
-
核心方法
过滤器五种拦截行为
-
Filter过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调用的全局错误页面。默认情况下过滤器是不参与过滤的, 要想使用, 就需要我们配置
-
拦截方式
Servlet里面执行的包含就是动态包含
Listener
监听器:
-
观察者设计模式,所有的监听器都是基于观察者设计模式的!
-
三个组成部分
- 事件源:触发事件的对象
- 事件:触发的动作,封装了事件源
- 监听器:当事件源触发事件后,可以完成功能
-
在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听。
-
Servlet规范中共计8个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成。
监听对象的监听器
-
ServletContextListener :用于监听ServletContext对象的创建和销毁
-
核心方法
-
参数: ServletContextEvent代表事件对象
- 事件对象中封装了事件源,也就是ServletContext
- 真正的事件指的是创建或销毁ServletContext对象的操作
-
HttpSessionListener :于监听HttpSession对象的创建和销毁
-
核心方法
-
参数: HttpSessionEvent代表事件对象
- 事件对象中封装了事件源,也就是HttpSession
- 真正的事件指的是创建或销毁HttpSession对象的操作
-
ServletRequestListener :用于监听ServletRequest对象的创建和销毁,
-
核心方法
- 参数: ServletRequestEvent代表事件对象
- 事件对象中封装了事件源,也就是ServletRequest
- 真正的事件指的是创建或销毁ServletRequest对象的操作
监听域对象属性变化的监听器
- ServletContextAttributeListener :于监听ServletContext应用域中属性的变化
- 核心方法
-
参数: ServletContextAttributeEvent代表事件对象
- 事件对象中封装了事件源,也就是ServletContext
- 真正的事件指的是添加、移除、替换应用域中属性的操作
-
HttpSessionAttributeListener :用于监听HttpSession会话域中属性的变化
-
核心方法
-
参数: HttpSessionBindingEvent代表事件对象
- 事件对象中封装了事件源,也就是HttpSession
- 真正的事件指的是添加、移除、替换会话域中属性的操作
-
ServletRequestAttributeListener :于监听ServletRequest请求域中属性的变化
-
核心方法
- 参数: ServletRequestAttributeEvent代表事件对象
- 事件对象中封装了事件源,也就是ServletRequest
- 真正的事件指的是添加、移除、替换请求域中属性的操作
监听会话相关的感知型监听器
感知型监听器:只要定义好就能够直接使用,并不需要进行一些相关的配置
-
HttpSessionBindingListener :用于感知对象和会话域绑定的监听器
- 绑定:就是针对会话域当中数据的变化,包括添加和移除数据
-
核心方法
-
参数: HttpSessionBindingEvent代表事件对象
- 事件对象中封装了事件源,也就是HttpSession
- 真正的事件指的是添加、移除会话域中数据的操作
-
HttpSessionActivationListener :于感知会话域中对象钝化和活化的监听器
- 钝化:序列化,持久化
- 活化:就它的一个正常的状态
-
核心方法
- 参数: HttpSessionEvent代表事件对象
- 事件对象中封装了事件源,也就是HttpSession
- 真正的事件指的是会话域中数据钝化、活化的操作
使用
通过配置文件或注解
配置文件:
- ServletContextListener与剩下的两个监听对象的类似
@WebListener
public class ServletContextListenerDemo implements ServletContextListener {
/*
ServletContext对像创建的时候执行此方法
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的创建...");
//获取对象
ServletContext servletContext = servletContextEvent.getServletContext();
System.out.println(servletContext);
}
/*
ServletContext对象销毁的时候执行此方法
*/
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的销毁...");
}
}
- ServletContextAttributeListener
@WebListener
public class ServletContextAttributeListenerDemo implements ServletContextAttributeListener {
//向应用域对象中添加属性时执行此方法
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到属性的添加");
// 获取应用域对象
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
//获取属性
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
//向应用域对象中移除属性时执行此方法
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到属性的移除");
// 获取应用域对象
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
//获取属性
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
//向应用域对象中替换属性时执行此方法
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到属性的替换");
// 获取应用域对象
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
//获取属性
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
}
优化上面的管理系统
解决乱码
使用过滤器实现所有资源的编码统一
@WebListener("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//解决乱码问题
//将请求和响应对象转换为和HTTP协议相关的对象
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//设置编码格式
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
}
@Override
public void destroy() {
}
}
检查登录
使用过滤器实现校验是否登录问题。
@WebFilter(value = {"/addStudent.jsp","/listStudentServlet"})
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//解决乱码问题
//将请求和响应对象转换为和HTTP协议相关的对象
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//获取回话域对象中的数据
Object username = request.getSession().getAttribute("username");
//判断用户名
if (username==null || "".equals(username)){
//重定向到登录页面
response.sendRedirect(request.getContextPath()+"/login.jsp");
return;
}
//放行
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
优化JSP页面
通过EL表达式和JSTL替换之前的Java代码块和JSP表达式
- addStudent.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加学生</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/addStudentServlet" method="get" autocomplete="off">
学生姓名:<input type="text" name="username"><br>
学生年龄:<input type="number" name="age"><br>
学生成绩:<input type="number" name="score"><br>
<button type="submit">保存</button>
</form>
</body>
</html>
- login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>学生登录</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/loginStudentServlet" method="get" autocomplete="off">
姓名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<button type="submit">登录</button>
</form>
</body>
</html>
- listStudent.jsp
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.yy.bean.Student1" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>查看学生</title>
</head>
<body>
<table width="600px" border="1px">
<tr>
<th>学生姓名</th>
<th>学生年龄</th>
<th>学生成绩</th>
</tr>
<c:forEach items="${students}" var="s">
<tr>
<td>${s.username}</td>
<td>${s.age}</td>
<td>${s.score}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
- index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>JSP</title>
</head>
<body>
<c:if test="${sessionScope.username eq null}">
<a href="${pageContext.request.contextPath}/login.jsp">请登录</a>
</c:if>
<c:if test="${sessionScope.username ne null}">
<a href="${pageContext.request.contextPath}/addStudent.jsp">添加学生</a>
<a href="${pageContext.request.contextPath}/listStudentServlet">显示学生</a>
</c:if>
</body>
</html>