JAVA微信公众号开发之二维码的创建与获取

微信文档说明

两种二维码:

1、临时二维码,是有过期时间的,最长可以设置为在二维码生成后的30天(即2592000秒)后过期,但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景
2、永久二维码,是无过期时间的,但数量较少(目前为最多10万个)。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。

用户扫描带场景值二维码时,可能推送以下两种事件:

如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。

如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。

获取带参数的二维码的过程包括两步,首先创建二维码ticket,然后凭借ticket到指定URL换取二维码。

 

 

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.liaofang.mapper.AccessTokenMapper;
import com.liaofang.po.AccessTokenPO;
import com.liaofang.po.WeiXinResult;
import com.liaofang.service.AccessTokenServiceImp;
import com.liaofang.util.ConfigUtil;
import com.liaofang.util.GetMapSign;
import com.liaofang.util.HttpRequestUtil;
import com.liaofang.util.SignUtil;
import net.sf.json.JSONObject;

	@Service

		
	public class WxQRCodeServiceImp implements WxQRCodeService {
		@Autowired
		private AccessTokenMapper atMapper;
		/**
		 * 创建临时二维码
		 * @MethodName:createTempTicket
		 *@author:maliran
		 *@ReturnType:String
		 *@param accessToken
		 *@param expireSeconds
		 *@param sceneId
		 *@return
		 * @throws Exception 
		 */
		public String createTempTicket(String expireSeconds, int sceneId) throws Exception {   
		      
			

			Map<String,String> map = new HashMap<String,String>();
			AccessTokenPO atPO = new AccessTokenPO();
			List<AccessTokenPO> list = new ArrayList<AccessTokenPO>();
			String accessToken = "";
			String jsapi_ticket="";
			String ticket="";
				list = atMapper.selectToken();
				System.out.println(list.size());
				
				if(list.size()!=0){
					System.out.println(list.get(0));
			    if((new Date().getTime()/1000-list.get(0).getCurrentTime().getTime()/1000)>6000){
			    	//access_token过期
			    	map = GetMapSign.getTicket();
			    	accessToken = map.get("access_token");
			    	atPO.setAccess_token(accessToken);
			    	atPO.setCurrentTime(new Date());
			    	atPO.setExpires_in(Integer.parseInt(map.get("expires_in")));
			    	jsapi_ticket=map.get("ticket");
			    	atPO.setTicket(jsapi_ticket);
			    	atMapper.updateToken(atPO);
			     }
			    else{
			    	list = atMapper.selectToken();
			    	jsapi_ticket=list.get(0).getTicket();
			    	accessToken = list.get(0).getAccess_token();
			    }
			}else{
				map = GetMapSign.getTicket();
				accessToken = map.get("access_token");
		    	atPO.setAccess_token(accessToken);
		    	atPO.setCurrentTime(new Date());
		    	atPO.setExpires_in(Integer.parseInt(map.get("expires_in")));
		    	jsapi_ticket=map.get("ticket");
		    	atPO.setTicket(jsapi_ticket);
		    	atMapper.insertToken(atPO);
			}
		    TreeMap<String,String> params = new TreeMap<String,String>();  
		    params.put("access_token", accessToken);  
		    Map<String,Integer> intMap = new HashMap<String,Integer>();  
		    intMap.put("scene_id",sceneId);  
		    Map<String,Map<String,Integer>> mapMap = new HashMap<String,Map<String,Integer>>();  
		    mapMap.put("scene", intMap);  
		    //  
		    Map<String,Object> paramsMap = new HashMap<String,Object>();  
		    paramsMap.put("expire_seconds", expireSeconds);  
		    paramsMap.put("action_name", ConfigUtil.QR_SCENE);  
		    paramsMap.put("action_info", mapMap);  
		    String data = JSONObject.fromObject(paramsMap).toString();  
		    JSONObject jsonObject = SignUtil.doPostStr(ConfigUtil.CREATE_TICKET_PATH, data);
		    
		    if(jsonObject!=null){
		    	ticket = jsonObject.optString("ticket");
		    }
		    return ticket;
		  
		}   
		/** 
		 * 创建永久二维码(数字) 
		 * @param accessToken 
		 * @param sceneId 场景Id 
		 * @return 
		 * @throws Exception 
		 */  
		public String createForeverTicket(int sceneId) throws Exception {  
			
			Map<String,String> map = new HashMap<String,String>();
			AccessTokenPO atPO = new AccessTokenPO();
			List<AccessTokenPO> list = new ArrayList<AccessTokenPO>();
			String accessToken = "";
			String jsapi_ticket="";
			String ticket="";
				list = atMapper.selectToken();
				System.out.println(list.size());
				
				if(list.size()!=0){
					System.out.println(list.get(0));
			    if((new Date().getTime()/1000-list.get(0).getCurrentTime().getTime()/1000)>6000){
			    	//access_token过期
			    	map = GetMapSign.getTicket();
			    	accessToken = map.get("access_token");
			    	atPO.setAccess_token(accessToken);
			    	atPO.setCurrentTime(new Date());
			    	atPO.setExpires_in(Integer.parseInt(map.get("expires_in")));
			    	jsapi_ticket=map.get("ticket");
			    	atPO.setTicket(jsapi_ticket);
			    	atMapper.updateToken(atPO);
			     }
			    else{
			    	list =atMapper.selectToken();
			    	jsapi_ticket=list.get(0).getTicket();
			    	accessToken = list.get(0).getAccess_token();
			    }
			}else{
				map = GetMapSign.getTicket();
				accessToken = map.get("access_token");
		    	atPO.setAccess_token(accessToken);
		    	atPO.setCurrentTime(new Date());
		    	atPO.setExpires_in(Integer.parseInt(map.get("expires_in")));
		    	jsapi_ticket=map.get("ticket");
		    	atPO.setTicket(jsapi_ticket);
		    	atMapper.insertToken(atPO);
			}
		    TreeMap<String,String> params = new TreeMap<String,String>();  
		    params.put("access_token", accessToken);  
		    Map<String,Integer> intMap = new HashMap<String,Integer>();  
		    intMap.put("scene_id",sceneId);  
		    Map<String,Map<String,Integer>> mapMap = new HashMap<String,Map<String,Integer>>();  
		    mapMap.put("scene", intMap);  
		    Map<String,Object> paramsMap = new HashMap<String,Object>();    
		    paramsMap.put("action_name", ConfigUtil.QR_LIMIT_SCENE);  
		    paramsMap.put("action_info", mapMap); 
		    String data =JSONObject.fromObject(paramsMap).toString();  
		    JSONObject jsonObject = SignUtil.doPostStr(ConfigUtil.CREATE_TICKET_PATH, data);
		    
		    if(jsonObject!=null){
		    	ticket = jsonObject.optString("ticket");
		    }
		    return ticket;
		    
		}  
		  
		/** 
		 * 创建永久二维码(字符串) 
		 *  
		 * @param accessToken 
		 * @param sceneStr 场景str 
		 * @return 
		 * @throws Exception 
		 */  
		public String createForeverStrTicket(String sceneStr) throws Exception{        
			
			Map<String,String> map = new HashMap<String,String>();
			AccessTokenPO atPO = new AccessTokenPO();
			List<AccessTokenPO> list = new ArrayList<AccessTokenPO>();
			String accessToken = "";
			String jsapi_ticket="";
			String ticket="";
				list = atMapper.selectToken();
				System.out.println(list.size());
				
				if(list.size()!=0){
					System.out.println(list.get(0));
			    if((new Date().getTime()/1000-list.get(0).getCurrentTime().getTime()/1000)>6000){
			    	//access_token过期
			    	map = GetMapSign.getTicket();
			    	accessToken = map.get("access_token");
			    	atPO.setAccess_token(accessToken);
			    	atPO.setCurrentTime(new Date());
			    	atPO.setExpires_in(Integer.parseInt(map.get("expires_in")));
			    	jsapi_ticket=map.get("ticket");
			    	atPO.setTicket(jsapi_ticket);
			    	atMapper.updateToken(atPO);
			     }
			    else{
			    	list = atMapper.selectToken();
			    	jsapi_ticket=list.get(0).getTicket();
			    	accessToken = list.get(0).getAccess_token();
			    }
			}else{
				map = GetMapSign.getTicket();
				accessToken = map.get("access_token");
		    	atPO.setAccess_token(accessToken);
		    	atPO.setCurrentTime(new Date());
		    	atPO.setExpires_in(Integer.parseInt(map.get("expires_in")));
		    	jsapi_ticket=map.get("ticket");
		    	atPO.setTicket(jsapi_ticket);
		    	atMapper.insertToken(atPO);
			}
		    TreeMap<String,String> params = new TreeMap<String,String>();  
		    params.put("access_token", accessToken); 
		    String url = ConfigUtil.CREATE_TICKET_PATH.replace("ACCESS_TOKEN", accessToken);
		    Map<String,String> intMap = new HashMap<String,String>();  
		    intMap.put("scene_str",sceneStr);  
		    Map<String,Map<String,String>> mapMap = new HashMap<String,Map<String,String>>();  
		    mapMap.put("scene", intMap);  
		    Map<String,Object> paramsMap = new HashMap<String,Object>();    
		    paramsMap.put("action_name", ConfigUtil.QR_LIMIT_STR_SCENE);  
		    paramsMap.put("action_info", mapMap); 
		    String data =JSONObject.fromObject(paramsMap).toString();  
		    JSONObject jsonObject = SignUtil.doPostStr(url, data);
		
		    if(jsonObject!=null){
		    	ticket = jsonObject.optString("ticket");
		    }
		    return ticket;
		     
		}  
		
		/** 
		 * 获取二维码ticket后,通过ticket换取二维码图片展示 
		 * @param ticket 
		 * @return 
		 */  
		public String showQrcode(String ticket){  
		    String	showqrcode_path = "";
			Map<String,String> params = new TreeMap<String,String>();  
		    params.put("ticket", HttpRequestUtil.urlEncode(ticket, HttpRequestUtil.DEFAULT_CHARSET));  
		    try {  
		        showqrcode_path = HttpRequestUtil.setParmas(params,ConfigUtil.SHOWCODE_PATH,"");  
		    } catch (Exception e) {  
		        e.printStackTrace();  
		    }  
		    return showqrcode_path;  
		}  
		  
		/** 
		 * 获取二维码ticket后,通过ticket换取二维码图片 
		 * @param ticket 
		 * @param savePath  保存的路径,例如 F:\\test\test.jpg 
		 * @return      Result.success = true 表示下载图片下载成功 
		 */  
		public WeiXinResult showQrcode(String ticket,String savePath) throws Exception{  
		    TreeMap<String,String> params = new TreeMap<String,String>();  
		    params.put("ticket", HttpRequestUtil.urlEncode(ticket, HttpRequestUtil.DEFAULT_CHARSET));  
		    WeiXinResult result = HttpRequestUtil.downMeaterMetod(params,HttpRequestUtil.GET_METHOD,ConfigUtil.  
		    
SHOWCODE_PATH,savePath);

return result; } }

 

 

 

 

 

 

 

 
import java.io.File;  
import java.io.FileNotFoundException;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.OutputStream;  
import java.io.UnsupportedEncodingException;  
import java.net.HttpURLConnection;  
import java.net.MalformedURLException;  
import java.net.URL;  
import java.net.URLEncoder;  
import java.util.Map;  
import java.util.Map.Entry;  
import java.util.Set;  
import java.util.TreeMap;  
  
import javax.net.ssl.HostnameVerifier;  
import javax.net.ssl.HttpsURLConnection;  
import javax.net.ssl.KeyManager;  
import javax.net.ssl.SSLContext;  
import javax.net.ssl.SSLSession;  
import javax.net.ssl.TrustManager;  
  
import com.liaofang.po.WeiXinResult;  
  
public class HttpRequestUtil {  
  
    //private static Logger logger = Logger.getLogger(HttpRequestUtil.class);  
  
    public static final String GET_METHOD = "GET";  
  
    public static final String POST_METHOD = "POST";  
  
    public static final String DEFAULT_CHARSET = "utf-8";  
  
    private static int DEFAULT_CONNTIME = 5000;  
      
    private static int DEFAULT_READTIME = 5000;  
    // 获取access_token的路径  
    private static String token_path = "https://api.weixin.qq.com/cgi-bin/token";  
  
    /** 
     * http请求 
     *  
     * @param method 
     *            请求方法GET/POST 
     * @param path 
     *            请求路径 
     * @param timeout 
     *            连接超时时间 默认为5000 
     * @param readTimeout 
     *            读取超时时间 默认为5000 
     * @param data  数据 
     * @return 
     */  
    public static String defaultConnection(String method, String path, int timeout, int readTimeout, String data)  
            throws Exception {  
        String result = "";  
        URL url = new URL(path);  
        if (url != null) {  
            HttpURLConnection conn = getConnection(method, url);  
            conn.setConnectTimeout(timeout == 0 ? DEFAULT_CONNTIME : timeout);  
            conn.setReadTimeout(readTimeout == 0 ? DEFAULT_READTIME : readTimeout);  
            if (data != null && !"".equals(data)) {  
                OutputStream output = conn.getOutputStream();  
                output.write(data.getBytes(DEFAULT_CHARSET));  
                output.flush();  
                output.close();  
            }  
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {  
                InputStream input = conn.getInputStream();  
                result = inputToStr(input);  
                input.close();  
                conn.disconnect();  
            }  
        }  
        return result;  
    }  
  
    /** 
     * 根据url的协议选择对应的请求方式 例如 http://www.baidu.com 则使用http请求,https://www.baidu.com 
     * 则使用https请求 
     *  
     * @param method 
     *            请求的方法 
     * @return 
     * @throws IOException 
     */  
    private static HttpURLConnection getConnection(String method, URL url) throws IOException {  
        HttpURLConnection conn = null;  
        if ("https".equals(url.getProtocol())) {  
            SSLContext context = null;  
            try {  
                context = SSLContext.getInstance("SSL", "SunJSSE");  
                context.init(new KeyManager[0], new TrustManager[] { new MyX509TrustManager() }, 

                        new java.security.SecureRandom());  
            } catch (Exception e) {  
                throw new IOException(e);  
            }  
            HttpsURLConnection connHttps = (HttpsURLConnection) url.openConnection();  
            connHttps.setSSLSocketFactory(context.getSocketFactory());  
            connHttps.setHostnameVerifier(new HostnameVerifier() {  
  
                @Override  
                public boolean verify(String arg0, SSLSession arg1) {  
                    return true;  
                }  
            });  
            conn = connHttps;  
        } else {  
            conn = (HttpURLConnection) url.openConnection();  
        }  
        conn.setRequestMethod(method);  
        conn.setUseCaches(false);  
        conn.setDoInput(true);  
        conn.setDoOutput(true);  
        return conn;  
    }  
  
    /** 
     * 将输入流转换为字符串 
     *  
     * @param input 
     *            输入流 
     * @return 转换后的字符串 
     */  
    public static String inputToStr(InputStream input) {  
        String result = "";  
        if (input != null) {  
            byte[] array = new byte[1024];  
            StringBuffer buffer = new StringBuffer();  
            try {  
                for (int index; (index = (input.read(array))) > -1;) {  
                    buffer.append(new String(array, 0, index, DEFAULT_CHARSET));  
                }  
                result = buffer.toString();  
            } catch (IOException e) {  
                e.printStackTrace();  
                result = "";  
            }  
        }  
        return result;  
    }  
  
    /** 
     * 设置参数 
     *  
     * @param map 
     *            参数map 
     * @param path 
     *            需要赋值的path 
     * @param charset 
     *            编码格式 默认编码为utf-8(取消默认) 
     * @return 已经赋值好的url 只需要访问即可 
     */  
    public static String setParmas(Map<String, String> map, String path, String charset) throws Exception {  
        String result = "";  
        boolean hasParams = false;  
        if (path != null && !"".equals(path)) {  
            if (map != null && map.size() > 0) {  
                StringBuilder builder = new StringBuilder();  
                Set<Entry<String, String>> params = map.entrySet();  
                for (Entry<String, String> entry : params) {  
                    String key = entry.getKey().trim();  
                    String value = entry.getValue().trim();  
                    if (hasParams) {  
                        builder.append("&");  
                    } else {  
                        hasParams = true;  
                    }  
                    if(charset != null && !"".equals(charset)){  
                        //builder.append(key).append("=").append(URLDecoder.(value, charset));    
                        builder.append(key).append("=").append(urlEncode(value, charset));  
                    }else{  
                        builder.append(key).append("=").append(value);  
                    }  
                }  
                result = builder.toString();  
            }  
        }  
        return doUrlPath(path, result).toString();  
    }  
  
    /** 
     * 设置连接参数 
     *  
     * @param path 
     *            路径 
     * @return 
     */  
    private static URL doUrlPath(String path, String query) throws Exception {  
        URL url = new URL(path);  
        if (org.apache.commons.lang.StringUtils.isEmpty(path)) {  
            return url;  
        }  
        if (org.apache.commons.lang.StringUtils.isEmpty(url.getQuery())) {  
            if (path.endsWith("?")) {  
                path += query;  
            } else {  
                path = path + "?" + query;  
            }  
        } else {  
            if (path.endsWith("&")) {  
                path += query;  
            } else {  
                path = path + "&" + query;  
            }  
        }  
        return new URL(path);  
    }  
  
    /** 
     * 默认的http请求执行方法,返回 
     *  
     * @param method 
     *            请求的方法 POST/GET 
     * @param path 
     *            请求path 路径 
     * @param map 
     *            请求参数集合 
     * @param data 
     *            输入的数据 允许为空 
     * @return 
     */  
    public static String HttpDefaultExecute(String method, String path, Map<String, String> map, String data) {  
        String result = "";  
        try {  
            String url = setParmas((TreeMap<String, String>) map, path, "");  
            result = defaultConnection(method, url, DEFAULT_CONNTIME, DEFAULT_READTIME, data);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
    /** 
     * 默认的https执行方法,返回 
     *  
     * @param method 
     *            请求的方法 POST/GET 
     * @param path 
     *            请求path 路径 
     * @param map 
     *            请求参数集合 
     * @param data 
     *            输入的数据 允许为空 
     * @return 
     */  
    public static String HttpsDefaultExecute(String method, String path, Map<String, String> map, String data) {  
        String result = "";  
        try {  
            String url = setParmas((TreeMap<String, String>) map, path, "");  
            result = defaultConnection(method, url, DEFAULT_CONNTIME, DEFAULT_READTIME, data);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
  
    /** 
     * 默认的下载素材方法 
     *  
     * @param method  http方法 POST/GET 
     * @param apiPath api路径 
     * @param savePath 素材需要保存的路径 
     * @return 是否下载成功 Reuslt.success==true 表示下载成功 
     */  
    public static WeiXinResult downMeaterMetod(TreeMap<String, String> params, String method, String apiPath, String savePath) {  
        WeiXinResult result = new WeiXinResult();  
        try {  
            apiPath = setParmas(params, apiPath, "");  
            URL url = new URL(apiPath);  
            HttpURLConnection conn = getConnection(method, url);  
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {  
                String contentType = conn.getContentType();  
                result = ContentType(contentType, conn, savePath);  
            } else {  
                result.setObj(conn.getResponseCode() + " " + conn.getResponseMessage());  
            }  
        } catch (MalformedURLException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
    /** 
     * 根据返回的头信息返回具体信息 
     *  
     * @param contentType 
     *            ContentType请求头信息 
     * @return Result.type==1 表示文本消息, 
     */  
    private static WeiXinResult ContentType(String contentType, HttpURLConnection conn, String savePath) {  
        WeiXinResult result = new WeiXinResult();  
        try {  
            if (conn != null) {  
                InputStream input = conn.getInputStream();  
                if (contentType.equals("image/gif")) { // gif图片  
                    result = InputStreamToMedia(input, savePath, "gif");  
                } else if (contentType.equals("image/jpeg")) { // jpg图片  
                    result = InputStreamToMedia(input, savePath, "jpg");  
                } else if (contentType.equals("image/jpg")) { // jpg图片  
                    result = InputStreamToMedia(input, savePath, "jpg");  
                } else if (contentType.equals("image/png")) { // png图片  
                    result = InputStreamToMedia(input, savePath, "png");  
                } else if (contentType.equals("image/bmp")) { // bmp图片  
                    result = InputStreamToMedia(input, savePath, "bmp");  
                } else if (contentType.equals("audio/x-wav")) { // wav语音  
                    result = InputStreamToMedia(input, savePath, "wav");  
                } else if (contentType.equals("audio/x-ms-wma")) { // wma语言  
                    result = InputStreamToMedia(input, savePath, "wma");  
                } else if (contentType.equals("audio/mpeg")) { // mp3语言  
                    result = InputStreamToMedia(input, savePath, "mp3");  
                } else if (contentType.equals("text/plain")) { // 文本信息  
                    String str = inputToStr(input);  
                    result.setObj(str);  
                } else if (contentType.equals("application/json")) { // 返回json格式的数据  
                    String str = inputToStr(input);  
                    result.setObj(str);  
                } else { // 此处有问题  
                    String str = inputToStr(input);  
                    result.setObj(str);  
                }  
            } else {  
                result.setObj("conn is null!");  
            }  
        } catch (Exception ex) {  
            ex.printStackTrace();  
        }  
        return result;  
    }  
  
    /** 
     * 将字符流转换为图片文件 
     *  
     * @param input 字符流 
     * @param savePath 图片需要保存的路径 
     * @param 类型 jpg/png等 
     * @return 
     */  
    private static WeiXinResult InputStreamToMedia(InputStream input, String savePath, String type) {  
        WeiXinResult result = new WeiXinResult();  
        try {  
            File file = null;  
            file = new File(savePath);  
            String paramPath = file.getParent(); // 路径  
            String fileName = file.getName(); //  
            String newName = fileName.substring(0, fileName.lastIndexOf(".")) + "." + type;// 根据实际返回的文件类型后缀  
            savePath = paramPath + "\\" + newName;  
            if (!file.exists()) {  
                File dirFile = new File(paramPath);  
                dirFile.mkdirs();  
            }  
            file = new File(savePath);  
            FileOutputStream output = new FileOutputStream(file);  
            int len = 0;  
            byte[] array = new byte[1024];  
            while ((len = input.read(array)) != -1) {  
                output.write(array, 0, len);  
            }  
            output.flush();  
            output.close();  
            result.setSuccess(true);  
            result.setObj("save success!");  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
            result.setSuccess(false);  
            result.setObj(e.getMessage());  
        } catch (IOException e) {  
            e.printStackTrace();  
            result.setSuccess(false);  
            result.setObj(e.getMessage());  
        }  
        return result;  
    }  
  
    public static String urlEncode(String source, String encode) {  
        String result = source;  
        try {  
            result = URLEncoder.encode(source, encode);  
        } catch (UnsupportedEncodingException e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
}  

 

/**
	 * post请求
	 */
	public static JSONObject doPostStr(String url,String outStr){

		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpPost httpPost = new HttpPost(url);
		JSONObject jsonObject = null;
		String result="";
		try {
			httpPost.setEntity(new StringEntity(outStr,"utf-8"));
			HttpResponse response = httpClient.execute(httpPost);
			result = EntityUtils.toString(response.getEntity(),"utf-8");
		} catch (Exception e) {
		} 
		jsonObject = JSONObject.fromObject(result);
		return jsonObject;
	}	

 

 

最近在整理一些资源工具,放在网站分享 http://tools.maqway.com
欢迎关注公众号:麻雀唯伊 , 不定时更新资源文章,生活优惠,或许有你想看的

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值