Java實現(xiàn)字符驗證碼掘殴、運算驗證碼

Java中很輕松可以實現(xiàn)驗證碼功能,在原生AWT圖形化工具包中寫一點簡單的邏輯就能輕松完成驗證碼功能车摄。
本文寺谤,同時將google的kaptcha驗證碼一同講解。

項目地址:https://gitee.com/gester/captcha.git

同時吮播,推一下滑動驗證碼的原理與實現(xiàn)的文章变屁。文章地址:http://www.reibang.com/p/6ff29737209f

原創(chuàng)不易!如果有幫到您意狠,可以給作者一個小星星鼓勵下 ^ _ ^

功能

  1. 字符驗證碼
    • AWT實現(xiàn)字符驗證碼
    • kaptcha實現(xiàn)字符驗證碼
  2. 運算驗證碼
    • AWT實現(xiàn)運算驗證碼
    • kaptcha實現(xiàn)運算驗證碼
  3. 滑動驗證碼(擴展)
    由于代碼量較大粟关,功能關聯(lián)性不強。一篇文章不夠清楚說明环戈,將在另外一篇文章講解闷板。

相關依賴

        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>

一. AWT實現(xiàn)驗證碼

字符驗證碼:

 /**
     * 生成字符驗證碼
     * @return 字符驗證碼
     */
    public static Map<String, Object> generatorCharVerificationCode() {
        //  驗證碼圖片邊框?qū)挾?        final int WIDTH = 150;
        //  驗證碼圖片邊框高度
        final int HEIGHT = 50;
        //  驗證碼字符長度
        int CHAR_LENGTH = 6;
        //  驗證碼字體高度
        int FONT_HEIGHT = HEIGHT - 12;
        //  驗證碼干擾線條數(shù)
        int INTERFERENCE_LINE = 4;
        //  生成驗證碼所需字符
        char[] charSequence = {
                'A', 'B', 'C', 'D', 'E', 'F',
                'G', 'H', 'I', 'J', 'K', 'L',
                'M', 'N', 'O', 'P', 'Q', 'R',
                'S', 'T', 'U', 'V', 'W', 'X',
                'Y', 'Z', '0', '1', '2', '3',
                '4', '5', '6', '7', '8', '9'
        };
        Map<String, Object> verificationCodeMap = null;

        //  生成透明rgb圖片
        BufferedImage bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics graphics = bufferedImage.getGraphics();
        //  備份原始畫筆顏色
        Color color = graphics.getColor();
        graphics.setColor(Color.BLACK);
        //  圖片填充黑色
        graphics.fillRect(0, 0, WIDTH, HEIGHT);

        graphics.setColor(Color.WHITE);
        //  圖片填充白色澎灸;組成黑色邊框的白色圖片
        graphics.fillRect(1, 1, WIDTH - 2, HEIGHT - 2);

        int newFontHeight = CHAR_LENGTH > 4 ? FONT_HEIGHT * 4 / CHAR_LENGTH : FONT_HEIGHT;

        //  設置畫筆字體
        Font font = new Font("微軟雅黑", Font.PLAIN, newFontHeight);
        graphics.setFont(font);
        //  根據(jù)系統(tǒng)時間創(chuàng)建隨機數(shù)對象
        Random random = new Random(System.currentTimeMillis());
        int r = 0;
        int g = 0;
        int b = 0;
        //  驗證碼字符串
        StringBuilder verificationCode = new StringBuilder();
        for (int i = 0; i < CHAR_LENGTH; i++) {
            char ch = charSequence[random.nextInt(charSequence.length)];
            //   隨機生成rgb顏色值,并設置畫筆顏色
            r = random.nextInt(255);
            g = random.nextInt(255);
            b = random.nextInt(255);
            graphics.setColor(new Color(r, g, b));
            //  根據(jù)畫筆顏色繪制字符
            graphics.drawString(String.valueOf(ch), i * (newFontHeight), FONT_HEIGHT);
            verificationCode.append(ch);
        }

        //  繪制干擾線
        int x1, y1, x2, y2;
        for (int i = 0; i < INTERFERENCE_LINE; i++) {
            //   隨機生成rgb顏色值蛔垢,并設置畫筆顏色
            r = random.nextInt(255);
            g = random.nextInt(255);
            b = random.nextInt(255);
            graphics.setColor(new Color(r, g, b));
            x1 = random.nextInt(WIDTH);
            y1 = random.nextInt(HEIGHT);
            x2 = random.nextInt(WIDTH);
            y2 = random.nextInt(HEIGHT);
            //  繪制線條
            graphics.drawLine(x1, y1, x2, y2);
        }

        //  恢復畫筆顏色
        graphics.setColor(color);

        verificationCodeMap = new HashMap<String, Object>();
        verificationCodeMap.put("verificationCodeImage", bufferedImage);
        verificationCodeMap.put("verificationCode", verificationCode);
        return verificationCodeMap;

    }

        public static void main(String[] args) throws IOException {
            Map<String, Object> charMap = generatorCharVerificationCode();
            BufferedImage bufferedImage1 = (BufferedImage) charMap.get("verificationCodeImage");

            OutputStream outputStream1 = new FileOutputStream("C:/Users/Administrator/Desktop/charVerificationCodeImage.png");
            ImageIO.write(bufferedImage1, "png", outputStream1);
            System.out.println("驗證碼: " + charMap.get("verificationCode"));
            outputStream1.flush();
            outputStream1.close();
        }

預覽圖

charVerificationCodeImage.png

運算驗證碼:


    static StringBuilder result = new StringBuilder();  // 運算驗證碼結(jié)果
    /**
     * 生成運算驗證碼
     * @return  運算驗證碼
     */
    public static Map<String, Object> generatorOperationVerificationCode() {
        //  驗證碼圖片邊框?qū)挾?        final int WIDTH = 185;
        //  驗證碼圖片邊框高度
        final int HEIGHT = 50;
        //  驗證碼字體高度
        int FONT_HEIGHT = HEIGHT - 12;
        //  驗證碼干擾線條數(shù)
        int INTERFERENCE_LINE = 4;

        Map<String, Object> verificationCodeMap = null;

        //  生成透明rgb圖片
        BufferedImage bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics graphics = bufferedImage.getGraphics();
        //  備份原始畫筆顏色
        Color color = graphics.getColor();
        graphics.setColor(Color.BLACK);
        //  圖片填充黑色
        graphics.fillRect(0, 0, WIDTH, HEIGHT);

        graphics.setColor(Color.WHITE);
        //  圖片填充白色击孩;組成黑色邊框的白色圖片
        graphics.fillRect(1, 1, WIDTH - 2, HEIGHT - 2);

        //  驗證碼字符串
        String text = getText();
        //  運算表達式
        String operationExpression = text.substring(0, text.lastIndexOf("@") - 1);
        //  計算結(jié)果
        String result = text.substring(text.lastIndexOf("@") + 1, text.length());

        int newFontHeight = operationExpression.length() > 4 ? FONT_HEIGHT * 4 / operationExpression.length() : FONT_HEIGHT;

        //  設置畫筆字體
        Font font = new Font("微軟雅黑", Font.PLAIN, FONT_HEIGHT);
        graphics.setFont(font);
        //  根據(jù)系統(tǒng)時間創(chuàng)建隨機數(shù)對象
        Random random = new Random(System.currentTimeMillis());
        int r = 0;
        int g = 0;
        int b = 0;

        //   隨機生成rgb顏色值,并設置畫筆顏色
        r = random.nextInt(255);
        g = random.nextInt(255);
        b = random.nextInt(255);
        graphics.setColor(new Color(r, g, b));
        //  根據(jù)畫筆顏色繪制字符
        graphics.drawString(operationExpression, 5, FONT_HEIGHT);

        //  繪制干擾線
        int x1, y1, x2, y2;
        for (int i = 0; i < INTERFERENCE_LINE; i++) {
            //   隨機生成rgb顏色值鹏漆,并設置畫筆顏色
            r = random.nextInt(255);
            g = random.nextInt(255);
            b = random.nextInt(255);
            graphics.setColor(new Color(r, g, b));
            x1 = random.nextInt(WIDTH);
            y1 = random.nextInt(HEIGHT);
            x2 = random.nextInt(WIDTH);
            y2 = random.nextInt(HEIGHT);
            //  繪制線條
            graphics.drawLine(x1, y1, x2, y2);
        }

        //  恢復畫筆顏色
        graphics.setColor(color);

        verificationCodeMap = new HashMap<String, Object>();
        verificationCodeMap.put("verificationCodeImage", bufferedImage);
        verificationCodeMap.put("verificationCode", result);
        return verificationCodeMap;

    }

    /**
     * 獲取運算驗證碼
     * @return 運算驗證碼
     */
    public static String getText() {
        Random random = new Random(System.currentTimeMillis());
        int x = random.nextInt(51);
        int y = random.nextInt(51);
        int operationalRules = random.nextInt(4);

        switch (operationalRules) {
            case 0:
                add(x, y);
                break;
            case 1:
                subtract(x, y);
                break;
            case 2:
                multiply(x, y);
                break;
            case 3:
                divide(x, y);
                break;
        }
        return result.toString();
    }

    /**
     * 加法運算
     * @param x 變量x
     * @param y 變量y
     */
    private static void add(int x, int y) {
        result.append(x);
        result.append(" + ");
        result.append(y);
        result.append(" = ?@");
        result.append(x + y);
    }

    /**
     * 減法運算
     * @param x 變量x
     * @param y 變量y
     */
    private static void subtract(int x, int y) {
        int max = Math.max(x, y);
        int min = Math.min(x, y);
        result.append(max);
        result.append(" - ");
        result.append(min);
        result.append(" = ?@");
        result.append(max - min);
    }

    /**
     * 乘法運算
     * @param x 變量x
     * @param y 變量y
     */
    private static void multiply(int x, int y) {
        int value = x * y;
        result.append(x);
        result.append(value > 100 ? " + " : " * ");
        result.append(y);
        result.append(" = ?@");
        result.append(value > 100 ? x + y : x * y);
    }

    /**
     * 出發(fā)運算
     * @param x 變量x
     * @param y 變量y
     */
    private static void divide(int x, int y) {
        int max = Math.max(x, y);
        int min = Math.min(x, y);
        if (min == 0) {
            multiply(max, min);
        } else if (max % min == 0) {
            result.append(max);
            result.append(" / ");
            result.append(min);
            result.append(" = ?@");
            result.append(max / min);
        } else {
            result.append(max);
            result.append(" % ");
            result.append(min);
            result.append(" = ?@");
            result.append(max % min);
        }
    }


    public static void main(String[] args) throws IOException {
        Map<String, Object> operationMap = generatorOperationVerificationCode();
        BufferedImage bufferedImage2 = (BufferedImage) operationMap.get("verificationCodeImage");

        OutputStream outputStream2 = new FileOutputStream("C:/Users/Administrator/Desktop/operationVerificationCodeImage.png");
        ImageIO.write(bufferedImage2, "png", outputStream2);
        System.out.println("驗證碼: " + operationMap.get("verificationCode"));
        outputStream2.flush();
        outputStream2.close();
    }

