最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實(shí)現(xiàn)短信驗(yàn)證碼功能的完整代碼

 更新時(shí)間:2025年12月16日 09:39:32   作者:悟空碼字  
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)短信驗(yàn)證碼功能的完整代碼,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解下

一、被盜刷的慘狀:驗(yàn)證碼的“春運(yùn)”現(xiàn)場(chǎng)

想象一下這個(gè)場(chǎng)景:你的短信驗(yàn)證碼接口就像雙十一的購物車,一群“羊毛黨”開著機(jī)器人拖拉機(jī),以每秒100次的速度瘋狂點(diǎn)擊“發(fā)送驗(yàn)證碼”按鈕。你的短信費(fèi)就像漏氣的氣球一樣癟下去,而真正的用戶卻收不到驗(yàn)證碼,急得像熱鍋上的螞蟻。

更可怕的是,可能:

  • 用你的錢給隔壁老王發(fā)“我愛你”短信
  • 測(cè)試出所有已注冊(cè)手機(jī)號(hào)(撞庫攻擊)
  • 讓你的服務(wù)器累到懷疑人生,直接躺平(DDoS)

二、防御戰(zhàn)術(shù)大全:給接口裝上“金鐘罩”

1.頻率限制:給“點(diǎn)擊狂魔”戴上手銬

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 短信衛(wèi)士 - 專治各種手速過快
 */
public class SmsGuard {
    
    // 使用Guava Cache存儲(chǔ)訪問頻率
    private static final Cache<String, AtomicInteger> IP_CACHE = 
        CacheBuilder.newBuilder()
            .expireAfterWrite(1, TimeUnit.HOURS)
            .build();
    
    private static final Cache<String, AtomicInteger> PHONE_CACHE = 
        CacheBuilder.newBuilder()
            .expireAfterWrite(1, TimeUnit.HOURS)
            .build();
    
    /**
     * 檢查這個(gè)IP是不是在開掛
     * @param ip 客戶端IP
     * @param maxAttempts 最大嘗試次數(shù)(比如1小時(shí)10次)
     * @return true=正常用戶,false=疑似黑客
     */
    public static boolean isIpAllowed(String ip, int maxAttempts) {
        try {
            AtomicInteger counter = IP_CACHE.get(ip, () -> new AtomicInteger(0));
            int attempts = counter.incrementAndGet();
            
            if (attempts > maxAttempts) {
                System.out.println("檢測(cè)到IP " + ip + " 疑似開掛,已攔截!");
                return false;
            }
            return true;
        } catch (Exception e) {
            return false; // 出錯(cuò)時(shí)保守一點(diǎn),拒絕訪問
        }
    }
    
