1. 程式人生 > >使用JSON進行資料傳輸的總結

使用JSON進行資料傳輸的總結

四、Struts 2 中使用Json ajax 支援

JSON 外掛提供了一種名為json 的ResultType ,一旦為某個Action 指定了一個型別為json 的Result ,則該Result 無需對映到任何檢視資源。因為JSON 外掛會負責將Action 裡的狀態資訊序列化成JSON 格式的資料,並將該資料返回給客戶端頁面的 JavaScript 。

  簡單地說,JSON 外掛允許我們在JavaScript 中非同步呼叫Action ,而且Action 不再需要使用檢視資源來顯示該Action 裡的狀態資訊,而是由JSON 外掛負責將Action 裡的狀態資訊返回給呼叫頁面——通過這種方式,就可以完成Ajax

 互動。

  Struts2 提供了一種可插拔方式來管理外掛,安裝Struts2 的JSON 外掛與安裝普通外掛並沒有太大的區別,一樣只需要將Struts2 外掛的JAR 檔案複製到Web 應用的WEB-INF/lib 路徑下即可。

安裝JSON 外掛按如下步驟進行:

1 )登陸http://code.google.com/p/jsonplugin/downloads/list 站點,下載Struts2 的JSON 外掛的最新版本,當前最新版本是0.7 ,我們可以下載該版本的JSON 外掛。

2 )將下載到的jsonplugin-0.7.jar 檔案複製到Web 應用的WEB-INF 路徑下,即可完成JSON

 外掛的安裝。

  實現Action 邏輯

  假設deptnew.html 輸入頁面中包含了四個表單域,這四個表單域對於四個請求引數,因此應該使用Action 來的dept 物件封裝這四個請求引數。四個表單域的name 分別為dept.deptid 、dept.deptname 、dept.deptnum 和dept.deptdesc 。

處理該請求的Action 類程式碼如下:

package org.wllt.ajax.actions;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

import org.wllt.ajax.beans.Dept;

import com.googlecode.jsonplugin.annotations.JSON;

import com.opensymphony.xwork2.Action;

public class JSONExample

{

   // 封裝請求引數的三個屬性

   private String field1;

   private transient String field2;

   private String field3;

   // 封裝處理結果的屬性

   private int[] ints ={10, 20};

   private Map map = new HashMap();

   private String customName = "custom";

   // 日期格式的屬性

   private Date date;

   private Dept dept;

   // 三個請求引數對應的 setter  getter 方法

   @JSON(serialize=false)

    public String getField1(){

   return field1;

   }

   public void setField1(String field1)

{

     this.field1 = field1;

}

   // 封裝處理結果的屬性的 setter  getter 方法

   public int[] getInts()

   {

  return ints;

   }

   public void setInts(int[] ints)

   {

  this.ints = ints;

   }

   @JSON(format="yyyy-MM-dd")

   public Map getMap()

   {

  return map;

   }

   public void setMap(Map map)

   {

     this.map = map;

   }

public String getField2() {

     return field2;

}

public void setField2(String field2) {

     this.field2 = field2;

}

public String getField3() {

     return field3;

}

public void setField3(String field3) {

     this.field3 = field3;

}

    public Dept getDept() {

     return dept;

}

public void setDept(Dept dept) {

this.dept = dept;

}

   // 使用註釋語法來改變該屬性序列化後的屬性名

     @JSON(name="newName")

    public String getCustomName()

    {

  return this.customName;

    }

    @JSON(format="yyyy-MM-dd")

public Date getDate() {

     return date;

}

public void setDate(Date date) {

     this.date = date;

}

public String execute()

{

     map.put("name", "yeeku");

     map.put("curdate",new Date());

    return Action.SUCCESS;

}

}

在上面程式碼中,使用了JSON 註釋,註釋時指定了name 域,name 域指定Action 屬性被序列化成JSON 物件的屬性名。除此之外,JSON 註釋還支援如下幾個域:

Name  Action 屬性被序列化成JSON 物件的屬性名

serialize :設定是否序列化該屬性( 預設的action 的所有屬性都會序列化成json 文字響應到原頁面,也可以根據需要設定某些屬性不序列化 ) 。也可以通過在配置json 型別的結果的時候定義需要不序列化的屬性:

        <result name="success" type="json">

         <param name="excludeProperties">service,joindate,dept</param>

       </result>

  deserialize :設定是否反序列化該屬性。

format :設定用於格式化輸出、解析日期表單域的格式。例如"yyyy-MM-dd'T'HH:mm:ss" 。

