1. 程式人生 > >SSH學習02 【SSH網上商城專案實戰02】基本增刪查改、Service和Action的抽取以及使用註解替換xml

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

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

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

上一節我們搭建好了Struts2、Hibernate和Spring的開發環境,併成功將它們整合在一起。這節主要完成一些基本的增刪改查以及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介面的具體實現:

複製程式碼
 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 }
複製程式碼

 

 

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 }
複製程式碼

 

        然後再根據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 }
複製程式碼

 

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

 

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

 

        從程式碼中可以看出,新增的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"/>

 

        將原來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 }
 6         然後寫一個AccountServiceImpl實現類繼承BaseServiceImpl實現類,並實現AccountService介面即可:
 7 
 8  
 9 
10 public class AccountServiceImpl extends BaseServiceImpl<Account> implements AccountService {
11 
12 /*
13 * 只需實現AccountService介面中新增的方法即可,公共方法已經在BaseServiceImpl中實現了
14 */
15 
16 //管理登陸功能,後期再完善
17 }
複製程式碼

 

      

  最後在beans.xml檔案里加上如下配置:

 

<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 }
複製程式碼

 

        還是上一節整合三大框架時的CategoryAction類,我們在裡面加了一個query方法,在該方法中,我們通過向request域、session域和application域中存入查詢的結果。第一種方法是直接使用ActionContext來實現,不需要實現任何介面,但是程式碼量較大;第二種方法通過實現RequestAware、SessionAware和ApplicationAware介面,實現該介面的三個抽象方法把request、session和application注入進來,然後賦給相應的成員變數中,這樣就可以在query方法中向域中存放查詢結果了。這程式碼量貌似比第一種方法更大……但是我們可以抽取,先往下看。
        我們在index.jsp中新加一個查詢連線來測試能否將查詢結果顯示出來:

 

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

 

        然後我們自己的Action如果需要用到這些域物件來儲存資料時,直接繼承BaseAction即可,就能直接使用request、session和application物件了。所以修改後的CategoryAction如下:

 

複製程式碼
 1  
 2 
 3 public class CategoryAction extends BaseAction {
 4 
 5 private Category category;
 6 <pre name="code" class="java">
 7     private CategoryService categoryService;
 8     
 9      public void setCategoryService(CategoryService categoryService) {
10          this.categoryService = categoryService;
11      }
12 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; }}
13 
14  
複製程式碼

 

 
        後面所有要使用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 }
36  
37 
38 
39  
複製程式碼

 

        這樣我們在前臺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>
複製程式碼

 

        測試結果是可以獲得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 }
複製程式碼

 

抽取完了後,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 }
複製程式碼

 

        到這裡,還有一個看著不爽的地方,就是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 }
複製程式碼

 

        這樣CategoryAction中就更加清爽了:

 

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

 

        有人可能會問,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"/>
複製程式碼

 

        新加一個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檔案中新增一個如下配置,就可以使用註解了。

<context:component-scan base-package="cn.it.shop.."/>

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

上一節我們搭建好了Struts2、Hibernate和Spring的開發環境,併成功將它們整合在一起。這節主要完成一些基本的增刪改查以及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介面的具體實現:

複製程式碼
 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 }
複製程式碼

 

 

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 }
複製程式碼

 

        然後再根據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 }
複製程式碼

 

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

 

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

 

        從程式碼中可以看出,新增的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"/>

 

        將原來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 }
 6         然後寫一個AccountServiceImpl實現類繼承BaseServiceImpl實現類,並實現AccountService介面即可:
 7 
 8  
 9 
10 public class AccountServiceImpl extends BaseServiceImpl<Account> implements AccountService {
11 
12 /*
13 * 只需實現AccountService介面中新增的方法即可,公共方法已經在BaseServiceImpl中實現了
14 */
15 
16 //管理登陸功能,後期再完善
17 }
複製程式碼

 

      

  最後在beans.xml檔案里加上如下配置:

 

<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 }
複製程式碼

 

        還是上一節整合三大框架時的CategoryAction類,我們在裡面加了一個query方法,在該方法中,我們通過向request域、session域和application域中存入查詢的結果。第一種方法是直接使用ActionContext來實現,不需要實現任何介面,但是程式碼量較大;第二種方法通過實現RequestAware、SessionAware和ApplicationAware介面,實現該介面的三個抽象方法把request、session和application注入進來,然後賦給相應的成員變數中,這樣就可以在query方法中向域中存放查詢結果了。這程式碼量貌似比第一種方法更大……但是我們可以抽取,先往下看。
        我們在index.jsp中新加一個查詢連線來測試能否將查詢結果顯示出來:

 

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

 

        然後我們自己的Action如果需要用到這些域物件來儲存資料時,直接繼承BaseAction即可,就能直接使用request、session和application物件了。所以修改後的CategoryAction如下:

 

複製程式碼
 1  
 2 
 3 public class CategoryAction extends BaseAction {
 4 
 5 private Category category;
 6 <pre name="code" class="java">
 7     private CategoryService categoryService;
 8     
 9      public void setCategoryService(CategoryService categoryService) {
10          this.categoryService = categoryService;
11      }
12 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; }}
13 
14  
複製程式碼

 

 
        後面所有要使用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 }
36  
37 
38 
39  
複製程式碼

 

        這樣我們在前臺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>
複製程式碼

 

        測試結果是可以獲得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 }
複製程式碼

 

抽取完了後,CategoryAction中的程式碼會越來越少:

 

相關推薦

SSH學習02 SSH網上商城專案實戰02基本增刪ServiceAction抽取以及使用註解替換xml

【SSH網上商城專案實戰02】基本增刪查改、Service和Action的抽取以及使用註解替換xml 轉自:https://blog.csdn.net/eson_15/article/details/51297698 上一節我們搭建好了Struts2、Hibernate和Spring的開

SSH網上商城專案實戰05完成資料庫的級聯查詢分頁

  轉自:https://blog.csdn.net/eson_15/article/details/51320212 上一節我們完成了EasyUI選單的實現。這一節我們主要來寫一下CategoryServiceImpl實現類,完成資料庫的級聯查詢。一般專案從後往前做,先做se

SSH網上商城專案實戰08查詢刪除商品類別功能的實現

  轉自:https://blog.csdn.net/eson_15/article/details/51338991 上一節我們完成了使用DataGrid顯示所有商品資訊,這節我們開始新增幾個功能:新增、更新、刪除和查詢。首先我們實現下前臺的顯示,然後再做後臺獲取資料。

SSH網上商城專案實戰07Struts2Json的整合

    轉自:https://blog.csdn.net/eson_15/article/details/51332758   上一節我們完成了DataGrid顯示jason資料,但是沒有和後臺聯絡在一起,只是單純地顯示了我們自己弄的json資

SSH網上商城專案實戰06基於DataGrid的資料顯示

  轉自:https://blog.csdn.net/eson_15/article/details/51322262 1. 回顧一下第4節內容         在第4節中,我們使用Eas

SSH網上商城專案實戰11查詢刪除商品功能的實現

  轉自:https://blog.csdn.net/eson_15/article/details/51360804   在第8節我們完成了查詢和刪除商品類別的功能,那麼現在實現查詢和刪除商品的功能就很好做了,原理和第8節一模一樣,只是修改一些引數,比如請求不同的a

SSH網上商城專案實戰10商品類基本模組的搭建

      前面我們完成了與商品類別相關的業務邏輯,接下來我們開始做具體商品部分。 1. 資料庫建表並對映Model         首先我們在資料庫中新建一張表,然後使用逆

SSH網上商城專案實戰17購物車基本功能的實現

  轉自:https://blog.csdn.net/eson_15/article/details/51418350 上一節我們將商品的詳細頁面做完了,並使用了Hibernate的二級快取載入詳細頁面來提高系統的效能。這節我們開始做購物車部分。 1. 新增新的表

SSH網上商城專案實戰16Hibernate的二級快取處理首頁的熱門顯示

    轉自:https://blog.csdn.net/eson_15/article/details/51405911   網上商城首頁都有熱門商品,那麼這些商品的點選率是很高的,當用戶點選某個熱門商品後需要進入商品的詳細資訊頁面,就像淘寶裡面

SSH網上商城專案實戰15執行緒定時器同步首頁資料(類似於部落格定期更新排名)

  轉自:https://blog.csdn.net/eson_15/article/details/51387378   上一節我們做完了首頁UI介面,但是有個問題:如果我在後臺添加了一個商品,那麼我必須重啟一下伺服器才能重新同步後臺資料,然後重新整理首頁才能同步資

SSH網上商城專案實戰14商城首頁UI的設計

  轉自:https://blog.csdn.net/eson_15/article/details/51373403 前面我們利用EasyUI和SSH搭建好了後臺的基本框架,做好了後臺的基本功能,包括對商品類別的管理和商品的管理等,這一節我們開始搭建前臺頁面。 做首頁的思

SSH網上商城專案實戰13Struts2實現檔案上傳功能

  轉自:https://blog.csdn.net/eson_15/article/details/51366384 上一節我們做完了新增和更新商品的功能,這兩個部分裡有涉及到商品圖片的上傳,並沒有詳細解說。為此,這篇文章詳細介紹一下Struts2實現檔案上傳的功能。 1

SSH網上商城專案實戰12新增更新商品功能的實現

  新增商品部分原理和新增商品類別是一樣的,不過要比商品類別複雜,因為商品的屬性有很多,對應的資料庫中的欄位也就多了,新增商品還有個選項是上傳圖片,這一小塊內容會在下一篇部落格中單獨說明,因為這涉及到一個知識點,就是Struts2實現檔案上傳功能。其他廢話不多說了,現在開始完善新增

SSH網上商城專案實戰18過濾器實現購物登入功能的判斷

    轉自:https://blog.csdn.net/eson_15/article/details/51425010     上一節我們做完了購物車的基本操作,但是有個問題是:當用戶點選結算

SSH網上商城專案實戰21從Demo中看易寶支付的流程

        這一節我們先寫一個簡單點的Demo來測試易寶支付的流程,熟悉這個流程後,再做實際的開發,因為是一個Demo,所以我沒有考慮一些設計模

SSH網上商城專案實戰23完成線上支付功能

    轉自: https://blog.csdn.net/eson_15/article/details/51464415  上一節我們做好了支付頁面的顯示,從上一節支付頁面顯示的jsp程式碼中可以看出,當用戶點選

SSH網上商城專案實戰25使用java email給使用者傳送郵件

      當用戶購買完商品後,我們應該向使用者傳送一封郵件,告訴他訂單已生成之類的資訊,郵箱地址是從使用者的基本資訊中獲取,好了,首先我們來看一下java中傳送郵件的方法。

SSH網上商城專案實戰24Struts2中如何處理多個Model請求

    1. 問題的提出   Struts2中如果實現了ModelDriven<model>介面

SSH網上商城專案實戰26完成訂單支付後的簡訊傳送功能

    上一節我們使用了Java mail完成了給買家傳送郵件的功能,還遺留一個功能,就是給買家傳送簡訊,告訴他訂單已經生成之類的。這一節主要介紹一下如何在使用者支付完成後自動給使用者傳送簡訊。

SSH網上商城專案實戰30專案總結(附原始碼下載地址)

0. 寫在前面 友情提示:文末有免費視訊資源贈送。 專案基本完成了,加上這個總結,與這個專案相關的部落格也寫了30篇了,積少成多,寫部落格的過程是固化思路的一個過程,對自己很有用,同時也能幫助別人。順便說個題外話,在學習的過程中肯定會遇到很多異常出現,我們要做