一口一口吃掉Volley(三)

**歡迎訪問我的個人博客轉(zhuǎn)發(fā)請注明出處:http://www.wensibo.top/2017/02/17/一口一口吃掉Volley(三)/ **

學(xué)習(xí)了一口一口吃掉Volley(二)之后,你應(yīng)該已經(jīng)學(xué)會了如何使用Volley自帶的Request,但是有的時候我們需要解析的數(shù)據(jù)多種多樣,例如XML又或者你想使用Google的gson,那么當(dāng)Volley不能直接提供給我們這些功能的時候就需要我們進(jìn)行自定義了,第一節(jié)我也向大家講過Volley面向接口編程,使得其很容易擴(kuò)展,那么這節(jié)課我們就一起來學(xué)習(xí)自定義的Request吧!

從StringRequest開始講講思路

先上最基本的StringRequest源碼

public class StringRequest extends Request<String>{
    private final Response.Listener<String> mListener;

    /** 根據(jù)給定的METHOD設(shè)置對應(yīng)的request. */
    public StringRequest(int method, String url, Response.Listener<String> listener,
                         Response.ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

    /** 默認(rèn)為GET請求的request. */
    public StringRequest(String url, Response.Listener<String> listener,
                         Response.ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

    /** 將HTTP請求結(jié)果轉(zhuǎn)換為String. */
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;

        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }

    /** 將解析的String結(jié)果傳遞給用戶的回調(diào)接口. */
    @Override
    protected void deliverResponse(String response) {
        mListener.onResponse(response);
    }
}

我們應(yīng)該可以提煉出如下幾點(diǎn):

  • StringRequest繼承自Request類,并制定其泛型為String,那么當(dāng)我們自定義XMLRequest時就應(yīng)該指定類型為XmlPullParser。
  • 有兩個構(gòu)造函數(shù),默認(rèn)使用的GET請求。
  • 由于Request類中的deliverResponse()和parseNetworkResponse()是兩個抽象方法,因此自定義Request中需要對這兩個方法進(jìn)行實(shí)現(xiàn)。
  • deliverResponse()方法中僅僅是調(diào)用了mListener中的onResponse()方法,并將response內(nèi)容傳入即可,這樣就可以將服務(wù)器響應(yīng)的數(shù)據(jù)進(jìn)行回調(diào)。
  • parseNetworkResponse()方法中則是對服務(wù)器響應(yīng)的數(shù)據(jù)進(jìn)行解析,其中數(shù)據(jù)是以字節(jié)的形式存放在NetworkResponse的response變量中的,這里將數(shù)據(jù)取出然后組裝成一個String,并傳入Response的success()方法中即可。
    既然知道內(nèi)部實(shí)現(xiàn)的邏輯,那就開始動手吧!

自定義XMLRequest

① 直接上代碼啦!
按照剛才我們解析StringRequest得到的幾點(diǎn)結(jié)論,我們應(yīng)該不難得到XMLRequest:

public class XMLRequest extends Request<XmlPullParser> {

    private final Response.Listener<XmlPullParser> mListener;

    public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

    public XMLRequest( String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

    @Override
    protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
        try {
            response.headers.put("HTTP.CONTENT_TYPE", "utf-8");
            String xmlString = new String(response.data,"utf-8");
            //加上這兩行可以解決亂碼的問題,尤其是對于中文的xml接口,由于每個xml的編碼格式不同,所以獲取原編碼格式之后再轉(zhuǎn)換為utf-8,即可。
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(xmlString));
            Log.d("SUCCESS", "xmlString的內(nèi)容為" + xmlString);
            return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (XmlPullParserException e) {
            return Response.error(new ParseError(e));
        }

    }

    @Override
    protected void deliverResponse(XmlPullParser response) {
        mListener.onResponse(response);
    }

}

這里需要注意的一點(diǎn)我在上一篇文章中也已經(jīng)提到了,就是在解析數(shù)據(jù)的時候如果出現(xiàn)亂碼應(yīng)該轉(zhuǎn)換編碼為utf-8。

② 測試接口
作為測試,我使用的XML接口是:http://flash.weather.com.cn/wmaps/xml/guangdong.xml ,它返回的是廣東省各個城市的天氣預(yù)報(bào),你也可以將guangdong改為你所在的省份就可以顯示其他數(shù)據(jù)了:

<guangdong dn="day">
<city cityX="137.7" cityY="385.95" cityname="湛江" centername="湛江" fontColor="FFFFFF" pyName="zhanjiang" state1="1" state2="1" stateDetailed="多云" tem1="23" tem2="16" temNow="24" windState="微風(fēng)" windDir="東南風(fēng)" windPower="2級" humidity="50%" time="15:30" url="101281001"/>
<city cityX="170.65" cityY="317.55" cityname="茂名" centername="茂名" fontColor="FFFFFF" pyName="maoming" state1="1" state2="1" stateDetailed="多云" tem1="26" tem2="14" temNow="26" windState="微風(fēng)" windDir="西南風(fēng)" windPower="1級" humidity="47%" time="15:30" url="101282001"/>
<city cityX="225" cityY="245" cityname="云浮" centername="云浮" fontColor="FFFFFF" pyName="yunfu" state1="1" state2="1" stateDetailed="多云" tem1="26" tem2="13" temNow="26" windState="微風(fēng)" windDir="東風(fēng)" windPower="2級" humidity="43%" time="15:30" url="101281401"/>
<city cityX="226.55" cityY="304.5" cityname="陽江" centername="陽江" fontColor="FFFFFF" pyName="yangjiang" state1="0" state2="1" stateDetailed="晴轉(zhuǎn)多云" tem1="24" tem2="15" temNow="23" windState="微風(fēng)" windDir="東南風(fēng)" windPower="3級" humidity="63%" time="15:30" url="101281801"/>
<city cityX="275.35" cityY="214.65" cityname="肇慶" centername="肇慶" fontColor="FFFFFF" pyName="zhaoqing" state1="1" state2="1" stateDetailed="多云" tem1="26" tem2="14" temNow="26" windState="微風(fēng)" windDir="西北風(fēng)" windPower="1級" humidity="43%" time="15:30" url="101280901"/>
<city cityX="291" cityY="285" cityname="江門" centername="江門" fontColor="FFFFFF" pyName="jiangmen" state1="0" state2="0" stateDetailed="晴" tem1="26" tem2="15" temNow="26" windState="微風(fēng)" windDir="東風(fēng)" windPower="2級" humidity="38%" time="15:30" url="101281101"/>
<city cityX="313.3" cityY="160.45" cityname="清遠(yuǎn)" centername="清遠(yuǎn)" fontColor="FFFFFF" pyName="qingyuan" state1="1" state2="1" stateDetailed="多云" tem1="25" tem2="15" temNow="26" windState="微風(fēng)" windDir="南風(fēng)" windPower="2級" humidity="44%" time="15:30" url="101281301"/>
<city cityX="308.7" cityY="225" cityname="佛山" centername="佛山" fontColor="FFFFFF" pyName="foshan" state1="0" state2="1" stateDetailed="晴轉(zhuǎn)多云" tem1="26" tem2="14" temNow="26" windState="微風(fēng)" windDir="北風(fēng)" windPower="1級" humidity="42%" time="15:30" url="101280800"/>
<city cityX="342.7" cityY="255" cityname="中山" centername="中山" fontColor="FFFFFF" pyName="zhongshan" state1="1" state2="1" stateDetailed="多云" tem1="25" tem2="14" temNow="26" windState="微風(fēng)" windDir="西北風(fēng)" windPower="2級" humidity="41%" time="15:30" url="101281701"/>
<city cityX="340.55" cityY="300" cityname="珠海" centername="珠海" fontColor="FFFFFF" pyName="zhuhai" state1="1" state2="1" stateDetailed="多云" tem1="23" tem2="17" temNow="23" windState="微風(fēng)" windDir="東風(fēng)" windPower="2級" humidity="48%" time="15:30" url="101280701"/>
<city cityX="352.6" cityY="80" cityname="韶關(guān)" centername="韶關(guān)" fontColor="FFFFFF" pyName="shaoguan" state1="1" state2="1" stateDetailed="多云" tem1="25" tem2="14" temNow="27" windState="微風(fēng)" windDir="西風(fēng)" windPower="1級" humidity="34%" time="15:30" url="101280201"/>
<city cityX="353" cityY="196" cityname="廣州" centername="廣州" fontColor="FFFF00" pyName="guangzhou" state1="0" state2="0" stateDetailed="晴" tem1="26" tem2="14" temNow="26" windState="微風(fēng)" windDir="南風(fēng)" windPower="1級" humidity="40%" time="15:20" url="101280101"/>
<city cityX="377" cityY="234" cityname="東莞" centername="東莞" fontColor="FFFFFF" pyName="dongguan" state1="0" state2="1" stateDetailed="晴轉(zhuǎn)多云" tem1="25" tem2="15" temNow="26" windState="微風(fēng)" windDir="北風(fēng)" windPower="1級" humidity="37%" time="15:30" url="101281601"/>
<city cityX="409" cityY="257" cityname="深圳" centername="深圳" fontColor="FFFFFF" pyName="shenzhen" state1="0" state2="0" stateDetailed="晴" tem1="24" tem2="15" temNow="24" windState="微風(fēng)" windDir="南風(fēng)" windPower="3級" humidity="49%" time="15:30" url="101280601"/>
<city cityX="423.85" cityY="214.65" cityname="惠州" centername="惠州" fontColor="FFFFFF" pyName="huizhou" state1="1" state2="0" stateDetailed="多云轉(zhuǎn)晴" tem1="26" tem2="13" temNow="26" windState="微風(fēng)" windDir="南風(fēng)" windPower="1級" humidity="38%" time="15:20" url="101280301"/>
<city cityX="442.55" cityY="141.6" cityname="河源" centername="河源" fontColor="FFFFFF" pyName="heyuan" state1="0" state2="1" stateDetailed="晴轉(zhuǎn)多云" tem1="25" tem2="15" temNow="27" windState="微風(fēng)" windDir="西南風(fēng)" windPower="1級" humidity="37%" time="15:30" url="101281201"/>
<city cityX="492" cityY="217" cityname="汕尾" centername="汕尾" fontColor="FFFFFF" pyName="shanwei" state1="1" state2="0" stateDetailed="多云轉(zhuǎn)晴" tem1="24" tem2="14" temNow="24" windState="東南風(fēng)3-4級轉(zhuǎn)微風(fēng)" windDir="東風(fēng)" windPower="2級" humidity="45%" time="15:30" url="101282101"/>
<city cityX="522.55" cityY="110.45" cityname="梅州" centername="梅州" fontColor="FFFFFF" pyName="meizhou" state1="1" state2="0" stateDetailed="多云轉(zhuǎn)晴" tem1="27" tem2="12" temNow="26" windState="微風(fēng)" windDir="東風(fēng)" windPower="1級" humidity="36%" time="15:30" url="101280401"/>
<city cityX="526.8" cityY="182" cityname="揭陽" centername="揭陽" fontColor="FFFFFF" pyName="jieyang" state1="0" state2="0" stateDetailed="晴" tem1="26" tem2="13" temNow="26" windState="微風(fēng)" windDir="東風(fēng)" windPower="2級" humidity="34%" time="15:30" url="101281901"/>
<city cityX="579" cityY="137.45" cityname="潮州" centername="潮州" fontColor="FFFFFF" pyName="chaozhou" state1="0" state2="0" stateDetailed="晴" tem1="25" tem2="12" temNow="26" windState="微風(fēng)" windDir="東南風(fēng)" windPower="2級" humidity="38%" time="15:30" url="101281501"/>
<city cityX="566.45" cityY="179.25" cityname="汕頭" centername="汕頭" fontColor="FFFFFF" pyName="shantou" state1="0" state2="1" stateDetailed="晴轉(zhuǎn)多云" tem1="24" tem2="13" temNow="24" windState="東北風(fēng)轉(zhuǎn)東風(fēng)小于3級" windDir="東風(fēng)" windPower="2級" humidity="54%" time="15:30" url="101280501"/>
</guangdong>

③ 調(diào)用XMLRequest,并加入RequestQueue
代碼中我將解析XML數(shù)據(jù)的城市展示在List View中:

 XMLRequest xmlRequest = new XMLRequest(
                "http://flash.weather.com.cn/wmaps/xml/guangdong.xml",
                new Response.Listener<XmlPullParser>() {
                    @Override
                    public void onResponse(XmlPullParser response) {
                        try {
                            int eventType = response.getEventType();
                            while (eventType != XmlPullParser.END_DOCUMENT) {
                                switch (eventType) {
                                    case XmlPullParser.START_TAG:
                                        String nodeName = response.getName();
                                        if ("city".equals(nodeName)) {
                                            String pname = response.getAttributeValue(2);
                                            Log.d("CITY", "PName is" + pname);
                                            citys.add(pname);
                                        }
                                        break;
                                }
                                eventType = response.next();
                            }

                            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(XMLRequestActivity.this, android.R.layout.simple_list_item_1, citys);
                            lv_xml_request.setAdapter(arrayAdapter);
                        } catch (XmlPullParserException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        lv_xml_request.setVisibility(View.GONE);
                        mTextView.setVisibility(View.VISIBLE);
                        Log.d("ERROR", "返回XMLRequest失敗");
                    }
                }
        );
        mQueue.add(xmlRequest);
    }

人品爆發(fā),看截圖

XMLRequest

自定義GsonRequest

雖然Volley提供了JsonRequest為我們解析Json,但是使用JSONObject還是太麻煩了,還有很多方法可以讓JSON數(shù)據(jù)解析變得更加簡單,比如說GSON,所以何不如自定義一個GsonRequest呢?思路也是大同小異!

① 直接上代碼啦!

public class GsonRequest<T> extends Request<T> {

    private final Response.Listener<T> mListener;
    private Gson mGson;
    private Class<T> mClazz;

    public GsonRequest(int method, String url, Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
        super(method, url, errorListener);
        mGson = new Gson();
        mClazz = clazz;
        mListener = listener;
    }

    public GsonRequest(String url, Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
        this(Method.GET, url, clazz, listener, errorListener);
    }


    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            response.headers.put("HTTP.CONTENT_TYPE", "utf-8");
            String jsonString = new String(response.data,"utf-8");
            //加上這兩行可以解決亂碼的問題,尤其是對于中文的json接口,由于每個網(wǎng)頁的編碼格式不同,所以獲取原編碼格式之后再轉(zhuǎn)換為utf-8,即可。
            return Response.success(mGson.fromJson(jsonString, mClazz),
                    HttpHeaderParser.parseCacheHeaders(response)
            );
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        }
    }

    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);
    }
}

同樣需要注意編碼的問題。在parseNetworkResponse()方法中,先是將服務(wù)器響應(yīng)的數(shù)據(jù)解析出來,然后通過調(diào)用Gson的fromJson方法將數(shù)據(jù)組裝成對象。在deliverResponse方法中仍然是將最終的數(shù)據(jù)進(jìn)行回調(diào)。

  • 記得為工程加入gson庫
compile 'com.google.code.gson:gson:2.8.0'

② json接口
使用之前使用的json接口:http://www.weather.com.cn/data/sk/101010100.html ,它返回的數(shù)據(jù)是一個叫做weatherinfo的jsonObject:

{"weatherinfo":{"city":"北京","cityid":"101010100","temp":"19","WD":"南風(fēng)","WS":"2級","SD":"43%","WSE":"2","time":"19:45","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB"}} 

③ 新建bean類
由于返回的jsonObject名字叫做weatherinfo,所以我們新建一個WeatherInfo類,定義了幾個最基本的屬性就行了:

public class WeatherInfo{
    private String city;
    private String temp;
    private String time;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getTemp() {
        return temp;
    }

    public void setTemp(String temp) {
        this.temp = temp;
    }

    public String gettime() {
        return time;
    }

    public void settime(String time) {
        this.time = time;
    }
}

另外還需要再定義一個Weather類,來獲取WeatherInfo對象:

public class Weather {
    //此處的weatherinfo不可以修改為weatherInfo,因?yàn)閺膉son獲取的數(shù)據(jù)格式為
    // {"weatherinfo":{"city":"北京","cityid":"101010100","temp":"19","WD":"南風(fēng)","WS":"2級","SD":"43%","WSE":"2","time":"19:45","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB"}}
    private WeatherInfo weatherinfo;

    public WeatherInfo getWeatherInfo() {
        return weatherinfo;
    }

    public void setWeatherInfo(WeatherInfo weatherinfo) {
        this.weatherinfo = weatherinfo;
    }
}

此處的weatherinfo不可以修改為weatherInfo

④調(diào)用GsonRequest
我們將獲取的數(shù)據(jù)顯示在Text View上就行了。

GsonRequest<Weather> gsonRequest=new GsonRequest<Weather>("http://www.weather.com.cn/data/sk/101010100.html"
                , Weather.class,
                new Response.Listener<Weather>() {
                    @Override
                    public void onResponse(Weather weather) {
                        WeatherInfo weatherInfo = weather.getWeatherInfo();
                        if (weatherInfo != null) {
                            StringBuffer str = new StringBuffer();
                            str.append("城市:" + weatherInfo.getCity() + "\n");
                            str.append("溫度:" + weatherInfo.getTemp() + "\n");
                            str.append("時間:" + weatherInfo.gettime());
                            tv_gson_request.setText(str);
                            Log.d("SUCCESS", "成功返回GsonRequest  " + str.toString());
                        } else {
                            Log.d("ERROR", "weatherinfo對象為空");
                        }
                    }
                }
                , new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("ERROR", "返回GsonRequest失敗");
                tv_gson_request.setText(getResources().getString(R.string.error_message));
            }
        }
        );

mQueue.add(gsonRequest);

看截圖啦!

GsonRequest

這一節(jié)只是向大家介紹了如何自定義Request,其實(shí)都是大同小異的,例如你覺得Gson不能滿足你,那你也可以改為FastJson或者其他的功能,但是請一定要注意編碼問題!最后一節(jié)我們將一起通過閱讀源碼來分析Volley的工作流程!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評論 2 374

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