IpuWadeMobile的Session管理

Session管理

1、場景描述:

  在你已經清晰的瞭解了不進行Session管理的環境下,進行普通頁面的開發以及進行頁面之間的跳轉的前提下,你或許會考慮讓你的服務器進行Session管理,以控制關鍵頁面的訪問和關鍵數據接口的調用。javascript

2、具體需求:

  使用Session進行會話管理,進行Session驗證。css

3、解決方案:

A、實現思路:

  首先想到,須要一個自定義的ContextData(上下文數據),用來緩存會話中產生的業務數據。再須要一個自定義的SessionManager(會話管理者),來進行自定義的Session校驗並管理ContextData。在自定義Session校驗的邏輯中,可使用Utility.error(paramString)或error(paramString)來拋出會話異常。當Session異常時,怎麼辦呢?此時便須要一個自定義的ExceptionHandler(異常管理者),來處理Session異常。在ExceptionHandler中,可使用MobileServerException.class.isInstance(e)和((MobileServerException)e).getCode()=="-100"來判斷是否爲Session異常,並做出相應處理。在登錄時,咱們可使用IpuSessionManager.getInstance().createSession(contextData)來建立Session。此方法會返回一個SessionId,咱們應將這個SessionId返回給前端JS。前端JS獲取到此SessionId後,保存到內存中。經過在common.js中重寫核心API(如openPage,callSvc),讓前端在訪問須要進行Session校驗的頁面時,自動在傳入參數中攜帶好本次會話的SessionId。最後,別忘了在server-config.xml中配置好你的異常處理類和會話管理類(配置參數爲exceptionHandler和sessionManager)。html

B、具體實現:

1.自定義上下文數據,類名IpuContextData。以下,在上下文數據中存入了當前登錄用戶的用戶名。 前端

package com.ipu.server.core.context;
import com.ailk.mobile.frame.context.impl.DefaultContextData;
public class IpuContextData extends DefaultContextData {
    private static final long serialVersionUID = 1L;
    public String getUserName(){
        return contextData.getString("USER_NAME");
    }
    public void setUserName(String name){
        contextData.put("USER_NAME", name);
    }
}

2.自定義會話管理者,類名IpuSessionManager。以下,用來書寫Session校驗邏輯,進行登錄狀態的檢測。因爲下面進行了用戶名的校驗,故須要在每次請求時,除了攜帶SessionId外,還須要攜帶當前登錄用戶的用戶名,而且要求保證本次請求傳入的用戶名與Context中保存的用戶名(登錄時傳入的用戶名)一致。 java

package com.ipu.server.core.session;
import com.ailk.common.data.IData;
import com.ailk.common.util.Utility;
import com.ailk.mobile.frame.context.IContextData;
import com.ailk.mobile.frame.session.impl.AbstractSessionManager;
import com.ipu.server.core.context.IpuContextData;
public class IpuSessionManager extends AbstractSessionManager {
    @Override
    public void customVerify(String paramString, IData paramIData,
            IContextData paramIContextData) throws Exception {
        System.out.println("IpuSessionManager.customVerify()");
        String userName = paramIData.getString("USER_NAME");
        String contextUserName = ((IpuContextData)paramIContextData).getUserName();
        if(userName == null || !userName.equals(contextUserName)){
            Utility.error("非法操做,請從新登錄!");
        }
    }
}

3.自定義異常管理類,類名IpuExceptionHandler。以下,用來處理Session校驗異常。此處須要注意,當在瀏覽器上訪問時,ServletManager.openPage("SessionErr")會生效,當客戶端訪問時,因爲新頁面並不是來自服務器端,上面的頁面跳轉不會生效。因此更明智的作法是,在此處書寫其它業務邏輯,而是否進行頁面跳轉的判斷在js端去執行。jquery

package com.ipu.server.core.handle;
import com.ailk.mobile.frame.handle.impl.DefaultExceptionHandler;
import com.ailk.mobile.servlet.ServletManager;
import com.ailk.mobile.util.MobileServerException;
public class IpuExceptionHandler extends DefaultExceptionHandler {
    @Override
    public void pageErrorHandle(Exception e, String pageAction, String data)
            throws Exception {
        if(MobileServerException.class.isInstance(e)){
            if(((MobileServerException)e).getCode()=="-100"){
                ServletManager.openPage("SessionErr");
            }
        }
        super.pageErrorHandle(e, pageAction, data); //執行父類的邏輯
    }
}

