【SSH網上商城項目實戰07】Struts2和Json的整合

轉自:http://blog.csdn.net/eson_15/article/details/51332758

       上一節我們完成了DataGrid顯示jason數據,但是沒有和後臺聯繫在一起,只是單純地顯示了我們自己弄的json數據,這一節我們將json和Struts2整合,打通EasyUI和Struts2之間的交互。

1. json環境的搭建

        json環境搭建很簡單,導入json的jar包即可,如下:

        (注:json-lib-2.4的jar包下載地址:http://download.csdn.net/detail/eson_15/9514985

2. 完善Action

        在DataGrid控件中有個屬性是url,可以指定請求數據的url地址,在上一節我們將這個地址直接設置成了一個具體的json文件,這裏我們將這個url設置成一個action,如url:'category_queryJoinAccount.action',表示會去請求categoryAction的queryJoinAccount方法(文章最後會給出query.jsp的代碼)。所以我們需要去完成categoryAction中的queryJoinAccount方法。

        在Struts2和json整合前,我們先看一下之前顯示一次json數據都發了哪些請求:


        因爲type是Category類的一個屬性,我們在BaseAction中已經實現了ModelDriven<Category>接口,所以這個type會被封裝到model中,我們不需要管它,可以通過model來獲取,但是EasyUI自動發過來的page和rows參數我們需要自己獲取了,所以我們可以在BaseModel中增加兩個成員變量page和rows並實現get和set方法,最後還要考慮一點,這些參數都獲得了後,我們根據這些參數去數據庫中查詢數據,那麼我們查出來的數據放到哪呢?而且還要打包成json格式發到前臺才能被DataGrid顯示。我們先不考慮將查詢到的數據如何打包成json格式,我們先考慮把這些數據放到一個地方,很自然的想到了使用Map,因爲json格式的數據就是key-value形式的。想到這裏,我們繼續完善BaseAction:

  1. @Controller("baseAction")  
  2. @Scope("prototype")  
  3. public class BaseAction<T> extends ActionSupport implements RequestAware,SessionAware,ApplicationAware,ModelDriven<T> {  
  4.   
  5.     //page和rows和分頁有關,pageMap存放查詢的數據,然後打包成json格式用的  
  6.     //page和rows實現get和set方法,pageMap只需要實現get方法即可,因爲pageMap不是接收前臺參數的,是讓struts獲取的  
  7.     protected Integer page;  
  8.     protected Integer rows;  
  9.     protected Map<String, Object> pageMap = null;//讓不同的Action自己去實現  
  10.         //省略get和set方法……  
  11.       
  12.     /******************* 下面還是原來BaseAction部分 *************************/  
  13.     //service對象  
  14.     @Resource  
  15.     protected CategoryService categoryService;  
  16.     @Resource  
  17.     protected AccountService accountService;  
  18.   
  19.     //域對象  
  20.     protected Map<String, Object> request;  
  21.     protected Map<String, Object> session;  
  22.     protected Map<String, Object> application;  
  23.           
  24.     @Override  
  25.     public void setApplication(Map<String, Object> application) {  
  26.         this.application = application;  
  27.     }  
  28.     @Override  
  29.     public void setSession(Map<String, Object> session) {  
  30.         this.session = session;  
  31.     }  
  32.     @Override  
  33.     public void setRequest(Map<String, Object> request) {  
  34.         this.request = request;  
  35.     }  
  36.       
  37.     //ModelDriven  
  38.     protected T model;  
  39.     @Override  
  40.     public T getModel() {  
  41.         ParameterizedType type = (ParameterizedType)this.getClass().getGenericSuperclass();  
  42.         Class clazz = (Class)type.getActualTypeArguments()[0];  
  43.         try {  
  44.             model = (T)clazz.newInstance();  
  45.         } catch (Exception e) {  
  46.             throw new RuntimeException(e);  
  47.         }     
  48.         return model;  
  49.     }  
  50. }  
@Controller("baseAction")
@Scope("prototype")
public class BaseAction<T> extends ActionSupport implements RequestAware,SessionAware,ApplicationAware,ModelDriven<T> {

	//page和rows和分頁有關,pageMap存放查詢的數據,然後打包成json格式用的
	//page和rows實現get和set方法,pageMap只需要實現get方法即可,因爲pageMap不是接收前臺參數的,是讓struts獲取的
	protected Integer page;
	protected Integer rows;
	protected Map<String, Object> pageMap = null;//讓不同的Action自己去實現
        //省略get和set方法……
	
	/******************* 下面還是原來BaseAction部分 *************************/
	//service對象
	@Resource
	protected CategoryService categoryService;
	@Resource
	protected AccountService accountService;

	//域對象
	protected Map<String, Object> request;
	protected Map<String, Object> session;
	protected Map<String, Object> application;
		
	@Override
	public void setApplication(Map<String, Object> application) {
		this.application = application;
	}
	@Override
	public void setSession(Map<String, Object> session) {
		this.session = session;
	}
	@Override
	public void setRequest(Map<String, Object> request) {
		this.request = request;
	}
	
	//ModelDriven
	protected T model;
	@Override
	public T getModel() {
		ParameterizedType type = (ParameterizedType)this.getClass().getGenericSuperclass();
		Class clazz = (Class)type.getActualTypeArguments()[0];
		try {
			model = (T)clazz.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}	
		return model;
	}
}
        好,完善了BaseCategory後,我們可以寫categoryAction中的queryJoinAccount方法了,我們將categoryAction中原來的方法全刪掉,因爲那些都是之前搭建環境時候測試用的,都不用了,現在真正開始項目代碼了:

  1. @Controller("categoryAction")  
  2. @Scope("prototype")  
  3. public class CategoryAction extends BaseAction<Category> {  
  4.       
  5.     public String queryJoinAccount() {  
  6.   
  7.         //用來存儲分頁的數據  
  8.         pageMap = new HashMap<String, Object>();  
  9.           
  10.         //根據關鍵字和分頁的參數查詢相應的數據。這個方法我們在Service中寫過了,當時完成級聯查詢  
  11.         List<Category> categoryList = categoryService.queryJoinAccount(model.getType(), page, rows);  
  12.         pageMap.put("rows", categoryList); //存儲爲JSON格式,從上一節的json文件可以看出,一個key是total,一個key是rows,這裏先把rows存放好  
  13.         //根據關鍵字查詢總記錄數  
  14.         Long total = categoryService.getCount(model.getType()); //這個方法沒寫,我們等會兒去Service層完善一下  
  15. //      System.out.println(total);  
  16.         pageMap.put("total", total); //存儲爲JSON格式,再把total存放好  
  17.   
  18.         return "jsonMap";  
  19.     }  
  20. }  
@Controller("categoryAction")
@Scope("prototype")
public class CategoryAction extends BaseAction<Category> {
	
	public String queryJoinAccount() {

		//用來存儲分頁的數據
		pageMap = new HashMap<String, Object>();
		
		//根據關鍵字和分頁的參數查詢相應的數據。這個方法我們在Service中寫過了,當時完成級聯查詢
		List<Category> categoryList = categoryService.queryJoinAccount(model.getType(), page, rows);
		pageMap.put("rows", categoryList); //存儲爲JSON格式,從上一節的json文件可以看出,一個key是total,一個key是rows,這裏先把rows存放好
		//根據關鍵字查詢總記錄數
		Long total = categoryService.getCount(model.getType()); //這個方法沒寫,我們等會兒去Service層完善一下
//		System.out.println(total);
		pageMap.put("total", total); //存儲爲JSON格式,再把total存放好

		return "jsonMap";
	}
}
        這樣Action我們就寫好了,現在Action拿到前臺傳來的參數,然後根據參數查詢了指定type的總記錄數,以及指定type的所有商品,並且按照json中指定的key(即total和rows)進行存放,放在HashMap中了,之後只要將這個HashMap中的數據打包成json格式發送到前臺就可以被DataGrid顯示了。我們先把這個HashMap放這,先去完善了Service層的代碼後,再來打包這個HashMap中的數據。

3. 完善categoryService

        從上面的categoryAction中可知,需要在categoryService中增加一個getCount方法,並且要在具體實現類中實現好,實現如下:

  1. //CategoryService接口  
  2. public interface CategoryService extends BaseService<Category> {  
  3.     //查詢類別信息,級聯管理員  
  4.     public List<Category> queryJoinAccount(String type, int page, int size); //使用類別的名稱查詢  
  5.     //根據關鍵字查詢總記錄數  
  6.     public Long getCount(String type);  
  7. }  
  8.   
  9. //CategoryServiceImpl實現類  
  10. @SuppressWarnings("unchecked")  
  11. @Service("categoryService")  
  12. public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {  
  13.   
  14.     @Override  
  15.     public List<Category> queryJoinAccount(String type, int page, int size) {  
  16.         String hql = "from Category c left join fetch c.account where c.type like :type";  
  17.         return getSession().createQuery(hql)  
  18.                 .setString("type""%" + type + "%")  
  19.                 .setFirstResult((page-1) * size) //從第幾個開始顯示  
  20.                 .setMaxResults(size) //顯示幾個  
  21.                 .list();  
  22.     }  
  23.   
  24.     @Override  
  25.     public Long getCount(String type) {  
  26.         String hql = "select count(c) from Category c where c.type like :type";  
  27.         return (Long) getSession().createQuery(hql)  
  28.             .setString("type""%" + type + "%")  
  29.             .uniqueResult(); //返回一條記錄:總記錄數  
  30.     }  
  31. }  
//CategoryService接口
public interface CategoryService extends BaseService<Category> {
	//查詢類別信息,級聯管理員
	public List<Category> queryJoinAccount(String type, int page, int size); //使用類別的名稱查詢
	//根據關鍵字查詢總記錄數
	public Long getCount(String type);
}

//CategoryServiceImpl實現類
@SuppressWarnings("unchecked")
@Service("categoryService")
public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {

    @Override
    public List<Category> queryJoinAccount(String type, int page, int size) {
        String hql = "from Category c left join fetch c.account where c.type like :type";
        return getSession().createQuery(hql)
                .setString("type", "%" + type + "%")
                .setFirstResult((page-1) * size) //從第幾個開始顯示
                .setMaxResults(size) //顯示幾個
                .list();
    }

    @Override
    public Long getCount(String type) {
        String hql = "select count(c) from Category c where c.type like :type";
        return (Long) getSession().createQuery(hql)
            .setString("type", "%" + type + "%")
            .uniqueResult(); //返回一條記錄:總記錄數
    }
}
        到現在爲止,這個數據庫中數據的獲取這條路就打通了,前面兩步完成了從前臺-->數據庫-->取數據,接下來就開始打包HashMap中存放的數據,然後發給前臺了。

4. 配置struts.xml

        在struts.xml中通過配置就可以完成對指定數據的打包,我們先看一下struts.xml中的配置:

  1. <struts>  
  2.       
  3.     <constant name="struts.devMode" value="true" />  
  4.       
  5.     <package name="shop" extends="json-default"><!-- jason-default繼承了struts-default -->  
  6.       
  7.         <global-results>  
  8.             <result name="aindex">/WEB-INF/main/aindex.jsp</result>  
  9.         </global-results>  
  10.   
  11.         <!-- class對應的是Spring中配置該Action的id值,因爲要交給Spring管理 -->  
  12.         <action name="category_*" class="categoryAction" method="{1}">  
  13.             <!-- 必須要先添加json包,然後上面繼承json-default -->  
  14.             <result name="jsonMap" type="json">  
  15.                 <!-- 要轉換成json對象的數據 -->  
  16.                 <param name="root">pageMap</param>  
  17.                 <!-- 配置黑名單,過濾不需要的選項 ,支持正則表達式  
  18.                 json格式:{total:3,rows:[{account:{id:2,login:"user",name:"客服A",pass:"user"},hot:true,id:3,…}]}  
  19.                 -->  
  20.                 <param name="excludeProperties">  
  21.                     <!-- rows[0].account.pass-->  
  22.                                         <!-- 這裏顯示不了正則表達式, CSDN的一個bug,我接個圖放下面 -->  
  23.                 </param>  
  24.             </result>  
  25.         </action>  
  26.           
  27.         <action name="account_*" class="accountAction" method="{1}">  
  28.             <result name="index">/index.jsp</result>  
  29.         </action>  
  30.           
  31.         <!-- 用來完成系統 請求轉發的action,所有的請求都交給execute-->  
  32.         <action name="send_*_*" class="sendAction">  
  33.             <result name="send">/WEB-INF/{1}/{2}.jsp</result>  
  34.         </action>  
  35.     </package>  
  36.   
  37. </struts>  
<struts>
	
	<constant name="struts.devMode" value="true" />
	
	<package name="shop" extends="json-default"><!-- jason-default繼承了struts-default -->
	
		<global-results>
			<result name="aindex">/WEB-INF/main/aindex.jsp</result>
		</global-results>

		<!-- class對應的是Spring中配置該Action的id值,因爲要交給Spring管理 -->
		<action name="category_*" class="categoryAction" method="{1}">
			<!-- 必須要先添加json包,然後上面繼承json-default -->
			<result name="jsonMap" type="json">
				<!-- 要轉換成json對象的數據 -->
				<param name="root">pageMap</param>
				<!-- 配置黑名單,過濾不需要的選項 ,支持正則表達式
				json格式:{total:3,rows:[{account:{id:2,login:"user",name:"客服A",pass:"user"},hot:true,id:3,…}]}
				-->
				<param name="excludeProperties">
					<!-- rows[0].account.pass-->
                                        <!-- 這裏顯示不了正則表達式, CSDN的一個bug,我接個圖放下面 -->
 				</param>
 			</result>
		</action>
		
		<action name="account_*" class="accountAction" method="{1}">
			<result name="index">/index.jsp</result>
		</action>
		
		<!-- 用來完成系統 請求轉發的action,所有的請求都交給execute-->
		<action name="send_*_*" class="sendAction">
			<result name="send">/WEB-INF/{1}/{2}.jsp</result>
		</action>
	</package>

</struts>


        從上面的配置可以看出,首先package要繼承json-default,因爲json-default繼承了struts-default,因爲在json的jar包裏有個struts2-json-plugin-2.3.24.1.jar,打開即可看到裏面有個struts-plugin.xml,打開即可看到json-default是繼承了struts-default:


        接下來我配置<result>,name是剛剛action返回的字符串,type一定要配成json。然後就是result中的參數了,首先必須要配的就是name爲root的參數,這個參數要配成剛剛需要轉換的HashMap對象,即我們定義的pageMap,有了這個參數的配置,struts纔會將pageMap中的數據打包成json格式。然後就是配置黑名單,黑名單的意思就是告訴struts在打包的時候,哪些字段不需要打包,比如管理員密碼之類的信息,由上面註釋中的jason格式可以看出rows[0].account.pass表示密碼字段,但是數據肯定不止一條,所以我們得用正則表達式來表示,這樣所有密碼都不會被打包到json中。

5. 修改query.jsp內容

             到此,我們已經將數據打包成了json格式了,接下來我們完善一下前臺query.jsp的內容就可以讓DataGrid正確顯示了:

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  3. <html>  
  4.   <head>  
  5.     <%@ include file="/public/head.jspf" %>  
  6.     <script type="text/javascript">  
  7.         $(function(){  
  8.             $('#dg').datagrid({     
  9.                 //url地址改爲請求categoryAction  
  10.                 url:'category_queryJoinAccount.action',  
  11.                 loadMsg:'Loading......',  
  12.                 queryParams:{type:''},//type參數,這裏不需要傳具體的type,因爲我們要顯示所有的  
  13.                 //width:300,  
  14.                 fitColumns:true,  
  15.                 striped:true,  
  16.                 nowrap:true,  
  17.                 singleSelect:true,  
  18.                 pagination:true,  
  19.                 rowStyler: function(index,row){  
  20.                     console.info("index" + index + "," + row)  
  21.                     if(index % 2 == 0) {  
  22.                         return 'background-color:#fff;';  
  23.                     } else {  
  24.                         return 'background-color:#ff0;';  
  25.                     }  
  26.                       
  27.                 },        
  28.                 frozenColumns:[[  
  29.                     {field:'checkbox',checkbox:true},  
  30.                     {field:'id',title:'編號',width:200}    //這裏的field字段要和json數據中的一樣               
  31.                 ]],  
  32.                 columns:[[                       
  33.                     {field:'type',title:'類別名稱',width:100, //字段type  
  34.                         formatter: function(value,row,index){  
  35.                             return "<span title=" + value + ">" + value + "</span>";  
  36.                         }  
  37.                     },      
  38.                     {field:'hot',title:'熱賣',width:100,  //字段hot  
  39.                         formatter: function(value,row,index){  
  40.                             if(value) { //如果是hot,該值爲true,value是boolean型變量  
  41.                                 return "<input type='checkbox' checked='checked' disabled='true'"//勾選  
  42.                             } else {  
  43.                                 return "<input type='checkbox' disable='true'"//不勾選  
  44.                             }  
  45.                         }  
  46.                     },  
  47.                     {field:'account.login',title:'所屬管理員',width:200, //account.login管理員登錄名  
  48.                         formatter: function(value,row,index){  
  49.                             if(row.account != null && row.account.login != null) {  
  50.                                 return row.account.login; //如果登錄名不爲空,顯示登錄名  
  51.                             } else {  
  52.                                 return "此類別沒有管理員";  
  53.                             }  
  54.                     }     
  55.                     }  
  56.                 ]]      
  57.             });   
  58.         });  
  59.     </script>  
  60.   </head>  
  61.     
  62.   <body>  
  63.     <table id="dg"></table>  
  64.   </body>  
  65. </html>  
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
	<%@ include file="/public/head.jspf" %>
	<script type="text/javascript">
		$(function(){
			$('#dg').datagrid({   
			    //url地址改爲請求categoryAction
			    url:'category_queryJoinAccount.action',
			    loadMsg:'Loading......',
			    queryParams:{type:''},//type參數,這裏不需要傳具體的type,因爲我們要顯示所有的
			    //width:300,
			    fitColumns:true,
			    striped:true,
			    nowrap:true,
			    singleSelect:true,
			    pagination:true,
			    rowStyler: function(index,row){
			    	console.info("index" + index + "," + row)
			    	if(index % 2 == 0) {
			    		return 'background-color:#fff;';
			    	} else {
			    		return 'background-color:#ff0;';
			    	}
			    	
			    },		
			    frozenColumns:[[
			        {field:'checkbox',checkbox:true},
					{field:'id',title:'編號',width:200}    //這裏的field字段要和json數據中的一樣             
			    ]],
			    columns:[[    		           
			        {field:'type',title:'類別名稱',width:100, //字段type
			        	formatter: function(value,row,index){
							return "<span title=" + value + ">" + value + "</span>";
						}
					},    
			        {field:'hot',title:'熱賣',width:100,  //字段hot
						formatter: function(value,row,index){
							if(value) { //如果是hot,該值爲true,value是boolean型變量
								return "<input type='checkbox' checked='checked' disabled='true'"; //勾選
							} else {
								return "<input type='checkbox' disable='true'"; //不勾選
							}
						}
			        },
			        {field:'account.login',title:'所屬管理員',width:200, //account.login管理員登錄名
			        	formatter: function(value,row,index){
			        		if(row.account != null && row.account.login != null) {
			        			return row.account.login; //如果登錄名不爲空,顯示登錄名
			        		} else {
			        			return "此類別沒有管理員";
			        		}
					}	
			        }
			    ]]    
			}); 
		});
	</script>
  </head>
  
  <body>
  	<table id="dg"></table>
  </body>
</html>

6.  測試顯示結果

        最後我們測試一下DataGrid的顯示結果,如下:

        到這裏,我們成功整合了Struts2和json,現在可以和前臺傳輸json格式的數據了。


       相關閱讀:http://blog.csdn.net/column/details/str2hiberspring.html

        整個項目的源碼下載地址:http://blog.csdn.net/eson_15/article/details/51479994

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章