Skip to content

Commit

Permalink
add CaptchaUtil
Browse files Browse the repository at this point in the history
  • Loading branch information
LJWLgl committed May 24, 2020
1 parent c00bf71 commit 969be82
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 44 deletions.
75 changes: 65 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## 目录

[TOC]

## 概述
Java开发常用工具类总结,如果对你有用欢迎点个start,此外,如果你有兴趣和我一起维护该仓库,欢迎提PR或者issue,让我们为拥有一个更强大的工具库而一同努力。

本仓库是Java开发常用工具类的总结,如果对你有用欢迎点个start,此外,如果你有兴趣和我一起维护该仓库,欢迎提PR或者issue,让我们为拥有一个更强大的工具库而一同努力。

## 导入项目
```
Expand All @@ -10,7 +15,6 @@ Java开发常用工具类总结,如果对你有用欢迎点个start,此外
</dependency>
```
## 工具类介绍

### **FastJsonUtil(FastJson工具类)**
借助FastJson实现序列化和反序列,同时自己实现了Json节点增删改,以及Json关键字段脱敏
- **toJsonString(Object object)**, 序列化Json
Expand Down Expand Up @@ -74,6 +78,7 @@ Java开发常用工具类总结,如果对你有用欢迎点个start,此外
- **getLocalHostAddress()**,返回本机IP
- **getLocalHostName()**,返回主机名
- **getLocalInetAddress**,返回InetAddress

### **BigDecimalUtil(BigDecimal计算工具类)**
在和钱打交道的服务里,经常会用到BigDecimal类,下面提供一些他的计算方法
- **subtract(double x, double y)**
Expand All @@ -95,9 +100,49 @@ Java开发常用工具类总结,如果对你有用欢迎点个start,此外
各坐标系相互转换,如bd09,wgs84,gcj02
- **convertLatLonByCoordinate(String newCoordinateType, String originalCoordinateType, double lat, double lon)**,将原本坐标系的经纬度转换成新的坐标系的经纬度,支持wgs84转bd09,bd09T转gcj02d等

### **EncodeDecodeUtil(编码与解码工具类)**
- **encodeWithMD5(String str)**, 对字符串进行MD5加密
- **encodeWithSHA1(String str)**,对字符串进行SHA1加密
- **encodeWithSHA256(String str)**,对字符串进行SHA-256加密
- **encode(String algorithm, String str)**,通过指定算法对字符串加密
- **encodeBase64(String str)**,对字符串进行Base64编码
- **decodeBase64(String str)**,对字符串进行Base64解码
- **encodeUrl(String str)**,对URL编码
- **decodeUrl(String str)**,对URL解码


### **ProtobufUtil(提供Protobuf格式的序列化和反序列)**
- **<T> byte[] serialize(T obj)**,序列化对象
- **<T> byte[] serializeList(List<T> objList)**,序列化数组
- **<T> T unSerialize(byte[] data,Class<?> clazz)**,反序列化对象
- **<T> List<T> unSerializeList(byte[] data, Class<T> clazz)**,反序列化数组

### **DeepCopyUtil(深拷贝工具类)**
- **Object depthClone(Object srcObj)**,单个对象的深拷贝,通过序列化与反序列的方式实现,所以srcObj对应的需实现java.io.Serializable接口
- **<T> List<T> listDepthClone(List<T> list)**,多个对象的深拷贝,srcObj对应的需实现java.io.Serializable接口

### **GZIPUtil(通过Gzip算法压缩和解压)**
- **compress(String str)**,字符串压缩为GZIP字节数组
- **compress(String str, String encoding)**,字符串压缩为GZIP字节数组
- **uncompress(byte[] bytes)**,GZIP解压缩

### **CaptchaUtil(验证码工具类)**

- **String genCaptcha(int count)**,生成指定位数为count的随机验证码
- **BufferedImage genCaptchaImg(String captcha)**,为一个验证码生成一个图片

### **UrlParamsUtil(对URL参数处理的工具类)**

- **String join(Map<String, String> map, String separator)**,将Map转成String, 可以指定分隔符,通常用于拼接URL后面的参数
- **Map<String, String> split(String paramsPath, String separator)**,解析ulr参数为map
- **Map<String, String> split(String paramsPath)**,解析ulr参数为map,这里的separator参数为“=”
- **Map<String, String> build(String ... keyValues)**,将keyValues转成Map
- **add(Map<String, String> originMap, String ... keyValues)**,在原Map添加keyValues