一般需要註釋到需要轉換日期格式屬性的get 方法上面

配置該Action 與配置普通Action 存在小小的區別,為該Action 配置結果型別為json 的Result 。而這個Result 無需配置任何檢視資源, 只需要把通過該結果把json 文字響應到原頁面。

配置該Action 的struts.xml 檔案程式碼如下:

<? xml version = "1.0" encoding = "UTF-8" ?>

<! DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

"http://struts.apache.org/dtds/struts-2.0.dtd" >

< struts >

< constant name = "struts.locale" value = "zh_CN" />

< constant name = "struts.action.extension" value = "do,action" />

< package name = "json" extends = "json-default" >

< action name = "dept" class = "org.wllt.ajax.actions.DeptAction" >

< result type = "json" />

</ action >

</ package >

</ struts >

  在上面配置檔案中有兩個值得注意的地方:

  第一個地方是配置struts.i18n.encoding 常量時,不再是使用GBK 編碼,而是UTF-8 編碼,這是因為Ajax 的POST 請求都是以UTF-8 的方式進行編碼的。

  第二個地方是配置包時,自己的包繼承了json-default 包,而不再繼承預設的default 包,這是因為只有在該包下才有json 型別的Result 。

實現JSP 頁面first.jsp :

為了簡單地訪問DOM 節點,這裡用了JavaScript 框架Prototype.js.

< html >

< head >

< title > 使用 JSON 外掛 </ title >

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

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

</ script >

< script language = "JavaScript" >

function gotClick()

{

// 請求的地址

var url= './dept.do' ;

    //  Form 中所有 Input 物件的值轉化為一個 URL String ,方便把 Form 轉為用 URL Get 方式 //  Ajax提交,常用 Ajax 提交 Form 的例子 :

var params=Form.serialize( 'form1' );

// 建立 Ajax.Request 物件,對應於傳送請求

var myAjax= new Ajax.Request(url, {

// 請求方式: POST

method: 'post' ,

// 請求引數

parameters:params,

// 指定回撥函式

onComplete: processResponse,

// 是否非同步傳送請求

asynchronous: true

       } );

}

  function processResponse(request)

{

$( "show" ).innerHTML=request.responseText;

}

</ script >

</ head >

< body >

< form id = "form1" name = "form1" method = "post" >

部門編號 < INPUT TYPE = "text" name = "dept.deptid" id = "deptid" />< br >

部門名稱 < INPUT TYPE = "text" name = "dept.deptname" id = "deptname" />< br >

部門編制 < INPUT TYPE = "text" name = "dept.deptnum" id = "deptnum" />< br >

部門描述 < INPUT TYPE = "text" name = "dept.deptdesc" id = "deptdesc" />< br >

< INPUT TYPE = "button" value = " 提交 onClick = "gotClick();" />

</ form >

< div id = "show" >

</ div >

</ body >

</ html >

五、當json 碰到hibernate 延時載入

在開發Struts2.0+hibernate3.2+spring2.0 專案過程中,遇到了 failed to lazily initialize a collection of role: org.wllt.www.pojo.Dept.emps, no session or session was closed 這個異常的出現,通過以下方法可以解決這個問題:

1 、是把對應一對多的那兩個列lazy=true 改為lazy =false 即可;

2 、對於查詢中如果用的是xxx.load (class ,id )則改為xxx,get(class ,id) ;

3 、在web.xml 檔案中加入:

   <filter>

      <filter-name>hibernateFilter</filter-name>

      <filter-class>

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

</filter-class>

           <init-param>

<param-name>singleSession</param-name>

            <param-value>false</param-value>

          </init-param>

<!-- 這個 --   <init-param> 一定要加不然很可能會報錯    org.springframework.dao.InvalidDataAccessApiUsageException:Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition

-->

     </filter>

     <filter-mapping>

         <filter-name>hibernateFilter</filter-name>

         <url-pattern>*.wllt</url-pattern>

     </filter-mapping>

對以上方法進行一一測試,到後來結果都是一樣,出現同樣的異常,其實spring 能很好地解決這個問題,Spring 框架為Hibernate 延遲載入與DAO 模式的整合提供了一種方便的解決方法。以一個Web 應用為例,Spring 提供了OpenSessionInViewFilter 和OpenSessionInViewInterceptor 。我們可以隨意選擇一個類來實現相同的功能。兩種方法唯一的不同就在於interceptor 在Spring