搜了一下网络上别人封装的HttpClient,大部分特别简单,有一些看起来比较高级,但是用起来都不怎么好用。调用关系不清楚,结构有点混乱。所以也就萌生了自己封装HttpClient工具类的想法。要做就做最好的,本工具类支持插件式配置Header、插件式配置httpclient对象,这样就可以方便地自定义header信息、配置ssl、配置proxy等。

  相关jar包下载:http://search.maven.org/#search%7Cga%7C1%7Chttpasyncclient

是不是觉得说的有点悬乎了,那就先看看调用吧:

  1.  public static void testSimple() throws HttpProcessException{
  2. String url = "http://www.oschina.net";
  3. //简单调用
  4. String resp = HttpClientUtil.send(url);
  5. System.out.println("请求结果内容长度:"+ resp.length());
  6. }
  7. public static void testOne() throws HttpProcessException{
  8. String url = "https://sso.tgb.com:8443/cas/login";
  9. //自定义HttpClient,设置超时、代理、ssl
  10. //HttpClient client= HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl().build();//采用默认方式(绕过证书验证)
  11. HttpClient client= HCB.custom().timeout(10000).ssl("D:\\keys\\wsriakey","tomcat").build();
  12. //设置header信息
  13. Header[] headers=HttpHeader.custom().keepAlive("false").connection("close").contentType(Headers.APP_FORM_URLENCODED).build();
  14. //执行请求
  15. String resp=HttpClientUtil.send(client, url, headers);
  16. System.out.println("请求结果如下:");
  17. System.out.println(resp);
  18. }

轻松配置了代理、自定义证书的ssl、以及各种header头信息,是不是觉得还凑合呢,那就继续看吧。

写这个工具类时,抽象了一下所有的demo,最后封装了一个最基本的方法(拆分成了2个方法了),其所有参数列表有:HttpClient对象、url(必须有)、请求方式、请求参数parasMap、header数组、编码格式encoding。

由于封装的是工具类,所以最好是无状态的,可以支持多线程的方式调用的,所以方法都是static类型的。这也是为什么要把HttpClient对象也是作为了一个参数传入而非成员变量了,而且这样也为扩展HttpClient的配置提供了便利。

因为HTTP1.1规范中定义了6种HTTP方法:GET, HEAD, POST, PUT, DELETE, TRACE 和 OPTIONS,其实还有一个PATCH,这几个方法在HttpClient中都有一个对应的类:HttpGet,HttpHead,HttpPost,HttpPut,HttpDelete,HttpTrace、HttpOptions以及HttpPatch。所有的这些类均继承了HttpRequestBase超类,故可以作为参数使用(用枚举类作为参数,用另一个方法来创建具体的请求方法对象)。

Header头信息也是作为一个重要的参数,在请求特定网站的时候需要设置不同的Header,而header又是比较繁杂的,所以这里也是作为了一个参数传入的,也是方便扩展。

使用map来作为post方式传入参数是习惯使然,不做过多的解释。

编码这个参数主要是为了为待提交的数据和反馈结果进行转码处理。

简单说一下流程:

    1. 创建请求对象request;
    2. 为request设置header信息;
    3. 判断当前请求对象是否是HttpEntityEnclosingRequestBase的子类,如果是,则支持setEntity方法,来设置参数。
    4. 执行请求,并拿到结果(同步阻塞);
    5. 获取并解码请求结果实体;
    6. 关闭链接