    /**
     * 檢查這個(gè)手機(jī)號(hào)是不是在刷驗(yàn)證碼
     * @param phone 手機(jī)號(hào)
     * @param maxSmsPerHour 每小時(shí)最多發(fā)幾條
     * @return true=可以發(fā),false=發(fā)太多了
     */
    public static boolean isPhoneAllowed(String phone, int maxSmsPerHour) {
        try {
            AtomicInteger counter = PHONE_CACHE.get(phone, () -> new AtomicInteger(0));
            int sentCount = counter.incrementAndGet();
            
            if (sentCount > maxSmsPerHour) {
                System.out.println("手機(jī)號(hào) " + phone + " 今天已經(jīng)收到" + sentCount + "條驗(yàn)證碼,讓它歇會(huì)兒吧");
                return false;
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

2.圖形驗(yàn)證碼:讓機(jī)器人“看圖說話”

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Random;

/**
 * 驗(yàn)證碼生成器 - 專治眼瞎的機(jī)器人
 */
public class CaptchaGenerator {
    
    /**
     * 生成能讓機(jī)器人懷疑人生的驗(yàn)證碼
     * @return [0]=圖片Base64, [1]=驗(yàn)證碼答案
     */
    public static String[] generateCaptcha() {
        int width = 120;
        int height = 40;
        
        // 創(chuàng)建一張讓機(jī)器人哭泣的圖片
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        
        // 設(shè)置背景色(隨機(jī)淺色)
        g.setColor(getRandomLightColor());
        g.fillRect(0, 0, width, height);
        
        // 畫干擾線(讓機(jī)器人眼花繚亂)
        g.setColor(Color.BLACK);
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            int x1 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int x2 = random.nextInt(width);
            int y2 = random.nextInt(height);
            g.drawLine(x1, y1, x2, y2);
        }
        
        // 生成隨機(jī)驗(yàn)證碼(避開容易混淆的字符)
        String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
        StringBuilder captchaText = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            char c = chars.charAt(random.nextInt(chars.length()));
            captchaText.append(c);
            
            // 扭曲、旋轉(zhuǎn)、變色 - 三連擊!
            g.setFont(new Font("Arial", Font.BOLD | Font.ITALIC, 30 + random.nextInt(5)));
            g.setColor(getRandomDarkColor());
            
            // 輕微旋轉(zhuǎn)字符
            double theta = random.nextDouble() * 0.5 - 0.25;
            g.rotate(theta, 20 + i * 25, 25);
            g.drawString(String.valueOf(c), 20 + i * 25, 25);
            g.rotate(-theta, 20 + i * 25, 25);
        }
        
        g.dispose();
        
        try {
            // 轉(zhuǎn)換為Base64
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            String base64Image = java.util.Base64.getEncoder().encodeToString(baos.toByteArray());
            
            return new String[]{"data:image/png;base64," + base64Image, captchaText.toString()};
        } catch (Exception e) {
            throw new RuntimeException("驗(yàn)證碼生成失敗", e);
        }
    }
    
    private static Color getRandomLightColor() {
        Random random = new Random();
        return new Color(200 + random.nextInt(55), 
                        200 + random.nextInt(55), 
                        200 + random.nextInt(55));
    }
    
    private static Color getRandomDarkColor() {
        Random random = new Random();
        return new Color(random.nextInt(150), 
                        random.nextInt(150), 
                        random.nextInt(150));
    }
}

3.滑動(dòng)驗(yàn)證碼:讓機(jī)器人“學(xué)走路”

import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 滑動(dòng)驗(yàn)證碼 - 專治不會(huì)用鼠標(biāo)的機(jī)器人
 */
public class SlideCaptchaService {
    
    // 存儲(chǔ)驗(yàn)證會(huì)話
    private static final ConcurrentHashMap<String, SlideCaptchaData> SESSIONS = 
        new ConcurrentHashMap<>();
    
    /**
     * 生成滑動(dòng)驗(yàn)證碼挑戰(zhàn)
     */
    public static SlideChallenge generateChallenge() {
        String sessionId = UUID.randomUUID().toString();
        
        // 隨機(jī)生成目標(biāo)位置(這里簡(jiǎn)化了,實(shí)際應(yīng)該有圖片處理)
        int targetX = 100 + new Random().nextInt(200);
        int targetY = 50 + new Random().nextInt(100);
        
        SlideCaptchaData data = new SlideCaptchaData(targetX, targetY);
        SESSIONS.put(sessionId, data);
        
        // 設(shè)置5分鐘過期
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                SESSIONS.remove(sessionId);
            }
        }, 5 * 60 * 1000);
        
        return new SlideChallenge(sessionId, targetX, targetY);
    }
    
    /**
     * 驗(yàn)證滑動(dòng)結(jié)果
     */
    public static boolean verify(String sessionId, int userX, int userY) {
        SlideCaptchaData data = SESSIONS.get(sessionId);
        if (data == null) {
            return false; // 會(huì)話過期
        }
        
        // 允許±5像素的誤差(人類手抖,機(jī)器人太精確反而可疑)
        boolean isValid = Math.abs(userX - data.targetX) <= 5 && 
                         Math.abs(userY - data.targetY) <= 5;
        
        if (isValid) {
            SESSIONS.remove(sessionId); // 一次性使用
        }
        
        return isValid;
    }
    
    static class SlideCaptchaData {
        int targetX;
        int targetY;
        
        SlideCaptchaData(int targetX, int targetY) {
            this.targetX = targetX;
            this.targetY = targetY;
        }
    }
    
    static class SlideChallenge {
        String sessionId;
        int targetX;
        int targetY;
        
        SlideChallenge(String sessionId, int targetX, int targetY) {
            this.sessionId = sessionId;
            this.targetX = targetX;
            this.targetY = targetY;
        }
    }
}

