| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1455 人关注过本帖
标题:[原创]动网论坛源代码解读及其向JSP的移植——第四章,编写index.jsp
只看楼主 加入收藏
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
 问题点数:0 回复次数:8 
[原创]动网论坛源代码解读及其向JSP的移植——第四章,编写index.jsp

通过前面的分析,我们根据动网论坛的源代码,写一个等笑的JSP源代码应该是很简单的了。但是,还存在一些问题:在ASP中,不管在哪个类哪个函数中,都可以自由使用application,session,request,response等固有对象,而且对于在页面中定义的全局变量,函数中也都可以自由访问。但是JSP中不行,JSP中的Script都属于是servlet类的service方法的代码,而定义的方法都是servlet类的方法,所以,在页面中定义的变量,都不能当全局变量使用,而且Java中没有全局变量这个概念。怎么办?
我的解决办法是这样的,把所有需要在页面中定义的变量都封装到一个类Scriptlet中,然后在每个类的构造函数中传递pageContex,request,response和Scriptlet的一个实例作为参数,根据pageContext又可以得到application,session和JspWriter,那么这个类的成员函数就可以自由的使用这些固有对象了。同理,每一个自定义函数都接受如上同样的参数。

下面,我们看一下index.jsp的代码:
<%@ page contentType="text/html;charset=gb2312" %>
<%@ page import="javabbs.ConnectionPool" %>
<%@ page import="javabbs.Scriptlet" %>
<%@ page import="javabbs.Forum" %>
<%@ page import="javabbs.Templates" %>
<%@ page import="javabbs.UserOnline" %>
<%@ page import="java.sql.*" %>
<%@ page import="java.util.Date" %>
<jsp:useBean class="javabbs.ConnectionPool" id="objConnectionPool" scope="application" />
<%
//Scriptlet是一个类,用来封装每一个页面中的变量,以便作为参数传递给各个类和函数
Scriptlet objScriptlet = new Scriptlet();
//获取页面运行的开始时间:
objScriptlet.startTime = (new Date()).getTime();
Forum objForum = new Forum(pageContext,request,response,objScriptlet);
Templates objTemplates = new Templates(pageContext,request,response,objScriptlet);
UserOnline objUserOnline = new UserOnline(pageContext,request,response,objScriptlet);
objForum.getForumSetting();
objForum.checkUserLogin();
if(request.getParameter("w") !=null && request.getParameter("w").equals("1")){
passportMain(pageContext,request,response,objScriptlet);
}

if(request.getParameter("action") != null && request.getParameter("action").equals("xml")){
showxml(pageContext,request,response,objScriptlet);
}else{
main(pageContext,request,response,objScriptlet);
}
try{
Thread.sleep(1234);
}catch(Exception e){
}
//获取页面运行结束时的时间
objScriptlet.endTime = (new Date()).getTime();
%>
该页面的运行时间为:<br>
<%=(objScriptlet.endTime - objScriptlet.startTime)*0.001%>秒
<%!
//定义函数
public void passportMain(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
JspWriter out = pageContext.getOut();
try{
out.println("调用passportMain()...<br>");
}catch(Exception e){
}
}

public void showxml(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
JspWriter out = pageContext.getOut();
try{
out.println("调用showxml()...<br>");
}catch(Exception e){
}
}

public void main(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
JspWriter out = pageContext.getOut();
try{
out.println("调用main()...<br>");
}catch(Exception e){
}
}
%>

运行结果如下:
构造objForum对象...
构造objTemplates对象...
构造objUserOnline对象...
调用objForum.getForumSetting()...
调用objForum.checkUserLogin()...
调用main()...
该页面的运行时间为:
1.234秒

其中用到的几个类的源代码列出如下:
Scriptlet.java
package javabbs;

/**
*
* @author 京山游侠
*
* 该类用来封装教本文件中使用的变量
*/
public class Scriptlet {
//页面开始执行的时间:
public long startTime;
//页面结束执行时间
public long endTime;

public Scriptlet(){

}

}

