1. 程式人生 > 其它 >java生成圖形驗證碼(算數運算圖形驗證碼 + 隨機字元圖形驗證碼)

java生成圖形驗證碼(算數運算圖形驗證碼 + 隨機字元圖形驗證碼)

技術標籤:javarandomjava

平凡也就兩個字: 懶和惰;
成功也就兩個字: 苦和勤;
優秀也就兩個字: 你和我。
跟著我從0學習JAVA、spring全家桶和linux運維等知識,帶你從懵懂少年走向人生巔峰,迎娶白富美!
關注微信公眾號【IT特靠譜】,每天都會分享技術心得~

生成圖形驗證碼(算數運算圖形驗證碼 + 隨機字元圖形驗證碼)

1 場景

在使用者登入、忘記密碼、使用者註冊、修改使用者資訊....等場景需要對使用者進行圖形化驗證。防止別有用心的人或機器通過介面來進行攻擊或惡意操作。

本示例講解通過java生成兩種圖形驗證碼:算數運算的圖形驗證碼和定長隨機字元圖形驗證碼!

2 編寫程式碼

2.1 建立生成指定長度的隨機字串工具類

建立生成指定長度的隨機字串工具類:RandomCodeUtil.java,該工具類在之前的部落格中講到過。

import java.util.Random;

/**
 * 生成指定長度的隨機字串
 */
public class RandomCodeUtil {

  /**
   * 生成指定長度的隨機字串(不包含數字0,和字母l、o和i)
   *
   * @param capacity 驗證碼長度
   */
  public static String genCode(Integer capacity) {
    //隨機字符集(不包含數字0和字母o、i和l)
    String str = "abcdefghjkmnpqrstuvwxyz123456789";
    Random rand = new Random();
    StringBuilder a = new StringBuilder();
    for (int i = 0; i < capacity; i++) {
      char c = str.charAt(rand.nextInt(str.length()));
      a.append(c);
    }
    return a.toString();
  }

  public static void main(String[] args) {
    //生產6位長度的隨機驗證碼
    System.out.println(RandomCodeUtil.genCode(6));
  }
}

2.2 建立圖形驗證碼工具類

建立圖形驗證碼工具類:ImgCodeUtil.java

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;

/**
 * 生成圖形驗證碼工具類
 */
public class ImgCodeUtil {

  /**
   * 圖片的寬度
   */
  private Integer width = 120;

  /**
   * 圖片的高度
   */
  private Integer height = 40;

  /**
   * 驗證碼干擾線條數
   */
  private Integer lineCount = 8;

  /**
   * 驗證碼code
   */
  private String validateCode = null;

  /**
   * 驗證碼圖片Buffer
   */
  private BufferedImage buffImg = null;

  /**
   * 構造方法
   */
  public ImgCodeUtil(String validateCode) {
    this.validateCode = validateCode;
    this.createCode();
  }

  /**
   * 構造方法
   */
  public ImgCodeUtil(String validateCode, int width, int height) {
    this.width = width;
    this.height = height;
    this.validateCode = validateCode;
    this.createCode();
  }

  /**
   * 生成驗證碼圖片
   */
  private void createCode() {
    int x = 0;
    int fontHeight;
    int codeY = 0;
    int red = 0;
    int green = 0;
    int blue = 0;
    int codeCount = validateCode.length();
    //每個字元的寬度
    x = width / codeCount;
    //字型的高度
    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);

    //圖片劃線
    for (int i = 0; i < lineCount; i++) {
      int xs = random.nextInt(width / 2);
      int ys = random.nextInt(height);
      int xe = random.nextInt(width / 2) + width / 2;
      int ye = random.nextInt(height);
      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);
    }

    Font font = new Font("Arial", Font.BOLD, fontHeight);
    g.setFont(font);
    // 將驗證碼寫入圖片
    for (int i = 0; i < codeCount; i++) {
      red = random.nextInt(255);
      green = random.nextInt(255);
      blue = random.nextInt(255);
      g.setColor(new Color(red, green, blue));
      g.drawString(String.valueOf(validateCode.charAt(i)), i * x, codeY);
    }
  }

  /**
   * 輸出圖片到指定路徑
   */
  public void write(String path) throws IOException {
    OutputStream outputStream = new FileOutputStream(path);
    this.write(outputStream);
  }

  /**
   * 將圖片輸出到輸出流中
   */
  public void write(OutputStream outputStream) throws IOException {
    ImageIO.write(buffImg, "png", outputStream);
    outputStream.close();
  }

  public BufferedImage getBuffImg() {
    return buffImg;
  }
}

2.3 建立圖形驗證碼介面類

建立圖形驗證碼介面類:ValidateCodeService.java

import com.xxx.alltest.dto.CheckCode;
import com.xxx.alltest.entity.ValidateCode;

/**
 * 圖形驗證碼介面類
 */
public interface ValidateCodeService {

  /**
   * 生成算數運算圖形驗證碼
   */
  ValidateCode generateMathImgCode(Integer width, Integer height);

  /**
   * 生成隨機字串圖形驗證碼
   */
  ValidateCode generateRandomImgCode(Integer width, Integer height);

  /**
   * 校驗圖形驗證碼值
   */
  String checkValidateCode(CheckCode checkCode);
}

2.4 建立圖形驗證碼介面實現類

