??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲美女视频免费,亚洲精品午夜国产VA久久成人,亚洲国产a∨无码中文777http://www.tkk7.com/balajinima/category/24466.htmlzh-cnSun, 02 Aug 2009 00:06:12 GMTSun, 02 Aug 2009 00:06:12 GMT60HTTP Session Q{载)(j)http://www.tkk7.com/balajinima/articles/289142.html李云?/dc:creator>李云?/author>Thu, 30 Jul 2009 09:07:00 GMThttp://www.tkk7.com/balajinima/articles/289142.htmlhttp://www.tkk7.com/balajinima/comments/289142.htmlhttp://www.tkk7.com/balajinima/articles/289142.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/289142.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/289142.htmlhttp://www.w3.org/Protocols/> http://www.w3.org/Protocols/Q是
"一ơ性单?协议?br />服务端不能主动连接客L(fng)Q只能被动等待ƈ{复客户端请求。客L(fng)q接服务端,?br />Z个HTTP RequestQ服务端处理hQƈ且返回一个HTTP Responsel客L(fng)Q本?br />HTTP Request-Response Cyclel束?br />我们看到QHTTP协议本nq不能支持服务端保存客户端的状态信息。于是,W(xu)eb Server
中引入了(jin)session的概念,用来保存客户端的状态信息?br />q里用一个Ş象的比喻来解释session的工作方式。假设W(wng)eb Server是一个商场的存包
处,HTTP Request是一个顾客,W一ơ来到存包处Q管理员把顾客的物品存放在某一?br />柜子里面Q这个柜子就相当于SessionQ,然后把一个号码牌交给q个֮Q作为取?a name="entrymore">
凭证Q这个号码牌是Session IDQ。顾客(HTTP RequestQ下一ơ来的时候,p?br />L(fng)牌(Session IDQ交l存包处QWeb ServerQ的理员。管理员Ҏ(gu)L(fng)?br />QSession IDQ找到相应的柜子QSessionQ,Ҏ(gu)֮QHTTP RequestQ的hQW(xu)eb
Server可以取出、更换、添加柜子(SessionQ中的物品,W(xu)eb Server也可以让֮
QHTTP RequestQ的L(fng)牌和L(fng)牌对应的柜子QSessionQ失效。顾客(HTTP
RequestQ的忘性很大,理员在֮回去的时候(HTTP ResponseQ都要重新提醒顾?br />C自己的号码牌QSession IDQ。这P֮QHTTP RequestQ下ơ来的时候,又
带着L(fng)牌回来了(jin)?br />Session ID实际上是在客L(fng)和服务端之间通过HTTP Request和HTTP Response传来?br />ȝ。号码牌QSession IDQ必d含在HTTP Request里面。关于HTTP Request的具?br />格式Q请参见HTTP协议Q?<http://www.w3.org/Protocols/>
http://www.w3.org/Protocols/Q。这里只做一个简单的介绍?br />在Java Web ServerQ即Servlet/JSP ServerQ中QSession ID用jsessionid表示Q请
参见Servlet规范Q?br />HTTP Request一般由3部分l成Q?br />Q?QRequest Line
q一行由HTTP MethodQ如GET或POSTQ、URL、和HTTP版本L(fng)成?br />例如QGET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
GET http://www.google.com/search?q=Tomcat HTTP/1.1
POST http://www.google.com/search HTTP/1.1
GET http://www.somsite.com/menu.do;jsessionid=1001 HTTP/1.1

Q?QRequest Headers
q部分定义了(jin)一些重要的头部信息Q如Q浏览器的种c,语言Q类型。Request
Headers中还可以包括Cookie的定义。例如:(x)
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
Accept-Language: en-us
Cookie: jsessionid=1001

Q?QMessage Body
如果HTTP Method是GETQ那么Message Body为空?br />如果HTTP Method是POSTQ说明这个HTTP Request是submit一个HTML Form的结果,
那么Message Body为HTML Form里面定义的Input属性。例如,
user=guest
password=guest
jsessionid=1001
LQ如果把HTML Form元素的Method属性改为GET。那么,Message Body为空Q所有的
Input属性都?x)加在URL的后面。你在浏览器的URL地址栏中?x)看到这些属性,cM?br />http://www.somesite/login.do?user=guest&password=guest&jsessionid=1001

从理Z来说Q这3个部分(Request URLQCookie Header, Message BodyQ都可以?br />来存放Session ID。由于Message BodyҎ(gu)必须需要一个包含Session ID的HTML
FormQ所以这U方法不通用?br />一般用来实现Session的方法有两种Q?br />Q?QURL重写?br />Web Server在返回Response的时候,(g)查页面中所有的URLQ包括所有的q接Q和HTML
Form的Action属性,在这些URL后面加上";jsessionid=XXX"?br />下一ơ,用户讉Kq个面中的URL。jsessionid׃(x)传回到Web Server?br />Q?QCookie?br />如果客户端支持CookieQW(xu)eb Server在返回Response的时候,在Response的Header?br />分,加入一?set-cookie: jsessionid=XXXX"header属性,把jsessionid攑֜
Cookie里传到客L(fng)?br />客户端会(x)把Cookie存放在本地文仉Q下一ơ访问Web Server的时候,再把Cookie的信
息放到HTTP Request?Cookie"header属性里面,q样jsessionid随着HTTP
Requestq回lWeb Server?br />
二、相兌?br />
前面是我自作聪明的一D个人浅见,下面我来扄权威资料支持?br /><http://www.w3.org/Protocols/> http://www.w3.org/Protocols/

Use of HTTP State Management (
<ftp://ftp.rfc-editor.org/in-notes/rfc2964.txt> RFC 2964).
<ftp://ftp.rfc-editor.org/in-notes/rfc2964.txt>
ftp://ftp.rfc-editor.org/in-notes/rfc2964.txt

q个文g是定?HTTP State Management"扩展协议部分。里面有q么一D,
It's important to realize that similar capabilities may also be (tng) (tng) (tng) (tng)achieved
using the "bare" HTTP protocol, and/or dynamically-generated
HTML, without the State Management extensions. (tng) (tng)For example, state
information can be transmitted from the service to the user by (tng) (tng) (tng) (tng)embedding
a session identifier in one or more URLs which appear in HTTP redirects, or
dynamically generated HTML; and the state information may be returned from
the user to the service when such URLs appear in a GET or POST request.
HTML forms can also be used to pass state information from the service to
the user and back, without the user being aware of this happening.

q段话的意思是_(d)不用q个 "HTTP State Management"扩展协议部分Q我们也可以
?Ua(b)"的HTTP协议实现Session -- 比如URL重写QHTML Form{?br />q里面没有提到Cookie。因?HTTP State Management" 扩展协议部分本n包括?jin)?br />于Cookie的内宏V这一点可以通过
HTTP State Management Mechanism (RFC 2965
<ftp://ftp.rfc-editor.org/in-notes/rfc2965.txt> ),
<ftp://ftp.rfc-editor.org/in-notes/rfc2965.txt>
ftp://ftp.rfc-editor.org/in-notes/rfc2965.txt
看出来?br />
STATE AND SESSIONS
This document describes a way to create stateful sessions with HTTP
requests and responses. (tng) (tng)Currently, HTTP servers respond to each (tng) (tng) (tng) (tng)client
request without relating that request to previous or (tng) (tng) (tng) (tng)subsequent requests;
the state management mechanism allows clients (tng) (tng) (tng) (tng)and servers that wish to
exchange state information to place HTTP (tng) (tng) (tng) (tng)requests and responses within a
larger context, which we term a (tng) (tng) (tng) (tng)"session". (tng) (tng)This context might be used to
create, for example, a (tng) (tng) (tng) (tng)"shopping cart", in which user selections can be
aggregated before (tng) (tng) (tng) (tng)purchase, or a magazine browsing system, in which a
user's previous (tng) (tng) (tng) (tng)reading affects which offerings are presented.
Neither clients nor servers are required to support cookies. (tng) (tng)A (tng) (tng) (tng) (tng)server
MAY refuse to provide content to a client that does not return (tng) (tng) (tng) (tng)the
cookies it sends.

后面q给Z(jin)例子Q其中的汉语部分是我加的Q?br />
4.1 (tng) (tng)Example 1
Most detail of request and response headers has been omitted. (tng) (tng)Assume
the user agent has no stored cookies.

 (tng) (tng) (tng) (tng) 1. User Agent -> Server

 (tng) (tng) (tng) (tng) (tng) (tng) POST /acme/login HTTP/1.1
 (tng) (tng) (tng) (tng) (tng) (tng) [form data]

 (tng) (tng) (tng) (tng) (tng) (tng) User identifies self via a form.

 (tng) (tng) (tng) (tng) 2. Server -> User Agent

 (tng) (tng) (tng) (tng) (tng) (tng) HTTP/1.1 200 OK
 (tng) (tng) (tng) (tng) (tng) (tng) Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"

 (tng) (tng) (tng) (tng) (tng) (tng) Cookie reflects user's identity.
Q这里面?Customer="WILE_E_COYOTE" 应该是从Form Data里面来的Q这时候又?br />回给?jin)客L(fng)Q?br />
 (tng) (tng) (tng) (tng) 3. User Agent -> Server

 (tng) (tng) (tng) (tng) (tng) (tng) POST /acme/pickitem HTTP/1.1
 (tng) (tng) (tng) (tng) (tng) (tng) Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
 (tng) (tng) (tng) (tng) (tng) (tng) [form data]

 (tng) (tng) (tng) (tng) (tng) (tng) User selects an item for "shopping basket".

 (tng) (tng) (tng) (tng) 4. Server -> User Agent

 (tng) (tng) (tng) (tng) (tng) (tng) HTTP/1.1 200 OK
 (tng) (tng) (tng) (tng) (tng) (tng) Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Path="/acme"

 (tng) (tng) (tng) (tng) (tng) (tng) Shopping basket contains an item.
Q这个火发器昄也是从Form Data来的。但Z?br />Part_Number="Rocket_Launcher_0001"也需要传回给客户端?
Customer="WILE_E_COYOTE"; 应该是在传统?Set-Cookie"里面传回l客L(fng)的?
Set-Cookie2" 的作用应该是向Cookie里面d东西。)(j)

 (tng) (tng) (tng) (tng) 5. User Agent -> Server

 (tng) (tng) (tng) (tng) (tng) (tng) POST /acme/shipping HTTP/1.1
 (tng) (tng) (tng) (tng) (tng) (tng) Cookie: $Version="1";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Customer="WILE_E_COYOTE"; $Path="/acme";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Part_Number="Rocket_Launcher_0001"; $Path="/acme"
 (tng) (tng) (tng) (tng) (tng) (tng) [form data]

 (tng) (tng) (tng) (tng) (tng) (tng) User selects shipping method from form.

Q客户传l服务器的Cookie里面包括?jin)Customer和Part_NumberQ?br />
 (tng) (tng) (tng) (tng) 6. Server -> User Agent

 (tng) (tng) (tng) (tng) (tng) (tng) HTTP/1.1 200 OK
 (tng) (tng) (tng) (tng) (tng) (tng) Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"

 (tng) (tng) (tng) (tng) (tng) (tng) New cookie reflects shipping method.

 (tng) (tng) (tng) (tng) 7. User Agent -> Server

 (tng) (tng) (tng) (tng) (tng) (tng) POST /acme/process HTTP/1.1
 (tng) (tng) (tng) (tng) (tng) (tng) Cookie: $Version="1";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Customer="WILE_E_COYOTE"; $Path="/acme";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Part_Number="Rocket_Launcher_0001"; $Path="/acme";
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Shipping="FedEx"; $Path="/acme"
 (tng) (tng) (tng) (tng) (tng) (tng) [form data]


 (tng) (tng) (tng) (tng) (tng) (tng) User chooses to process order.

 (tng) (tng) (tng) (tng) 8. Server -> User Agent

 (tng) (tng) (tng) (tng) (tng) (tng) HTTP/1.1 200 OK

 (tng) (tng) (tng) (tng) (tng) (tng) Transaction is complete.

 (tng) (tng)The user agent makes a series of requests on the origin server, after
each of which it receives a new cookie. (tng) (tng)All the cookies have the same Path
attribute and (default) domain. (tng) (tng)Because the request-URIs all path-match
/acme, the Path attribute of each cookie, each request contains all the
cookies received so far.
Q看到这里,我才大致明白Q原来那?Path="/acme" 大致L(fng) JSessionID的作用)(j)


三、Tomcat5的HTTP Session实现

下面我们来看Tomcat5的源代码如何支持HTTP 1.1 Session?br />我们可以用jsessionid, Set-Cookie{关键字搜烦(ch)Tomcat5源代码?br />
首先Q我们来看常量定义:(x)
org.apache.catalina.Globals

 (tng) (tng) /**
 (tng) (tng) (tng) (tng)* The name of the cookie used to pass the session identifier back
 (tng) (tng) (tng) (tng)* and forth with the client.
 (tng) (tng) (tng) (tng)*/
 (tng) (tng) public static final String SESSION_COOKIE_NAME = "JSESSIONID";


 (tng) (tng) /**
 (tng) (tng) (tng) (tng)* The name of the path parameter used to pass the session identifier
 (tng) (tng) (tng) (tng)* back and forth with the client.
 (tng) (tng) (tng) (tng)*/
public static final String SESSION_PARAMETER_NAME = "jsessionid";

Cookie里面用大写的JSESSIONIDQURL后缀用的是小写的jsessionid?br />Session的具体实现类是org.apache.catalina.session.StandardSession。一个Tomcat
Server的所有Session都由一个ManagerQ拥有一个ContextQ统一理。我估计有一?br />Session Listener 专门理Cluster之间的Session数据复制Q具体的我没有追查下
厅R?br />
另外几个重要的相关类是org.apache.coyote.tomcat5包下面的CoyoteRequest ,
CoyoteResponse, CoyoteAdapter三个cR?br />
org.apache.coyote.tomcat5.CoyoteResponsecȝtoEncoded()Ҏ(gu)支持URL重写?br />String toEncoded(String url, String sessionId) {
...
 (tng) (tng) (tng) (tng) (tng) (tng) StringBuffer sb = new StringBuffer(path);
 (tng) (tng) (tng) (tng) (tng) (tng) if( sb.length() > 0 ) { // jsessionid can't be first.
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) sb.append(";jsessionid=");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) sb.append(sessionId);
 (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) sb.append(anchor);
 (tng) (tng) (tng) (tng) (tng) (tng) sb.append(query);
 (tng) (tng) (tng) (tng) (tng) (tng) return (sb.toString());
}

我们来看org.apache.coyote.tomcat5.CoyoteRequest的两个方?br />configureSessionCookie()
doGetSession()用Cookie支持jsessionid.

 (tng) (tng) /**
 (tng) (tng) (tng) (tng)* Configures the given JSESSIONID cookie.
 (tng) (tng) (tng) (tng)*
 (tng) (tng) (tng) (tng)* @param cookie The JSESSIONID cookie to be configured
 (tng) (tng) (tng) (tng)*/
 (tng) (tng) protected void configureSessionCookie(Cookie cookie) {
 (tng) (tng) (tng) (tng) (tng) (tng)...
 (tng) (tng) }

 (tng) (tng) HttpSession doGetSession(boolean create){
 (tng) (tng) (tng) (tng) ...
 (tng) (tng) (tng) (tng) (tng) (tng) // Creating a new session cookie based on that session
 (tng) (tng) (tng) (tng) (tng) (tng) if ((session != null) && (getContext() != null)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)&& getContext().getCookies()) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)session.getId());
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) configureSessionCookie(cookie);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ((HttpServletResponse) response).addCookie(cookie);
 (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) ...
 (tng) (tng) }


