精华内容
下载资源
问答
  • Java调用第三方接口示范

    万次阅读 多人点赞 2018-10-08 15:03:53
    在项目开发中经常会遇到调用第三方接口的情况,比如说调用第三方的天气预报接口。 使用流程 【1】准备工作:在项目的工具包下导入HttpClientUtil这个工具类,或者也可以使用Spring框架的restTemplate来调用,上面...

    人工智能,零基础入门!http://www.captainbed.net/inner

    在项目开发中经常会遇到调用第三方接口的情况,比如说调用第三方的天气预报接口。

    使用流程

    【1】准备工作:在项目的工具包下导入HttpClientUtil这个工具类,或者也可以使用Spring框架的restTemplate来调用,上面有调用接口的方法【分为Get和Post方式的有参和无参调用】:

    package com.njsc.credit.util;
    
    import java.io.IOException;
    import java.net.URI;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.http.NameValuePair;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.client.utils.URIBuilder;
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.util.EntityUtils;
    
    public class HttpClientUtil {
    
    	/**
    	 * 带参数的get请求
    	 * @param url
    	 * @param param
    	 * @return String
    	 */
    	public static String doGet(String url, Map<String, String> param) {
    		// 创建Httpclient对象
    		CloseableHttpClient httpclient = HttpClients.createDefault();
    
    		String resultString = "";
    		CloseableHttpResponse response = null;
    		try {
    			// 创建uri
    			URIBuilder builder = new URIBuilder(url);
    			if (param != null) {
    				for (String key : param.keySet()) {
    					builder.addParameter(key, param.get(key));
    				}
    			}
    			URI uri = builder.build();
    			// 创建http GET请求
    			HttpGet httpGet = new HttpGet(uri);
    			// 执行请求
    			response = httpclient.execute(httpGet);
    			// 判断返回状态是否为200
    			if (response.getStatusLine().getStatusCode() == 200) {
    				resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				if (response != null) {
    					response.close();
    				}
    				httpclient.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return resultString;
    	}
    	
    	/**
    	 * 不带参数的get请求
    	 * @param url
    	 * @return String
    	 */
    	public static String doGet(String url) {
    		return doGet(url, null);
    	}
    
    	/**
    	 * 带参数的post请求
    	 * @param url
    	 * @param param
    	 * @return String
    	 */
    	public static String doPost(String url, Map<String, String> param) {
    		// 创建Httpclient对象
    		CloseableHttpClient httpClient = HttpClients.createDefault();
    		CloseableHttpResponse response = null;
    		String resultString = "";
    		try {
    			// 创建Http Post请求
    			HttpPost httpPost = new HttpPost(url);
    			// 创建参数列表
    			if (param != null) {
    				List<NameValuePair> paramList = new ArrayList<>();
    				for (String key : param.keySet()) {
    					paramList.add(new BasicNameValuePair(key, param.get(key)));
    				}
    				// 模拟表单
    				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
    				httpPost.setEntity(entity);
    			}
    			// 执行http请求
    			response = httpClient.execute(httpPost);
    			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				response.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return resultString;
    	}
    
    	/**
    	 * 不带参数的post请求
    	 * @param url
    	 * @return String
    	 */
    	public static String doPost(String url) {
    		return doPost(url, null);
    	}
    	
    	/**
    	 * 传送json类型的post请求
    	 * @param url
    	 * @param json
    	 * @return String
    	 */
    	public static String doPostJson(String url, String json) {
    		// 创建Httpclient对象
    		CloseableHttpClient httpClient = HttpClients.createDefault();
    		CloseableHttpResponse response = null;
    		String resultString = "";
    		try {
    			// 创建Http Post请求
    			HttpPost httpPost = new HttpPost(url);
    			// 创建请求内容
    			StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
    			httpPost.setEntity(entity);
    			// 执行http请求
    			response = httpClient.execute(httpPost);
    			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				response.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return resultString;
    	}
    }
    

    【2】创建url和访问key 以及参数等:

    代码如下:

    /**
     * 聚合接口校验身份证
     * @param idCard
     * @param realName
     * @return boolean
     */
    public boolean identityCheck(String idCard, String realName){
    	logger.info("-----------------调用聚合数据 身份证验证API BEGIN--------------->");
    	String key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    	String url = "http://op.juhe.cn/idcard/query" + "?key=" + key + "&idcard=" + idCard + "&realname=" + realName;
    	logger.info("请求url:" + url);
    	boolean match = false; //是否匹配
    	try {
    		String result = HttpClientUtil.doGet(url);
    		System.out.println("请求结果:" + result);
    		IdentityCheckResult identityCheckResult = JsonUtils.parse(result, IdentityCheckResult.class);
    		IdentityCheck identityCheck = JsonUtils.parse(result, "result", IdentityCheck.class);
    		logger.info(identityCheckResult);
    		logger.info(identityCheck.toString());
    		if(identityCheckResult.correct() && identityCheck.getRes() == 1){
    			match = true;
    		}
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	logger.info("<-----------------调用聚合数据 身份证验证API END---------------");
    	return match;
    }

    【3】请求这个第三方接口:

    使用HttpClientUtil工具类中的doGet方法来请求URL,得到结果,现在大多数是一个json字符串,类型为String

    【4】根据接口返回数据格式来解析数据:

    可以看到,返回参数有六个,所以在项目中新建一个bean,包含以上六个字段,用来接住返回数据,如下:

    因为接口返回的数据是一个json的字符串,类型实际上是一个String字符串,要解析数据,用工具类JsonUtils的parse方法将字符串转换为Java对象,JsonUtils的代码如下:

    package com.eqianxian.commons.utils.json;
    
    import java.util.List;
    import java.util.Map;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.alibaba.fastjson.serializer.PropertyFilter;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    
    /**
     * 在系统中统一使用这个,以方便将来切换不同的JSON生成工具
     * 
     * @author KelvinZ
     * 
     */
    public class JsonUtils {
    	public static final int TYPE_FASTJSON = 0;
    	public static final int TYPE_GSON = 1;
    
    	/**
    	 * <pre>
    	 * 对象转化为json字符串
    	 * 
    	 * @param obj 待转化对象
    	 * @return 代表该对象的Json字符串
    	 */
    	public static final String toJson(final Object obj) {
    		return JSON.toJSONString(obj);
    		// return gson.toJson(obj);
    	}
    
    	/**
    	 * <pre>
    	 * 对象转化为json字符串
    	 * 
    	 * @param obj 待转化对象
    	 * @return 代表该对象的Json字符串
    	 */
    	public static final String toJson(final Object obj, SerializerFeature... features) {
    		return JSON.toJSONString(obj, features);
    		// return gson.toJson(obj);
    	}
    
    	/**
    	 * 对象转化为json字符串并格式化
    	 * 
    	 * @param obj
    	 * @param format 是否要格式化
    	 * @return
    	 */
    	public static final String toJson(final Object obj, final boolean format) {
    		return JSON.toJSONString(obj, format);
    	}
    
    	/**
    	 * 对象对指定字段进行过滤处理,生成json字符串
    	 * 
    	 * @param obj
    	 * @param fields 过滤处理字段
    	 * @param ignore true做忽略处理,false做包含处理
    	 * @param features json特征,为null忽略
    	 * @return
    	 */
    	public static final String toJson(final Object obj, final String[] fields, final boolean ignore,
    			SerializerFeature... features) {
    		if (fields == null || fields.length < 1) {
    			return toJson(obj);
    		}
    		if (features == null)
    			features = new SerializerFeature[] { SerializerFeature.QuoteFieldNames };
    		return JSON.toJSONString(obj, new PropertyFilter() {
    			@Override
    			public boolean apply(Object object, String name, Object value) {
    				for (int i = 0; i < fields.length; i++) {
    					if (name.equals(fields[i])) {
    						return !ignore;
    					}
    				}
    				return ignore;
    			}
    		}, features);
    	}
    
    	/**
    	 * <pre>
    	 * 解析json字符串中某路径的值
    	 * 
    	 * @param json
    	 * @param path
    	 * @return
    	 */
    	@SuppressWarnings("unchecked")
    	public static final <E> E parse(final String json, final String path) {
    		String[] keys = path.split(",");
    		JSONObject obj = JSON.parseObject(json);
    		for (int i = 0; i < keys.length - 1; i++) {
    			obj = obj.getJSONObject(keys[i]);
    		}
    		return (E) obj.get(keys[keys.length - 1]);
    	}
    
    	/**
    	 * <pre>
    	 * json字符串解析为对象
    	 * 
    	 * @param json 代表一个对象的Json字符串
    	 * @param clazz 指定目标对象的类型,即返回对象的类型
    	 * @return 从json字符串解析出来的对象
    	 */
    	public static final <T> T parse(final String json, final Class<T> clazz) {
    		return JSON.parseObject(json, clazz);
    	}
    
    	/**
    	 * <pre>
    	 * json字符串解析为对象
    	 * 
    	 * @param json json字符串
    	 * @param path 逗号分隔的json层次结构
    	 * @param clazz 目标类
    	 */
    	public static final <T> T parse(final String json, final String path, final Class<T> clazz) {
    		String[] keys = path.split(",");
    		JSONObject obj = JSON.parseObject(json);
    		for (int i = 0; i < keys.length - 1; i++) {
    			obj = obj.getJSONObject(keys[i]);
    		}
    		String inner = obj.getString(keys[keys.length - 1]);
    		return parse(inner, clazz);
    	}
    
    	/**
    	 * 将制定的对象经过字段过滤处理后,解析成为json集合
    	 * 
    	 * @param obj
    	 * @param fields
    	 * @param ignore
    	 * @param clazz
    	 * @param features
    	 * @return
    	 */
    	public static final <T> List<T> parseArray(final Object obj, final String[] fields, boolean ignore,
    			final Class<T> clazz, final SerializerFeature... features) {
    		String json = toJson(obj, fields, ignore, features);
    		return parseArray(json, clazz);
    	}
    
    	/**
    	 * <pre>
    	 * 从json字符串中解析出一个对象的集合,被解析字符串要求是合法的集合类型
    	 * (形如:["k1":"v1","k2":"v2",..."kn":"vn"])
    	 * 
    	 * @param json - [key-value-pair...]
    	 * @param clazz
    	 * @return
    	 */
    	public static final <T> List<T> parseArray(final String json, final Class<T> clazz) {
    		return JSON.parseArray(json, clazz);
    	}
    
    	/**
    	 * <pre>
    	 * 从json字符串中按照路径寻找,并解析出一个对象的集合,例如:
    	 * 类Person有一个属性name,要从以下json中解析出其集合:
    	 * {
    	 * 	"page_info":{
    	 * 		"items":{
    	 * 			"item":[{"name":"KelvinZ"},{"name":"Jobs"},...{"name":"Gates"}]
    	 * 	}
    	 * }
    	 * 使用方法:parseArray(json, "page_info,items,item", Person.class),
    	 * 将根据指定路径,正确的解析出所需集合,排除外层干扰
    	 * 
    	 * @param json json字符串
    	 * @param path 逗号分隔的json层次结构
    	 * @param clazz 目标类
    	 * @return
    	 */
    	public static final <T> List<T> parseArray(final String json, final String path, final Class<T> clazz) {
    		String[] keys = path.split(",");
    		JSONObject obj = JSON.parseObject(json);
    		for (int i = 0; i < keys.length - 1; i++) {
    			obj = obj.getJSONObject(keys[i]);
    		}
    		String inner = obj.getString(keys[keys.length - 1]);
    		List<T> ret = parseArray(inner, clazz);
    		return ret;
    	}
    
    	/**
    	 * <pre>
    	 * 有些json的常见格式错误这里可以处理,以便给后续的方法处理
    	 * 常见错误:使用了\" 或者 "{ 或者 }",腾讯的页面中常见这种格式
    	 * 
    	 * @param invalidJson 包含非法格式的json字符串
    	 * @return
    	 */
    	public static final String correctJson(final String invalidJson) {
    		String content = invalidJson.replace("\\\"", "\"").replace("\"{", "{").replace("}\"", "}");
    		return content;
    	}
    
    	/**
    	 * 格式化Json
    	 * 
    	 * @param json
    	 * @return
    	 */
    	public static final String formatJson(String json) {
    		Map<?, ?> map = (Map<?, ?>) JSON.parse(json);
    		return JSON.toJSONString(map, true);
    	}
    
    	/**
    	 * 获取json串中的子json
    	 * 
    	 * @param json
    	 * @param path
    	 * @return
    	 */
    	public static final String getSubJson(String json, String path) {
    		String[] keys = path.split(",");
    		JSONObject obj = JSON.parseObject(json);
    		for (int i = 0; i < keys.length - 1; i++) {
    			obj = obj.getJSONObject(keys[i]);
    			System.out.println(obj.toJSONString());
    		}
    		return obj != null ? obj.getString(keys[keys.length - 1]) : null;
    	}
    
    }
    

     

    展开全文
  • 第三方token过期监控及刷新机制

    万次阅读 2020-12-21 11:10:53
    背景 信息系统随着业务发展的多样化及场景的拓展,需要接入越来越多的第三方系统,部分收费的第三方服务都会按照合同约定给用户提供对应的应用授权账户,授权账户包含并不仅限于账号/密码/...针对目前的一些第三方服务

    背景

    信息系统随着业务发展的多样化及场景的拓展,需要接入越来越多的第三方系统,部分收费的第三方服务都会按照合同约定给用户提供对应的应用授权账户,授权账户包含并不仅限于账号/密码/AppKey/AppSecret/MerchantId,但是从系统安全角度出发,为了保护授参数的安全性和系统的稳定性,服务商都有针对账号进行流量控制/服务降级/关键安全信息定期更新等机制,来确保双方系统稳定及安全,本次说到的Token过期就是其中的一种保护账号安全的机制

    现状

    各第三方服务token过期时间

    针对目前的一些第三方服务,目前渣渣所了解到的是,拼多多的部分接口授权token是15天过期时间,蘑菇街/蘑菇街小店的token过期时间是7天,京东/淘宝等是一年的过期时间。

    存在的问题点

    有朋友会说,这个问题很好处理,token过期那就刷token就是的;是的,对于一个开发来说,刷token很简单,按照官方的文档操作就可以了,但是现在大多数的企业都存在以下场景,致使刷token的过程效率比较低,沟通成本却很高,从开发和运营角度去看

    开发角度
    • 用来刷token的账号一般都是业务账号,开发需要走流程才能获取到。
    • 此类账号一般异地登陆或者换PC登录都需要手机号验证,沟通成本和及时性很难保障
    • 操作2分钟,沟通一小时,线上问题迫在眉睫
    运营角度
    • 大多数运营不知道这个系统中存在这个问题,只在线上出问题后,开发才反馈有此问题
    • 我有账号,我不知道怎么操作,操作的流程都是一串串代码,我不会
    • 线上出问题了,需要快速恢复业务,我直接去开发工位去处理

    以上问题总结起来就是,有权限的不会处理,会处理的没权限,部分公司的做法就是运营把账号给到开发,并提供手机号验证码;开发愿意去接这个么?大多数情况不愿意,因为此类账号里面一般都会有运营的数据或者一些销售数据,比较敏感,例如天猫和京东的账号,是有发优惠卷和上线营销活动的权限的。

    处理方案

    开发侧
    • 在token过期前提醒运营进行刷新操作,一般是过期前一周内(有效期较短的过期前3天,一般有效期比较短的都不需要验证账号)
    • 开发业务操作页面,方便运营在自研系统中进行操作
    • 页面简历tips,提示具体的每一步操作
    运营侧
    • 注意查收特定邮箱的预警邮件,处理完成后回复邮件及抄送人
    • 操作过程中有问题需要开发协助及时沟通
    具体落地方案(以京东平台为例)
    开发建立第三方服务表(第三方服务信息管理)

    存储关键信息:
    平台名称/业务名称/AppKey/AppSecret/Token/RefreshToken/EndDate等关键参数

    了解刷新流程

    京东平台授权刷新流程
    以下内容转发,可以直接去
    京东授权刷新流程查看原汁原味的

    1、请求入口地址
    1)获取授权码(code)
    https://open-oauth.jd.com/oauth2/to_login
    2)获取访问令牌(access_token)
    https://open-oauth.jd.com/oauth2/access_token
    注意:如授权账号(商家为主账号)修改密码则授权码(Access token)随之失效,需重新授权。
    2、授权操作步骤
           实际进行授权操作时,测试的数据 app_key、app_secret、redirect_uri 均需要根据自己创建的应用实际数据给予替换,不能拿示例中给出的值直接进行测试,以免影响实际测试效果。
     1)拼接授权url
        拼接用户授权需访问url ,示例及参数说明如下:
    https://open-oauth.jd.com/oauth2/to_login?app_key=XXXXX&response_type=code&redirect_uri=XXXXX&state=20180416&scope=snsapi_base
    2)引导用户登录授权
        引导用户通过浏览器访问以上授权url,将弹出登录授权页面。用户输入账号、密码点“登录”按钮,即完成授权流程。在PC浏览器里,该页面支持授权用户京东APP扫码登录;若授权用户已经在该浏览器中登录京东,则可实现一键授权登录。
    3)获取code
        上图页面,若用户点“登录”按钮后,开放平台会跳转到指定的redirect_uri并多添加两个参数code和state参数(浏览器地址栏),应用可以获取并使用该code去换取access_token;
    返回示例:
    redirect_uri?code=CODE&state=STATE
    说明:
        可发布服务市场(fw.jd.com)的应用,在应用上线后,如购买应用的用户,通过"我的服务--立即使用”访问(下图),系统会自动跳到授权页面(因此这种方式访问应用的,不需要拼接url),只需注意获取code即可。同时返回code时,还会返回通过state传递订购服务相关的信息;
    注意:state中如果有“+”号,因浏览器交互的原因,会出现“+”号替换成空格的现象,导致授权报错,如果出现此种情况,请把的state 中的空格再替换成“+”号,state后面的是经过base64编码,使用者可以通过收费项目编码或者版本号来指定自己软件对应的服务并可以通过接口进行验证参数的正确性,反编码后内容如下:
    
    {
       "jos_parameters":
    {
            "app_key": "CB69F1769C4B110D010D128E41030C94",
            "end_date": 1469289600000,
            "item_code": "FW_GOODS-233232-1",
            "source": "JM",
            "user_name": "sop_order",
            "version_no": 1
        }
    }
    

    大体流程如下图:
    在这里插入图片描述

    建立监控机制

    上述表中我们有存储字段EndDate,通过建立定时调度去扫描此表,判断当前时间与EndDate之间的关系,确定刷否需要刷新token,不需要则无提示,需要刷新时可通过邮件/钉钉/企业微信等方式通知相应人员;注意此处最好发送给操作人员,抄送给相关支持人员和开发

    操作平台设计

    页面简图:
    页面可选模式:列表展示单行修改/平台名称+业务模块下拉选择修改
    在这里插入图片描述

    1. 建立单行表单,可选择平台名称/业务名称,触发授权按钮,服务拼接授权参数访问第三方登陆平台,此处需要保留原页面。
    2. 用户在页面上获取到code后,将code填充到表单中的授权code栏目中并点击确认授权按钮,应用发起授权请求,并从返回的结果中解析出对应的end_date/access_token/refresh_token等字段
    3. 将以上信息更新到表中维持之后的监控判断

    写在最后

    以上方案,只有在第一次处理时需要开发接入,原则上后续的流程只是对此功能的维护。
    另外有些企业可能考虑到将这些参数存在表中,安全性可能会有问题,此类数据可以考虑关闭开发访问权限。

    展开全文
  • 今天我们来学习:码云(Gitee)授权第三方登录,相比之前 支付宝登录、腾讯QQ登录 以及 新浪微博登录 来说,相对于比较简单 一、准备工作 1、登录 码云官网 官网地址:https://gitee.com/ 注册、登录我们的...

    今天我们来学习:码云(Gitee)授权第三方登录,相比之前 支付宝登录腾讯QQ登录 以及 新浪微博登录 来说,相对于比较简单

    一、准备工作

    官网地址:https://gitee.com/
    

    注册、登录我们的账号

    • 2、创建应用
      设置
      在右上角菜单找到 “设置” 选项
      第三方应用
      在 “安全设置” 下找到 “第三方应用”
      我的应用
      点击 “创建应用” 开始创建第三方应用
      创建应用信息
      按照要求填写应用信息即可
      应用详情
    • 3、将应用信息保存到项目中
      应用配置信息
      由于我使用的是 SpringBoot 项目,我放在了 application.yml 文件中

    二、开始开发

    • 1、引入 Maven 依赖
    <!-- 网络请求 -->
    <dependency>
    	<groupId>org.apache.httpcomponents</groupId>
    	<artifactId>httpclient</artifactId>
    	<version>4.5.6</version>
    </dependency>
    <!-- alibaba的fastjson -->
    <dependency>
    	<groupId>com.alibaba</groupId>
    	<artifactId>fastjson</artifactId>
    	<version>1.2.51</version>
    </dependency>
    

    其余的依赖请自行加入

    • 2、在页面放置 “码云(Gitee)” 授权登录的 DOM 元素
    <a th:href="@{gitee/auth}" class="link" title="Gitee登录"><i class="iconfont icon-gitee"></i></a>
    

    这里使用的是阿里的 iconfont 图标

    三、接口类

    创建 “码云(Gitee)” 授权登录的 Controller,GiteeController.java

    • 1、从配置文件中获取 “码云(Gitee)” 配置信息
    /**
     * gitee授权中提供的 appid 和 appkey
     */
    @Value("${gitee.oauth.clientid}")
    public String CLIENTID;
    @Value("${gitee.oauth.clientsecret}")
    public String CLIENTSECRET;
    @Value("${gitee.oauth.callback}")
    public String URL;
    
    • 2、页面登录按钮点击后的接口
    /**
     * 请求授权页面
     */
    @GetMapping(value = "/auth")
    public String qqAuth(HttpSession session) {
        // 用于第三方应用防止CSRF攻击
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        session.setAttribute("state", uuid);
    
        // Step1:获取Authorization Code
        String url = "https://gitee.com/oauth/authorize?response_type=code" +
                "&client_id=" + CLIENTID +
                "&redirect_uri=" + URLEncoder.encode(URL) +
                "&state=" + uuid +
                "&scope=user_info";
    
        return PasswordUtils.redirectTo(url);
    }
    

    接口文档中建议我们在授权登录时传入一个加密的数据防止被攻击,我们传入了UUID,最后重定向到授权页面
    授权页面

    • 3、当该用户点击“授权”按钮,同意授权后,就会回调到我们在应用中填写的回调地址里去
    /**
     * 授权回调
     */
    @GetMapping(value = "/callback")
    public String qqCallback(HttpServletRequest request) throws Exception {
        HttpSession session = request.getSession();
        // 得到Authorization Code
        String code = request.getParameter("code");
        // 我们放在地址中的状态码
        String state = request.getParameter("state");
        String uuid = (String) session.getAttribute("state");
    
        // 验证信息我们发送的状态码
        if (null != uuid) {
            // 状态码不正确,直接返回登录页面
            if (!uuid.equals(state)) {
                return PasswordUtils.redirectTo("/login");
            }
        }
    
        // Step2:通过Authorization Code获取Access Token
        String url = "https://gitee.com/oauth/token?grant_type=authorization_code" +
                "&client_id=" + CLIENTID +
                "&client_secret=" + CLIENTSECRET +
                "&code=" + code +
                "&redirect_uri=" + URL;
        JSONObject accessTokenJson = GiteeHttpClient.getAccessToken(url);
    
        // Step3: 获取用户信息
        url = "https://gitee.com/api/v5/user?access_token=" + accessTokenJson.get("access_token");
        JSONObject jsonObject = GiteeHttpClient.getUserInfo(url);
        /**
         * 获取到用户信息之后,就该写你自己的业务逻辑了
         */
        return PasswordUtils.redirectTo("/success");
    }
    

    四、网络请求方法

    上面回调方法中所用到的网络接口方法,我放在了 GiteeHttpClient.java 文件中,主要有两个方法

    • 1、网络接口
    /**
     * 获取Access Token
     * post
     */
    public static JSONObject getAccessToken(String url) throws IOException {
        HttpClient client = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
        HttpResponse response = client.execute(httpPost);
        HttpEntity entity = response.getEntity();
        if (null != entity) {
            String result = EntityUtils.toString(entity, "UTF-8");
            return JSONObject.parseObject(result);
        }
        httpPost.releaseConnection();
        return null;
    }
    
    /**
     * 获取用户信息
     * get
     */
    public static JSONObject getUserInfo(String url) throws IOException {
        JSONObject jsonObject = null;
        CloseableHttpClient client = HttpClients.createDefault();
    
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
        HttpResponse response = client.execute(httpGet);
        HttpEntity entity = response.getEntity();
    
        if (entity != null) {
            String result = EntityUtils.toString(entity, "UTF-8");
            jsonObject = JSONObject.parseObject(result);
        }
    
        httpGet.releaseConnection();
    
        return jsonObject;
    }
    

    分别就是使用 code 获取 token,在使用 token 获取 用户信息

    注意:我们需要在请求时加上请求头

    User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
    

    最终我们获取到一个 JSON 对象,该对象包含了用户的信息,例如:id,name,email,phone 等等。

    https://gitee.com/api/v5/oauth_doc#/
    

    五、总结

    该授权认证过程符合 OAuth2 认证基本流程,流程如下:
    授权过程

    1、用户点击页面登录按钮,请求授权页面,用户在此页面登录账号并同意授权
    2、用户同意授权后,回调至我们项目中,首先验证 state 是否一致
    3、使用上一步拿到的 code 请求 access_token
    4、使用 access_token 请求 用户信息,完成授权登录过程

    下一篇:

    【第三方互联】十四、Github授权第三方登录

    如您在阅读中发现不足,欢迎留言!!!

    展开全文
  • Pycharm第三方库的安装及使用方法

    万次阅读 多人点赞 2019-03-05 14:59:35
    参考博客:https://blog.csdn.net/china_xin1/article/details/80513898 快捷键参考:... 1、Pycharm第三方库的安装 方法一:pip install包名;pip uninstall包名。 方法二:pip in...

    目录

    1、Pycharm第三方库的安装

    2、pycharm常用快捷键

    1、编辑(Editing)

     2、查找/替换(Search/Replace)

     3、运行(Running)

     4、调试(Debugging)

     5、导航(Navigation)

     6、搜索相关(Usage Search)

     7、重构(Refactoring)

     8、控制VCS/Local History

     9、模版(Live Templates)

     3、pycharm常用设置

    4、pycharm环境和路径设置

    python解释器路径

    pycharm中进行python包管理

    python脚本解释路径

    console执行路径和当前工作目录

    pycharm配置os.environ环境

    pycharm配置第三方库代码自动提示 

    Pycharm实用拓展功能

    pycharm中清除已编译.pyc中间文件

    pycharm设置外部工具

    将上面的删除代码改成外部工具

    之后可以通过下面的方式直接执行

    代码质量

    python2转python3最快方式 


     

    参考博客:https://blog.csdn.net/china_xin1/article/details/80513898

    快捷键参考:https://blog.csdn.net/weixin_41059146/article/details/78826163

    1、Pycharm第三方库的安装

    方法一:pip install 包名;pip uninstall 包名。

    方法二:pip install 下载路径\包名.whl (需要先下载第三包:地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/,找到所需的包并下载保存),如下例安装gensim包所示:

    方法三:若在pycharm编辑中,则在菜单setting/project/project interpreter中添加第三包。或者将第三方包放置于pycharm的site-packages目录, 可直接在程序中通过import 包名 来引用了。 

    方法四:先下载第三方包,如http://pypi.python.org/pypi/jieba/ ,解压后在解压路径下运行命令:python setup.py install

     我采用的是方法一,比如安装numpy

    然后打开pychram,file->settings ->project interpreter

     点击+号搜索numpy

     选择pip安装的然后点击 install Package 等一会就会提示安装成功

    2、pycharm常用快捷键

    1、编辑(Editing)

    Ctrl + Space    基本的代码完成(类、方法、属性)
    Ctrl + Alt + Space  快速导入任意类
    Ctrl + Shift + Enter    语句完成
    Ctrl + P    参数信息(在方法中调用参数)
    Ctrl + Q    快速查看文档

    F1   外部文档

    Shift + F1    外部文档,进入web文档主页

    Ctrl + Shift + Z --> Redo 重做

    Ctrl + 鼠标    简介/进入代码定义
    Ctrl + F1    显示错误描述或警告信息
    Alt + Insert    自动生成代码
    Ctrl + O    重新方法
    Ctrl + Alt + T    选中
    Ctrl + /    行注释/取消行注释
    Ctrl + Shift + /    块注释
    Ctrl + W    选中增加的代码块
    Ctrl + Shift + W    回到之前状态
    Ctrl + Shift + ]/[     选定代码块结束、开始
    Alt + Enter    快速修正
    Ctrl + Alt + L     代码格式化
    Ctrl + Alt + O    优化导入
    Ctrl + Alt + I    自动缩进
    Tab / Shift + Tab  缩进、不缩进当前行
    Ctrl+X/Shift+Delete    剪切当前行或选定的代码块到剪贴板
    Ctrl+C/Ctrl+Insert    复制当前行或选定的代码块到剪贴板
    Ctrl+V/Shift+Insert    从剪贴板粘贴
    Ctrl + Shift + V    从最近的缓冲区粘贴
    Ctrl + D  复制选定的区域或行
    Ctrl + Y    删除选定的行
    Ctrl + Shift + J  添加智能线
    Ctrl + Enter   智能线切割
    Shift + Enter    另起一行
    Ctrl + Shift + U  在选定的区域或代码块间切换
    Ctrl + Delete   删除到字符结束
    Ctrl + Backspace   删除到字符开始
    Ctrl + Numpad+/-   展开/折叠代码块(当前位置的:函数,注释等)
    Ctrl + shift + Numpad+/-   展开/折叠所有代码块
    Ctrl + F4   关闭运行的选项卡


     2、查找/替换(Search/Replace)


    F3   下一个
    Shift + F3   前一个
    Ctrl + R   替换
    Ctrl + Shift + F  或者连续2次敲击shift   全局查找{可以在整个项目中查找某个字符串什么的,如查找某个函数名字符串看之前是怎么使用这个函数的}
    Ctrl + Shift + R   全局替换


     3、运行(Running)


    Alt + Shift + F10   运行模式配置
    Alt + Shift + F9    调试模式配置
    Shift + F10    运行
    Shift + F9   调试
    Ctrl + Shift + F10   运行编辑器配置
    Ctrl + Alt + R   运行manage.py任务


     4、调试(Debugging)


    F8   跳过
    F7   进入
    Shift + F8   退出
    Alt + F9    运行游标
    Alt + F8    验证表达式
    Ctrl + Alt + F8   快速验证表达式
    F9    恢复程序
    Ctrl + F8   断点开关
    Ctrl + Shift + F8   查看断点


     5、导航(Navigation)


    Ctrl + N    跳转到类
    Ctrl + Shift + N    跳转到符号
    Alt + Right/Left    跳转到下一个、前一个编辑的选项卡
    F12    回到先前的工具窗口
    Esc    从工具窗口回到编辑窗口
    Shift + Esc   隐藏运行的、最近运行的窗口
    Ctrl + Shift + F4   关闭主动运行的选项卡
    Ctrl + G    查看当前行号、字符号
    Ctrl + E   当前文件弹出,打开最近使用的文件列表
    Ctrl+Alt+Left/Right   后退、前进
    Ctrl+Shift+Backspace    导航到最近编辑区域
    Alt + F1   查找当前文件或标识
    Ctrl+B / Ctrl+Click    跳转到声明
    Ctrl + Alt + B    跳转到实现
    Ctrl + Shift + I查看快速定义
    Ctrl + Shift + B跳转到类型声明
    Ctrl + U跳转到父方法、父类
    Alt + Up/Down跳转到上一个、下一个方法
    Ctrl + ]/[跳转到代码块结束、开始
    Ctrl + F12弹出文件结构
    Ctrl + H类型层次结构
    Ctrl + Shift + H方法层次结构
    Ctrl + Alt + H调用层次结构
    F2 / Shift + F2下一条、前一条高亮的错误
    F4 / Ctrl + Enter编辑资源、查看资源
    Alt + Home显示导航条F11书签开关
    Ctrl + Shift + F11书签助记开关
    Ctrl + #[0-9]跳转到标识的书签
    Shift + F11显示书签


     6、搜索相关(Usage Search)


    Alt + F7/Ctrl + F7文件中查询用法
    Ctrl + Shift + F7文件中用法高亮显示
    Ctrl + Alt + F7显示用法


     7、重构(Refactoring)


    F5复制F6剪切
    Alt + Delete安全删除
    Shift + F6重命名
    Ctrl + F6更改签名
    Ctrl + Alt + N内联
    Ctrl + Alt + M提取方法
    Ctrl + Alt + V提取属性
    Ctrl + Alt + F提取字段
    Ctrl + Alt + C提取常量
    Ctrl + Alt + P提取参数


     8、控制VCS/Local History


    Ctrl + K提交项目
    Ctrl + T更新项目
    Alt + Shift + C查看最近的变化
    Alt + BackQuote(’)VCS快速弹出


     9、模版(Live Templates)


    Ctrl + Alt + J当前行使用模版
    Ctrl +J插入模版
     10、基本(General)
    Alt + #[0-9]打开相应的工具窗口
    Ctrl + Alt + Y同步
    Ctrl + Shift + F12最大化编辑开关
    Alt + Shift + F添加到最喜欢
    Alt + Shift + I根据配置检查当前文件
    Ctrl + BackQuote(’)快速切换当前计划
    Ctrl + Alt + S 打开设置页
    Ctrl + Shift + A查找编辑器里所有的动作
    Ctrl + Tab在窗口间进行切换

     3、pycharm常用设置

     

    lz提示一下,pycharm中的设置是可以导入和导出的,file>export settings可以保存当前pycharm中的设置为jar文件,重装时可以直接import settings>jar文件,就不用重复配置了。

     

    file -> Setting ->Editor

    1. 设置Python自动引入包,要先在 >general > autoimport -> python :show popup

         快捷键:Alt + Enter: 自动添加包
    2. “代码自动完成”时间延时设置

      > Code Completion   -> Auto code completion in (ms):0  -> Autopopup in (ms):500

    3. Pycharm中默认是不能用Ctrl+滚轮改变字体大小的,可以在〉Mouse中设置

    4. 显示“行号”与“空白字符”

      > Appearance  -> 勾选“Show line numbers”、“Show whitespaces”、“Show method separators”

    5. 设置编辑器“颜色与字体”主题

      > Colors & Fonts -> Scheme name -> 选择"monokai"“Darcula”

      说明:先选择“monokai”,再“Save As”为"monokai-pipi",因为默认的主题是“只读的”,一些字体大小颜色什么的都不能修改,拷贝一份后方可修改!

      修改字体大小

    > Colors & Fonts -> Font -> Size -> 设置为“14”

    6. 设置缩进符为制表符“Tab”

      File -> Default Settings -> Code Style

      -> General -> 勾选“Use tab character”

      -> Python -> 勾选“Use tab character”

      -> 其他的语言代码同理设置

    7. 去掉默认折叠
      > Code Folding -> Collapse by default -> 全部去掉勾选

    8. pycharm默认是自动保存的,习惯自己按ctrl + s  的可以进行如下设置:
        > General -> Synchronization -> Save files on frame deactivation  和 Save files automatically if application is idle for .. sec 的勾去掉
        > Editor Tabs -> Mark modified tabs with asterisk 打上勾

    9.>file and code template>python scripts

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """
    __title__ = '$Package_name'
    __author__ = '$USER'
    __mtime__ = '$DATE'
    # code is far away from bugs with the god animal protecting
        I love animals. They taste delicious.
                  ┏┓      ┏┓
                ┏┛┻━━━┛┻┓
                ┃      ☃      ┃
                ┃  ┳┛  ┗┳  ┃
                ┃      ┻      ┃
                ┗━┓      ┏━┛
                    ┃      ┗━━━┓
                    ┃  神兽保佑    ┣┓
                    ┃ 永无BUG!   ┏┛
                    ┗┓┓┏━┳┓┏┛
                      ┃┫┫  ┃┫┫
                      ┗┻┛  ┗┻┛
    """

    10 python文件默认编码

    File Encodings> IDE Encoding: UTF-8;Project Encoding: UTF-8;

    11. 代码自动整理设置

    这里line breaks去掉√,否则bar, 和baz会分开在不同行,不好看。

    File -> Settings -> appearance

    1. 修改IDE快捷键方案

      > Keymap

    1) execute selection in console : add keymap > ctrl + enter

      系统自带了好几种快捷键方案,下拉框中有如“defaul”,“Visual Studio”,在查找Bug时非常有用,“NetBeans 6.5”,“Default for GNOME”等等可选项,

      因为“Eclipse”方案比较大众,个人用的也比较多,最终选择了“Eclipse”。 

      还是有几个常用的快捷键跟Eclipse不一样,为了能修改,还得先对Eclipse方案拷贝一份: 

      (1).代码提示功能,默认是【Ctrl+空格】,现改为跟Eclipse一样,即【Alt+/】

      Main menu -> code -> Completion -> Basic -> 设置为“Alt+/”

      Main menu -> code -> Completion -> SmartType -> 设置为“Alt+Shift+/”

      不过“Alt+/”默认又被 

      Main menu -> code -> Completion -> Basic -> Cyclic Expand Word 占用,先把它删除再说吧(单击右键删除)!

      (2).关闭当前文档,默认是【Ctrl+F4】,现改为跟Eclipse一样,即【Ctrl+W】

      Main menu -> Window -> Active Tool Window -> Close Active Tab -> 设置为 “Ctrl+F4”;

      Main menu -> Window -> Editor -> Close -> 设置为 “Ctrl+W”;
    2.设置IDE皮肤主题

     

     > Theme -> 选择“Alloy.IDEA Theme”

      或者在setting中搜索theme可以改变主题,所有配色统一改变

    File > settings > build.excution

    每次打开python控制台时自动执行代码

    > console > pyconsole

    import sys
    # print('Python %s on %s' % (sys.version, sys.platform))
    sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])
    import  os
    print('current workdirectory : ', os.getcwd() )
    import  numpy as  np
    import  scipy as sp
    import  matplotlib as mpl
    如果安装了ipython,则在pyconsole中使用更强大的ipython

    > console

    选中use ipython if available

    这样每次打开pyconsole就会打开ipython

    Note: 在virtualenv中安装ipython: (ubuntu_env) pika:/media/pika/files/mine/python_workspace/ubuntu_env$pip install ipython

     

    File > settings > Languages & Frameworks

     

    如果在项目设置中开启了django支持,打开python console时会自动变成打开django console,当然如果不想这样就关闭项目对django的支持:

    如果打开支持就会在 settings > build.excution > console下多显示一个django console:

    Django console设置如下

     

    import sys
    print('Python %s on %s' % (sys.version, sys.platform))
    import django
    print('Django %s' % django.get_version())
    sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])
    if 'setup' in dir(django): django.setup()
    import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)
     

    File > settings > Project : initial projectproject dependencies > LDA > project depends on these projects > 选择sim_cluster就可以在LDA中调用sim_cluster中的包

    4、pycharm环境和路径设置

    python解释器路径

    python项目解释器路径

    用于配置python项目执行的python路径

    比如,有的项目是运行的是系统python2.7下的环境;有的是3.4;有的项目使用的是virtualenv的python环境[python虚拟环境配置 - pycharm中的项目配置]

    在pycharm > file > settings > project:pythonworkspace > project interpreter > 选择对应项目 > project interpreter中指定python解释器

    pycharm中运行configuration有一个选项add content roots to pythonpath

    选中后sys.path中会多一整个项目project的路径/media/pika/files/mine/python_workspace,里面的目录就被当成包使用,这样就可以通过from SocialNetworks.SocialNetworks引入不是python包的目录中的文件了。

    不过最好使用sys.path.append(os.path.join(os.path.split(os.path.realpath(__file__))[0],"../.."))来添加,这样在pycharm外也可以运行不出错 。

    pycharm中进行python包管理

    pycharm中的项目中可以包含package、目录(目录名可以有空格)、等等

    目录的某个包中的某个py文件要调用另一个py文件中的函数,首先要将目录设置为source root,这样才能从包中至上至上正确引入函数,否则怎么引入都出错:

    SystemError: Parent module '' not loaded, cannot perform relative import

    Note:目录 > 右键 > make directory as > source root

    python脚本解释路径

    ctrl + shift + f10 / f10 执行python脚本时

    当前工作目录cwd为run/debug configurations 中的working directory

    可在edit configurations > project or defaults中配置

    console执行路径和当前工作目录

    python console中执行时

    cwd为File > settings > build.excution > console > pyconsole中的working directory

    并可在其中配置

    pycharm配置os.environ环境

    pycharm中os.environ不能读取到terminal中的系统环境变量

    pycharm中os.environ不能读取.bashrc参数

    使用pycharm,无论在python console还是在module中使用os.environ返回的dict中都没有~/.bashrc中的设置的变量,但是有/etc/profile中的变量配置。然而在terminal中使用python,os.environ却可以获取~/.bashrc的内容。

    解决方法1:

     

    在~/.bashrc中设置的系统环境只能在terminal shell下运行Spark程序才有效,因为.bashrc is only read for interactive shells.

    如果要在当前用户整个系统中都有效(包括pycharm等等IDE),就应该将系统环境变量设置在~/.profile文件中。如果是设置所有用户整个系统,修改/etc/profile或者/etc/environment吧。

    如SPARK_HOME的设置[Spark:相关错误总结 ]

    解决方法2:在代码中设置,这样不管环境有没有问题了

     

    # spark environment settings
    import sys, os
    os.environ['SPARK_HOME'] = conf.get(SECTION, 'SPARK_HOME')
    sys.path.append(os.path.join(conf.get(SECTION, 'SPARK_HOME'), 'python'))
    os.environ["PYSPARK_PYTHON"] = conf.get(SECTION, 'PYSPARK_PYTHON')
    os.environ['SPARK_LOCAL_IP'] = conf.get(SECTION, 'SPARK_LOCAL_IP')
    os.environ['JAVA_HOME'] = conf.get(SECTION, 'JAVA_HOME')
    os.environ['PYTHONPATH'] = '$SPARK_HOME/python/lib/py4j-0.10.3-src.zip:$PYTHONPATH'

    pycharm配置第三方库代码自动提示 

    Pycharm实用拓展功能

    pycharm中清除已编译.pyc中间文件

    选中你的workspace > 右键 > clean python compiled files

     

    还可以自己写一个清除代码

    pycharm设置外部工具

    [python小工具 ]针对当前pycharm中打开的py文件对应的目录删除其中所有的pyc文件。如果是直接运行(而不是在下面的tools中运行),则删除E:\mine\python_workspace\WebSite目录下的pyc文件。

    将上面的删除代码改成外部工具

    PyCharm > settings > tools > external tools > +添加

    Name: DelPyc

    program: $PyInterpreterDirectory$/python Python安装路径

    Parameters: $ProjectFileDir$/Oth/Utility/DelPyc.py $FileDir$

    Work directory: $FileDir$

    Note:Parameters后面的 $FileDir$参数是说,DelPyc是针对当前pycharm中打开的py文件对应的目录删除其中所有的pyc文件。

    之后可以通过下面的方式直接执行

    Note:再添加一个Tools名为DelPycIn

    program: Python安装路径,e.g.     D:\python3.4.2\python.exe

    Parameters: E:\mine\python_workspace\Utility\DelPyc.py

    Work directory 使用变量 $FileDir$

    参数中没有$FileDir$,这样就可以直接删除常用目录r'E:\mine\python_workspace\WebSite'了,两个一起用更方便

    代码质量

    当你在打字的时候,PyCharm会检查你的代码是否符合PEP8。它会让你知道,你是否有太多的空格或空行等等。如果你愿意,你可以配置PyCharm运行pylint作为外部工具。

    python2转python3最快方式 

    /usr/bin/2to3 -wn $FileDir$

    这样在pycharm中打开某个文件,右键external tools > py2topy3就可以瞬间将当前文件所在目录下的所有py2转换成py3,是不是很机智!
     

     

     

     

     

     

     

     

    展开全文
  • Android第三方开源框架ImageLoader的完美Demo

    千次下载 热门讨论 2013-08-19 17:26:28
    Android第三方开源框架ImageLoader的完美Demo,很好地体现了ImageLoadr异步加载图片的优越性。
  • 你有没有遇到过这样的怪事:“pip安装第三方库,但PyCharm中却无法识别的?”如果有,也许你需要看这篇文章,看完你就会知道pip按照的库在哪里;为什么安装后,PyCharm导入不了;以及PyCharm安装第三方库的方法解析...
  • 第三方登录功能的实现

    万次阅读 多人点赞 2017-03-28 17:13:04
    为什么要使用第三方登录:一般稍微作为一个大点的项目,为了提高用户的群体都会做第三方登录(如:QQ,微信,新浪等) 在往下看之前先注册第三方网站的开发者账号,创建应用完成审核。 QQ : QQ开发者平台 微信: 微信...
  • OPPO设备设置第三方桌面为默认Launcher

    万次阅读 热门讨论 2018-11-06 15:54:57
    大家都知道在OPPO 5.0以上版本Color OS 3.0以上版本是不能设置第三方的Launcher为默认的,只能使用OPPO自己的桌面,这对于喜欢第三方Launcher的人来说是个很不好的坏消息。 然而总有解决的办法不是: 1、准备Color...
  • 想要调用第三方软件首先必须知道intent 这里使用逆向工具获取清单文件的IntentFilter PrinterShare 清单 <activity android:configChanges="keyboardHidden|locale|orientation|screenSize" android:icon="@...
  • Angular引入第三方

    万次阅读 多人点赞 2017-05-05 20:31:29
    如果我们想在Angular中使用第三方的库,比如jquery或bootstrap等,该如果做呢?首先我们先来看看package.json这个文件,在目录介绍那篇博客中我们已经知道,package.json这个文件列出了项目所使用的第三方依赖包。...
  • 第三方互联】三、腾讯QQ授权第三方登录

    万次阅读 多人点赞 2020-02-25 15:24:15
    定义三个变量,接收 QQ 互联的信息 2、登录按钮点击后的接口 /** * 请求授权页面 */ @GetMapping(value = "/auth") public String qqAuth(HttpSession session) { // 用于第三方应用防止CSRF攻击 String uuid = ...
  • pycharm查看第三方库安装路径

    万次阅读 多人点赞 2018-05-30 10:51:57
    pycharm查看第三方库安装路径 更多原创性能测试文章关注 十年性能测试专家&7DGroup公众号 1、在文件--setting 2、鼠标放在安装好的第三方库名称上,自动显示安装路径 ...
  • Python常用第三方库——简介及下载地址

    万次阅读 多人点赞 2019-02-22 15:42:25
    Python常用第三方库 可以在 The Python Package Index (PyPI) 软件库(官网主页:https://pypi.org/)查询、下载 和 发布Python包或库。 网络爬虫 requests:https://pypi.org/project/requests/ 简洁且简单的...
  • Anaconda安装jieba、wordcloud等第三方

    万次阅读 多人点赞 2018-02-04 17:30:50
    本文是jieba在anaconda中的安装方法,wordcloud等第三方库与jieba安装方法相同,这里是wordcloud包的下载地址 许多论坛中说使用conda install jieba安装,我的尝试是不可行的。我发现jieba作为一个第三方库,并不...
  • 下载第三方app + 导入第三方beat saber歌曲 这篇文章有几个步骤:下载安装sidequest,打开开发者模式,用sidequest下载安装自定义歌曲,导入自己的自定义歌曲 教程部分来源:...
  • 微信小程序跳转第三方网页、第三方小程序。微信小程序跳转第三方网页跳转第三方网页的问题微信小程序跳转第三方小程序 微信小程序跳转第三方网页 最近需要做一个小程序跳转携程的功能,首先考虑到的是跳转到携程的h5...
  • 我们有第一方,第三方,现在甚至还有第二方的数据。你如何了解和区分呢? 一、什么是第一方数据? 第一方数据是指企业直接从受众(包括客户、网站访问者和社交媒体关注者)那里收集的数据。“第一方”是指收集第一手...
  • 第三方授权登录

    千次阅读 多人点赞 2021-01-21 22:28:40
    第三方授权登录 使用Visusal Studio2012 完成一个简便的第三方授权登录,有兴趣的宝宝可以康康哦~ 第一步: 打开VS 画一个登录窗体 有账号,密码框 可以登录的那种(也就是我们最普通的登录方式) 新添加了一个...
  • 前面的几篇文章介绍了NSIS的传统界面的安装包和现代界面的安装包的...但使用起来还是不太方便(需要专门了解这个插件诸多用法),而且不够灵活,所以本文介绍一种终极的自定义界面的安装包解决方案,即完全使用第三方
  • 更多微信技术交流,请加QQ群:289709451、287090836 公众号第三方平台的开放,是为了让公众号运营者,在面向垂直行业需求时,可以一键登录授权给第三方的公众号运营平台,通过第三方开发者提供的公众号第三方平台来...
  • $ git clone git://github.com/kennethreitz/requests.git $ cd requests $ python setup.py install

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 281,816
精华内容 112,726
关键字:

第三方