论坛首页 移动开发技术论坛

通过sessionId的方式使手机浏览支持session

浏览 8274 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-06-09   最后修改:2010-06-11
WAP
   Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,用该SessionID为标识符来存取服务器端的Session存储空间。而SessionID这一数据则是保存到客户端,用Cookie保存的,用户提交页面时,会将这一SessionID提交到服务器端,来存取Session数据。所以一旦客户端禁用Cookie,那么Session也会失效。
   由于目前有的手机不支持cookie,导致手机上session支持不了,于是乎就有了几种针对这些特殊情况而提出的解决方案。而最常见的就是url重写,而url重写又分几种,有jstl实现,struts实现,普通传参实现,而我用的也就是最普通最常见的一种实现方式。
    其实我也是根据kaixin001中的方式来做的,kaixin001中的wap形式就是在链接后面直接传sessionId的方式(其中包括了用户的id,后面有串字符串,我猜想应该就是sessionId),比如:http://localhost:8080/project/MobileLogin.do?sessionId=xxxxxxxx;这个sessionId就是session的id,通过链接传参的方式传到后台,在后台,由于不支持session,故需要自己开发一套基于session的操作。
    首先,先了解下Map的含义,在java中,我们都知道Map是一个用于存储键值对的一个集合,也就是我们常说的key、value对应值,并且每个键映射一个值,这个键是不能重复的。
    上面了解了Map的含义,为什么要了解Map,是因为在接下来我需要在程序中用到Map。好了,言归正传,怎么才能实现sessionId取session的步骤呢,相信看了上面的Map,应该有人脑子里面有思路了,那就是利用Map的存储方式来操作sessionId,根据sessionId生成一个session,由于Map是key不能重复,所以就可以把sessionId设置成key,session设置为map的value,并且要保证这个sessionId永远都只需要创建一次,这就又用到了一个经典的设计模式:单例模式。第一次登录访问sessionId是新的,就往map中put一个,
public synchronized void sessionCreated(HttpSession session) {   
        
    	if(session != null) {   
        	map.put(session.getId(), session);   
        }   
    }   

除非你登录失败,否则这个sessionId一直跟随你的程序在运行,直到你手动注销session(把session destroryed)或者重新登录一次(替换原有的sessionId)。
public synchronized void sessionDestroyed(HttpSession session) {   
        
    	if(session != null) {   
        	map.remove(session.getId());   
        }   
    } 

单例模式的session容器已经构建,最后就是在类中提供一个getSession的方法;
public synchronized HttpSession getSession(String sessionId) {   
        
    	if(sessionId == null)
    		return null;   
        return (HttpSession) map.get(sessionId);   
    }   

session容器的构建类已经写完,现在就是监听事件了,新建一个Listener监听器,实现HttpSessionListener,HttpSessionListener提供2个方式,一个是sesionCreated(session的创建方法),一个是sessionDistoryed(session的销毁方法),在created方法中,调用单例类中的sessionCreate方法,在destroyed方法中调用单例类中的sessionDistoryed方法,监听器需要在web.xml中进行配置.
<listener>
           <listener-class>xxx包下的xxx类</listener-class>
    </listener>

至此,就完成了一个session的构建,并且这个session是根据sessionId的变化而变化。下面看具体的代码:
//session容器单例类

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

public class SessionContext {

	private static SessionContext instance;   
    private Map<String, HttpSession> map;   
    
    private SessionContext() {   
    	map = new HashMap<String, HttpSession>();   
    }   
    
    public static SessionContext getInstance() {   
        
    	if(instance == null) {   
            instance = new SessionContext();   
        }   
        return instance;   
    }   
    
    public synchronized void sessionCreated(HttpSession session) {   
        
    	if(session != null) {   
        	map.put(session.getId(), session);   
        }   
    }   
    
    public synchronized void sessionDestroyed(HttpSession session) {   
        
    	if(session != null) {   
        	map.remove(session.getId());   
        }   
    }   
    
    public synchronized HttpSession getSession(String sessionId) {   
        
    	if(sessionId == null)
    		return null;   
        return (HttpSession) map.get(sessionId);   
    }   



}


//session监听器

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

public class SessionListener implements HttpSessionListener {

    private SessionContext sessionContext = SessionContext.getInstance();

    
	public void sessionCreated(HttpSessionEvent httpSessionEvent) {
		sessionContext.sessionCreated(httpSessionEvent.getSession());

	}

	public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
		sessionContext.sessionDestroyed(httpSessionEvent.getSession());		
	}
	

}

session容器构建好了,现在就是action的操作了,action中相对比较简单。
public String sessionId;	
	
	public HttpSession getWapSession() throws Exception {
		HttpSession session = SessionContext.getInstance().getSession(sessionId);
		return session;
	}
	
	public void delSession() throws Exception {
		SessionContext.getInstance().sessionDestroyed(getWapSession());
	}

	public void setWapAttribute(String key, Object value) throws Exception {
		this.getWapSession().setAttribute(key, value);
	}
	
	public String getSessionId() {
		return sessionId;
	}


	public void setSessionId(String sessionId) {
		this.sessionId = sessionId;
	}