搜索更多相关主题的帖子: 源代码 JSP jsp index 
2006-06-14 20:40
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

Forum.java
package javabbs;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public class Forum {
private PageContext pageContext = null;
private HttpServletRequest request = null;
private HttpServletResponse response = null;
private Scriptlet objScriptlet = null;
private JspWriter out = null;

public Forum(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
this.pageContext = pageContext;
this.request = request;
this.response = response;
this.objScriptlet = objScriptlet;
out = pageContext.getOut();
try{
out.println("构造objForum对象...<br>");
}catch(Exception ex){
}
}

public void getForumSetting(){
try{
out.println("调用objForum.getForumSetting()...<br>");
}catch(Exception ex){
}
}

public void checkUserLogin(){
try{
out.println("调用objForum.checkUserLogin()...<br>");
}catch(Exception ex){
}
}
}


相濡以沫,不如相忘于江湖
2006-06-14 20:40
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

Templates.java
package javabbs;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public class Templates {
private PageContext pageContext = null;
private HttpServletRequest request = null;
private HttpServletResponse response = null;
private Scriptlet objScriptlet = null;
private JspWriter out = null;

public Templates(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
this.pageContext = pageContext;
this.request = request;
this.response = response;
this.objScriptlet = objScriptlet;
out = pageContext.getOut();
try{
out.println("构造objTemplates对象...<br>");
}catch(Exception ex){
}
}
}


相濡以沫,不如相忘于江湖
2006-06-14 20:41
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

UserOnline.java

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public class UserOnline {
private PageContext pageContext = null;
private HttpServletRequest request = null;
private HttpServletResponse response = null;
private Scriptlet objScriptlet = null;
private JspWriter out = null;

public UserOnline(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
this.pageContext = pageContext;
this.request = request;
this.response = response;
this.objScriptlet = objScriptlet;
out = pageContext.getOut();
try{
out.println("构造objUserOnline对象...<br>");
}catch(Exception ex){
}
}

}


相濡以沫,不如相忘于江湖
2006-06-14 20:41
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

今天分析了Forum类的构造函数,发现其中的主要逻辑是:
1.从客户的Cookie中获取username,userid,password和userclass
2.获取客户的IP地址,以及使用的代理服务器的地址
3.还有一段我看不懂的代码,如下:
Dim Tmpstr
Tmpstr = Request.ServerVariables("PATH_INFO")
Tmpstr = Split(Tmpstr,"/")
ScriptName = Lcase(Tmpstr(UBound(Tmpstr)))
ScriptFolder = Lcase(Tmpstr(UBound(Tmpstr)-1)) & "/"
MemberClass = checkStr(Request.Cookies(Forum_sn)("userclass"))
Page_Admin=False
If InStr(ScriptName,"showerr")>0 Or InStr(ScriptName,"login")>0 Or InStr(ScriptName,"admin_")>0 Then Page_Admin=True
sendmsgnum=0:sendmsgid=0:sendmsguser=""
''模拟HTML部分开始
Is_Isapi_Rewrite = 0
If Is_Isapi_Rewrite = 0 Then ModHtmlLinked = "?"
ArchiverType = 0
If InStr(ScriptName,"indexhtml.asp") > 0 Then
iArchiverUrl = Lcase(Request.ServerVariables("QUERY_STRING"))
If iArchiverUrl <> "" Then
ArchiverUrl = iArchiverUrl
iArchiverUrl = Split(iArchiverUrl,"_")
If iArchiverUrl(0) = "list" And Ubound(iArchiverUrl) = 5 Then
If IsNumeric(iArchiverUrl(1)) Then
ArchiverType = 1
BoardID = Clng(iArchiverUrl(1))
End If
End If
End If
End If
''模拟HTML部分结束
''Response.Write Server.MapPath("index.asp")
''response.end
这里的逻辑是先获取用户请求的脚本文件和教本文件的路径,然后判断,如果教本文件为indexhtml.jsp则执行一段代码,但是,整个动网的目录下面也没有indexhtml.asp文件,因此我不知道这段代码的作用。

根据如上的分析,我编写的等效的Forum类如下:
package javabbs;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public class Forum {
private PageContext pageContext ;
private HttpServletRequest request ;
private HttpServletResponse response ;
private Scriptlet objScriptlet ;
private JspWriter out ;

//定义变量
String strForumSN,strCatchName,strBoardID,strMemberName,strMemberWord;
String strUserHidden,strUserID,strUserTrueIP,strActForIP,strMemberClass;
int nSqlQueryNum,nBoardID,nUserHidden,nUserID,IP_MAX;

public Forum(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
this.pageContext = pageContext;
this.request = request;
this.response = response;
this.objScriptlet = objScriptlet;
out = pageContext.getOut();
try{
out.println("构造objForum对象...<br>");
}catch(Exception ex){
}

strForumSN = "DvForum";
strCatchName = "DvCatch";
nSqlQueryNum = 0;
//获取board id
strBoardID = request.getParameter("BoardID");
if(strBoardID == null || strBoardID.length() == 0){
nBoardID = 0;
}else{
try{
nBoardID = Integer.parseInt(strBoardID);
}catch(NumberFormatException e){
nBoardID = 0;
}
}
//从Cookies中间获取用户名,密码,是否隐身和UserID,MemberClass
Cookie[] arrCookes = request.getCookies();
for(int i=0; i<arrCookes.length; i++){
if(arrCookes[i].getName().equals("username")){
strMemberName = checkStr(arrCookes[i].getValue().trim());
}
if(arrCookes[i].getName().equals("password")){
strMemberWord = checkStr(arrCookes[i].getValue().trim());
}
if(arrCookes[i].getName().equals("userhidden")){
strUserHidden = arrCookes[i].getValue().trim();
}
if(arrCookes[i].getName().equals("UserID")){
strUserID = arrCookes[i].getValue().trim();
}
if(arrCookes[i].getName().equals("userclass")){
strMemberClass = arrCookes[i].getValue().trim();
}
}
//将strUserHidden和strUserID转化为数值
try{
nUserHidden = Integer.parseInt(strUserHidden);
}catch(NumberFormatException e){
nUserHidden = 2;
}
try{
nUserID = Integer.parseInt(strUserID);
}catch(NumberFormatException e){
nUserID = 0;
}
//获取客户的IP
strUserTrueIP = getIP();
IP_MAX = 0;
}

public String checkStr(String strIn){
if(strIn == null){
return "";
}
strIn = strIn.replaceAll("\00", "");
strIn = strIn.replaceAll("''", "''''");
return strIn;
}

public String getIP(){
String strIpAddr;
String tempstr = request.getHeader("HTTP_X_FORWARDED_FOR");
if(tempstr ==null || tempstr.indexOf("unknown")!=-1){
strIpAddr = request.getRemoteAddr();
}else if(tempstr.indexOf(",")>-1){
strIpAddr = tempstr.substring(0, tempstr.indexOf(",")-1);
strActForIP = request.getRemoteAddr();
}else if(tempstr.indexOf(";")>-1){
strIpAddr = tempstr.substring(0, tempstr.indexOf(";")-1);
strActForIP = request.getRemoteAddr();
}else{
strIpAddr = tempstr;
strActForIP = request.getRemoteAddr();
}
return checkStr(strIpAddr.trim());
}

public void getForumSetting(){
try{
out.println("调用objForum.getForumSetting()...<br>");
}catch(Exception ex){
}
}

public void checkUserLogin(){
try{
out.println("调用objForum.checkUserLogin()...<br>");
}catch(Exception ex){
}
}
}


相濡以沫,不如相忘于江湖
2006-06-14 20:42
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

由于Templates类没有构造函数,所以我们接下来要研究的是UserOnline类的构造函数
UserOnline类构造函数的逻辑是这样的:
1.把Reloadtime设置为60分钟
2.判断是否到期,如果到期,则更新Application中的在线用户数据,否则,从Application中获取用户在线数据
3.用户在线数据包括总在线人数,在线会员数和在线客人数