四、More

HTTP Session的协议、规范、实现大概就是这些?br />另外Q在frameset中用Session的情冉|些复杂,不同环境表现可能不同?br />其余相关的概忉|"单点d"(Sing Sign On - SSO), Domain, Cluster, Proxy,
Cache{?!-- Added by RelatedTopic, plugin for Bo-Blog 2.0.0 -->

]]>
pȝ权限解决Ҏ(gu)(转蝲)http://www.tkk7.com/balajinima/articles/249745.html李云?/dc:creator>李云?/author>Sun, 04 Jan 2009 07:40:00 GMThttp://www.tkk7.com/balajinima/articles/249745.htmlhttp://www.tkk7.com/balajinima/comments/249745.htmlhttp://www.tkk7.com/balajinima/articles/249745.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/249745.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/249745.html
每个软g中都有权限这个功能,搞了(jin)个通过tag实现的方?复用性很强,


psy-operation.tld

Xml代码
<?xml version="1.0" encoding="UTF-8" ?> (tng)
<taglib xmlns=" (tng) (tng) (tng) xmlns:xsi=" (tng) (tng) (tng) xsi:schemaLocation="http://www.blog.com.cn/http://java.sun.com/xml/ns/j2ee (tng) (tng) (tng) version=" (tng) <description> (tng)
 (tng)psychcn 标记?1.0 (tng) (tng)
 (tng) </description> (tng)
 (tng) <tlib-version>1.0</tlib-version> (tng)
 (tng) <short-name>psydict</short-name> (tng)
 (tng) <uri>http://www.psychcn.com/taglibs</uri> (tng)
 (tng) (tng) (tng) <tag> (tng)
 (tng) (tng) (tng) <name>op</name> (tng)
 (tng) (tng) (tng) <description>权限标签</description> (tng)
 (tng) (tng) (tng) <tag-class>com.psychcn.web.tags.OperationTag</tag-class> (tng)
 (tng)<body-content>scriptless</body-content> (tng)
 (tng) (tng) (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) <attribute> (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) <name>code</name> (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) <required>true</required> (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) <rtexprvalue>true</rtexprvalue> (tng)
 (tng) (tng) (tng) </attribute> (tng)
 (tng) (tng) (tng) <attribute> (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) <name>opset</name> (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) <required>false</required> (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) <rtexprvalue>true</rtexprvalue> (tng)
 (tng) (tng) (tng) </attribute> (tng) (tng) (tng) (tng) (tng) (tng)
 (tng) </tag> (tng)
</taglib> (tng)

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="
 (tng) (tng) (tng) xmlns:xsi=" (tng) (tng) (tng) xsi:schemaLocation="http://www.blog.com.cn/http://java.sun.com/xml/ns/j2ee (tng) (tng) (tng) version=" (tng) <description>
 (tng)psychcn 标记?1.0
 (tng) </description>
 (tng) <tlib-version>1.0</tlib-version>
 (tng) <short-name>psydict</short-name>
 (tng) <uri>http://www.psychcn.com/taglibs</uri>
 (tng) (tng) (tng) <tag>
 (tng) (tng) (tng) <name>op</name>
 (tng) (tng) (tng) <description>权限标签</description>
 (tng) (tng) (tng) <tag-class>com.psychcn.web.tags.OperationTag</tag-class>
 (tng)<body-content>scriptless</body-content>
 (tng) (tng) (tng)
 (tng) (tng) (tng) <attribute>
 (tng) (tng) (tng) (tng) (tng) (tng) <name>code</name>
 (tng) (tng) (tng) (tng) (tng) (tng) <required>true</required>
 (tng) (tng) (tng) (tng) (tng) (tng) <rtexprvalue>true</rtexprvalue>
 (tng) (tng) (tng) </attribute>
 (tng) (tng) (tng) <attribute>
 (tng) (tng) (tng) (tng) (tng) (tng) <name>opset</name>
 (tng) (tng) (tng) (tng) (tng) (tng) <required>false</required>
 (tng) (tng) (tng) (tng) (tng) (tng) <rtexprvalue>true</rtexprvalue>
 (tng) (tng) (tng) </attribute> (tng) (tng) (tng)
 (tng) </tag>
</taglib>

OperationTag.java

Java代码
import javax.servlet.jsp.JspException; (tng) (tng)
import javax.servlet.jsp.tagext.SimpleTagSupport; (tng) (tng)
 (tng)
import java.io.IOException; (tng) (tng)
import java.util.*; (tng) (tng)
 (tng)
public class OperationTag extends SimpleTagSupport { (tng) (tng)
 (tng)private Set operation_set; (tng) (tng)
 (tng)private String default_operation_set_name = "ops"; (tng) (tng)
 (tng)private String code; (tng) (tng)
 (tng) (tng) (tng)
 (tng)public void setCode(String code) { (tng) (tng)
 (tng) this.code = code; (tng) (tng)
 (tng)} (tng) (tng)
 (tng)public void setOpset(Set operation_set) { (tng) (tng)
 (tng) this.operation_set = operation_set; (tng) (tng)
 (tng)} (tng) (tng)
 (tng)public void setOpsetName(String name) { (tng) (tng)
 (tng) this.default_operation_set_name= name; (tng) (tng)
 (tng)} (tng) (tng)
 (tng) (tng) (tng)
 (tng)public void doTag() throws JspException, IOException{ (tng) (tng)
 (tng) //session中没有设|权限HashSet,l默认值?tng)?
 (tng) if (operation_set==null) { (tng) (tng)
 (tng) (tng) Object o = this.getJspContext().findAttribute(default_operation_set_name); (tng) (tng)
 (tng) (tng) if (o instanceof Set) (tng) (tng)
 (tng) (tng) (tng) operation_set = (Set)o; (tng) (tng)
 (tng) } (tng) (tng)
 (tng) (tng) (tng) (tng)
 (tng) if (code == null || operation_set == null) (tng) (tng)
 (tng) (tng) throw new JspException("标签属性无?无法执行!"); (tng) (tng)
 (tng) (tng) (tng) (tng)
 (tng) //q里支持多个code,?,'分割,有一个符合条件就输出,全部不满_不输?注意不能有空?区分大小? (tng) (tng)
 (tng) String[] codes = code.split(","); (tng) (tng)
 (tng) for (String s : codes) { (tng) (tng)
 (tng) (tng) if (operation_set.contains(s)) { (tng) (tng)
 (tng) (tng) (tng) this.getJspBody().invoke(this.getJspContext().getOut()); (tng) (tng)
 (tng) (tng) (tng) return; (tng) (tng)
 (tng) (tng) } (tng) (tng)
 (tng) } (tng) (tng)
 (tng)} (tng) (tng)
} (tng)

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import java.io.IOException;
import java.util.*;

public class OperationTag extends SimpleTagSupport {
 (tng)private Set operation_set;
 (tng)private String default_operation_set_name = "ops";
 (tng)private String code;
 (tng)
 (tng)public void setCode(String code) {
 (tng) this.code = code;
 (tng)}
 (tng)public void setOpset(Set operation_set) {
 (tng) this.operation_set = operation_set;
 (tng)}
 (tng)public void setOpsetName(String name) {
 (tng) this.default_operation_set_name= name;
 (tng)}
 (tng)
 (tng)public void doTag() throws JspException, IOException{
 (tng) //session中没有设|权限HashSet,l默认?br /> (tng) if (operation_set==null) {
 (tng) (tng) Object o = this.getJspContext().findAttribute(default_operation_set_name);
 (tng) (tng) if (o instanceof Set)
 (tng) (tng) (tng) operation_set = (Set)o;
 (tng) }
 (tng)
 (tng) if (code == null || operation_set == null)
 (tng) (tng) throw new JspException("标签属性无?无法执行!");
 (tng)
 (tng) //q里支持多个code,?,'分割,有一个符合条件就输出,全部不满_不输?注意不能有空?区分大小?
 (tng) String[] codes = code.split(",");
 (tng) for (String s : codes) {
 (tng) (tng) if (operation_set.contains(s)) {
 (tng) (tng) (tng) this.getJspBody().invoke(this.getJspContext().getOut());
 (tng) (tng) (tng) return;
 (tng) (tng) }
 (tng) }
 (tng)}
}
 (tng)

 (tng)

底层查找权限接口Q?/p>

OperationService.java

Java代码
public java.util.HashSet<String> findByUserId(String userId) throws Exception; (tng) (tng)
实现接口c:(x)(//通过USERID扑ֈ对应的operation的code) (tng) (tng)
 (tng)
OperationServiceImpImp.java (tng) (tng)
 (tng)
 (tng)public java.util.HashSet<String> findByUserId(String userId) throws Exception{ (tng) (tng)
 (tng) Session s = getSession(); (tng) (tng)
 (tng) Transaction tx = s.beginTransaction(); (tng) (tng)
 (tng) (tng) (tng) (tng)
 (tng) String sql = "select DISTINCT o.code from users u " + (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) "inner join groupmember gm on u.userId=gm.user_Id " + (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) "inner join groupacl ga on gm.group_id=ga.group_id " + (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) "inner join operation o on ga.op_id = o.id " + (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) "where u.userId=?"; (tng) (tng)
 (tng) Query q = s.createSQLQuery(sql).setString(0,userId); (tng) (tng)
 (tng) List<Object> ls = q.list(); (tng) (tng)
 (tng) HashSet ops = new HashSet(); (tng) (tng)
 (tng) for(Object object : ls){ (tng) (tng)
 (tng) (tng) ops.add(object); (tng) (tng)
 (tng) } (tng) (tng)
 (tng) tx.commit(); (tng) (tng)
 (tng) releaseSession(s); (tng) (tng)
 (tng) (tng) (tng) (tng)
 (tng) return ops; (tng) (tng)
 (tng)} (tng)

public java.util.HashSet<String> findByUserId(String userId) throws Exception;
实现接口c:(x)(//通过USERID扑ֈ对应的operation的code)

OperationServiceImpImp.java

 (tng)public java.util.HashSet<String> findByUserId(String userId) throws Exception{
 (tng) Session s = getSession();
 (tng) Transaction tx = s.beginTransaction();
 (tng)
 (tng) String sql = "select DISTINCT o.code from users u " +
 (tng) (tng) (tng) (tng) (tng) "inner join groupmember gm on u.userId=gm.user_Id " +
 (tng) (tng) (tng) (tng) (tng) "inner join groupacl ga on gm.group_id=ga.group_id " +
 (tng) (tng) (tng) (tng) (tng) "inner join operation o on ga.op_id = o.id " +
 (tng) (tng) (tng) (tng) (tng) "where u.userId=?";
 (tng) Query q = s.createSQLQuery(sql).setString(0,userId);
 (tng) List<Object> ls = q.list();
 (tng) HashSet ops = new HashSet();
 (tng) for(Object object : ls){
 (tng) (tng) ops.add(object);
 (tng) }
 (tng) tx.commit();
 (tng) releaseSession(s);
 (tng)
 (tng) return ops;
 (tng)}

q样Q在用户dӞ可以把该用户的权限HashSet装蝲到Session?/p>

 (tng)

//把当前用L(fng)权限d到HashSet
 (tng) (tng)

Java代码
HashSet ops = AppResource.operationService.findByUserId(user.getUserId()); (tng) (tng)
session.setAttribute("ops",ops); (tng)

HashSet ops = AppResource.operationService.findByUserId(user.getUserId());
session.setAttribute("ops",ops);

最后,在JSP中就可以单的使用标签来判断有没有某个权限Q没有则不显C?/p>

Xml代码
<%@ taglib prefix="psy" uri="
<psy:op code="Finance_Payment">看你有没有权限让我显C?lt;/psy:op> (tng)

<%@ taglib prefix="psy" uri="<psy:op code="Finance_Payment">看你有没有权限让我显C?lt;/psy:op>

 (tng)

OKQ可以根据需要修攏V?br />



]]>
J2EE框架Qstruts+hibernate+springQ?/title><link>http://www.tkk7.com/balajinima/articles/218466.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Tue, 29 Jul 2008 08:28:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/218466.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/218466.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/218466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/218466.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/218466.html</trackback:ping><description><![CDATA[ <p>框架说白?jin)就是JAVA工作者多q以来ȝ出的一些开发标准。让我们可以以成功的l验模式来开发我们自已的pȝQ一般用框架的好处?<br />·在好的框架下Q开发者只需要写一些必ȝ代码Q他们不需要直接接触底层的API?q一点很重要?<br /><br />·l过良好设计的框架可以ؓ(f)E序提供清晰的结构ƈ且提高程序的内聚性。好清晰的结构得其他h可以更容易加入项目?<br /><br />·一个容易用的框架可以通过一些例子和文档为用h供最?jng)_c(din)?<br /><br />·采用成功的框架的代码比自q代码Ҏ(gu)试 <br /><br />J2EE本n提供?jin)一些框架。比如, Enterprise Java-Beans (EJB) container或?Servlet engine 而这些框架一般在中小工程中我们都不会(x)使用Q会(x)让我们把大量的时间浪费在开发框架上?<br />而现在比较流行开源框?主要是struts,hibernate,spring{?<br />比如struts是在原有mvc基础上实现在代码分离{功能,非常好用?<br />而hibernate可以把我们的关系型数据库转换成我们在JAVA中的面像对像来用。从而让我们在开发时不需要直接写SQL语句Q比如database.getName();可以直接把数据库中的用户名取出来?<br />Spring <br />J2EE框架被大规模地运用到目中,而项目总要负责q些框架以及(qing)自己业务代码的连接,使之真正融合C赗Spring是专注于这个问题的Q它和Hibernate融合的很好?<br />q三U框架在一起ƈ不冲H,所以现在最常用的框架就?<br />struts+hibernate+spring像我们盖房子一P先把框架搭好Q我们在在上面写代码很规范?<br /><br /><br />Struts框架介绍 :<br /><br />Struts只是一个MVC框架QF(tun)rameworkQ?用于快速开发Java Web应用。Struts实现的重点在C(Controller)Q包括ActionServlet/RequestProcessor和我们定制的 Action,也ؓ(f)V(View)提供?jin)一pd定制标签QCustom TagQ。但Struts几乎没有涉及(qing)M(Model),所以Struts可以采用JAVA实现的Q何Ş式的商业逻辑?<br />Spring是一个轻型容?light-weight container)Q其核心(j)是Bean工厂(Bean Factory)Q用以构造我们所需要的M(Model)。在此基之上QSpring提供?jin)AOPQAspect-Oriented Programming, 面向层面的编E)(j)的实玎ͼ用它来提供非理环境下申明方式的事务、安全等服务Q对Bean工厂的扩展ApplicationContext更加方便我们?现J2EE的应用;DAO/ORM的实现方便我们进行数据库的开发;Web MVC和Spring Web提供?jin)Java Web应用的框架或与其他流行的Web框架q行集成?<br />是说可两者一起用,辑ֈ两者自w的特点q行互补?br /><br /><br />spring 框架介绍 :<br /><br /><br />它关注的领域是其他许多流行的Framework未曾x(chng)的。Spring要提供的是一U管理你的业务对象的Ҏ(gu)?<br /><br />Spring既是全面的又是模块化的。Spring有分层的体系l构Q这意味着你能选择仅仅使用它Q何一个独立的部分Q而它的架构又是内部一致?因此你能从你的学?fn)中Q得到最大的价倹{例如,你可能选择仅仅使用Spring来简单化JDBC的用,或用来管理所有的业务对象?<br /><br />它的设计从一开始就是要帮助你编写易于测试的代码。Spring是用测试驱动开发的工程的理x(chng)架?<br /><br /><br />Spring不会(x)l你的工E添加对其他的框架依赖。Spring也许U得上是个一站式解决Ҏ(gu)Q提供了(jin)一个典型应用所需要的大部分基架构。它q涉?qing)到了(jin)其他framework没有考虑到的内容?<br /><br />管它仅仅是一个从2003q?月才开始的开源项目,但Spring有深厚的历史根基?/p> <p> <br />Spring架构上的好处 <br /><br />在我们进入细节之前,让我们来看看Spring能够l工E带来的U种好处Q?/p> <p>Spring能有效地l织你的中间层对象,不管你是否选择使用?jin)EJB。如果你仅仅使用?jin)Struts或其他ؓ(f)J2EE?API特制的frameworkQSpring致力于解军_下的问题?<br /><br />Spring能消除在许多工程中常见的对Singleton的过多用。根据我的经验,q是一个很大的问题Q它降低?jin)系l的可测试性和面向对象的程度?<br /><br />通过一U在不同应用E序和项目间一致的Ҏ(gu)来处理配|文ӞSpring能消除各U各栯定义格式的属性文件的需要。曾l对某个c要L的是哪个 法般的属性项或系l属性感C解,为此不得不去读Javadoc甚至源编码?有了(jin)SpringQ你仅仅需要看看类的JavaBean属性?Inversion of Control的用(在下面讨论)(j)帮助完成?jin)这U简化?<br /><br />通过把对接口~程而不是对cȝE的代h(hun)几乎减少到没有,Spring能够?j)进L好的~程?fn)惯?<br /><br />Spring被设计ؓ(f)让用它创徏的应用尽可能的依赖于他的APIs。在Spring应用中的大多C务对象没有依赖于Spring?<br /><br />使用Spring构徏的应用程序易于单元测试?<br /><br />Spring能EJB的用成Z个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实C务接口,却不?x)?jing)响调用代码?<br /><br />Spring帮助你解册多问题而无需使用EJB。Spring能提供一UEJB的替换物Q它们适用于许多web应用。例如,Spring能用AOP提供声明性事务管理而不通过EJB容器Q如果你仅仅需要与单个数据库打交道Q甚至不需要一个JTA实现?<br /><br />Spring为数据存取提供了(jin)一个一致的框架,不论是用的是JDBCq是O/R mapping产品Q如HibernateQ?/p> <img src ="http://www.tkk7.com/balajinima/aggbug/218466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2008-07-29 16:28 <a href="http://www.tkk7.com/balajinima/articles/218466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用filterqo(h)hhttp://www.tkk7.com/balajinima/articles/218464.html李云?/dc:creator>李云?/author>Tue, 29 Jul 2008 08:26:00 GMThttp://www.tkk7.com/balajinima/articles/218464.htmlhttp://www.tkk7.com/balajinima/comments/218464.htmlhttp://www.tkk7.com/balajinima/articles/218464.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/218464.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/218464.html

