前言 总结记录一下在开发中经常使用到的一些工具类。
MD5加密 用户的密码一般都会进行加密后在存储到数据库当中,所以一般用到MD5这种加密算法。
这种加密算法最大的特点就是不可逆,只能加密不能解密。
这是挺简单的一种加密算法了,之后还可以考虑加盐和哈希散列,进行更复杂的加密手段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Md5Utils { public static String encrypt (String strSrc) { try { char hexChars[] = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' }; byte [] bytes = strSrc.getBytes(); MessageDigest md = MessageDigest.getInstance("MD5" ); md.update(bytes); bytes = md.digest(); 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]; 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); } } }
雪花算法 对于MySQL的主键问题,一般都需要使用自增的主键。但是只是从1自增就会因为分库分表产生主键相同的情况。
所以这次使用雪花算法生成一个分布式全局唯一ID
首先要知道雪花算法生成的ID是怎么样的。
分布式ID一般都是Long类型,所以会有64位。
第一部分是一个bit位,是一个标识部分,在java中由于long的最高位是符号位,正数是0,负数是1,一般生成的ID为正数,所以固定为0
第二部分是时间戳,该部分占41bit,这个是毫秒级的时间
第三部分是工作机器ID,占10bit
第四部分是序列号,占12bit,支持同一毫秒内同一个节点可以生成4096个ID
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 public class SnowFlake { private final static long START_STMP = 1480166465631L ; private final static long SEQUENCE_BIT = 12 ; private final static long MACHINE_BIT = 5 ; private final static long DATACENTER_BIT = 5 ; private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); private final static long MACHINE_LEFT = SEQUENCE_BIT; private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; private long datacenterId; private long machineId; private long sequence = 0L ; private long lastStmp = -1L ; public SnowFlake (long datacenterId, long machineId) { if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0 ) { throw new IllegalArgumentException ("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0" ); } if (machineId > MAX_MACHINE_NUM || machineId < 0 ) { throw new IllegalArgumentException ("machineId can't be greater than MAX_MACHINE_NUM or less than 0" ); } this .datacenterId = datacenterId; this .machineId = machineId; } public synchronized long nextId () { long currStmp = getNewstmp(); if (currStmp < lastStmp) { throw new RuntimeException ("Clock moved backwards. Refusing to generate id" ); } if (currStmp == lastStmp) { sequence = (sequence + 1 ) & MAX_SEQUENCE; if (sequence == 0L ) { currStmp = getNextMill(); } } else { sequence = 0L ; } lastStmp = currStmp; return (currStmp - START_STMP) << TIMESTMP_LEFT | datacenterId << DATACENTER_LEFT | machineId << MACHINE_LEFT | sequence; } private long getNextMill () { long mill = getNewstmp(); while (mill <= lastStmp) { mill = getNewstmp(); } return mill; } private long getNewstmp () { return System.currentTimeMillis(); } public static void main (String[] args) { SnowFlake snowFlake = new SnowFlake (2 , 3 ); for (int i = 0 ; i < (1 << 12 ); i++) { System.out.println(snowFlake.nextId()); } } }
参考于:https://github.com/beyondfengyu/SnowFlake
JWT工具类 引入依赖 1 2 3 4 5 6 <dependency > <groupId > com.auth0</groupId > <artifactId > java-jwt</artifactId > <version > ${jwt.version}</version > </dependency >
工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 package com.yww.management.utils;import com.auth0.jwt.JWT;import com.auth0.jwt.algorithms.Algorithm;import com.auth0.jwt.exceptions.*;import com.auth0.jwt.interfaces.DecodedJWT;import com.auth0.jwt.interfaces.JWTVerifier;import java.util.Date;import java.util.HashMap;import java.util.Map;public class TokenUtil { public static String genToken (String secret) { Map<String, Object> header = new HashMap <String, Object>(2 ) { private static final long serialVersionUID = 1L ; { put("alg" , "HMAC512" ); put("typ" , "JWT" ); } }; Map<String, Object> payload = new HashMap <String, Object>(3 ) { private static final long serialVersionUID = 1L ; { put("name" , "yww" ); put("num" , 1141950370 ); } }; Date now = new Date (); Date exp = new Date (now.getTime() + 10 ); return JWT.create() .withHeader(header) .withIssuer("yww" ) .withSubject("management" ) .withAudience("vue-management" ) .withNotBefore(now) .withExpiresAt(exp) .withIssuedAt(now) .withJWTId("123456" ) .withPayload(payload) .sign(Algorithm.HMAC512(secret)); } public static void parse (String token) { try { JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC512("1" )).build(); DecodedJWT decode = jwtVerifier.verify(token); System.out.println(decode.getHeader()); System.out.println(decode.getPayload()); System.out.println(decode.getSignature()); } catch (AlgorithmMismatchException e) { System.out.println("签名算法不匹配" ); } catch (SignatureVerificationException e) { System.out.println("签名无效" ); } catch (TokenExpiredException e) { System.out.println("令牌已过期" ); } catch (MissingClaimException e) { System.out.println("缺少要验证的声明" ); } catch (IncorrectClaimException e) { System.out.println("声明包含的值和预期不符合" ); } catch (JWTVerificationException e) { System.out.println("验证中的某一个步骤失败" ); } } }
响应工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import cn.hutool.json.JSONUtil;import com.yww.management.common.Result;import javax.servlet.http.HttpServletResponse;import java.io.IOException;public class ResponseUtil { public static void response (HttpServletResponse response, Result<Object> result) throws IOException { response.setHeader("Access-Control-Allow-Origin" , "*" ); response.setHeader("Cache-Control" ,"no-cache" ); response.setCharacterEncoding("UTF-8" ); response.setContentType("application/json" ); response.setStatus(result.getCode()); response.getWriter().write(JSONUtil.toJsonStr(result)); response.getWriter().flush(); } }
IP工具类 这个工具类主要是用于获取请求的IP地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 import cn.hutool.core.util.StrUtil;import javax.servlet.http.HttpServletRequest;public class IpUtil { public static String getIpAddr (HttpServletRequest request) { if (request == null ) { return "unknown" ; } String ip = request.getHeader("x-forwarded-for" ); if (isNotUnknown(ip)) { ip = request.getHeader("Proxy-Client-IP" ); } if (isNotUnknown(ip)) { ip = request.getHeader("X-Forwarded-For" ); } if (isNotUnknown(ip)) { ip = request.getHeader("WL-Proxy-Client-IP" ); } if (isNotUnknown(ip)) { ip = request.getHeader("X-Real-IP" ); } if (isNotUnknown(ip)) { ip = request.getRemoteAddr(); } return "0:0:0:0:0:0:0:1" .equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); } @SuppressWarnings("all") public static String getMultistageReverseProxyIp (String ip) { if (ip != null && ip.indexOf("," ) > 0 ) { final String[] ips = ip.trim().split("," ); for (String subIp : ips) { if (isNotUnknown(subIp)) { ip = subIp; break ; } } } return ip; } public static boolean isNotUnknown (String checkString) { return StrUtil.isNotBlank(checkString) && StrUtil.isNotEmpty(checkString) && !"unknown" .equalsIgnoreCase(checkString); } }
BigDecimal工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 import java.math.BigDecimal;import java.math.RoundingMode;public class BigDecimalUtil { private static final int DEFAULT_PRECISION = 10 ; private BigDecimalUtil () {} public static double addUp (double value1, double value2) { BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); return b1.add(b2).doubleValue(); } public static double subtract (double value1, double value2) { BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); return b1.subtract(b2).doubleValue(); } public static double multiply (double value1, double value2) { BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); return b1.multiply(b2).doubleValue(); } public static double div (double value1, double value2) throws IllegalAccessException { return div(value1, value2, DEFAULT_PRECISION); } public static double div (double value1, double value2, int precision) throws IllegalAccessException { if (precision < 0 ) { throw new IllegalAccessException ("除法的精度不能小于0" ); } return div(value1, value2, precision, RoundingMode.HALF_UP); } public static double div (double value1, double value2, int precision, RoundingMode mode) throws IllegalAccessException { if (precision < 0 ) { throw new IllegalAccessException ("除法的精度不能小于0" ); } BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); return b1.divide(b2, precision, mode).doubleValue(); } }
断言工具类
hutool里也有很多断言的工具类,但是抛出的异常不是自己定义的,所以为了指定抛出的异常,需要自己在定义一个断言工具类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import cn.hutool.core.util.StrUtil;import com.yww.management.common.exception.GlobalException;public class AssertUtils { private AssertUtils () {} public static void notNull (Object object) throws GlobalException { notNull(object, "不能处理空对象" ); } public static void notNull (Object object, String message) throws GlobalException { if (object == null ) { throw new GlobalException (message); } } public static void hasText (String text) throws GlobalException { hasText(text, "此参数不能为空字符串" ); } public static void hasText (String text, String message) throws GlobalException { if (StrUtil.isBlank(text)) { throw new GlobalException (message); } } }
ThreadLocal工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 import java.util.HashMap;import java.util.Map;@SuppressWarnings("unchecked") public class ThreadLocalUtil { private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL_MAP = ThreadLocal.withInitial(HashMap::new ); private ThreadLocalUtil () {} public static <T> T get (String key) { return (T) THREAD_LOCAL_MAP.get().get(key); } public static <T> T get (String key, T defaultValue) { T value = get(key); return value == null ? defaultValue : value; } public static void set (String key, Object value) { THREAD_LOCAL_MAP.get().put(key, value); } public static void remove (String key) { THREAD_LOCAL_MAP.get().remove(key); } public static void close () { THREAD_LOCAL_MAP.remove(); } }
分页工具类 封装分页请求对象
如果需要添加其他的属性筛选,只需要继承该封装对象即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 import com.fasterxml.jackson.annotation.JsonIgnore;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;@SuppressWarnings("all") @JsonIgnoreProperties(ignoreUnknown = true) public class PageVo { private static final int DEFAULT_SIZE = 10 ; private int page = 1 ; private int size = DEFAULT_SIZE; private String sort; private String dir; public static PageVo of (int page, int size) { PageVo pageReqVo = new PageVo (); pageReqVo.setPage(page); pageReqVo.setSize(size); return pageReqVo; } public PageVo () {} @JsonIgnore public int getOffset () { return (getPage() - 1 ) * getSize(); } public int getPage () { return page > 0 ? page : 1 ; } public void setPage (int page) { this .page = page; } public int getSize () { return size > 0 ? size : DEFAULT_SIZE; } public void setSize (int size) { this .size = size; } public String getSort () { return sort; } public void setSort (String sort) { this .sort = sort; } public String getDir () { return dir; } public void setDir (String dir) { this .dir = dir; } }
分页结果类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 import com.fasterxml.jackson.annotation.JsonPropertyOrder;import java.util.List;@JsonPropertyOrder({"start", "size", "total", "rows"}) public class PageResultVo <T> { private int start; private int size; private int total; private List<T> rows; public static <E> PageResultVo<E> ofReqVo (PageVo reqVo, List<E> rows, int total) { PageResultVo<E> pageResultVo = new PageResultVo <>(); pageResultVo.setSize(reqVo.getSize()); pageResultVo.setStart(reqVo.getOffset()); pageResultVo.setTotal(total); pageResultVo.setRows(rows); return pageResultVo; } public PageResultVo () { } public int getStart () { return start; } public void setStart (int start) { this .start = start; } public int getSize () { return size; } public void setSize (int size) { this .size = size; } public int getTotal () { return total; } public void setTotal (int total) { this .total = total; } public List<T> getRows () { return rows; } public void setRows (List<T> rows) { this .rows = rows; } }
分页工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 import cn.hutool.core.bean.BeanUtil;import cn.hutool.core.util.StrUtil;import com.baomidou.mybatisplus.core.conditions.ISqlSegment;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;import com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.baomidou.mybatisplus.core.metadata.IPage;import com.baomidou.mybatisplus.core.toolkit.Wrappers;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.yww.management.common.exception.GlobalException;import java.util.ArrayList;import java.util.List;@SuppressWarnings("all") public class PageUtil { public static <R, Q extends PageVo > PageResultVo<R> paging (Q pageVo, BaseMapper<R> mapper, Class<R> clazz) { R entity; try { entity = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new GlobalException ("分页类型转换错误" ); } BeanUtil.copyProperties(pageVo, entity); IPage<R> page = new Page <>(pageVo.getPage(), pageVo.getSize()); page = mapper.selectPage(page, Wrappers.lambdaQuery(entity)); return PageResultVo.ofReqVo(pageVo, page.getRecords(), Long.valueOf(page.getTotal()).intValue()); } public static <R, Q extends PageVo > PageResultVo<R> paging (Q pageVo, BaseMapper<R> mapper, LambdaQueryWrapper<R> lambdaQuery, Class<R> clazz) { R entity; try { entity = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new GlobalException ("分页类型转换错误" ); } String[] whereFields = getWhereFields(lambdaQuery); BeanUtil.copyProperties(pageVo, entity, whereFields); lambdaQuery.setEntity(entity); IPage<R> page = new Page <>(pageVo.getPage(), pageVo.getSize()); page = mapper.selectPage(page, lambdaQuery); return PageResultVo.ofReqVo(pageVo, page.getRecords(), Long.valueOf(page.getTotal()).intValue()); } public static <R> String[] getWhereFields(LambdaQueryWrapper<R> lambdaQuery) { List<String> fields = new ArrayList <>(); MergeSegments expression = lambdaQuery.getExpression(); NormalSegmentList normal = expression.getNormal(); int index = 0 ; for (ISqlSegment iSqlSegment : normal) { if (index % 4 == 0 ) { String field = StrUtil.toCamelCase(iSqlSegment.getSqlSegment()); fields.add(field); } index++; } return fields.toArray(new String []{}); } }
文件工具类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 package com.yww.filebackend.utils;import cn.hutool.core.util.IdUtil;import cn.hutool.core.util.StrUtil;import com.yww.filebackend.entity.SysFile;import lombok.extern.slf4j.Slf4j;import org.springframework.web.multipart.MultipartFile;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.text.SimpleDateFormat;import java.util.Date;@Slf4j public class FileUtil { private final static String FILE_SAVE_PATH = "D:\\file" ; public final static String DATE_FORMAT = "/yyyy/MM/dd/" ; private final static String DATE_FORMAT_WIN = "\\yyyy\\MM\\dd\\" ; public static SysFile saveFile (MultipartFile file) { String originalFilename = file.getOriginalFilename(); String ext = getExtName(originalFilename); String newName = IdUtil.fastSimpleUUID() + "." + ext; String dateFormat = new SimpleDateFormat (getDateFormat()).format(new Date ()); String path = FILE_SAVE_PATH + dateFormat + newName; File dest = new File (path); if (!dest.exists()) { cn.hutool.core.io.FileUtil.touch(dest); } try { file.transferTo(dest); } catch (IOException e) { log.warn("保存文件出错,保存的文件名称为:" + originalFilename); log.warn("保存文件出错,保存的路径为:" + path); throw new RuntimeException (e); } return SysFile.builder() .fileName(originalFilename) .path(path) .size(file.getSize()) .build(); } public static String getExtName (String fileName) { if (fileName == null ) { return null ; } int index = fileName.lastIndexOf("." ); if (index == -1 ) { return "" ; } int secondToLastIndex = fileName.substring(0 , index).lastIndexOf("." ); return fileName.substring(secondToLastIndex == -1 ? index + 1 : secondToLastIndex + 1 ); } public static String getDateFormat () { String osName = System.getProperty("os.name" ).toLowerCase(); if (StrUtil.isNotBlank(osName) && osName.contains("win" )) { return DATE_FORMAT_WIN; } return DATE_FORMAT; } }