搭建SpringBoot+dubbo+zookeeper+maven框架(四)


 今天我們完成框架的thymeleaf模板顯示頁面功能,頁面的用戶登陸,密碼的AES加密解密,輸錯3次進行驗證碼驗證功能,東西可能比較多,這個是我這兩天在網上結合各種資源整合出來的,基本功能都已經實現,項目代碼我會附在文章的最后面。

 

1.thymeleaf模板顯示頁面功能 

簡單說, Thymeleaf 是一個跟 Velocity、FreeMarker 類似的模板引擎,它可以完全替代 JSP 。相較與其他的模板引擎,它有如下三個極吸引人的特點:
 
a、Thymeleaf 在有網絡和無網絡的環境下皆可運行,即它可以讓美工在瀏覽器查看頁面的靜態效果,也可以讓程序員在服務器查看帶數據的動態頁面效果。這是由於它支持 html 原型,然后在 html 標簽里增加額外的屬性來達到模板+數據的展示方式。瀏覽器解釋 html 時會忽略未定義的標簽屬性,所以 thymeleaf 的模板可以靜態地運行;當有數據返回到頁面時,Thymeleaf 標簽會動態地替換掉靜態內容,使頁面動態顯示。
 
b、Thymeleaf 開箱即用的特性。它提供標准和spring標准兩種方言,可以直接套用模板實現JSTL、 OGNL表達式效果,避免每天套模板、該jstl、改標簽的困擾。同時開發人員也可以擴展和創建自定義的方言。
 
c、Thymeleaf 提供spring標准方言和一個與 SpringMVC 完美集成的可選模塊,可以快速的實現表單綁定、屬性編輯器、國際化等功能。
 
下面在原有的項目框架中整合thymeleaf:
首先在pom.xml中添加thymeleaf的依賴
<dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring4</artifactId>
            <version>3.0.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

在customer模塊的resources下創建static、templates文件夾,如下:

 

在static下放置一些頁面樣式的js和css,在templates文件夾下放置html頁面,此時在resources下的application.properties配置文件中配置thymeleaf,

#thymelea模板配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
#熱部署文件,頁面不產生緩存,及時更新
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

此時thymeleaf模板就配置完成了。

 

2.頁面的用戶登陸,AES加密解密:

關於AES的加密解密,我的實現思路是:首先用戶在瀏覽器中輸入網址跳轉到登錄頁面,此時在頁面中已經保存了從后台傳過來的key,該key值是后台隨機生成的,后台session中保存key值,前台頁面的隱藏框中也要保存key值,用於前端頁面的密碼加密以及后端的密碼解密,頁面刷新或用戶名、密碼輸入錯誤時,都會重新生成新的key值來替換原有保存的key。

首先在pom.xml中添加依賴:

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>

用AES加密解密

a.前端加密用到的js有:aes.js和mode-ecb-min.js,就為了下載這兩個js花了我30個積分呢,[/哭],可以在static文件夾下創建一個aes文件夾,用於放置這兩個js。js下載地址:https://download.csdn.net/download/weixin_38340967/10677798
在templates下創建login.html,代碼如下:
<!DOCTYPE html>
<!--<html xmlns:th="http://www.thymeleaf.org" >-->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">

<head>
    <meta charset="UTF-8">
    <title>welcome</title>
    <script type="text/javascript" src="../jquery/jquery-1.11.1.min.js"></script>
    <script type="text/javascript" src="../jquery/jquery.easyui.min.js"></script>
    <script type="text/javascript" src="../aes/aes.js"></script>
    <script type="text/javascript" src="../aes/mode-ecb-min.js"></script>
    <!--<script th:src="@{jquery/jquery-1.11.1.min.js}"></script>-->
    <!--<script th:src="@{jquery/jquery-1.11.1.min.js}"></script>-->
    <!--<script th:src="@{jquery/jquery-1.11.1.min.js}"></script>-->
    <!--<script th:src="@{jquery/jquery-1.11.1.min.js}"></script>-->