預覽圖

operationVerificationCodeImage.png

總的來說巩梢,AWT實現(xiàn)驗證碼非常簡單,只需要編寫簡單的邏輯即可實現(xiàn)需要的驗證碼功能艺玲。代碼中的驗證碼可以根據(jù)字符長度和運算表達式長度適應畫布大小括蝠。但是,仍是不完美饭聚;這時忌警,kaptcha就登場了,我們?yōu)樯兑褂胟apcha秒梳,kapcha的優(yōu)勢有什么法绵?
kaptcha驗證碼是谷歌編寫開源的,也是基于AWT實現(xiàn)酪碘。但是功能更加豐富朋譬,可以配置背景、畫布兴垦、尺寸徙赢、顏色、樣式探越、噪點等等諸多好處狡赐。項目具有輕量級、功能豐富钦幔、易于上手枕屉,且是大公司開源,穩(wěn)定性有保障节槐。為何不用搀庶?

kaptcha實現(xiàn)字符驗證碼:
默認情況下,kaptcha是默認生成英文數(shù)字組合的字符驗證碼铜异。但是哥倔,這里功能很強大,可以自己編寫驗證碼的生成器規(guī)則揍庄,注冊到kapcha攔截器中咆蒿,即可使用。運算驗證碼就是使用這一種方式,待會再議沃测。

