spring项目结构设计-验证码工具类
2020-05-13 本文已影响0人
jinelei
注意:这里是依赖awt的
object VerifyCodeUtils {
//使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
const val VERIFY_CODES = "0123456789"
private val random: Random = Random()
/**
* 使用指定源生成验证码
*
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
/**
* 使用系统默认字符源生成验证码
*
* @param verifySize 验证码长度
* @return
*/
@JvmOverloads
fun generateVerifyCode(verifySize: Int, sourceCode: String? = VERIFY_CODES): String {
var sources = sourceCode
if (sources == null || sources.length == 0) {
sources = VERIFY_CODES
}
val codesLen = sources.length
val rand = Random(System.currentTimeMillis())
val verifyCode = StringBuilder(verifySize)
for (i in 0 until verifySize) {
verifyCode.append(sources[rand.nextInt(codesLen - 1)])
}
return verifyCode.toString()
}
/**
* 生成随机验证码文件,并返回验证码值
*
* @param w
* @param h
* @param outputFile
* @param verifySize
* @return
* @throws IOException
*/
@Throws(IOException::class)
fun outputVerifyImage(w: Int, h: Int, outputFile: File?, verifySize: Int): String {
val verifyCode = generateVerifyCode(verifySize)
outputImage(w, h, outputFile, verifyCode)
return verifyCode
}
/**
* 输出随机验证码图片流,并返回验证码值
*
* @param w
* @param h
* @param os
* @param verifySize
* @return
* @throws IOException
*/
@Throws(IOException::class)
fun outputVerifyImage(w: Int, h: Int, os: OutputStream?, verifySize: Int): String {
val verifyCode = generateVerifyCode(verifySize)
outputImage(w, h, os, verifyCode)
return verifyCode
}
/**
* 生成指定验证码图像文件
*
* @param w
* @param h
* @param outputFile
* @param code
* @throws IOException
*/
@Throws(IOException::class)
fun outputImage(w: Int, h: Int, outputFile: File?, code: String?) {
if (outputFile == null) {
return
}
val dir: File = outputFile.getParentFile()
if (!dir.exists()) {
dir.mkdirs()
}
try {
outputFile.createNewFile()
val fos = FileOutputStream(outputFile)
outputImage(w, h, fos, code!!)
fos.close()
} catch (e: IOException) {
throw e
}
}
/**
* 输出指定验证码图片流
*
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
@Throws(IOException::class)
fun outputImage(w: Int, h: Int, os: OutputStream?, code: String) {
val verifySize = code.length
val image = BufferedImage(w, h, BufferedImage.TYPE_INT_RGB)
val rand = Random()
val g2 = image.createGraphics()
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
val colors: Array<Color?> = arrayOfNulls<Color>(5)
val colorSpaces: Array<Color> = arrayOf<Color>(Color.WHITE, Color.CYAN,
Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.YELLOW)
val fractions = FloatArray(colors.size)
for (i in colors.indices) {
colors[i] = colorSpaces[rand.nextInt(colorSpaces.size)]
fractions[i] = rand.nextFloat()
}
Arrays.sort(fractions)
g2.color = Color.GRAY // 设置边框色
g2.fillRect(0, 0, w, h)
val c: Color = getRandColor(200, 250)
g2.color = c // 设置背景色
g2.fillRect(0, 2, w, h - 4)
//绘制干扰线
val random = Random()
g2.color = getRandColor(160, 200) // 设置线条的颜色
for (i in 0..19) {
val x: Int = random.nextInt(w - 1)
val y: Int = random.nextInt(h - 1)
val xl: Int = random.nextInt(6) + 1
val yl: Int = random.nextInt(12) + 1
g2.drawLine(x, y, x + xl + 40, y + yl + 20)
}
// 添加噪点
val yawpRate = 0.05f // 噪声率
val area = (yawpRate * w * h).toInt()
for (i in 0 until area) {
val x: Int = random.nextInt(w)
val y: Int = random.nextInt(h)
val rgb = randomIntColor
image.setRGB(x, y, rgb)
}
shear(g2, w, h, c) // 使图片扭曲
g2.color = getRandColor(100, 160)
val fontSize = h - 4
val font = Font("Algerian", Font.ITALIC, fontSize)
g2.font = font
val chars = code.toCharArray()
for (i in 0 until verifySize) {
val affine = AffineTransform()
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * if (rand.nextBoolean()) 1 else -1, w / verifySize * i + fontSize / 2.toDouble(), h / 2.toDouble())
g2.transform = affine
g2.drawChars(chars, i, 1, (w - 10) / verifySize * i + 5, h / 2 + fontSize / 2 - 10)
}
g2.dispose()
ImageIO.write(image, "jpg", os)
}
private fun getRandColor(frontColor: Int, backgroundColor: Int): Color {
var fc = frontColor
var bc = backgroundColor
if (fc > 255) fc = 255
if (bc > 255) bc = 255
val r: Int = fc + random.nextInt(bc - fc)
val g: Int = fc + random.nextInt(bc - fc)
val b: Int = fc + random.nextInt(bc - fc)
return Color(r, g, b)
}
private val randomIntColor: Int
get() {
val rgb = randomRgb
var color = 0
for (c in rgb) {
color = color shl 8
color = color or c
}
return color
}
private val randomRgb: IntArray
get() {
val rgb = IntArray(3)
for (i in 0..2) {
rgb[i] = random.nextInt(255)
}
return rgb
}
private fun shear(g: Graphics, w1: Int, h1: Int, color: Color) {
shearX(g, w1, h1, color)
shearY(g, w1, h1, color)
}
private fun shearX(g: Graphics, w1: Int, h1: Int, color: Color) {
val period: Int = random.nextInt(2)
val borderGap = true
val frames = 1
val phase: Int = random.nextInt(2)
for (i in 0 until h1) {
val d = ((period shr 1).toDouble()
* Math.sin(i.toDouble() / period.toDouble()
+ 6.2831853071795862 * phase.toDouble()
/ frames.toDouble()))
g.copyArea(0, i, w1, 1, d.toInt(), 0)
if (borderGap) {
g.setColor(color)
g.drawLine(d.toInt(), i, 0, i)
g.drawLine(d.toInt() + w1, i, w1, i)
}
}
}
private fun shearY(g: Graphics, w1: Int, h1: Int, color: Color) {
val period: Int = random.nextInt(40) + 10 // 50;
val borderGap = true
val frames = 20
val phase = 7
for (i in 0 until w1) {
val d = ((period shr 1).toDouble()
* Math.sin(i.toDouble() / period.toDouble()
+ 6.2831853071795862 * phase.toDouble()
/ frames.toDouble()))
g.copyArea(i, 0, 1, h1, 0, d.toInt())
if (borderGap) {
g.setColor(color)
g.drawLine(i, d.toInt(), i, 0)
g.drawLine(i, d.toInt() + h1, i, h1)
}
}
}
}