4.完整的短信發(fā)送服務(wù)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;

/**
 * 短信發(fā)送服務(wù) - 武裝到牙齒的版本
 */
@Service
public class SmsService {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Autowired
    private RiskControlService riskControlService;
    
    /**
     * 發(fā)送驗(yàn)證碼(安全加強(qiáng)版)
     */
    public ApiResponse sendVerificationCode(String phone, String ip, String captchaCode, String sessionId) {
        
        // 1. 檢查IP風(fēng)險(xiǎn)
        if (!riskControlService.checkIpRisk(ip)) {
            return ApiResponse.error("您的網(wǎng)絡(luò)環(huán)境存在風(fēng)險(xiǎn),請(qǐng)稍后再試");
        }
        
        // 2. 驗(yàn)證圖形驗(yàn)證碼(如果有)
        if (captchaCode != null && !validateCaptcha(sessionId, captchaCode)) {
            return ApiResponse.error("驗(yàn)證碼錯(cuò)誤,請(qǐng)重新輸入");
        }
        
        // 3. 頻率控制:同一手機(jī)號(hào)1分鐘內(nèi)只能發(fā)1次
        String minuteKey = "sms:minute:" + phone;
        if (Boolean.TRUE.equals(redisTemplate.hasKey(minuteKey))) {
            return ApiResponse.error("操作過于頻繁,請(qǐng)1分鐘后再試");
        }
        
        // 4. 頻率控制:同一手機(jī)號(hào)1小時(shí)內(nèi)最多5次
        String hourKey = "sms:hour:" + phone;
        Long hourCount = redisTemplate.opsForValue().increment(hourKey);
        if (hourCount != null && hourCount == 1) {
            redisTemplate.expire(hourKey, 1, TimeUnit.HOURS);
        }
        if (hourCount != null && hourCount > 5) {
            return ApiResponse.error("今日驗(yàn)證碼發(fā)送次數(shù)已達(dá)上限");
        }
        
        // 5. 生成6位隨機(jī)驗(yàn)證碼
        String code = String.format("%06d", new Random().nextInt(999999));
        
        // 6. 存儲(chǔ)驗(yàn)證碼(5分鐘過期)
        String codeKey = "sms:code:" + phone;
        redisTemplate.opsForValue().set(codeKey, code, 5, TimeUnit.MINUTES);
        
        // 7. 設(shè)置1分鐘冷卻期
        redisTemplate.opsForValue().set(minuteKey, "1", 1, TimeUnit.MINUTES);
        
        // 8. 記錄發(fā)送日志(用于分析)
        logSmsSent(phone, ip, code);
        
        // 9. 調(diào)用第三方短信服務(wù)(實(shí)際發(fā)送)
        boolean sent = realSendSms(phone, code);
        
        if (sent) {
            // 10. 返回脫敏的手機(jī)號(hào)
            String maskedPhone = phone.substring(0, 3) + "****" + phone.substring(7);
            return ApiResponse.success("驗(yàn)證碼已發(fā)送至" + maskedPhone);
        } else {
            return ApiResponse.error("短信發(fā)送失敗,請(qǐng)稍后重試");
        }
    }
    
    /**
     * 驗(yàn)證短信驗(yàn)證碼
     */
    public boolean verifyCode(String phone, String userCode) {
        String codeKey = "sms:code:" + phone;
        String correctCode = redisTemplate.opsForValue().get(codeKey);
        
        if (correctCode == null) {
            return false; // 驗(yàn)證碼已過期
        }
        
        // 驗(yàn)證成功后刪除驗(yàn)證碼(防止重復(fù)使用)
        boolean isValid = correctCode.equals(userCode);
        if (isValid) {
            redisTemplate.delete(codeKey);
        }
        
        return isValid;
    }
    
    private void logSmsSent(String phone, String ip, String code) {
        // 這里應(yīng)該記錄到數(shù)據(jù)庫或日志系統(tǒng)
        System.out.println(String.format(
            "短信發(fā)送日志: phone=%s, ip=%s, code=%s, time=%s",
            phone, ip, code, new java.util.Date()
        ));
    }
    
    private boolean realSendSms(String phone, String code) {
        // 調(diào)用真實(shí)的短信服務(wù)商接口
        // 這里簡(jiǎn)化處理,實(shí)際應(yīng)該用HTTP客戶端調(diào)用
        try {
            System.out.println(String.format(
                "發(fā)送短信到 %s: 您的驗(yàn)證碼是%s,5分鐘內(nèi)有效,打死也不要告訴別人哦!",
                phone, code
            ));
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

5.風(fēng)控服務(wù):火眼金睛識(shí)破壞人

/**
 * 風(fēng)控服務(wù) - 專治各種不服
 */
@Service
public class RiskControlService {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    /**
     * 綜合風(fēng)險(xiǎn)評(píng)估
     */
    public RiskLevel assessRisk(String phone, String ip, String userAgent) {
        int riskScore = 0;
        
        // 1. IP地址檢查
        if (isSuspiciousIp(ip)) {
            riskScore += 30;
        }
        
        // 2. User-Agent檢查
        if (isSuspiciousUserAgent(userAgent)) {
            riskScore += 20;
        }
        
        // 3. 請(qǐng)求頻率檢查
        if (isHighFrequency(ip)) {
            riskScore += 40;
        }
        
        // 4. 手機(jī)號(hào)歸屬地 vs IP歸屬地
        if (!isLocationConsistent(phone, ip)) {
            riskScore += 20;
        }
        
        // 5. 歷史行為檢查
        if (hasBadHistory(ip)) {
            riskScore += 50;
        }
        
        // 根據(jù)分?jǐn)?shù)返回風(fēng)險(xiǎn)等級(jí)
        if (riskScore >= 80) {
            return RiskLevel.HIGH;
        } else if (riskScore >= 50) {
            return RiskLevel.MEDIUM;
        } else {
            return RiskLevel.LOW;
        }
    }
    
    /**
     * 檢查IP風(fēng)險(xiǎn)
     */
    public boolean checkIpRisk(String ip) {
        String key = "risk:ip:" + ip;
        Long count = redisTemplate.opsForValue().increment(key);
        
        if (count == 1) {
            redisTemplate.expire(key, 1, TimeUnit.HOURS);
        }
        
        // 1小時(shí)內(nèi)超過50次請(qǐng)求視為風(fēng)險(xiǎn)
        return count == null || count <= 50;
    }
    
    enum RiskLevel {
        LOW,    // 低風(fēng)險(xiǎn):正常通過
        MEDIUM, // 中風(fēng)險(xiǎn):需要額外驗(yàn)證
        HIGH    // 高風(fēng)險(xiǎn):直接拒絕
    }
    
    // 其他檢測(cè)方法...
}

三、防御體系總結(jié):打造鐵桶陣

多層防御體系

第一層:前端防護(hù)

  • 圖形驗(yàn)證碼(專治簡(jiǎn)單機(jī)器人)
  • 滑動(dòng)驗(yàn)證碼(專治中級(jí)機(jī)器人)
  • 點(diǎn)擊按鈕防重放(防止連續(xù)點(diǎn)擊)

第二層:頻率限制

  • IP級(jí)別限流(防止單一IP攻擊)
  • 手機(jī)號(hào)級(jí)別限流(防止針對(duì)特定號(hào)碼)
  • 設(shè)備指紋限流(更精準(zhǔn)的識(shí)別)

第三層:行為分析

  • 請(qǐng)求時(shí)間分布分析(機(jī)器人請(qǐng)求太規(guī)律)
  • 鼠標(biāo)軌跡分析(機(jī)器人不會(huì)手抖)
  • 操作間隔分析(機(jī)器人反應(yīng)太快)

第四層:業(yè)務(wù)邏輯

  • 驗(yàn)證碼有效期控制(通常5分鐘)
  • 驗(yàn)證碼一次性使用(用后即焚)
  • 錯(cuò)誤次數(shù)限制(防止破解)

監(jiān)控與預(yù)警

/**
 * 監(jiān)控服務(wù) - 短信接口的"心電圖"
 */
@Service
public class SmsMonitorService {
    
    // 關(guān)鍵指標(biāo)監(jiān)控
    public void monitorMetrics() {
        // 1. 成功率監(jiān)控
        // 2. 響應(yīng)時(shí)間監(jiān)控
        // 3. 異常請(qǐng)求監(jiān)控
        // 4. 費(fèi)用消耗監(jiān)控
        
        // 發(fā)現(xiàn)異常立即告警
        // - 短信量突增
        // - 成功率突降
        // - 特定IP大量請(qǐng)求
    }
    
    /**
     * 自動(dòng)熔斷機(jī)制
     */
    public void circuitBreaker(String phonePrefix) {
        // 如果某個(gè)號(hào)段異常,自動(dòng)臨時(shí)屏蔽
        // 比如:170號(hào)段被大量攻擊,自動(dòng)限制該號(hào)段
    }
}

實(shí)踐建議

  • 按需發(fā)送:只有必要的時(shí)候才發(fā)驗(yàn)證碼,比如注冊(cè)、登錄、支付
  • 內(nèi)容脫敏:短信中不要包含完整手機(jī)號(hào)
  • 成本控制:設(shè)置每日、每月短信預(yù)算上限
  • 驗(yàn)證碼復(fù)雜度:6位數(shù)字足夠,別搞太復(fù)雜
  • 失敗處理:失敗時(shí)給出友好提示,但不要泄露細(xì)節(jié)
  • 定期審計(jì):定期檢查日志,發(fā)現(xiàn)異常模式

四、道高一尺,魔高一丈

安全是一場(chǎng)持久戰(zhàn)。今天防住了普通機(jī)器人,明天可能就有高級(jí)AI來挑戰(zhàn)。關(guān)鍵在于:

  • 不要依賴單一防御:多層防御才靠譜
  • 保持更新:安全方案需要與時(shí)俱進(jìn)
  • 監(jiān)控報(bào)警:早發(fā)現(xiàn)、早處理、早止損
  • 成本意識(shí):既要安全,也要考慮用戶體驗(yàn)和實(shí)現(xiàn)成本

最最重要的是:不要把驗(yàn)證碼接口當(dāng)成公共廁所,誰想來就來! 給它裝上門禁、攝像頭、保安,還要收門票(驗(yàn)證手段),這樣才能讓羊毛黨知難而退。

以上就是Java實(shí)現(xiàn)短信驗(yàn)證碼功能的完整代碼的詳細(xì)內(nèi)容,更多關(guān)于Java短信驗(yàn)證碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 23種設(shè)計(jì)模式(7) java代理模式

    23種設(shè)計(jì)模式(7) java代理模式

    這篇文章主要為大家詳細(xì)介紹了23種設(shè)計(jì)模式之java代理模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java并發(fā)編程示例(九):本地線程變量的使用

    Java并發(fā)編程示例(九):本地線程變量的使用

    這篇文章主要介紹了Java并發(fā)編程示例(九):本地線程變量的使用,有時(shí),我們更希望能在線程內(nèi)單獨(dú)使用,而不和其他使用同一對(duì)象啟動(dòng)的線程共享,Java并發(fā)接口提供了一種很清晰的機(jī)制來滿足此需求,該機(jī)制稱為本地線程變量,需要的朋友可以參考下
    2014-12-12
  • Java使用釘釘創(chuàng)建企業(yè)內(nèi)部機(jī)器人的實(shí)現(xiàn)

    Java使用釘釘創(chuàng)建企業(yè)內(nèi)部機(jī)器人的實(shí)現(xiàn)

    釘釘?shù)某霈F(xiàn)為企業(yè)節(jié)約了大量人力成本,其中也開放了大量的外部api接口方便企業(yè)使用。本文主要介紹了Java使用釘釘創(chuàng)建企業(yè)內(nèi)部機(jī)器人的實(shí)現(xiàn),感興趣的可以了解一下
    2021-11-11
  • 注冊(cè)中心配置了spring?security后客戶端啟動(dòng)報(bào)錯(cuò)

    注冊(cè)中心配置了spring?security后客戶端啟動(dòng)報(bào)錯(cuò)

    這篇文章主要為大家介紹了注冊(cè)中心配置了spring?security后客戶端啟動(dòng)報(bào)錯(cuò)問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 靜態(tài)工具類中注入Bean及引用Nacos配置方式

    靜態(tài)工具類中注入Bean及引用Nacos配置方式

    在Spring開發(fā)中,靜態(tài)工具類無法注入Bean或Nacos值,因靜態(tài)變量加載時(shí)Spring上下文未初始化,建議通過@Component標(biāo)記Bean,使用構(gòu)造器或Setter注入依賴,或直接在Bean內(nèi)處理Nacos配置,實(shí)現(xiàn)靈活調(diào)用
    2025-07-07
  • Maven入門教程之如何在idea中配置Maven

    Maven入門教程之如何在idea中配置Maven

    Maven是非常出色的項(xiàng)目管理工具,我們可以用它管理本地項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于Maven入門教程之如何在idea中配置Maven的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • java代理模式(jdk proxy)

    java代理模式(jdk proxy)

    代理(Proxy)是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象另外的訪問方式;這篇文章主要介紹了Java 中的三種代理模式,需要的朋友可以參考下,希望能幫助到你
    2021-07-07
  • Java使用線程同步解決線程安全問題詳解

    Java使用線程同步解決線程安全問題詳解

    線程安全是多線程編程時(shí)的計(jì)算機(jī)程序代碼中的一個(gè)概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會(huì)通過同步機(jī)制保證各個(gè)線程都可以正常且正確的執(zhí)行,不會(huì)出現(xiàn)數(shù)據(jù)污染等意外情況
    2022-05-05
  • Java封裝數(shù)組實(shí)現(xiàn)包含、搜索和刪除元素操作詳解

    Java封裝數(shù)組實(shí)現(xiàn)包含、搜索和刪除元素操作詳解

    這篇文章主要介紹了Java封裝數(shù)組實(shí)現(xiàn)包含、搜索和刪除元素操作,結(jié)合實(shí)例形式分析了java針對(duì)數(shù)組元素的查找、刪除、判斷等相關(guān)操作封裝與使用技巧,需要的朋友可以參考下
    2020-03-03
  • java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)爬蟲代碼示例

    java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)爬蟲代碼示例

    這篇文章主要介紹了java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)爬蟲代碼示例,還是挺不錯(cuò)的,這里分享給大家,需要的朋友可以參考下。
    2017-11-11

最新評(píng)論

纳雍县| 凭祥市| 山西省| 越西县| 滁州市| 航空| 阳朔县| 建德市| 两当县| 固镇县| 常宁市| 太白县| 天津市| 和龙市| 清新县| 边坝县| 八宿县| 吉水县| 江门市| 盐边县| 凯里市| 如皋市| 江西省| 博兴县| 上饶市| 波密县| 洞口县| 土默特左旗| 镇原县| 横山县| 黄陵县| 海南省| 张家口市| 永善县| 察雅县| 应用必备| 石柱| 乌什县| 濮阳市| 浮山县| 岑巩县|