4.自定義數據接口的父類,類名IpuAppBean。以下,因爲通常的數據接口類都是繼承自AbstractBean,他的getContextData方法返回的數據類型爲IContext,爲了不每次獲取時主動的強制類型轉換,能夠自定義一個數據接口的父類,將強制類型轉換的邏輯寫入父類中。 web

package com.ipu.server.core.bean;
import com.ailk.mobile.frame.bean.AbstractBean;
import com.ipu.server.core.context.IpuContextData;
public class IpuAppBean extends AbstractBean {
    @Override
    protected IpuContextData getContextData() throws Exception {
        return (IpuContextData)(getContext().getContextData());
    }
}

5.建立登錄驗證的數據接口,類名Login,方法名checkLogin。以下,從前端傳來用戶名和密碼以後,能夠進行用戶名和密碼的校驗,如若校驗經過,則首先建立一個新的上下文數據,做爲建立Session時的參數,進而建立了一個新的Session,同時,將新的Session對應的SessionId返回給JS端。 瀏覽器

package com.ipu.server.bean;
import com.ailk.common.data.IData;
import com.ailk.common.data.impl.DataMap;
import com.ipu.server.core.bean.IpuAppBean;
import com.ipu.server.core.context.IpuContextData;
import com.ipu.server.core.session.IpuSessionManager;
public class Login extends IpuAppBean{
    public IData checkLogin(IData param){
        String userName = param.getString("USER_NAME");
        @SuppressWarnings("unused")
        String passWord = param.getString("PASS_WORD");
        if(userName == null){
            userName = "無名氏";
        }
        String sessionId="ERR";
        try {
            IpuContextData contextData = new IpuContextData();
            contextData.setUserName(userName);
            sessionId = IpuSessionManager.getInstance().createSession(contextData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        IData resultData = new DataMap();
        resultData.put("SESSION_ID",sessionId);
        return resultData;
    }
}

6.配置Login.checkLogin數據接口。找到etc/server-data.xml配置文件,在datas節點下,添加或修改以下配置。 緩存

<action name="Login.checkLogin" class="com.ipu.server.bean.Login" method="checkLogin" verify="false" >
</action>

7.配置會話管理類和異常管理類。找到etc/server-config.xml配置文件,添加或修改以下兩項配置(exceptionHandler和sessionManager)。 服務器

<config name="exceptionHandler" value="com.ipu.server.core.handle.IpuExceptionHandler"/>
<config name="sessionManager" value="com.ipu.server.core.session.IpuSessionManager"/>

8.建立本身的登錄頁面,文件名Login.html。

<!DOCTYPE html>
<html>
  <head>
    <title>登陸</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <link rel="apple-touch-icon" href="touch-icon-iphone.png" />
    <link rel="apple-touch-icon-precomposed" href="touch-icon-iphone.png" />
    <!--1,引入CSS文件 -->
    <link rel="stylesheet" href="biz/ipu/theme/hum.css">
  </head>
  <body>

  <header class="ui-toolbar" id="header" >
    <a class="ui-icon icon-left-nav fn-left" href="javascript:;" action="Index" ></a>
    <h1 class="ui-toolbar-title">登陸</h1>
  </header>
  <div class="ui-panel-content">
      <form>
          <input type="text" placeholder="用戶名" id="userName" />                
          <input type="text" placeholder="密碼" id="passWord"  />
          <button type="button" class="ui-btn ui-btn-block" id="loginBtn" >登陸</button>
      </form>
  </div>
  </body>
      {%>template/common/Head.html%}
    <script type="text/javascript" src="biz/js/Login.js"></script>
</html>

9.配置本身的登錄頁面。找到etc/server-page配置文件,在pages節點下,添加或修改以下配置項。

<action name="Login" template="template/webapp/ipu/Login.html" ></action>

10.書寫業務JS邏輯,文件名Login.js。以下,經過Mobile的callSvc方法,訪問數據接口Login.checkLogin。在回調方法中,獲取到返回的SessionId,並調用Mobile的setMemoryCache方法,將SessionId和UserName存入內存中(以便後續須要時取用,{注:在common.js中須要})。

require(["mobile","zepto","jcl"],function(Mobile,$,Wade){

    $("#header").children().click(function(){

        Mobile.openPage("Index");

    });

    $("#loginBtn").click(function(){

        Mobile.loadingStart("登錄中,請稍等……","等待");

        setTimeout(function(){

            Mobile.loadingStop();

            var userName = $("#userName").val();

            var passWord = $("#passWord").val();

            var data = Wade.DataMap();

            data.put("USER_NAME",userName);

            data.put("PASS_WORD",passWord);

            Mobile.callSvc("Login.checkLogin",data,function(resultData){

                var myData = new Wade.DataMap(resultData);

                var sessionId = myData.get("SESSION_ID");

                if(sessionId){

                    Mobile.setMemoryCache("SESSION_ID",sessionId);

                    Mobile.setMemoryCache("USER_NAME",userName);

                    Mobile.tip("登錄成功!");

                    Mobile.openPage("Index");

                }else{

                    alert("登錄異常,請聯繫管理員!");

                }

            });

        },600);

    });

});

 

11.在web/biz/js/common/common.js中,重寫核心Api(如:openPage,callSvc)。以下,從內存中獲取到以前存入的SessionId和UserName,將這兩個數據合併到即將發往服務端的參數中。即,經過common.js中的方法發送數據請求時,會自動帶上SessionId和UserName這兩個參數。

this.openPage = function(action,param){

    param = param?param:new Wade.DataMap();

    Mobile.getMemoryCache(function(data){

        data = new Wade.DataMap(data);

        param.put("SESSION_ID",data.get("SESSION_ID"));

        param.put("USER_NAME",data.get("USER_NAME"));

        Mobile.openPage(action,param);

    },['SESSION_ID','USER_NAME']);

};

this.callSvc = function(action,param,callback,err){

    param = param?param:new Wade.DataMap();

    Mobile.getMemoryCache(function(data){

        data = new Wade.DataMap(data);

        param.put("SESSION_ID",data.get("SESSION_ID"));

        param.put("USER_NAME",data.get("USER_NAME"));

        Mobile.callSvc(action,param,callback,err);

    },['SESSION_ID','USER_NAME']);

};

12.建立一個普通的html頁面,文件名Test.html。以下,此頁面會將獲取到的UserName顯示到頁面上。注意,此UserName是從上下文數據中獲取到,並返回到頁面上的。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
http://www.w3.org/TR/html4/loose.dtd
">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

{%>template/common/Head.html%}

</head>

<body>

    <h1>

        Session數據:{%USER_NAME%}

    </h1>

    <input type="button" value="打開照相" id="getPhoto" >

    <script type="text/javascript" src="biz/js/Test.js"></script>

</body>

</html>

13.建立一個普通的數據接口,類名Test,方法名getData。以下,他繼承自自定義的IpuAppBean,並調用了父類中的getContextData方法來獲取上下文數據。

package com.ipu.server.bean;
import com.ailk.common.data.IData;
import com.ailk.common.data.impl.DataMap;
import com.ipu.server.core.bean.IpuAppBean;
import com.ipu.server.core.context.IpuContextData;
public class Test extends IpuAppBean {
    public IData getData(IData param) throws Exception{
        IData data = new DataMap();
        IpuContextData contextData = getContextData();
        String name = contextData.getUserName();
        data.put("USER_NAME", name);
        return data;
    }
}

14.書寫普通html頁面對應的JS業務邏輯,文件名Test.js。

require(["mobile","zepto","wadeMobile"],function(Mobile,$,WadeMobile){

    $("#getPhoto").click(function(){

        Mobile.tip("測試成功!!!");

        WadeMobile.getPhoto(function(result){

            alert(result);

        },1);

    });

});

15.配置普通的數據接口。找到etc/server-data.xml配置文件,在datas節點下,添加或修改以下配置項。注意,此處的verify="true"。說明,訪問這個數據接口時,會進行Session校驗。

<action name="Test.getData" class="com.ipu.server.bean.Test" method="getData" verify="true" >
</action>

16.配置普通的html頁面。找到etc/server-page.xml配置文件,在pages節點下,添加或修改以下配置項。

<action name="Test" template="template/webapp/ipu/Test.html" data="Test.getData" >

</action>

17.關鍵點。上述工做完成後,若是須要從某個頁面(如index.html頁面),跳轉到須要進行Session校驗的頁面(或僅僅是訪問須要進行Session校驗的數據接口),應當(也必須)使用common.js中重寫的核心Api(如,Common.openPage,Common.callSvc),不然會產生Session異常。緣由是,使用普通的打開新頁面的方法(如:Mobile.openPage,Mobile.callSvc),不會自動將SessionId(以及UserName)帶到服務器端,故服務器端的Session校驗沒法經過。寫法,請參看以下示例。

require(["mobile","jquery","common"],function(Mobile,$,Common){

    $("#openTestPage").click(function(){

        Common.openPage("Test");

    });

});
相關文章
相關標籤/搜索