我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java实现发送短信验证码+redis限制发送的次数功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java实现发送短信验证码+redis限制发送的次数功能

java实现短信验证码发送,由于我们使用第三方平台进行验证码的发送,所以首先,我们要在一个平台进行注册。这样的平台有很多,有的平台在新建账号的时候会附带赠几条免费短信。这里我仅做测试使用(具体哪个平台见参考三,很简单,注册账号就行,记得添加短信签名)。

另外,在实际项目中,如果有人恶意攻击,不停的发送短信验证码,就会造成很大的损失。故对发送次数做一定的限制就非常必要,这里我们限制一个手机号一天可以发多少短信和短信平台无关。

这里采用的是存redis来实现这一个功能。就是每次调用发送验证码这个接口都会判断手机号码是否在redis中存为key了。如果没有则创建一个key为手机号码value是1.因为redis中不支持数字所以将其变为了string类型。如果redis中已经有这个key了则将此key的值取出来加1再存进redis中。

代码实现:

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lmc</groupId>
    <artifactId>springboot-sendsms</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-sendsms</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

RespBean.java

package com.lmc.bean;
 
public class RespBean {
    private Integer status;
    private String msg;
    private Object obj;
 
    public static RespBean build() {
        return new RespBean();
    }
 
    public static RespBean ok(String msg) {
        return new RespBean(200, msg, null);
    }
 
    public static RespBean ok(String msg, Object obj) {
        return new RespBean(200, msg, obj);
    }
 
    public static RespBean error(String msg) {
        return new RespBean(500, msg, null);
    }
 
    public static RespBean error(String msg, Object obj) {
        return new RespBean(500, msg, obj);
    }
 
    private RespBean() {
    }
 
    private RespBean(Integer status, String msg, Object obj) {
        this.status = status;
        this.msg = msg;
        this.obj = obj;
    }
 
    public Integer getStatus() {
        return status;
    }
 
    public RespBean setStatus(Integer status) {
        this.status = status;
        return this;
    }
 
    public String getMsg() {
        return msg;
    }
 
    public RespBean setMsg(String msg) {
        this.msg = msg;
        return this;
    }
 
    public Object getObj() {
        return obj;
    }
 
    public RespBean setObj(Object obj) {
        this.obj = obj;
        return this;
    }
}

RedisConfig.java

package com.lmc.config;
 
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import java.net.UnknownHostException;
@Configuration
public class RedisConfig {
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(
        StringRedisTemplate template = new StringRedisTemplate();
}

SMSController.java


package com.lmc.controller;
 
import com.lmc.bean.RespBean;
import com.lmc.utils.HttpClientUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
public class SMSController {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @RequestMapping("/send")
    public RespBean sendSMS() {
        String Uid = "xxxxxxxx";
        String Key = "xxxxxxxxxxxxxxx";
        String smsMob = "xxxxxxxxx";
        String sendSMSCount = "sendSMSCount:" + smsMob;
        if ("2".equals(stringRedisTemplate.opsForValue().get(sendSMSCount))) {
            return RespBean.error("今天已达到发送短信验证码上限,请明天再试");
        }
        //短信内容
        String smsText = "欢迎使用xx系统,验证码:8888";
        Map maps = new HashMap();
        maps.put("Uid", Uid);
        maps.put("Key", Key);
        maps.put("smsMob", smsMob);
        maps.put("smsText", smsText);
        String result = HttpClientUtils.sendHttpPost("http://utf8.sms.webchinese.cn", maps);
        int i = Integer.parseInt(result);
        if (i > 0) {
            if (stringRedisTemplate.opsForValue().get(sendSMSCount) == null) {
                stringRedisTemplate.opsForValue().set(sendSMSCount, "1", getEndTime(), TimeUnit.MILLISECONDS);
            } else {
                String value = stringRedisTemplate.opsForValue().get(sendSMSCount);
                int times = Integer.parseInt(value) + 1;
                String timesStr = String.valueOf(times);
                stringRedisTemplate.opsForValue().set(sendSMSCount, timesStr, getEndTime(), TimeUnit.MILLISECONDS);
            }
            return RespBean.ok("发送成功");
        return RespBean.ok("发送失败");
    }
    
    //获取当前时间到今天结束时间所剩余的毫秒数:
    public static long getEndTime() {
        //获取当前时间的毫秒数
        long time = new java.util.Date().getTime();
        //获取到今天结束的毫秒数
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.set(Calendar.HOUR_OF_DAY, 23); // Calendar.HOUR 12小时制。HOUR_OF_DAY 24小时制
        todayEnd.set(Calendar.MINUTE, 59);
        todayEnd.set(Calendar.SECOND, 59);
        todayEnd.set(Calendar.MILLISECOND, 999);
        long endTime = todayEnd.getTimeInMillis();
        //这里endTime-time获取的是到23:59:59:999的毫秒数。再加1才是到24点整的毫秒数
        return endTime-time+1;
}

HttpClientUtils.java(HttpClient工具类,可以复用)

package com.lmc.utils;
 
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
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.methods.HttpRequestBase;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.util.PublicSuffixMatcher;
import org.apache.http.conn.util.PublicSuffixMatcherLoader;
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.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpClientUtils {
	private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
	// 链接相关参数
	private static int socketTimeout = 15000;
	private static int connectTimeout = 15000;
	private static int connectionRequestTimeout = 15000;
	private static RequestConfig requestConfig = null;
	// 连接池相关参数
	private static int connMgrMaxTotal = 100;
	private static int connMgrMaxPerRoute = 50;
	private static PoolingHttpClientConnectionManager connMgr = null;
	
	static {
		requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout).build();
		connMgr = new PoolingHttpClientConnectionManager();
		connMgr.setDefaultMaxPerRoute(connMgrMaxPerRoute);
		connMgr.setMaxTotal(connMgrMaxTotal);
	}
	private static String doHttp(HttpRequestBase httpRequestBase) {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		String responseContent = null;
		
		try {
			// 创建默认的httpClient实例.
			String scheme = httpRequestBase.getURI().getScheme();
			if (scheme.equalsIgnoreCase("https")) {
				PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.load(new URL(httpRequestBase.getURI().toString()));
				DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
				httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).setConnectionManager(connMgr).build();
				//httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build();
			} else if (scheme.equalsIgnoreCase("http")) {
				httpClient = HttpClients.custom().setConnectionManager(connMgr).build();
				//httpClient = HttpClients.createDefault();
			} else {
				throw new IllegalArgumentException("url的scheme错误,必须是http或者https! ");
			}
			httpRequestBase.setConfig(requestConfig);
			// 执行请求
			response = httpClient.execute(httpRequestBase);
			// 如果这里有必要获取的是其他资料都可以在这里进行逻辑处理
			responseContent = EntityUtils.toString(response.getEntity(), "UTF-8");
			return responseContent;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭连接,释放资源
				if (response != null) {
					// EntityUtils.consume(response.getEntity());
					response.close();
				}
				// 这里不能关闭httpClient,这个会关链接池
				//if (httpClient != null) {
				//  httpClient.close();
				//}
				
			} catch (IOException e) {
				e.printStackTrace();
		}
		return responseContent;
	
	public static String sendHttpGet(String url) {
		return doHttp(new HttpGet(url));
	 * sendHttpGet()
	 * @param param key1=value1&key2=value2&key3=value3
	public static String sendHttpGet(String url, String param) {
		// 创建httpGet
		HttpGet httpGet = new HttpGet(url + '?' + param);
		return doHttp(httpGet);
	 * sendHttpPost()
	public static String sendHttpPost(String url, String param) {
		// 创建httpPost
		HttpPost httpPost = new HttpPost(url);
			StringEntity stringEntity = new StringEntity(param, "UTF-8");
			stringEntity.setContentType("application/x-www-form-urlencoded");
			httpPost.setEntity(stringEntity);
		return doHttp(httpPost);
	 * sendHttpGet
	 * @param param 是个map<String, String>
	public static String sendHttpGet(String url, Map<String, String> param) {
		String paramStr = "";
		for (String key : param.keySet()) {
			String tmp = "";
			tmp = "&" + key + "=" + param.get(key);
			paramStr += tmp;
		paramStr = paramStr.substring(1);
		HttpGet httpGet = new HttpGet(url + '?' + paramStr);
        return doHttp(httpGet);
	 * sendHttpPost
	 * @param param 是个map<String,String>
	public static String sendHttpPost(String url, Map<String, String> param) {
		// 创建参数队列 
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        for (String key : param.keySet()) {
            nameValuePairs.add(new BasicNameValuePair(key, param.get(key)));   
        }
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));    
        } catch (Exception e) {
            e.printStackTrace();
        
        return doHttp(httpPost);
	public static String sendHttpPostJson(String url, String json) {
			// StringEntity stringEntity = new StringEntity(param, "UTF-8");
			// stringEntity.setContentType("application/json");
			// stringEntity.setContentEncoding("UTF-8");
			StringEntity stringEntity = new StringEntity(json, ContentType.create("application/json", "UTF-8"));
						
	public static void main(String[] args) {
		String url = "http://api.crpay.com/payapi/gateway";
		String param = "merchant_no=TOF00001&method=unified.trade.pay&version=1.0";
		Map map = new HashMap<String, String>();
		map.put("merchant_no", "TOF00001");
		map.put("method", "unified.trade.pay");
		map.put("version", "1.0");
		// 这个工具是走的链接池,但是在关闭httpClient会关闭连接池的地方已经注销
		//System.out.println(HttpClientUtils.sendHttpPost(url, map));
		//System.out.println(HttpClientUtils.sendHttpPost(url, param));
		//System.out.println(HttpClientUtils.sendHttpGet(url, map));
		System.out.println(HttpClientUtils.sendHttpGet("https://www.baidu.com"));
		System.out.println(HttpClientUtils.sendHttpGet("http://www.baidu.com/s?wd=aaa"));
		Map map2 = new HashMap<String, String>();
		map2.put("wd", "aaa");
		System.out.println(HttpClientUtils.sendHttpGet("http://www.baidu.com/s",map2));
		// doHttp是静态私有方法,不能使用多次,会报Connection pool shut down 
		System.out.println(HttpClientUtils.doHttp(new HttpGet("http://www.baidu.com/s?wd=aaa")));
		System.out.println(HttpClientUtils.doHttp(new HttpGet("https://www.baidu.com/")));
		System.out.println(HttpClientUtils.sendHttpGet("https://www.cnblogs.com/hugo-zhangzhen/p/6858013.html"));
		System.out.println(HttpClientUtils.sendHttpGet("https://www.cnblogs.com/hugo-zhangzhen/p/6739658.html"));
		System.out.println(HttpClientUtils.sendHttpGet("https://www.cnblogs.com/hugo-zhangzhen/p/6737810.html"));
		System.out.println(HttpClientUtils.sendHttpGet("http://blog.csdn.net/xiechengfa/article/details/42016153"));
}

application.properties

# 配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456

项目结果如下:

 结果展示:

使用postman调用接口,超过2次后,显示如下。

在具体项目中的流程一般如下:

①构造手机验证码,需要生成一个6位的随机数字串;

②找短信平台获取使用接口向短信平台发送手机号和验证码,然后短信平台再把验证码发送到制定手机号上;

③将手机号验证码、操作时间存入Session中,作为后面验证使用;

④接收用户填写的验证码、手机号及其他注册数据;

⑤对比提交的验证码与Session中的验证码是否一致,同时判断提交动作是否在有效期内;

⑥验证码正确且在有效期内,请求通过,处理相应的业务。

参考:

接收短信验证码条数限制(java发送短信验证码限制) - 简书

Java如何实现短信验证码功能? - 知乎

Java 实现手机发送短信验证码 - 胖头陀春天 - 博客园

到此这篇关于Java实现发送短信验证码+redis限制发送的次数的文章就介绍到这了,更多相关java短信验证码限制发送次数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java实现发送短信验证码+redis限制发送的次数功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java如何实现发送短信验证码功能

小编给大家分享一下Java如何实现发送短信验证码功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一个发送短信验证码的功能,使用的是信易通的短信平台接口,然后在J
2023-05-30

Redis怎么实现验证码发送并限制每日发送次数

这篇文章主要讲解了“Redis怎么实现验证码发送并限制每日发送次数”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Redis怎么实现验证码发送并限制每日发送次数”吧!1、功能输入手机号,点击发
2023-06-30

怎么用java+maven实现发送短信验证码功能

这篇文章主要介绍“怎么用java+maven实现发送短信验证码功能”,在日常操作中,相信很多人在怎么用java+maven实现发送短信验证码功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么用java+m
2023-06-02

Android实现发送短信验证码倒计时功能示例

一、简介: 开发中在用户注册或找回密码之类的功能,经常会遇到获取短信验证码,获取验证码后需要等待1分钟倒计时,这段时间是不能再次发送短信请求的。 效果图:二、实现步骤: 1、一个关键类:CountDownTimer(Android系统自带的
2022-06-06

教你用Python实现短信验证码的发送

当我们在注册一个网页时,有的网页会让必须要短信验证、邮箱验证,才可以进行账号的注册,下面这篇文章主要给大家介绍了关于用Python实现短信验证码发送的相关资料,需要的朋友可以参考下
2022-12-08

Springboot实现阿里云通信短信服务有关短信验证码的发送功能

前言短信验证码是通过发送验证码到手机的一种有效的验证码系统。主要用于验证用户手机的合法性及敏感操作的身份验证。现在市面上的短信服务平台有很多。大家在选择的时候未免会有些不好抉择。本人建议选择短信服务商应遵循以下几点: 服务商知名度高,业务
2023-05-31

使用python爬虫怎么实现一个发送短信验证码功能

本篇文章为大家展示了使用python爬虫怎么实现一个发送短信验证码功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。内联代码片。import timedef get_time() : " 获取当前
2023-06-06

Java中怎么实现SMS短信通发送手机验证码

本篇文章给大家分享的是有关Java中怎么实现SMS短信通发送手机验证码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。设置短信签名注意不要乱写别的公司等,会被视为诈骗信息设置短信
2023-06-20

php如何实现发送验证码的功能

这篇文章给大家分享的是有关php如何实现发送验证码的功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。php实现发送验证码功能的方法:1、创建好HTML和js文件;2、创建“Msm.php”文件,内容为“publ
2023-06-25

php怎么实现发送验证码的功能

php实现发送验证码功能的方法:1、创建好HTML和js文件;2、创建“Msm.php”文件,内容为“public function sendmsm(){...}”;3、通过CURL发送HTTP请求即可。
2021-10-31

PHP实现发送短信验证码的方法是什么

本篇内容主要讲解“PHP实现发送短信验证码的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PHP实现发送短信验证码的方法是什么”吧!1、创建好HTML和js文件。2、创建“Msm.ph
2023-06-25

异步协程开发技巧:实现高效的短信验证码发送

在移动互联网时代,短信验证码已成为了用户注册、登录以及找回密码等操作的必备步骤。然而,短信验证码的发送一直以来都是开发中的一大难点,尤其是在高并发场景下,往往会导致系统性能的下降。为了解决这一问题,本文介绍了异步协程开发技巧,并提供了具体的
异步协程开发技巧:实现高效的短信验证码发送
2023-12-09

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录