就是这么简单,具体来看看代码吧:

  1. /**
  2. * 请求资源或服务,自定义client对象,传入请求参数,设置内容类型,并指定参数和返回数据的编码
  3. *
  4. * @param client        client对象
  5. * @param url           资源地址
  6. * @param httpMethod    请求方法
  7. * @param parasMap      请求参数
  8. * @param headers       请求头信息
  9. * @param encoding      编码
  10. * @return              返回处理结果
  11. * @throws HttpProcessException
  12. */
  13. public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap,
  14. Header[] headers, String encoding) throws HttpProcessException {
  15. String body = "";
  16. try {
  17. //创建请求对象
  18. HttpRequestBase request = getRequest(url, httpMethod);
  19. //设置header信息
  20. request.setHeaders(headers);
  21. //判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持)
  22. if(HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass())){
  23. List<NameValuePair> nvps = new ArrayList<NameValuePair>();
  24. //检测url中是否存在参数
  25. url = Utils.checkHasParas(url, nvps);
  26. //装填参数
  27. Utils.map2List(nvps, parasMap);
  28. //设置参数到请求对象中
  29. ((HttpEntityEnclosingRequestBase)request).setEntity(new UrlEncodedFormEntity(nvps, encoding));
  30. logger.debug("请求地址:"+url);
  31. if(nvps.size()>0){
  32. logger.debug("请求参数:"+nvps.toString());
  33. }
  34. }else{
  35. int idx = url.indexOf("?");
  36. logger.debug("请求地址:"+url.substring(0, (idx>0 ? idx-1:url.length()-1)));
  37. if(idx>0){
  38. logger.debug("请求参数:"+url.substring(idx+1));
  39. }
  40. }
  41. //调用发送请求
  42. body = execute(client, request, url, encoding);
  43. } catch (UnsupportedEncodingException e) {
  44. throw new HttpProcessException(e);
  45. }
  46. return body;
  47. }
  48. /**
  49. * 请求资源或服务
  50. *
  51. * @param client        client对象
  52. * @param request       请求对象
  53. * @param url           资源地址
  54. * @param parasMap      请求参数
  55. * @param encoding      编码
  56. * @return              返回处理结果
  57. * @throws HttpProcessException
  58. */
  59. private static String execute(HttpClient client, HttpRequestBase request,String url, String encoding) throws HttpProcessException {
  60. String body = "";
  61. HttpResponse response =null;
  62. try {
  63. //执行请求操作,并拿到结果(同步阻塞)
  64. response = client.execute(request);
  65. //获取结果实体
  66. HttpEntity entity = response.getEntity();
  67. if (entity != null) {
  68. //按指定编码转换结果实体为String类型
  69. body = EntityUtils.toString(entity, encoding);
  70. logger.debug(body);
  71. }
  72. EntityUtils.consume(entity);
  73. } catch (ParseException | IOException e) {
  74. throw new HttpProcessException(e);
  75. } finally {
  76. close(response);
  77. }
  78. return body;
  79. }

第一个方法中,我们看到有HttpMethods类型的参数,在创建request对象时,用到了它。它是什么呢?其实只是一个枚举类:

  1. /**
  2. * 枚举HttpMethods方法
  3. *
  4. * @author arron
  5. * @date 2015年11月17日 下午4:45:59
  6. * @version 1.0
  7. */
  8. public enum HttpMethods{
  9. /**
  10. * 求获取Request-URI所标识的资源
  11. */
  12. GET(0, "GET"),
  13. /**
  14. * 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。
  15. * POST请求可能会导致新的资源的建立和/或已有资源的修改
  16. */
  17. POST(1, "POST"),
  18. /**
  19. * 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。
  20. * 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息
  21. * 只获取响应信息报头
  22. */
  23. HEAD(2, "HEAD"),
  24. /**
  25. * 向指定资源位置上传其最新内容(全部更新,操作幂等)
  26. */
  27. PUT (3, "PUT"),
  28. /**
  29. * 请求服务器删除Request-URI所标识的资源
  30. */
  31. DELETE  (4, "DELETE"),
  32. /**
  33. * 请求服务器回送收到的请求信息,主要用于测试或诊断
  34. */
  35. TRACE(5, "TRACE"),
  36. /**
  37. * 向指定资源位置上传其最新内容(部分更新,非幂等)
  38. */
  39. PATCH   (6, "PATCH"),
  40. /**
  41. * 返回服务器针对特定资源所支持的HTTP请求方法。
  42. * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性
  43. */
  44. OPTIONS (7, "OPTIONS"),
  45. //      /**
  46. //       * HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
  47. //       */
  48. //      CONNECT(99, "CONNECT"),
  49. ;
  50. private int code;
  51. private String name;
  52. private HttpMethods(int code, String name){
  53. this.code = code;
  54. this.name = name;
  55. }
  56. public String getName() {
  57. return name;
  58. }
  59. public int getCode() {
  60. return code;
  61. }
  62. }