圖形驗證碼介面實現類:ValidateCodeServiceImpl.java

import com.xxx.alltest.dto.CheckCode;
import com.xxx.alltest.entity.ValidateCode;
import com.xxx.alltest.service.ValidateCodeService;
import com.xxx.alltest.utils.ImgCodeUtil;
import com.xxx.alltest.utils.RandomCodeUtil;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;
import javax.imageio.ImageIO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;

/**
 * 圖形驗證碼介面實現類
 */
@Slf4j
@Service
public class ValidateCodeServiceImpl implements ValidateCodeService {

  /**
   * 驗證碼過期時間:5分鐘
   */
  private static final Long EXPIRE_TIME = 5 * 60 * 1000L;

  /**
   * 生成算數運算圖形驗證碼
   */
  @Override
  public ValidateCode generateMathImgCode(Integer width, Integer height) {
    Integer firstNum = RandomUtils.nextInt() % 10 + 1;
    Integer secondNum = RandomUtils.nextInt() % 10 + 1;
    Integer validateCode = firstNum + secondNum;
    ImgCodeUtil imgCodeUtil = new ImgCodeUtil(firstNum + "+" + secondNum + "=?", width, height);
    BufferedImage buffImg = imgCodeUtil.getBuffImg();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

    String base64ImgCode = null;
    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    try {
      ImageIO.write(buffImg, "png", byteArrayOutputStream);
      byte[] bytes = byteArrayOutputStream.toByteArray();
      base64ImgCode = Base64Utils.encodeToString(bytes);
      //將生成的驗證碼快取起來
//            redisTemplate.set(String.join(":", "mathImgCode", uuid), validateCode.toString(), EXPIRE_TIME);
    } catch (IOException var10) {
      log.error("生成算數運算圖形驗證碼失敗");
    }
    return ValidateCode.builder()
        .base64ImgCode(base64ImgCode)
        .uuid(uuid)
        .build();
  }

  /**
   * 生成隨機字串圖形驗證碼
   */
  @Override
  public ValidateCode generateRandomImgCode(Integer width, Integer height) {
    String validateCode = RandomCodeUtil.genCode(4);
    ImgCodeUtil imgCodeUtil = new ImgCodeUtil(validateCode, width, height);
    BufferedImage buffImg = imgCodeUtil.getBuffImg();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

    String base64ImgCode = null;
    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    try {
      ImageIO.write(buffImg, "png", byteArrayOutputStream);
      byte[] bytes = byteArrayOutputStream.toByteArray();
      base64ImgCode = Base64Utils.encodeToString(bytes);
      //將生成的驗證碼快取起來
//            redisTemplate.set(String.join(":", "randomImgCode", uuid), validateCode, EXPIRE_TIME);
    } catch (IOException var10) {
      log.error("生成隨機字串圖形驗證碼失敗");
    }
    return ValidateCode.builder()
        .base64ImgCode(base64ImgCode)
        .uuid(uuid)
        .build();
  }

  /**
   * 校驗圖形驗證碼值
   */
  @Override
  public String checkValidateCode(CheckCode checkCode) {
    String redisCode = null;
//        String redisCode = redisTemplate.get(String.join(":", "randomImgCode", checkCode.getUuid()));
    if (StringUtils.isEmpty(redisCode)) {
      return "驗證碼已過期";
    }
    if (!Objects.equals(checkCode.getValidateCode(), redisCode)) {
      return "驗證碼錯誤";
    }
    return null;
  }
}

2.5 建立驗證碼相關api介面類

建立驗證碼相關api介面類:ValidateCodeController.java

import com.xxx.alltest.all.oss.common.Result;
import com.xxx.alltest.dto.CheckCode;
import com.xxx.alltest.entity.ValidateCode;
import com.xxx.alltest.service.ValidateCodeService;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 驗證碼相關api介面
 */
@RestController
@RequestMapping("/validate")
public class ValidateCodeController {

  @Autowired
  private ValidateCodeService validateCodeService;

  /**
   * 生成圖形驗證碼
   *
   * @param type 0-普通字元圖形驗證碼(如:1a4h)  1-算數圖形驗證碼(1+8=?)
   */
  @GetMapping("generate")
  public Result<ValidateCode> generate(@RequestParam(value = "type", defaultValue = "0") String type,
      @RequestParam(value = "width", defaultValue = "100") Integer width,
      @RequestParam(value = "height", defaultValue = "40") Integer height) {
    ValidateCode validateCode = null;
    if (Objects.equals("0", type)) {
      validateCode = validateCodeService.generateRandomImgCode(width, height);
    } else {
      validateCode = validateCodeService.generateMathImgCode(width, height);
    }

    if (StringUtils.isEmpty(validateCode.getBase64ImgCode())) {
      return Result.failed("生成圖形驗證碼失敗");
    } else {
      return Result.ok(validateCode);
    }
  }

  /**
   * 校驗圖形驗證碼
   */
  @PostMapping("check")
  public Result check(@RequestBody CheckCode checkCode) {
    String msg = validateCodeService.checkValidateCode(checkCode);
    if (!StringUtils.isEmpty(msg)) {
      return Result.failed(msg);
    }
    return Result.ok();
  }
}

如果你有疑問或需要技術支援,關注公眾號聯絡我吧~