简介
JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%
开头以%>
结束。
Scriptlet脚本小程序
如果你想在HTML中写Java代码,就需要将Java代码写入Scriptlet中,有三种写法:
- 定义局部变量、编写语句等:
<%在这里写Java代码%>
。生成的代码在servlet中的service方法体中 - 声明,声明全局变量、方法、类等:
<%!在这里声明全局变量%>
。生成的代码在servlet的类体中 - 输出表达式,可以输出变量或字面量:
<%=数值%>
。生成的代码在servlet中的service方法体中,相当于out.print()
输出
<body>
<%-- 第一种:Java脚本段,可以写Java代码,定义局部变量、编写语句等 --%>
<%
// 定义局部变量
String str = "Hello Jsp";
// 输出内容到控制台
System.out.println(str);
// 输出内容到浏览器
out.print(str);
out.write("------");
// 输出全局变量
out.write("全局变量:" + num);
out.write("------");
%>
<%-- 第二种:声明,声明全局变量、方法、类等 --%>
<%!
// 声明全局变量
int num = 10;
%>
<%-- 第三种:输出表达式,可以输出变量或字面量 --%>
<%=str %>
</body>
JSP的指令标签
使用包含操作,可以将一些重复的代码包含进来继续使用,从正常的页面组成来看,有时可能分为几个区域。而其中的一些区域可能是一直不需要改变的,改变的就其中的一个具体内容区域。现在有两种方法可以实现上述功能。
- 方法一:在每个 JSP 页面(HTML)都包含工具栏、头部信息、尾部信息、具体内容
- 方法二:将工具栏、头部信息、尾部信息都分成各个独立的文件,使用的时候直接导入
很明显,第二种方法比第一种更好,第一种会存在很多重复的代码,并且修改很不方便,在 JSP 中如果要想实现包含的操作,有两种做法:静态包含、动态包含,静态包含使用 include 指令即可,动态包含则需要使用 include 动作标
签。
include静态包含
语法:<%@ include file="要包含的文件路径(注意:要写相对路径,不能为空,可以为表达式)" %>
现在我们建一个header.jsp:
<head>
<title>头部</title>
</head>
<body>
<h2>头部内容</h2>
<%
int num = 1;
%>
</body>
再建一个footer.jsp:
<head>
<title>底部</title>
</head>
<body>
<h2>底部内容</h2>
<%
int a = 10;
%>
</body>
把上面两个文件引入进来
<body>
<%--
include静态包含
格式:
<%@include file="要包含的页面地址"%>
特点:
1. 将内容进行了直接的替换
2. 静态包含只会生成一个源码文件,最终的内容全部在_jspService方法体中(源码文件中)
3. 不能出现同名变量
4. 运行效率高一点点。耦合性较高,不够灵活。
--%>
<%@include file="04-header.jsp"%>
<h2>主体内容</h2>
<%
int num = 1;// 在这里还是可以定义num
%>
<%@include file="04-footer.jsp"%>
</body>
静态包含就是将内容进行了直接的替换,就好比程序中定义的变量一样,是在 servlet 引擎转译时,就把此文件内容包含了进去(两个文件的源代码整合到一起, 全部放到_jspService 方法中),所以只生成了一个 servlet,所以两个
页面不能有同名的变量。
include动态包含
动态包含在代码的编译阶段,包含和被包含部分是两个独立的部分,只有当运行时,才会动态包含进来,好比方法的调用,可以传递参数。
不传参
语法:<jsp:include page="要包含的页面路径(注意:要写相对路径,不能为空,可以为表达式)"></jsp:include>
。
注意:当动态包含不需要传递参数时,include双标签之间不要有任何内容,包括换行和空格:<jsp:include page="要包含的页面路径">这里啥都别写</jsp:include>
<body>
<%--
include动态包含不传递参数
格式:
<jsp:include page="要包含的页面路径"></jsp:include>
特点:
1. 动态包含相当于方法的调用
2. 动态包含会生成多个源码文件,包含3个会生成4个源码文件(加上自己就是4个嘛)
3. 可以定义同名变量
4. 效率高,耦合度低
--%>
<jsp:include page="04-header.jsp"></jsp:include>
<h2>主体内容</h2>
<%
int a = 1;
%>
<jsp:include page="04-footer.jsp"></jsp:include>
</body>
传参
语法:
<jsp:include page="要包含的页面路径(注意:要写相对路径,不能为空,可以为表达式)">
<jsp:param name="参数名" value="参数值"/>
</jsp:include>
注意:name属性不支持表达式,value属性支持表达式
<body>
<%
String str = "hello";
String url = "04-footer.jsp";
%>
<%--page的值为表达式--%>
<jsp:include page="<%=url%>">
<jsp:param name="uname" value="admin"/>
<%--value属性支持表达式--%>
<jsp:param name="msg" value="<%=str%>"/>
</jsp:include>
</body>
获取参数:request.getParameter(name); 通过指定参数名获取参数值
,04-footer.jsp:
<body>
<h2>底部内容</h2>
<%
int a = 10;
// 获取动态包含传递的参数
String uname = request.getParameter("uname");
String msg = request.getParameter("msg");
out.print(uname+","+msg);
%>
</body>
一个页面可以被重复包含多次:
<body>
<jsp:include page="04-footer.jsp"></jsp:include>
<jsp:include page="04-footer.jsp"></jsp:include>
</body>
JSP的四大域对象
四种属性范围
在JSP中提供了四种属性的保存范围,所谓的属性保存范围,指的就是一个设置的对象,可以在多少个页面中保存并继续使用
- page范围
- pageContext : 只在一个页面中保存属性,跳转之后无效
- request范围
request : 只在一次请求中保存,服务器跳转后依然有效,客户端跳转失效 - session范围
session : 在一次会话范围中,无论何种跳转都可以使用,只要session对象不销毁 - application范围
application : 在整个服务器上保存,只要服务器不关闭,他就一直有效
方法 | 类型 | 描述 |
---|---|---|
public void setAttribute(String name, Object o) | 普通 | 设置属性的名称及内容 |
public Object getAttribute(String name) | 普通 | 根据属性名称取属性 |
public void removeAttribute(String name) | 普通 | 删除指定的属性 |
验证属性范围的特点
- page:本页面可以取得数据,服务器端跳转(
<jsp:forward page="跳转的页面地址"></jsp:forward>
)后无效 - request:服务器跳转有效,客户端跳转(超链接跳转)无效
如果是客户端跳转,则相当于发出了两次请求,那么第一次的请求将不存在了;如果希望不管是客户端还是服务器跳转,都能保存的话,就需要继续扩大范围。 - session:无论客户端还是服务器端都可以取得,但是现在重新开启一个新的浏览器,则无法取得之前设置的session了,因为每一个session只保存在当前的浏览器当中,并在相关的页面取得。
对于服务器而言,每一个连接到它的客户端都是一个session
如果想要让属性设置一次之后,不管是否是新的浏览器打开都能取得则可以使用application - application:所有的application属性直接保存在服务器上,所有的用户(每一个session)都可以直接访问取得。只要是通过application设置的属性,则所有的session都可以取得,表示公共的内容,但是如果此时服务器重启了,则无法取得了,因为关闭服务器后,所有的属性都消失了,所以需要重新设置
注意:使用哪个范围在合理范围尽可能小,因为范围越大,损耗的资源越多
测试jsp中服务端跳转,新建06-JSP的四大域对象.jsp
,在其中设置域对象:
<body>
<%
// 设置page范围的域对象
pageContext.setAttribute("name1","zhangsan");
// 设置request范围的域对象
request.setAttribute("name2","lisi");
// 设置session范围的域对象
session.setAttribute("name3","wangwu");
// 设置application范围的域对象
application.setAttribute("name4","zhaoliu");
%>
<%-- jsp中服务端跳转 --%>
<%--<jsp:forward page="06-JSP的四大域对象-02.jsp"></jsp:forward>--%>
</body>
在以上页面启动服务器,会自动跳转到06-JSP的四大域对象-02.jsp
页面,该页面内容如下:
<body>
<%
// 获取域对象中的值
out.print("page范围:" + pageContext.getAttribute("name1") + "<br>");
out.print("request范围:" + request.getAttribute("name2") + "<br>");
out.print("session范围:" + session.getAttribute("name3") + "<br>");
out.print("application范围:" + application.getAttribute("name4") + "<br>");
%>
</body>
06-JSP的四大域对象-02.jsp
页面获取到的内容如下,因为页面做了跳转,所以page范围的域对象获取不到
如果使用客户端跳转,06-JSP的四大域对象.jsp
中跳转方式改为超链接:
<body>
<%
// 设置page范围的域对象
pageContext.setAttribute("name1","zhangsan");
// 设置request范围的域对象
request.setAttribute("name2","lisi");
// 设置session范围的域对象
session.setAttribute("name3","wangwu");
// 设置application范围的域对象
application.setAttribute("name4","zhaoliu");
%>
<%-- 超链接跳转--%>
<a href="06-JSP的四大域对象-02.jsp">跳转</a>
</body>
在06-JSP的四大域对象.jsp
页面启动服务器,点击页面超链接,会自动跳转到06-JSP的四大域对象-02.jsp
页面,获取到的内容如下,因为是超链接跳转,所以获取不到session范围的域对象
关闭浏览器,然后打开浏览器,在URL中输入地址,得到的数据如下,因为关闭了浏览器嘛,所以获取不到session范围的域对象
EL表达式
操作字符串
<body>
<%--
EL表达式
作用:
简化JSP代码
格式:
${域对象的名称}
操作对象:
EL表达式一般操作的是域对象,不能操作局部变量。
操作范围:
page范围
在当前页面
request范围
在一次请求
session范围
在一次会话
application范围
在整个应用程序
注:
1. 如果el表达式获取域对象的值为空,默认显示空字符串
2. el表达式默认从小到大范围去找,找到即可,如果四个范围都未找到,则显示空字符串
--%>
<%-- 设置数据 --%>
<%
pageContext.setAttribute("uname","zhangsan"); // page作用域
request.setAttribute("uname","lisi"); // request作用域
session.setAttribute("uname","wangwu"); // session作用域
application.setAttribute("uname","zaholiu"); // application
// 定义局部变量
String str = "Hello";
%>
<%-- 获取数据 --%>
获取局部变量:${str} <br>
获取域对象:${uname} <br>
</body>
显然获取不到局部变量,显示空字符串。每个域中都定义了uname,但是取的是page作用域的值,因为他是从小到大取:
查找数据时可以使用四个域对象对应的空间对象,分别是:pageScope,requestScope, sessionScope, applicationScope
<body>
<%-- 设置数据 --%>
<%
pageContext.setAttribute("uname","zhangsan"); // page作用域
request.setAttribute("uname","lisi"); // request作用域
session.setAttribute("uname","wangwu"); // session作用域
application.setAttribute("uname","zaholiu"); // application
%>
获取指定范围的域对象:<br>
page范围:${pageScope.uname}<br>
request范围:${requestScope.uname}<br>
session范围:${sessionScope.uname}<br>
application范围:${applicationScope.uname}<br>
</body>
获取结果:
操作集合
<body>
<%--
EL表达式的使用
获取List
获取List的size ${list.size()}
获取List的指定下标的值 ${list[下标]}
注:list代表的是限域变量名,即存在域对象中的一个变量名
获取Map
获取Map中指定key的value ${map.key} 或 ${map["key"]}
注:map代表的是限域变量名
获取JavaBean对象
获取JavaBean中的属性
${javaBean.属性名} 或 ${JavaBean对象.get属性名()}
注:JavaBean中的属性字段必须提供get方法
--%>
<%
// List
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
request.setAttribute("list", list);
// Map
Map map = new HashMap();
map.put("aaa", "111");
map.put("bbb", 2222);
map.put("ccc-a", 333);
request.setAttribute("map", map);
// JavaBean对象
User user = new User();
user.setUserId(1);
user.setUname("zhangsan");
user.setUpwd("123456");
request.setAttribute("user",user);
%>
<h4>获取List</h4>
获取List的size:${list.size()} <br>
获取List的指定下标的值:${list[1]} <br>
<h4>获取Map</h4>
获取Map指定key的value值:${map.aaa} -- ${map["bbb"]}
<h4>获取JavaBean对象</h4>
获取JavaBean对象:${user}<br>
获取JavaBean中的属性:${user.uname} -- ${user.getUpwd()}
</body>