jsp、struts1.2、struts2 中文件上传

 a.在jsp中简单利用Commons-fileupload组件实现
b.在struts1.2中实现
c.在sturts2中实现
注:此为三个简单Demo,仅供练习用,并没有做太多上传限制 如有兴趣可以自行查看相关文档说明 。

一.在JSP环境中利用Commons-fileupload组件实现文件上传
   1.页面upload.jsp清单如下:

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>   
  2.   
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">   
  4. <html>   
  5.   <head>   
  6.     <title>The FileUpload Demo</title>   
  7.   </head>   
  8.      
  9.   <body>   
  10.     <form action="UploadFile" method="post" enctype="multipart/form-data">   
  11.         <p><input type="text" name="fileinfo" value="">文件介绍</p>   
  12.         <p><input type="file" name="myfile" value="浏览文件"></p>   
  13.         <p><input type="submit" value="上 传"></p>   
  14.     </form>   
  15.   </body>   
  16. </html> 

注意:在上传表单中,既有普通文本域也有文件上传域

2.FileUplaodServlet.java清单如下:

  1. import java.io.File;   
  2. import java.io.IOException;   
  3. import java.util.Iterator;   
  4. import java.util.List;   
  5.   
  6. import javax.servlet.ServletException;   
  7. import javax.servlet.http.*;   
  8.   
  9. import org.apache.commons.fileupload.FileItem;   
  10. import org.apache.commons.fileupload.FileItemFactory;   
  11. import org.apache.commons.fileupload.disk.DiskFileItemFactory;   
  12. import org.apache.commons.fileupload.servlet.ServletFileUpload;   
  13.   
  14. public class FileUplaodServlet extends HttpServlet {   
  15.   
  16.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {   
  17.         doPost(request, response);   
  18.     }   
  19.   
  20.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {   
  21.            
  22.         request.setCharacterEncoding("UTF-8");   
  23.            
  24.         //文件的上传部分   
  25.         boolean isMultipart = ServletFileUpload.isMultipartContent(request);   
  26.            
  27.         if(isMultipart)   
  28.         {   
  29.             try {   
  30.                 FileItemFactory factory = new DiskFileItemFactory();   
  31.                 ServletFileUpload fileload = new ServletFileUpload(factory);   
  32.                    
  33. //               设置最大文件尺寸,这里是4MB       
  34.                 fileload.setSizeMax(4194304);   
  35.                 List<FileItem> files = fileload.parseRequest(request);   
  36.                 Iterator<FileItem> iterator = files.iterator();      
  37.                 while(iterator.hasNext())   
  38.                 {   
  39.                     FileItem item = iterator.next();   
  40.                     if(item.isFormField())   
  41.                     {   
  42.                         String name = item.getFieldName();   
  43.                         String value = item.getString();   
  44.                         System.out.println("表单域名为: " + name + "值为: " + value);   
  45.                     }else  
  46.                     {   
  47.                         //获得获得文件名,此文件名包括路径   
  48.                         String filename = item.getName();   
  49.                         if(filename != null)   
  50.                         {   
  51.                             File file = new File(filename);   
  52.                             //如果此文件存在   
  53.                             if(file.exists()){   
  54.                                 File filetoserver = new File("d://upload//",file.getName());   
  55.                                 item.write(filetoserver);   
  56.                                 System.out.println("文件 " + filetoserver.getName() + " 上传成功!!");   
  57.                             }   
  58.                         }   
  59.                     }   
  60.                 }   
  61.             } catch (Exception e) {   
  62.                 System.out.println(e.getStackTrace());   
  63.             }   
  64.         }   
  65.     }   
  66. }  

 

3.web.xml清单如下:

  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <web-app version="2.4"    
  3.     xmlns="http://java.sun.com/xml/ns/j2ee"    
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee    
  6.     http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">   
  7.        
  8.     <servlet>   
  9.         <servlet-name>UploadFileServlet</servlet-name>   
  10.         <servlet-class>   
  11.             org.chris.fileupload.FileUplaodServlet   
  12.         </servlet-class>   
  13.     </servlet>   
  14.   
  15.     <servlet-mapping>   
  16.         <servlet-name>UploadFileServlet</servlet-name>   
  17.         <url-pattern>/UploadFile</url-pattern>   
  18.     </servlet-mapping>   
  19.        
  20.     <welcome-file-list>   
  21.         <welcome-file>/Index.jsp</welcome-file>   
  22.     </welcome-file-list>   
  23.        
  24. </web-app>  

 

二.在strut1.2中实现
1.上传页面file.jsp 清单如下:

  1. <%@ page language="java" pageEncoding="ISO-8859-1"%>   
  2. <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>    
  3. <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>   
  4.     
  5. <html>    
  6.     <head>   
  7.         <title>JSP for FileForm form</title>   
  8.     </head>   
  9.     <body>   
  10.         <html:form action="/file" enctype="multipart/form-data">   
  11.         <html:file property="file1"></html:file>   
  12.             <html:submit/><html:cancel/>   
  13.         </html:form>   
  14.     </body>   
  15. </html> 

 

2.FileAtion.java的清单如下:

  1. import java.io.*;   
  2.   
  3. import javax.servlet.http.HttpServletRequest;   
  4. import javax.servlet.http.HttpServletResponse;   
  5. import org.apache.struts.action.Action;   
  6. import org.apache.struts.action.ActionForm;   
  7. import org.apache.struts.action.ActionForward;   
  8. import org.apache.struts.action.ActionMapping;   
  9. import org.apache.struts.upload.<SPAN class=hilite2>FormFile</SPAN>;   
  10.   
  11. import form.FileForm;   
  12.   
  13. /**   
  14.  * @author Chris  
  15.  * Creation date: 6-27-2008  
  16.  *   
  17.  * XDoclet definition:  
  18.  * @struts.action path="/file" name="fileForm" input="/file.jsp"  
  19.  */  
  20. public class FileAction extends Action {   
  21.     /*  
  22.      * Generated Methods  
  23.      */  
  24.   
  25.     /**   
  26.      * Method execute  
  27.      * @param mapping  
  28.      * @param form  
  29.      * @param request  
  30.      * @param response  
  31.      * @return ActionForward  
  32.      */  
  33.     public ActionForward execute(ActionMapping mapping, ActionForm form,   
  34.             HttpServletRequest request, HttpServletResponse response) {   
  35.         FileForm fileForm = (FileForm) form;   
  36.         <SPAN class=hilite2>FormFile</SPAN> file1=fileForm.getFile1();   
  37.         if(file1!=null){   
  38.             //上传路径   
  39.             String dir=request.getSession(true).getServletContext().getRealPath("/upload");   
  40.             OutputStream fos=null;   
  41.             try {   
  42.                 fos=new FileOutputStream(dir+"/"+file1.getFileName());   
  43.                 fos.write(file1.getFileData(),0,file1.getFileSize());   
  44.                 fos.flush();   
  45.             } catch (Exception e) {   
  46.                 // TODO Auto-generated catch block   
  47.                 e.printStackTrace();   
  48.             }finally{   
  49.                 try{   
  50.                 fos.close();   
  51.                 }catch(Exception e){}   
  52.             }   
  53.         }   
  54.         //页面跳转   
  55.         return mapping.findForward("success");   
  56.     }   
  57. }  

 

3.FileForm.java的清单如下:

  1. import javax.servlet.http.HttpServletRequest;   
  2. import org.apache.struts.action.ActionErrors;   
  3. import org.apache.struts.action.ActionForm;   
  4. import org.apache.struts.action.ActionMapping;   
  5. import org.apache.struts.upload.<SPAN class=hilite2>FormFile</SPAN>;   
  6.   
  7. /**   
  8.  * @author Chris  
  9.  * Creation date: 6-27-2008  
  10.  *   
  11.  * XDoclet definition:  
  12.  * @struts.form name="fileForm"  
  13.  */  
  14. public class FileForm extends ActionForm {   
  15.     /*  
  16.      * Generated Methods  
  17.      */  
  18.     private <SPAN class=hilite2>FormFile</SPAN> file1;   
  19.     /**   
  20.      * Method validate  
  21.      * @param mapping  
  22.      * @param request  
  23.      * @return ActionErrors  
  24.      */  
  25.     public ActionErrors validate(ActionMapping mapping,   
  26.             HttpServletRequest request) {   
  27.         // TODO Auto-generated method stub   
  28.         return null;   
  29.     }   
  30.   
  31.     /**   
  32.      * Method reset  
  33.      * @param mapping  
  34.      * @param request  
  35.      */  
  36.     public void reset(ActionMapping mapping, HttpServletRequest request) {   
  37.         // TODO Auto-generated method stub   
  38.     }   
  39.   
  40.     public <SPAN class=hilite2>FormFile</SPAN> getFile1() {   
  41.         return file1;   
  42.     }   
  43.   
  44.     public void setFile1(<SPAN class=hilite2>FormFile</SPAN> file1) {   
  45.         this.file1 = file1;   
  46.     }   

 

4.struts-config.xml的清单如下:

  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd">   
  3.   
  4. <struts-config>   
  5.   <data-sources />   
  6.   <form-beans >   
  7.     <form-bean name="fileForm" type="form.FileForm" />   
  8.   
  9.   </form-beans>   
  10.   
  11.   <global-exceptions />   
  12.   <global-forwards />   
  13.   <action-mappings >   
  14.     <action   
  15.       attribute="fileForm"  
  16.       input="/file.jsp"  
  17.       name="fileForm"  
  18.       path="/file"  
  19.       type="action.FileAction"  
  20.       validate="false">   
  21.        <forward name="success" path="/file.jsp"></forward>   
  22.       </action>   
  23.   
  24.   </action-mappings>   
  25.   
  26.   <message-resources parameter="ApplicationResources" />   
  27. </struts-config>

 

5.web.xml代码清单如下:

  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">   
  3.   <servlet>   
  4.     <servlet-name>action</servlet-name>   
  5.     <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>   
  6.     <init-param>   
  7.       <param-name>config</param-name>   
  8.       <param-value>/WEB-INF/struts-config.xml</param-value>   
  9.     </init-param>   
  10.     <init-param>   
  11.       <param-name>debug</param-name>   
  12.       <param-value>3</param-value>   
  13.     </init-param>   
  14.     <init-param>   
  15.       <param-name>detail</param-name>   
  16.       <param-value>3</param-value>   
  17.     </init-param>   
  18.     <load-on-startup>0</load-on-startup>   
  19.   </servlet>   
  20.   <servlet-mapping>   
  21.     <servlet-name>action</servlet-name>   
  22.     <url-pattern>*.do</url-pattern>   
  23.   </servlet-mapping>   
  24. </web-app>  

 

三.在struts2中实现(以图片上传为例)
1.FileUpload.jsp代码清单如下:

  1. <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>   
  2. <%@ taglib prefix="s" uri="/struts-tags" %>   
  3. <html>   
  4.   <head>   
  5.     <title>The FileUplaodDemo In <SPAN class=hilite1>Struts2</SPAN></title>   
  6.   </head>   
  7.      
  8.   <body>   
  9.     <s:form action="fileUpload.action" method="POST" enctype="multipart/form-data">   
  10.         <s:file name="myFile" label="MyFile" ></s:file>   
  11.         <s:textfield name="caption" label="Caption"></s:textfield>   
  12.         <s:submit label="提交"></s:submit>   
  13.     </s:form>   
  14.   </body>   
  15. </html>  

 

2.ShowUpload.jsp的功能清单如下:

  1. <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>   
  2. <%@ taglib prefix="s" uri="/struts-tags" %>   
  3. <html>   
  4.   <head>   
  5.     <title>ShowUpload</title>   
  6.   </head>   
  7.      
  8.   <body>   
  9.     <div style ="padding: 3px; border: solid 1px #cccccc; text-align: center" >    
  10.         <img src ='UploadImages/<s:property value ="imageFileName"/> '/>   
  11.         <br />    
  12.         <s:property value ="caption"/>    
  13.     </div >    
  14.   </body>   
  15. </html>  

 

3.FileUploadAction.java的代码清单如下 :

  1. import java.io.*;   
  2. import java.util.Date;   
  3.   
  4. import org.apache.<SPAN class=hilite1>struts2</SPAN>.ServletActionContext;   
  5.   
  6.   
  7. import com.opensymphony.xwork2.ActionSupport;   
  8.   
  9. public class FileUploadAction extends ActionSupport{   
  10.   
  11.      private static final long serialVersionUID = 572146812454l ;   
  12.      private static final int BUFFER_SIZE = 16 * 1024 ;   
  13.        
  14.      //注意,文件上传时<s:file/>同时与myFile,myFileContentType,myFileFileName绑定   
  15.      //所以同时要提供myFileContentType,myFileFileName的set方法   
  16.         
  17.      private File myFile;   //上传文件   
  18.      private String contentType;//上传文件类型   
  19.      private String fileName;   //上传文件名   
  20.      private String imageFileName;   
  21.      private String caption;//文件说明,与页面属性绑定   
  22.        
  23.      public void setMyFileContentType(String contentType)  {   
  24.          System.out.println("contentType : " + contentType);   
  25.          this .contentType = contentType;   
  26.     }    
  27.        
  28.      public void setMyFileFileName(String fileName)  {   
  29.          System.out.println("FileName : " + fileName);   
  30.          this .fileName = fileName;   
  31.     }    
  32.            
  33.      public void setMyFile(File myFile)  {   
  34.          this .myFile = myFile;   
  35.     }    
  36.        
  37.      public String getImageFileName()  {   
  38.          return imageFileName;   
  39.     }    
  40.        
  41.      public String getCaption()  {   
  42.          return caption;   
  43.     }    
  44.     
  45.       public void setCaption(String caption)  {   
  46.          this .caption = caption;   
  47.     }    
  48.        
  49.      private static void copy(File src, File dst)  {   
  50.          try  {   
  51.             InputStream in = null ;   
  52.             OutputStream out = null ;   
  53.              try  {                   
  54.                 in = new BufferedInputStream( new FileInputStream(src), BUFFER_SIZE);   
  55.                 out = new BufferedOutputStream( new FileOutputStream(dst), BUFFER_SIZE);   
  56.                  byte [] buffer = new byte [BUFFER_SIZE];   
  57.                  while (in.read(buffer) > 0 )  {   
  58.                     out.write(buffer);   
  59.                 }    
  60.              } finally  {   
  61.                  if ( null != in)  {   
  62.                     in.close();   
  63.                 }    
  64.                   if ( null != out)  {   
  65.                     out.close();   
  66.                 }    
  67.             }    
  68.          } catch (Exception e)  {   
  69.             e.printStackTrace();   
  70.         }    
  71.     }    
  72.        
  73.      private static String getExtention(String fileName)  {   
  74.          int pos = fileName.lastIndexOf(".");   
  75.          return fileName.substring(pos);   
  76.     }    
  77.     
  78.     @Override  
  79.      public String execute()      {           
  80.         imageFileName = new Date().getTime() + getExtention(fileName);   
  81.         File imageFile = new File(ServletActionContext.getServletContext().getRealPath("/UploadImages" ) + "/" + imageFileName);   
  82.         copy(myFile, imageFile);   
  83.          return SUCCESS;   
  84.     }   
  85. }  

 

注:此时仅为方便实现Action所以继承ActionSupport,并Overrider execute()方法
  在struts2中任何一个POJO都可以作为Action

4.struts.xml清单如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>   
  2. <!DOCTYPE struts PUBLIC   
  3.     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"  
  4.     "http://struts.apache.org/dtds/struts-2.0.dtd">   
  5. <struts>   
  6.     <package name="example" namespace="/" extends="struts-default">   
  7.         <action name="fileUpload" class="com.chris.FileUploadAction">   
  8.         <interceptor-ref name="fileUploadStack"/>   
  9.         <result>/ShowUpload.jsp</result>   
  10.         </action>   
  11.     </package>   
  12. </struts>  

5.web.xml清单如下:

  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <web-app version="2.4"    
  3.     xmlns="http://java.sun.com/xml/ns/j2ee"    
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee    
  6.     http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">   
  7.     <filter >    
  8.         <filter-name> struts-cleanup </filter-name >    
  9.         <filter-class>    
  10.             org.apache.struts2.dispatcher.ActionContextCleanUp 
  11.         </filter-class >    
  12.     </filter >    
  13.      <filter-mapping >    
  14.         <filter-name > struts-cleanup </filter-name >    
  15.         <url-pattern > /* </url-pattern >    
  16.     </filter-mapping >   
  17.        
  18.     <filter>   
  19.         <filter-name>struts2</filter-name>   
  20.         <filter-class>org.apachestruts2.dispatcher.FilterDispatcher</filter-class>   
  21.     </filter>   
  22.     <filter-mapping>   
  23.         <filter-name>struts2</filter-name>   
  24.         <url-pattern>/*</url-pattern>   
  25.     </filter-mapping>   
  26.   <welcome-file-list>   
  27.     <welcome-file>Index.jsp</welcome-file>   
  28.   </welcome-file-list>   
  29.      
  30. </web-app>  

发布运行应用程序,在浏览器地址栏中键入:http://localhost:8080/Struts2_Fileupload/FileUpload.jsp,出现图示页面:


清单7 FileUpload页面

选择图片文件,填写Caption并按下Submit按钮提交,出现图示页面:


清单8 上传成功页面

更多配置

在运行上述例子,如果您留心一点的话,应该会发现服务器控制台有如下输出:

Mar 20 , 2007 4 : 08 : 43 PM org.apache.struts2.dispatcher.Dispatcher getSaveDir
INFO: Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
Mar
20 , 2007 4 : 08 : 43 PM org.apache.struts2.interceptor.FileUploadInterceptor intercept
INFO: Removing file myFile C:/Program Files/Tomcat
5.5 /work/Catalina/localhost/Struts2_Fileupload/upload_251447c2_1116e355841__7ff7_00000006.tmp

清单9 服务器控制台输出

上述信息告诉我们,struts.multipart.saveDir没有配置。struts.multipart.saveDir用于指定存放临时文件的文件夹,该配置写在struts.properties文件中。例如,如果在struts.properties文件加入如下代码:

struts.multipart.saveDir = /tmp

清单10 struts配置

这样上传的文件就会临时保存到你根目录下的tmp文件夹中(一般为c:/tmp),如果此文件夹不存在,Struts 2会自动创建一个。

错误处理

上述例子实现的图片上传的功能,所以应该阻止用户上传非图片类型的文件。在Struts 2中如何实现这点呢?其实这也很简单,对上述例子作如下修改即可。

首先修改FileUpload.jsp,在<body>与<s:form>之间加入“<s:fielderror />”,用于在页面上输出错误信息。

然后修改struts.xml文件,将Action fileUpload的定义改为如下所示:

        < action name ="fileUpload" class ="tutorial.FileUploadAction" >
           
< interceptor-ref name ="fileUpload" >
               
< param name ="allowedTypes" >
                    image/bmp,image/png,image/gif,image/jpeg
               
</ param >
           
</ interceptor-ref >
           
< interceptor-ref name ="defaultStack" />            
           
< result name ="input" > /FileUpload.jsp </ result >
           
< result name ="success" > /ShowUpload.jsp </ result >
       
</ action >

清单11 修改后的配置文件

显而易见,起作用就是fileUpload拦截器的allowTypes参数。另外,配置还引入defaultStack它会帮我们添加验证等功能,所以在出错之后会跳转到名称为“input”的结果,也即是FileUpload.jsp。

发布运行应用程序,出错时,页面如下图所示:


清单12 出错提示页面

上面的出错提示是Struts 2默认的,大多数情况下,我们都需要自定义和国际化这些信息。通过在全局的国际资源文件中加入“struts.messages.error.content.type.not.allowed=The file you uploaded is not a image”,可以实现以上提及的需求。对此有疑问的朋友可以参考我之前的文章《在Struts 2.0中国际化(i18n)您的应用程序》。

实现之后的出错页面如下图所示:


清单13 自定义出错提示页面

同样的做法,你可以使用参数“maximumSize”来限制上传文件的大小,它对应的字符资源名为:“struts.messages.error.file.too.large”。

字符资源“struts.messages.error.uploading”用提示一般的上传出错信息。

多文件上传

与单文件上传相似,Struts 2实现多文件上传也很简单。你可以将多个<s:file />绑定Action的数组或列表。如下例所示。

< s:form action ="doMultipleUploadUsingList" method ="POST" enctype ="multipart/form-data" >
   
< s:file label ="File (1)" name ="upload" />
   
< s:file label ="File (2)" name ="upload" />
   
< s:file label ="FIle (3)" name ="upload" />
   
< s:submit />
</ s:form >

清单14 多文件上传JSP代码片段

如果你希望绑定到数组,Action的代码应类似:

    private File[] uploads;
   
private String[] uploadFileNames;
   
private String[] uploadContentTypes;

   
public File[] getUpload()  { return this .uploads; }
   
public void setUpload(File[] upload)  { this .uploads = upload; }

   
public String[] getUploadFileName()  { return this .uploadFileNames; }
   
public void setUploadFileName(String[] uploadFileName)  { this .uploadFileNames = uploadFileName; }

   
public String[] getUploadContentType()  { return this .uploadContentTypes; }
   
public void setUploadContentType(String[] uploadContentType)  { this .uploadContentTypes = uploadContentType; }

清单15 多文件上传数组绑定Action代码片段

如果你想绑定到列表,则应类似:

    private List < File > uploads = new ArrayList < File > ();
   
private List < String > uploadFileNames = new ArrayList < String > ();
   
private List < String > uploadContentTypes = new ArrayList < String > ();

   
public List < File > getUpload()  {
       
return this .uploads;
   }

   
public void setUpload(List < File > uploads)  {
       
this .uploads = uploads;
   }


   
public List < String > getUploadFileName()  {
       
return this .uploadFileNames;
   }

   
public void setUploadFileName(List < String > uploadFileNames)  {
       
this .uploadFileNames = uploadFileNames;
   }


   
public List < String > getUploadContentType()  {
       
return this .uploadContentTypes;
   }

   
public void setUploadContentType(List < String > contentTypes)  {
       
this .uploadContentTypes = contentTypes;
   }

清单16 多文件上传列表绑定Action代码片段

总结

在Struts 2中实现文件上传的确是轻而易举,您要做的只是使用<s:file />与Action的属性绑定。这又一次有力地证明了Struts 2的简单易用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

無名VF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值