根据分析,我们得到等效的Java代码为:
package javabbs;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.sql.*;

public class UserOnline {
private PageContext pageContext ;
private HttpServletRequest request ;
private HttpServletResponse response ;
private Scriptlet objScriptlet ;
private JspWriter out ;

//定义数据保存在线用户总数,在线会员总数和在线游客总数
public int nForumOnline, nForumUserOnline,nForumGuestOnline;
private int nOnline,nGuestOnline;

public UserOnline(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
this.pageContext = pageContext;
this.request = request;
this.response = response;
this.objScriptlet = objScriptlet;
out = pageContext.getOut();
try{
out.println("构造objUserOnline对象...<br>");
}catch(Exception ex){
}
//判断从上次更新在线用户到现在是否超时,如果超时则刷新
objScriptlet.objForum.nReloadTime = 60; //每60分钟刷新一次
if(objScriptlet.objForum.isObjEmpty("Forum_Online")){
RefreshOnlineNum();
}
nForumOnline = (Integer)(objScriptlet.objForum.getCatchValue("Forum_Online"));
nForumUserOnline = (Integer)(objScriptlet.objForum.getCatchValue("Forum_UserOnline"));
nForumGuestOnline = nForumOnline - nForumUserOnline;
nOnline = -1;
nGuestOnline = -1;
objScriptlet.objForum.nReloadTime = 28800;
}

public void RefreshOnlineNum(){
ResultSet rs;
try{
rs = objScriptlet.objForum.excute("Select Count(*) From Dv_Online");
rs.first();
objScriptlet.objForum.setCatchValue("Forum_Online",rs.getLong(0));
rs.close();
rs = objScriptlet.objForum.excute("Select Count(*) From Dv_Online Where UserID>0");
rs.first();
objScriptlet.objForum.setCatchValue("Forum_UserOnline",rs.getLong(0));
rs.close();
}catch(Exception e){

}
}

}


相濡以沫,不如相忘于江湖
2006-06-14 20:42
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
//判断某一个对象是否在application中存在和过期
public boolean isObjEmpty(String strObjectName){
Long nOldTime;
nOldTime = (Long)application.getAttribute(strCatchName + "_" + strObjectName + "_time");
if(nOldTime == null)return true;
if((new Date()).getTime() - nOldTime > nReloadTime*60*1000){
return true;
}
return false;
}

public ResultSet excute(String strSQL){

ConnectionPool objConnectionPool = (ConnectionPool)application.getAttribute("objConnectionPool");
Connection con = objConnectionPool.getConnection();
ResultSet rs;
try{
Statement stmt = con.createStatement();
rs = stmt.executeQuery(strSQL);
}catch(Exception e){
rs = null;
}
objConnectionPool.releaseConnection(con);
nSqlQueryNum ++ ;
return rs;
}

public Object getCatchValue(String strObjectName){
return application.getAttribute(strCatchName + "_" + strObjectName);
}

public void setCatchValue(String strObjectName, Object obj){
application.setAttribute(strCatchName + "_" + strObjectName, obj);
application.setAttribute(strCatchName + "_" + strObjectName + "_time", (new Date()).getTime());
}

相濡以沫,不如相忘于江湖
2006-06-14 20:44
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
下面来进行测试

