【Java EE 學習 70 下】【數據採集系統次日】【Action中User注入】【設計調查頁面】【Action中模型賦值問題】【編輯調查】

1、Action中User注入問題css

  Action中可能會常常用到已經登錄的User對象,若是每次都從Session中拿會顯得很是繁瑣。能夠想一種方法,當Action想要獲取User對象的時候直接使用,這種方法仍是得須要藉助攔截器的力量,直接在登陸攔截器中實現便可,可是登錄攔截器怎麼知道該Action想要獲取User對象呢?這就須要給Action加上一個接口,若是該Action是該接口的實現類,則表示該Action想要獲取User對象。接口仿照HttpRequestAware接口的形式,名字爲用戶關注接口:html

 1 package com.kdyzm.struts.action.aware;
 2 
 3 import com.kdyzm.domain.User;
 4 /**
 5  * 用戶關注接口,用於Action獲取Session中的User對象
 6  * @author kdyzm
 7  *
 8  */
 9 public interface UserAware {
10     public void setUser(User user);
11 }

這樣在登錄攔截器中直接進行判斷便可,若是用戶已經登錄了,並且請求的Action是UserAware的實現類,那麼就經過setUser方法將User注入到Action中。這樣登陸攔截器中的intercept方法就變成了以下的形式:前端

 1 public String intercept(ActionInvocation invocation) throws Exception {
 2         System.out.println("被登陸攔截器攔截!");
 3         Action action=(Action) invocation.getAction();
 4         if(action instanceof LoginAction ||action instanceof RegisterAction){
 5             System.out.println("即將進行登陸或者註冊,直接放行!");
 6             return invocation.invoke();
 7         }
 8         HttpServletRequest request=ServletActionContext.getRequest();
 9         HttpSession session=request.getSession();
10         User user=(User) session.getAttribute("user");
11         if(user==null){
12             System.out.println("用戶未登陸,必須先登陸再訪問其餘資源!即將跳轉到登錄界面!");
13             return "toLoginPage";
14         }else{
15             System.out.println("用戶已經登錄,登陸攔截器已經放行!");
16             //若是用戶名不爲空,並且實現了UserAware接口,就須要調用該接口中的相應方法給類中的成員變量賦值
17             //TODO 給Action中User動態賦值的方法
18             if(action instanceof UserAware){ 19  ((UserAware)action).setUser(user); 20  } 21             return invocation.invoke();
22         }
23     }

2、設計調查頁面,設計調查頁面幾乎是該項目中最複雜的一個頁面了在「個人調查」中的其中一個調查欄目中直接單擊「設計調查」超連接,就直接跳轉到設計調查頁面,固然須要在Action將調查對象(Survey對象)先查詢出來。完整的頁面設計代碼以下這個頁面設計起來很是困難,我也是寫了好幾個小時才完成的,由於須要考慮到不少因素,須要一步一步的進行調試才行。java

完整代碼是:數據庫

  1 <%@ page language="java" pageEncoding="utf-8"%>
  2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  3 <html>
  4 <head>
  5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  6 <link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/header.css" type="text/css">
  7 <style type="text/css">
  8     table{
  9         border: 1px solid black;
 10         border-collapse: collapse;
 11         width: 100%;
 12     }
 13     table tr{
 14         border-collapse: collapse;
 15     }
 16     tr td{
 17         border:1px solid black;
 18         border-collapse: collapse;
 19     }
 20     a{
 21         color: gray;
 22         text-decoration: none;
 23     }
 24     a:HOVER {
 25         color: red;
 26     }
 27     .tdHL{
 28         text-align: left;
 29         border-width: 0px;
 30     }
 31     .tdHR{
 32         text-align: right;
 33         border-width: 0px;
 34     }
 35     .pageTitle{
 36         background-color: #CCF;
 37     }
 38     .questionTitle{
 39         background-color: #CCC;
 40     }
 41 </style>
 42 <title>Insert title here</title>
 43 </head>
 44 <body>
 45     <%@ include file="/header.jsp" %>
 46     <div>
 47         <!-- 先設計一個變量保存住surveyid -->
 48         <s:set value="%{surveyId}" name="id"/>
 49         <table>
 50             <tr>
 51                 <td colspan="2">設計調查</td>
 52             </tr>
 53             <tr>
 54                 <td class="tdHL">
 55                     <!-- 這裏使用sturs2標籤直接判斷圖片是否存在! -->
 56                     <!-- 在這裏加上一個logo標識 -->
 57                     <s:if test="isLogoImageExists()">
 58                         <img width="40px"  alt="這是logo標識" src="<s:url value='%{logoPath}'/>"/>
 59                     </s:if>
 60                     <s:else>
 61                         <!-- 若是圖片不存在,則什麼都不顯示 -->
 62                     </s:else>
 63                     <s:property value="title"/>
 64                 </td>
 65                 <td class="tdHR">
 66                     <s:a action="SurveyAction_toUploadLogoPage.action" namespace="/">
 67                         <s:param name="surveyId" value="%{#id}"></s:param>
 68                     增長Logo
 69                     </s:a>
 70                     &nbsp;
 71                     <s:a action="SurveyAction_toEditSurveyPage.action" namespace="/">
 72                         <s:param name="surveyId" value="%{#id}"></s:param>
 73                     編輯調查</s:a>&nbsp;
 74                     <s:a action="PageAction_toAddPagePage.action" namespace="/">
 75                         <s:param value="%{#id}" name="surveyId"></s:param>
 76                     增長頁</s:a>
 77                 </td>
 78             </tr>
 79             <tr>
 80                 <td colspan="2">
 81                     <!-- 主幹內容開始 -->
 82                     <table>
 83                         <tr>
 84                             <td width="20px"></td>
 85                             <td width="*">
 86                                 <!-- 迭代頁面集合 -->
 87                                 <table>
 88                                     <s:iterator value="%{pages}" var="page">
 89                                         <s:set var="pId" value="%{#page.pageId}"></s:set>
 90                                         <tr>
 91                                             <td>
 92                                                 <table>
 93                                                     <tr class="pageTitle">
 94                                                         <!-- 頁面標題 -->
 95                                                         <td width="40%" class="tdHL">
 96                                                             <s:property value="%{#page.title}"/>
 97                                                         </td>
 98                                                         <td width="60%" class="tdHR">
 99                                                             <s:a action="PageAction_toEditPageTitlePage.action" namespace="/">
100                                                                 <s:param name="pageId" value="%{#pId}"></s:param>
101                                                                 <s:param name="surveyId" value="%{#id}"></s:param>
102                                                             編輯頁面標題</s:a>&nbsp;
103                                                             <s:a action="PageAction_toSelectTargetPage.action" namespace="/">
104                                                                 <s:param name="pageId" value="%{#pId}"></s:param>
105                                                                 <s:param name="surveyId" value="%{#id}"></s:param>
106                                                             移動/複製頁
107                                                             </s:a>
108                                                             &nbsp;
109                                                             <s:a action="QuestionAction_toSelectQuestionTypePage.action" namespace="/">
110                                                                 <s:param name="pageId" value="%{#pId}"></s:param>
111                                                                 <s:param name="surveyId" value="%{#id}"></s:param>
112                                                             增長問題</s:a>&nbsp;
113                                                             <s:a action="PageAction_deletePage.action" namespace="/">
114                                                                 <s:param name="pageId" value="%{#pId}"></s:param>
115                                                                 <s:param name="surveyId" value="%{#id}"></s:param>
116                                                             刪除頁</s:a>
117                                                         </td>
118                                                     </tr>
119                                                     <tr>
120                                                         <td colspan="2">
121                                                             <table>
122                                                                 <tr>
123                                                                     <td width="20px"></td>
124                                                                     <td>
125                                                                         <!-- 迭代問題的集合 -->
126                                                                         <table>
127                                                                             <s:iterator value="%{#page.questions}" var="question">
128                                                                                 <s:set var="qid" value="%{#question.questionId}"></s:set>
129                                                                                 <!-- 問題題幹 -->
130                                                                                 <tr class="questionTitle">
131                                                                                     <td class="tdHL"><s:property value="%{#question.title}"/></td>
132                                                                                     <td class="tdHR">
133                                                                                         <s:a action="QuestionAction_editQuestion.action" namespace="/">
134                                                                                             <s:param name="pageId" value="%{#pId}"></s:param>
135                                                                                             <s:param name="surveyId" value="%{#id}"></s:param>
136                                                                                             <s:param name="questionId" value="%{#qid}"></s:param>
137                                                                                         編輯問題</s:a>&nbsp;
138                                                                                         <s:a action="QuestionAction_deleteQuestion.action" namespace="/">
139                                                                                             <s:param name="pageId" value="%{#pId}"></s:param>
140                                                                                             <s:param name="surveyId" value="%{#id}"></s:param>
141                                                                                             <s:param name="questionId" value="%{#qid}"></s:param>
142                                                                                         刪除問題</s:a>&nbsp;
143                                                                                     </td>
144                                                                                 </tr>
145                                                                                 <!-- 問題主體,主要涉及的問題就是問題的分類 -->
146                                                                                 <tr>
147                                                                                     <td colspan="2">
148                                                                                         <!-- 定義變量,爲當前類型的題型 -->
149                                                                                         <s:set value="%{#question.questionType}" var="qt"></s:set>
150                                                                                         <!-- 第一種題型:帶有單選框或者複選框的 
151                                                                                             題目標識就是題號小於4,0-3
152                                                                                         -->
153                                                                                         <s:if test="#qt lt 4">
154                                                                                             <s:iterator value="#question.optionTextArr">
155                                                                                                 <input type='<s:property value="#qt<2?'radio':'checkbox'"/>'>
156                                                                                                 <s:property/>
157                                                                                                 <s:if test="#qt==1 || #qt==3">
158                                                                                                     <br/>
159                                                                                                 </s:if>
160                                                                                             </s:iterator>
161                                                                                             <!-- 處理other的狀況 -->
162                                                                                             <s:if test="#question.other">
163                                                                                                 <input type='<s:property value="#qt<2?'radio':'checkbox'"/>'>其它
164                                                                                                 <s:if test="#question.otherType==1">
165                                                                                                     <input type="text">
166                                                                                                 </s:if>
167                                                                                                 <s:elseif test="#question.otherType==2">
168                                                                                                     <s:select list="#question.otherSelectOptionArr">
169                                                                                                     </s:select>
170                                                                                                 </s:elseif>
171                                                                                             </s:if>
172                                                                                         </s:if>
173                                                                                         <!-- 第二種題型,是下拉列表類型的題型 -->
174                                                                                         <s:elseif test="#qt==4">
175                                                                                             <s:select list="#question.optionTextArr"></s:select>
176                                                                                         </s:elseif>
177                                                                                         <s:elseif test="#qt==5">
178                                                                                             <s:textfield></s:textfield>
179                                                                                         </s:elseif>
180                                                                                         <!-- 第三種題型,矩陣問題,6,7,8 -->
181                                                                                         <s:else>
182                                                                                             <table>
183                                                                                                 <!-- 列頭 -->
184                                                                                                 <tr>
185                                                                                                     <td></td>
186                                                                                                     <s:iterator value="#question.matrixColTitleArr">
187                                                                                                         <td><s:property/></td>
188                                                                                                     </s:iterator>
189                                                                                                 </tr>
190                                                                                                 <!-- 輸出N多行 -->
191                                                                                                 <s:iterator value="#question.matrixRowTitleArr">
192                                                                                                     <tr>
193                                                                                                         <td><s:property/></td>
194                                                                                                         <s:iterator value="#question.matrixColTitleArr">
195                                                                                                             <td>
196                                                                                                                 <s:if test="#qt==6">
197                                                                                                                     <input type="radio">
198                                                                                                                 </s:if>
199                                                                                                                 <s:elseif test="#qt==7">
200                                                                                                                     <input type="checkbox">
201                                                                                                                 </s:elseif>
202                                                                                                                 <s:elseif test="#qt==8">
203                                                                                                                     <select>
204                                                                                                                         <s:iterator value="#question.matrixSelectOptionArr">
205                                                                                                                             <option>
206                                                                                                                                 <s:property/>
207                                                                                                                             </option>
208                                                                                                                         </s:iterator>
209                                                                                                                     </select>
210                                                                                                                 </s:elseif>
211                                                                                                             </td>
212                                                                                                         </s:iterator>
213                                                                                                     </tr>
214                                                                                                 </s:iterator>
215                                                                                             </table>
216                                                                                         </s:else>
217                                                                                     </td>
218                                                                                 </tr>
219                                                                             </s:iterator>
220                                                                         </table>
221                                                                     </td>
222                                                                 </tr>
223                                                             </table>
224                                                         </td>
225                                                     </tr>
226                                                 </table>
227                                             </td>
228                                         </tr>
229                                     </s:iterator>
230                                 </table>
231                             </td>
232                         </tr>
233                     </table>                
234                 </td>
235             </tr>
236         </table>
237     </div>
238 </body>
239 </html>
View Code

最核心的代碼是對問題種類的判斷:session

 1 <s:set value="%{#question.questionType}" var="qt"></s:set>
 2 <!-- 第一種題型:帶有單選框或者複選框的 
 3     題目標識就是題號小於4,0-3
 4 -->
 5 <s:if test="#qt lt 4">
 6     <s:iterator value="#question.optionTextArr">
 7         <input type='<s:property value="#qt<2?'radio':'checkbox'"/>'>
 8         <s:property/>
 9         <s:if test="#qt==1 || #qt==3">
10             <br/>
11         </s:if>
12     </s:iterator>
13     <!-- 處理other的狀況 -->
14     <s:if test="#question.other">
15         <input type='<s:property value="#qt<2?'radio':'checkbox'"/>'>其它
16         <s:if test="#question.otherType==1">
17             <input type="text">
18         </s:if>
19         <s:elseif test="#question.otherType==2">
20             <s:select list="#question.otherSelectOptionArr">
21             </s:select>
22         </s:elseif>
23     </s:if>
24 </s:if>
25 <!-- 第二種題型,是下拉列表類型的題型 -->
26 <s:elseif test="#qt==4">
27     <s:select list="#question.optionTextArr"></s:select>
28 </s:elseif>
29 <s:elseif test="#qt==5">
30     <s:textfield></s:textfield>
31 </s:elseif>
32 <!-- 第三種題型,矩陣問題,6,7,8 -->
33 <s:else>
34     <table>
35         <!-- 列頭 -->
36         <tr>
37             <td></td>
38             <s:iterator value="#question.matrixColTitleArr">
39                 <td><s:property/></td>
40             </s:iterator>
41         </tr>
42         <!-- 輸出N多行 -->
43         <s:iterator value="#question.matrixRowTitleArr">
44             <tr>
45                 <td><s:property/></td>
46                 <s:iterator value="#question.matrixColTitleArr">
47                     <td>
48                         <s:if test="#qt==6">
49                             <input type="radio">
50                         </s:if>
51                         <s:elseif test="#qt==7">
52                             <input type="checkbox">
53                         </s:elseif>
54                         <s:elseif test="#qt==8">
55                             <select>
56                                 <s:iterator value="#question.matrixSelectOptionArr">
57                                     <option>
58                                         <s:property/>
59                                     </option>
60                                 </s:iterator>
61                             </select>
62                         </s:elseif>
63                     </td>
64                 </s:iterator>
65             </tr>
66         </s:iterator>
67     </table>
68 </s:else>

以前就說過,每一個問題的位置不能改變,這是由於將會使用該問題的下標獲得該問題是什麼種類的問題,一種有九種類型的問題,每一種問題都對應一種獨一無二的問題類型。app

最終設計效果以下圖所示:固然若是隻是當前階段的話是沒有這種效果的,必須結合以後的添加問題的功能才行。整個頁面都是用表格標籤進行了嵌套,因此顯得比較難看,可是也沒有好的方法,若是有時間的話就會對其進行優化。dom

3、Action中模型賦值問題。(重點)jsp

每個Action基本上都是BaseAction的子類,繼承BaseAction的優勢就是不須要每次都實現模型驅動接口而且重寫getModel方法了,模型的賦值過程將會在父類中實現,這裏固然也會用到泛型。ide

可是實現了模型驅動接口須要注意一點事項:可能會有數據庫中的信息和前端頁面顯示的信息不一致的狀況發生。

首先實現編輯調查功能,小功能很是小,因此略過不提。可是有必要說一下這個過程,由於這是引起該問題的關鍵

在設計調查頁面單擊「編輯調查」->請求SurveyAction.toEditSurveyPage()方法,該方法查詢數據庫,賦值到model->跳轉到editSurveyPage.jsp頁面回顯,這時候詭異的事情就發生了,回顯的時候有異常的狀況發生。回顯的調查標題是「未命名」,可是該調查原來明明有標題是「居民生活水平調查」。爲何會發生這種狀況呢?

緣由分析:棧頂指針未改變致使的。看一下在編輯調查方法中的代碼:  

1 //跳轉到編輯調查的頁面上去
2     public String toEditSurveyPage() throws Exception{
3         this.model=this.surveyService.getModelById(this.model.getSurveyId());
4         return "toEditSurveyPage";
5     }

實際上該方法中只有一句代碼而已。就是將數據庫中查到的對象賦值給model對象。好像這樣就將模型給「刷新」了,可是這也只是「好像」而已,實際上並無刷新model對象。

在棧頂中存放的是舊model的引用地址,說到底model只是一個變量而已,若是改變了model的值,只是將model的指針指向了新的地址,可是棧頂的model對象中的值並無被改變。只是沒法再經過model對象訪問到而已。因此若是直接給model對象賦值可是不作其餘修改是沒有任何意義的。

解決方法:

  方法1.再次壓棧,示例代碼以下:

ActionContext.getContext().getValueStack().push(model);

  固然實際上值棧中就會有兩份model對象了,這樣作的好處就是解決了model賦值的問題,可是也有弊端,每次都須要這麼寫不嫌麻煩麼?並且這麼作一點都不「優雅」。

   方法2.經過prepare攔截器加上paramsPrepareStack攔截器棧組合完成該項任務。

  具體作法是首先將BaseAction實現Prepare接口,而後在Action中重寫接口中的方法。僞代碼以下:

public void prepareDesignSurvey(){
            this.model = xxx ;
        }

  固然最重要的仍是須要改變默認棧爲parameterPrepareStack,不然仍是沒有任何效果。

  Action中的目標方法DesignSurvey中直接跳轉頁面便可,不須要再對model進行修改。

    爲何使用這種方法可以解決問題:實際上引起該問題的緣由是模型賦值在模型驅動攔截器獲取model以後完成的,這樣就致使了即便改變model對象也不會改變棧頂指針,若是將二者順序顛倒一下,即先給模型賦值,而後模型驅動攔截器再取值,這樣就沒問題了,關鍵是在合適的位置實現模型賦值,首先肯定的是必定是在模型驅動攔截器以前,合適的位置就是prepareInterceptor攔截器,因此實現Prepare接口而後重寫方法便可;可是僅僅這麼作仍是不夠的,由於parametersInterceptor在默認攔截器棧中的順序是在模型驅動攔截器以後,因此在prepareInterceptor攔截器中獲取不到Action中的相關參數,必定會引起相似於id can't load的異常 ,解決方法就是使用paramsPreparedStack攔截器棧,該攔截器棧和默認的攔截器棧的惟一區別就是在prepare攔截器以前增長了一個parameter攔截器,正好解決了Action中屬性賦值的問題。

    下面是兩個攔截器棧的定義:

 1 <!-- An example of the paramsPrepareParams trick. This stack is exactly 
 2                 the same as the defaultStack, except that it includes one extra interceptor 
 3                 before the prepare interceptor: the params interceptor. This is useful for 
 4                 when you wish to apply parameters directly to an object that you wish to 
 5                 load externally (such as a DAO or database or service layer), but can't load 
 6                 that object until at least the ID parameter has been loaded. By loading the 
 7                 parameters twice, you can retrieve the object in the prepare() method, allowing 
 8                 the second params interceptor to apply the values on the object. -->
 9             <interceptor-stack name="paramsPrepareParamsStack">
10                 <interceptor-ref name="exception" />
11                 <interceptor-ref name="alias" />
12                 <interceptor-ref name="i18n" />
13                 <interceptor-ref name="checkbox" />
14                 <interceptor-ref name="multiselect" />
15                 <interceptor-ref name="params">
16                     <param name="excludeParams">dojo\..*,^struts\..*</param>
17                 </interceptor-ref>
18                 <interceptor-ref name="servletConfig" />
19                 <interceptor-ref name="prepare" />
20                 <interceptor-ref name="chain" />
21                 <interceptor-ref name="modelDriven" />
22                 <interceptor-ref name="fileUpload" />
23                 <interceptor-ref name="staticParams" />
24                 <interceptor-ref name="actionMappingParams" />
25                 <interceptor-ref name="params">
26                     <param name="excludeParams">dojo\..*,^struts\..*</param>
27                 </interceptor-ref>
28                 <interceptor-ref name="conversionError" />
29                 <interceptor-ref name="validation">
30                     <param name="excludeMethods">input,back,cancel,browse</param>
31                 </interceptor-ref>
32                 <interceptor-ref name="workflow">
33                     <param name="excludeMethods">input,back,cancel,browse</param>
34                 </interceptor-ref>
35             </interceptor-stack>

  方法3.修改模型驅動攔截器,設置刷新model標識爲true

    模型驅動攔截器代碼很短,看看它到底幹了什麼事:

 1 public class ModelDrivenInterceptor extends AbstractInterceptor {
 2 
 3     protected boolean refreshModelBeforeResult = false;  4 
 5     public void setRefreshModelBeforeResult(boolean val) {
 6         this.refreshModelBeforeResult = val;
 7     }
 8 
 9     @Override
10     public String intercept(ActionInvocation invocation) throws Exception {
11         Object action = invocation.getAction();
12 
13         if (action instanceof ModelDriven) {
14             ModelDriven modelDriven = (ModelDriven) action;
15             ValueStack stack = invocation.getStack();
16             Object model = modelDriven.getModel();
17             if (model !=  null) {
18                 stack.push(model);
19             }
20             if (refreshModelBeforeResult) { 21 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); 22  } 23         }
24         return invocation.invoke();
25     }
26 
27     /**
28      * Refreshes the model instance on the value stack, if it has changed
29      */
30     protected static class RefreshModelBeforeResult implements PreResultListener { 31         private Object originalModel = null;
32         protected ModelDriven action;
33 
34 
35         public RefreshModelBeforeResult(ModelDriven action, Object model) {
36             this.originalModel = model;
37             this.action = action;
38         }
39 
40         public void beforeResult(ActionInvocation invocation, String resultCode) {
41             ValueStack stack = invocation.getStack();
42             CompoundRoot root = stack.getRoot();
43 
44             boolean needsRefresh = true;
45             Object newModel = action.getModel();
46 
47             // Check to see if the new model instance is already on the stack
48             for (Object item : root) {
49                 if (item.equals(newModel)) {
50                     needsRefresh = false;
51                     break;
52                 }
53             }
54 
55             // Add the new model on the stack
56             if (needsRefresh) {
57 
58                 // Clear off the old model instance
59                 if (originalModel != null) {
60                     root.remove(originalModel);
61                 }
62                 if (newModel != null) {
63                     stack.push(newModel);
64                 }
65             }
66         }
67     }
68 }

    在模型驅動攔截器中有個很是重要的屬性:refreshModelBeforeResult,該屬性是一個標識字段的屬性,用於標識是否須要刷新model,什麼是刷新model,就是從新獲取model的值並壓棧,這樣最終就可以實現棧頂中的model對象是最新的model對象。

  實現原理:執行模型驅動攔截器的時候,會判斷refreshModelBeforeResult的值是否爲true,若是爲true,則給invocation對象添加一個PreResultListener監聽器,模型驅動攔截器中有一個靜態類RefreshModelBeforeResult實現了該監聽器的接口,觀察該實現類的類名,翻譯成中文就是「在執行Result以前刷新Model對象」,真是一個直白的方法名,咱們知道執行結果集是在最後完成的,那麼在執行結果集以前刷新Model對象的話就不會出現上述問題了。它實現刷新的原理十分簡單,就是先讓老的Model對象彈棧,再獲取新的model對象並將新的model對象壓棧,OK,前端頁面獲取的必定就是最新的Model對象了。

  方法4:使用BeanUtils中的copy屬性的方法直接給model對象中的全部屬性從新賦值,使用這種方式的好處就是不須要考慮model對象是新的對象仍是老的對象,可是有一點很差之處就是該方法底層使用反射技術,效率比較低,並且每次都要寫該方法實際上和方法一沒有什麼差異了,都比較麻煩,並且顯得十分的「不優雅」。

4、編輯調查,略。

相關文章
相關標籤/搜索