</head>
<body>
<input type="hidden" id="KEY" th:value="${model.loginToken}" />
<form action="signIn" method="post" id="loginForm">
    <div class="form-group has-feedback">
        <input type="text" class="form-control" placeholder="Email" name="username"
               onkeydown="javascript:if(event.keyCode==13) $('#password').focus();">
        <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
    </div>
    <div class="form-group has-feedback">
        <input type="password" class="form-control" id="password"
               onkeydown="javascript:if(event.keyCode==13) login();" >
        <span class="glyphicon glyphicon-lock form-control-feedback"></span>
    </div>
    [[${session.SESSION_LOGIN_FAILURE_COUNT}]]
    <div class="form-group has-feedback" th:if="${session.SESSION_LOGIN_FAILURE_COUNT}<=0">
        <input name="checkCode" onkeydown="javascript:if(event.keyCode==13)  login();" type="text" id="checkCode" maxlength="4" style="width:120px;"/>
        <img src="getValidateCode" id="CreateCheckCode" align="middle" title="點擊刷新驗證碼" onclick="getCode()"  style="cursor: pointer;">
        <span id="checkCodeSpan" style="color: red;"></span>
    </div>
<div class="row">
    <div class="col-xs-8">
        <div class="checkbox icheck">
            <label>
                <input type="checkbox" name="remember" checked="checked"  >記住密碼
            </label>
        </div>
    </div>
    <!-- /.col -->
    <div class="col-xs-4">
        <button type="button" onclick="login()"  class="btn btn-primary btn-block btn-flat">登錄</button>
    </div>
    <!-- /.col -->