配置類代碼:

@Configuration
public class CaptchaConfig
{
    @Bean(name = "captchaProducer")
    public DefaultKaptcha getKaptchaBean()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有邊框 默認為true 我們可以自己設置yes缭黔,no
        properties.setProperty("kaptcha.border", "yes");
        // 邊框顏色 默認為Color.BLACK
        properties.setProperty("kaptcha.border.color",  "black");
        // 驗證碼文本字符顏色 默認為Color.BLACK
        properties.setProperty("kaptcha.textproducer.font.color", "black");
        // 驗證碼圖片寬度 默認為200
        properties.setProperty("kaptcha.image.width", "150");
        // 驗證碼圖片高度 默認為50
        properties.setProperty("kaptcha.image.height", "60");
        // 驗證碼文本字符大小 默認為40
        properties.setProperty("kaptcha.textproducer.font.size", "30");
        // KAPTCHA_SESSION_KEY
        properties.setProperty("kaptcha.session.key", "kaptchaCharCode");
        // 驗證碼文本字符間距 默認為2
        properties.setProperty("kaptcha.textproducer.char.space", "3");
        // 驗證碼文本字符長度 默認為4
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        // 驗證碼文本字體樣式 默認為new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty("kaptcha.textproducer.font.names", "微軟雅黑");
        // 驗證碼噪點顏色 默認為Color.BLACK
        properties.setProperty("kaptcha.noise.color",  "black");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

生成字符驗證碼

 /**
     * 獲取字符驗證碼
     *
     * @param imageVerificationDto 用戶信息
     * @return 字符驗證碼
     * @throws ServiceException 獲取字符驗證碼異常
     */
    private ImageVerificationVo selectCharVerificationCode(ImageVerificationDto imageVerificationDto) throws ServiceException {

        byte[] bytes = null;
        String text = "";
        BufferedImage bufferedImage = null;
        ImageVerificationVo imageVerificationVo = null;

        try {

            imageVerificationVo = new ImageVerificationVo();
            //  生成字符驗證碼文本
            text = captchaProducer.createText();
            //  生成字符驗證碼圖片
            bufferedImage = captchaProducer.createImage(text);
            getRequest().getSession().setAttribute("imageVerificationVo", imageVerificationVo);
            //  在分布式應用中,可將session改為redis存儲
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
            bytes = byteArrayOutputStream.toByteArray();
            //  圖片base64加密
            imageVerificationVo.setCharImage(Base64Utils.encodeToString(bytes));
            imageVerificationVo.setType(imageVerificationDto.getType() == null ? "char" : imageVerificationDto.getType());

        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(ServiceExceptionCode.SELECT_VERIFICATION_CODE_ERROR);
        }
        return imageVerificationVo;

    }

預覽圖

QQ截圖20190821105231.png

kaptcha實現(xiàn)運算驗證碼

配置類

@Configuration
public class CaptchaConfig
{
@Bean(name = "captchaProducerMath")
    public DefaultKaptcha getKaptchaBeanMath()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有邊框 默認為true 我們可以自己設置yes蒂破,no
        properties.setProperty("kaptcha.border", "no");
        // 邊框顏色 默認為Color.BLACK
        properties.setProperty("kaptcha.border.color", "55,160,204");
        // 驗證碼文本字符顏色 默認為Color.BLACK
        properties.setProperty("kaptcha.textproducer.font.color", "blue");
        // 背景漸變色馏谨,開始顏色
        properties.setProperty("kaptcha.background.clear.from", "234,172,236");
        // 背景漸變色,結(jié)束顏色
        properties.setProperty("kaptcha.background.clear.to", "234,144,115");
        // 驗證碼圖片寬度 默認為200
        properties.setProperty("kaptcha.image.width", "170");
        // 驗證碼圖片高度 默認為50
        properties.setProperty("kaptcha.image.height", "60");
        // 驗證碼文本字符大小 默認為40
        properties.setProperty("kaptcha.textproducer.font.size", "35");
        // KAPTCHA_SESSION_KEY
        properties.setProperty("kaptcha.session.key", "kaptchaMathCode");
// --------------驗證碼文本生成器,這里需要設置成自己項目的包名----------------------
        properties.setProperty("kaptcha.textproducer.impl", "com.selfimpr.captcha.config.KaptchaMathTextCreator");
        // 驗證碼文本字符間距 默認為2
        properties.setProperty("kaptcha.textproducer.char.space", "3");
        // 驗證碼文本字符長度 默認為9
        properties.setProperty("kaptcha.textproducer.char.length", "9");
        // 驗證碼文本字體樣式 默認為new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");
        // 驗證碼噪點顏色 默認為Color.BLACK
        properties.setProperty("kaptcha.noise.color", "243,79,67");
        // 干擾實現(xiàn)類
//        properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
        // 圖片樣式 水紋com.google.code.kaptcha.impl.WaterRipple 魚眼com.google.code.kaptcha.impl.FishEyeGimpy 陰影com.google.code.kaptcha.impl.ShadowGimpy
//        properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

注意附迷。這里注冊了自定義驗證碼生成器

image.png

自定義運算器惧互,同AWT生成運算驗證碼的運算方法沒有區(qū)別。

package com.selfimpr.captcha.config;


import com.google.code.kaptcha.text.impl.DefaultTextCreator;

import java.util.Random;

/**
 * @Description: 運算驗證碼
 * -------------------
 * @Author: YangXingfu
 * @Date: 2019/07/12 09:11
 */

public class KaptchaMathTextCreator extends DefaultTextCreator {

    StringBuilder result = new StringBuilder();


    @Override
    public String getText() {
        Random random = new Random(System.currentTimeMillis());
        int x = random.nextInt(51);
        int y = random.nextInt(51);
        int operationalRules = random.nextInt(4);

        switch (operationalRules) {
            case 0 : add(x, y); break;
            case 1 : subtract(x, y); break;
            case 2 : multiply(x, y); break;
            case 3 : divide(x, y); break;
        }
        return result.toString();
    }
    
    private void add(int x, int y) {
        result.append(x);
        result.append(" + ");
        result.append(y);
        result.append(" = ?@");
        result.append(x + y);
    }

    private void subtract(int x, int y) {
        int max = Math.max(x, y);
        int min = Math.min(x, y);
        result.append(max);
        result.append(" - ");
        result.append(min);
        result.append(" = ?@");
        result.append(max - min);
    }

    private void multiply(int x, int y) {
        int value = x * y;
        result.append(x);
        result.append(value > 100 ? " + " : " * ");
        result.append(y);
        result.append(" = ?@");
        result.append(value > 100 ? x + y : x * y);
    }

    private void divide(int x, int y) {
        int max = Math.max(x, y);
        int min = Math.min(x, y);
        if (min == 0) {
            multiply(max, min);
        } else if(max % min == 0) {
            result.append(max);
            result.append(" / ");
            result.append(min);
            result.append(" = ?@");
            result.append(max / min);
        } else {
            result.append(max);
            result.append(" % ");
            result.append(min);
            result.append(" = ?@");
            result.append(max % min);
        }
    }

}

生成運算驗證碼

**
     * 獲取運算驗證碼
     *
     * @param imageVerificationDto 用戶信息
     * @return 運算驗證嗎
     * @throws ServiceException 查詢運算驗證碼異常
     */
    private ImageVerificationVo selectOperationVerificationCode(ImageVerificationDto imageVerificationDto) throws ServiceException {

        byte[] bytes = null;
        String text = "";
        BufferedImage bufferedImage = null;
        ImageVerificationVo imageVerificationVo = null;

        try {

            imageVerificationVo = new ImageVerificationVo();
            imageVerificationVo.setType(imageVerificationDto.getType());
            //  生成運算驗證碼文本
            text = captchaProducerMath.createText();
            String value = text.substring(0, text.lastIndexOf("@"));
            //  生成運算驗證碼圖片
            bufferedImage = captchaProducerMath.createImage(value);
            //  驗證碼存入redis
            getRequest().getSession().setAttribute("imageVerificationVo", imageVerificationVo);
            //  在分布式應用中喇伯,可將session改為redis存儲
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
            bytes = byteArrayOutputStream.toByteArray();
            //  圖片base64加密
            imageVerificationVo.setOperationImage(Base64Utils.encodeToString(bytes));
            imageVerificationVo.setType(imageVerificationDto.getType());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(ServiceExceptionCode.SELECT_VERIFICATION_CODE_ERROR);
        }
        return imageVerificationVo;

    }
image.png

后話

這里的驗證碼樣式喊儡、字體等都有點丑,原諒作者的藝術水平太高稻据,大大們可自行調(diào)整艾猜。kapcha驗證碼與手動編寫的驗證碼可以明顯看出kaptcha驗證碼的優(yōu)勢,推薦大家使用kaptcha來做驗證碼捻悯。
有了這些驗證碼為什么會有新的驗證碼匆赃?值得大家思考的一個問題。

項目地址:https://gitee.com/gester/captcha.git

如果這篇文章有幫到您今缚,可以給個star炸庞,謝謝大大。

同時荚斯,推薦一波當下流行的滑動驗證碼,驗證碼實現(xiàn)和京東的滑動驗證碼沒有多大區(qū)別查牌。下面給個傳送門事期,給個預覽圖哈。
滑動驗證碼原理與實現(xiàn)文章地址:http://www.reibang.com/p/6ff29737209f

1.png

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纸颜,一起剝皮案震驚了整個濱河市兽泣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胁孙,老刑警劉巖唠倦,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異涮较,居然都是意外死亡稠鼻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門狂票,熙熙樓的掌柜王于貴愁眉苦臉地迎上來候齿,“玉大人,你說我怎么就攤上這事』哦ⅲ” “怎么了周霉?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長亚皂。 經(jīng)常有香客問我俱箱,道長,這世上最難降的妖魔是什么灭必? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任狞谱,我火速辦了婚禮,結(jié)果婚禮上厂财,老公的妹妹穿的比我還像新娘芋簿。我一直安慰自己,他們只是感情好璃饱,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布与斤。 她就那樣靜靜地躺著,像睡著了一般荚恶。 火紅的嫁衣襯著肌膚如雪撩穿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天谒撼,我揣著相機與錄音食寡,去河邊找鬼。 笑死廓潜,一個胖子當著我的面吹牛抵皱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辩蛋,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼呻畸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悼院?” 一聲冷哼從身側(cè)響起伤为,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎据途,沒想到半個月后绞愚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡颖医,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年位衩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片便脊。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚂四,死狀恐怖光戈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遂赠,我是刑警寧澤久妆,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站跷睦,受9級特大地震影響筷弦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抑诸,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一烂琴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜕乡,春花似錦奸绷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辛块,卻和暖如春畔派,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背润绵。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工线椰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尘盼。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓憨愉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卿捎。 傳聞我的和親對象是個殘疾皇子莱衩,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 前言: 關于kaptcha簡介以及spring整合kaptcha以及在Linux上驗證碼顯示亂碼問題,我在另一篇文...
    貪挽懶月閱讀 30,311評論 16 91
  • 1.import static是Java 5增加的功能,就是將Import類中的靜態(tài)方法娇澎,可以作為本類的靜態(tài)方法來...
    XLsn0w閱讀 1,216評論 0 2
  • 面向?qū)ο笾饕槍γ嫦蜻^程。 面向過程的基本單元是函數(shù)睹晒。 什么是對象:EVERYTHING IS OBJECT(萬物...
    sinpi閱讀 1,046評論 0 4
  • 0x00 簡介驗證碼作為一種輔助安全手段在Web安全中有著特殊的地位趟庄,驗證碼安全和web應用中的眾多漏洞相比似乎微...
    windgod閱讀 2,266評論 0 19
  • 成長是痛苦的,最近因為創(chuàng)業(yè)總是失眠伪很,每天被各種事情所困擾戚啥,日更沒有堅持,早起看書锉试,健身也都沒有堅持猫十,意識到自己的不...
    suan木子說閱讀 283評論 1 0