### **EmailUtil(邮件发送工具类)**

邮件工具类是通过JavaEmail实现,企业级项目一般都会专门的服务去发送邮件,但如果自己的小Demo,用工具类发送Email也未尝不可。示例Demo如下,有兴趣的可以fork代码自己研究一下,代码有详情的注释。
```
```java
public class EmailUtilTest {
@Before
public void before() throws GeneralSecurityException {
Expand All @@ -112,21 +157,31 @@ public class EmailUtilTest {

}
```
### **ProtobufUtil(提供Protobuf格式的序列化和反序列)**
### GZIPUtil(提供Gzip)
- **compress(String str)**,字符串压缩为GZIP字节数组
- **compress(String str, String encoding)**,字符串压缩为GZIP字节数组
- **uncompress(byte[] bytes)**,GZIP解压缩

## 关于开源

本项目是开源项目,若有摘取本项目的代码,请注明出处!(码字不易,请遵重开源精神)


## Contributor

下面是笔主收集的一些对本仓库提过有价值的pr或者issue的朋友,人数较多,如果你也对本仓库提过不错的pr或者issue的话,你可以加我的微信与我联系。下面的排名不分先后
下面是笔者收集的一些对本仓库提过有价值的pr或者issue的朋友,如果你也对本仓库提过不错的pr或者issue的话,你可以加我的微信与我联系。另外,请提下面的排名不分先后

<a href="https://github.com/LJWLgl">
<img src="https://avatars1.githubusercontent.com/u/22522146?s=460&u=34378925405f18325ea493aa7df788410d6204e3&v=4" width="45px">
</a>
<a href="https://github.com/fansengithub">
<img src="https://avatars1.githubusercontent.com/u/16862948?s=400&v=4" width="45px">
</a>

**简单说明PR原则**

- 注释需要完备,应该对新增的每个方法标注方法说明,同时对传入参数和返回参数也要相应的说明
- 充分的Unit Test,保证每行代码和分支都要覆盖到
- 代码规范,请遵循[阿里巴巴Java开发手册](https://yq.aliyun.com/articles/69327)

## 更新日志
- 2020-05-22,新增LanguageUtil & 升级pom

- 2018年8月,first commit
- 2020年05月22日,新增LanguageUtil & 发布2.0.7版本
- 2020年05月24日,新增EncodeDecodeUtil、CaptchaUtil & 发布2.0.8版本(审核中)
123 changes: 123 additions & 0 deletions src/main/java/io/github/ljwlgl/util/CaptchaUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package io.github.ljwlgl.util;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.concurrent.ThreadLocalRandom;

/**
* @author zq_gan
* @since 2018/5/23
**/

public class CaptchaUtil {

static char[] chars = {'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'};

/**
* 生成一个位数为count的随机验证码
*
* @param count
* @return
*/
public static String genCaptcha(int count) {
StringBuilder captcha = new StringBuilder();

for (int i = 0; i < count; i++) {
char c = chars[ThreadLocalRandom.current().nextInt(chars.length)];//随机选取一个字母或数字
captcha.append(c);
}
return captcha.toString();
}

/**
* 为一个验证码生成一个图片
* <p>
* 特性:
* - 颜色随机
* - 上下位置随机
* - 左右位置随机,但字符之间不会重叠
* - 左右随机旋转一个角度
* - 避免字符出界
* - 随机颜色的小字符做背景干扰
* - 根据字符大小自动调整图片大小、自动计算干扰字符的个数
*
* @param captcha
* @return
* @author XuJijun
*/
public static BufferedImage genCaptchaImg(String captcha) {
ThreadLocalRandom r = ThreadLocalRandom.current();

int count = captcha.length();
int fontSize = 80; //code的字体大小
int fontMargin = fontSize / 4; //字符间隔
int width = (fontSize + fontMargin) * count + fontMargin; //图片长度
int height = (int) (fontSize * 1.2); //图片高度,根据字体大小自动调整;调整这个系数可以调整字体占图片的比例
int avgWidth = width / count; //字符平均占位宽度
int maxDegree = 26; //最大旋转度数

//背景颜色
Color bkColor = Color.WHITE;
//验证码的颜色
Color[] catchaColor = {Color.MAGENTA, Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN, Color.ORANGE, Color.PINK};

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();

//填充底色为灰白
g.setColor(bkColor);
g.fillRect(0, 0, width, height);

//画边框
g.setColor(Color.WHITE);
g.drawRect(0, 0, width - 1, height - 1);

//画干扰字母、数字
int dSize = fontSize / 3; //调整分母大小以调整干扰字符大小
Font font = new Font("Fixedsys", Font.PLAIN, dSize);
g.setFont(font);
int dNumber = width * height / dSize / dSize;//根据面积计算干扰字母的个数
for (int i = 0; i < dNumber; i++) {
char d_code = chars[r.nextInt(chars.length)];
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
g.drawString(String.valueOf(d_code), r.nextInt(width), r.nextInt(height));
}

//开始画验证码:

// 创建字体
font = new Font(Font.MONOSPACED, Font.ITALIC | Font.BOLD, fontSize);
// 设置字体
g.setFont(font);

for (int i = 0; i < count; i++) {
char c = captcha.charAt(i);
g.setColor(catchaColor[r.nextInt(catchaColor.length)]);//随机选取一种颜色

//随机旋转一个角度[-maxDegre, maxDegree]
int degree = r.nextInt(-maxDegree, maxDegree + 1);

//偏移系数,和旋转角度成反比,以避免字符在图片中越出边框
double offsetFactor = 1 - (Math.abs(degree) / (maxDegree + 1.0));//加上1,避免出现结果为0

g.rotate(degree * Math.PI / 180); //旋转一个角度
int x = (int) (fontMargin + r.nextInt(avgWidth - fontSize) * offsetFactor); //横向偏移的距离
int y = (int) (fontSize + r.nextInt(height - fontSize) * offsetFactor); //上下偏移的距离

g.drawString(String.valueOf(c), x, y); //x,y是字符的左下角,偏离原点的距离!!!

g.rotate(-degree * Math.PI / 180); //画完一个字符之后,旋转回原来的角度
g.translate(avgWidth, 0);//移动到下一个画画的原点
//System.out.println(c+": x="+x+" y="+y+" degree="+degree+" offset="+offsetFactor);

//X、Y坐标在合适的范围内随机,不旋转:
//g.drawString(String.valueOf(c), width/count*i+r.nextInt(width/count-fontSize), fontSize+r.nextInt(height-fontSize));
}

g.dispose();

return image;
}
}
121 changes: 121 additions & 0 deletions src/main/java/io/github/ljwlgl/util/EncodeDecodeUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package io.github.ljwlgl.util;

import org.apache.commons.lang3.StringUtils;

import java.security.MessageDigest;
import java.util.Base64;

/**
* @author zqgan
* @since 2019/4/28
**/

public class EncodeDecodeUtil {

private static final char[] HEX = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

private static final String DEFAULT_CHARSET = "utf-8";


/**
* 对字符串进行MD5加密
* @param str 待加密字符串
* @return 加密后的字符串
*/
public static String encodeWithMD5(String str) {
return encode("MD5", str);
}

/**
* 对字符串进行SHA1加密
* @param str 待加密字符串
* @return 加密后的字符串
*/
public static String encodeWithSHA1(String str) {
return encode("SHA1", str);
}

/**
* 对字符串进行SHA-256加密
* @param str 待加密字符串
* @return 加密后的字符串
*/
public static String encodeWithSHA256(String str) {
return encode("SHA-256", str);
}

/**
* 通过加密算法加密字符串
*/
public static String encode(String algorithm, String str) {
if (str == null) {
return null;
}
try {
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
messageDigest.update(str.getBytes());
return getFormattedText(messageDigest.digest());
} catch (Exception e) {
throw new RuntimeException(e);
}

}

public static String encodeBase64(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
try {
return Base64.getEncoder().encodeToString(str.getBytes(DEFAULT_CHARSET));
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static String decodeBase64(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
try {
byte[] bytes = Base64.getDecoder().decode(str);
return new String(bytes, DEFAULT_CHARSET);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static String decodeUrl(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
try {
return java.net.URLDecoder.decode(str, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static String encodeUrl(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
try {
return java.net.URLEncoder.encode(str, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
// 把密文转换成十六进制的字符串形式
for (int j = 0; j < len; j++) {
buf.append(HEX[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX[bytes[j] & 0x0f]);
}
return buf.toString();
}

}
Loading

0 comments on commit 969be82

Please sign in to comment.