</div>
</form>
<script>
    function login(){
        $('#loginForm').form('submit',{
            onSubmit: function(param){
                var username = $('#loginForm input[name=username]').val();
                if($.trim(username)==''){
                    alert('賬號不能為空!')
                    $('#loginForm input[name=username]').focus();
                    return false;
                }
                var p = $('#loginForm #password').val();
                if($.trim(p)==''){
                    alert('密碼不能為空!')
                    $('#loginForm #password').focus();
                    return false;
                }
                var checkCodeInput = $('#loginForm #checkCode');
                if(checkCodeInput.length>0){//判斷元素是否存在
                    var checkCode = checkCodeInput.val();
                    if($.trim(checkCode)=='' || checkCode.length!=4 ){
                        alert('請輸入4位驗證碼!')
                        checkCodeInput.select();
                        checkCodeInput.focus();
                        return false;
                    }
                }
                var key = $('#KEY').val();
                // alert("key的值是:  "+key);
                key = CryptoJS.enc.Utf8.parse(key);
                // alert("加密后key的值是:  "+key);
                p = CryptoJS.enc.Utf8.parse($.trim(p));
                var encrypted = CryptoJS.AES.encrypt(p, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
                param.password = encrypted.toString();
            },
            success:function(data){
                var data = eval('(' + data + ')');
                if (data.success){
                    window.location.href = 'index';
                }else{
                    if(data.msg=='timeout'){//可能已經就登錄了,無需再次登錄
                        alert('登錄超時或已經登錄!');
                        window.location.href = '${request.contextPath}/';
                    }else if('用戶名或密碼錯誤!'==data.msg){//需要驗證碼了
                        alert('用戶名或密碼錯誤!');
                        window.location.href = 'login';
                    }else if('codeError'==data.msg){//驗證碼錯誤
                        getCode();
                        $('#checkCodeSpan').text('驗證碼錯誤');
                        $('#loginForm #checkCode').select();
                        $('#loginForm #checkCode').focus();
                    }else{
                        //登錄失敗,更新login_token
                        $('#KEY').val(data.data);
                        if($('#checkCodeSpan')){
                            $('#checkCodeSpan').text('');
                        }
                        alert(data.msg);
                    }
                }
            },

        }) ;
    }

    function getCode(){
        var img = document.getElementById("CreateCheckCode");
        img.src = "getValidateCode?nocache=" + new Date().getTime();
        // $("#CreateCheckCode").attr('src',"getValidateCode?nocache=" + new Date().getTime());
    }
</script>
</body>
</html>

這里有一個坑,就是在html頁面中引入js的時候路徑的問題,可以看到我在頁面中是這樣寫的:<script type="text/javascript" src="../jquery/jquery-1.11.1.min.js"></script>,但是你仔細看應該是<script type="text/javascript" src="../static/jquery/jquery-1.11.1.min.js"></script>才對,為什么會少一個static呢,這是因為thymeleaf模板本身引入js時的路徑就是默認在static下的,要是加上static反而頁面會報js404錯誤,不信大家可以試試看。

var key = $('#KEY').val();
 // alert("key的值是:  "+key);
key = CryptoJS.enc.Utf8.parse(key); // alert("加密后key的值是: "+key); p = CryptoJS.enc.Utf8.parse($.trim(p)); var encrypted = CryptoJS.AES.encrypt(p, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7}); param.password = encrypted.toString();

這段代碼就是通過AES將用戶輸入的明文密碼和后台傳過來的key加密成密文,放到input框中提交到后台。

b.后台生成隨機的key值,並將前台傳過來的密文解密成明文密碼,

這里要在common模塊中寫幾個工具類:EncryptUtil用於密碼的加密解密,Helper用於記錄一些常量,RandomUtil用於隨機生成key值,Result用於向前台返回一個結果對象,樣式如下:

工具類代碼如下:

EncryptUtil:

package com.lj.common.util;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

import sun.misc.BASE64Decoder;

import java.security.SecureRandom;

/**
 * Created with IntelliJ IDEA.
 * User: gaopeng
 * Date: 2018/9/17 0017
 * Time: 17:30
 * Description:
 */
public class EncryptUtil {
    private static final String KEY = "abcdefgabcdefg12";
    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
    public static String base64Encode(byte[] bytes){
        return Base64.encodeBase64String(bytes);
    }
    public static byte[] base64Decode(String base64Code) throws Exception{
        return new BASE64Decoder().decodeBuffer(base64Code);
    }
    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));

        return cipher.doFinal(content.getBytes("utf-8"));
    }
    public static String aesEncrypt(String content, String encryptKey) throws Exception {
        return base64Encode(aesEncryptToBytes(content, encryptKey));
    }
    public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
        secureRandom.setSeed(decryptKey.getBytes());
        kgen.init(128,secureRandom);

        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
        byte[] decryptBytes = cipher.doFinal(encryptBytes);

        return new String(decryptBytes);
    }
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        return aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    }


    /**
     * 測試
     *
     */
    public static void main(String[] args) throws Exception {

        String content = "Test String么么噠";  //0gqIDaFNAAmwvv3tKsFOFf9P9m/6MWlmtB8SspgxqpWKYnELb/lXkyXm7P4sMf3e
        System.out.println("加密前:" + content);

        System.out.println("加密密鑰和解密密鑰:" + KEY);

        String encrypt = aesEncrypt(content, KEY);
        System.out.println(encrypt.length()+":加密后:" + encrypt);

        String decrypt = aesDecrypt(encrypt, KEY);
        System.out.println("解密后:" + decrypt);
    }
}

Helper:

package com.lj.common.util;

/**
 * Created with IntelliJ IDEA.
 * User: gaopeng
 * Date: 2018/9/17 0017
 * Time: 17:08
 * Description:
 */
public class Helper {
    public static final String SESSION_CHECKCODE = "SESSION_CHECKCODE";
    public static final String SESSION_LOGIN_TOKEN = "SESSION_LOGIN_TOKEN";
    public static final String SESSION_USER = "SESSION_USER";
    public static final String SESSION_LOGIN_FAILURE_COUNT = "SESSION_LOGIN_FAILURE_COUNT";
    public static final String logTypeSecurity = "logTypeSecurity";
    public static final Integer COUNT = 3;
}

RandomUtil:

package com.lj.common.util;

import java.util.Random;

/**
 * Created with IntelliJ IDEA.
 * User: gaopeng
 * Date: 2018/9/17 0017
 * Time: 17:22
 * Description:
 */
public class RandomUtil {
    public static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    public static final String LETTERCHAR = "abcdefghijkllmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    public static final String NUMBERCHAR = "0123456789";

