目录
CreateVerifiCodeImage.java 绘制验证码图片
ResultCodeEnum.java 统一返回结果状态信息类
AuthContextHolder.java
import javax.servlet.http.HttpServletRequest;
public class AuthContextHolder {
//从请求头token获取userid
public static Long getUserIdToken(HttpServletRequest request) {
//从请求头token
String token = request.getHeader("token");
//调用工具类
Long userId = JwtHelper.getUserId(token);
return userId;
}
//从请求头token获取name
public static String getUserName(HttpServletRequest request) {
//从header获取token
String token = request.getHeader("token");
//jwt从token获取username
String userName = JwtHelper.getUserName(token);
return userName;
}
}
CreateVerifiCodeImage.java 绘制验证码图片
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* @project: ssm_sms
* @description: 绘制验证码图片
*/
public class CreateVerifiCodeImage {
private static int WIDTH = 90;
private static int HEIGHT = 35;
private static int FONT_SIZE = 20; //字符大小
private static char[] verifiCode; //验证码
private static BufferedImage verifiCodeImage; //验证码图片
/**
* @description: 获取验证码图片
* @param: no
* @return: java.awt.image.BufferedImage
*/
public static BufferedImage getVerifiCodeImage() {
// 创建一个指定宽度、高度和颜色深度的BufferedImage对象
verifiCodeImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);
// 获取BufferedImage的对象Graphics,用于绘制图像
Graphics graphics = verifiCodeImage.getGraphics();
// 生成验证码字符串
verifiCode = generateCheckCode();
// 绘制验证码背景
drawBackground(graphics);
// 在背景上绘制验证码数字或字符
drawRands(graphics, verifiCode);
// 释放Graphics对象的资源
graphics.dispose();
// 返回生成的验证码图像
return verifiCodeImage;
}
/**
* @description: 获取验证码
* @param: no
* @return: char[]
*/
public static char[] getVerifiCode() {
return verifiCode;
}
/**
* 随机生成一个包含4个字符的验证码。
* 验证码的字符集包括0-9、小写a-z、大写A-Z。
*
* @return char[] 返回一个长度为4的字符数组,每个字符都是验证码的一部分。
*/
private static char[] generateCheckCode() {
// 定义可用字符集合
String chars = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] rands = new char[4]; // 初始化一个长度为4的字符数组用于存放随机字符
// 生成4个随机字符
for (int i = 0; i < 4; i++) {
// 生成随机索引,用于从chars中选取一个字符
int rand = (int) (Math.random() * (10 + 26 * 2));
rands[i] = chars.charAt(rand); // 将选取的字符存入数组
}
return rands;
}
/**
* 绘制验证码的函数。
* @param g Graphics对象,用于绘制验证码。
* @param rands 包含随机字符的数组,用于生成验证码。
* 该函数没有返回值。
*/
private static void drawRands(Graphics g, char[] rands) {
// 设置字体为粗体的"Console",大小为预定义的FONT_SIZE
g.setFont(new Font("Console", Font.BOLD, FONT_SIZE));
// 遍历字符数组,逐个绘制字符
for (int i = 0; i < rands.length; i++) {
// 为每个字符随机设置颜色
g.setColor(getRandomColor());
// 在画布上绘制字符,位置为(i * FONT_SIZE + 10, 25)
g.drawString("" + rands[i], i * FONT_SIZE + 10, 25);
}
}
/**
* 绘制验证码图片的背景。
* 这个方法通过绘制随机的色块和干扰点来创建一个具有噪声的背景,以增加验证码的抗自动识别能力。
*
* @param g Graphics对象,用于绘制图形。
* @return void 方法没有返回值。
*/
private static void drawBackground(Graphics g) {
// 设置背景颜色并填充整个验证码图片区域
g.setColor(Color.white);
g.fillRect(0, 0, WIDTH, HEIGHT);
// 绘制验证码干扰点
// 这一环节是为了增加验证码的复杂度,使得计算机更难识别。
for (int i = 0; i < 200; i++) {
int x = (int) (Math.random() * WIDTH); // 随机生成点的x坐标
int y = (int) (Math.random() * HEIGHT); // 随机生成点的y坐标
g.setColor(getRandomColor()); // 随机设置颜色
g.drawOval(x, y, 1, 1); // 绘制单个像素的圆点
}
}
/**
* @description: 获取随机颜色
* @param: no
* @return: java.awt.Color
*/
private static Color getRandomColor() {
Random ran = new Random();
return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220));
}
}
JwtHelper.java
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;
public class JwtHelper {
private static long tokenExpiration = 24*60*60*1000;
private static String tokenSignKey = "123456";
/**
* 生成token字符串。
* 该token包含用户ID和用户类型信息,用于用户身份验证。
*
* @param userId 用户的ID,唯一标识一个用户。
* @param userType 用户的类型,用于区分不同类型的用户(如普通用户、管理员等)。
* @return 返回生成的token字符串。
*/
public static String createToken(Long userId, Integer userType) {
// 使用JWT构建器开始构建token
String token = Jwts.builder()
.setSubject("YYGH-USER") // 设置token的主题
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) // 设置token的过期时间
// 添加自定义的声明,这里包含用户ID和用户类型
.claim("userId", userId)
.claim("userType", userType)
// 使用HS512算法和预定义的tokenSignKey对token进行签名
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
// 对token进行GZIP压缩
.compressWith(CompressionCodecs.GZIP)
// 将构建好的token对象转换成紧凑的字符串形式
.compact();
return token;
}
/**
* 从token字符串中解析并获取用户ID。
*
* @param token 用户身份验证的token字符串。
* @return 如果token有效并包含userId,则返回对应的用户ID(Long类型);如果token无效或缺失userId,则返回null。
*/
public static Long getUserId(String token) {
// 检查token是否为空
if(StringUtils.isEmpty(token)) return null;
// 使用JJWT解析token并获取其中的声明
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
// 从声明中获取用户ID
Integer userId = (Integer)claims.get("userId");
// 将用户ID转换为Long类型并返回
return userId.longValue();
}
/**
* 从token字符串中获取用户类型。
*
* @param token 用户的token字符串,用于身份验证和授权。
* @return 返回从token中解析出的用户类型,如果token为空或解析失败则返回null。
*/
public static Integer getUserType(String token) {
// 检查token是否为空
if(StringUtils.isEmpty(token)) return null;
// 使用JJWT库解析token并获取其中的声明
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
// 从声明中获取并返回用户类型
return (Integer)(claims.get("userType"));
}
/**
* 从token字符串中获取用户名。
*
* @param token 用户身份验证的令牌。
* @return 返回从token中解析出的用户名,如果token为空或解析失败则返回空字符串。
*/
public static String getUserName(String token) {
// 检查token是否为空
if(StringUtils.isEmpty(token)) return "";
// 解析token为Claims对象
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
// 从Claims中获取用户名并返回
return (String)claims.get("userName");
}
/**
* 判断token是否有效。
* 这个方法通过解析token并检查其是否过期来判断token的有效性。
*
* @param token 需要验证的token字符串。
* @return boolean 如果token未过期,则返回false,表示有效;如果token已过期或解析失败,则返回true。
*/
public static boolean isExpiration(String token){
try {
// 解析token,获取其过期时间,并判断是否当前时间之前
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey) // 设置用于签名的密钥
.parseClaimsJws(token) // 解析token为Claims
.getBody() // 获取token的主体(包含claims)
.getExpiration().before(new Date()); // 判断token是否已过期
// 如果token未过期,则返回false,表示有效
return isExpire;
}catch(Exception e) {
// 如果解析过程中发生异常,认为token无效或已过期,返回true
return true;
}
}
/**
* 刷新Token
* @param token
* @return
*/
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody();
refreshedToken = JwtHelper.createToken(getUserId(token), getUserType(token));
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
public static void main(String[] args) {
// String token = JwtHelper.createToken(1L, "lucy");
// System.out.println(token);
// System.out.println(JwtHelper.getUserId(token));
// System.out.println(JwtHelper.getUserName(token));
}
}
MD5.java
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5 {
/**
* 使用MD5算法对输入字符串进行加密
*
* @param strSrc 需要加密的源字符串
* @return 经过MD5加密后,转换为16进制字符串的结果
*/
public static String encrypt(String strSrc) {
try {
// 定义16进制字符数组,用于转换加密后的字节数据
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
// 将源字符串转换为字节数组
byte[] bytes = strSrc.getBytes();
// 获取MD5消息摘要算法的实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 更新消息摘要
md.update(bytes);
// 计算消息摘要
bytes = md.digest();
// 拼接摘要为16进制字符串
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
// 将每个字节转换为两位16进制数
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
// 返回转换后的字符串
return new String(chars);
} catch (NoSuchAlgorithmException e) {
// 处理算法不可用的异常
e.printStackTrace();
throw new RuntimeException("MD5加密出错!!+" + e);
}
}
}
Result.java 全局统一返回结果类
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 全局统一返回结果类
*
*/
@Data
@ApiModel(value = "全局统一返回结果")
public class Result<T> {
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private T data;
public Result(){}
// 返回数据
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
public static<T> Result<T> ok(){
return Result.ok(null);
}
/**
* 操作成功
* @param data
* @param <T>
* @return
*/
public static<T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.SUCCESS);
}
public static<T> Result<T> fail(){
return Result.fail(null);
}
/**
* 操作失败
* @param data
* @param <T>
* @return
*/
public static<T> Result<T> fail(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.FAIL);
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
public boolean isOk() {
if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
return true;
}
return false;
}
}
ResultCodeEnum.java 统一返回结果状态信息类
import lombok.Getter;
/**
* 统一返回结果状态信息类
*
*/
@Getter
public enum ResultCodeEnum {
SUCCESS(200,"成功"),
FAIL(201, "失败"),
SERVICE_ERROR(2012, "服务异常"),
ILLEGAL_REQUEST( 204, "非法请求"),
PAY_RUN(205, "支付中"),
ARGUMENT_VALID_ERROR(206, "参数校验错误"),
LOGIN_ERROR(207, "用户名或密码错误"),
LOGIN_AUTH(208, "未登陆"),
PERMISSION(209, "没有权限"),
SECKILL_NO_START(210, "秒杀还没开始"),
SECKILL_RUN(211, "正在排队中"),
SECKILL_NO_PAY_ORDER(212, "您有未支付的订单"),
SECKILL_FINISH(213, "已售罄"),
SECKILL_END(214, "秒杀已结束"),
SECKILL_SUCCESS(215, "抢单成功"),
SECKILL_FAIL(216, "抢单失败"),
SECKILL_ILLEGAL(217, "请求不合法"),
SECKILL_ORDER_SUCCESS(218, "下单成功"),
COUPON_GET(220, "优惠券已经领取"),
COUPON_LIMIT_GET(221, "优惠券已发放完毕"),
//2022-02-22
LOGIN_CODE(222,"长时间未操作,会话已失效,请刷新页面后重试!"),
CODE_ERROR(223,"验证码错误!"),
TOKEN_ERROR(224,"Token无效!")
;
private Integer code;
private String message;
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
UploadFile.java 上传文件的工具类
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @project: sms
* @description: 上传文件的工具类
*/
public class UploadFile {
//存储文件上传失败的错误信息
private static Map<String, Object> error_result = new HashMap<>();
//存储头像的上传结果信息
private static Map<String, Object> upload_result = new HashMap<>();
/**
* 验证上传图片的大小、格式等信息,并尝试保存图片。
*
* @param photo 用户上传的图片文件,作为MultipartFile类型传入。
* @param path 图片文件将要保存的服务器路径。
* @return 返回一个Map<String, Object>,其中包含上传结果的成功与否及消息。
*/
private static Map<String, Object> uploadPhoto(MultipartFile photo, String path) {
// 设置最大允许上传的文件大小(20MB)
int MAX_SIZE = 20971520;
// 获取上传文件的原始名称
String orginalName = photo.getOriginalFilename();
// 检查保存文件的目录是否存在,不存在则创建
File filePath = new File(path);
if (!filePath.exists()) {
filePath.mkdirs();
}
// 检查上传文件大小是否符合规定
if (photo.getSize() > MAX_SIZE) {
error_result.put("success", false);
error_result.put("msg", "上传的图片大小不能超过20M哟!");
return error_result;
}
// 检查上传文件的类型是否被允许
String[] suffixs = new String[]{".png", ".PNG", ".jpg", ".JPG", ".jpeg", ".JPEG", ".gif", ".GIF", ".bmp", ".BMP"};
SuffixFileFilter suffixFileFilter = new SuffixFileFilter(suffixs);
if (!suffixFileFilter.accept(new File(path + orginalName))) {
error_result.put("success", false);
error_result.put("msg", "禁止上传此类型文件! 请上传图片哟!");
return error_result;
}
// 若文件大小和类型检查都通过,则应进行文件保存逻辑(当前代码未实现)
return null;
}
/**
* 获取头像的上传结果信息
* 该方法用于处理头像上传的过程,包括检查文件、上传文件、重命名文件,并返回上传结果。
* @param photo 用户上传的头像文件
* @param dirPaht 上传目录的路径
* @param portraitPath 头像在项目中的相对路径
* @return 返回一个Map,包含上传结果的信息,如成功与否、错误消息等
*/
public static Map<String, Object> getUploadResult(MultipartFile photo, String dirPaht, String portraitPath) {
// 检查照片是否为空且大小大于0
if (!photo.isEmpty() && photo.getSize() > 0) {
// 获取图片原始名称
String orginalName = photo.getOriginalFilename();
// 上传图片,处理可能的上传错误
Map<String, Object> error_result = UploadFile.uploadPhoto(photo, dirPaht);
if (error_result != null) {
return error_result;
}
// 使用UUID重命名图片以避免重复
String newPhotoName = UUID.randomUUID() + "__" + orginalName;
try {
// 将上传的图片保存到指定目录下
photo.transferTo(new File(dirPaht + newPhotoName));
// 设置上传成功的结果
upload_result.put("success", true);
upload_result.put("portrait_path", portraitPath + newPhotoName);
} catch (IOException e) {
// 处理保存图片时可能出现的异常
e.printStackTrace();
upload_result.put("success", false);
upload_result.put("msg", "上传文件失败! 服务器端发生异常!");
}
} else {
// 处理未选择图片或图片为空的情况
upload_result.put("success", false);
upload_result.put("msg", "头像上传失败! 未找到指定图片!");
}
return upload_result;
}
}