1、简单的使用
1、1 一个最为简单的JSP文件
如:
<%
out.print("Hello!");
%>
可以将该jsp文件放入<Tomcat>\webapps\jsp-examples或者<Tomcat>\webapps\jsp-examples\jsp下的某个自己建立的目录中,访问方法为:
http://localhost:8088/jsp-examples/hello.jsp
或者
http://localhost:8088/jsp-examples/lsq/hello.jsp
注意:
修改后无需重启Tomcat即可刷新看到新的结果
上述做法的真正代码是servlet代码,在编译执行JSP网页后,可以发现在<Tomcat>/work目录下存在新的java文件,里面就是一个servlet,名称为JSP文件名称加上“_jsp”后缀,它继承org.apache.jasper.runtime.HttpJspBase,而此类继承javax.servlet.http.HttpServlet。所以,里面有个_jspService方法,即包含JSP网页代码
1、2 结合网页HTML的JSP文件
如:
<html>
<head>
</head>
<body>
<%
String msg="Welcome to JSP world!";
out.print("Hello!<br>");
out.print("Hello!");
%>
<hr>
<h1>
<%=msg%>
<%out.print(msg);%>
</h1>
<%out.print(msg);%>
</body>
</html>
</html>
注意:
1)<%=msg%>表示的意思和<%out.print(msg);%>完全等价,是种简单写法。注意前者无需分号,而后者每行都以分号结尾
2)h1标记结束后自动换行
3)可以继续观察生成的servlet代码,注意代码的变化
4)out的println方法并不会产生换行效果,必须使用诸如out.print("Hello!<br>")的写法
1、3 注释的使用
注释分为两种,一种为在网页中的注释,可以使用<!--、-->和<%--、--%>,前者编译后可以在servlet代码中看见,而后者编译后不可以看见;另外一种为Java代码中的注释,就是传统的Java语言注释,如:
<html>
<head>
</head>
<body>
<!--This is a exec!-->
<%
//This is a comment in java code.
out.print("Hello!");
%>
<!--Today is <%=(new java.util.Date()).toLocaleString()%>-->
<%--You can not see it!--%>
</body>
</html>
注意:
可以继续观察生成的servlet代码,注意不同注释的位置
1、4 JSP程序的部署配置
JSP程序也可以象servlet那样在web.xml中进行路径配置,如:
<servlet>
<servlet-name>exec</servlet-name>
<jsp-file>/exec.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>exec</servlet-name>
<url-pattern>/exec</url-pattern>
</servlet-mapping>
相应的jsp网页请求可以为:http://localhost:8088/myexec/exec
1、5 几个练习
显示不同字体之一:
<%@page language="java"%>
<%
out.print("<html><head></head><body>");
String str="Welcome!";
int font_size=0;
for(int i=0;i<str.length();i++)
{
out.print("<font size=");
out.print(++font_size);
out.print(">");
out.print(str.substring(i,i+1));
out.print("</font>");
}
out.print("</body>");
out.print("</html>");
%>
显示不同字体之二:
<html>
<head>
</head>
<body>
<%@page language="java"%>
<%
out.print("");
String str="Welcome!";
int font_size=0;
for(int i=0;i<str.length();i++)
{
%>
<font size=<%=++font_size%>>
<%=str.charAt(i)%></font>
<%}%>
</body>
</html>
时间显示之一:
<%@page import="java.util.GregorianCalendar" %>
<%@page import="java.text.SimpleDateFormat" %>
<%@page import="java.util.Date" %>
<%@page c%>
<html>
<head>
</head>
<body>
<h1>
<%
GregorianCalendar target=new GregorianCalendar();
target.set(target.YEAR,3000);
target.set(target.MONTH,1);
target.set(target.DATE,1);
target.set(target.AM_PM,0);
target.set(target.HOUR,0);
target.set(target.MINUTE,0);
target.set(target.SECOND,0);
Date Dtarget=(Date)target.getTime();
Date Dcurrent=new Date();
int i=Dtarget.compareTo(Dcurrent);
if(i==1)
{
long secs=Dtarget.getTime()-Dcurrent.getTime();
long days=(long)secs/(long)(1000*60*60*24);
//毫秒与天的换算
out.print("距离3000年还有"+days+"天!");
}
%>
</h1>
</body>
</html>
时间显示之二:
<html>
<head>
<meta http-equiv = "refresh" c />
<title>A Simple JSP Example</title>
<style type = "text/css">
.big { font-family: helvetica, arial, sans-serif;
font-weight: bold;
font-size: 2em; }
</style>
</head>
<body>
<p class = "big">Simple JSP Example</p>
<table style = "border: 6px outset;">
<tr>
<td style = "background-color: black;">
<p class = "big" style = "color: cyan;">
<%= new java.util.Date() %>
</p>
</td>
</tr>
</table>
</body>
</html>
2、类型和变量声明
可以使用<%!、%>进行类型和变量声明,可以在里面加入多条声明语句,甚至可以包含类型不相同的类型和变量,其中包含类和函数等,如:
<html>
<head>
</head>
<body>
<%!
public class Tc
{
String n1,n2;
public Tc(String a1,String a2)
{
n1=a1;
n2=a2;
}
public String getN1()
{
return this.n1;
}
public String getN2()
{
return n2;
}
}
%>
<%
String str1="Hello!",str2="Welcome!";
Tc t=new Tc(str1,str2);
%>
<br>
<%
out.print("n1="+t.getN1());
out.print("<br>");
out.print("n2="+t.getN2());
%>
</body>
</html>
注意:
声明语句中的“!”具有特殊含义,可以通过查看servlet源代码,发现带有此符号的语句块,就作为servlet类中的成员直接摆放,而不带有此符号的将放入_jspService方法,如下面的程序会将str1和t变量的声明直接放入servlet类中,所以,不能将纯粹的非声明语句块加上“!”符号,如:
<html>
<head>
</head>
<body>
<%!
public class Tc
{
String n1,n2;
public Tc(String a1,String a2)
{
n1=a1;
n2=a2;
}
public String getN1()
{
return this.n1;
}
public String getN2()
{
return n2;
}
}
%>
<%!
String str1="Hello!",str2="Welcome!";
Tc t=new Tc(str1,str2);
%>
<br>
<%
out.print("n1="+t.getN1());
out.print("<br>");
out.print("n2="+t.getN2());
%>
</body>
</html>
下面的程序声明了函数,如:
<html>
<head>
</head>
<body>
<%!
public String getSome()
{
return "Some";
}
%>
<br>
<%
out.print(getSome());
%>
</body>
</html>
注意:
1)函数并非独立,在编译时会自动生成为servlet类的成员函数
2)此时的声明语句块必须添加“!”符号
充分使用servlet类中的成员属性,可以表达具有共享性质的变量。如统计访问次数的程序:
<html>
<head>
</head>
<body>
<%!int i=0;%>
<%
i=i+1;
out.print("i="+i);
%>
</body>
</html>
注意:
1)注意程序段和变量声明中都可以定义变量,但是变量声明中定义的变量为全局变量
2)可以观察反复刷新后的效果
3、编译指令(Directives)
编译指令不会产生输出,主要用于配置编译器指令信息
如:
<%@page c%>
<html>
<head>
</head>
<body>
<%@include file="head.htm"%>
<H1>欢迎来到JSP Web Site!</H1>
<HR>
<%@include file="foot.jsp"%>
</body>
</html>
其中包含的head.htm文件为:
<table border="0" width="100%">
<tr>
<td bgcolor="#EEDDEE" width="100%">This is a head!</td>
</tr>
</table>
包含的foot.jsp文件为:
<table border="0" width="100%">
<tr>
<td bgcolor="#DDEEDD" width="100%">
Current time is <%=(new java.util.Date()).toLocaleString()%>
</td>
</tr>
</table>
注意:
1)page指令中的contentType属性用于设置输出方式和字符集
2)include指令用于设置包含的文件
4、操作指令(Actions)
操作指令比较多,主要功能为设置网页跳转、包含和JavaBean的处理等
4、1 forward
意为将内容完全跳转到新的网页以替换当前的网页,注意此时的文件名称认为原来的文件名称,如exec.jsp为:
<%@page c%>
<html>
<head>
</head>
<body>
<H1>欢迎来到JSP Web Site!</H1>
<HR>
<jsp:forward page="other1.jsp"/>
</body>
</html>
文件other1.jsp的内容为:
Hello
显示的结果只有other1.jsp的内容,没有exec.jsp的任何内容
注意:
跳转的网页既可以是jsp网页,也可以是一般的html网页,甚至是servlet,如下面的网页能够跳转到一个servlet中:
<%@page c%>
<html>
<head>
</head>
<body>
<jsp:forward page="/HTTPGetTime"/>
</body>
</html>
servlet为:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.Date;
public class HTTPGetTime extends HttpServlet
{
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException
{
PrintWriter output;
response.setContentType("text/html");
output=response.getWriter();
Date d=new Date();
output.println(d.toLocaleString());
output.close();
}
}
将其编译后放入WEB-INF\classes下,并对web.xml增加节点为:
<servlet>
<servlet-name>HTTPGetTime</servlet-name>
<servlet-class>HTTPGetTime</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HTTPGetTime</servlet-name>
<url-pattern>/HTTPGetTime</url-pattern>
</servlet-mapping>
更加有效的方式还可以传送参数给servlet,其原因在于JSP和Servlet共享同一个请求对象。此时的网页为:
<%@page c%>
<html>
<head>
</head>
<body>
<jsp:forward page="/HTTPGetTime?number=000001"/>
</body>
</html>
带有处理参数的servlet为:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.Date;
public class HTTPGetTime extends HttpServlet
{
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException
{
PrintWriter output;
response.setContentType("text/html");
output=response.getWriter();
String str=request.getParameter("number");
output.println(str);
Date d=new Date();
output.println(d.toLocaleString());
output.close();
}
}
上述的跳转网页也可以使用下面的方式向servlet传递参数,如:
<%@page c%>
<html>
<head>
</head>
<body>
<jsp:forward page="/HTTPGetTime">
<jsp:param name="number" value="000002"/>
</jsp:forward>
</body>
</html>
当然这种传递参数的方式也可以向其他jsp网页传递参数,如发送参数的jsp网页为:
<%@page c%>
<html>
<head>
</head>
<body>
<jsp:forward page="login.jsp">
<jsp:param name="sname" value="Tom"/>
<jsp:param name="snumber" value="000001"/>
</jsp:forward>
</body>
</html>
另一个接受参数的jsp网页为:
<%
String s1=request.getParameter("sname");
String s2=request.getParameter("snumber");
out.println(s1+"<p>"+s2);
%>
注意:
1)JSWDK不支持forward操作指令
2)对于这种用法,也可以直接调用,如:
http://localhost:8088/jsp-examples/lsq/login.jsp?sname=Tom&snumber=00012
4、2 include
可以不仅包含静态页面,也可以包含动态页面。较@include有区别,主要在于处理时间不一样,jsp:include在客户请求时才动态编译,而@include在编译JSP文件时就已经编译好了,如:
<html>
<head>
</head>
<body>
<jsp:include page="head.htm" flush="true"/>
<H1>JSP Web Site!</H1>
<HR>
<jsp:include page="foot.jsp" flush="true"/>
</body>
</html>
其中包含的head.htm文件为:
<table border="0" width="100%">
<tr>
<td bgcolor="#EEDDEE" width="100%">This is a head!</td>
</tr>
</table>
包含的foot.jsp文件为:
<table border="0" width="100%">
<tr>
<td bgcolor="#DDEEDD" width="100%">
Current time is <%=(new java.util.Date()).toLocaleString()%>
</td>
</tr>
</table>
这个指令也可以传递参数,如:
<html>
<head>
</head>
<body>
<jsp:include page="head.htm" flush="true"/>
<H1>JSP Web Site!</H1>
<HR>
<jsp:include page="foot.jsp?num=tom" flush="true"/>
</body>
</html>
此时的foot.jsp文件为:
<table border="0" width="100%">
<tr>
<td bgcolor="#DDEEDD" width="50%">
Current time is <%=(new java.util.Date()).toLocaleString()%>
</td>
<td bgcolor="#DDEEDD" width="50%">
<%=request.getParameter("num")%><P>
</td>
</tr>
</table>
也可以使用下面的参数传递方式,如:
<html>
<head>
</head>
<body>
<H1>JSP Web Site!</H1>
<HR>
<jsp:include page="foot.jsp" flush="true">
<jsp:param name="num" value="tom"/>
</jsp:include>
</body>
</html>
此时的foot.jsp文件不变,为:
<table border="0" width="100%">
<tr>
<td bgcolor="#DDEEDD" width="50%">
Current time is <%=(new java.util.Date()).toLocaleString()%>
</td>
<td bgcolor="#DDEEDD" width="50%">
<%=request.getParameter("num")%><P>
</td>
</tr>
</table>
4、3 plugin
直接在网页中加入applet小程序,如:
<html>
<head>
</head>
<body>
<h3>Current time is :</h3>
<jsp:plugin type="applet" code="Clock2.class" codebase="applet" jreversion="1.2" width="160" height="150" >
<jsp:fallback>
Plugin tag OBJECT or EMBED not supported by browser.
</jsp:fallback>
</jsp:plugin>
</body>
</html>
其中的小程序可以在jsp-examples\plugin中找到,直接将目录applet全部拷贝至自己的目录即可
5、表单元素的使用
直接在网页中编写各个网页组件,名称一定要注意,因为在JSP文件可以进一步根据组件的名称得到它们的值
下面的网页显示若干组件,如:
<html>
<head>
</head>
<body>
<form action="http://localhost:8088/jsp-examples/lsq/exec.jsp" name="thisform" method="get" target="_blank">
<p align="center"><b><font size="6">Information</font></b>
<p><input type="radio" name="R1" value="Male" checked>Male
<p><input type="radio" name="R1" value="Female">Female
<p><input type="checkbox" name="C1" value="VB">VB
<p><input type="checkbox" name="C1" value="Cpp">C++
<p><select size="1" name="D1">
<option>Beginning</option>
<option>Median</option>
<option>Advanced</option>
</select>
<p><textarea rows="2" name="S1" cols="20"></textarea>
<p><input type="submit" value="OK!" name="B1">
</form>
</body>
</html>
相应的JSP文件为:
<html>
<head>
</head>
<body>
sex=<%out.print(request.getParameter("R1"));%>
<P>
language=<%out.print(request.getParameter("C1"));%>
<P>
language=
<%
String [] list=request.getParameterValues("C1");
if(list!=null)
{
for(int i=0;i<list.length;i++)
{
out.print(list[i]);
out.print("<br>");
}
out.print("<P>");
}
else
out.print("No List!<p>");
%>
grade=<%out.println(request.getParameter("D1")+"<P>");%>
FAQ=<%out.println(request.getParameter("S1"));%>
</body>
</html>
说明:
1)提交方式默认为method="get",附加字符于URL后,也可以使用post方式,两种方式都是一样的处理方法,通过getParameter()方法获取之,相应的JSP文件无需修改,只是在URL后看不见附加字符了
2)target="_blank"表示新建窗体,"_self"为默认值,表示当前窗体显示结果网页
3)action中也可以使用相对路径,如action="exec.jsp"就表示当前路径
6、JavaBean的使用
在JSP中,只能使用没有界面的Bean,主要负责处理事务(如数据运算、操纵数据库等)。一般来说,它是一个公共(public)的类,必须有一个不带参数的构造函数,通过get、set方法来获取和设置属性,也可以直接调用其方法。
6、1 用法介绍
一般可以直接使用,如JavaBean为:
package com.lsq.execs;
public class exec
{
public exec()
{}
private String make="Ford";
public String getMake()
{
return make;
}
public void setMake(String m)
{
this.make=m;
}
}
编译好后放入<Tomcat>\webapps\jsp-examples\WEB-INF\classes下,编译jsp文件时自动默认查找
相应的JSP文件为:
<html>
<head>
</head>
<body>
<%
com.lsq.execs.exec c=new com.lsq.execs.exec();
c.setMake("New One");
out.print(c.getMake());
%>
</body>
</html>
注意:一定要使用包结构
在JSP网页中,给JavaBean赋值和读取属性的更加简单方法是下面的做法:
<html>
<head>
</head>
<body>
<jsp:useBean id="c" class="com.lsq.execs.exec"/>
<jsp:getProperty name="c" property="make"/><br>
<jsp:setProperty name="c" property="make" value="NewOne"/><br>
<jsp:getProperty name="c" property="make"/>
</body>
</html>
说明:
1)其中jsp:getProperty标记可以读取属性,jsp:setProperty可以设置属性,注意此时的JavaBean必须规范的命名其中的属性方法
2)在指定范围内存在此对象时,<jsp:useBean>不会创建新的对象,而是获得现有Bean对象的引用,查看生成的servlet可以看到:
com.lsq.execs.exec c = null;
synchronized (_jspx_page_context) {
c = (com.lsq.execs.exec) _jspx_page_context.getAttribute("c", PageContext.PAGE_SCOPE);
if (c == null){
c = new com.lsq.execs.exec();
_jspx_page_context.setAttribute("c", c, PageContext.PAGE_SCOPE);
}
3)即使有导入语句,如:
<%@ page import="com.lsq.execs.exec" %>
<jsp:useBean>中指定的class属性后也一定要有完整的Bean名称,包含包的名称,否则会找不到类
4)也可以混合使用,声明采用标记来做,使用采用一般写法,如:
<jsp:useBean id="c" class="com.lsq.execs.exec"/>
<%
out.print(c.getMake());
%>
但是不能先采用一般写法,再使用标记来做,如:
<%
com.lsq.execs.exec c=new com.lsq.execs.exec();
%>
<jsp:getProperty name="c" property="make"/>
这是因为单纯的Bean对象生成语句不能在JSP环境中注册Bean对象,所以JSP无法在上下文中找到对应的Bean信息,查看servlet可以看到:
out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty(_jspx_page_context.findAttribute("c"), "make")));
5)所有对Bean属性的设置和读取都采用通过上下文环境中搜索注册Bean信息的方式来间接获取Bean对象引用以进行操纵,查看servlet可以看到:
读取Bean属性的<jsp:getProperty>标签转换为:
out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((com.lsq.execs.exec)_jspx_page_context.findAttribute("c")).getMake())));
设置Bean属性的<jsp:setProperty>标签转换为:
org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("c"), "make", "NewOne", null, null, false);
再如一个更加复杂的JavaBean为:
package com.lsq.execs;
public class exec
{
public exec()
{}
private String make="Ford";
public String getMake()
{
return make;
}
public void setMake(String m)
{
this.make=m;
}
private double cost=10000.00;
private double tax=17.5;
public void setCost(double d)
{
cost=d;
}
public double getCost()
{
return cost;
}
public double getPrice()
{
double price=(cost+(cost*tax/100));
return price;
}
//下述函数可以省略
public void setPrice(double newprice)
{}
}
此时的JSP文件为:
<html>
<head>
</head>
<body>
<jsp:useBean id="c" class="com.lsq.execs.exec"/>
<jsp:getProperty name="c" property="make"/><br>
<jsp:setProperty name="c" property="make" value="OK"/>
<jsp:getProperty name="c" property="make"/><br>
<jsp:getProperty name="c" property="price"/><br>
<jsp:setProperty name="c" property="cost" value="12.89"/>
<jsp:getProperty name="c" property="cost"/><br>
<jsp:getProperty name="c" property="price"/><br>
<jsp:setProperty name="c" property="price" value="12"/>
<jsp:getProperty name="c" property="price"/>
</body>
</html>
注意:
1)JavaBean中的setPrice方法意义不大,可以省略,同理,JSP文件中的<jsp:setProperty name="c" property="price"/>也可以省略
2)修改JavaBean后一定要重启Tomcat才能起效
6、2 作用域
6、2、1 说明
<jsp:useBean>标签的SCOPE属性完成很简单的功能,它设置相关的bean的作用域,有四个可能的值,共享级别越来越宽泛:
Page:对象只可被来自它所在页的一个客户机程序存取,如果不设置,它为默认级别。
request:对象在一个客户请求的生存时间内被一个客户机程序存取。
session:对象在整个用户会话的生存时间内被来自该应用程序中任何地方的一个客户机程序存取。
application:对象在应用程序的生存时间内可以被应用程序内来自任何页面的客户机程序存取。
不论是何种级别,如果已经存在创建了的Bean,生成Bean的标记语句不会再次被执行,如:
<%@ page c %>
<html>
<head>
</head>
<body>
<jsp:useBean id="cc" scope="session" class="com.lsq.execs.exec"/>
<jsp:getProperty name="cc" property="make"/><br>
<jsp:setProperty name="cc" property="make" value="OK"/><br>
<jsp:getProperty name="cc" property="make"/><br>
</body>
</html>
只要不结束当前会话,则始终显示修改后的“OK”值,即使是将上述文件拷贝两份,同一会话查看,也会发现创建Bean只进行一次
1)application级别
两个JSP网页,exec.jsp为:
<%@ page c %>
<html>
<head>
</head>
<body>
<jsp:useBean id="c" scope="application" class="com.lsq.execs.exec"/>
<jsp:getProperty name="c" property="make"/><br>
</body>
</html>
addit.jsp为:
<jsp:setProperty name="c" property="make" value="NewOne"/><br>
<jsp:getProperty name="c" property="make"/>
访问完exec.jsp后访问addit.jsp可以显示内容,显然同一应用程序内部的网页共享此Bean
2)session级别
修改上述两个网页,exec.jsp为:
<%@ page c %>
<html>
<head>
</head>
<body>
<jsp:useBean id="cc" scope="session" class="com.lsq.execs.exec"/>
<jsp:getProperty name="cc" property="make"/><br>
</body>
</html>
addit.jsp为:
<jsp:setProperty name="cc" property="make" value="NewOne"/><br>
<jsp:getProperty name="cc" property="make"/>
访问完exec.jsp后直接在当前窗体可以访问addit.jsp并显示内容,但是重启窗体访问addit.jsp不可以显示内容,显然不同会话的网页不共享此Bean(注意,为了看到效果,注意Bean的名称已经变化,否则,遗留的应用程序级别的Bean可能还会起作用)
3)request级别
修改上述两个网页,exec.jsp为:
<%@ page c %>
<html>
<head>
</head>
<body>
<jsp:useBean id="ccc" scope="request" class="com.lsq.execs.exec"/>
<jsp:getProperty name="ccc" property="make"/><br>
</body>
</html>
addit.jsp为:
<jsp:setProperty name="ccc" property="make" value="NewOne"/><br>
<jsp:getProperty name="ccc" property="make"/>
此时访问完exec.jsp后直接在当前窗体不能访问addit.jsp,说明不同请求不共享此Bean
但是,下面的exec.jsp网页可以显示addit.jsp网页内容,,因为它们通过包含已经位于同一请求范围之内,如:
<%@ page c %>
<html>
<head>
</head>
<body>
<jsp:useBean id="ccc" scope="request" class="com.lsq.execs.exec"/>
<jsp:getProperty name="ccc" property="make"/><br>
<hr>
<jsp:include page="addit.jsp"/>
</body>
</html>
4)Page级别
修改上述两个网页,exec.jsp为:
<%@ page c %>
<html>
<head>
</head>
<body>
<jsp:useBean id="cccc" scope="page" class="com.lsq.execs.exec"/>
<jsp:getProperty name="cccc" property="make"/><br>
<hr>
<jsp:include page="addit.jsp"/>
</body>
</html>
addit.jsp为:
<jsp:setProperty name="cccc" property="make" value="NewOne"/><br>
<jsp:getProperty name="cccc" property="make"/>
此时不能访问exec.jsp,原因在于它包含的addit.jsp使用了网页级别的Bean,其实,不仅是<jsp:include>,只要是离开当前网页的任何标签,如<jsp:forward>等,都会导致Bean失效
6、2、2 查看作用域级别
<html>
<head>
</head>
<body>
<jsp:useBean id="c" scope="session" class="com.lsq.execs.exec"/>
<jsp:getProperty name="c" property="make"/><br>
<jsp:setProperty name="c" property="make" value="NewOne"/><br>
<jsp:getProperty name="c" property="make"/>
<%
String scope=null;
com.lsq.execs.exec obj=(com.lsq.execs.exec)request.getAttribute("c");
if(obj!=null)
scope="request";
obj=(com.lsq.execs.exec)session.getAttribute("c");
if(obj!=null)
scope="session";
obj=(com.lsq.execs.exec)application.getAttribute("c");
if(obj!=null)
scope="application";
if(scope==null)
scope="page";//default value
out.print(scope);
%>
</body>
</html>
这种代码也说明,不同scope的设定是在不同系统环境对象中进行属性设置来表达的,如session级别的scope就是在HttpSession对象中设置一个名称为Bean名称的属性,值为Bean对象
7 用户跟踪
利用会话Session可以跟踪用户行为,可以实现创建、删除和销毁,保存会话等操作。另外,除了会话以外还有三种用户跟踪技术:Cookies,URL重写,隐藏式表单域
1)Cookies
可以实现用户跟踪,但是缺点在于容量一般不超过4KB,任何域不超过20个Cookie,而且敏感信息不应该使用此技术,另外,有些客户端阻止Cookie。同时,不做时间设置的Cookie只能在一次会话中使用,如将myCookie.setMaxAge(24*60*60)删除,可以发现重新打开IE后Cookie值就没有了
2)URL重写
在URL后附加标示会话的数据,并且服务器保存此数据,较少使用
3)隐含表单域
即Hidden控件,缺点在于用户可以查看源代码看到数据
8 会话的使用
打开多个窗体观察下面的程序,会发现彼此的Session并不相同。
JSP网页前加入的<%@page language="java" import="java.util.*" session="true"%>
默认session为"true",表明网页中隐含javax.servlet.http.HttpSession对象,可以使用,如不存在则创建,所以此句可以省略
利用session.setAttribute存放信息,每个对象值都用一个唯一的Key值来标示,所以整数需用 new Integer(1)来生成
利用session.getAttribute得到信息
利用session.getAttributeName得到对象的名称
利用session.removeAttribute删除对象
利用session.getId得到session标示
利用session.invalidate杀死会话
利用session.isNew判断是否是新会话
利用session.setMaxInactiveInterval设置超时过期间隔,以秒为单位(-1表示永不过期)
上述Session属性的设置也可以在web应用程序的web.xml文件中定义,如设置过期时间:进行设置,如:
<web-app>
<session-config>
<session-timeout>10</session-timeout>
</session-config>
</web-app>
下面的程序演示了会话变量的创建、会话信息的获取和会话对象的使用,可以利用刷新窗体和重新打开窗体的方式来查看效果,如:
<%@page language="java" import="java.util.*" session="true"%>
<html>
<head>
</head>
<body bgcolor="white">
<%
String aValue=(String)session.getAttribute("Some");
if(aValue==null)
{
aValue=new String("Hello!");
session.setAttribute("Some", aValue);
out.print("You are welcome!");
}
%>
<br>
<%=aValue%>
<br>
<%=session.getId()%>
<br>
<%=new Date(session.getCreationTime())%>
<br>
<%=new Date(session.getLastAccessedTime())%>
<br>
<%
if(session.isNew())
{
out.println("New One!");
}
%>
</body>
</html>
注意:
1)第一行为指令,用于设置导入包的名称和允许会话(默认为true)
2)会话的创建和使用接近于servlet中会话的创建和使用
3)会话对象本身的很多属性和方法可以用来得到许多会话元数据信息
4)关于session如何实现用户跟踪的原因,主要在于JSP的session容器能够在客户端产生对应session的cookie来维持客户状态,如果客户端不支持cookie,则session容器可以重写URL以实现用户跟踪,这种自己重写URL的手工编写方法是在所有的超链前添加response.encodeURL方法重写URL值,如:
<form name="loginForm" method="post" action="<%=response.encodeURL("mailcheck.jsp")%>">
或者
<a href="<%=response.encodeURL("mailcheck.jsp")%>">重新登录邮件系统</a>
一般此时会在网页源代码中发现:
<form name="loginForm" method="post" action="mailcheck.jsp;jsessionid=72F23F843D42F6D9E6FBADCE8FFDA8DC">
或者
<a href="mailcheck.jsp;jsessionid=72F23F843D42F6D9E6FBADCE8FFDA8DC">重新登录邮件系统</a>
事实上,自己完全可以在请求的URL后手工添加其他会话值来模拟其他会话,如:
http://localhost:8088/books/mail2/maillogin.jsp;jsessionid=72F23F843D42F6D9E6FBADCE8FFDA8DC
下面演示一个例子:
maillogin.jsp:
<%@ page c %>
<%@ page session="true" %>
<html>
<head>
<title>helloapp</title>
</head>
<body bgcolor="#FFFFFF" >
<%
String name="";
if(!session.isNew())
{
name=(String)session.getAttribute("username");
if(name==null)name="";
}
%>
<p>当前用户为:<%=name%> </P>
<p>欢迎光临邮件系统</p>
<p>Session ID:<%=session.getId()%></p>
<table width="500" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<table width="500" border="0" cellspacing="0" cellpadding="0">
<form name="loginForm" method="post" action="<%=response.encodeURL("mailcheck.jsp")%>">
<tr>
<td width="401"><div align="right">User Name: </div></td>
<td width="399"><input type="text" name="username" value=<%=name%>></td>
</tr>
<tr>
<td width="401"><div align="right">Password: </div></td>
<td width="399"><input type="password" name="password"></td>
</tr>
<tr>
<td width="401"> </td>
<td width="399"><br><input type="Submit" name="Submit" value="提交"></td>
</tr>
</form>
</table>
</td>
</tr>
</table>
</body>
</html>
mailcheck.jsp:
<%@ page c %>
<%@ page session="true" %>
<html>
<head>
<title>checkmail</title>
</head>
<body>
<%
String name=null;
name=request.getParameter("username");
if(name!=null)session.setAttribute("username",name);
%>
<a href="<%=response.encodeURL("maillogin.jsp")%>">登录</a>
<p>当前用户为:<%=name%> </P>
</body>
</html>
先运行一次上述JSP文件,获取其sessionID,比如2E1D052358DEF98DE21C3259662D66E0
在新建浏览器窗体,直接键入:
http://localhost:8088/books/mail2/maillogin.jsp;jsessionid=2E1D052358DEF98DE21C3259662D66E0
观察用户名称和第一个窗体一样,说明session容器直接查找相同ID的session为此新会话使用,实现多用户共享同一个session
一个利用Session实现的统计访问次数的网页:
<%@page language="java" import="java.util.*" session="true"%>
<html>
<head>
</head>
<body bgcolor="white">
<%
String heading;
Integer accessCount = (Integer)session.getAttribute("accessCount");
if(accessCount==null)
{
accessCount=new Integer(1);
heading="Welcome, this is your First Visit";
}
else
{
accessCount=new Integer(accessCount.intValue()+1);
heading="Welcome, this is your visit # "+accessCount;
}
session.setAttribute("accessCount", accessCount);
%>
<br>
<%=heading%>
<%
if(accessCount.intValue()==5)
session.invalidate();
%>
</body>
</html>
注意:
会话的invalidate方法可以用于显式的释放当前会话
一个利用Session和JavaBean实现的购物车:
JavaBean:
package com.shopping;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
public class ShoppingCart extends Object
{
private Vector cart=null;
String product=null;
String submit=null;
public ShoppingCart()
{
cart=new Vector();
}
public void setProduct(String product)
{
this.product=product;
}
public void setSubmit(String submit)
{
this.submit=submit;
}
public Vector getProducts()
{
return cart;
}
public void addProduct(String product)
{
cart.add(product);
}
public void removeProduct(String product)
{
cart.remove(product);
}
public void processRequest(HttpServletRequest req)
{
if(submit!=null)
{
if(submit.equals("add"))
{
addProduct(product);
}
else
{
removeProduct(product);
}
reset();
}
}
public void reset()
{
submit = null;
product = null;
}
}
编译后放入<Tomcat>\webapps\jsp-examples\WEB-INF\classes下
网页为:
<%@page import="java.util.Vector"%>
<html>
<head></head>
<body>
<center>
<form type=post action="exec.jsp">
<h1>Shopping Cart Example</h1>
<br>
Please select a Product and add it to your Shopping Cart
<br>
<select name='product'>
<option>Beginning Java 2 by Ivor Horton</option>
<option>Professional Java Programming by Brett Spell</option>
<option>Professional Jini by Sing Li</option>
<option>Professional JSP by Sing Li et al</option>
<option>Professional XSL by Andrew Watt et al</option>
<option>XML Applications by Frank Boumphrey et al</option>
<option>Beginning XML by Nikola Ozu et al</option>
<option>Instant UML by Pierre-Alain Muller</option>
<option>Beginning Java Objects by Jacquie Barker</option>
</select>
<input type=submit name="submit" value="add">
</form>
<!-- Here goes the shopping cart display -->
<%
String submit=request.getParameter("submit");
if(submit!=null)
{
%>
<hr>
<h2 align="center">Your Shopping Cart</h2>
<p>
<jsp:useBean id="cart" scope="session" class="com.shopping.ShoppingCart"/>
<jsp:setProperty name="cart" property="*" />
<%
cart.processRequest(request);
%>
<table width="75%" align="center" border="1">
<%
Vector products=cart.getProducts();
for(int i=0;i<products.size();i++)
{
%>
<tr>
<td><%=products.get(i)%></td>
<td><a href="exec.jsp?product=<%=products.get(i)%>&submit=remove">Remove</a></td>
</tr>
<%
}
if(products.size()==0)
{
%>
<tr>
<td>Your cart is currently empty</td>
</tr>
<%
}
%>
</table>
<%
}
%>
</center>
</body>
</html>
注意:
1)此网页具有新的文件名称,可能需要重启Tomcat,运行方法为:http://localhost:8088/jsp-examples/lsq/exec.jsp
2)在网页中使用Bean可以设置会话范围,如
<jsp:useBean id="cart" scope="session" class="com.shopping.ShoppingCart"/>
表示整个会话Bean都有效,好像用session对象的setAttribute方法设置会话对象变量一样。此Bean对象在会话结束后自动撤销释放。同时,scope还有page,request(如网页A传递给网页B的参数即为此类型,即变量只能在B中使用),session,application(全局使用)等值。
3)<jsp:setProperty name="cart" property="*" />表示自动按同名变量进行Bean属性设置。
9 应用的使用
应用Application对象可以在应用程序中共享对象信息,而且不会超时(应用程序重启会结束原来的Application),没有唯一标识符
一个利用application实现的访问次数统计网页:
<%@page language="java"%>
<html>
<head>
</head>
<body>
<%
String heading;
Integer totalAccessCount=(Integer)application.getAttribute("totalAccessCount");
if(totalAccessCount==null)
{
totalAccessCount=new Integer(1);
heading="Welcome, this is your First Visit";
}
else
{
totalAccessCount=new Integer(totalAccessCount.intValue()+1);
heading="Welcome, you visit this web site at # "+totalAccessCount;
}
application.setAttribute("totalAccessCount", totalAccessCount);
%>
<br>
<%=heading%>
</body>
</html>
11、3 Cookie的使用
查看所有的Cookie:
<html>
<head>
</head>
<body>
<%
Cookie[] cookieList=request.getCookies();
for(int i=0;i<cookieList.length;i++)
{
Cookie myCookie=cookieList[i];
out.println(myCookie.getName()+":"+myCookie.getValue()+"<br>");
}
%>
</body>
</html>
一个利用Cookie实现的统计访问次数的网页:
<html>
<head>
</head>
<body>
<%
String val=null;
Cookie[] cookieList=request.getCookies();
if(cookieList!=null)
{
for(int i=0;i<cookieList.length;i++)
{
Cookie myCookie=cookieList[i];
if(myCookie.getName().equals("user"))
{
val=myCookie.getValue();
out.println("The Name of the user is: "+val);
}
if(myCookie.getName().equals("counter"))
{
out.println("! You have visited this site for "+myCookie.getValue()+" times!");
Cookie myCookieCounter=new Cookie("counter",String.valueOf(Integer.parseInt(myCookie.getValue())+1));
myCookieCounter.setMaxAge(24*60*60);
response.addCookie(myCookieCounter);
}
}
}
if(val==null)
{
Cookie myCookieUser=new Cookie("user", "newUser");
Cookie myCookieCounter=new Cookie("counter", "1");
myCookieUser.setMaxAge(24*60*60);
myCookieCounter.setMaxAge(24*60*60);
response.addCookie(myCookieUser);
response.addCookie(myCookieCounter);
out.println("Welcome to you!");
}
%>
</body>
</html>
注意:
可以删除IE的Cookie来观察效果
[此贴子已经被作者于2010-12-12 08:16:11编辑过]