    /**
     * 返回一個定長的隨機字符串(只包含大小寫字母、數字)
     *
     * @param length
     *            隨機字符串長度
     * @return 隨機字符串
     */
    public static String generateString(int length) {
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        return sb.toString();
    }

    /**
     * 返回一個定長的隨機純字母字符串(只包含大小寫字母)
     *
     * @param length
     *            隨機字符串長度
     * @return 隨機字符串
     */
    public static String generateMixString(int length) {
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(LETTERCHAR.charAt(random.nextInt(LETTERCHAR.length())));
        }
        return sb.toString();
    }

    /**
     * 返回一個定長的隨機純大寫字母字符串(只包含大小寫字母)
     *
     * @param length
     *            隨機字符串長度
     * @return 隨機字符串
     */
    public static String generateLowerString(int length) {
        return generateMixString(length).toLowerCase();
    }

    /**
     * 返回一個定長的隨機純小寫字母字符串(只包含大小寫字母)
     *
     * @param length
     *            隨機字符串長度
     * @return 隨機字符串
     */
    public static String generateUpperString(int length) {
        return generateMixString(length).toUpperCase();
    }

    /**
     * 生成一個定長的純0字符串
     *
     * @param length
     *            字符串長度
     * @return 純0字符串
     */
    public static String generateZeroString(int length) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            sb.append('0');
        }
        return sb.toString();
    }

    /**
     * 根據數字生成一個定長的字符串,長度不夠前面補0
     *
     * @param num
     *            數字
     * @param fixdlenth
     *            字符串長度
     * @return 定長的字符串
     */
    public static String toFixdLengthString(long num, int fixdlenth) {
        StringBuffer sb = new StringBuffer();
        String strNum = String.valueOf(num);
        if (fixdlenth - strNum.length() >= 0) {
            sb.append(generateZeroString(fixdlenth - strNum.length()));
        } else {
            throw new RuntimeException("將數字" + num + "轉化為長度為" + fixdlenth
                    + "的字符串發生異常!");
        }
        sb.append(strNum);
        return sb.toString();
    }

    /**
     * 每次生成的len位數都不相同
     *
     * @param param
     * @return 定長的數字
     */
    public static int getNotSimple(int[] param, int len) {
        Random rand = new Random();
        for (int i = param.length; i > 1; i--) {
            int index = rand.nextInt(i);
            int tmp = param[index];
            param[index] = param[i - 1];
            param[i - 1] = tmp;
        }
        int result = 0;
        for (int i = 0; i < len; i++) {
            result = result * 10 + param[i];
        }
        return result;
    }
}

Result:

package com.lj.common.util;

import java.util.Date;

/**
 * Created with IntelliJ IDEA.
 * User: gaopeng
 * Date: 2018/9/17 0017
 * Time: 18:26
 * Description:
 */
public class Result {
    private Boolean success;
    private String msg;
    private String key;

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Result(Boolean b, String s){
        this.success = b;
        this.msg = s;
    }

    public Result(Boolean b, String s, String k){
        this.success = b;
        this.msg = s;
        this.key = k;
    }
}

 




在customer模塊中的controller中攔截/login和/signIn路徑的代碼如下:

    @GetMapping("login")
    public ModelAndView login(HttpServletResponse response, HttpServletRequest request, Model model){
        //生成login_token

        HttpSession session = request.getSession();
        String key = RandomUtil.generateString(16);
        session.setAttribute(Helper.SESSION_LOGIN_TOKEN, key);//登錄令牌,用於密碼加密的key,16位長度
        if(session.getAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT) == null){
            session.setAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT, Helper.COUNT);//登錄剩余失敗次數
        }
        model.addAttribute("loginToken",key);
        System.out.println("傳到前台的key值為:"+ key);
        System.out.println("頁面跳轉到login.html");
//        return "login";
//        if(session.getAttribute(Helper.SESSION_USER) == null){
            return new ModelAndView("login","model",model);