index.jsp的代码如下:
<%@ page contentType="text/html;charset=gb2312" %>
<%@ page import="javabbs.ConnectionPool" %>
<%@ page import="javabbs.Scriptlet" %>
<%@ page import="javabbs.Forum" %>
<%@ page import="javabbs.Templates" %>
<%@ page import="javabbs.UserOnline" %>
<%@ page import="java.sql.*" %>
<%@ page import="java.util.Date" %>
<jsp:useBean class="javabbs.ConnectionPool" id="objConnectionPool" scope="application" />
<%
//Scriptlet是一个类,用来封装每一个页面中的变量,以便作为参数传递给各个类和函数
Scriptlet objScriptlet = new Scriptlet();
//获取页面运行的开始时间:
objScriptlet.startTime = (new Date()).getTime();
objScriptlet.objForum = new Forum(pageContext,request,response,objScriptlet);
Templates objTemplates = new Templates(pageContext,request,response,objScriptlet);
UserOnline objUserOnline = new UserOnline(pageContext,request,response,objScriptlet);
objScriptlet.objForum.getForumSetting();
objScriptlet.objForum.checkUserLogin();
if(request.getParameter("w") !=null && request.getParameter("w").equals("1")){
passportMain(pageContext,request,response,objScriptlet);
}

if(request.getParameter("action") != null && request.getParameter("action").equals("xml")){
showxml(pageContext,request,response,objScriptlet);
}else{
main(pageContext,request,response,objScriptlet);
}


out.println("在线用户人数:" + application.getAttribute("DvCatch_Forum_Online") + "<br>");
out.println("在线会员人数:" + objUserOnline.nForumUserOnline + "<br>");
out.println("在线游客人数:" + objUserOnline.nForumGuestOnline + "<br>");
out.println("数据库查询次数:" + objScriptlet.objForum.nSqlQueryNum + "<br>");
out.println("访问该页面的IP为:"+request.getRemoteAddr()+"<br>");
//获取页面运行结束时的时间
objScriptlet.endTime = (new Date()).getTime();
%>
该页面的运行时间为:
<%=(objScriptlet.endTime - objScriptlet.startTime)*0.001%>秒
<%!
//定义函数
public void passportMain(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
JspWriter out = pageContext.getOut();
try{
out.println("调用passportMain()...<br>");
}catch(Exception e){
}
}

public void showxml(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
JspWriter out = pageContext.getOut();
try{
out.println("调用showxml()...<br>");
}catch(Exception e){
}
}

public void main(PageContext pageContext,HttpServletRequest request,HttpServletResponse response,Scriptlet objScriptlet){
JspWriter out = pageContext.getOut();
try{
out.println("调用main()...<br>");
}catch(Exception e){
}
}
%>

得到的结果为:
构造objForum对象...
构造objTemplates对象...
构造objUserOnline对象...
调用objForum.getForumSetting()...
调用objForum.checkUserLogin()...
调用main()...
在线用户人数:1
在线会员人数:1
在线游客人数:0
数据库查询次数:2
访问该页面的IP为:127.0.0.1
该页面的运行时间为: 0.015秒

由此可见,使用Java访问Mysql数据库速度是相当快的,只需要15毫秒

这里创建数据表的SQL语句如下:
create table Dv_Online(
id double,
username varchar(50),
userclass varchar(20),
stats varchar(250),
ip varchar(40),
actforip varchar(40),
startime datetime,
lasttimebak datetime,
boardid long,
browser varchar(250),
usergroupid long,
actCome varchar(50),
userid long);

使用下面的语句向表中添加一行记录
insert into Dv_Online values(1,''admin'',''管理员'',''Error-错误信息'',''127.0.0
.1'',''127.0.0.1'',now(),now(),1,''Windows XP | IE6.0'',1,'''',1);


相濡以沫,不如相忘于江湖
2006-06-14 20:44
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
关于使用JDBC进行数据库访问,这里还存在一个问题,就是Statement对象的资源没有释放。
我们的代码完全模拟了DvBBS的代码,也就是使用Forum类的execute方法来执行一个查询,该方法会返回一个ResultSet对象,在该方法内部,使用了Statement对象,但是这个Statement对象是不能够调用close方法的,因为Statement对象不能在ResultSet对象之前关闭,因此,这就会造成资源没有释放的问题。

幸好,ResultSet方法提供的getStatement方法可以帮我们解决这个问题。

相濡以沫,不如相忘于江湖
2006-06-14 20:45
快速回复:[原创]动网论坛源代码解读及其向JSP的移植——第四章,编写index.jsp
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.022448 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved