plupload文件上传插件使用

官方文档:http://www.phpin.net/tools/plupload/

//实例化组件
//附件1上传路径
var dirFile1 = '/upload/htfj/rchtfj/${data.xshthtbh}/fj1/';
var uploader1 = new plupload.Uploader({
	runtimes: 'html5,flash,silverlight,html4',//当前运行环境,自适应
	browse_button: ['pluploadfiles1'],//浏览文件按钮
	url: context + '/service/pub/fileupload/uploads?dirFile='+dirFile1,//文件上传后台方法
	max_file_size: '2mb',//限制选择文件的大小
	multi_selection: true,//多选对话框
	unique_names: false,
	prevent_duplicates : false, //不允许选取重复文件
	flash_swf_url: '../../dist/js/Moxie.swf',
    silverlight_xap_url: '../../dist/js/Moxie.xap',
    filters: [//控制上传文件的类型 
	          	{title: "图片格式:jpg,gif,bmp", extensions : "jpg,jpeg,png"},
	          	{title: "文档格式:doc,docx,xls,xlsx", extensions : "doc,docx,pdf"}
           	],
    init: {
	    FilesAdded: function(up, files) {
	    	document.getElementById('scfj1').value = '';//选择时清除已有文件
	    	document.getElementById('cresult1').innerHTML = "";//选择时清除已有文件
	    	if(uploader1.files.length>1){ 
                 uploader1.splice(0,uploader1.files.length-1);
            }
		    plupload.each(files, function(file) {
		    	 if ($('#scfj1').val() !== '') {
				    	Alert('只允许上传一个文件!');
				    	up.removeFile(file);
					return;
				}
		    	var fileArray= new Array(); //定义一数组  
		    	fileArray = document.getElementById('scfj1').value.split(";");//字符分割 
		    	if($.inArray(file.name,fileArray) == -1) {
		    		document.getElementById('scfj1').value += file.name;
				    document.getElementById('cresult1').innerHTML += '<div id="' + file.id + '"  style="float:right;position:absolute;width:500px">'
					+ "<div class='pull-left' style=' overflow: hidden; word-break:keep-all;display:block;text-overflow:ellipsis;white-space:nowrap;width:600px'>" + file.name
					+ ' </div>('
					+ plupload.formatSize(file.size)
					+ ')<div class="pull-right progress" style="width:200px;float: left !important;"><div class="progress-bar"><span></span></div></div></div><br id="br' + file.id + '">';
    
		    	}
		    	$('#rcHtFj1mc').val($("#scfj1").val());
            });
        },
        UploadProgress: function(up, file) {
        	//$('#yjbzYjsjwhFj').val($('#yjbzYjsjwhFj').val+";"+file.name);
	        $('#' + file.id).find('.progress-bar')[0].style.width = $('#' + file.id).find('.progress-bar')[0].innerText = file.percent + '%';
        },
        Error: function(up, err) {
	        Alert("文件大小不能超过2M!");
	      //  document.getElementById('cresult').appendChild(document.createTextNode('\nError #' + err.code + ': ' + err.message));
        },
        FileUploaded: function(up, file, result) {//文件上传成功后触发
	        var fileName = document.getElementById(file.id).innerHTML;
	        var filedir = dirFile1;
	       	document.getElementById(file.id).innerHTML = "<a onclick=\"previewImage('"+filedir+"','"+file.id+"')\">"+fileName+"</a><img src='<%=request.getContextPath()%>/jsp/genersoft/gxgl/htgl/xsht/image/deleteFile.png'  style='cursor: pointer;width: 15px;margin-left: 20px;' onclick=\"imgclick1('${item}')\"/>";
        	$('#rcHtFj1mc').val($("#scfj1").val());
    	}	
    }
});

uploader1.init();

页面展示区域: 

<tr style="height:33.3%;">
			            		<td class="tdTitle" style="text-align: right;">附件1名称:</td>
			                	<td class="tdRight">
			                  			<input id="rcHtFj1mc" name="rcHtFj1mc" class="form-control ue-form" type="hidden" value="${data.rcHtFj1mc}" />			
										<input id="scfj1" class="form-control ue-form" style="width:55%;display:inline;" type="text" placeholder="请点击右侧浏览" value="${data.rcHtFj1mc}" readonly="readonly"></input>			
									 	<a id="pluploadfiles1" class="btn ue-btn">浏览</a>
						                <button class="btn ue-btn" id="startUpload1" style="display: none">开始上传</button>
						                <font color="red">(附件不超2兆)</font>
						                
						                <c:set value="${fn:split(data.rcHtFj1mc, ';') }" var="rcHtFj1mcList" />
						                <c:forEach items="${rcHtFj1mcList }" var="item" varStatus="status">
						                 	<c:if test="${item != '' }">
									    	<div id="cresult11" >
						    	          		<a onclick="previewImage('upload/htfj/rchtfj/${data.xshtnm}/fj1/${item}','${item}')">${item}</a>
						    	          		<img src='image/deleteFile.png'  style='cursor: pointer;width: 15px;margin-left: 20px;' onclick="imgclick1('${item}')"/>
						    	          	</div>
						    	          	</c:if> 
						    	        </c:forEach>
						           		<div id="cresult1" style="display: none"></div>
										<div id="errorTp1" style="display: none">
										</div>	
			                	</td>
				                <td class="tdTitle" style="text-align: right;">附件1说明:</td>
				                <td class="tdRight">
				                	<input type="text" class="form-control ue-form" id="rcHtFj1sm" name="rcHtFj1sm" />	
				                </td>
							</tr>

文件上传触发

//文件上传
uploader1.start();

 后台方法说明:

1.上传工具类

package com.genersoft.pub.FileUpload.util;

import java.io.BufferedOutputStream;  
import java.io.File;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.OutputStream;  
import java.util.Iterator;  
import java.util.List;  
  

import java.util.Map;

import org.springframework.util.MultiValueMap;  
import org.springframework.web.multipart.MultipartFile;  
import org.springframework.web.multipart.MultipartHttpServletRequest;  

import com.genersoft.pub.FileUpload.data.Plupload;


/**
 * Plupload工具类
 */
public class PluploadUtil {
	private static final int BUF_SIZE = 2 * 1024;  
    /**上传失败响应的成功状态码*/  
    public static final String RESP_SUCCESS = "{\"jsonrpc\" : \"2.0\", \"result\" : \"success\", \"id\" : \"id\"}";  
    /**上传失败响应的失败状态码*/  
    public static final String RESP_ERROR = "{\"jsonrpc\" : \"2.0\", \"error\" : {\"code\": 101, \"message\": \"Failed to open input stream.\"}, \"id\" : \"id\"}";  
      
    /** 
     * 用于Plupload插件的文件上传,自动生成唯一的文件保存名 
     * @param plupload - 存放上传所需参数的bean 
     * @param dir - 保存目标文件目录 
     * @throws IllegalStateException 
     * @throws IOException 
     */  
    public static void upload(Plupload plupload, File dir) throws IllegalStateException, IOException {  
        //生成唯一的文件名
        //String filename = "" + System.currentTimeMillis() + plupload.getName().substring(plupload.getName().lastIndexOf("."));
    	//使用原文件名称
    	String filename = "" + plupload.getName();
        upload(plupload, dir, filename); 
    }  
    /** 
     * 用于Plupload插件的文件上传,自动生成唯一的文件保存名 ——视频文件上传
     * @param plupload - 存放上传所需参数的bean 
     * @param dir - 保存目标文件目录 
     * @throws IllegalStateException 
     * @throws IOException 
     */  
    public static void uploadSp(Plupload plupload, File dir, Map<String, String> map) throws IllegalStateException, IOException {  
    	//生成唯一的文件名
    	//String filename = "" + System.currentTimeMillis() + plupload.getName().substring(plupload.getName().lastIndexOf("."));
    	//使用原文件名称
    	//String filename = "" + plupload.getName();
    	String filename = map.get("newFileName") + plupload.getName().substring(plupload.getName().lastIndexOf("."));
    	upload(plupload, dir, filename);  
    }  
      
    /** 
     * 用于Plupload插件的文件上传 
     * @param plupload - 存放上传所需参数的bean 
     * @param dir - 保存目标文件目录 
     * @param filename - 保存的文件名 
     * @throws IllegalStateException 
     * @throws IOException 
     */  
    public static void upload(Plupload plupload, File dir, String filename) throws IllegalStateException, IOException {  
        int chunks = plupload.getChunks();  //获取总的碎片数  
        int chunk = plupload.getChunk();    //获取当前碎片(从0开始计数)  
          
        System.out.println(plupload.getMultipartFile() + "----------");  
          
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) plupload.getRequest();   
        MultiValueMap<String, MultipartFile> map = multipartRequest.getMultiFileMap();  
          
        if(map != null) {  
            if (!dir.exists()) dir.mkdirs();    //如果目标文件夹不存在则创建新的文件夹  
              
            //事实上迭代器中只存在一个值,所以只需要返回一个值即可  
            Iterator<String> iter = map.keySet().iterator();  
            while(iter.hasNext()) {  
                String str = (String) iter.next();  
                List<MultipartFile> fileList =  map.get(str);  
                for(MultipartFile multipartFile : fileList) {  
                    //因为只存在一个值,所以最后返回的既是第一个也是最后一个值  
                    plupload.setMultipartFile(multipartFile);  
                      
                    //创建新目标文件  
                    File targetFile = new File(dir.getPath()+ "/" + filename);  
                      
                    //当chunks>1则说明当前传的文件为一块碎片,需要合并  
                    if (chunks > 1) {  
                        //需要创建临时文件名,最后再更改名称  
                        File tempFile = new File(dir.getPath()+ "/" + multipartFile.getName());  
                        //如果chunk==0,则代表第一块碎片,不需要合并  
                        saveUploadFile(multipartFile.getInputStream(), tempFile, chunk == 0 ? false : true);  
                          
                        //上传并合并完成,则将临时名称更改为指定名称  
                        if (chunks - chunk == 1) {  
                            tempFile.renameTo(targetFile);  
                        }  
                          
                    } else {  
                    	boolean checkFileType = VerifyFileType.checkFileType(multipartFile);
                    	if(checkFileType){
                    		System.out.println("正确上传了");
                    		 //否则直接将文件内容拷贝至新文件  
                            multipartFile.transferTo(targetFile);
                    	}
                    	else{
                    		System.out.println("异常");
                    	}
                         
                    }  
                }  
            }
        }  
          
    }  
      
    /** 
     * 保存上传文件,兼合并功能 
     */  
    private static void saveUploadFile(InputStream input, File targetFile, boolean append) throws IOException {  
        OutputStream out = null;  
        try {  
            if (targetFile.exists() && append) {  
                out = new BufferedOutputStream(new FileOutputStream(targetFile, true), BUF_SIZE);  
            } else {  
                out = new BufferedOutputStream(new FileOutputStream(targetFile), BUF_SIZE);  
            }  
              
            byte[] buffer = new byte[BUF_SIZE];  
            int len = 0;  
            //写入文件  
            while ((len = input.read(buffer)) > 0) {  
                out.write(buffer, 0, len);  
            }  
        } catch (IOException e) {  
            throw e;  
        } finally {  
            //关闭输入输出流  
            if (null != input) {  
                try {  
                    input.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
            if (null != out) {  
                try {  
                    out.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
      
    /** 
     * 判断是否全部上传完成 
     * 碎片需合并后才返回真 
     */  
    public static boolean isUploadFinish(Plupload plupload) {  
        return (plupload.getChunks() - plupload.getChunk() == 1);  
    }  
}

 VerifyFileType.java

package com.genersoft.pub.FileUpload.util;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.springframework.web.multipart.MultipartFile;
public class VerifyFileType {
public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();     
    
    private VerifyFileType(){}
    static{     
        getAllFileType(); //初始化文件类型信息     
    }     
         
    /**   
     * Discription:[getAllFileType,常见文件头信息] 
     */     
    private static void getAllFileType()     
    {     
//        FILE_TYPE_MAP.put("ffd8ffe000104a464946", "jpg"); //JPEG (jpg)     
//        FILE_TYPE_MAP.put("89504e470d0a1a0a0000", "png"); //PNG (png)     
//        FILE_TYPE_MAP.put("47494638396126026f01", "gif"); //GIF (gif)     
//        FILE_TYPE_MAP.put("49492a00227105008037", "tif"); //TIFF (tif)     
//        FILE_TYPE_MAP.put("424d228c010000000000", "bmp"); //16色位图(bmp)     
//        FILE_TYPE_MAP.put("424d8240090000000000", "bmp"); //24位位图(bmp)     
//        FILE_TYPE_MAP.put("424d8e1b030000000000", "bmp"); //256色位图(bmp)     
//        FILE_TYPE_MAP.put("41433130313500000000", "dwg"); //CAD (dwg)     
          FILE_TYPE_MAP.put("3c21444f435459504520", "html"); //HTML (html)
          FILE_TYPE_MAP.put("3c21646f637479706520", "htm"); //HTM (htm)
          FILE_TYPE_MAP.put("48544d4c207b0d0a0942", "css"); //css
          FILE_TYPE_MAP.put("696b2e71623d696b2e71", "js"); //js
//        FILE_TYPE_MAP.put("7b5c727466315c616e73", "rtf"); //Rich Text Format (rtf)     
//        FILE_TYPE_MAP.put("38425053000100000000", "psd"); //Photoshop (psd)     
//        FILE_TYPE_MAP.put("46726f6d3a203d3f6762", "eml"); //Email [Outlook Express 6] (eml)       
//        FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "doc"); //MS Excel 注意:word、msi 和 excel的文件头一样     
//        FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "vsd"); //Visio 绘图     
//        FILE_TYPE_MAP.put("5374616E64617264204A", "mdb"); //MS Access (mdb)      
//        FILE_TYPE_MAP.put("252150532D41646F6265", "ps");     
//        FILE_TYPE_MAP.put("255044462d312e350d0a", "pdf"); //Adobe Acrobat (pdf)   
//        FILE_TYPE_MAP.put("2e524d46000000120001", "rmvb"); //rmvb/rm相同  
//        FILE_TYPE_MAP.put("464c5601050000000900", "flv"); //flv与f4v相同  
//        FILE_TYPE_MAP.put("00000020667479706d70", "mp4"); 
//        FILE_TYPE_MAP.put("49443303000000002176", "mp3"); 
//        FILE_TYPE_MAP.put("000001ba210001000180", "mpg"); //     
//        FILE_TYPE_MAP.put("3026b2758e66cf11a6d9", "wmv"); //wmv与asf相同    
//        FILE_TYPE_MAP.put("52494646e27807005741", "wav"); //Wave (wav)  
//        FILE_TYPE_MAP.put("52494646d07d60074156", "avi");  
//        FILE_TYPE_MAP.put("4d546864000000060001", "mid"); //MIDI (mid)   
//        FILE_TYPE_MAP.put("526172211a0700cf9073", "zip");    
//        FILE_TYPE_MAP.put("504b0304140000000800", "rar");   
//        FILE_TYPE_MAP.put("235468697320636f6e66", "ini");   
//        FILE_TYPE_MAP.put("504b03040a0000000000", "jar"); 
          FILE_TYPE_MAP.put("3c25402070616765206c", "jsp");//jsp文件
//        FILE_TYPE_MAP.put("4d616e69666573742d56", "mf");//MF文件
//        FILE_TYPE_MAP.put("3c3f786d6c2076657273", "xml");//xml文件
          FILE_TYPE_MAP.put("494e5345525420494e54", "sql");//xml文件
          FILE_TYPE_MAP.put("7061636b616765207765", "java");//java文件
          FILE_TYPE_MAP.put("406563686f206f66660d", "bat");//bat文件
//        FILE_TYPE_MAP.put("1f8b0800000000000000", "gz");//gz文件
//        FILE_TYPE_MAP.put("6c6f67346a2e726f6f74", "properties");//bat文件
          FILE_TYPE_MAP.put("cafebabe0000002e0041", "class");//bat文件
//        FILE_TYPE_MAP.put("49545346030000006000", "chm");//bat文件
//        FILE_TYPE_MAP.put("04000000010000001300", "mxp");//bat文件
  //      FILE_TYPE_MAP.put("504b0304140006000800", "docx");//docx文件
//        FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "wps");//WPS文字wps、表格et、演示dps都是一样的
//        FILE_TYPE_MAP.put("6431303a637265617465", "torrent");
           FILE_TYPE_MAP.put("3c68746d6c20786d6c6e", "htm");//htm
//        FILE_TYPE_MAP.put("46726f6d3a3cd3c920cd", "mht");//mht
//        FILE_TYPE_MAP.put("6D6F6F76", "mov"); //Quicktime (mov)  
//        FILE_TYPE_MAP.put("FF575043", "wpd"); //WordPerfect (wpd)   
//        FILE_TYPE_MAP.put("CFAD12FEC5FD746F", "dbx"); //Outlook Express (dbx)     
//        FILE_TYPE_MAP.put("21424440E", "pst"); //Outlook (pst)      
//        FILE_TYPE_MAP.put("AC9EBD8F", "qdf"); //Quicken (qdf)     
//        FILE_TYPE_MAP.put("E3828596", "pwl"); //Windows Password (pwl)         
//        FILE_TYPE_MAP.put("2E7261FD", "ram"); //Real Audio (ram)   
          FILE_TYPE_MAP.put("4d5a9000030000000400", "exe");//可执行文件
    }                       
    
    /**
     * 得到上传文件的文件头
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
    
    /**
     * 根据制定文件的文件头判断其文件类型
     * @param filePaht
     * @return 当文件格式为exe时,返回false;否则返回true
     */
    public static boolean checkFileType(MultipartFile upfile){
        String res = null;
        try {
        	
        	InputStream is = upfile.getInputStream();
        	System.out.println("2");
            byte[] b = new byte[10];
            is.read(b, 0, b.length);
            String fileCode = bytesToHexString(b);    
            
            System.out.println("3:"+fileCode);
            
            
            //这种方法在字典的头代码不够位数的时候可以用但是速度相对慢一点
            Iterator<String> keyIter = FILE_TYPE_MAP.keySet().iterator();
            while(keyIter.hasNext()){
                String key = keyIter.next();
                if(key.toLowerCase().startsWith(fileCode.toLowerCase()) || fileCode.toLowerCase().startsWith(key.toLowerCase())){
                    res = FILE_TYPE_MAP.get(key);
                    System.out.println("4:"+key);
                    System.out.println("5:"+res);
                    return false;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }
}

plupload实体类:

package com.genersoft.pub.FileUpload.data;
import javax.servlet.http.HttpServletRequest;

import org.springframework.web.multipart.MultipartFile;
/**
 * plupload实体类
 */
public class Plupload {
	/**文件临时名(打文件被分解时)或原名*/  
    private String name;  
    /**总的块数*/  
    private int chunks = -1;  
    /**当前块数(从0开始计数)*/  
    private int chunk = -1;  
    /**HttpServletRequest对象,不能直接传入进来,需要手动传入*/  
    private HttpServletRequest request;  
    /**保存文件上传信息,不能直接传入进来,需要手动传入*/  
    private MultipartFile multipartFile;  
      
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public int getChunks() {  
        return chunks;  
    }  
  
    public void setChunks(int chunks) {  
        this.chunks = chunks;  
    }  
  
    public int getChunk() {  
        return chunk;  
    }  
  
    public void setChunk(int chunk) {  
        this.chunk = chunk;  
    }  
  
    public HttpServletRequest getRequest() {  
        return request;  
    }  
  
    public void setRequest(HttpServletRequest request) {  
        this.request = request;  
    }  
  
    public MultipartFile getMultipartFile() {  
        return multipartFile;  
    }  
  
    public void setMultipartFile(MultipartFile multipartFile) {  
        this.multipartFile = multipartFile;  
    }  
}

上传方法:

 @RequestMapping(value="/uploads")  
    public String upload(Plupload plupload,HttpServletRequest request, HttpServletResponse response) {  
          
        //System.out.println(plupload.getChunk() + "===" + plupload.getName() + "---" + plupload.getChunks());  
        plupload.setRequest(request);  
        String dirFile=request.getParameter("dirFile");
        if(dirFile == null || "".equals(dirFile)){
        	dirFile=FileDir;
        }
        //文件存储路径  
        File dir = new File(plupload.getRequest().getSession().getServletContext().getRealPath("/") + dirFile);  
          
        System.out.println(dir.getPath());  
          
        try {  
            //上传文件  
        	PluploadUtil.upload(plupload, dir);
            //判断文件是否上传成功(被分成块的文件是否全部上传完成)  
            if (PluploadUtil.isUploadFinish(plupload)) {  
                System.out.println(plupload.getName() + "----");  
            }  
              
        } catch (IllegalStateException e) {   
            e.printStackTrace();  
        } catch (IOException e) {   
            e.printStackTrace();  
        }  
        
        return "login.upload";  
    } 
    

文件删除方法:

@RequestMapping(value="/uploadsDelete")
    @ResponseBody
    public String uploadsDelete(Plupload plupload,HttpServletRequest request) {  
    	String result = "";
    	String dirFile = null;
		try {
			dirFile =URLDecoder.decode(request.getParameter("dirFile"),"UTF-8");
			dirFile = dirFile.replace("/", "\\");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
        if(dirFile == null || "".equals(dirFile)){
        	dirFile=FileDir;
        }
        //文件存储路径  绝对路径
        String dir=request.getSession().getServletContext().getRealPath("/")+dirFile;
        File file = new File(dir);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
	       file.delete();
	       result = "成功";
	    }
    	return result;
    }

文件下载方法:

@RequestMapping(value="/download")  
	 public void download(HttpServletRequest request,HttpServletResponse response) throws Exception 
		 { 
			 String fileName =  request.getParameter("fileName"); 
			 fileName =  URLDecoder.decode(fileName,"UTF-8").replace(";", "");
			 String dir = request.getParameter("dir");
			//windows环境处理  linux下路径不识别\;windows下“/”  “\”都可以
			 if(dir.startsWith("/")){//对路径开头以"/"的值处理
				 dir = dir.substring(1);
			 }
			 dir = URLDecoder.decode(dir,"UTF-8");
			 String realPath = request.getSession().getServletContext().getRealPath("/");
			 String fileDir = "";
			 //区分新增、修改 下载路径(新增  dir 不包含文件名fileName  修改 包含文件名fileName)
			 if(dir.indexOf(fileName)>=0){
				 fileDir = realPath+dir;
			 }else{
				 fileDir = realPath+dir+fileName;
			 }
			
			 File f = new File(fileDir);
			 String file_name = new String(fileName.getBytes(), "ISO-8859-1");
			 response.setHeader("Content-Disposition", "attachment; filename="+file_name); 
			 response.setContentType("application/octet-stream"); 
			 BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));
			 byte[] buf = new byte[1024];
			 int len = 0;
			 OutputStream out = response.getOutputStream();
			 while ((len = br.read(buf)) > 0){
					out.write(buf, 0, len);
			 }
			 br.close();
			 out.close(); 
	    }

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值