//        }
//        else
//            return "redirect:/";
    }
    @PostMapping(value = "signIn")
    @ResponseBody
    public String signIn(String username,String password,boolean remember,String checkCode,HttpServletRequest request, HttpServletResponse response){
        System.out.println(username+","+password+","+remember+","+checkCode);
        HttpSession session = request.getSession();
        Object token = session.getAttribute(Helper.SESSION_LOGIN_TOKEN);//原始令牌

        if(token==null) return JSON.toJSONString(new Result(false,"timeout"));//登錄成功后token失效,則頁面失效,客戶端需要重定向到主界面
        Object countObj = session.getAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT);
        int count = countObj==null?3:Integer.parseInt(countObj.toString());
        System.out.println("剩余次數:"+count);
        //驗證碼邏輯
        if(count<=0){//需要驗證碼
            Object oldCode = session.getAttribute(Helper.SESSION_CHECKCODE);
            if(checkCode==null||oldCode==null){//該登錄界面沒有驗證碼字段,但是已經消耗掉了剩余次數,說明該頁面是過期頁面,需要重新登錄
                System.out.println("chaoshila");
                return JSON.toJSONString(new Result(false,"timeout"));//客戶端需要重定向到主界面
            }
            if(checkCode.trim().isEmpty()) return JSON.toJSONString(new Result(false,"請輸入驗證碼"));
            if(oldCode.toString().equalsIgnoreCase(checkCode)){
                //驗證通過,可信客戶端,給0次剩余次數
                count=0;
                session.setAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT,count);
            }else{
                return JSON.toJSONString(new Result(false,"codeError"));//驗證碼不正確,客戶端需要刷新驗證碼
            }
        }
        //解密
        try {
            password = EncryptUtil.aesDecrypt(password,token.toString());//解密后
            System.out.println("Decrypt:"+password);
        } catch (Exception e) {
            e.printStackTrace();
            return JSON.toJSONString(new Result(false,"timeout"));//客戶端需要重定向到主界面
        }
        //登錄校驗
        String loginKey = RandomUtil.generateString(16);//重新生成登錄令牌,任何登錄失敗的操作都需要更新登錄令牌
        User user =  null;
        System.out.println(user == null);
        if(user == null){
            session.setAttribute(Helper.SESSION_LOGIN_TOKEN,loginKey);
            session.setAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT,--count);//剩余次數-1
            System.out.println("剩余次數:" + session.getAttribute(Helper.SESSION_LOGIN_FAILURE_COUNT));
            //if(count<=0) return JSON.toJSONString(new Result(false,"checkCode",loginKey));//客戶端需要重定向到登錄界面將驗證碼顯示出來
            System.out.println("這里直接要返回了!!!");
            Result result = new Result(false,"用戶名或密碼錯誤!",loginKey);
            System.out.println("result對象的值是:" + result.getKey());
            System.out.println(JSON.toJSONString(result));
            return JSON.toJSONString(new Result(false,"用戶名或密碼錯誤!",loginKey));
        }else{
//            if(user.getUserid()!=ConfigInfo.admin_id && !user.getuStatus().equals(ConfigInfo.user_status_normal)) {
//                session.setAttribute(Helper.SESSION_LOGIN_TOKEN,key);
//                return JSON.toJSONString(new Result(false,"登錄失敗,該賬號已被禁止使用!",key));
//            }
            //登錄成功
            session.removeAttribute(Helper.SESSION_LOGIN_TOKEN);
//            loginUser = user;
            session.setAttribute(Helper.SESSION_USER,user);
//            sysEventService.insertEventLog(Helper.logTypeSecurity,username+" 登錄系統");
            return JSON.toJSONString(new Result(true,"登錄成功!"));
        }
    }

 

上面生成key以及解密的部分都有注解,應該能看懂的。

c.輸錯3次顯示驗證碼
這里要實現驗證碼功能,首先要在common中寫一個工具類,用於生成驗證碼,代碼如下:
package com.lj.common.util;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;
/**
 * Created with IntelliJ IDEA.
 * User: gaopeng
 * Date: 2018/9/17 0017
 * Time: 16:57
 * Description:
 */
