如何使用http或httpClient向服务器上传图片 以及使用http上传图片时协议的描述



向服务器上传图片的实例:

  在Java web中上传图片相对比较容易,只需简单几个按钮和应用即可,以下的例子是如何使用http或httpClient向本地服务器上传图片。


1.网页版

   在本地创建一个Java web项目并上传图片到本地服务器。服务器版本须为3.0,一般Tomcat7.0以上。

  创建web项目 uploadImage,在 webContent目录下创建index.jsp,body中的代码为:

[java]  view plain  copy
  1. <form action="Uploadimage" method="post" enctype="multipart/form-data">  
  2.    <input type="file" name="file"><br>  
  3.    <input type="submit" value="submit">  
  4.   
  5. </form>  


指定数据类型:enctype="multipart/form-data",使用multipart/form-data最后数据会以二进制形式提交给服务器,字符不需要编码不会对服务端的获取有影响。

表单中enctype类型默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传。

具体请参考:http://blog.csdn.NET/MSPinyin/article/details/6141638


创建一个servlet:Uploadimage.jave,需要注意的是在Uploadimage类的上方中需要再添加一个注解标签来指定文件保存的路径,不然会在添加文件上传时报空指针异常。

注解标签为:@MultipartConfig(location="E://"),以下是添加地方。

[java]  view plain  copy
  1. @WebServlet("/Uploadimage")  
  2. @MultipartConfig(location="E://")  
  3. public class Uploadimage extends HttpServlet {  

添加完标签以后在doGet方法中调用doPost方法,在doPost方法中写入以下代码:

[java]  view plain  copy
  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  2.       
  3.       
  4.     //将当前系统时间作为文件的名称避免重名  
  5.     //Date data=new Date();  
  6.     SimpleDateFormat adf=new SimpleDateFormat("HHmmss");  
  7.     String filename=adf.format(new Date());  
  8.     Part part=request.getPart("file");//获取文件路径  
  9.     part.write(filename+".jpg");  
  10.       
  11.     response.setCharacterEncoding("UTF-8");  
  12.     PrintWriter out=response.getWriter();  
  13.     out.print("success!");  
  14.     System.out.print("上传成功!");  
  15. }  
注意,Part,引入的包为:
[java]  view plain  copy
  1. import javax.servlet.http.Part;  


完成以上以后,将web项目运行在服务器上。在web页面选择图片并点击上传,会在你的E盘上生成一个以时间为命名的jsp图片。

至此,通过java web上传图片的例子结束,以下是如何在Android客户端通过http上传图片。


2.通过http从Android客户端上传图片,在这之前,需要先了解在网页上是如何通过multipart/form-data来传输数据的。


打开浏览器,在地址栏输入我们以上网页版的web项目地址:http://localhost:8080/uploadImage,在浏览器:工具----》开发者工具---》网络---》启用网络流量捕获,然后选择文件,提交。

回到开发者工具后会检测到一个刚提交的数据:


双击打开,会在content-type看到一个编节符的请求头文件信息,点击上方的请求正文,将会看到以下内容,这个内容也将是待会使用http进行图片上传时需要转化数据格式。



需要指出的是,由于浏览器的原因,以上的编节符前面并不是一条直线,而是虚线:

-----------------------------7e020233150564,这个一般由系统随机产生,且开头增加了两个"-",减去这两个”-“就是一个"boundary",boundary这待会会用到的。

Content-Type:image/jpeg  就是文件的 类型。

<二进制文件数据未显示>:这一部分就是上传的图片。

以上的就是通过这样的协议向服务器发送数据。客户端向服务器发送数据时也需要遵守这样的协议。


了解了上传的协议描述后,接下来将是进行代码:

创建项目UploadImageDome,并创建UploadThread.java 类,让该类继承Thread:

创建方法:httpUpload();//该方法中写的是通过http方式上传图片,代码为:

[java]  view plain  copy
  1. public void httpUpload(){  
  2.         String boundary="-------------------------7e020233150564";//编节符  
  3.         String prefix="--";//前缀 上传时需要多出两个-- 一定需要注意!!!  
  4.         String end="\r\n";//这里也需要注意,在html协议中,用 “/r/n” 换行,而不是 “/n”。  
  5.   
  6.         SimpleDateFormat adf=new SimpleDateFormat("HHmmss");//通过时间来创建文件名  
  7.         String uploadname=adf.format(new Date())+".jsp";//上传的文件名称  
  8.   
  9.         try {  
  10.             URL http=new URL(murl);  
  11.             HttpURLConnection conn= (HttpURLConnection) http.openConnection();  
  12.             conn.setRequestMethod("POST");  
  13.             conn.setReadTimeout(5000);  
  14.             conn.setDoInput(true);//准许向服务器读数据  
  15.             conn.setDoOutput(true);//准许向服务器写入数据  
  16.   
  17.             /*设置向服务器上传数据的请求方式  默认的是表单形式 
  18.             * 通过Content-Type协议向服务器上传数据 
  19.             * boundary 
  20.             * */  
  21.             conn.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);  
  22.   
  23.             //创建一个输出流对象,  
  24.             DataOutputStream out=new DataOutputStream(conn.getOutputStream());  
  25.             /* 
  26.             * 
  27.               -----------------------------7e020233150564 
  28.               Content-Disposition: form-data; name="file"; filename="I:\迅雷下载\18fb1f51c9eb63489cce9e029154782e.jpg" 
  29.               Content-Type: image/jpeg 
  30.                                         //这里是空一行  需要注意 
  31.               <二进制文件数据未显示> 
  32.               ---------------------------7e020233150564-- 
  33.               */  
  34.             //向服务器写入数据  这里就需要完全根据以上协议格式来写,需要仔细,避免出错。  
  35.             out.writeBytes(prefix+boundary+end);//这是第一行  并回车换行  
  36.             //这是第二行,文件名和对应服务器的  
  37.             out.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\""+uploadname+"\""+end);//这是第二行  
  38.             out.writeBytes(end);//空一行  
  39.             //以下写入图片  
  40.             FileInputStream fileInputStream=new FileInputStream(new File(mfilename));  
  41.             byte[]b=new byte[1024*4];//缓冲区  
  42.             int len;  
  43.             //循环读数据  
  44.             while((len=fileInputStream.read(b))!=-1){  
  45.                 out.write(b, 0, len);  
  46.             }  
  47.             //写完数据后 回车换行  
  48.             out.writeBytes(end);  
  49.             out.writeBytes(prefix + boundary + prefix + end);  
  50.             out.flush();//清空  
  51.   
  52.             //创建一个输入流对象  获取返回的信息  是否上传成功  
  53.             BufferedReader reader=new BufferedReader(new InputStreamReader(conn.getInputStream()));  
  54.             StringBuffer sb=new StringBuffer();  
  55.             String str;  
  56.             while((str=reader.readLine())!=null){  
  57.                 sb.append(str);  
  58.             }  
  59.             //关闭流信息  
  60.             if(out!=null)out.close();  
  61.             if(reader!=null)reader.close();  
  62.   
  63.             System.out.print("返回结果:"+sb.toString());  
  64.         } catch (MalformedURLException e) {  
  65.             e.printStackTrace();  
  66.         } catch (IOException e) {  
  67.             e.printStackTrace();  
  68.         }  
  69.   
  70.     }  

在run()方法中调用该httpUpload()方法。


MainActivity.java类,代码为:

[java]  view plain  copy
  1. </pre><pre name="code" class="java">import android.os.Environment;  
  2. import android.support.v7.app.AppCompatActivity;  
  3. import android.os.Bundle;  
  4. import android.view.View;  
  5. import android.widget.Button;  
  6.   
  7. import java.io.File;  
  8.   
  9. public class MainActivity extends AppCompatActivity {  
  10.   
  11.     Button button;  
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         button= (Button) findViewById(R.id.button);  
  17.         button.setOnClickListener(new View.OnClickListener() {  
  18.             @Override  
  19.             public void onClick(View v) {  
  20.   
  21.                 String url="http://125.217.54.155:8080/uploadImage/Uploadimage";  
  22.   
  23.                 /***获取文件路径  在这部分可以设置为跳转到你的相册选取  暂时写死  以后加上***/  
  24.                 File file= Environment.getExternalStorageDirectory();//获取文件路径  
  25.                 File fileupload=new File(file,"zxy.jpg");//在SD卡里需要有这个图片 不然会获取不到  
  26.                 String name=fileupload.getAbsolutePath();//获取到该图片的绝对路径  
  27.                 UploadImageThread thread=new UploadImageThread(url,name);  
  28.                 thread.start();  
  29.             }  
  30.         });  
  31.     }  
  32. }  


记得加上联网权限和读取SD卡权限:

[java]  view plain  copy
  1. <uses-permission android:name="android.permission.INTERNET"/>  
  2.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
  3.     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  

运行的结果会在E盘中生成一个图片文件:






3.以上是使用http的方式,这个方式需要谨慎的遵循协议格式,较容易出错,以下使用httpClient第三发库来上传  这种方式比较容易,但是在新版的sdk中,Google已经将该类剔除,需要使用的话:

eclipse里的话,在libs里添加org.apache.http.legacy.jar包

android studio的话里在相应的module下的build.gradle中的
android {
  加入:useLibrary 'org.apache.http.legacy'
}

且需要引入两个jar包为:httpcore-4.4.1和httpmine-4.5,后面的数字为版本号,不建议使太高的版本,否则编译不通过。



在uploadHttpClient()写入以下代码:

[java]  view plain  copy
  1. /** 
  2.     * 使用HttpClient来上传数据 
  3.     */  
  4.    public void uploadHttpClient(){  
  5.        HttpClient client=new DefaultHttpClient();  
  6.        HttpPost httpPost=new HttpPost(murl);//通过post传递  
  7.        /**绑定数据  这里需要注意  如果是中文  会出现中文乱码问题 但只要按设置好*/  
  8.        MultipartEntity muit=new MultipartEntity();  
  9.        // 上传 文本, 转换编码为utf-8 其中"text" 为字段名,  
  10.        //Charset.forName(CHARSET)为参数值,可设置为UTF-8,其实就是正常的值转换成utf-8的编码格式  
  11.        // 后边new StringBody(text,Charset.forName(CHARSET))  
  12.   
  13.        File parent= Environment.getExternalStorageDirectory();//路径  
  14.        File fileupload=new File(parent,"zxy.jpg");  
  15.        FileBody fileBody=new FileBody(fileupload);  
  16.        muit.addPart("file",fileBody);  
  17.        httpPost.setEntity(muit);  
  18.        /**发送请求*/  
  19.        try {  
  20.            HttpResponse response=client.execute(httpPost);  
  21.            //判断师傅上传成功  返回200  
  22.            if (response.getStatusLine().getStatusCode()== HttpStatus.SC_OK){  
  23.                System.out.println(EntityUtils.toString(response.getEntity()));  
  24.            }  
  25.        } catch (ClientProtocolException e){  
  26.            e.printStackTrace();  
  27.        } catch (IOException e) {  
  28.            e.printStackTrace();  
  29.        }  
  30.   
  31.    }  


完成后在run()方法中调用uploadHttpClient()。

[java]  view plain  copy
  1. @Override  
  2.    public void run() {  
  3.       // httpUpload();  
  4.        uploadHttpClient();  
  5.   
  6.   
  7.    }  



运行结果跟http方法一样,不赘述。至此,三个方法已经全部结束。所需jar可自行下载。


以下是参考的博客:

http://blog.csdn.Net/linwei_1029/article/details/6990971

http://blog.csdn.net/MSPinyin/article/details/6141638


向服务器上传图片的实例:

  在Java web中上传图片相对比较容易,只需简单几个按钮和应用即可,以下的例子是如何使用http或httpClient向本地服务器上传图片。


1.网页版

   在本地创建一个Java web项目并上传图片到本地服务器。服务器版本须为3.0,一般Tomcat7.0以上。

  创建web项目 uploadImage,在 webContent目录下创建index.jsp,body中的代码为:

[java]  view plain  copy
  1. <form action="Uploadimage" method="post" enctype="multipart/form-data">  
  2.    <input type="file" name="file"><br>  
  3.    <input type="submit" value="submit">  
  4.   
  5. </form>  


指定数据类型:enctype="multipart/form-data",使用multipart/form-data最后数据会以二进制形式提交给服务器,字符不需要编码不会对服务端的获取有影响。

表单中enctype类型默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传。

具体请参考:http://blog.csdn.NET/MSPinyin/article/details/6141638


创建一个servlet:Uploadimage.jave,需要注意的是在Uploadimage类的上方中需要再添加一个注解标签来指定文件保存的路径,不然会在添加文件上传时报空指针异常。

注解标签为:@MultipartConfig(location="E://"),以下是添加地方。

[java]  view plain  copy
  1. @WebServlet("/Uploadimage")  
  2. @MultipartConfig(location="E://")  
  3. public class Uploadimage extends HttpServlet {  

添加完标签以后在doGet方法中调用doPost方法,在doPost方法中写入以下代码:

[java]  view plain  copy
  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  2.       
  3.       
  4.     //将当前系统时间作为文件的名称避免重名  
  5.     //Date data=new Date();  
  6.     SimpleDateFormat adf=new SimpleDateFormat("HHmmss");  
  7.     String filename=adf.format(new Date());  
  8.     Part part=request.getPart("file");//获取文件路径  
  9.     part.write(filename+".jpg");  
  10.       
  11.     response.setCharacterEncoding("UTF-8");  
  12.     PrintWriter out=response.getWriter();  
  13.     out.print("success!");  
  14.     System.out.print("上传成功!");  
  15. }  
注意,Part,引入的包为:
[java]  view plain  copy
  1. import javax.servlet.http.Part;  


完成以上以后,将web项目运行在服务器上。在web页面选择图片并点击上传,会在你的E盘上生成一个以时间为命名的jsp图片。

至此,通过java web上传图片的例子结束,以下是如何在Android客户端通过http上传图片。


2.通过http从Android客户端上传图片,在这之前,需要先了解在网页上是如何通过multipart/form-data来传输数据的。


打开浏览器,在地址栏输入我们以上网页版的web项目地址:http://localhost:8080/uploadImage,在浏览器:工具----》开发者工具---》网络---》启用网络流量捕获,然后选择文件,提交。

回到开发者工具后会检测到一个刚提交的数据:


双击打开,会在content-type看到一个编节符的请求头文件信息,点击上方的请求正文,将会看到以下内容,这个内容也将是待会使用http进行图片上传时需要转化数据格式。



需要指出的是,由于浏览器的原因,以上的编节符前面并不是一条直线,而是虚线:

-----------------------------7e020233150564,这个一般由系统随机产生,且开头增加了两个"-",减去这两个”-“就是一个"boundary",boundary这待会会用到的。

Content-Type:image/jpeg  就是文件的 类型。

<二进制文件数据未显示>:这一部分就是上传的图片。

以上的就是通过这样的协议向服务器发送数据。客户端向服务器发送数据时也需要遵守这样的协议。


了解了上传的协议描述后,接下来将是进行代码:

创建项目UploadImageDome,并创建UploadThread.java 类,让该类继承Thread:

创建方法:httpUpload();//该方法中写的是通过http方式上传图片,代码为:

[java]  view plain  copy
  1. public void httpUpload(){  
  2.         String boundary="-------------------------7e020233150564";//编节符  
  3.         String prefix="--";//前缀 上传时需要多出两个-- 一定需要注意!!!  
  4.         String end="\r\n";//这里也需要注意,在html协议中,用 “/r/n” 换行,而不是 “/n”。  
  5.   
  6.         SimpleDateFormat adf=new SimpleDateFormat("HHmmss");//通过时间来创建文件名  
  7.         String uploadname=adf.format(new Date())+".jsp";//上传的文件名称  
  8.   
  9.         try {  
  10.             URL http=new URL(murl);  
  11.             HttpURLConnection conn= (HttpURLConnection) http.openConnection();  
  12.             conn.setRequestMethod("POST");  
  13.             conn.setReadTimeout(5000);  
  14.             conn.setDoInput(true);//准许向服务器读数据  
  15.             conn.setDoOutput(true);//准许向服务器写入数据  
  16.   
  17.             /*设置向服务器上传数据的请求方式  默认的是表单形式 
  18.             * 通过Content-Type协议向服务器上传数据 
  19.             * boundary 
  20.             * */  
  21.             conn.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);  
  22.   
  23.             //创建一个输出流对象,  
  24.             DataOutputStream out=new DataOutputStream(conn.getOutputStream());  
  25.             /* 
  26.             * 
  27.               -----------------------------7e020233150564 
  28.               Content-Disposition: form-data; name="file"; filename="I:\迅雷下载\18fb1f51c9eb63489cce9e029154782e.jpg" 
  29.               Content-Type: image/jpeg 
  30.                                         //这里是空一行  需要注意 
  31.               <二进制文件数据未显示> 
  32.               ---------------------------7e020233150564-- 
  33.               */  
  34.             //向服务器写入数据  这里就需要完全根据以上协议格式来写,需要仔细,避免出错。  
  35.             out.writeBytes(prefix+boundary+end);//这是第一行  并回车换行  
  36.             //这是第二行,文件名和对应服务器的  
  37.             out.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\""+uploadname+"\""+end);//这是第二行  
  38.             out.writeBytes(end);//空一行  
  39.             //以下写入图片  
  40.             FileInputStream fileInputStream=new FileInputStream(new File(mfilename));  
  41.             byte[]b=new byte[1024*4];//缓冲区  
  42.             int len;  
  43.             //循环读数据  
  44.             while((len=fileInputStream.read(b))!=-1){  
  45.                 out.write(b, 0, len);  
  46.             }  
  47.             //写完数据后 回车换行  
  48.             out.writeBytes(end);  
  49.             out.writeBytes(prefix + boundary + prefix + end);  
  50.             out.flush();//清空  
  51.   
  52.             //创建一个输入流对象  获取返回的信息  是否上传成功  
  53.             BufferedReader reader=new BufferedReader(new InputStreamReader(conn.getInputStream()));  
  54.             StringBuffer sb=new StringBuffer();  
  55.             String str;  
  56.             while((str=reader.readLine())!=null){  
  57.                 sb.append(str);  
  58.             }  
  59.             //关闭流信息  
  60.             if(out!=null)out.close();  
  61.             if(reader!=null)reader.close();  
  62.   
  63.             System.out.print("返回结果:"+sb.toString());  
  64.         } catch (MalformedURLException e) {  
  65.             e.printStackTrace();  
  66.         } catch (IOException e) {  
  67.             e.printStackTrace();  
  68.         }  
  69.   
  70.     }  

在run()方法中调用该httpUpload()方法。


MainActivity.java类,代码为:

[java]  view plain  copy
  1. </pre><pre name="code" class="java">import android.os.Environment;  
  2. import android.support.v7.app.AppCompatActivity;  
  3. import android.os.Bundle;  
  4. import android.view.View;  
  5. import android.widget.Button;  
  6.   
  7. import java.io.File;  
  8.   
  9. public class MainActivity extends AppCompatActivity {  
  10.   
  11.     Button button;  
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         button= (Button) findViewById(R.id.button);  
  17.         button.setOnClickListener(new View.OnClickListener() {  
  18.             @Override  
  19.             public void onClick(View v) {  
  20.   
  21.                 String url="http://125.217.54.155:8080/uploadImage/Uploadimage";  
  22.   
  23.                 /***获取文件路径  在这部分可以设置为跳转到你的相册选取  暂时写死  以后加上***/  
  24.                 File file= Environment.getExternalStorageDirectory();//获取文件路径  
  25.                 File fileupload=new File(file,"zxy.jpg");//在SD卡里需要有这个图片 不然会获取不到  
  26.                 String name=fileupload.getAbsolutePath();//获取到该图片的绝对路径  
  27.                 UploadImageThread thread=new UploadImageThread(url,name);  
  28.                 thread.start();  
  29.             }  
  30.         });  
  31.     }  
  32. }  


记得加上联网权限和读取SD卡权限:

[java]  view plain  copy
  1. <uses-permission android:name="android.permission.INTERNET"/>  
  2.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
  3.     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  

运行的结果会在E盘中生成一个图片文件:






3.以上是使用http的方式,这个方式需要谨慎的遵循协议格式,较容易出错,以下使用httpClient第三发库来上传  这种方式比较容易,但是在新版的sdk中,Google已经将该类剔除,需要使用的话:

eclipse里的话,在libs里添加org.apache.http.legacy.jar包

android studio的话里在相应的module下的build.gradle中的
android {
  加入:useLibrary 'org.apache.http.legacy'
}

且需要引入两个jar包为:httpcore-4.4.1和httpmine-4.5,后面的数字为版本号,不建议使太高的版本,否则编译不通过。



在uploadHttpClient()写入以下代码:

[java]  view plain  copy
  1. /** 
  2.     * 使用HttpClient来上传数据 
  3.     */  
  4.    public void uploadHttpClient(){  
  5.        HttpClient client=new DefaultHttpClient();  
  6.        HttpPost httpPost=new HttpPost(murl);//通过post传递  
  7.        /**绑定数据  这里需要注意  如果是中文  会出现中文乱码问题 但只要按设置好*/  
  8.        MultipartEntity muit=new MultipartEntity();  
  9.        // 上传 文本, 转换编码为utf-8 其中"text" 为字段名,  
  10.        //Charset.forName(CHARSET)为参数值,可设置为UTF-8,其实就是正常的值转换成utf-8的编码格式  
  11.        // 后边new StringBody(text,Charset.forName(CHARSET))  
  12.   
  13.        File parent= Environment.getExternalStorageDirectory();//路径  
  14.        File fileupload=new File(parent,"zxy.jpg");  
  15.        FileBody fileBody=new FileBody(fileupload);  
  16.        muit.addPart("file",fileBody);  
  17.        httpPost.setEntity(muit);  
  18.        /**发送请求*/  
  19.        try {  
  20.            HttpResponse response=client.execute(httpPost);  
  21.            //判断师傅上传成功  返回200  
  22.            if (response.getStatusLine().getStatusCode()== HttpStatus.SC_OK){  
  23.                System.out.println(EntityUtils.toString(response.getEntity()));  
  24.            }  
  25.        } catch (ClientProtocolException e){  
  26.            e.printStackTrace();  
  27.        } catch (IOException e) {  
  28.            e.printStackTrace();  
  29.        }  
  30.   
  31.    }  


完成后在run()方法中调用uploadHttpClient()。

[java]  view plain  copy
  1. @Override  
  2.    public void run() {  
  3.       // httpUpload();  
  4.        uploadHttpClient();  
  5.   
  6.   
  7.    }  



运行结果跟http方法一样,不赘述。至此,三个方法已经全部结束。所需jar可自行下载。


以下是参考的博客:

http://blog.csdn.Net/linwei_1029/article/details/6990971

http://blog.csdn.net/MSPinyin/article/details/6141638


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值