通过getRequest方法,来实例化对应方法的请求对象。

  1. /**
  2. * 根据请求方法名,获取request对象
  3. *
  4. * @param url                   资源地址
  5. * @param method            请求方式
  6. * @return
  7. */
  8. private static HttpRequestBase getRequest(String url, HttpMethods method) {
  9. HttpRequestBase request = null;
  10. switch (method.getCode()) {
  11. case 0:// HttpGet
  12. request = new HttpGet(url);
  13. break;
  14. case 1:// HttpPost
  15. request = new HttpPost(url);
  16. break;
  17. case 2:// HttpHead
  18. request = new HttpHead(url);
  19. break;
  20. case 3:// HttpPut
  21. request = new HttpPut(url);
  22. break;
  23. case 4:// HttpDelete
  24. request = new HttpDelete(url);
  25. break;
  26. case 5:// HttpTrace
  27. request = new HttpTrace(url);
  28. break;
  29. case 6:// HttpPatch
  30. request = new HttpPatch(url);
  31. break;
  32. case 7:// HttpOptions
  33. request = new HttpOptions(url);
  34. break;
  35. default:
  36. request = new HttpPost(url);
  37. break;
  38. }
  39. return request;
  40. }

当然最后的关闭链接也是一个小方法:

  1. /**
  2. * 尝试关闭response
  3. *
  4. * @param resp              HttpResponse对象
  5. */
  6. private static void close(HttpResponse resp) {
  7. try {
  8. if(resp == null) return;
  9. //如果CloseableHttpResponse 是resp的父类,则支持关闭
  10. if(CloseableHttpResponse.class.isAssignableFrom(resp.getClass())){
  11. ((CloseableHttpResponse)resp).close();
  12. }
  13. } catch (IOException e) {
  14. logger.error(e);
  15. }
  16. }

当然各种参数的组合方法也简单提供一下(为了节约空间,已去掉注释):

  1. public static String send(String url) throws HttpProcessException {
  2. return send(url, Charset.defaultCharset().name());
  3. }
  4. public static String send(String url, String encoding) throws HttpProcessException {
  5. return send(url, new Header[]{},encoding);
  6. }
  7. public static String send(String url, Header[] headers) throws HttpProcessException {
  8. return send(url, headers, Charset.defaultCharset().name());
  9. }
  10. public static String send(String url, Header[] headers, String encoding) throws HttpProcessException {
  11. return send(url, new HashMap<String,String>(), headers, encoding);
  12. }
  13. public static String send(String url, Map<String,String>parasMap) throws HttpProcessException {
  14. return send(url, parasMap, Charset.defaultCharset().name());
  15. }
  16. public static String send(String url, Map<String,String>parasMap, String encoding) throws HttpProcessException {
  17. return send(url, parasMap, new Header[]{}, encoding);
  18. }
  19. public static String send(String url, Map<String,String>parasMap, Header[] headers) throws HttpProcessException {
  20. return send(url, parasMap, headers, Charset.defaultCharset().name());
  21. }
  22. public static String send(String url, Map<String,String>parasMap, Header[] headers, String encoding) throws HttpProcessException {
  23. return send(url, HttpMethods.POST, parasMap, headers, encoding);
  24. }
  25. public static String send(String url, HttpMethods httpMethod) throws HttpProcessException {
  26. return send(url, httpMethod, Charset.defaultCharset().name());
  27. }
  28. public static String send(String url, HttpMethods httpMethod, String encoding) throws HttpProcessException {
  29. return send(url, httpMethod, new Header[]{},encoding);
  30. }
  31. public static String send(String url, HttpMethods httpMethod, Header[] headers) throws HttpProcessException {
  32. return send(url, httpMethod, headers, Charset.defaultCharset().name());
  33. }
  34. public static String send(String url, HttpMethods httpMethod, Header[] headers, String encoding) throws HttpProcessException {
  35. return send(url, httpMethod, new HashMap<String, String>(), headers, encoding);
  36. }
  37. public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap) throws HttpProcessException {
  38. return send(url, httpMethod, parasMap, Charset.defaultCharset().name());
  39. }
  40. public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap, String encoding) throws HttpProcessException {
  41. return send(url, httpMethod, parasMap, new Header[]{}, encoding);
  42. }
  43. public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap, Header[] headers) throws HttpProcessException {
  44. return send(url, httpMethod, parasMap, headers, Charset.defaultCharset().name());
  45. }
  46. public static String send(String url, HttpMethods httpMethod, Map<String,String>parasMap, Header[] headers, String encoding) throws HttpProcessException {
  47. return send(create(url), url, httpMethod, parasMap, headers, encoding);
  48. }
  49. public static String send(HttpClient client, String url) throws HttpProcessException {
  50. return send(client, url, Charset.defaultCharset().name());
  51. }
  52. public static String send(HttpClient client, String url, String encoding) throws HttpProcessException {
  53. return send(client, url, new Header[]{}, encoding);
  54. }
  55. public static String send(HttpClient client, String url, Header[] headers) throws HttpProcessException {
  56. return send(client, url, headers, Charset.defaultCharset().name());
  57. }
  58. public static String send(HttpClient client, String url, Header[] headers, String encoding) throws HttpProcessException {
  59. return send(client, url, new HashMap<String, String>(), headers, encoding);
  60. }
  61. public static String send(HttpClient client, String url, Map<String,String>parasMap) throws HttpProcessException {
  62. return send(client, url, parasMap, Charset.defaultCharset().name());
  63. }
  64. public static String send(HttpClient client, String url, Map<String,String>parasMap, String encoding) throws HttpProcessException {
  65. return send(client, url, parasMap, new Header[]{}, encoding);
  66. }
  67. public static String send(HttpClient client, String url, Map<String,String>parasMap, Header[] headers) throws HttpProcessException {
  68. return send(client, url, parasMap, headers, Charset.defaultCharset().name());
  69. }
  70. public static String send(HttpClient client, String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException {
  71. return send(client, url, HttpMethods.POST, parasMap, headers, encoding);
  72. }
  73. public static String send(HttpClient client, String url, HttpMethods httpMethod) throws HttpProcessException {
  74. return send(client, url, httpMethod, Charset.defaultCharset().name());
  75. }
  76. public static String send(HttpClient client, String url, HttpMethods httpMethod, String encoding) throws HttpProcessException {
  77. return send(client, url, httpMethod, new Header[]{}, encoding);
  78. }
  79. public static String send(HttpClient client, String url, HttpMethods httpMethod, Header[] headers) throws HttpProcessException {
  80. return send(client, url, httpMethod, headers, Charset.defaultCharset().name());
  81. }
  82. public static String send(HttpClient client, String url, HttpMethods httpMethod, Header[] headers, String encoding) throws HttpProcessException {
  83. return send(client, url, httpMethod, new HashMap<String, String>(), headers, encoding);
  84. }
  85. public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap) throws HttpProcessException {
  86. return send(client, url, httpMethod, parasMap, Charset.defaultCharset().name());
  87. }
  88. public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap, String encoding) throws HttpProcessException {
  89. return send(client, url, httpMethod, parasMap, new Header[]{}, encoding);
  90. }
  91. public static String send(HttpClient client, String url, HttpMethods httpMethod, Map<String,String>parasMap, Header[] headers) throws HttpProcessException {
  92. return send(client, url, httpMethod, parasMap, headers, Charset.defaultCharset().name());
  93. }

