WebService使用实例

WebService使用实例

大家好,又见面了,我是全栈君。

近期刚刚開始学习使用WebService的方法进行server端数据交互,发现网上的资料不是非常全,

眼下就结合收集到的一些资料做了一个小样例和大家分享一下~

我们在PC机器javaclient中。须要一些库,比方XFire,Axis2,CXF等等来支持訪问WebService,可是这些库并不适合我们资源有限的android手机client,做过JAVA ME的人都知道有KSOAP这个第三方的类库。能够帮助我们获取server端webService调用,当然KSOAP已经提供了基于android版本号的jar包了。那么我们就開始吧:

首先下载KSOAP包:ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar包      下载地址         点击进入代码下载

然后新建android项目:并把下载的KSOAP包放在android项目的lib文件夹下:右键->build path->configure build path–选择Libraries。如图:

WebService使用实例

 

同一时候,仅仅加入jar包肯能是不够的,须要加入class folder,即能够再project的libs目录中加入下载的KSOAP包,如图:

WebService使用实例  

WebService使用实例

 

环境配好之后能够用以下七个步骤来调用WebService方法:

第一:实例化SoapObject对象。指定webService的命名空间(从相关WSDL文档中能够查看命名空间),以及调用方法名称。

如:

//命名空间
privatestatic final String serviceNameSpace=“http://WebXml.com.cn/”;
//调用方法(获得支持的城市)
privatestatic final String getSupportCity=“getSupportCity”;

//实例化SoapObject对象
SoapObject request=new SoapObject(serviceNameSpace, getSupportCity);

第二步:如果方法有參数的话,设置调用方法參数:

request.addProperty(參数名称,參数值);

第三步:设置SOAP请求信息(參数部分为SOAP协议版本,与你要调用的webService中版本一致)

//获得序列化的Envelope
SoapSerializationEnvelope envelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut=request;

第四步:注冊Envelope

(new MarshalBase64()).register(envelope);

第五步:构建传输对象,并指明WSDL文档URL

//请求URL
privatestatic final String serviceURL=“http://www.webxml.com.cn/webservices/weatherwebservice.asmx”;
//Android传输对象
AndroidHttpTransport transport=new AndroidHttpTransport(serviceURL);
transport.debug=true;

第六步:调用WebService(当中參数为1:命名空间+方法名称,2Envelope对象)

transport.call(serviceNameSpace+getWeatherbyCityName, envelope);

第七步:解析返回数据:

if(envelope.getResponse()!=null){
                return parse(envelope.bodyIn.toString());
            }

这里有个地址提供webService天气预报的服务站点。在浏览器中输入站点:http://www.webxml.com.cn/webservices/weatherwebservice.asmx能够看到该站点提供的

调用方法,点进去之后能够看到调用时须要输入的參数,当然有的不须要參数,比如:getSupportProvince 。而getSupportCity须要输入查找的省份名,getWeatherbyCityName 须要输入查找的城市名。接下来我们就利用这三个接口获得数据,并做出显示:

获得本天气预报Web Service支持的洲,国内外省份和城市信息:

[html] 
view plain
copy
print
?

  1. public class MainActivity extends Activity {  
  2.     // WSDL文档中的命名空间  
  3.     private static final String targetNameSpace = “http://WebXml.com.cn/”;  
  4.     // WSDL文档中的URL  
  5.     private static final String WSDL = “http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl”;  
  6.   
  7.     // 须要调用的方法名(获得本天气预报Web Services支持的洲、国内外省份和城市信息)  
  8.     private static final String getSupportProvince = “getSupportProvince”;  
  9.     private List<Map<String,String>> listItems;  
  10.     private ListView mListView;  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         listItems = new ArrayList<Map<String,String>>();  
  17.         mListView = (ListView) findViewById(R.id.province_list);  
  18.         new NetAsyncTask().execute();  
  19.         mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  20.   
  21.             @Override  
  22.             public void onItemClick(AdapterView<?

    > parent, View view,  

  23.                     int position, long id) {  
  24.                 String mProvinceName = listItems.get(position).get(“province”);  
  25.                 Log.d(“ProvinceName”, mProvinceName);  
  26.                 Intent intent = new Intent();  
  27.                 intent.putExtra(“Pname”, mProvinceName);  
  28.                 intent.setClass(MainActivity.this, CityActivity.class);  
  29.                 startActivity(intent);  
  30.             }  
  31.               
  32.         });  
  33.     }  
  34.   
  35.     class NetAsyncTask extends AsyncTask<Object, Object, String> {  
  36.   
  37.         @Override  
  38.         protected void onPostExecute(String result) {  
  39.             if (result.equals(“success”)) {  
  40.                 //列表适配器  
  41.                 SimpleAdapter simpleAdapter = new SimpleAdapter(MainActivity.this, listItems, R.layout.province_item,   
  42.                         new String[] {“province”}, new int[]{R.id.province});  
  43.                 mListView.setAdapter(simpleAdapter);  
  44.             }  
  45.             super.onPostExecute(result);  
  46.         }  
  47.   
  48.         @Override  
  49.         protected String doInBackground(Object… params) {  
  50.             // 依据命名空间和方法得到SoapObject对象  
  51.             SoapObject soapObject = new SoapObject(targetNameSpace,  
  52.                     getSupportProvince);  
  53.             // 通过SOAP1.1协议得到envelop对象  
  54.             SoapSerializationEnvelope envelop = new SoapSerializationEnvelope(  
  55.                     SoapEnvelope.VER11);  
  56.             // 将soapObject对象设置为envelop对象,传出消息  
  57.   
  58.             envelop.dotNet = true;  
  59.             envelop.setOutputSoapObject(soapObject);  
  60.             // 或者envelop.bodyOut = soapObject;  
  61.             HttpTransportSE httpSE = new HttpTransportSE(WSDL);  
  62.             // 開始调用远程方法  
  63.             try {  
  64.                 httpSE.call(targetNameSpace + getSupportProvince, envelop);  
  65.                 // 得到远程方法返回的SOAP对象  
  66.                 SoapObject resultObj = (SoapObject) envelop.getResponse();  
  67.                 // 得到server传回的数据  
  68.                 int count = resultObj.getPropertyCount();  
  69.                 for (int i = 0; i < count; i++) {  
  70.                     Map<String,String> listItem = new HashMap<String, String>();  
  71.                     listItem.put(“province”, resultObj.getProperty(i).toString());  
  72.                     listItems.add(listItem);  
  73.                 }  
  74.             } catch (IOException e) {  
  75.                 e.printStackTrace();  
  76.                 return “IOException”;  
  77.             } catch (XmlPullParserException e) {  
  78.                 e.printStackTrace();  
  79.                 return “XmlPullParserException”;  
  80.             }  
  81.             return “success”;  
  82.         }  
  83.     }  
  84. }  

显示省份列表的activity_main.xml文件:

[html] 
view plain
copy
print
?

  1. <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
  2.     android:layout_width=“fill_parent”  
  3.     android:layout_height=“match_parent” >  
  4.   
  5.     <ListView   
  6.         android:id=“@+id/province_list”  
  7.         android:layout_width=“fill_parent”  
  8.         android:layout_height=“fill_parent”/>  
  9.   
  10. </LinearLayout>  

列表中选项显示的province_item.xml文件:

  1. <?

    xml version=“1.0” encoding=“utf-8”?

    >  

  2. <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
  3.     android:layout_width=“match_parent”  
  4.     android:layout_height=“match_parent”  
  5.     android:orientation=“vertical” >  
  6.       
  7.     <TextView   
  8.         android:id=“@+id/province”  
  9.         android:layout_width=“fill_parent”  
  10.         android:layout_height=“match_parent”  
  11.         android:textSize=“20sp”/>  
  12.   
  13. </LinearLayout>  

效果图。如图:

WebService使用实例

 

查询本天气预报Web Services支持的国内外城市或地区信息:

  1. public class CityActivity extends Activity {  
  2.     // WSDL文档中的命名空间  
  3.     private static final String targetNameSpace = “http://WebXml.com.cn/”;  
  4.     // WSDL文档中的URL  
  5.     private static final String WSDL = “http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl”;  
  6.   
  7.     // 须要调用的方法名(获得本天气预报Web Services支持的城市信息,依据省份查询城市集合:带參数)  
  8.     private static final String getSupportCity = “getSupportCity”;  
  9.     private List<Map<String,String>> listItems;  
  10.     private ListView mListView;  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         listItems = new ArrayList<Map<String,String>>();  
  17.         mListView = (ListView) findViewById(R.id.province_list);  
  18.         new NetAsyncTask().execute();  
  19.         //列表单击事件监听  
  20.         mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  21.   
  22.             @Override  
  23.             public void onItemClick(AdapterView<?> parent, View view,  
  24.                     int position, long id) {  
  25.                 String mCityName = listItems.get(position).get(“city”);  
  26.                 String cityName = getCityName(mCityName);  
  27.                 Log.d(“CityName”, cityName);  
  28.                 Intent intent = new Intent();  
  29.                 //存储选择的城市名  
  30.                 intent.putExtra(“Cname”, cityName);  
  31.                 intent.setClass(CityActivity.this, WeatherActivity.class);  
  32.                 startActivity(intent);  
  33.             }  
  34.               
  35.         });  
  36.     }  
  37.     /** 
  38.      * 拆分“城市 (代码)”字符串,将“城市”字符串分离 
  39.      * @param name 
  40.      * @return 
  41.      */  
  42.     public String getCityName(String name) {  
  43.         String city = “”;  
  44.         int position = name.indexOf(‘ ‘);  
  45.         city = name.substring(0, position);  
  46.         return city;  
  47.     }  
  48.   
  49.     class NetAsyncTask extends AsyncTask<Object, Object, String> {  
  50.   
  51.         @Override  
  52.         protected void onPostExecute(String result) {  
  53.             if (result.equals(“success”)) {  
  54.                 //列表适配器  
  55.                 SimpleAdapter simpleAdapter = new SimpleAdapter(CityActivity.this, listItems, R.layout.province_item,   
  56.                         new String[] {“city”}, new int[]{R.id.province});  
  57.                 mListView.setAdapter(simpleAdapter);  
  58.             }  
  59.             super.onPostExecute(result);  
  60.         }  
  61.   
  62.         @Override  
  63.         protected String doInBackground(Object… params) {  
  64.             // 依据命名空间和方法得到SoapObject对象  
  65.             SoapObject soapObject = new SoapObject(targetNameSpace,getSupportCity);  
  66.             //參数输入  
  67.             String name = getIntent().getExtras().getString(“Pname”);  
  68.             soapObject.addProperty(“byProvinceName”, name);  
  69.             // 通过SOAP1.1协议得到envelop对象  
  70.             SoapSerializationEnvelope envelop = new SoapSerializationEnvelope(  
  71.                     SoapEnvelope.VER11);  
  72.             // 将soapObject对象设置为envelop对象,传出消息  
  73.             envelop.dotNet = true;  
  74.             envelop.setOutputSoapObject(soapObject);  
  75.             HttpTransportSE httpSE = new HttpTransportSE(WSDL);  
  76.             // 開始调用远程方法  
  77.             try {  
  78.                 httpSE.call(targetNameSpace + getSupportCity, envelop);  
  79.                 // 得到远程方法返回的SOAP对象  
  80.                 SoapObject resultObj = (SoapObject) envelop.getResponse();  
  81.                 // 得到server传回的数据  
  82.                 int count = resultObj.getPropertyCount();  
  83.                 for (int i = 0; i < count; i++) {  
  84.                     Map<String,String> listItem = new HashMap<String, String>();  
  85.                     listItem.put(“city”, resultObj.getProperty(i).toString());  
  86.                     listItems.add(listItem);  
  87.                 }  
  88.             } catch (IOException e) {  
  89.                 e.printStackTrace();  
  90.                 return “IOException”;  
  91.             } catch (XmlPullParserException e) {  
  92.                 e.printStackTrace();  
  93.                 return “XmlPullParserException”;  
  94.             }  
  95.             return “success”;  
  96.         }  
  97.     }  
  98. }  

用于列表显示的xml反复使用,这里就不再反复写一次了,效果图。如图:

WebService使用实例

最后,依据选择的城市或地区名称获得天气情况:

  1. public class WeatherActivity extends Activity {  
  2.     //WSDL文档中的命名空间  
  3.     private static final String targetNameSpace=“http://WebXml.com.cn/”;  
  4.     //WSDL文档中的URL  
  5.     private static final String WSDL=“http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl”;  
  6.     //依据城市或地区名称查询获得未来三天内天气情况、如今的天气实况、天气和生活指数  
  7.     private static final String getWeatherbyCityName=“getWeatherbyCityName”;  
  8.     WeatherBean mWBean;  
  9.     private ImageView mImageView;  
  10.     private EditText mCityName;  
  11.     private EditText mTemp;  
  12.     private EditText mWeather;  
  13.     private TextView mToday;  
  14.     private TextView mDetail;  
  15.     private int Image[];  
  16.       
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.weather);  
  21.         Image = new int[]{R.drawable.image0,R.drawable.image1,R.drawable.image2,  
  22.                 R.drawable.image3,R.drawable.image4,R.drawable.image5,  
  23.                 R.drawable.image6,R.drawable.image7,R.drawable.image8,  
  24.                 R.drawable.image9,R.drawable.image10,R.drawable.image11,  
  25.                 R.drawable.image12,R.drawable.image13,R.drawable.image14,  
  26.                 R.drawable.image15,R.drawable.image16,R.drawable.image17,  
  27.                 R.drawable.image18,R.drawable.image19,R.drawable.image20,  
  28.                 R.drawable.image21,R.drawable.image22,R.drawable.image23,  
  29.                 R.drawable.image24,R.drawable.image25,R.drawable.image26,  
  30.                 R.drawable.image27};  
  31.         mWBean = new WeatherBean();  
  32.         mImageView = (ImageView) findViewById(R.id.picture);  
  33.         mCityName = (EditText) findViewById(R.id.city_name);  
  34.         mTemp = (EditText) findViewById(R.id.temp);  
  35.         mWeather = (EditText) findViewById(R.id.weather);  
  36.         mToday = (TextView) findViewById(R.id.today_weather);  
  37.         mDetail = (TextView) findViewById(R.id.city_detail);  
  38.         new NetAsyncTask().execute();  
  39.           
  40.     }  
  41.       
  42.     class NetAsyncTask extends AsyncTask<Object, Object, String> {  
  43.   
  44.         @Override  
  45.         protected void onPostExecute(String result) {  
  46.             String image = mWBean.getWeatherPicture();  
  47.             int position = getImageId(image);  
  48.             Log.d(“image”, Image[position]+“”);  
  49.             mImageView.setImageResource(Image[position]);  
  50.             mCityName.setText(mWBean.getCityName());  
  51.             mTemp.setText(mWBean.getTemp());  
  52.             mWeather.setText(mWBean.getWeather());  
  53.             mToday.setText(mWBean.getLiveWeather());  
  54.             mDetail.setText(mWBean.getCityDetail());  
  55.             super.onPostExecute(result);  
  56.         }  
  57.           
  58.         public int getImageId(String picture) {  
  59.             int id = 0;  
  60.             int tempId = picture.indexOf(‘.’);  
  61.             String sub = picture.substring(0, tempId);  
  62.             id = Integer.parseInt(sub);  
  63.             return id;  
  64.         }  
  65.   
  66.         @Override  
  67.         protected String doInBackground(Object… params) {  
  68.             // 依据命名空间和方法得到SoapObject对象  
  69.             SoapObject soapObject = new SoapObject(targetNameSpace,getWeatherbyCityName);  
  70.             String city = getIntent().getExtras().getString(“Cname”);  
  71.             soapObject.addProperty(“theCityName”,city);//调用的方法參数与參数值(依据详细须要可选可不选)  
  72.             // 通过SOAP1.1协议得到envelop对象  
  73.             SoapSerializationEnvelope envelop = new SoapSerializationEnvelope(SoapEnvelope.VER11);  
  74.             // 将soapObject对象设置为envelop对象,传出消息  
  75.   
  76.             envelop.dotNet = true;  
  77.             envelop.setOutputSoapObject(soapObject);  
  78.             // 或者envelop.bodyOut = soapObject;  
  79.             HttpTransportSE httpSE = new HttpTransportSE(WSDL);  
  80.             // 開始调用远程方法  
  81.             try {  
  82.                 httpSE.call(targetNameSpace + getWeatherbyCityName, envelop);  
  83.                 // 得到远程方法返回的SOAP对象  
  84.                 SoapObject resultObj = (SoapObject) envelop.getResponse();  
  85.                 // 得到server传回的数据  
  86.                 mWBean.setCityName(resultObj.getProperty(1).toString());  
  87.                 mWBean.setTemp(resultObj.getProperty(5).toString());  
  88.                 mWBean.setWeather(resultObj.getProperty(6).toString());  
  89.                 mWBean.setWeatherPicture(resultObj.getProperty(8).toString());  
  90.                 mWBean.setLiveWeather(resultObj.getProperty(10).toString());  
  91.                 mWBean.setCityDetail(resultObj.getProperty(22).toString());  
  92.                   
  93.             } catch (IOException e) {  
  94.                 e.printStackTrace();  
  95.                 return “IOException”;  
  96.             } catch (XmlPullParserException e) {  
  97.                 e.printStackTrace();  
  98.                 return “XmlPullParserException”;  
  99.             }  
  100.             return “success”;  
  101.         }  
  102.     }  
  103. }  

这里没有显示所有的信息,提供了一个存储部分天气信息的类:

[java] 
view plain
copy
print
?

  1. public class WeatherBean {  
  2.     private String CityName;  
  3.     private String Temp;  
  4.     private String Weather;  
  5.     private String WeatherPicture;  
  6.     private String LiveWeather;  
  7.     private String CityDetail;  
  8.     public String getCityName() {  
  9.         return CityName;  
  10.     }  
  11.     public void setCityName(String cityName) {  
  12.         CityName = cityName;  
  13.     }  
  14.     public String getLiveWeather() {  
  15.         return LiveWeather;  
  16.     }  
  17.     public void setLiveWeather(String liveWeather) {  
  18.         LiveWeather = liveWeather;  
  19.     }  
  20.       
  21.     public String getTemp() {  
  22.         return Temp;  
  23.     }  
  24.     public void setTemp(String temp) {  
  25.         Temp = temp;  
  26.     }  
  27.     public String getWeather() {  
  28.         return Weather;  
  29.     }  
  30.     public void setWeather(String weather) {  
  31.         Weather = weather;  
  32.     }  
  33.     public String getWeatherPicture() {  
  34.         return WeatherPicture;  
  35.     }  
  36.     public void setWeatherPicture(String weatherPicture) {  
  37.         WeatherPicture = weatherPicture;  
  38.     }  
  39.     public String getCityDetail() {  
  40.         return CityDetail;  
  41.     }  
  42.     public void setCityDetail(String cityDetail) {  
  43.         CityDetail = cityDetail;  
  44.     }  
  45. }  

 

显示天气状况的weather.xml文件:

[html] 
view plain
copy
print
?

  1. <?

    xml version=“1.0” encoding=“utf-8”?>  

  2. <ScrollView xmlns:android=“http://schemas.android.com/apk/res/android”  
  3.     android:layout_width=“match_parent”  
  4.     android:layout_height=“match_parent”  
  5.     android:orientation=“vertical” >  
  6.   
  7.     <LinearLayout  
  8.         android:layout_width=“fill_parent”  
  9.         android:layout_height=“wrap_content”  
  10.         android:orientation=“vertical” >  
  11.   
  12.         <TableLayout  
  13.             android:layout_width=“fill_parent”  
  14.             android:layout_height=“wrap_content” >  
  15.               
  16.             <TableRow>  
  17.   
  18.                 <TextView  
  19.                     android:layout_width=“fill_parent”  
  20.                     android:layout_height=“wrap_content”  
  21.                     android:text=“天气实况:”  
  22.                     android:textSize=“16sp” />  
  23.   
  24.                 <ImageView  
  25.                     android:id=“@+id/picture”  
  26.                     android:layout_width=“wrap_content”  
  27.                     android:layout_height=“wrap_content” />  
  28.             </TableRow>  
  29.   
  30.             <TableRow>  
  31.   
  32.                 <TextView  
  33.                     android:layout_width=“wrap_content”  
  34.                     android:layout_height=“wrap_content”  
  35.                     android:layout_weight=“1”  
  36.                     android:text=“城市:”  
  37.                     android:textSize=“16sp” />  
  38.   
  39.                 <EditText  
  40.                     android:id=“@+id/city_name”  
  41.                     android:layout_width=“wrap_content”  
  42.                     android:layout_height=“wrap_content”  
  43.                     android:layout_weight=“2”  
  44.                     android:hint=“城市名称”  
  45.                     android:editable=“false” />  
  46.             </TableRow>  
  47.   
  48.             <TableRow>  
  49.   
  50.                 <TextView  
  51.                     android:layout_width=“wrap_content”  
  52.                     android:layout_height=“wrap_content”  
  53.                     android:layout_weight=“1”  
  54.                     android:text=“温度:”  
  55.                     android:textSize=“16sp” />  
  56.   
  57.                 <EditText  
  58.                     android:id=“@+id/temp”  
  59.                     android:layout_width=“wrap_content”  
  60.                     android:layout_height=“wrap_content”  
  61.                     android:layout_weight=“2”  
  62.                     android:hint=“今日气温”  
  63.                     android:editable=“false” />  
  64.             </TableRow>  
  65.   
  66.             <TableRow>  
  67.   
  68.                 <TextView  
  69.                     android:layout_width=“wrap_content”  
  70.                     android:layout_height=“wrap_content”  
  71.                     android:layout_weight=“1”  
  72.                     android:text=“天气:”  
  73.                     android:textSize=“16sp” />  
  74.   
  75.                 <EditText  
  76.                     android:id=“@+id/weather”  
  77.                     android:layout_width=“wrap_content”  
  78.                     android:layout_height=“wrap_content”  
  79.                     android:layout_weight=“2”  
  80.                     android:hint=“今日天气”  
  81.                     android:editable=“false” />  
  82.             </TableRow>  
  83.   
  84.         </TableLayout>  
  85.   
  86.         <TextView  
  87.             android:id=“@+id/today_weather”  
  88.             android:layout_width=“fill_parent”  
  89.             android:layout_height=“wrap_content”  
  90.             android:textSize=“16sp” />  
  91.   
  92.         <TextView  
  93.             android:layout_width=“fill_parent”  
  94.             android:layout_height=“wrap_content”  
  95.             android:text=“城市简单介绍:”  
  96.             android:textSize=“16sp” />  
  97.   
  98.         <TextView  
  99.             android:id=“@+id/city_detail”  
  100.             android:layout_width=“fill_parent”  
  101.             android:layout_height=“wrap_content”  
  102.             android:textSize=“16sp” />  
  103.     </LinearLayout>  
  104.   
  105. </ScrollView>  

效果图如图:

WebService使用实例

这里很多功能做得不是非常完好,大家能够依据自己的须要进行设计~

点击进入代码下载

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/115223.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号