public class ValidateCode {
    // 圖片的寬度。
    private int width = 160;
    // 圖片的高度。
    private int height = 28;
    // 驗證碼字符個數
    private int codeCount = 4;
    // 驗證碼干擾線數
    private int lineCount = 150;
    // 驗證碼
    private String code = null;
    // 驗證碼圖片Buffer
    private BufferedImage buffImg = null;

    private char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
            'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

    public ValidateCode() {
        this.createCode();
    }

    /**
     *
     * @param width
     *            圖片寬
     * @param height
     *            圖片高
     */
    public ValidateCode(int width, int height) {
        this.width = width;
        this.height = height;
        this.createCode();
    }

    /**
     *
     * @param width
     *            圖片寬
     * @param height
     *            圖片高
     * @param codeCount
     *            字符個數
     * @param lineCount
     *            干擾線條數
     */
    public ValidateCode(int width, int height, int codeCount, int lineCount) {
        this.width = width;
        this.height = height;
        this.codeCount = codeCount;
        this.lineCount = lineCount;
        this.createCode();
    }

    public void createCode() {
        int x = 0, fontHeight = 0, codeY = 0;
        int red = 0, green = 0, blue = 0;

        x = width / (codeCount + 2);// 每個字符的寬度
        fontHeight = height - 2;// 字體的高度
        codeY = height - 4;

        // 圖像buffer
        buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = buffImg.createGraphics();
        // 生成隨機數
        Random random = new Random();
        // 將圖像填充為白色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
        // 創建字體
        Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
        g.setFont(font);
        //干擾線
        for (int i = 0; i < lineCount; i++) {
            int xs = random.nextInt(width);
            int ys = random.nextInt(height);
            int xe = xs + random.nextInt(width / 8);
            int ye = ys + random.nextInt(height / 8);
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);
            g.setColor(new Color(red, green, blue));
            g.drawLine(xs, ys, xe, ye);
        }

        // randomCode記錄隨機產生的驗證碼
        StringBuffer randomCode = new StringBuffer();
        // 隨機產生codeCount個字符的驗證碼。
        for (int i = 0; i < codeCount; i++) {
            String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
            // 產生隨機的顏色值,讓輸出的每個字符的顏色值都將不同。
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);
            g.setColor(new Color(red, green, blue));
            g.drawString(strRand, (i + 1) * x, codeY);
            // 將產生的四個隨機數組合在一起。
            randomCode.append(strRand);
        }
        // 將四位數字的驗證碼保存到Session中。
        code = randomCode.toString();
    }

    public void write(String path) throws IOException {
        OutputStream sos = new FileOutputStream(path);
        this.write(sos);
    }

    public void write(OutputStream sos) throws IOException {
        ImageIO.write(buffImg, "png", sos);
        sos.close();
    }

    public BufferedImage getBuffImg() {
        return buffImg;
    }

    public String getCode() {
        return code;
    }
}

 

在customer模塊中的controller,編寫攔截/getValidateCode路徑的請求,用於生成驗證碼,代碼如下:
 @GetMapping("getValidateCode")
    public void getValidateCode(HttpServletRequest reqeust, HttpServletResponse response) throws IOException {
        response.setContentType("image/jpeg");
        // 禁止圖像緩存。
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        HttpSession session = reqeust.getSession();

        ValidateCode vCode = new ValidateCode(100, 28, 4, 100);
        session.setAttribute(Helper.SESSION_CHECKCODE, vCode.getCode());
        vCode.write(response.getOutputStream());
    }

驗證碼在3次輸入錯誤用戶名密碼后啟動的邏輯代碼在上面都已經貼出來了,這個3次是存儲在session中的,前台頁面要通過獲取session中的“可輸入錯誤剩余次數SESSION_LOGIN_FAILURE_COUNT”來判斷

至此,頁面的用戶登陸,密碼的AES加密解密,輸錯3次進行驗證碼驗證功能。演示效果如下:

第一次:

第二次:

第三次:

第三次以后的頁面就有驗證碼了:

下面是該項目的源碼下載地址:https://download.csdn.net/download/weixin_38340967/10677372

文章參考文獻:https://www.cnblogs.com/nicknailo/p/8947643.html

http://itfish.net/article/64414.html

 

 

 

 

 





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM