【SSH網上商城項目實戰02】基本增刪查改、Service和Action的抽取以及使用註解替換xml

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

上一節我們搭建好了Struts2、hibernatespring的開發環境,併成功將它們整合在一起。這節主要完成一些基本的增刪改查以及Service、Dao和Action的抽取。

1. Service層的抽取

        上一節中,我們在service層簡單寫了save和update方法,這裏我們開始完善該部分的代碼,然後對service層的代碼進行抽取。

1.1 完善CategoryService層

        對數據庫的操作無非是增刪改查,首先我們來完善CategoryService層的接口和實現:

  1. //CategoryService接口  
  2. public interface CategoryService extends BaseService<Category> {  
  3.       
  4.     public void save(Category category); //插入  
  5.   
  6.     public void update(Category category);//更新  
  7.       
  8.     public void delete(int id); //刪除  
  9.       
  10.     public Category get(int id); //獲取一個Category  
  11.       
  12.     public List<Category> query(); //獲取全部Category  
  13.   
  14. }  
//CategoryService接口
public interface CategoryService extends BaseService<Category> {
	
	public void save(Category category); //插入

	public void update(Category category);//更新
	
	public void delete(int id); //刪除
	
	public Category get(int id); //獲取一個Category
	
	public List<Category> query(); //獲取全部Category

}
        對CategoryService接口的具體實現:

  1. public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {  
  2.   
  3.     private SessionFactory sessionFactory;  
  4.       
  5.     //Spring會注進來  
  6.     public void setSessionFactory(SessionFactory sessionFactory) {  
  7.         this.sessionFactory = sessionFactory;  
  8.     }  
  9.       
  10.     protected Session getSession() {  
  11.         //從當前線程獲取session,如果沒有則創建一個新的session  
  12.         return sessionFactory.getCurrentSession();  
  13.     }  
  14.        
  15.     @Override   
  16.     public void save(Category category) {  
  17.         getSession().save(category);  
  18.     }  
  19.       
  20.     @Override   
  21.     public void update(Category category) {  
  22.         getSession().update(category);    
  23.     }  
  24.   
  25.     @Override  
  26.     public void delete(int id) {  
  27.         /*第一種方法有個弊端,就是沒刪除一次得先查詢一次 
  28.         Object obj = getSession().get(Category.class, id); 
  29.         if(obj != null) { 
  30.             getSession().delete(obj); 
  31.         }*/  
  32.         String hql = "delete Category while id=:id";  
  33.         getSession().createQuery(hql) //  
  34.                 .setInteger("id", id) //  
  35.                 .executeUpdate();  
  36.     }  
  37.   
  38.     @Override  
  39.     public Category get(int id) {  
  40.         return (Category) getSession().get(Category.class, id);  
  41.     }  
  42.   
  43.     @Override  
  44.     public List<Category> query() {  
  45.         String hql = "from Category";  
  46.         return getSession().createQuery(hql).list();  
  47.     }  
  48. }  
public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {

	private SessionFactory sessionFactory;
	
	//Spring會注進來
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	protected Session getSession() {
		//從當前線程獲取session,如果沒有則創建一個新的session
		return sessionFactory.getCurrentSession();
	}
	 
	@Override 
	public void save(Category category) {
		getSession().save(category);
	}
	
	@Override 
	public void update(Category category) {
		getSession().update(category);	
	}

	@Override
	public void delete(int id) {
		/*第一種方法有個弊端,就是沒刪除一次得先查詢一次
		Object obj = getSession().get(Category.class, id);
		if(obj != null) {
			getSession().delete(obj);
		}*/
		String hql = "delete Category while id=:id";
		getSession().createQuery(hql) //
				.setInteger("id", id) //
				.executeUpdate();
	}

	@Override
	public Category get(int id) {
		return (Category) getSession().get(Category.class, id);
	}

	@Override
	public List<Category> query() {
		String hql = "from Category";
		return getSession().createQuery(hql).list();
	}
}

1.2 Service層抽取實現

        完成了CategoryService後,我們來抽取Service層的基礎實現。思路是這樣的:我們抽取一個基礎接口BaseService以及基礎接口的實現BaseServiceImpl,後面開發的時候,如果需要新的Service,只需要做兩步即可:首先定義一個新的接口xxxService繼承BaseService接口,這個接口可以增加新的抽象方法;然後定義一個新的實現類xxxServiceImpl繼承BaseServiceImpl並實現xxxService接口即可。這樣更加便於項目的維護。

        我們先根據上面的CategoryService接口來創建BaseService接口:

  1. //基礎接口BaseService,使用泛型  
  2. public interface BaseService<T> {  
  3.     public void save(T t);  
  4.   
  5.     public void update(T t);  
  6.       
  7.     public void delete(int id);  
  8.       
  9.     public T get(int id);  
  10.       
  11.     public List<T> query();  
  12. }  
//基礎接口BaseService,使用泛型
public interface BaseService<T> {
	public void save(T t);

	public void update(T t);
	
	public void delete(int id);
	
	public T get(int id);
	
	public List<T> query();
}
        然後再根據CategoryServiceImpl實現類創建BaseService接口的實現類BaseServiceImpl:

  1. /** 
  2.  * @Description TODO(公共模塊的抽取) 
  3.  * @author eson_15 
  4.  * 
  5.  */  
  6. @SuppressWarnings("unchecked")  
  7. public class BaseServiceImpl<T> implements BaseService<T> {  
  8.   
  9.     private Class clazz; //clazz中存儲了當前操作的類型,即泛型T  
  10.     private SessionFactory sessionFactory;  
  11.       
  12.     public BaseServiceImpl() {  
  13.                 //下面三個打印信息可以去掉,這裏是給自己看的  
  14.                 System.out.println("this代表的是當前調用構造方法的對象" + this);  
  15.         System.out.println("獲取當前this對象的父類信息" + this.getClass().getSuperclass());  
  16.         System.out.println("獲取當前this對象的父類信息(包括泛型信息)" + this.getClass().getGenericSuperclass());  
  17.         //拿到泛型的參數類型  
  18.         ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();  
  19.         clazz = (Class)type.getActualTypeArguments()[0];  
  20.     }  
  21.       
  22.     public void setSessionFactory(SessionFactory sessionFactory) {  
  23.         this.sessionFactory = sessionFactory;  
  24.     }  
  25.       
  26.     protected Session getSession() {  
  27.         //從當前線程獲取session,如果沒有則創建一個新的session  
  28.         return sessionFactory.getCurrentSession();  
  29.     }  
  30.       
  31.     @Override  
  32.     public void save(T t) {  
  33.         getSession().save(t);  
  34.     }  
  35.   
  36.     @Override  
  37.     public void update(T t) {  
  38.         getSession().update(t);   
  39.     }  
  40.   
  41.     @Override  
  42.     public void delete(int id) {  
  43.         System.out.println(clazz.getSimpleName());  
  44.         String hql = "delete " + clazz.getSimpleName() + " as c where c.id=:id";  
  45.         getSession().createQuery(hql) //  
  46.                   .setInteger("id", id) //  
  47.                   .executeUpdate();  
  48.     }  
  49.   
  50.     @Override  
  51.     public T get(int id) {  
  52.         return (T) getSession().get(clazz, id);  
  53.     }  
  54.   
  55.     @Override  
  56.     public List<T> query() {  
  57.         String hql = "from " + clazz.getSimpleName();  
  58.         return getSession().createQuery(hql).list();  
  59.     }  
  60.   
  61. }  
/**
 * @Description TODO(公共模塊的抽取)
 * @author eson_15
 *
 */
@SuppressWarnings("unchecked")
public class BaseServiceImpl<T> implements BaseService<T> {

	private Class clazz; //clazz中存儲了當前操作的類型,即泛型T
	private SessionFactory sessionFactory;
	
	public BaseServiceImpl() {
                //下面三個打印信息可以去掉,這裏是給自己看的
                System.out.println("this代表的是當前調用構造方法的對象" + this);
		System.out.println("獲取當前this對象的父類信息" + this.getClass().getSuperclass());
		System.out.println("獲取當前this對象的父類信息(包括泛型信息)" + this.getClass().getGenericSuperclass());
		//拿到泛型的參數類型
		ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
		clazz = (Class)type.getActualTypeArguments()[0];
	}
	
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	protected Session getSession() {
		//從當前線程獲取session,如果沒有則創建一個新的session
		return sessionFactory.getCurrentSession();
	}
	
	@Override
	public void save(T t) {
		getSession().save(t);
	}

	@Override
	public void update(T t) {
		getSession().update(t);	
	}

	@Override
	public void delete(int id) {
		System.out.println(clazz.getSimpleName());
		String hql = "delete " + clazz.getSimpleName() + " as c where c.id=:id";
		getSession().createQuery(hql) //
				  .setInteger("id", id) //
				  .executeUpdate();
	}

	@Override
	public T get(int id) {
		return (T) getSession().get(clazz, id);
	}

	@Override
	public List<T> query() {
		String hql = "from " + clazz.getSimpleName();
		return getSession().createQuery(hql).list();
	}

}
        抽取完了後,我們就可以改寫CategoryService接口和CategoryServiceImpl實現類了。如下:

  1. //CategoryService接口繼承BaseService接口  
  2. public interface CategoryService extends BaseService<Category> {  
  3.     /* 
  4.         * 只要添加CategoryService本身需要的新的方法即可,公共方法已經在BaseService中了 
  5.         */  
  6. }  
  7.   
  8. /** 
  9.  * @Description TODO(模塊自身的業務邏輯) 
  10.  * @author eson_15 
  11.  * 
  12.  */  
  13. public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {  
  14.   
  15.     /* 
  16.      * 只需實現CategoryService接口中新增的方法即可,公共方法已經在BaseServiceImpl中實現了 
  17.      */  
  18. }  
//CategoryService接口繼承BaseService接口
public interface CategoryService extends BaseService<Category> {
	/*
        * 只要添加CategoryService本身需要的新的方法即可,公共方法已經在BaseService中了
        */
}

/**
 * @Description TODO(模塊自身的業務邏輯)
 * @author eson_15
 *
 */
public class CategoryServiceImpl extends BaseServiceImpl<Category> implements CategoryService {

    /*
     * 只需實現CategoryService接口中新增的方法即可,公共方法已經在BaseServiceImpl中實現了
     */
}
        從代碼中可以看出,新增的Service只需要繼承BaseService接口,然後在接口中新增本Service所需要的業務邏輯即可。新增的ServiceImpl只需要繼承BaseServiceImpl並實現新增的業務邏輯即可。
        但是別忘了很重要的一點:就是修改Spring的配置文件beans.xml中的bean

  1. <!-- 泛型類是不能實例化的,所以要加lazy-init屬性 -->  
  2. <bean id="baseService" class="cn.it.shop.service.impl.BaseServiceImpl" lazy-init="true">  
  3.      <property name="sessionFactory" ref="sessionFactory" />  
  4. </bean>  
  5.        
  6. <bean id="categoryService" class="cn.it.shop.service.impl.CategoryServiceImpl" parent="baseService"/>  
<!-- 泛型類是不能實例化的,所以要加lazy-init屬性 -->
<bean id="baseService" class="cn.it.shop.service.impl.BaseServiceImpl" lazy-init="true">
	 <property name="sessionFactory" ref="sessionFactory" />
</bean>
	 
<bean id="categoryService" class="cn.it.shop.service.impl.CategoryServiceImpl" parent="baseService"/>
        將原來categoryService中的property幹掉,然後增加parent屬性,指明繼承baseService;然後配置一下baseService,將sessionFactory配到baseService中去,另外要注意一點:設置lazy-init屬性爲true,因爲baseService是泛型類,泛型類是不能實例化的。至此,Service層的抽取就搞定了。

2. Service層添加一個Account

        剛剛抽取好了Service層,那麼現在我們想寫一個Account(管理員)的service就很簡單了:

        首先寫一個AccountService接口繼承BaseService:

  1. public interface AccountService extends BaseService<Account> { //注意BaseService裏的泛型現在是Account  
  2.     /* 
  3.      * 只要添加AccountService本身需要的新的方法即可,公共方法已經在BaseService中了 
  4.      */  
  5. }  
public interface AccountService extends BaseService<Account> { //注意BaseService裏的泛型現在是Account
	/*
	 * 只要添加AccountService本身需要的新的方法即可,公共方法已經在BaseService中了
	 */
}
        然後寫一個AccountServiceImpl實現類繼承BaseServiceImpl實現類,並實現AccountService接口即可:
  1. public class AccountServiceImpl extends BaseServiceImpl<Account> implements AccountService {  
  2.   
  3.     /* 
  4.      * 只需實現AccountService接口中新增的方法即可,公共方法已經在BaseServiceImpl中實現了 
  5.      */  
  6.       
  7.     //管理登陸功能,後期再完善  
  8. }  
public class AccountServiceImpl extends BaseServiceImpl<Account> implements AccountService {

	/*
	 * 只需實現AccountService接口中新增的方法即可,公共方法已經在BaseServiceImpl中實現了
	 */
	
	//管理登陸功能,後期再完善
}
        最後在beans.xml文件里加上如下配置:

  1. <bean id="accountService" class="cn.it.shop.service.impl.AccountServiceImpl" parent="baseService" />  
<bean id="accountService" class="cn.it.shop.service.impl.AccountServiceImpl" parent="baseService" />
        這樣就寫好了一個新的service了,以後需要添加service就遵循這個流程,非常方便。

3. Action的抽取

3.1 Action中往域(request,session,application等)中存數據

        我們知道,在Action中可以直接通過ActionContext.getContext()去獲取一個ActionContext對象,然後通過該對象再去獲得相應的域對象;也可以通過實現xxxAware接口來注入相應的域對象。我們先來看一下這兩種方法:

  1. public class CategoryAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{  
  2.       
  3.     private Category category;  
  4.   
  5.         private CategoryService categoryService;  
  6.       
  7.         public void setCategoryService(CategoryService categoryService) {  
  8.             this.categoryService = categoryService;  
  9.         }  
  10.   
  11.     public String update() {  
  12.         System.out.println("----update----");  
  13.         categoryService.update(category);  
  14.         return "index";  
  15.     }  
  16.       
  17.     public String save() {  
  18.         System.out.println("----save----");  
  19.         return "index";  
  20.     }  
  21.       
  22.     public String query() {  
  23.          //解決方案一,採用相應的map取代原來的內置對象,這樣與jsp沒有依賴,但是代碼量比較大  
  24.  //     ActionContext.getContext().put("categoryList", categoryService.query()); //放到request域中  
  25.  //     ActionContext.getContext().getSession().put("categoryList", categoryService.query()); //放到session域中  
  26.  //     ActionContext.getContext().getApplication().put("categoryList", categoryService.query()); //放到application域中  
  27.           
  28.         //解決方案二,實現相應的接口(RequestAware,SessionAware,ApplicationAware),讓相應的map注入  
  29.         request.put("categoryList", categoryService.query());   
  30.         session.put("categoryList", categoryService.query());   
  31.         application.put("categoryList", categoryService.query());   
  32.         return "index";  
  33.     }  
  34.   
  35.     public Category getCategory() {  
  36.         return category;  
  37.     }  
  38.   
  39.     public void setCategory(Category category) {  
  40.         this.category = category;  
  41.     }  
  42.       
  43.     private Map<String, Object> request;  
  44.     private Map<String, Object> session;  
  45.     private Map<String, Object> application;  
  46.   
  47.     @Override  
  48.     public void setApplication(Map<String, Object> application) {  
  49.         this.application = application;  
  50.     }  
  51.   
  52.     @Override  
  53.     public void setSession(Map<String, Object> session) {  
  54.         this.session = session;  
  55.     }  
  56.   
  57.     @Override  
  58.     public void setRequest(Map<String, Object> request) {  
  59.         this.request = request;  
  60.     }  
  61. }  
public class CategoryAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
	
	private Category category;

        private CategoryService categoryService;
    
        public void setCategoryService(CategoryService categoryService) {
            this.categoryService = categoryService;
        }

	public String update() {
		System.out.println("----update----");
		categoryService.update(category);
 		return "index";
 	}
	
	public String save() {
		System.out.println("----save----");
		return "index";
 	}
	
 	public String query() {
		 //解決方案一,採用相應的map取代原來的內置對象,這樣與jsp沒有依賴,但是代碼量比較大
 //		ActionContext.getContext().put("categoryList", categoryService.query()); //放到request域中
 //		ActionContext.getContext().getSession().put("categoryList", categoryService.query()); //放到session域中
 //		ActionContext.getContext().getApplication().put("categoryList", categoryService.query()); //放到application域中
		
		//解決方案二,實現相應的接口(RequestAware,SessionAware,ApplicationAware),讓相應的map注入
		request.put("categoryList", categoryService.query()); 
		session.put("categoryList", categoryService.query()); 
		application.put("categoryList", categoryService.query()); 
		return "index";
	}

	public Category getCategory() {
		return category;
	}

	public void setCategory(Category category) {
		this.category = category;
	}
	
	private Map<String, Object> request;
	private Map<String, Object> session;
	private 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;
	}
}
        還是上一節整合三大框架時的CategoryAction類,我們在裏面加了一個query方法,在該方法中,我們通過向request域、session域和application域中存入查詢的結果。第一種方法是直接使用ActionContext來實現,不需要實現任何接口,但是代碼量較大;第二種方法通過實現RequestAware、SessionAware和ApplicationAware接口,實現該接口的三個抽象方法把request、session和application注入進來,然後賦給相應的成員變量中,這樣就可以在query方法中向域中存放查詢結果了。這代碼量貌似比第一種方法更大……但是我們可以抽取,先往下看。
        我們在index.jsp中新加一個查詢連接來測試能否將查詢結果顯示出來:

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  4. <html>  
  5.   <head>  
  6.     <title>My JSP 'index.jsp' starting page</title>  
  7.   </head>  
  8.     
  9.   <body>  
  10.     <a href="${pageContext.request.contextPath }/category_update.action?category.id=2&category.type=gga&category.hot=false">訪問update</a>  
  11.     <a href="category_save.action">訪問save</a>  
  12.     <a href="category_query.action">查詢所有類別</a><br/>  
  13.     <c:forEach items="${requestScope.categoryList }" var="category">  
  14.         ${category.id } | ${category.type } | ${category.hot } <br/>  
  15.     </c:forEach>  
  16.       
  17.     <c:forEach items="${sessionScope.categoryList }" var="category">  
  18.         ${category.id } | ${category.type } | ${category.hot } <br/>  
  19.     </c:forEach>  
  20.       
  21.     <c:forEach items="${applicationScope.categoryList }" var="category">  
  22.         ${category.id } | ${category.type } | ${category.hot } <br/>  
  23.     </c:forEach>  
  24.   </body>  
  25. </html>  
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>
    <a href="${pageContext.request.contextPath }/category_update.action?category.id=2&category.type=gga&category.hot=false">訪問update</a>
    <a href="category_save.action">訪問save</a>
    <a href="category_query.action">查詢所有類別</a><br/>
    <c:forEach items="${requestScope.categoryList }" var="category">
    	${category.id } | ${category.type } | ${category.hot } <br/>
    </c:forEach>
    
    <c:forEach items="${sessionScope.categoryList }" var="category">
    	${category.id } | ${category.type } | ${category.hot } <br/>
    </c:forEach>
    
    <c:forEach items="${applicationScope.categoryList }" var="category">
    	${category.id } | ${category.type } | ${category.hot } <br/>
    </c:forEach>
  </body>
</html>

3.2 抽取BaseAction

        剛剛提到了,第二種方法的代碼量更大,但是我們可以抽取一個BaseAction,專門處理這些域相關的操作。

  1. public class BaseAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware {  
  2.   
  3.     protected Map<String, Object> request;  
  4.     protected Map<String, Object> session;  
  5.     protected Map<String, Object> application;  
  6.       
  7.     @Override  
  8.     public void setApplication(Map<String, Object> application) {  
  9.         this.application = application;  
  10.     }  
  11.   
  12.     @Override  
  13.     public void setSession(Map<String, Object> session) {  
  14.         this.session = session;  
  15.     }  
  16.   
  17.     @Override  
  18.     public void setRequest(Map<String, Object> request) {  
  19.         this.request = request;  
  20.     }  
  21. }  
public class BaseAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware {

	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;
	}
}
        然後我們自己的Action如果需要用到這些域對象來存儲數據時,直接繼承BaseAction即可,就能直接使用request、session和application對象了。所以修改後的CategoryAction如下:

  1. public class CategoryAction extends BaseAction {  
  2.       
  3.     private Category category;  
  4. <pre name="code" class="java">  
  5.         private CategoryService categoryService;  
  6.       
  7.         public void setCategoryService(CategoryService categoryService) {  
  8.             this.categoryService = categoryService;  
  9.         }  
public class CategoryAction extends BaseAction {
	
	private Category category;
<pre name="code" class="java">
        private CategoryService categoryService;
    
        public void setCategoryService(CategoryService categoryService) {
            this.categoryService = categoryService;
        }
public String update() {System.out.println("----update----");categoryService.update(category); return "index"; }public String save() {System.out.println("----save----");return "index"; } public String query() {request.put("categoryList", categoryService.query()); session.put("categoryList", categoryService.query()); application.put("categoryList", categoryService.query()); return "index"; } public Category getCategory() { return category; } public void setCategory(Category category) {this.category = category; }}


        後面所有要使用request、session和application域的Action,只要直接繼承BaseAction即可,非常方便。

3.3 獲取參數(ModelDriven)

        我們繼續看上面的CategoryAction類,裏面有個成員變量category,這是個POJO,定義這個變量並寫好set和get方法是爲了JSP頁面可以通過url後面附帶參數傳進來,參數是category對象中的屬性,比如id,type等,但是url中的參數必須寫成category.id、category.type等。這樣struts會自動將這寫參數注入到category對象中,然後我們就可以直接使用這個category對象了,但是這樣有點繁瑣。我們可以使用ModelDriven來更方便的解決。

  1. public class CategoryAction extends BaseAction implements ModelDriven<Category>{  
  2.       
  3.     private Category category;  
  4.       
  5.     //使用ModelDriven接口必須要實現getModel()方法,此方法會把返回的項壓到棧頂  
  6.     @Override  
  7.     public Category getModel() {  
  8.         category = new Category();  
  9.         return category;  
  10.     }  
  11. <pre name="code" class="java">        private CategoryService categoryService;  
  12.       
  13.         public void setCategoryService(CategoryService categoryService) {  
  14.             this.categoryService = categoryService;  
  15.         }  
  16.   
  17.     public String update() {  
  18.         System.out.println("----update----");  
  19.         categoryService.update(category);  
  20.         return "index";  
  21.     }  
  22.       
  23.     public String save() {  
  24.         System.out.println("----save----");  
  25.         return "index";  
  26.     }  
  27.       
  28.     public String query() {  
  29.         request.put("categoryList", categoryService.query());   
  30.         session.put("categoryList", categoryService.query());   
  31.         application.put("categoryList", categoryService.query());   
  32.         return "index";  
  33.     }  
  34.   
  35. }  
public class CategoryAction extends BaseAction implements ModelDriven<Category>{
	
	private Category category;
	
	//使用ModelDriven接口必須要實現getModel()方法,此方法會把返回的項壓到棧頂
	@Override
	public Category getModel() {
		category = new Category();
		return category;
	}
<pre name="code" class="java">        private CategoryService categoryService;
    
        public void setCategoryService(CategoryService categoryService) {
            this.categoryService = categoryService;
        }

	public String update() {
		System.out.println("----update----");
		categoryService.update(category);
 		return "index";
 	}
	
	public String save() {
		System.out.println("----save----");
		return "index";
	}
	
	public String query() {
		request.put("categoryList", categoryService.query()); 
		session.put("categoryList", categoryService.query()); 
		application.put("categoryList", categoryService.query()); 
		return "index";
	}

}


        這樣我們在前臺JSP頁面就不用帶category.id這種繁瑣的參數了,看JSP頁面中的ModelDriven部分:

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  4. <html>  
  5.   <head>  
  6.     <title>My JSP 'index.jsp' starting page</title>  
  7.   </head>  
  8.     
  9.   <body>  
  10.     <a href="${pageContext.request.contextPath }/category_update.action?category.id=2&category.type=gga&category.hot=false">訪問update</a>  
  11.     <a href="category_save.action?id=1&type=haha&hot=true">測試ModelDriven</a>  
  12.     <a href="category_query.action">查詢所有類別</a><br/>  
  13.     <c:forEach items="${requestScope.categoryList }" var="category">  
  14.         ${category.id } | ${category.type } | ${category.hot } <br/>  
  15.     </c:forEach>  
  16.       
  17.     <c:forEach items="${sessionScope.categoryList }" var="category">  
  18.         ${category.id } | ${category.type } | ${category.hot } <br/>  
  19.     </c:forEach>  
  20.       
  21.     <c:forEach items="${applicationScope.categoryList }" var="category">  
  22.         ${category.id } | ${category.type } | ${category.hot } <br/>  
  23.     </c:forEach>  
  24.   </body>  
  25. </html>  
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>
    <a href="${pageContext.request.contextPath }/category_update.action?category.id=2&category.type=gga&category.hot=false">訪問update</a>
    <a href="category_save.action?id=1&type=haha&hot=true">測試ModelDriven</a>
    <a href="category_query.action">查詢所有類別</a><br/>
    <c:forEach items="${requestScope.categoryList }" var="category">
    	${category.id } | ${category.type } | ${category.hot } <br/>
    </c:forEach>
    
    <c:forEach items="${sessionScope.categoryList }" var="category">
    	${category.id } | ${category.type } | ${category.hot } <br/>
    </c:forEach>
    
    <c:forEach items="${applicationScope.categoryList }" var="category">
    	${category.id } | ${category.type } | ${category.hot } <br/>
    </c:forEach>
  </body>
</html>

        測試結果是可以獲得catgory,並且將id,type和hot屬性全部賦值好。我們可以看出,通過實現ModelDriven接口,我們可以很方便的在url中攜帶參數,Action中只需要實現getModel方法,new一個要使用的對象返回即可。到這裏我們很容易想到,struts中肯定會有很多這種model需要獲取,所以這一塊我們也要抽取到BaseAction中去。

3.4 抽取ModelDriven到BaseAction

        首先我們在BaseAction中添加ModelDriven部分的代碼,如下:

  1. //因爲有很多不同的model都需要使用ModelDriven,所以這裏使用泛型  
  2. public class BaseAction<T> extends ActionSupport implements RequestAware,SessionAware,ApplicationAware,ModelDriven<T> {  
  3.   
  4.     protected Map<String, Object> request;  
  5.     protected Map<String, Object> session;  
  6.     protected Map<String, Object> application;  
  7.       
  8.     protected T model;  
  9.       
  10.     @Override  
  11.     public void setApplication(Map<String, Object> application) {  
  12.         this.application = application;  
  13.     }  
  14.   
  15.     @Override  
  16.     public void setSession(Map<String, Object> session) {  
  17.         this.session = session;  
  18.     }  
  19.   
  20.     @Override  
  21.     public void setRequest(Map<String, Object> request) {  
  22.         this.request = request;  
  23.     }  
  24.   
  25.     @Override  
  26.     public T getModel() { //這裏通過解析傳進來的T來new一個對應的instance  
  27.         ParameterizedType type = (ParameterizedType)this.getClass().getGenericSuperclass();  
  28.         Class clazz = (Class)type.getActualTypeArguments()[0];  
  29.         try {  
  30.             model = (T)clazz.newInstance();  
  31.         } catch (Exception e) {  
  32.             throw new RuntimeException(e);  
  33.         }     
  34.         return model;  
  35.     }  
  36. }  
//因爲有很多不同的model都需要使用ModelDriven,所以這裏使用泛型
public class BaseAction<T> extends ActionSupport implements RequestAware,SessionAware,ApplicationAware,ModelDriven<T> {

	protected Map<String, Object> request;
	protected Map<String, Object> session;
	protected Map<String, Object> application;
	
	protected T model;
	
	@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;
	}

	@Override
	public T getModel() { //這裏通過解析傳進來的T來new一個對應的instance
		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;
	}
}
抽取完了後,CategoryAction中的代碼會越來越少:

  1. //繼承BaseAction,並且加上泛型  
  2. public class CategoryAction extends BaseAction<Category> {  
  3.   
  4.     private CategoryService categoryService;  
  5.       
  6.     public void setCategoryService(CategoryService categoryService) {  
  7.         this.categoryService = categoryService;  
  8.     }  
  9.       
  10.     public String update() {  
  11.         System.out.println("----update----");  
  12.         categoryService.update(model);//直接使用model  
  13.         return "index";  
  14.     }  
  15.       
  16.     public String save() {  
  17.         System.out.println("----save----");  
  18.         System.out.println(model); //直接使用model  
  19.         return "index";  
  20.     }  
  21.       
  22.     public String query() {   
  23.         request.put("categoryList", categoryService.query());   
  24.         session.put("categoryList", categoryService.query());   
  25.         application.put("categoryList", categoryService.query());   
  26.         return "index";  
  27.     }  
  28.   
  29. }  
//繼承BaseAction,並且加上泛型
public class CategoryAction extends BaseAction<Category> {

	private CategoryService categoryService;
	
	public void setCategoryService(CategoryService categoryService) {
		this.categoryService = categoryService;
	}
	
	public String update() {
		System.out.println("----update----");
		categoryService.update(model);//直接使用model
		return "index";
	}
	
	public String save() {
		System.out.println("----save----");
		System.out.println(model); //直接使用model
		return "index";
	}
	
	public String query() {	
		request.put("categoryList", categoryService.query()); 
		session.put("categoryList", categoryService.query()); 
		application.put("categoryList", categoryService.query()); 
		return "index";
	}

}
        到這裏,還有一個看着不爽的地方,就是categoryService這個成員變量,它一直存在在CategoryAction裏,因爲CategoryAction中有用到categoryService對象中的方法,所以必須得創建這個對象,並且有set方法才能注入進來。這就導致一個弊端:如果很多Action都需要使用categoryService的話,那就必須在它們的Action裏創建這個對象和set方法,而且,如果一個Action中要使用好幾個不同的service對象,那就得全部創建,這樣就變得很冗雜。

3.5 抽取service到BaseAction

        針對上面的問題,我們將工程中所有的service對象都抽取到BaseAction中創建,這樣其他Action繼承BaseAction後,想用什麼service就直接拿來用即可:

  1. //我將BaseAction中的內容歸歸類了  
  2. public class BaseAction<T> extends ActionSupport implements RequestAware,SessionAware,ApplicationAware,ModelDriven<T> {  
  3.   
  4.     //service對象  
  5.     protected CategoryService categoryService;  
  6.     protected AccountService accountService;  
  7.       
  8.     public void setCategoryService(CategoryService categoryService) {  
  9.         this.categoryService = categoryService;  
  10.     }  
  11.     public void setAccountService(AccountService accountService) {  
  12.         this.accountService = accountService;  
  13.     }  
  14.   
  15.     //域對象  
  16.     protected Map<String, Object> request;  
  17.     protected Map<String, Object> session;  
  18.     protected Map<String, Object> application;  
  19.           
  20.     @Override  
  21.     public void setApplication(Map<String, Object> application) {  
  22.         this.application = application;  
  23.     }  
  24.     @Override  
  25.     public void setSession(Map<String, Object> session) {  
  26.         this.session = session;  
  27.     }  
  28.     @Override  
  29.     public void setRequest(Map<String, Object> request) {  
  30.         this.request = request;  
  31.     }  
  32.       
  33.     //ModelDriven  
  34.     protected T model;  
  35.     @Override  
  36.     public T getModel() {  
  37.         ParameterizedType type = (ParameterizedType)this.getClass().getGenericSuperclass();  
  38.         Class clazz = (Class)type.getActualTypeArguments()[0];  
  39.         try {  
  40.             model = (T)clazz.newInstance();  
  41.         } catch (Exception e) {  
  42.             throw new RuntimeException(e);  
  43.         }     
  44.         return model;  
  45.     }  
  46. }  
//我將BaseAction中的內容歸歸類了
public class BaseAction<T> extends ActionSupport implements RequestAware,SessionAware,ApplicationAware,ModelDriven<T> {

	//service對象
	protected CategoryService categoryService;
	protected AccountService accountService;
	
	public void setCategoryService(CategoryService categoryService) {
		this.categoryService = categoryService;
	}
	public void setAccountService(AccountService accountService) {
		this.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;
	}
}
        這樣CategoryAction中就更加清爽了:

  1. public class CategoryAction extends BaseAction<Category> {  
  2.       
  3.     public String update() {  
  4.         System.out.println("----update----");  
  5.         categoryService.update(model);  
  6.         return "index";  
  7.     }  
  8.       
  9.     public String save() {  
  10.         System.out.println("----save----");  
  11.         System.out.println(model);  
  12.         return "index";  
  13.     }  
  14.       
  15.     public String query() {  
  16.         request.put("categoryList", categoryService.query());   
  17.         session.put("categoryList", categoryService.query());   
  18.         application.put("categoryList", categoryService.query());   
  19.         return "index";  
  20.     }  
  21.   
  22. }  
public class CategoryAction extends BaseAction<Category> {
	
	public String update() {
		System.out.println("----update----");
		categoryService.update(model);
		return "index";
	}
	
	public String save() {
		System.out.println("----save----");
		System.out.println(model);
		return "index";
	}
	
	public String query() {
		request.put("categoryList", categoryService.query()); 
		session.put("categoryList", categoryService.query()); 
		application.put("categoryList", categoryService.query()); 
		return "index";
	}

}
        有人可能會問,BaseAction中注入了那麼多service對象的話不會冗餘麼?這是不會的,因爲就算不寫在BaseAction中,Spring容器也是會創建這個對象的,這點沒有關係,相反,service對象全放在BaseAction中更加便於其他Action的開發,而且BaseAction不需要配到struts.xml文件中,因爲根本就沒有哪個JSP會請求BaseAction,它只是讓其他Action來繼承用的。

        還有一點別忘了:那就是修改在beans.xml中的配置:

  1. <!-- 如果是prototype類型,默認是使用時創建,不是啓動時自動創建 -->  
  2. <bean id="baseAction" class="cn.it.shop.action.BaseAction" scope="prototype">  
  3.      <property name="categoryService" ref="categoryService"></property>  
  4.      <property name="accountService" ref="accountService"></property>  
  5. </bean>  
  6.        
  7. <bean id="categoryAction" class="cn.it.shop.action.CategoryAction" scope="prototype" parent="baseAction"/>  
<!-- 如果是prototype類型,默認是使用時創建,不是啓動時自動創建 -->
<bean id="baseAction" class="cn.it.shop.action.BaseAction" scope="prototype">
	 <property name="categoryService" ref="categoryService"></property>
	 <property name="accountService" ref="accountService"></property>
</bean>
	 
<bean id="categoryAction" class="cn.it.shop.action.CategoryAction" scope="prototype" parent="baseAction"/>
        新加一個baseAction的bean,將工程中所有service對象作爲property配好,將原來的categoryAction中的property幹掉。

        以後我們如果要寫新的xxxAction,直接繼承BaseAction即可,如果xxxAction中有用到某個service,直接拿來用即可,只需要在beans.xml文件中加一個xxxAction對應的bean,在struts.xml文件中配置好跳轉即可。

4. 將xml改成註解

        我們可以看到,隨着項目越寫越大,beans.xml中的配置會越來越多,而且很多配置有冗餘,爲了更加便於開發,我們現在將xml的配置改成註解的形式,我們先看一下beans.xml中的配置:


        這些是我們之前搭建環境以及抽取的時候寫的bean,這些都需要轉換成註解的形式,下面我們一塊一塊的換掉:首先替換service部分,這部分有三個:baseService、categoryService和accountService。替換如下:


        然後將beans.xml中的相應部分幹掉即可。接下來修改ActIon部分,主要有baseAction、categoryAction和accountAction三個,替換如下:


        然後再幹掉beans.xml中的Action部分的配置即可,最後在beans.xml文件中添加一個如下配置,就可以使用註解了。

  1. <context:component-scan base-package="cn.it.shop.."/>  
<context:component-scan base-package="cn.it.shop.."/>
        有人可能會問,爲什麼service和action兩個使用註解的時候不一樣呢?service中使用的是@Service而action中使用的是@Controller呢?其實是一樣的,只是爲了區分它們是不同層的bean而已,便於閱讀。



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

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

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