1. 程式人生 > >基於strut2處理json資料原理及具體例項

基於strut2處理json資料原理及具體例項

認識json

    JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式。易於人閱讀和編寫。同時也易於機器解析和生成。它 基於JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一個子集。 JSON採用完全獨立於語言的文字格式,但是也使用了類似於C語言家族的習慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)。這些特性使JSON成為理想的資料交換語言。(更多內容請參見JSON官網http://json.org/json-zh.html)。

JSON建構於兩種結構:

  • “名稱/值”對的集合(A collection of name/value     pairs)。不同的語言中,它被理解為物件(object,紀錄(record),結構(struct),字典(dictionary),雜湊表(hash table),有鍵列表(keyed list),或者關聯陣列 (associative array)。
  • 值的有序列表(An ordered list of values)。在大部分語言中,它被理解為陣列(array)。

這些都是常見的資料結構。事實上大部分現代計算機語言都以某種形式支援它們。這使得一種資料格式在同樣基於這些結構的程式語言之間交換成為可能。

JSON具有以下兩種形式:

一、 MAP

物件是一個無序的“‘名稱/值’對”集合。一個物件以“{”(左括號)開始,“}”(右括號)結束。每個“名稱”後跟一個“:”(冒號);“‘名稱/值’ 對”之間使用“,”(逗號)分隔。                           

二、ARRAY

 陣列是值(value)的有序集合。一個數組以“[”(左中括號)開始,“]”(右中括號)結束。值之間使用“,”(逗號)分隔。

Strut2中的json

    因為JSON是脫離語言的理想的資料交換格式,所以它被頻繁的應用在客戶端與伺服器的通訊過程中,這一點是毋庸置疑的。而在客戶端與伺服器的通訊過程中,JSON資料的傳遞又被分為伺服器向客戶端傳送JSON資料,和客戶端向伺服器傳送JSON資料,前者的核心過程中將物件轉換成JSON,而後者的核心是將JSON轉換成物件,這是本質的區別

。另外,值得一提的是,JSON資料在傳遞過程中,其實就是傳遞一個普通的符合JSON語法格式的字串而已,所謂的“JSON物件”是指對這個JSON字串解析和包裝後的結果,這一點請牢記,因為下面的內容會依賴這一點。

(1)Struts2返回JSON資料到客戶端

        在常規WEB應用中由伺服器返回JSON資料到客戶端有兩種方式:一,是在Servlet中輸出JSON串,二,是在JSP頁面中輸出JSON串。上文提到,伺服器像客戶端返回JSON資料,其實就是返回一個符合JSON語法規範的字串,所以在上述兩種 方法中存在一個共同點,就是將需要返回的資料包裝稱符合JSON語法規範的字串後在頁面中顯示。如下所示

使用Servlet返回JSON資料到客戶端:

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		//將要被返回到客戶端的物件
		User user=new User();
		user.setId("123");
		user.setName("JSONServlet");
		user.setPassword("JSON");
		user.setSay("Hello , i am a servlet !");
		JSONObject json=new JSONObject();
		json.accumulate("success", true);
		json.accumulate("user", user);
		out.println(json.toString());
      //因為JSON資料在傳遞過程中是以普通字串形式傳遞的,所以我們也可以手動拼接符合JSON語法規範的
      //字串輸出到客戶端
      //以下這兩句的作用與38-46行程式碼的作用是一樣的,將向客戶端返回一個User物件,和一個success欄位
     //String jsonString="{\"user\":{\"id\":\"123\",\"name\":\"JSONServlet\",\"say\":\"Hello , i am a servlet !\",\"password\":\"JSON\"},\"success\":true}";
//		out.println(jsonString);
		out.flush();
		out.close();
	}

結果在意料之中,如下圖所示:

使用JSP(或html等)返回JSON資料到客戶端:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
{"user":{"id":"123","name":"JSONJSP","say":"Hello , i am a JSP !","password":"JSON"},"success":true}

        再回到Struts,在Struts的MVC模型中,Action替代Servlet擔當了Model的角色,所以對於Struts而言,返回JSON資料到客戶端,跟傳統的WEB應用一樣,存在兩種方式,即在Action中輸出JSON資料,和在檢視資源中輸出JSON資料。再往下細分的話,在Action中輸出JSON資料又分為兩種方式,一是使用傳統方式輸出自己包裝後的JSON資料,二是使用Struts自帶的JSON資料封裝功能來自動包裝並返回JSON資料。

在檢視資源中輸出JSON資料

      Action處理完使用者請求後,將資料存放在某一位置,如request中,並返回檢視,然後Struts將跳轉至該檢視資源,在該檢視中,我們需要做的是將資料從存放位置中取出,然後將其轉換為JSON字串,輸出在檢視中。這跟傳統WEB應用中在JSP頁面輸出JSON資料的做法如出一轍:

public String testByJSP() {
		User user = new User();
		user.setId("123");
		user.setName("Struts2");
		user.setPassword("123");
		user.setSay("Hello world !");
		JSONObject jsonObject=new JSONObject();
		jsonObject.accumulate("user", user);
		//這裡在request物件中放了一個data,所以struts的result配置中不能有type="redirect"
		ServletActionContext.getRequest().setAttribute("data", jsonObject.toString());
		return SUCCESS;
	};

因為是常規的Struts流程配置,所以配置內容就不再展示了。JSP程式碼就非常簡單了,

 使用————${data }獲取

在Action中以傳統方式輸出JSON資料

 這一點跟傳統的Servlet的處理方式基本上一模一樣,程式碼如下

public void doAction() throws IOException{
		HttpServletResponse response=ServletActionContext.getResponse();
		//以下程式碼從JSON.java中拷過來的
		response.setContentType("text/html");
		PrintWriter out;
		out = response.getWriter();
		//將要被返回到客戶端的物件
		User user=new User();
		user.setId("123");
		user.setName("JSONActionGeneral");
		user.setPassword("JSON");
		user.setSay("Hello , i am a action to print a json!");
		JSONObject json=new JSONObject();
		json.accumulate("success", true);
		json.accumulate("user", user);
		out.println(json.toString());
//		因為JSON資料在傳遞過程中是以普通字串形式傳遞的,所以我們也可以手動拼接符合JSON語法規範的字串輸出到客戶端
//		以下這兩句的作用與38-46行程式碼的作用是一樣的,將向客戶端返回一個User物件,和一個success欄位
//		String jsonString="{\"user\":{\"id\":\"123\",\"name\":\"JSONActionGeneral\",\"say\":\"Hello , i am a action to print a json!\",\"password\":\"JSON\"},\"success\":true}";
//		out.println(jsonString);
		out.flush();
		out.close();
	}

struts.xml中的配置:

<package name="default" extends="struts-default" namespace="/">
	<action name="testJSONFromActionByGeneral" class="cn.ysh.studio.struts2.json.demo.action.UserAction" method="doAction">
	</action>
</package>

注意:這個action沒有result,且doAction方法沒有返回值!

就不再貼圖了,因為結果可想而知!

在Action中以Struts2的方式輸出JSON資料

本著“不重複發明輪子”的原則,我們將轉換JSON資料的工作交給Struts2來做,那麼相對於在Action中以傳統方式輸出JSON不同的是,Action是需要將注意力放在業務處理上,而無需關心處理結果是如何被轉換成JSON被返回客戶端的——這些 工作通過簡單的配置,Struts2會幫我們做的更好。

public String testByAction() {
		// dataMap中的資料將會被Struts2轉換成JSON字串,所以這裡要先清空其中的資料
		dataMap.clear();
		User user = new User();
		user.setId("123");
		user.setName("JSONActionStruts2");
		user.setPassword("123");
		user.setSay("Hello world !");
		dataMap.put("user", user);
		// 放入一個是否操作成功的標識
		dataMap.put("success", true);
		// 返回結果
		return SUCCESS;
	}

struts.xml中action的配置:

<package name="json" extends="json-default" namespace="/test">
		<action name="testByAction"
			class="cn.ysh.studio.struts2.json.demo.action.UserAction" method="testByAction">
			<result type="json">
				<!-- 這裡指定將被Struts2序列化的屬性,該屬性在action中必須有對應的getter方法 -->
				<param name="root">dataMap</param>
			</result>
		</action>
</package>

凡是使用Struts2序列化物件到JSON的action,所在的package必須繼承自json-default,注意,這裡唯一的result,沒有指定name屬性。

上面很詳細的說明了在WEB應用中如何返回JSON資料到客戶端,講了那麼多種方式,涉及的技術核心無非只有兩點:

1、將物件轉換成符合JSON語法格式的字串;
2、將符合JSON語法格式的字串返回客戶端;

第二點是整個實現過程的本質,但卻不難做到;第一點其實也不難,他甚至有兩種做法,一是通過字串拼接方式,而是通過JSONObject以物件方式轉換。看下面的一個例子:

下面是整個Action的完整程式碼:

package cn.ysh.studio.struts2.json.demo.action;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;

import net.sf.json.JSONObject;

import cn.ysh.studio.struts2.json.demo.bean.User;

import com.opensymphony.xwork2.ActionSupport;

public class UserAction extends ActionSupport {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	//將會被Struts2序列化為JSON字串的物件
	private Map<String, Object> dataMap;

	/**
	 * 構造方法
	 */
	public UserAction() {
		//初始化Map物件
		dataMap = new HashMap<String, Object>();
	}

	/**
	 * 測試通過action以檢視方式返回JSON資料
	 * @return
	 */
	public String testByJSP() {
		User user = new User();
		user.setId("123");
		user.setName("JSONActionJSP");
		user.setPassword("123");
		user.setSay("Hello world !");
		JSONObject jsonObject=new JSONObject();
		jsonObject.accumulate("user", user);
		jsonObject.accumulate("success", true);
		//這裡在request物件中放了一個data,所以struts的result配置中不能有type="redirect"
		ServletActionContext.getRequest().setAttribute("data", jsonObject.toString());
		return SUCCESS;
	};

	/**
	 * 測試通過action以Struts2預設方式返回JSON資料
	 * @return
	 */
	public String testByAction() {
		// dataMap中的資料將會被Struts2轉換成JSON字串,所以這裡要先清空其中的資料
		dataMap.clear();
		User user = new User();
		user.setId("123");
		user.setName("JSONActionStruts2");
		user.setPassword("123");
		user.setSay("Hello world !");
		dataMap.put("user", user);
		// 放入一個是否操作成功的標識
		dataMap.put("success", true);
		// 返回結果
		return SUCCESS;
	}

	/**
	 * 通過action是以傳統方式返回JSON資料
	 * @throws IOException
	 */
	public void doAction() throws IOException{
		HttpServletResponse response=ServletActionContext.getResponse();
		//以下程式碼從JSON.java中拷過來的
		response.setContentType("text/html");
		PrintWriter out;
		out = response.getWriter();
		//將要被返回到客戶端的物件
		User user=new User();
		user.setId("123");
		user.setName("JSONActionGeneral");
		user.setPassword("JSON");
		user.setSay("Hello , i am a action to print a json!");
		JSONObject json=new JSONObject();
		json.accumulate("success", true);
		json.accumulate("user", user);
		out.println(json.toString());
//		因為JSON資料在傳遞過程中是以普通字串形式傳遞的,所以我們也可以手動拼接符合JSON語法規範的字串輸出到客戶端
//		以下這兩句的作用與38-46行程式碼的作用是一樣的,將向客戶端返回一個User物件,和一個success欄位
//		String jsonString="{\"user\":{\"id\":\"123\",\"name\":\"JSONActionGeneral\",\"say\":\"Hello , i am a action to print a json!\",\"password\":\"JSON\"},\"success\":true}";
//		out.println(jsonString);
		out.flush();
		out.close();
	}
	
	/**
	 * Struts2序列化指定屬性時,必須有該屬性的getter方法,實際上,如果沒有屬性,而只有getter方法也是可以的
	 * @return
	 */
	public Map<String, Object> getDataMap() {
		return dataMap;
	}

}

完整的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>
	<package name="json" extends="json-default" namespace="/test">
		<action name="testByAction"
			class="cn.ysh.studio.struts2.json.demo.action.UserAction" method="testByAction">
			<result type="json">
				<!-- 這裡指定將被Struts2序列化的屬性,該屬性在action中必須有對應的getter方法 -->
				<!-- 預設將會序列所有有返回值的getter方法的值,而無論該方法是否有對應屬性 -->
				<param name="root">dataMap</param>
				<!-- 指定是否序列化空的屬性 -->
				<!--
				<param name="excludeNullProperties">true</param>
				-->
				<!-- 這裡指定將序列化dataMap中的那些屬性 -->
				<!-- 
				<param name="includeProperties">
     				userList.*
				</param>
				 -->
				<!-- 這裡指定將要從dataMap中排除那些屬性,這些排除的屬性將不被序列化,一半不與上邊的引數配置同時出現 -->
				<!-- 
				<param name="excludeProperties">
     				SUCCESS
				</param>
				-->
			</result>
		</action>
	</package>
	<package name="default" extends="struts-default" namespace="/">
		<action name="testJSONFromActionByGeneral"
			class="cn.ysh.studio.struts2.json.demo.action.UserAction" method="doAction">
		</action>
		<action name="testByJSP"
			class="cn.ysh.studio.struts2.json.demo.action.UserAction" method="testByJSP">
			<result name="success">/actionJSP.jsp</result>
		</action>
	</package>
</struts>