package anni;
public class EncodingFilter implements Filter {
 (tng) (tng) (tng) public void init(FilterConfig config) throws ServletException {}
 (tng) (tng) (tng) public void destroy() {}
 (tng) (tng) (tng) public void doFilter(ServletRequest request,
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ServletResponse response,
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) FilterChain chain)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) throws IOException, ServletException {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) request.setCharacterEncoding("gb2312");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) chain.doFilter(request, response);
 (tng) (tng) (tng) }
}

web.xml?br /><filter>
 (tng) (tng) (tng) <filter-name>EncodingFilter</filter-name>
 (tng) (tng) (tng) <filter-class>anni.EncodingFilter</filter-class>
</filter>
<filter-mapping>
 (tng) (tng) (tng) <filter-name>EncodingFilter</filter-name>
 (tng) (tng) (tng) <url-pattern>/*</url-pattern>
</filter-mapping>

filter标签部分定义使用的过滤器Qfilter-mapping标签告诉服务器把哪些h交给qo(h)器处理。这里的/*表示所有请求,/表示根\径,*Q星P(j)代表所有请求,加在一起就变成?jin)根路径下的所有请求。这P所有的h都会(x)先被EncodingFilter拦截Qƈ在请求里讄上指定的gb2312~码?/p>

================================
用filter控制用户讉K权限

我们要保护的面是admin/index.jspQؓ(f)此我们在web.xmlq行如下配置?br /><filter>
 (tng) (tng) (tng) <filter-name>SecurityFilter</filter-name>
 (tng) (tng) (tng) <filter-class>anni.SecurityFilter</filter-class>
</filter>
<filter-mapping>
 (tng) (tng) (tng) <filter-name>SecurityFilter</filter-name>
 (tng) (tng) (tng) <url-pattern>/admin/*</url-pattern>
</filter-mapping>

SecurityFilterqo(h)?
public void doFilter(ServletRequest request,
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) ServletResponse response,
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) FilterChain chain)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) throws IOException, ServletException {
 (tng) (tng) (tng) HttpServletRequest req = (HttpServletRequest) request;
 (tng) (tng) (tng) HttpServletResponse res = (HttpServletResponse) response;
 (tng) (tng) HttpSession session = req.getSession();
 (tng) (tng) (tng) if (session.getAttribute("username") != null) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) chain.doFilter(request, response);
 (tng) (tng) (tng) } else {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) res.sendRedirect("../failure.jsp");
 (tng) (tng) (tng) }
}

首先要将ServletRequest和ServletResponse转换成HttpServletRequest和HttpServletResponseQ因为Filter本来设计成ؓ(f)多种协议服务Qhttp协议仅仅是其中一部分。不q我们接触到的也只有httpQ而且也只有{换成对应HttpServletRequest和HttpServletResponse才能q行下面的session操作和页面重定向?br />得到?jin)httph之后Q可以获得请求对应的sessionQ判断session中的username变量是否为nullQ如果不为nullQ说明用户已l登录,可以调用doFilterl箋(hu)h讉K的资源。如果ؓ(f)nullQ说明用戯没有dQ禁止用戯问,q用页面重定向跌{到failure.jsp面昄提示信息?/p>

==================================
filter所谓的Ҏ(gu)?/p>

h映射
filter-mapping和servlet-mapping都是对应的filter或servlet映射到某个url-pattern上,当客户发h一hӞ服务器先此h与web.xml中定义的所有url-patternq行匚wQ然后执行匹配通过的filter和servlet?/p>

你可以用三U方式定义url-pattern?br />1.直接映射一个请求?br /><servlet-mapping>
 (tng) (tng) (tng) <servlet-name>ContactServlet</servlet-name>
 (tng) (tng) (tng) <url-pattern>/contact.do</url-pattern>
</servlet-mapping>
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)
2.映射一个\径下的所有请求?br /><servlet-mapping>
 (tng) (tng) (tng) <servlet-name>EncodingFilter</servlet-name>
 (tng) (tng) (tng) <url-pattern>/*</url-pattern>
</servlet-mapping>

3.映射l尾相同的一c请求?br /><servlet-mapping>
 (tng) (tng) (tng) <servlet-name>ControllerServlet</servlet-name>
 (tng) (tng) (tng) <url-pattern>*.do</url-pattern>
</servlet-mapping>

惌获得所有以user开?dol尾的请求吗Quser*.do在url-pattern是无法识别的Q只能配|成*.doQ再去servlet中对hq行{选?br />惌让一个servlet负责多个h吗?/user/*,/admin/*,*.do写在一起url-pattern也不认识Q只能配成多个servlet-mapping?br /><servlet-mapping>
 (tng) (tng) (tng) <servlet-name>ControllerServlet</servlet-name>
 (tng) (tng) (tng) <url-pattern>/user/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
 (tng) (tng) (tng) <servlet-name>ControllerServlet</servlet-name>
 (tng) (tng) (tng) <url-pattern>/admin/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
 (tng) (tng) (tng) <servlet-name>ControllerServlet</servlet-name>
 (tng) (tng) (tng) <url-pattern>*.do</url-pattern>
</servlet-mapping>

qo(h)?/p>

服务器会(x)按照web.xml中过滤器定义的先后@序组装成一条链Q然后一ơ执行其中的doFilter()Ҏ(gu)。执行的序如上图所C,执行W一个过滤器的chain.doFilter()之前的代码,W二个过滤器的chain.doFilter()之前的代码,h的资源,W二个过滤器的chain.doFilter()之后的代码,W一个过滤器的chain.doFilter()之后的代码,最后返回响应?br />qo(h)铄好处是,执行q程中Q何时候都可以打断Q只要不执行chain.doFilter()׃?x)再执行后面的过滤器和请求的内容。而在实际使用Ӟp特别注意qo(h)铄执行序问题Q像EncodingFilter׃定要攑֜所有Filter之前Q这h能确保在使用h中的数据前设|正的~码?/p>

filter的详l配|?/p>

在servlet-2.3中,Filter?x)过滤一切请求,包括服务器内部用forward转发h?lt;%@ include file="/index.jsp"%>的情c(din)?br />C(jin)servlet-2.4中Filter默认下只拦截外部提交的请求,forward和includeq些内部转发都不?x)被qo(h)Q但是有时候我们需要forward的时候也用到FilterQ这样就需要如下配|?br /><filter>
 (tng) (tng) (tng) <filter-name>TestFilter</filtername>
 (tng) (tng) (tng) <filter-class>anni.TestFilter</filter-class>
</filter>
<filter-mapping>
 (tng) (tng) (tng) <filter-name>TestFilter</filtername>
 (tng) (tng) (tng) <url-pattern>/*</url-pattern>
 (tng) (tng) (tng) <dispatcher>REQUEST</dispatcher>
 (tng) (tng) (tng) <dispatcher>FORWARD</dispatcher>
 (tng) (tng) (tng) <dispatcher>INCLUDE</dispatcher>
 (tng) (tng) (tng) <dispatcher>EXCEPTION</dispatcher>
</filter-mapping>
 (tng) (tng) (tng) (tng) (tng) (tng) (tng)
q样TestFilter׃(x)qo(h)所有状态下的请求。如果我们没有进行设|,默认使用的就是REQUEST。而EXCEPTION是在isErrorPage="true"的情况下出现的,q个用处不多Q看一下即可?br />q里FORWARD是解决request.getDispatcher("index.jsp").forward(request, response);无法触发Filter的关键,配置上这个以后再q行forward的时候就可以触发qo(h)器了(jin)?/p>

Filterq有一个有的用法Q在filter-mapping中我们可以直接指定servlet-mappingQ让qo(h)器只处理一个定义在web.xml中的servlet?br /><filter-mapping>
 (tng) (tng) (tng) <filter-name>TestFilter</filter-name>
 (tng) (tng) (tng) <servlet-name>TestServlet</servlet-name>
</filter-mapping>
<servlet>
 (tng) (tng) (tng) <servlet-name>TestServlet</servlet-name>
 (tng) (tng) (tng) <servlet-class>anni.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
 (tng) (tng) (tng) <servlet-name>TestServlet</servlet-name>
 (tng) (tng) (tng) <url-pattern>/TestServlet</url-pattern>
</servlet-mapping>
 (tng) (tng) (tng) (tng) (tng) (tng)
直接指定servlet-nameQTestFilter便会(x)引用TestServlet配置的url-patternQ在某些filter与servletl定的情况下不失Z个好办法?/p>

]]>
web.xml?-使用监听器Servlethttp://www.tkk7.com/balajinima/articles/218462.html李云?/dc:creator>李云?/author>Tue, 29 Jul 2008 08:20:00 GMThttp://www.tkk7.com/balajinima/articles/218462.htmlhttp://www.tkk7.com/balajinima/comments/218462.htmlhttp://www.tkk7.com/balajinima/articles/218462.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/218462.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/218462.html监听器概qW?tng)?
 (tng) (tng)
1.Listener是Servlet的监听器 (tng) (tng) (tng) (tng)
2.可以监听客户端的h、服务端的操作等。?tng) (tng)?
3.通过监听器,可以自动Ȁ发一些操作,如监听在U用h?当增加一个HttpSessionӞl在Uh数加1。?tng) (tng)?
4.~写监听器需要实现相应的接口 (tng) (tng) (tng)
5.~写完成后在web.xml文g中配|一?可以v作用?jin) (tng) (tng)?
6.可以在不修改现有pȝ基础?增加web应用E序生命周期事g的跟t?tng) (tng)?
 (tng) (tng)
 (tng) (tng)
常用的监听接口?tng) (tng)?
 (tng) (tng)
1.ServletContextAttributeListener (tng) (tng) (tng)
监听对ServletContext属性的操作Q比如增?删除/修改 (tng) (tng) (tng)
2.ServletContextListener (tng) (tng) (tng)
监听ServletContext,当创建ServletContextӞȀ发contextInitialized(ServletContextEvent sce)Ҏ(gu)Q当销毁ServletContextӞȀ发contextDestroyed(ServletContextEvent sce)Ҏ(gu)。?tng) (tng)?
3.HttpSessionListener (tng) (tng) (tng)
监听HttpSession的操作。当创徏一个SessionӞȀ发session Created(SessionEvent se)Ҏ(gu)Q当销毁一个SessionӞȀ发sessionDestroyed (HttpSessionEvent se)Ҏ(gu)。?tng) (tng)?
4.HttpSessionAttributeListener (tng) (tng) (tng)
监听HttpSession中的属性的操作。当在Session增加一个属性时Q激发attributeAdded(HttpSessionBindingEvent se) Ҏ(gu)Q当在Session删除一个属性时Q激发attributeRemoved(HttpSessionBindingEvent se)Ҏ(gu)Q当在Session属性被重新讄ӞȀ发attributeReplaced(HttpSessionBindingEvent se) Ҏ(gu)。?tng) (tng)?
 (tng) (tng)
使用范例Q?tng) (tng)?
q听器理׃n数据库连接?tng) (tng)?
 (tng) (tng)
生命周期事g的一个实际应用由context监听器管理共享数据库q接。在web.xml中如下定义监听器Q?tng) (tng)?
<listener> (tng) (tng) (tng)
 (tng) (tng) (tng) <listener-class>XXX.MyConnectionManager</listener-class> (tng) (tng) (tng)
</listener> ?server创徏监听器的实例,接受事gq自动判断实现监听器接口的类型。要C的是׃监听器是配置在部|描q符web.xml中,所以不需要改变(sh)Q何代码就可以d新的监听器。?tng) (tng)?
 (tng) (tng)
public class MyConnectionManager implements ServletContextListener{ (tng) (tng) (tng) (tng) (tng)
public void contextInitialized(ServletContextEvent e) { (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) Connection con = // create connection (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) e.getServletContext().setAttribute("con", con); (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) } (tng) (tng) (tng) (tng) (tng)
 (tng) (tng) public void contextDestroyed(ServletContextEvent e) { (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) Connection con = (Connection) e.getServletContext().getAttribute("con"); (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) try { (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) con.close(); (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) } (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) catch (SQLException ignored) { } // close connection (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) } (tng) (tng) (tng) (tng)
} (tng) (tng) (tng) (tng) (tng)
监听器保证每新生成一个servlet context都会(x)有一个可用的数据库连?q且所有的q接对会(x)在context关闭的时候随之关闭。?tng) (tng) (tng) (tng)?br /> (tng) (tng)
在web.xml中加? (tng) (tng) (tng)
<listener><listener-class>servletlistener111111.SecondListener</listener-class> </listener>

==================================================

关于用户时的例子:(x)

public class OnlineUserListener implements HttpSessionListener {
 (tng) (tng) (tng) public void sessionCreated(HttpSessionEvent event) {
 (tng) (tng) (tng) }
 (tng) (tng) (tng) public void sessionDestroyed(HttpSessionEvent event) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) HttpSession session = event.getSession();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) ServletContext application = session.getServletContext();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) // 取得d的用户名
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) String username = (String) session.getAttribute("username");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) // 从在U列表中删除用户?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) List onlineUserList = (List) application.getAttribute("onlineUserList");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) onlineUserList.remove(username);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println(username + "时退出?);
 (tng) (tng) (tng) }
}

以下两种情况下就?x)发生sessionDestoryedQ会(x)话销毁)(j)事gQ?/p>

1.执行session.invalidate()Ҏ(gu)时。例如:(x)request.getSession().invalidate();

2.如果用户长时间没有访问服务器Q超q了(jin)?x)话最大超时时_(d)服务器就?x)自动销毁超时的session。会(x)话超时时间可以在web.xml中进行设|?/p>

========================================

使用HttpSessionBindingListener

HttpSessionBindingListener虽然叫做监听器,但用方法与HttpSessionListener完全不同。我们实际看一下它是如何用的?/p>

我们的OnlineUserBindingListener实现?jin)HttpSessionBindingListener接口Q接口中共定义了(jin)两个Ҏ(gu)QvalueBound()和valueUnbound()Q分别对应数据绑定,和取消绑定两个事件?/p>

所谓对sessionq行数据l定Q就是调用session.setAttribute()把HttpSessionBindingListener保存qsession中。我们在LoginServlet.java中进行这一步?/p>

// 把用户名攑օ在线列表
session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));
 (tng) (tng) (tng) (tng) (tng) (tng) (tng)
q就是HttpSessionBindingListener和HttpSessionListener之间的最大区别:(x)HttpSessionListener只需要设|到web.xml中就可以监听整个应用中的所有session。HttpSessionBindingListener必须实例化后攑օ某一个session中,才可以进行监听?/p>

从监听范围上比较QHttpSessionListener讄一ơ就可以监听所有sessionQHttpSessionBindingListener通常都是一对一的?/p>

正是q种区别成就?jin)HttpSessionBindingListener的优势,我们可以让每个listener对应一个usernameQ这样就不需要每ơ再去session中读取usernameQ进一步可以将所有操作在U列表的代码都移入listenerQ更Ҏ(gu)l护?/p>

valueBound()Ҏ(gu)的代码如下:(x)

public void valueBound(HttpSessionBindingEvent event) {
 (tng) (tng) (tng) HttpSession session = event.getSession();
 (tng) (tng) (tng) ServletContext application = session.getServletContext();

 (tng) (tng) (tng) // 把用户名攑օ在线列表
 (tng) (tng) (tng) List onlineUserList = (List) application.getAttribute("onlineUserList");
 (tng) (tng) (tng) // W一ơ用前Q需要初始化
 (tng) (tng) (tng) if (onlineUserList == null) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) onlineUserList = new ArrayList();
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) application.setAttribute("onlineUserList", onlineUserList);
 (tng) (tng) (tng) }
 (tng) (tng) (tng) onlineUserList.add(this.username);
}
 (tng) (tng) (tng) (tng) (tng) (tng) (tng)
username已经通过构造方法传递给listenerQ在数据l定Ӟ可以直接把它攑օ用户列表?/p>

与之对应的valueUnbound()Ҏ(gu)Q代码如下:(x)

public void valueUnbound(HttpSessionBindingEvent event) {
 (tng) (tng) (tng) HttpSession session = event.getSession();
 (tng) (tng) (tng) ServletContext application = session.getServletContext();

 (tng) (tng) (tng) // 从在U列表中删除用户?br /> (tng) (tng) (tng) List onlineUserList = (List) application.getAttribute("onlineUserList");
 (tng) (tng) (tng) onlineUserList.remove(this.username);

 (tng) (tng) (tng) System.out.println(this.username + "退出?);
}
 (tng) (tng) (tng) (tng) (tng) (tng) (tng)
q里可以直接使用listener的username操作在线列表Q不必再L?j)session中是否存在username?/p>

valueUnbound的触发条件是以下三种情况Q?/p>

1.执行session.invalidate()时?/p>

2.session时Q自动销毁时?/p>

3.执行session.setAttribute("onlineUserListener", "其他对象");或session.removeAttribute("onlineUserListener");listener从session中删除时?/p>

因此Q只要不listener从session中删除,可以监听到session的销毁?/p>

]]>
jsp获得在线用户http://www.tkk7.com/balajinima/articles/218152.html李云?/dc:creator>李云?/author>Mon, 28 Jul 2008 10:51:00 GMThttp://www.tkk7.com/balajinima/articles/218152.htmlhttp://www.tkk7.com/balajinima/comments/218152.htmlhttp://www.tkk7.com/balajinima/articles/218152.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/218152.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/218152.html (tng)
 (tng)
用HttpSessionListener ?

package demo.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class SessionCounter implements HttpSessionListener {
 (tng) (tng) (tng) (tng) public void sessionCreated(HttpSessionEvent event) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ServletContext ctx = event.getSession( ).getServletContext( );
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Integer numSessions = (Integer) ctx.getAttribute("numSessions");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (numSessions == null) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) numSessions = new Integer(1);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) else {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int count = numSessions.intValue( );
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) numSessions = new Integer(count + 1);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ctx.setAttribute("numSessions", numSessions);
 (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) public void sessionDestroyed(HttpSessionEvent event) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ServletContext ctx = event.getSession( ).getServletContext( );
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Integer numSessions = (Integer) ctx.getAttribute("numSessions");
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (numSessions == null) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) numSessions = new Integer(0);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) else {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int count = numSessions.intValue( );
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) numSessions = new Integer(count - 1);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ctx.setAttribute("numSessions", numSessions);
 (tng) (tng) (tng) (tng) }
}

在这个解x(chng)案中QQ何一个Session被创建或者销毁时Q都?x)通知SessionCounter q个c,当然通知的原因是必须在web.xml文g中做相关的配|工作。如下面的配|代码:(x)

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE web-app PUBLIC
 (tng) (tng) (tng) (tng) "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 (tng) (tng) (tng) (tng) "http://java.sun.com/dtd/web-app_2_3.dtd">
 (tng) (tng) (tng) (tng)
<web-app>
 (tng) (tng) <display-name>Struts Examples</display-name>
 (tng) (tng)
 (tng) (tng) <listener>
 (tng) (tng) (tng) (tng) (tng) (tng) <listener-class>demo.listener.SessionCounter
 (tng) (tng) (tng) (tng) (tng) (tng) </listener-class>
 (tng) (tng) </listener>


]]>
execute、executeQuery和executeUpdate之间的区??http://www.tkk7.com/balajinima/articles/215428.html李云?/dc:creator>李云?/author>Thu, 17 Jul 2008 03:31:00 GMThttp://www.tkk7.com/balajinima/articles/215428.htmlhttp://www.tkk7.com/balajinima/comments/215428.htmlhttp://www.tkk7.com/balajinima/articles/215428.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/215428.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/215428.html  
  JDBCTM中Statement接口提供的execute、executeQuery和executeUpdate之间的区?
  
  
   Statement 接口提供?jin)三U执?SQL 语句的方法:(x)executeQuery、executeUpdate ?execute。用哪一个方法由 SQL 语句所产生的内容决定?
  
   Ҏ(gu)executeQuery
   用于产生单个l果集的语句Q例?SELECT 语句?被用最多的执行 SQL 语句的方法是 executeQuery。这个方法被用来执行 SELECT 语句Q它几乎是用最多的 SQL 语句?
  
   Ҏ(gu)executeUpdate
   用于执行 INSERT、UPDATE ?DELETE 语句以及(qing) SQL DDLQ数据定义语aQ语句,例如 CREATE TABLE ?DROP TABLE。INSERT、UPDATE ?DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整敎ͼ指示受媄(jing)响的行数Q即更新计数Q。对?CREATE TABLE ?DROP TABLE {不操作行的语句QexecuteUpdate 的返回值Mؓ(f)零?
  
   使用executeUpdateҎ(gu)是因为在 createTableCoffees 中的 SQL 语句?DDL Q数据定义语aQ语句。创Q改变表Q删除表都是 DDL 语句的例子,要用 executeUpdate Ҏ(gu)来执行。你也可以从它的名字里看出,Ҏ(gu) executeUpdate 也被用于执行更新?SQL 语句。实际上Q相对于创徏表来_(d)executeUpdate 用于更新表的旉更多Q因只需要创Zơ,但经常被更新?
  
  
   Ҏ(gu)executeQ?
   用于执行q回多个l果集、多个更新计数或二者组合的语句。因为多数程序员?sh)?x)需要该高功能
  
   executeҎ(gu)应该仅在语句能返回多个ResultSet对象、多个更新计数或ResultSet对象与更新计数的l合时用。当执行某个已存储过E?或动态执行未?SQL 字符Ԍ卛_用程序程序员在编译时未知Q时Q有可能出现多个l果的情况,管q种情况很少见?
   因ؓ(f)Ҏ(gu) execute 处理非常规情况,所以获取其l果需要一些特D处理ƈ不为怪。例如,假定已知某个q程q回两个l果集,则在使用Ҏ(gu) execute 执行该过E后Q必调用方?getResultSet 获得W一个结果集Q然后调用适当?getXXX Ҏ(gu)获取其中的倹{要获得W二个结果集Q需要先调用 getMoreResults Ҏ(gu)Q然后再调用 getResultSet Ҏ(gu)。如果已知某个过E返回两个更新计敎ͼ则首先调用方?getUpdateCountQ然后调?getMoreResultsQƈ再次调用 getUpdateCount?
   对于不知道返回内容,则情冉|为复杂。如果结果是 ResultSet 对象Q则Ҏ(gu) execute q回 trueQ如果结果是 Java intQ则q回 false。如果返?intQ则意味着l果是更新计数或执行的语句是 DDL 命o(h)。在调用Ҏ(gu) execute 之后要做的第一件事情是调用 getResultSet ?getUpdateCount。调用方?getResultSet 可以获得两个或多?ResultSet 对象中第一个对象;或调用方?getUpdateCount 可以获得两个或多个更新计CW一个更新计数的内容?
   ?SQL 语句的结果不是结果集Ӟ则方?getResultSet 返?null。这可能意味着l果是一个更新计数或没有其它l果。在q种情况下,判断 null 真正含义的唯一Ҏ(gu)是调用方?getUpdateCountQ它?yu)返回一个整数。这个整Cؓ(f)调用语句所影响的行敎ͼ如果?-1 则表C结果是l果集或没有l果。如果方?getResultSet 已返?nullQ表C结果不?ResultSet 对象Q,则返回?-1 表示没有其它l果。也是_(d)当下列条件ؓ(f)真时表示没有l果Q或没有其它l果Q:(x)
  
  ((stmt.getResultSet() == null) && (stmt.getUpdateCount() == -1))
  
   如果已经调用Ҏ(gu) getResultSet q处理了(jin)它返回的 ResultSet 对象Q则有必要调用方?getMoreResults 以确定是否有其它l果集或更新计数。如?getMoreResults q回 trueQ则需要再ơ调?getResultSet 来检索下一个结果集。如上所qͼ如果 getResultSet q回 nullQ则需要调?getUpdateCount 来检?null 是表C结果ؓ(f)更新计数q是表示没有其它l果?
  
   ?getMoreResults q回 false Ӟ它表C SQL 语句q回一个更新计数或没有其它l果。因此需要调用方?getUpdateCount 来检查它是哪一U情c(din)在q种情况下,当下列条件ؓ(f)真时表示没有其它l果Q?
  
  ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
  
   下面的代码演CZ(jin)一U方法用来确认已讉K调用Ҏ(gu) execute 所产生的全部结果集和更新计敎ͼ(x)
  
  
  stmt.execute(queryStringWithUnknownResults);
  while (true) {
  int rowCount = stmt.getUpdateCount();
  if (rowCount > 0) { // 它是更新计数
  System.out.println("Rows changed = " + count);
  stmt.getMoreResults();
  continue;
  }
  if (rowCount == 0) { // DDL 命o(h)?0 个更?
  System.out.println(" No rows changed or statement was DDL
  command");
  stmt.getMoreResults();
  continue;
  }
  
  // 执行到这里,证明有一个结果集
  // 或没有其它结?
  
  ResultSet rs = stmt.getResultSet;
  if (rs != null) {
  . . . // 使用元数据获得关于结果集列的信息
  while (rs.next()) {
  . . . // 处理l果
  stmt.getMoreResults();
  continue;
  }
  break; // 没有其它l果
  

]]>
通过Map取提交的表单域?/title><link>http://www.tkk7.com/balajinima/articles/181106.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Thu, 21 Feb 2008 09:27:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/181106.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/181106.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/181106.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/181106.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/181106.html</trackback:ping><description><![CDATA[ <p>import java.util.Enumeration;<br />import java.util.HashMap;<br />import java.util.Map;</p> <p>import javax.servlet.http.HttpServletRequest;</p> <p>import com.mdcl.mocha.fe.developer.template.util.TemplateUtil;</p> <p>public class ParamUtil {</p> <p> (tng)/**<br /> (tng) * 把request取到的参数放C个Map?br /> (tng) * @param request<br /> (tng) * @return<br /> (tng) */<br /> (tng)public static Map parseRequest(HttpServletRequest request){<br /> (tng) (tng)Map map = new HashMap();<br /> (tng) (tng)String key = null;<br /> (tng) (tng)String value = null;<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) for(Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements(); map.put(key, value))<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) {<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) key = (String)enumeration.nextElement();<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) String as[] = request.getParameterValues(key);<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) value = as[0];<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) for(int i = 1; i < as.length; i++)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)value = value + "," +as[i];</p> <p> (tng) (tng) (tng) (tng) (tng) (tng) (tng) }<br /> (tng) (tng)return map;<br /> (tng)}<br />}<br /></p> <img src ="http://www.tkk7.com/balajinima/aggbug/181106.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2008-02-21 17:27 <a href="http://www.tkk7.com/balajinima/articles/181106.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsp查看session信息http://www.tkk7.com/balajinima/articles/165409.html李云?/dc:creator>李云?/author>Wed, 05 Dec 2007 02:29:00 GMThttp://www.tkk7.com/balajinima/articles/165409.htmlhttp://www.tkk7.com/balajinima/comments/165409.htmlhttp://www.tkk7.com/balajinima/articles/165409.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/165409.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/165409.html<%@ page language="java" contentType="text/html; charset=GBK"
 (tng)import="java.util.*" pageEncoding="GBK"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>Insert title here</title>
</head>
<body>
<%
out.print("<br>"+"session is new:"+session.isNew());

Date created = new Date(session.getCreationTime());
//得到session对象创徏的时?br />Date accessed = new Date(session.getLastAccessedTime());
//得到最后访问该session对象的时?br />out.println("<br>"+"ID " + session.getId()+" ");
//得到该session的idQƈ打印
out.println("<br>"+"Created: " + created+" ");
//打印session创徏旉
out.println("<br>"+"Last Accessed: " + accessed+" ");
//打印最后访问时?/p>

session.setAttribute("Name","Tom");
//在session中添加变量Name=Tom
session.setAttribute("UID","12345678");
//在session中添加变量UID=12345678

Enumeration e = session.getAttributeNames();
//得到session中变量名的枚丑֯?br />while (e.hasMoreElements()) { //遍历每一个变?br />String name = (String)e.nextElement(); //首先得到名字
String value = session.getAttribute(name).toString();
//由名字从session中得到?br />out.println("<br>"+name + " = " + value+" "); //打印
}

%>
</body>
</html>



]]>
如何把两个rsl果集中的内容合q到一个结果集?/title><link>http://www.tkk7.com/balajinima/articles/157690.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Fri, 02 Nov 2007 02:55:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/157690.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/157690.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/157690.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/157690.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/157690.html</trackback:ping><description><![CDATA[ <div id="r3tt9tf" class="cnt">假设你的二个数据集分别是Q?tng) (tng)?br /> (tng) (tng) rs1 (tng) (tng) (tng) 和?tng) (tng)?rs2 (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) List (tng) (tng) (tng) list (tng) (tng) (tng) = (tng) (tng) (tng) new (tng) (tng) (tng) ArrayList(); (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) list.add(rs1); (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) list.add(rs2); (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try (tng) (tng) (tng) { (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) for (tng) (tng) (tng) (int (tng) (tng) (tng) i (tng) (tng) (tng) = (tng) (tng) (tng) 0; (tng) (tng) (tng) i (tng) (tng) (tng) < (tng) (tng) (tng) list.size(); (tng) (tng) (tng) i++) (tng) (tng) (tng) { (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) while (tng) (tng) (tng) (((ResultSet) (tng) (tng) (tng) list.get(i)).next()) (tng) (tng) (tng) { (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //在这里取数据 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } (tng) (tng) (tng) catch (tng) (tng) (tng) (SQLException (tng) (tng) (tng) e) (tng) (tng) (tng) { (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) e.printStackTrace(); (tng) (tng) (tng) (tng) (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } (tng) (tng) (tng)<br /> (tng) (tng) (tng) (tng)<br /> (tng) (tng) 不管你有多少个数据集Q都攑ֈ那个list里就可以?jin)?/div> <img src ="http://www.tkk7.com/balajinima/aggbug/157690.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2007-11-02 10:55 <a href="http://www.tkk7.com/balajinima/articles/157690.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP上传囄q生成羃略图http://www.tkk7.com/balajinima/articles/157685.html李云?/dc:creator>李云?/author>Fri, 02 Nov 2007 02:48:00 GMThttp://www.tkk7.com/balajinima/articles/157685.htmlhttp://www.tkk7.com/balajinima/comments/157685.htmlhttp://www.tkk7.com/balajinima/articles/157685.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/157685.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/157685.html下蝲解压后,jar包复制到 \WEB-INF\lib 目录后重启服务器Qjspsmart卛_正常使用?br />
1、uploadimage.jsp

<%@ page contentType="text/html;charset=gb2312" language="java" import="java.io.*,java.awt.Image,java.awt.image.*,com.sun.image.codec.jpeg.*,
java.sql.*,com.jspsmart.upload.*,java.util.*,cn.oof.database.*,cn.oof.house.*"%>
<%
SmartUpload mySmartUpload =new SmartUpload();
long file_size_max=4000000;
String fileName2="",ext="",testvar="";
String url="uploadfile/images/"; (tng) (tng) (tng) (tng) (tng) (tng) //应保证在根目录中有此目录的存?br />//初始?br />mySmartUpload.initialize(pageContext);
//只允怸载此cL?br />try {
mySmartUpload.setAllowedFilesList("jpg,gif");
//上蝲文g
mySmartUpload.upload();
} catch (Exception e){
%>
 (tng) (tng) <SCRIPT language=javascript>
 (tng) (tng) alert("只允怸?jpg?gifcd囄文g");
 (tng) (tng) window.location=''upfile.jsp'';
 (tng) (tng) </script>
<%
}
try{

 (tng) (tng) (tng) (tng) com.jspsmart.upload.File myFile = mySmartUpload.getFiles().getFile(0);
 (tng) (tng) (tng) (tng) if (myFile.isMissing()){%>
 (tng) (tng) (tng) <SCRIPT language=javascript>
 (tng) (tng) (tng) alert("请先选择要上传的文g");
 (tng) (tng) (tng) window.location=''upfile.jsp'';
 (tng) (tng) (tng) </script>
 (tng) (tng) (tng) (tng) <%}
 (tng) (tng) (tng) (tng) else{
 (tng) (tng) (tng) (tng) (tng) (tng) //String myFileName=myFile.getFileName(); //取得上蝲的文件的文g?br /> (tng) (tng) (tng) ext= myFile.getFileExt(); (tng) (tng) (tng) (tng) (tng) (tng) //取得后缀?br /> (tng) (tng) (tng) int file_size=myFile.getSize(); (tng) (tng) (tng) (tng) (tng) //取得文g的大?tng)?br /> (tng) (tng) (tng) String saveurl="";
 (tng) (tng) (tng) if(file_size<file_size_max){
 (tng) (tng) (tng) (tng) //更改文g名,取得当前上传旉的毫U数?br /> (tng) (tng) (tng) (tng) Calendar calendar = Calendar.getInstance();
 (tng) (tng) (tng) (tng) String filename = String.valueOf(calendar.getTimeInMillis());
 (tng) (tng) (tng) (tng) saveurl=request.getRealPath("/")+url;
 (tng) (tng) (tng) (tng) saveurl+=filename+"."+ext; (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //保存路径
 (tng) (tng) (tng) (tng) myFile.saveAs(saveurl,mySmartUpload.SAVE_PHYSICAL);
 (tng) (tng) (tng) (tng) //out.print(filename);
//-----------------------上传完成Q开始生成羃略图------------------------- (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) java.io.File file = new java.io.File(saveurl); (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //d刚才上传的文?br /> (tng) (tng) (tng) (tng) String newurl=request.getRealPath("/")+url+filename+"_min."+ext; (tng) (tng) //新的~略图保存地址
 (tng) (tng) (tng) (tng) Image src = javax.imageio.ImageIO.read(file); (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //构造I(yng)mage对象
 (tng) (tng) (tng) (tng) float tagsize=200;
 (tng) (tng) (tng) (tng) int old_w=src.getWidth(null); (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //得到源图?br /> (tng) (tng) (tng) (tng) int old_h=src.getHeight(null); (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) int new_w=0;
 (tng) (tng) (tng) (tng) int new_h=0; (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //得到源图?br /> (tng) (tng) (tng) (tng) int tempsize;
 (tng) (tng) (tng) (tng) float tempdouble;
 (tng) (tng) (tng) (tng) if(old_w>old_h){
 (tng) (tng) (tng) (tng) (tng) tempdouble=old_w/tagsize;
 (tng) (tng) (tng) (tng) }else{
 (tng) (tng) (tng) (tng) (tng) tempdouble=old_h/tagsize;
 (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) new_w=Math.round(old_w/tempdouble);
 (tng) (tng) (tng) (tng) new_h=Math.round(old_h/tempdouble);//计算新图长宽
 (tng) (tng) (tng) (tng) BufferedImage tag = new BufferedImage(new_w,new_h,BufferedImage.TYPE_INT_RGB);
 (tng) (tng) (tng) (tng) tag.getGraphics().drawImage(src,0,0,new_w,new_h,null); (tng) (tng) (tng) (tng) (tng) (tng) (tng) //l制~小后的?br /> (tng) (tng) (tng) (tng) FileOutputStream newimage=new FileOutputStream(newurl); (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //输出到文件流
 (tng) (tng) (tng) (tng) JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newimage); (tng) (tng) (tng) (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng) encoder.encode(tag); (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) //qJPEG~码
 (tng) (tng) (tng) (tng) (tng) newimage.close(); (tng) (tng) (tng) (tng)

 (tng) (tng) (tng) }
 (tng) (tng) (tng) else{
 (tng) (tng) (tng) (tng) out.print("<SCRIPT language=''javascript''>");
 (tng) (tng) (tng) (tng) out.print("alert(''上传文g大小不能过"+(file_size_max/1000)+"K'');");
 (tng) (tng) (tng) (tng) out.print("window.location=''upfile.jsp;''");
 (tng) (tng) (tng) (tng) out.print("</SCRIPT>");
 (tng) (tng) (tng) }
 (tng) (tng) }
}catch (Exception e){

e.toString();

}
%>

2 upload.htm
<html>
<head>
<title>请选择上传的图?lt;/title>
</head>
<body>
<table border="0" align="center" cellpadding="0" cellspacing="0">
 (tng) (tng) <tr>
 (tng) (tng) (tng) (tng) <td height="45" align="center" valign="middle"><form action="uploadimage.jsp" method="post" enctype="multipart/form-data" name="form1">
请选择上传的图?br /> (tng) (tng) (tng) (tng) <input type="file" name="file">
<input type="submit" name="Submit" value="上传">
 (tng) (tng) (tng) (tng) </form></td>
 (tng) (tng) </tr>
</table>
</body>
</html>

]]>
ZJSP实现数据库中囄的存储与昄http://www.tkk7.com/balajinima/articles/157683.html李云?/dc:creator>李云?/author>Fri, 02 Nov 2007 02:47:00 GMThttp://www.tkk7.com/balajinima/articles/157683.htmlhttp://www.tkk7.com/balajinima/comments/157683.htmlhttp://www.tkk7.com/balajinima/articles/157683.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/157683.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/157683.html
数据库应用程序,特别是基于WEB的数据库应用E序Q常?x)涉及(qing)到囄信息的存储和昄。通常我们使用的方法是所要显C的囄存在特定的目录下Q在数据库中保存相应的图片的名称Q在JSP中徏立相应的数据源,利用数据库访问技术处理图片信息。但是,如果我们惛_态的昄囄Q上q方法就不能满需要了(jin)。我们必L囄存入数据库,然后通过~程动态地昄我们需要的囄。实际操作中Q可以利用JSP的编E模式来实现囄的数据库存储和显C?

2、徏立后台数据库

假定处理的是囄新闻Q那么我们可以徏立相应的数据库及(qing)数据表对象。我们要存取的数据表l构的SQL脚本如下所C:(x)


if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[picturenews]') andOBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[picturenews]
GO
CREATE TABLE [dbo].[picturenews] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[image] [image] NULL ,
[content] [varchar] (500) COLLATE Chinese_PRC_CI_AS NULL ,
[detail] [varchar] (5000) COLLATE Chinese_PRC_CI_AS NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO


表picturenews中,字段id作ؓ(f)标识Q每存储一行数据,自动增加1。字Dimage

用于存储囄信息Q其数据cd为“image”?

3、向数据库存储二q制囄

启动Dreamweaver MX后,新徏一个JSP文g。其代码如下所C?


<%@ page contentType="text/html;charset=gb2312"%>
<HTML>
<HEAD>
<TITLE>存储囄</TITLE>
</HEAD>
<body>
<!-- 下面的窗体将以PostҎ(gu)Q将数据传递给testimage.jsp文g -->
<FORM METHOD=POST ACTION="testimage.jsp">
???题:(x)<INPUT TYPE="text" NAME="content"><BR>
???片:(x)<INPUT TYPE="file" NAME="image"><BR>
新闻内容Q?br /><TEXTAREA name="txtmail" rows="15" cols="90"
style="BORDER-BOTTOM: #000000 1px solid; BORDER-LEFT: #000000 1px solid;
BORDER-RIGHT: #000000 1px solid; BORDER-TOP: #000000 1px solid; FONT-SIZE: 9pt;
HEIGHT: 200px; WIDTH: 100%" wrap="physical" ></TEXTAREA><br>
<INPUT TYPE="submit"></form>
</body>
</HTML>


此文g保存?sh)InputImage.jsp文gQ其中testimage.jsp文g是用来将囄数据存入数据库的Q具体代码如下所C:(x)


<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*" %>
<%@ page import="java.util.*"%>
<%@ page import="java.text.*"%>
<%@ page import="java.io.*"%>
<html>
<body>
<%
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//加蝲驱动E序c?br />Connection con=DriverManager.getConnection("jdbc:odbc:denglu","sa","sa");
//建立数据库联机,其中denglu为数据库名,sa接数据库的帐号及(qing)密码?br />Statement stmt=con.createStatement();
//建立Statement对象
String content=request.getParameter("content");
content=new String(content.getBytes("8859_1"),"gb2312");
String filename=request.getParameter("image");
filename=new String(filename.getBytes("8859_1"),"gb2312");
String detail=request.getParameter("txtmail");
detail=new String(detail.getBytes("8859_1"),"gb2312");
//获得所要显C图片的标题、存储\径、内容,q进行中文编?br />FileInputStream str=new FileInputStream(filename);
String sql="insert into picturenews(content,image,detail) values(?,?,?)";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setString(1,content);
pstmt.setBinaryStream(2,str,str.available());
pstmt.setString(3,detail);
pstmt.execute();
//数据存入数据库
out.println("Success,You Have Insert an Image Successfully");
%>



4、网中动态显C图?

接下来我们要~程从数据库中取出图片,其代码如下所C?


<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*" %>
<%@ page import="java.util.*"%>
<%@ page import="java.text.*"%>
<%@ page import="java.io.*"%>
<html>
<body>
<%
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//加蝲驱动E序c?br />Connection con=DriverManager.getConnection("jdbc:odbc:denglu","sa","sa");
Statement stmt=con.createStatement();
ResultSet rs=null;
//建立ResultSetQ结果集Q对?br />int id= Integer.parseInt(request.getParameter("id"));
//获得所要显C图片的~号idQƈ转换为整?br />String sql = "select image from picturenews WHERE id="+id+"";
//要执行查询的SQL语句
rs=stmt.executeQuery(sql);
while(rs.next()) {
ServletOutputStream sout = response.getOutputStream();
//囄输出的输出流
InputStream in = rs.getBinaryStream(1);
byte b[] = new byte[0x7a120];
for(int i = in.read(b); i != -1;)
{
sout.write(b);
//缓冲区的输入输出到面
in.read(b);
}
sout.flush();
//输入完毕Q清除缓?br />sout.close();
}
%>
</body>
</html>


此文g保存?sh)testimageout.jsp文g。下一步要做的工作是使用HTML标记Q?


<IMG src="testimageout.jsp?id=<%=rs.getInt("id")%>" width=100 height=100>


取出所要显C的囄Q其中id是所要取出图片的~号。本例中我们输出?jin)第一个和最后一个图片信息,详细的程序代码如下所C?


<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*" %>
<html>
<head>
<title>动态显C数据库囄</title>
</head>
<body>
<%
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con=DriverManager.getConnection("jdbc:odbc:denglu","sa","sa");
Statement stmt=con.createStatement();
String sql=new String();
sql= "select * from picturenews";
ResultSet rs=stmt.executeQuery(sql);
rs.last();
//指针移x(chng)后一条记?br />%>
<table>
<tr><td><IMG height=99 src="testimageout.jsp?id=1" width=136></td>
//取出W一个图?br /><td><IMG height=99 src="testimageout.jsp?id=<%=rs.getInt("id")%>" width=136></td>
//取出最后一个图?br /></tr></table>
</body>
</html>

]]>
JSP中实现文件上?/title><link>http://www.tkk7.com/balajinima/articles/157682.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Fri, 02 Nov 2007 02:44:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/157682.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/157682.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/157682.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/157682.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/157682.html</trackback:ping><description><![CDATA[ <table width="620" align="center"> <tbody> <tr> <td class="a14"> <strong>一、前a</strong> </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">文g上蝲对于Mweb应用E序都是一个很有用处的功能。比如,在基于web的email中用文件上载在消息中加入附Ӟ在技术支持站点可以用文件上载接收从用户处发来的错误日志和缺h告文档;在web应用中用文件上载,通过友好的web界面在用户间׃n文g。本文将对如何在JSP~程中上载文件进行讨论,q给?gu)x(chng)法?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"> <strong>二、文件上载的方式</strong> </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">在TCP/IP中最早出现的文g上蝲机制是FTPQ它是将文g由客L(fng)发送到服务器的标准机制。它很可靠,能够考虑到跨q_的文本和二进制格式文件。但在JSP~程中不能用FTPҎ(gu)来上载文Ӟq是由JSP的运行机制所军_的。我们知道:(x)JSPQJavaServer PagesQ是由Sun MicroSystems公司倡导、许多公司参与,一起徏立的一U动态网|术标准。它在传l的|页HTML文g中加入JAVAE序片段和JSP标记构成了(jin)JSP|页。web服务器在遇到讉KJSP|页hӞ首先执行其中的程序片D,然后执行结果以HTML形式q回客户。这U运行机制就要求客户与服务器的联p需要用HTTP协议而不能是FTP协议?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">在HTTP协议中上载文件主要有两种机制Q?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">1QRFC1867方式QRFC1867在作为标准发布之前首先被Netscape的Navigator 2.0中采用。随后被Microsoft的IE3.0的附件和IE3.03的一部分使用。它是一U简单实用的Ҏ(gu)。只在表单字D中定义一个filecd的inputQ?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><input type="file"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">q且在表单本w中加入?jin)不同的~码Ҏ(gu)Q它不再使用典型的:(x)</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><form action="test.jsp" method="post"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">而是使用</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><form action="test.jsp" method="post" enctype="multipart/form-data"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">q种~码Ҏ(gu)在传送大量数据时比缺省的"application/x-url-encoded"表单~码Ҏ(gu)要效率高得多。因为URL~码只有很有限的字符集。当使用M出字符集的字符Ӟ必须?%nn"代替Q这里的nn表示相应的两个十q制敎ͼ(j)。这样即使是普通的I格字符也要?%20"代替。那么,通过URL~码方式上蝲的文件将?x)是原来?-3倍大。而用RFC1867~码方式则只是在传送数据的周围加上很简单的头部来标识文件内宏V?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">2Qput方式Q在HTTP1.1中引入了(jin)一个新的HTTP动词Qput。当web服务器收C个HTTP的puth和对象名字(如:(x)"/myweb/images/x.gif"Q时Q它?x)验证用P接收HTTP的内容Qƈ把它直接存入web服务器。由于这U方式可能会(x)对一个web站点造成破坏Q因而ƈ不常用。而且它也失去?jin)web服务器端的最大优势:(x)服务器的可编E性。在使用put方式Ӟ服务器自己处理客L(fng)hQ没有空间让JSP介入Q因此,此方式对于JSP应用开发都是毫无用处的?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"> <strong>三、JSP中实现文件上载的Ҏ(gu)</strong> </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">从以上分析中我们可以得出l论QRFC1867是在JSP~写的web应用E序中实现文件上载的最好方法。它是如何在实际应用的呢Q?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">q里介l一U简单而实用的Ҏ(gu)Q只需要几行代码就可以在JSPE序中实现文件上载。这是使用一个免费的JAVAlgJspSmartUploadQhttp://www.jspsmart.comQ实现文件上载?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">1Q?JspSmartUpload的配|要?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">安装JspSmartUploadlg需要如下的配置Q?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">a. web服务器(如IISQapache{)(j)</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">b. JDK1.1.2以上的JAVA~译?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">c. 支持JSP1.1?qing)JavaServelet API 2.2的引擎?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">其中的JSP引擎有许多品,如:(x)</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">Tomcat: http://java.sun.com/products/jsp/tomcat</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">Allaire Jrun: http://www.allaire.com/products/jrun</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">JSWDK: http://java.sun.com/produces/jsp/</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">IBM webSphere: http://www-4.ibm.com/software/webservers/</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">Resin: http://www.caucho.com</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">注意Q本文将主要讨论JspSmartUpload在Tomcat引擎中的安装?qing)用?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">2Q?JspSmartUpload的安?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">首先Q?把下载的压羃文gJspSmartUpload.zip解压~到/tomcat/webapps/ 目录下(/tomcat目录是你的tomcat引擎安装的根目录Q,q样׃(x)形成如下的目录结?tomcat/webapps/jspsmartupload/。所有必需的文仉在这个目录下?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">其次Q把如下内容_脓(chung)?tomcat/conf/server.xml文g中?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><Context path="/jspsmartupload" docBase="/tomcat/webapps/jspsmartupload"</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">defaultSessionTimeOut="30" isWARExpanded="true" isWARValidated="false" isInvokerEnabled="true" isWorkDirPersistent="false" /></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">最后,把如下的内容_脓(chung)?tomcat/conf/uniworkermap.properties文g中?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">/jspsmartupload/*.jsp=ajp12</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">/jspsmartupload/servlet/*=ajp12</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">x(chng)Qjspsmartupload在tomcat引擎中的安装完成了(jin)?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">3Q?上蝲文g的HTML表单</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">如前所qͼ在JSP中文件上载用的是RFC1867标准。在其中也规定了(jin)上蝲文g所使用的HTML表单的格式。此表单的格式被Netscape 3和Microsoft IE3.02以上的浏览器所支持。上载文件的表单发布具备如下的格式:(x)</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">a) 单所使用的方法必Lpost</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">b) 在action属性中的执行程序必能处理由客L(fng)q回的数?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">c) 表单必须使用MIMEcdQmultipart/form-data</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">d) 表单必须臛_包含一?lt;input type=”file?gt;元素。与RFC1867兼容的浏览器会(x)在客L(fng)界面上显CZ个文本框和一个“游览”按钮,以方便客L(fng)选择上蝲的文件?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">下面是用此cd表单的HTML文g例子?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">upload.htm</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><HTML></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><BODY BGCOLOR="white"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><H1>jspUpload : Sample </H1></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><HR></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><form METHOD="POST" ACTION="/jspsmartupload/upload.jsp" NAME="PW" ENCTYPE="multipart/form-data"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><table CELLSPACING="0" CELLPADDING="3" BORDER="1" WIDTH="474"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><!-- FILE --></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><td><small><font face="Verdana"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">Select a first file : </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></font></small></td></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><td><small><font face="Verdana"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><input TYPE="file" name="FILE1"></font></small></td></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><td><small><font face="Verdana">Select a second file : (tng) (tng) </font></small></td></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><td><small><font face="Verdana"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><input TYPE="file" name="FILE2"></font></small></td></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><!-- TEXT --></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><td width="150"><div align="left"><p><small><font face="Verdana">Text : (tng) (tng) </font></small></td></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><td width="324"><small><font face="Verdana"><input TYPE="TEXT" name="myText" value=""><br></font></small></td></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><!-- SUBMIT --></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><td colspan="2" width="474"><div align="center"><center><p><small><font face="Verdana"><input</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">TYPE="Submit"> </font></small></td></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></tr></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></table></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></form></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></BODY></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></HTML></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">4Q?使用JspSmartUpload处理表单</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">当客L(fng)submit表单以后Q服务器会(x)调用表单action中的JSPE序处理客户端的h。在此JSP中就要调用JspSmartUpload来完成文件上载的h?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">在JSPE序中,首先要在<%@ page import=my.class %>中声明引入JspSmartUploadcR然后用JavaBean来实例化一个JspSmartUploadcR如Q?lt;jsp:useBean id=”mybean?class=”my.class?gt;。在实例化后Q要使用JSP引擎隐含的对象pageContext对JspSmartUpload JavaBeanq行初化,q样把客户端的h传给?jin)JspSmartUploadlg。然后用组件的upload()Ҏ(gu)对客L(fng)hq行分析Q最后把q些数据通过save()Ҏ(gu)存入一个文件?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">下面是处理上一个HTML表单的JSP例程?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">upload.jsp</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><%@page language="java" import="com.jspsmart.upload.*"%></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><jsp:useBean id="myUpload" scope="page" class="com.jspsmart.upload.SmartUpload" /></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"> </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><HTML></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><BODY BGCOLOR="white"></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"> </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><H1>jspUpload : Sample</H1></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><HR></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"> </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"><%</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">// 初?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">myUpload.initialize(pageContext);</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">// 分析客户数据</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">myUpload.upload(); </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">//</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">// 处理上蝲文g</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">//</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.println("<BR><STRONG>关于文g的信?lt;/STRONG><BR>");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.println("上蝲文g的数?= " + myUpload.getFiles().getCount() + "<BR>");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">//out.println("文g大小 (bytes) = " + myUpload.getFiles().getSize() +"<BR>");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">for (int i=0;i<myUpload.getFiles().getCount();i++){</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.print(myUpload.getFiles().getFile(i).getFieldName());</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">if (!myUpload.getFiles().getFile(i).isMissing())</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.print(" = " + myUpload.getFiles().getFile(i).getFileName() + " (" + myUpload.getFiles().getFile(i).getSize() + ")");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">else</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.print(" = I?); </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.println("<BR>");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">}</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">//</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">// 处理客户h信息</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">//</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.println("<BR><BR><STRONG>昄客户表单数据</STRONG><BR>");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">// 昄h?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">java.util.Enumeration e = myUpload.getRequest().getParameterNames();</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">// 得到h的?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">while (e.hasMoreElements()) {</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">String key = (String)e.nextElement();</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">String[] values = myUpload.getRequest().getParameterValues(key); </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">// 昄h的?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">for(int i = 0; i < values.length; i++) {</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.print(key + " = ");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">out.print(values[i] + "<BR>");</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">} </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">}</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">%></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"></BODY></HTML></td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">5Q?q行例程</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">把上q的HTML表单例子?qing)处理表单的JSP例程存到/tomcat/webapps/uspsmartupload/目录下,然后q行/tomcat/bin/startup.bat启动服务器。在IE或Netscape的地址栏中输入Q?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">http://localhost:8080/jspsmartupload/jspupload.htm</td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">可以看到运行结果了(jin)?/td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14"> <strong>四、结?/strong> </td> </tr> </tbody> </table> <table width="620" align="center"> <tbody> <tr> <td class="a14">JspSmartUploadlg不仅可以把客L(fng)的数据存入到文g中,也可以把它存入到数据库中。而且Q它的安装及(qing)使用Ҏ(gu)单易学,是一个非常好的上传组Ӟ可以lJSP~制的web应用E序提供更强大的功能?/td> </tr> </tbody> </table> <img src ="http://www.tkk7.com/balajinima/aggbug/157682.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2007-11-02 10:44 <a href="http://www.tkk7.com/balajinima/articles/157682.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入理解和改qJSP/Servlet?x)话理机?/title><link>http://www.tkk7.com/balajinima/articles/157679.html</link><dc:creator>李云?/dc:creator><author>李云?/author><pubDate>Fri, 02 Nov 2007 02:41:00 GMT</pubDate><guid>http://www.tkk7.com/balajinima/articles/157679.html</guid><wfw:comment>http://www.tkk7.com/balajinima/comments/157679.html</wfw:comment><comments>http://www.tkk7.com/balajinima/articles/157679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/balajinima/comments/commentRss/157679.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/balajinima/services/trackbacks/157679.html</trackback:ping><description><![CDATA[ <div id="xfvjnvb" class="tit"> (tng)</div> <table style="TABLE-LAYOUT: fixed"> <tbody> <tr> <td> <div id="dz9v7zb" class="cnt">在Web服务器端~程中,?x)话状态管理是一个经常必考虑的重要问题。本文分析JSP/Servlet的会(x)话管理机制及(qing)其所面(f)的问题,然后提出?jin)一U改q的?x)话理?gu)?<br /><br />一、Servlet的会(x)话管理机?<br /><br />Ҏ(gu)设计QHTTP是一U无状态的协议。它意味着Web应用q不?jin)解有关同一用户以前h的信息。维持会(x)话状态信息的Ҏ(gu)之一是用Servlet或者JSP容器提供的会(x)话跟t功能。Servlet API规范定义?jin)一个简单的HttpSession接口Q通过它我们可以方便地实现?x)话跟踪?<br /><br />HttpSession接口提供?jin)存储和q回标准?x)话属性的Ҏ(gu)。标准会(x)话属性如?x)话标识W、应用数据等Q都以“名?值”对的Ş式保存。简而言之,HttpSession接口提供?jin)一U把对象保存到内存、在同一用户的后l请求中提取q些对象的标准办法。在?x)话中保存数据的?gu)是setAttribute(String s, Object o)Q从?x)话提取原来所保存对象的方法是getAttribute(String s)?<br /><br />在HTTP协议中,当用户不再活动时不存在显式的l止信号。由于这个原因,我们不知道用h否还要再ơ返回,如果不采取某U方法解册个问题,内存?sh)?x)U篏起大量的HttpSession对象?<br /><br />为此QServlet采用“超旉制”的办法来判断用h否还在访问:(x)如果某个用户在一定的旉之内没有发出后(h)hQ则该用L(fng)?x)话被作废,他的HttpSession对象被释放。会(x)话的默认时间隔由Servlet容器定义。这个值可以通过getMaxInactiveIntervalҎ(gu)获得Q通过setMaxInactiveIntervalҎ(gu)修改Q这些方法中的超时时间以U计。如果会(x)话的时旉D|成-1Q则?x)话怸时。Servlet可以通过getLastAccessedTimeҎ(gu)获得当前h之前的最后一ơ访问时间?<br /><br />要获得HttpSession对象Q我们可以调用HttpServletRequest对象的getSessionҎ(gu)。ؓ(f)?jin)正地l持?x)话状态,我们必须在发送Q何应{内容之前调用getSessionҎ(gu)?<br />用户?x)话既可以用手工?gu)作废Q也可以自动作废。作废会(x)话意味着从内存(sh)删除HttpSession对象以及(qing)它的数据。例如,如果一定时间之内(默认30分钟Q用户不再发送请求,Java Web Server自动C废他的会(x)话?<br /><br />Servlet/JSP?x)话跟踪机制有着一定的局限,比如Q?<br /><br />· ?x)话对象保存在内存?sh)中,占用?jin)可观的资源?<br /><br />· ?x)话跟踪依赖于Cookie。由于各U原因,特别是安全上的原因,一些用户关闭了(jin)Cookie?<br /><br />· ?x)话跟踪要用到服务器创徏的?x)话标识符。在多个Web服务器以?qing)多个JVM的环境中QW(xu)eb服务器不能识别其他服务器创徏的会(x)话标识符Q会(x)话跟t机制无法发挥作用?<br />要深入理解会(x)话跟t机Ӟ首先我们必须理解在Servlet/JSP容器中会(x)话如何运作?<br /><br /><br />二、会(x)话标识符 <br /><br />每当新用戯求一个用了(jin)HttpSession对象的JSP面QJSP容器除了(jin)发回应答面之外Q它q要向浏览器发送一个特D的数字。这个特D的数字UCؓ(f)“会(x)话标识符”,它是一个唯一的用h识符。此后,HttpSession对象驻留在内存?sh)中Q等待同一用户q回时再ơ调用它的方法?<br /><br />在客L(fng)Q浏览器保存?sh)(x)话标识W,q在每一个后l请求中把这个会(x)话标识符发送给服务器。会(x)话标识符告诉JSP容器当前h不是用户发出的第一个请求,服务器以前已lؓ(f)该用户创Z(jin)HttpSession对象。此ӞJSP容器不再为用户创建新的HttpSession对象Q而是Lh相同?x)话标识W的HttpSession对象Q然后徏立该HttpSession对象和当前请求的兌?<br /><br />?x)话标识W以Cookie的Ş式在服务器和览器之间传送。如果浏览器不支持Cookie又如何呢Q此ӞҎ(gu)务器的后l请求将不会(x)带有?x)话标识W。结果,JSP容器认ؓ(f)该请求来自一个新用户Q它?x)再创徏一个HttpSession对象Q而以前创建的HttpSession对象仍旧ȝ在内存(sh)Q但该用户以前的?x)话信息却丢׃?jin)?<br /><br />另外QServlet/JSP容器只认可它自己创徏的会(x)话标识符。如果同一Web应用在“Web农场”(Web farmQ的多台服务器上q行Q则必须存在q样一U机Ӟ(x)保证来自同一用户的请求L被定向到处理该用L(fng)一ơ请求的服务器?<br /><br />三、伪?x)话理机?<br /><br />如前所qͼZCookie的会(x)话管理技术面临着U种问题。下面我们要设计一U新的会(x)话管理机制来解决q些问题。这U会(x)话管理机制称为“伪?x)话”(Pseudo SessionQ机Ӟ它具有如下特点:(x) <br /><br />· 对象和数据不是保存在内存?sh),而是以文本文件Ş式保存。每一个文本文件与一个特定的用户兌Q文件的名字是?x)话的标识符。因此,文g名字必须是唯一的?<br />· 文本文g保存在一个专用的目录中,所有Web服务器都可以讉Kq个目录。因此,伪会(x)话可以用于Web农场?<br />· ?x)话标识W不作ؓ(f)Cookie发送,而是直接~码到URL里面。因此,采用伪会(x)话技术要求修Ҏ(gu)有的链接Q包括HTML表单的ACTION属性?<br />此外Q实C?x)话理机制时我们还要考虑C下几点:(x) <br />· 它应该与应用无关Q其他想要实现同样功能的开发者应该能够方便地重用它?<br />· 考虑到安全原因,应该有一Uؓ(f)?x)话标识W生成随机数字的办法?<br />· Z(jin)作废q期的会(x)话,应该讑֮一个超时倹{同一个用P如果他超q一定的旉之后再次q回Q他获得一个新的会(x)话标识符。此举能够防止未l授权的用户冒用其他人的?x)话?<br />· 应该有一U收集过期会(x)话ƈ删除相应文本文g的机制?<br />· 如果用户使用已经q期的会(x)话标识符再次讉K服务器,即ɘq个?x)话标识W的文本文gq没有删除,pȝ也不应该允许用户使用原来的会(x)话?<br />· 同时Q应该存在一U更C(x)话文本文件最后改动时间的机制Q得用户在?x)话q期旉之前q回时会(x)话L保持最C合法的状态数据?<br /><br /><br />四、实C?x)话理机?<br /><br />下面所介绍的工E称为PseudoSessionQ它是伪?x)话机制一个很单的实现。考虑到移植性,我们以JavaBean的Ş式实现它。PseudoSessionBean的完整代码可以从本文后面下蝲?<br /><br />PseudoSessionBean拥有如下域(F(tun)ieldQ:(x) <br />public String path;public long timeOut; <br />path是保存所有会(x)话文本文件的目录。如果Web服务器的数量在一个以上,q个目录必须允许所有服务器讉K。然而,Z(jin)防止用户直接讉Kq些文本文gQ这个\径应该不允许用户直接讉K。解册个问题的一U方法是使用Web|站根之外的目录?<br /><br />timeOut是用L(fng)最后一个请求到?x)话q期作废之间的时间。在PseudoSessionBean的代码清单中QtimeOut讄成了(jin)以毫U表C的20分钟Q这是一个比较合理的时旉倹{对于Q何用P如果他在q个时旉之后才(h)l发?gu)求,他将得到一个新的会(x)话标识符?<br />PseudoSessionBean?个方法:(x)getSessionIDQsetValueQgetValueQdeleteAllInvalidSessions?<br /><br />4.1 getSessionIDҎ(gu) <br />getSessionIDҎ(gu)的声明如下:(x) <br />public String getSessionID(HttpServletRequest request) <br />q个Ҏ(gu)应该在每一个JSP面的开头调用。它完成如下dQ?<br />· 如果用户是第一ơ访问,则ؓ(f)该用戯定一个新的会(x)话标识符?<br />· (g)查URL所带会(x)话标识符的合法性。如果会(x)话标识符已经q期Q则getSessionIDҎ(gu)q回一个新的会(x)话标识符?<br />下面我们来看看getSessionIDҎ(gu)的工作过E?<br />String sessionId = request.getParameter("sessionId"); <br />validSessionIdFound是一个标讎ͼ用于指示?x)话标识W是否合法。validSessionIdFound的初始值是false?<br />boolean validSessionIdFound = false; <br />longcd的now变量包含h出现时的服务器时间。该变量用于定用户?x)话的合法性?<br />long now = System.currentTimeMillis(); <br />如果扑ֈ?jin)?x)话标识符Q则getSessionIDҎ(gu)(g)查它的合法性。检查过E如下:(x) <br />· 一个合法的?x)话标识W必L对应的同名文本文件?<br />· 文g的最后修Ҏ(gu)间加上timeOut应该大于当前旉?<br />· 如果存在与会(x)话对应的文本文gQ但文g已经q期Q则原来的文件被删除?<br />· 把合法会(x)话标识符所对应文本文g的最后修Ҏ(gu)期改为now?<br />q些d主要借助File对象完成Q创建File对象的参数就是会(x)话文本文件的路径Q?<br />if (sessionId!=null) {File f = new File(path + sessionId);if (f.exists()) { if (f.lastModified() + timeOut > now) { // ?x)话合?/ 使用setLastModifiedӞ如果文g已经被其他程序锁定,// E序不会(x)产生M异常Q但文g数据不会(x)改变f.setLastModified(now);validSessionIdFound = true; } else { // ?x)话已经q期 // 删除文gf.delete(); }} // end if (f.exists) } // end if (sessionId!=null) <br />如果不存在合法的?x)话标识W,则getSessionIDҎ(gu)生成一个会(x)话标识符以及(qing)相应的文本文Ӟ(x) <br />if (!validSessionIdFound) { sessionId = Long.toString(now); // 创徏文g File f = new File(path + sessionId); try {f.createNewFile(); } catch (IOException ioe) {}} // end of if !validSessionIdFound <br />E序保证文g名字随机性的Ҏ(gu)非常单:(x)把当前的pȝ旉直接转换成会(x)话标识符。对于那些涉?qing)敏感数据的应用Q我们应该考虑q用更安全的随机数生成器来生成会(x)话标识符?<br />lg所qͼgetSessionIDq不Lq回新的合法?x)话标识W:(x)它返回的标识W可能与传递给它的标识W相同,也可能是新创建的?x)话标识W?<br />Z(jin)保证JSP面拥有合法的会(x)话标识符以便调用setValue、getValueҎ(gu)Q每个JSP面都必d开头位|调用getSesstionIDҎ(gu)?<br /><br /><br />4.2 setValueҎ(gu) <br />setValueҎ(gu)保存value字符串以?qing)与它关联的字符串名字。这U“名?值”对很容易人想起Dictionary对象。setValueҎ(gu)要求在第一个参C提供合法的会(x)话标识符Q它假定在自p调用之前getSessionIDҎ(gu)已经执行Q经q检验的合法?x)话标识W必然存在,因此它不再对传入的会(x)话标识符q行合法性检验?<br />setValueҎ(gu)按如下规则保存名?值对Q?<br />· 如果与value值关联的name以前q没有保存过Q则新的名字-值对加入到文本文件的末尾?<br />· 如果value字符串关联的nameg前已l保存过Q则原来保存的D新的value值替换?<br />setValueҎ(gu)按照如下格式保存名字-值对Q注意“名字”是大小写敏感的Q?<br />name-1 value-1name-2 value-2name-3 value-3...name-n value-n <br />setValueҎ(gu)的声明如下:(x) <br />public void setValue(String sessionId, String name, String value) <br />setValueҎ(gu)首先L与当前会(x)话对应的文本文g。如果不能找到文本文Ӟ则setValueҎ(gu)不做M事情直接q回。如果找C(jin)?x)话文本文gQsetValueҎ(gu)d文本文g的各个行Q然后比较读入的行与nameQ如果读入的文本行开头与name一P则说明该名字已经保存QsetValueҎ(gu)替换该行后面的|如果name不能与读入的文本行匹配,则这行文本被直接复制C个(f)时文件?<br />q部分功能的实现代码如下Q?<br />try { FileReader fr = new FileReader(path + sessionId); BufferedReader br = new BufferedReader(fr); FileWriter fw = new FileWriter(path + sessionId + ".tmp"); BufferedWriter bw = new BufferedWriter(fw); String s; while ((s = br.readLine()) != null)if (!s.startsWith(name + " ")) { bw.write(s); bw.newLine();} bw.write(name + " " + value); bw.newLine(); bw.close(); br.close(); fw.close(); bw.close(); . . .}catch (FileNotFoundException e) {}catch (IOException e) { System.out.println(e.toString());} <br />原来文本文g中的所有行复制C(f)时文件之后,setValueҎ(gu)删除原来的文本文Ӟ然后把(f)时文件改成会(x)话文本文件的名字Q?<br />File f = new File(path + sessionId + ".tmp");File dest = new File(path + sessionId);dest.delete();f.renameTo(dest); <br /><br /><br />4.3 getValueҎ(gu) <br />getValueҎ(gu)用于提取原来保存在伪?x)话中的数据。正如setValueҎ(gu)QgetValueҎ(gu)也要求传入一个合法的?x)话标识W,而且getValueҎ(gu)不再对传入的?x)话标识W进行合法性检查。getValueҎ(gu)的第二个参数是待提取数据的nameQ返回值是与指定name兌的value?<br />getValueҎ(gu)的声明如下:(x) <br />public String getValue(String sessionId, String name) <br />getValueҎ(gu)的基本执行过E如下:(x)首先扑ֈ?x)话文本文gQ然后按行读入直x(chng)Cname匚w的文本行Q找到匹配的文本行之后,getValueҎ(gu)q回该行保存的valueQ如果不能找刎ͼgetValueҎ(gu)q回null?<br /><br /><br />4.4 deleteAllInvalidSessionsҎ(gu) <br />deleteAllInvalidSessionsҎ(gu)删除那些与已l过期的?x)话兌的文本文件。由于调用getSessionIDҎ(gu)时过期的?x)话文本文g?x)被删除QdeleteAllInvalidSessionsҎ(gu)q不是关键的Ҏ(gu)。什么时候调用这个方法由应用自己军_。例如,我们可以~写一个专用的后台E序Q由q个E序每天一ơ清除所有过期的文本文g。最单的办法是在JSP文g末尾调用deleteAllInvalidSessionsҎ(gu)Q但如果|站比较J忙Q重复地调用deleteAllInvalidSessionsҎ(gu)降低整个网站的响应能力。一U明智的做法是:(x)~写一个在讉K量较?yu)的时候自动进行清理的后台E序?<br />deleteAllInvalidSessionsҎ(gu)的声明如下:(x) <br />public void deleteAllInvalidSessions() <br />它首先把所有会(x)话文本文件的名字dfiles字符串数l:(x) <br />File dir = new File(path); String[] files = dir.list(); <br />deleteAllInvalidSessionsҎ(gu)比较文本文g的最后修Ҏ(gu)_(d)加上时旉Q和pȝ当前旉Q确定会(x)话是否过期。longcd的变量now用于保存pȝ的当前时间?<br />long now = System.currentTimeMillis(); <br />接下来,deleteAllInvalidSessionsҎ(gu)通过循环讉Kfiles数组Q依ơ检查每个文件的lastModified属性。所有与q期?x)话兌的文仉被删除Q?<br />for (int i=0; i<files.length; i++) { File f = new File(path + files[i]); if (f.lastModified() + timeOut > now) f.delete(); // 删除q期的会(x)话文本文件} <br /><br /><br />五、应用实?<br /><br /><br />~译好PseudoSessionBeanq个JavaBean之后Q我们就可以利用伪会(x)话管理机制来理Web应用的会(x)话状态信息了(jin)。由于不必再使用服务器的?x)话理机制Q我们可以在page指o(h)中把session属性设|ؓ(f)false关闭默认的JSP/Servlet?x)话理功能?<br /><%@ page session="false" %> <br /><br />然后Q我们用JSP?lt;jsp:useBean>标记告诉JSP容器E序要用PseudoSessionBeanQ?<br /><jsp:useBean id="PseudoSessionId" scope="application" class="pseudosession.PseudoSessionBean" /> <br /><br />在上面这?lt;jsp:useBean>标记中,class属性值是“包.cd字”Ş式。当?dng)对于不同的包名字Qclass属性的值应该作相应的修攏V注意Bean的scope属性是“application”,q是因ؓ(f)我们要在应用的所有页面中使用q个Bean。在q个应用中,把Bean的scope属性设|ؓ(f)“application”具有最好的效率Q因为我们只需创徏Bean对象一ơ就可以?jin)。另外,正如前面所提到的,getSessionIDҎ(gu)必须在所有其他代码之前调用?<br /><% String sessionId = PseudoSessionId.getSessionID(request);%> <br />Z(jin)说明PseudoSessionBean的应用,下面我们来看两个JSP面Q它们是index.jsp和secondPage.jsp。index.jsp面在伪?x)话变量中保存用L(fng)名字Q而secondPage.jsp则提取这个用户名字?<br /><br />index.jsp面的代码如下:(x) <br /><%@ page session="false" contentType="text/html;charset=gb2312" %><br /><jsp:useBean id="PseudoSessionId" scope="application" class="pseudosession.PseudoSessionBean" /><br /><% String sessionId = PseudoSessionId.getSessionID(request);%><br /><html><br /><head><br /><title>伪会(x)?lt;/title><br /></head><br /><body><br /><h1>伪会(x)话管理机?lt;/h1><br /><% String userName = "bulbul"; PseudoSessionId.setValue(sessionId, "userName", userName);%><br /><a href=secondPage.jsp?sessionId=<%=sessionId%>>点击此处</a><br /><form method="post" action=anotherPage.jsp?sessionId=<%=sessionId%>><br />输入数据:<input type="text" name="sample"><br /><input type="submit" name="Submit" value="Submit"><br /></form><br /></body><br /></html><br /><% PseudoSessionId.deleteAllInvalidSessions();%> <br /><br />注意Q包?lt;form>标记的action属性在内,所有的链接都已l改写,现在都包含了(jin)?x)话标识W。另外也h意页面的最后调用了(jin)deleteAllInvalidSessionsҎ(gu)?<br />secondPage.jsp面只简单地q回以前保存的用户名字?<br /><%@ contentType="text/html;charset=gb2312" page session="false" %><br /><jsp:useBean id="PseudoSessionId" scope="application" class="pseudosession.PseudoSessionBean" /><br /><% String sessionId = PseudoSessionId.getSessionID(request);%><br /><html><br /><head><br /><title>W?个页?lt;/title><br /></head><br /><body><br /><% String userName = PseudoSessionId.getValue(sessionId, "userName"); out.println("用户名字?" + userName);%><br /></body><br /></html> </div> </td> </tr> </tbody> </table> <img src ="http://www.tkk7.com/balajinima/aggbug/157679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/balajinima/" target="_blank">李云?/a> 2007-11-02 10:41 <a href="http://www.tkk7.com/balajinima/articles/157679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC基础知识 http://www.tkk7.com/balajinima/articles/146901.html李云?/dc:creator>李云?/author>Thu, 20 Sep 2007 11:54:00 GMThttp://www.tkk7.com/balajinima/articles/146901.htmlhttp://www.tkk7.com/balajinima/comments/146901.htmlhttp://www.tkk7.com/balajinima/articles/146901.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/146901.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/146901.html阅读全文

]]>
单的jsp控制分页http://www.tkk7.com/balajinima/articles/134185.html李云?/dc:creator>李云?/author>Fri, 03 Aug 2007 02:55:00 GMThttp://www.tkk7.com/balajinima/articles/134185.htmlhttp://www.tkk7.com/balajinima/comments/134185.htmlhttp://www.tkk7.com/balajinima/articles/134185.html#Feedback0http://www.tkk7.com/balajinima/comments/commentRss/134185.htmlhttp://www.tkk7.com/balajinima/services/trackbacks/134185.html
<%
 (tng)//分页昄
 (tng)int num = 0;
 (tng)int countall = infolist.size();//L
 (tng)int pageSize = 28;//每页数量
 (tng)int pageCount;//d|
 (tng)int pageNo = 1;//当前号
 (tng)int mixNum; (tng) (tng) //当前|据开始号
 (tng)int maxNum;
 (tng)
 (tng)String pNO = request.getParameter("pageNo");

 (tng)if((pNO != null) && (!pNO.equals(""))){

 (tng) (tng)pageNo=Integer.parseInt(pNO);
 (tng)}

 (tng)if (countall > pageSize) {
 (tng) (tng)if ((countall / pageSize) * pageSize < countall) {
 (tng) (tng) (tng)pageCount = (countall / pageSize) + 1;
 (tng) (tng)}
 (tng) (tng)else{
 (tng) (tng) (tng)pageCount = (countall / pageSize);
 (tng) (tng)}
 (tng)}
 (tng)
 (tng)else if (countall / pageSize == 1) {
 (tng) (tng)pageCount = 1;
 (tng)}
 (tng)else {
 (tng) (tng)pageCount = 1;
 (tng)}

 (tng)if (pageNo >= pageCount) {
 (tng) (tng)pageNo = pageCount;
 (tng)}
 (tng)else if (pageNo < 1) {
 (tng) (tng)pageNo = 1;
 (tng)}
 (tng) (tng) (tng) (tng)
 (tng) (tng) (tng) (tng)
 (tng)mixNum = (pageNo-1) * pageSize;
 (tng)maxNum = pageNo*pageSize;
 (tng)
 (tng)if((mixNum + pageSize) > countall){
 (tng) (tng)maxNum = countall;
 (tng)}
 (tng)else{
 (tng) (tng)maxNum = mixNum+pageSize;
 (tng)}
%>
---------------------------------------------------------------------------------------------
<html>
<head>
<script language="JavaScript" type="text/JavaScript">
function check(){
 (tng)if(Jtrim(document.forms.meslistForm.textfield.value)==""){
 (tng) (tng)alert("误入页?);
 (tng)}
 (tng)else if(checkNum(document.forms.meslistForm.textfield.value)){
 (tng) (tng)window.location.href="?pageNo="+document.forms.meslistForm.textfield.value;
 (tng)}else{
 (tng) (tng)alert("误入数字?);
 (tng)}
 (tng)document.forms.meslistForm.textfield.value = "";
 (tng)document.forms.meslistForm.textfield.select();
}
function checkNum(str){
return str.match(/\D/)==null;
}

function Jtrim(str)
{

 (tng) (tng) (tng) (tng) (tng) (tng) (tng) var i = 0;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) var len = str.length;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) if ( str == "" ) return( str );
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) j = len -1;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) flagbegin = true;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) flagend = true;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) while ( flagbegin == true && i< len)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if ( str.charAt(i) == " " )
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) i=i+1;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) flagbegin=true;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) else
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) flagbegin=false;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) }

 (tng) (tng) (tng) (tng) (tng) (tng) (tng) while (tng) (flagend== true && j>=0)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (str.charAt(j)==" ")
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) j=j-1;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) flagend=true;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) else
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) {
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) flagend=false;
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) }

 (tng) (tng) (tng) (tng) (tng) (tng) (tng) if ( i > j ) return ("")

 (tng) (tng) (tng) (tng) (tng) (tng) (tng) trimstr = str.substring(i,j+1);
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) return trimstr;
}</script>
</head>


<body>
<%
 (tng)for(int i=mixNum;i<maxNum;i++){
 (tng)//此处用list循环下标用i
 (tng)} (tng) (tng) (tng) (tng) (tng)  (tng) (tng) (tng)
%>

 (tng)

 (tng)

 (tng)

 (tng)


 (tng)<table align="center" width="100%" border="0" cellspacing="0" cellpadding="0">
 (tng) (tng) (tng)<tr>
 (tng) (tng) (tng) (tng)<td width="4%" height="27" align="center" valign="middle"
 (tng) (tng) (tng) (tng) (tng)class="word">&nbsp;</td>
 (tng) (tng) (tng) (tng)<td width="56%" align="center" valign="middle" class="word"><img
 (tng) (tng) (tng) (tng) (tng)src="<%=path%>/images/pagination/list_home.gif" width="13"
 (tng) (tng) (tng) (tng) (tng)height="13">&nbsp; <%
 (tng) (tng) (tng) (tng) (tng) (tng)if (pageNo > 1) {
 (tng) (tng) (tng) (tng) (tng)%> <a href="?pageNo=1">&nbsp;首页</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 (tng) (tng) (tng) (tng)<%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)}else{
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %> &nbsp;首页&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)}
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %> <img src="<%=path%>/images/pagination/list_pre.gif"
 (tng) (tng) (tng) (tng) (tng)width="13" height="13"> <%
 (tng) (tng) (tng) (tng) (tng) (tng)if (pageNo > 1) {
 (tng) (tng) (tng) (tng) (tng)%> <a href="?pageNo=<%=(pageNo-1)%>">&nbsp;前一?lt;/a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 (tng) (tng) (tng) (tng)<%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)}else{
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %> &nbsp;前一?amp;nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)}
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %> <img
 (tng) (tng) (tng) (tng) (tng)src="<%=path%>/images/pagination/list_next.gif" width="13"
 (tng) (tng) (tng) (tng) (tng)height="13"> <%
 (tng) (tng) (tng) (tng) (tng) (tng)if (pageCount>pageNo) {
 (tng) (tng) (tng) (tng) (tng)%> <a href="?pageNo=<%=(pageNo+1)%>">&nbsp;&nbsp;后一?lt;/a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 (tng) (tng) (tng) (tng)<%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)}else{
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %> &nbsp;&nbsp;后一?amp;nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)} (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %> <img src="<%=path%>/images/pagination/list_end.gif"
 (tng) (tng) (tng) (tng) (tng)width="13" height="13"> <%
 (tng) (tng) (tng) (tng) (tng) (tng)if (pageCount>pageNo) {
 (tng) (tng) (tng) (tng) (tng)%> <a href="?pageNo=<%=(pageCount)%>">&nbsp;&nbsp;N</a> <%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)}else{
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %> &nbsp;&nbsp;N <%
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)  (tng)} (tng)
 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %>
 (tng) (tng) (tng) (tng)<td width="26%" align="center" valign="middle" class="word">?lt;%=pageCount%>?amp;nbsp;W?lt;%=pageNo%>?amp;nbsp;
 (tng) (tng) (tng) (tng)跌{</td>
 (tng) (tng) (tng) (tng)<td width="4%" align="center" valign="middle" class="word"><input
 (tng) (tng) (tng) (tng) (tng)name="textfield" type="text" class="input" size="1"></td>
 (tng) (tng) (tng) (tng)<td width="6%" align="center" valign="middle" class="word"><a
 (tng) (tng) (tng) (tng) (tng)href="javascript:check()"><img
 (tng) (tng) (tng) (tng) (tng)src="<%=path%>/images/pagination/go.gif" border="0" width="18"
 (tng) (tng) (tng) (tng) (tng)height="18"></a></td>

 (tng) (tng) (tng) (tng)<td width="4%" align="left" valign="middle" class="word">&nbsp;</td>
 (tng) (tng) (tng)</tr>
 (tng) (tng)</table></body> (tng) (tng)
</html>



]]>
վ֩ģ壺 ɬɬƵ| µĻ| ޾Ʒþþwww| Ļۺ234| ޹˾ƷҰһ| ߹۹Ļ | AVվ߹ۿ| ˳վ| ŮܳƵ| ѿbbb| ŷһվ7777 | ؼؼŷһ| 鶹Ƶѹۿ| ۺʮ| պAVר| øѹۿ| ޾Ʒ˳߲ӰԺ| avվyy| պһ| aۺaav| ŮҹëƬѿ| þþþseɫ͵͵޾Ʒav | ŮˬˬˬˬˬƵ| Ʒ޲Ʒһ | xxxxձ| Ļ߹ۿ| Ʒ鶹ѹۿ| ĻۺϾƷһ| 1000žžʮδֹۿ | ŷպۺ| ԻƵs| Ļ| ѵҰսƵ| þþù޾Ʒ| Ѹ߰Ƶ| þþþþavѿ| ۲ӰԺƷַ| Ѹ߹ۿ| 鶹ۺ뾫Ʒ| ˬaëƬ| þþƷAV뽿ɫ|