通过session传值,setWapAttribute(key,value),在页面上同样还是用SessionContext.getInstance().getSession(sessionId)得到session,才能从session中getAttribute值,其中的sessionId从request请求中get出,目前我还在测试怎么让它支持EL表达式,所以页面上还是用的<%%>这种取值方法。
以上就是action的部分代码,sessionId指的是页面上session.getId(),通过URL参数的方式传到后台,http://localhost:8080/project/xxx.do?session=<%=session.getId()%>,链接是这样的。url是自己组装。这个url方式是仿照开心网中的手机版本(wml.kaixin001.com),至此,一个手机登录的session问题是完美解决了,这里没有加权限判断。只提供了处理手机的登录session问题,相信有了session,其余的对我们来说不是什么难点。后期有时间再来写权限验证。
    wap开发,页面展示必须是符合wml规范的文件,可以是jsp文件,只不过头部要把头部的contentType类型改成wml形式的,
<%@ page contentType="text/vnd.wap.wml;charset=utf-8"%>

然后
<?xml version="1.0"  encoding="utf-8" ?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
	<card id="" title="">
</card>
</wml>

记住一点,wml语法的一点就是一定要有结束标签,哪怕是用这样的<br>,在wml语法中也是错误的,必须要有结束。<br/>或者<br></br>,而且wml中严格区分大小写。这些都是必须遵守的。
    如果有比这个更好的方法,期待共同探讨。
   发表时间:2010-06-13  
<c:url 用标签库中这个标签写Url 不就结了。。干嘛要自己去写。。
重定向就这样写
String url= response.encodeRedirectURL(request.getContextPath(+"/wap/Index_input.action");
response.sendRedirect(url);
自动会检查浏览器是否支持,如果不支持就会重写url  自动带上sessionid
我现在wap就是这样做的。。  楼主你这样我感觉有多余。  而且你还要维护哪个map。
???
楼主你这样写 有点误入子弟。。。
0 请登录后投票
   发表时间:2010-06-13  
楼主提到
   url重写又分几种,有jstl实现,struts实现,普通传参实现
普通实现应该就是
response.encodeURL(url);
可以了 。
 
0 请登录后投票
   发表时间:2010-06-15  
liweixw 写道
<c:url 用标签库中这个标签写Url 不就结了。。干嘛要自己去写。。
重定向就这样写
String url= response.encodeRedirectURL(request.getContextPath(+"/wap/Index_input.action");
response.sendRedirect(url);
自动会检查浏览器是否支持,如果不支持就会重写url  自动带上sessionid
我现在wap就是这样做的。。  楼主你这样我感觉有多余。  而且你还要维护哪个map。
???
楼主你这样写 有点误入子弟。。。

哦,弱弱的问下,请问你这种session要怎么管理呢?我看了你写的文章,90%是网络上抄袭的,还有就是没有写session的管理。我没有恶意,只是我想问下你session是怎么管理的,我还没用过项目中,只是在研究阶段,第一次做wap开发,没什么经验。既然你有这方面的经验,那么我虚心请教下你。
0 请登录后投票
   发表时间:2010-06-15  
没有必要对session进行手动管理,encodeURL()就可以达到你上面的几十行代码的效果了。
另外singleton的实现有点问题
0 请登录后投票
   发表时间:2010-06-16  
如果浏览器不支持Cookie,就直接是URL rewrite就行了。
0 请登录后投票
   发表时间:2010-06-17  
mercyblitz 写道
如果浏览器不支持Cookie,就直接是URL rewrite就行了。

恩,知道了,是我多此一举了,我想复杂了。
0 请登录后投票
   发表时间:2010-06-17  
herryhaixiao 写道
liweixw 写道
<c:url 用标签库中这个标签写Url 不就结了。。干嘛要自己去写。。
重定向就这样写
String url= response.encodeRedirectURL(request.getContextPath(+"/wap/Index_input.action");
response.sendRedirect(url);
自动会检查浏览器是否支持,如果不支持就会重写url  自动带上sessionid
我现在wap就是这样做的。。  楼主你这样我感觉有多余。  而且你还要维护哪个map。
???
楼主你这样写 有点误入子弟。。。

哦,弱弱的问下,请问你这种session要怎么管理呢?我看了你写的文章,90%是网络上抄袭的,还有就是没有写session的管理。我没有恶意,只是我想问下你session是怎么管理的,我还没用过项目中,只是在研究阶段,第一次做wap开发,没什么经验。既然你有这方面的经验,那么我虚心请教下你。


是的。我是网上找的资料,为了以后方便查阅,其实也就是一时兴起, 我原来考虑也和你一样,我是参考的网易是怎么做的,(wap.163.com opera访问的) 我发现在禁用cookie的时候url网易会自动带上这个sessionid。
综合我现在的项目实践 我是这样做的。
1.在jsp中涉及到url是用的是标签库 <c:url 标签 填写url(这个标签自动会检查浏览器是否支持cookie,支持就原样返回,不支持自动带上sessionid)
2。在涉及后台转发时候用 首先用response.encodeURL()方法重写,和上面的标签一样的功能;
3.后台重定向用response.encodeRedirectURL()方法重写后转发。


0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics