Maven 整合 SSH 框架

?????前面的一系列文章中扁远,我們總結(jié)了三大框架:Struts2平夜,Hibernate那婉,Spring 的基本知識。本篇就姑且嘗試著使用 Maven 這個項目構(gòu)建工具來將這三個框架整合一起叫榕。說到這里浑侥,如果有對 Maven 還不熟悉的同學(xué),此處推薦下面兩個鏈接快速了解下晰绎,記得回來寓落!

Maven 是什么?
如何給小白說明 Maven 是什么荞下?

我對 Maven 的理解就是伶选,它是一個工具能提供兩大主要功能,其一是依賴管理锄弱,其二是項目構(gòu)建考蕾。

所謂的依賴管理就是指,我們對于框架中的 jar 包從此不需要手動的添加到項目中來会宪,而是使用 Maven 的語法進(jìn)行引用肖卧,當(dāng)然在打包發(fā)布的時候,這些包還是會被加入進(jìn)來掸鹅,但是在我們的源代碼中就不存在任何的 jar 包塞帐,整個項目輕量可移植性強(qiáng)拦赠。

而所謂的項目構(gòu)建指的是,對項目進(jìn)行編譯葵姥,測試荷鼠,打包,發(fā)布等榔幸。原先我們是通過 IDE 來完成這樣的工作允乐,但是不同的 IDE 有不同的使用操作,但是如果你是 Maven 項目的話削咆,無論你在哪種 IDE 中編碼牍疏,都可以使用相同的 Maven 命令進(jìn)行上述的幾種操作,這其實在一定程度上減少了我們對 IDE 的依賴拨齐。

上述我們簡單介紹了 Maven 這個項目管理工具鳞陨,具體深入的學(xué)習(xí)不是本篇的重點(diǎn),本篇著重完成對 SSH 框架整合的一個操作瞻惋,主要涉及以下內(nèi)容:

  • 分別配置各個框架的運(yùn)行環(huán)境
  • 了解整個 Web 項目配置文件的加載順序
  • Spring 整合 Struts2
  • Spring 整合 Hibernate
  • 創(chuàng)建Action厦滤,Service,Dao 模擬登錄過程
  • 項目的模塊分離與再聚合

一歼狼、分別配置各個框架的運(yùn)行環(huán)境

首先掏导,我們先將三個框架各自的運(yùn)行環(huán)境都配置到我們的 web 項目中。

創(chuàng)建一個 Maven 的 web 工程蹂匹,基本的目錄結(jié)構(gòu)大致是這樣的:

web 項目的基本目錄結(jié)構(gòu)

然后我們先來配置 struts2 的運(yùn)行環(huán)境碘菜。
第一步,pom.xml 中依賴 struts2 的核心包:

<dependency>
   <groupId>org.apache.struts</groupId>
   <artifactId>struts2-core</artifactId>
   <version>2.3.32</version>
</dependency>

由于 Maven 會自動引入該核心包所依賴的其他 jar 包限寞,所以我們無需在手動依賴其他任何 jar 包忍啸。

第二步,web.xml 中配置核心過濾器:

<!--配置Struts的核心過濾器-->
<filter>
  <filter-name>struts</filter-name>
  <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class></filter>

<filter-mapping>
  <filter-name>struts</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

第三步履植,創(chuàng)建 struts.xml 用于配置控制器 Action计雌。

至此,struts2 的運(yùn)行環(huán)境已經(jīng)配置完成玫霎,下面我們看 Hibernate 運(yùn)行環(huán)境的配置凿滤。
第一步,依賴相關(guān)的 jar 包庶近,我們看看 Hibernate 需要依賴哪些 jar 包翁脆?

//mysql 驅(qū)動的依賴
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>6.0.6</version>
</dependency>
//Hibernate 核心包依賴
<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>4.3.11.Final</version>
</dependency>

同樣,hibernate 核心包需要依賴的其他 jar 包鼻种,Maven 會為我們自動查詢并引入反番。

第二步,創(chuàng)建 Hibernate 核心配置文件 hibernate.cfg.xml 并完成基本信息的配置。

這里寫圖片描述

需要說明一點(diǎn)的是罢缸,為了簡單起見篙贸,這里我們并沒有使用數(shù)據(jù)源進(jìn)行數(shù)據(jù)庫的連接,等到與 Spring 整合的時候會使用數(shù)據(jù)源配置數(shù)據(jù)庫連接枫疆。

至此爵川,Hibernate 的基本環(huán)境也已經(jīng)配置完成,下面我們看 Spring 的環(huán)境配置息楔。

第一步寝贡,引入 Spring 相關(guān)依賴:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-expression</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>
    
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

第二步,創(chuàng)建 Spring 核心配置文件 applicationContext.xml 值依。

第三步兔甘,web.xml 中創(chuàng)建 Spring 的配置文件加載 Listener,它的具體作用我們下一小節(jié)進(jìn)行介紹鳞滨。

<!--配置Spring監(jiān)聽器-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListene</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

這樣,三個框架各自的運(yùn)行環(huán)境就已經(jīng)創(chuàng)建完成了蟆淀,但是顯然它們現(xiàn)在是不能整合共同工作的拯啦。整個項目的目錄結(jié)構(gòu)如下:

這里寫圖片描述

二、了解整個 Web 項目配置文件的加載順序

如果上述操作無誤的話熔任,現(xiàn)在我們的 web.xml 配置文件中起碼應(yīng)該是這樣的:

這里寫圖片描述

當(dāng)整個 web 應(yīng)用啟動時褒链,首先會去加載 web.xml ,其中會啟動 struts 的核心過濾器疑苔,然后我們的 Spring 監(jiān)聽器監(jiān)聽到 web 容器啟動后甫匹,會根據(jù) ServletContext 中保存的我們的配置參數(shù)信息去加載 Spring 的配置文件。而一般來說惦费,Spring 整合 Hibernate 之后兵迅,Spring 的配置文件中會指明去加載 Hibernate 的配置文件,更具體的我們下文會詳細(xì)介紹薪贫,此處只需要了解 Spring 配置文件中會去加載 Hibernate 的核心配置文件恍箭。

那么,這樣的話瞧省,我們?nèi)齻€框架的核心配置文件已經(jīng)能夠按順序加載了扯夭。下面我們兩兩整合框架,先進(jìn)行 Spring 與 Struts2 的整合鞍匾。

三交洗、Spring 整合 Struts2

Spring 與 Struts2 整合的核心點(diǎn)在于,將 Struts2 的 Action 交由 Spring 的 IOC 容器來創(chuàng)建橡淑。我們先創(chuàng)建一個 Action构拳,

//index.jsp
<body>
    <form action="login" method="post">
        姓名:<input type="text" name="name" /><br/>
        <input type="submit" value="提交" />
    </form>
</body>
public class LoginAction extends ActionSupport {

    private String name;
    //省略getter,setter方法
    public String execute(){
        if("single".equals(this.name)){
            return SUCCESS;
        }else{
            return ERROR;
        }
    }
}

Spring 中配置該 Action 的實例信息:

<bean id="login_action" class="Actions.LoginAction" scope="prototype">
        
</bean>

接下來在 struts.xml 中引用該 bean 即可。

<package name="myPackage" extends="struts-default">
    <action name="login" class="login_action">
        <result name="success">/welcom.jsp</result>
        <result name="error">/error.jsp</result>
    </action>
</package>

注意我們這里 action 標(biāo)簽中的 class 屬性已經(jīng)不再指向具體的 Action 類了隐圾,它指向的是 Spring 中的實例 bean伍掀。

至此,對于 Struts2 和 Spring 的整合大致上結(jié)束了暇藏,為什么說大致呢蜜笤?當(dāng)你啟動 web 容器運(yùn)行上述程序時,會報錯:

Unable to load configuration. - action .....

告訴你無法加載 struts.xml 配置文件盐碱,其實就是 action 的 class 屬性對應(yīng)的類找不到的意思把兔。解決辦法是,添加一個 Spring 插件依賴瓮顽,該插件會讓容器在找不到對應(yīng)的實體類的時候县好,去 Spring IOC 容器中找。具體依賴是:

<dependency>
  <groupId>org.apache.struts</groupId>
  <artifactId>struts2-spring-plugin</artifactId>
  <version>2.3.15.1</version>
</dependency>

然后我們啟動 web 容器測試我們的整合效果暖混。

這里寫圖片描述

這里寫圖片描述

整合成功缕贡! Struts2 與 Spring 的整合還算簡單,Spring 整合 Hibernate 則相對復(fù)雜一些拣播。

四晾咪、Spring 整合 Hibernate

整合 Hibernate 的第一步依然是依賴相關(guān) jar 包。

//MySQL 驅(qū)動包
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>6.0.6</version>
</dependency>
//c3p0 
<dependency>
  <groupId>com.mchange</groupId>
  <artifactId>c3p0</artifactId>
  <version>0.9.5</version>
</dependency>

第二步是配置數(shù)據(jù)源和 session 工廠贮配。

<!--讀取屬性配置文件內(nèi)容-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置c3p0數(shù)據(jù)源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${diverClass}"/>
    <property name="jdbcUrl" value="${jdbcUrl}"/>
    <property name="user" value="${user}"/>
    <property name="password" value="${password}"/>
</bean>

創(chuàng)建一個屬性文件保存 jdbc 連接的基本信息谍倦,連接驅(qū)動,連接 url泪勒,用戶名昼蛀,密碼等。然后我們在 Spring 配置文件中配置了一個單例的數(shù)據(jù)源圆存,它負(fù)責(zé)創(chuàng)建于數(shù)據(jù)庫的連接叼旋。

接著配置一個 SessionFactory 實例:

<!--配置session工廠-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocations" value="classpath:hibernate.cfg.xml"/>
</bean>

創(chuàng)建 session 工廠的時候會去加載 Hibernate 的核心配置文件,這里我們通過注入 configLocations 屬性的值告訴 Spring 該文件的位置沦辙。這里還需要引入一個在 Spring 配置文件中支持 Hibernate 相關(guān)操作的一個插件:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

Spring 對 Hibernate 的整合也基本結(jié)束送淆,下面我們通過模擬一個登陸操作來初步體驗下整合后框架的整體運(yùn)行過程。

五怕轿、模擬登錄過程

為了項目之間各個模塊的耦合性低偷崩,我們通常會選擇將整個項目分分層,Action 控制器攔截請求撞羽,Service 處理業(yè)務(wù)阐斜,Dao 完成對數(shù)據(jù)的存取。

這里寫圖片描述

MyDao 中封裝著我們對于數(shù)據(jù)庫的所有操作诀紊,MyService 中封裝著我們所有的業(yè)務(wù)邏輯谒出。我們先在 Dao 層中添加一個方法用于根據(jù)用戶名返回給用于所有信息,也就是返回該用戶名所匹配的那條記錄。

public class MyDao {

    private SessionFactory sessionFactory;
    //省略getter笤喳,setter方法
    public UserInfo getByName(String name){
        Session session = this.sessionFactory.openSession();
        List list = session.createSQLQuery("SELECT * FROM logins WHERE NAME ='"+name+"'")
                .addEntity(UserInfo.class)
                .list();
        session.close();
        if(list != null && list.size() != 0){
            return (UserInfo) list.get(0);
        }else {
            return null;
        }
    }
}
//Spring IOC 容器中配置一個 MyDao 實例
<bean id="myDao" class="Dao.MyDao">
   <property name="sessionFactory" ref="sessionFactory"/>
</bean>

接著我們寫 Service 層:

public class MyService {

    private MyDao dao;
    //省略getter为居,setter方法
    public boolean sure(String name,String pwd){
        UserInfo userInfo = this.dao.getByName(name);
        if(userInfo == null){
            return false;
        }else {
            if(userInfo.getPwd().equals(pwd)) return true;
            else return false;
        }
    }
}
//Spring IOC 容器中配置一個 Service 實例
<bean id="myService" class="Service.MyService">
    <property name="dao" ref="myDao"/>
</bean>

創(chuàng)建 Service 實例的同時并將 MyDao 實例注入到其中,邏輯上實現(xiàn)了 Service 調(diào) Dao杀狡,組件調(diào)用蒙畴。下面寫控制器:

public class LoginAction extends ActionSupport {

    private String name;
    private String pwd;
    private MyService service;
    //省略getter,setter方法
    public void setName(String name) {
        this.name = name;
    }

    public String execute(){
       boolean flag = this.service.sure(name,pwd);
       if(flag) return SUCCESS;
       else return ERROR;
    }
}
//Spring IOC 容器中配置 Action 實例
<bean id="login_Action" class="Actions.LoginAction" scope="prototype">
    <property name="service" ref="myService"/>
</bean>
//struts.xml 中使 Action 生效
<package name="myPackage" extends="struts-default">
    <action name="login" class="login_Action">
        <result name="success">/welcom.jsp</result>
        <result name="error">/error.jsp</result>
    </action>
</package>

好了呜象,我們來測試一下膳凝!

這里寫圖片描述

這里寫圖片描述
這里寫圖片描述

這里寫圖片描述

上述我們使用整合后的框架做了一個小案例,由于代碼量較小還不能體現(xiàn)框架分層處理的優(yōu)勢恭陡,但是我們還要對其進(jìn)行更深層次的解耦蹬音。

六、項目的模塊分離與再聚合

上述的項目中休玩,我們的 Dao著淆,Service,Action 等層次的代碼都處于同一個項目中拴疤,項目的模塊化就是將這些層分離出去牧抽,然后再以熱插拔的形式聚合回原項目,這樣的話遥赚,項目中的各個組件都是一個一個的子模塊,那么任意一個模塊出現(xiàn)問題后阐肤,可以立即用一個新模塊接上凫佛。這種模塊化的思想已經(jīng)越來越成為一種主流的思想。

下面我們來介紹下孕惜,如何拆分出這些模塊愧薛。

首先我們要新建一個工程作為父工程,這些 Dao衫画,Service毫炉,Action 都是它下面的子模塊。打個比方來說削罩,父工程就相當(dāng)于電腦主板瞄勾,Dao,Service弥激,Action 都是熱插拔在上面的內(nèi)存條进陡、硬盤等部件,主板上的資源在各個部件上都是可見的微服。所以我們的父工程只需要做一件事趾疚,依賴子模塊所需要的所有的 jar 包。

這里寫圖片描述

這個父工程什么都不要有,只需要有一個 pom.xml 文件用于依賴所有需要的 jar 包即可糙麦。然后我們將上一個項目中所有需要依賴的 jar 包都添加到父工程的 pom.xml 中進(jìn)行引用辛孵。

然后我們選中項目創(chuàng)建第一個子模塊 Dao,

這里寫圖片描述

將屬于 Dao 的所有相關(guān)文件全部移植到 Dao 模塊中來赡磅。

這里寫圖片描述

除了這些魄缚,還有一些配置在 Spring 中的代碼,我們也要拷貝過來仆邓。

這里寫圖片描述

拷貝原先的 Spring 的配置文件并刪除和我們 Dao 層無關(guān)的所有配置代碼鲜滩。這就完成了對 Dao 模塊的分離,下面我們分離 Service 模塊节值。

第一步是一樣的徙硅,先創(chuàng)建一個子模塊然后移植過來原先項目中和 Service 相關(guān)的所有代碼文件。

這里寫圖片描述

相關(guān)的文件拷貝后的 Service 目錄結(jié)構(gòu)如上圖所示搞疗,但是整個 Service 模塊是報錯的嗓蘑,原因很簡單,Service 現(xiàn)在是獨(dú)立于 Dao 的匿乃,但是它又是依賴 Dao 的桩皿,所以我們只需要將 Dao 模塊打包發(fā)布到本地倉庫,然后 Service 通過 Maven 依賴即可幢炸。

<dependency>
    <groupId>top.walkeryam</groupId>
    <artifactId>Dao</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

依賴 Dao 包之后就會發(fā)現(xiàn)項目不再報錯了泄隔,最后我們分離 Action。

第一步依然是創(chuàng)建子模塊并移植過來相關(guān)的所有代碼宛徊,

這里寫圖片描述

這里的報錯和上述的原因是一樣的佛嬉,Action 要依賴 Service ,所以我們只要為其添加 Service 的引用即可闸天。

<dependency>
   <groupId>top.walkeryam</groupId>
   <artifactId>Service</artifactId>
   <version>1.0-SNAPSHOT</version>
</dependency>

但是還沒完暖呕,這么多 Spring 配置文件,web 容器怎么知道加載哪個苞氮?
修改 web.xml 中有關(guān) Spring 配置文件位置的代碼:

這里寫圖片描述

使用通配符告訴容器加載所有類路徑下符合指定規(guī)則的配置文件湾揽,這樣我們各個模塊中的 Spring 的配置都可以被加載了。

下面我們將 Action 打成 war 包笼吟,并存放到 web 容器的項目目錄下库物,單獨(dú)運(yùn)行 Action,由于 Dao 和 Service 都已經(jīng)以熱插拔的形式接入到 Action 中了贷帮,所以直接運(yùn)行 Action 是沒有問題的艳狐。

這里寫圖片描述

啟動本地 Tomcat ,瀏覽器中進(jìn)行測試皿桑。

這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

測試成功毫目!那至此我們也完成了 Maven 項目的模塊化拆分與聚合的操作蔬啡,項目之間的各個組件耦合度降低,每個組件又都是可熱插拔的镀虐,一旦哪天項目中的某個組件崩潰導(dǎo)致整個項目掛了箱蟆,可隨機(jī)替換出錯的組件。

模塊化的思想已經(jīng)越來越成熟了刮便,不知道本篇上述的所有內(nèi)容闡述的是否到位空猜,但依然建議你深入理解整個解耦模塊化的思想『藓担總結(jié)不到之處辈毯,望指出!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搜贤,一起剝皮案震驚了整個濱河市谆沃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仪芒,老刑警劉巖唁影,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掂名,居然都是意外死亡据沈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門饺蔑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锌介,“玉大人,你說我怎么就攤上這事猾警】谆觯” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵肿嘲,是天一觀的道長。 經(jīng)常有香客問我筑公,道長雳窟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任匣屡,我火速辦了婚禮封救,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捣作。我一直安慰自己誉结,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布券躁。 她就那樣靜靜地躺著惩坑,像睡著了一般掉盅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上以舒,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天趾痘,我揣著相機(jī)與錄音,去河邊找鬼蔓钟。 笑死,一個胖子當(dāng)著我的面吹牛侣集,可吹牛的內(nèi)容都是我干的兰绣。 我是一名探鬼主播世分,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼罚攀!你這毒婦竟也來了雌澄?” 一聲冷哼從身側(cè)響起斋泄,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎镐牺,沒想到半個月后炫掐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體募胃,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畦浓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年讶请,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夺溢。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡风响,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鞋怀,到底是詐尸還是另有隱情,我是刑警寧澤攒读,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布辛友,位于F島的核電站,受9級特大地震影響邓梅,放射性物質(zhì)發(fā)生泄漏邑滨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一匣距、第九天 我趴在偏房一處隱蔽的房頂上張望哎壳。 院中可真熱鬧归榕,春花似錦、人聲如沸刹泄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墩莫。三九已至乞旦,卻和暖如春题山,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玖姑。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工焰络, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闪彼。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓畏腕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親把夸。 傳聞我的和親對象是個殘疾皇子铭污,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容