可以看到上面这一堆方法,其实主要分成2类,一类是传入client对象的,一组是没有传入的。也就是说该工具类提供了一种默认的client对象。这个将会在下一篇文章会有补充。

当然,为了方便操作,还是提供了get、post、put、patch、delete、head、options、trace等方法,由于推荐使用send方法,所以这几个方法只是做了一个简单的调用:

  1. public static String get(String url, Header[] headers,String encoding) throws HttpProcessException {
  2. return get(create(url), url, headers, encoding);
  3. }
  4. public static String get(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException {
  5. return send(client, url, HttpMethods.GET, headers, encoding);
  6. }
  7. public static String post(String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException {
  8. return post(create(url), url, parasMap, headers, encoding);
  9. }
  10. public static String post(HttpClient client, String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException {
  11. return send(client, url, HttpMethods.POST, parasMap, headers, encoding);
  12. }
  13. public static String put(String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException {
  14. return put(create(url), url, parasMap, headers, encoding);
  15. }
  16. public static String put(HttpClient client, String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException {
  17. return send(client, url, HttpMethods.PUT, parasMap, headers, encoding);
  18. }
  19. public static String delete(String url, Header[] headers,String encoding) throws HttpProcessException {
  20. return delete(create(url), url, headers, encoding);
  21. }
  22. public static String delete(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException {
  23. return send(client, url, HttpMethods.DELETE, headers, encoding);
  24. }
  25. public static String patch(String url, Map<String,String>parasMap,Header[] headers,String encoding) throws HttpProcessException {
  26. return patch(create(url), url, parasMap, headers, encoding);
  27. }
  28. public static String patch(HttpClient client, String url, Map<String,String>parasMap, Header[] headers,String encoding) throws HttpProcessException {
  29. return send(client, url, HttpMethods.PATCH, parasMap, headers, encoding);
  30. }
  31. public static String head(String url, Header[] headers,String encoding) throws HttpProcessException {
  32. return head(create(url), url, headers, encoding);
  33. }
  34. public static String head(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException {
  35. return send(client, url, HttpMethods.HEAD, headers, encoding);
  36. }
  37. public static String options(String url, Header[] headers,String encoding) throws HttpProcessException {
  38. return options(create(url), url, headers, encoding);
  39. }
  40. public static String options(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException {
  41. return send(client, url, HttpMethods.OPTIONS, headers, encoding);
  42. }
  43. public static String trace(String url, Header[] headers,String encoding) throws HttpProcessException {
  44. return trace(create(url), url, headers, encoding);
  45. }
  46. public static String trace(HttpClient client, String url, Header[] headers,String encoding) throws HttpProcessException {
  47. return send(client, url, HttpMethods.TRACE, headers, encoding);
  48. }

差点忘记了,最后还有一个简单的通用工具类

  1. /**
  2. *
  3. * @author arron
  4. * @date 2015年11月10日 下午12:49:26
  5. * @version 1.0
  6. */
  7. public class Utils {
  8. /**
  9. * 检测url是否含有参数,如果有,则把参数加到参数列表中
  10. *
  11. * @param url                   资源地址
  12. * @param nvps              参数列表
  13. * @return  返回去掉参数的url
  14. */
  15. public static String checkHasParas(String url, List<NameValuePair> nvps) {
  16. // 检测url中是否存在参数
  17. if (url.contains("?") && url.indexOf("?") < url.indexOf("=")) {
  18. Map<String, String> map = buildParas(url.substring(url
  19. .indexOf("?") + 1));
  20. map2List(nvps, map);
  21. url = url.substring(0, url.indexOf("?"));
  22. }
  23. return url;
  24. }
  25. /**
  26. * 参数转换,将map中的参数,转到参数列表中
  27. *
  28. * @param nvps              参数列表
  29. * @param map               参数列表(map)
  30. */
  31. public static void map2List(List<NameValuePair> nvps, Map<String, String> map) {
  32. if(map==null) return;
  33. // 拼接参数
  34. for (Entry<String, String> entry : map.entrySet()) {
  35. nvps.add(new BasicNameValuePair(entry.getKey(), entry
  36. .getValue()));
  37. }
  38. }
  39. /**
  40. * 生成参数
  41. * 参数格式“k1=v1&k2=v2”
  42. *
  43. * @param paras             参数列表
  44. * @return                      返回参数列表(map)
  45. */
  46. public static Map<String,String> buildParas(String paras){
  47. String[] p = paras.split("&");
  48. String[][] ps = new String[p.length][2];
  49. int pos = 0;
  50. for (int i = 0; i < p.length; i++) {
  51. pos = p[i].indexOf("=");
  52. ps[i][0]=p[i].substring(0,pos);
  53. ps[i][1]=p[i].substring(pos+1);
  54. pos = 0;
  55. }
  56. return buildParas(ps);
  57. }
  58. /**
  59. * 生成参数
  60. * 参数类型:{{"k1","v1"},{"k2","v2"}}
  61. *
  62. * @param paras                 参数列表
  63. * @return                      返回参数列表(map)
  64. */
  65. public static Map<String,String> buildParas(String[][] paras){
  66. // 创建参数队列
  67. Map<String,String> map = new HashMap<String, String>();
  68. for (String[] para: paras) {
  69. map.put(para[0], para[1]);
  70. }
  71. return map;
  72. }
  73. }

简单的封装就是这样了。

转:轻松把玩HttpClient之封装HttpClient工具类(一)(现有网上分享中的最强大的工具类)的更多相关文章

  1. 轻松把玩HttpClient之封装HttpClient工具类(五),携带Cookie的请求

    近期更新了一下HttpClientUtil工具类代码,主要是加入了一个參数HttpContext,这个是用来干嘛的呢?事实上是用来保存和传递Cookie所须要的. 由于我们有非常多时候都须要登录.然后 ...

  2. HttpClient 常用方法封装

    简介 在平时写代码中,经常需要对接口进行访问,对于 http 协议 rest 风格的接口请求,大多使用 HttpClient 工具进行编写,想着方便就寻思着把一些常用的方法进行封装,便于平时快速的使用 ...

  3. 完成OSS.Http底层HttpClient重构封装 支持标准库

    OSS.Http项目对于.Net Standard标准库的支持已经迁移完毕,OSS开源系列两个最底层的类库已经具备跨运行时支持的能力.由于OSS.Http类库是几年前我参照RestSharp的思路,完 ...

  4. 封装HttpClient进行http请求与https请求

    一.https忽略证书 /** * 用于进行Https请求的HttpClient * * @author joey * */ public class SSLClient { public stati ...

  5. Qt 访问网络的 HttpClient(封装QNetworkAccessManager,且有服务端)

    Qt 使用 QNetworkAccessManager 访问网络,这里对其进行了简单的封装,访问网络的代码可以简化为: 1 2 3 HttpClient("http://localhost: ...

  6. httpclient常规封装的方法

    <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compr ...

  7. httpClient简单封装

    package com.Interface.util; import java.util.Iterator; import java.util.Map; import org.apache.commo ...

  8. swfdump——从内存中提取swf的工具

    刚刚整理代码时发现以前写的从进程的内存镜像中提取swf文件的工具,现在分享出来,希望能帮到有需要的朋友.这个小工具是命令行使用,没有界面,可以很方便的从指定进程中(比如浏览器,swf播放器等等),按s ...

  9. C#中那些常用的工具类(Utility Class)(一)

    代码越写越多,但是我们也需要经常去反思那些写过的代码,Utility Class就是这一类需要特别去反思总结的类,这些类像工具一样,我们经常通过一些静态方法,通过传入一些参数,然后得到我们需要的结果, ...

随机推荐

  1. vue.config.js常用配置

    使用vue-cli3.0搭建项目比之前更简洁,没有了build和config文件夹. vue-cli3的一些服务配置都迁移到CLI Service里面了,对于一些基础配置和一些扩展配置需要在根目录新建 ...

  2. 小白学 Python(21):生成器基础

    人生苦短,我选Python 前文传送门 小白学 Python(1):开篇 小白学 Python(2):基础数据类型(上) 小白学 Python(3):基础数据类型(下) 小白学 Python(4):变 ...

  3. Redis必备面试题《基础篇》

    Date:2019-11-12 读前思考: 面试官会问什么样的问题? 所问的问题背后真实的套路是什么? 喜欢问Redis哪些问题? 如何顺畅回答面试问的问题?吊打面试官. 1.什么是Redis? Re ...

  4. PHP导出成PDF你用哪个插件

    准备工作 首先查询了相关的类库,有FPDF,zendPDF,TcPDF等等.首先看了下先选择了FPDF,可以说除了中文字符以外没有什么问题,中文乱码而且看了下最新版本没有很好的解决方案,所以只能放弃. ...

  5. Linux 下的这些高效指令,是你快速学习的神器

    Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序和网络协议.它支持32位 ...

  6. 利用SSH隧道技术穿越内网访问远程设备

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/11899478.html 通常,我们用于调试的计算机无法远程访问位于局域网中的待调试设备. ...

  7. CSS中越界问题的经典解决方案

    (1)如何解决父元素的第一个子元素的margin-top越界问题 1)为父元素加border-top: 1px;——有副作用 2)为父元素指定padding-top: 1px;——有副作用 3)为父元 ...

  8. 《JAVA 程序员面试宝典(第四版)》读书笔记之前言

    工作五年了一直在小的软件公司混,总感觉自己的专业知识没有太大的提升.当然了中间也换了一两家公司,面试的公司就很多家,总感觉正规的软件公司(无论大小)对于基础知识的考核都非常重视,而不管你说你之前服务过 ...

  9. .NET进阶篇06-async异步、thread多线程3

    知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 梯子 一.任务Task1.启动任务2.阻塞延续3.任务层次结构4.枚举参数5.任务取消6.任务结果7.异常二.并行Parallel1.Paral ...

  10. 如何编译和使用自定义Qt动态链接库 | how to build and use user-defined qt library

    本文首发于个人博客https://kezunlin.me/post/cf628dd8/,欢迎阅读! guide to build qt library and use in another proje ...