日常工具类记录

前言

目前参加工作也有1年多了,收获颇丰,打算在这里分享一下日常使用的工具类,也方便大家学习工作里进行使用。

一、Hutool

Hutool是一个Java工具类库,它封装了很多常用的Java工具类,如加密解密、文件操作、日期时间处理、Http客户端等。它的目标是让Java开发变得更加简单、高效。日常开发必备工具包!!

二、Redis缓存的工具类

代码如下(示例):

/**
 * @author wlm
 * @date 2023-03-02
 */
@Component
public class RedisCache
{
    @Autowired
    public RedisTemplate redisTemplate;

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value)
    {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param timeout 时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
    {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout)
    {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit)
    {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 删除单个对象
     *
     * @param key
     */
    public boolean deleteObject(final String key)
    {
        return redisTemplate.delete(key);
    }

    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public long deleteObject(final Collection collection)
    {
        return redisTemplate.delete(collection);
    }

    /**
     * 缓存List数据
     *
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList)
    {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final String key)
    {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 缓存Set
     *
     * @param key 缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
    {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext())
        {
            setOperation.add(it.next());
        }
        return setOperation;
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key)
    {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
    {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key)
    {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 往Hash中存入数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
    {
        redisTemplate.opsForHash().put(key, hKey, value);
    }

    /**
     * 获取Hash中的数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey)
    {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }

    /**
     * 删除Hash中的数据
     *
     * @param key
     * @param hkey
     */
    public void delCacheMapValue(final String key, final String hkey)
    {
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(key, hkey);
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param key Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
    {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern)
    {
        return redisTemplate.keys(pattern);
    }
}

三、PageUtils

日常开发里经常会遇到一些自定义对象并不能使用MabatisPlus的框架的Page方法,这个PageUtils可以将任意的list的转换成一个Page对象,即拿即用。

代码如下:

public class PageUtils {

    private static final ThreadLocal<Page<?>> LOCAL_PAGE = new ThreadLocal<>();

    public static void startPage(int pageNum, int pageSize) {
        Page<?> page = new Page<>(pageNum, pageSize);
        LOCAL_PAGE.set(page);
    }

    public static <T> Page<T> endPage() {
        Page<T> page = (Page<T>) LOCAL_PAGE.get();
        LOCAL_PAGE.remove();
        return page;
    }

    public static <T> IPage<T> getPage(int pageNum, int pageSize, List<T> t) {
        // 创建IPage对象,指定当前页码和每页显示的记录数
        IPage<T> page = new Page<>(pageNum, pageSize);
        // 设置总记录数
        page.setTotal(t.size());
        // 计算分页起始索引
        int startIndex = (pageNum - 1) * pageSize;
        // 计算分页结束索引
        int endIndex = Math.min(startIndex + pageSize, t.size());
        // 截取分页数据
        List<T> pageData = t.subList(startIndex, endIndex);
        // 设置分页数据
        page.setRecords(pageData);
        // 返回分页后的数据
        return page;
    }
}


四、AES加密工具类

最近由于公司项目有三级等保要求,给我的任务是将数据库里所有的数据进行aes加密,入库加密,出库解密,返回给前端时进行脱敏,这一块当时确实难到我了,普通的加解密不难,但由于这个还需要用sql也能解密,方便业务的模糊查询工作,导致开发起来确实有一些难度,但也解决掉了。完成的一套是工具类+加密注解+脱敏注解进行完美解决,有小伙伴需要具体细节的话可以点赞私聊我。

代码如下:

public class MPAESUtil {


    /**
     * 密钥长度: 128, 192 or 256
     */
    private static final int KEY_SIZE = 256;

    /**
     * 加密/解密算法名称
     */
    private static final String ALGORITHM = "AES";

    /**
     * 随机数生成器(RNG)算法名称
     */
    private static final String RNG_ALGORITHM = "SHA1PRNG";

    /**
     * 生成密钥的种子不可泄露
     */
    public static final String KEY = "你自己的密钥";


    /**
     * 生成密钥对象
     */
    private static SecretKey generateKey(byte[] key) throws Exception {
        byte[] bytes = KEY.getBytes();
        // 创建安全随机数生成器
        SecureRandom random = SecureRandom.getInstance(RNG_ALGORITHM);
        // 设置 密钥key的字节数组 作为安全随机数生成器的种子
        random.setSeed(key);

        // 创建 AES算法生成器
        KeyGenerator gen = KeyGenerator.getInstance(ALGORITHM);
        // 初始化算法生成器
        gen.init(KEY_SIZE, random);

        // 生成 AES密钥对象, 也可以直接创建密钥对象: return new SecretKeySpec(key, ALGORITHM);
//        return gen.generateKey();
        return new SecretKeySpec(key, ALGORITHM);
    }


    /**
     * 数据加密: 明文 -> 密文
     */
    public static String encrypt(String content, byte[] key) {
        // 生成密钥对象
        SecretKey secKey;
        try {
            secKey = generateKey(key);
            // 获取 AES 密码器
             Cipher cipher = Cipher.getInstance(ALGORITHM);
            // 初始化密码器(加密模型)
            cipher.init(Cipher.ENCRYPT_MODE, secKey);
            // 加密数据, 返回密文
            byte[] plainBytes = content.getBytes("utf-8");
            byte[] result = cipher.doFinal(plainBytes);
            return Base64.getEncoder().encodeToString(result);//通过Base64转码返回
        } catch (Exception e) {
            throw new RuntimeException( "AES 加密失败:" + e.getMessage());
        }

    }

    /**
     * 数据解密: 密文 -> 明文
     */
    public static String decrypt(String content, byte[] key) {
        try {
            // 生成密钥对象
            SecretKey secKey = generateKey(key);

            // 获取 AES 密码器
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            // 初始化密码器(解密模型)
            cipher.init(Cipher.DECRYPT_MODE, secKey);

            // 解密数据, 返回明文
            byte[] result = cipher.doFinal(Base64.getDecoder().decode(content));
            return new String(result, "utf-8");
        } catch (Exception e) {
            throw new RuntimeException( "AES 解密失败:" + e.getMessage());
        }
    }

    /**
     * 加密文件: 明文输入 -> 密文输出
     */
    public static void encryptFile(File plainIn, File cipherOut, byte[] key) throws Exception {
        aesFile(plainIn, cipherOut, key, true);
    }

    /**
     * 解密文件: 密文输入 -> 明文输出
     */
    public static void decryptFile(File cipherIn, File plainOut, byte[] key) throws Exception {
        aesFile(plainOut, cipherIn, key, false);
    }

    /**
     * AES 加密/解密文件
     */
    private static void aesFile(File plainFile, File cipherFile, byte[] key, boolean isEncrypt) throws Exception {
        // 获取 AES 密码器
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        // 生成密钥对象
        SecretKey secKey = generateKey(key);
        // 初始化密码器
        cipher.init(isEncrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, secKey);

        // 加密/解密数据
        InputStream in = null;
        OutputStream out = null;

        try {
            if (isEncrypt) {
                // 加密: 明文文件为输入, 密文文件为输出
                in = new FileInputStream(plainFile);
                out = new FileOutputStream(cipherFile);
            } else {
                // 解密: 密文文件为输入, 明文文件为输出
                in = new FileInputStream(cipherFile);
                out = new FileOutputStream(plainFile);
            }

            byte[] buf = new byte[1024];
            int len = -1;

            // 循环读取数据 加密/解密
            while ((len = in.read(buf)) != -1) {
                out.write(cipher.update(buf, 0, len));
            }
            out.write(cipher.doFinal());    // 最后需要收尾

            out.flush();

        } finally {
            close(in);
            close(out);
        }
    }

    private static void close(Closeable c) {
        if (c != null) {
            try {
                c.close();
            } catch (IOException e) {
                // nothing
            }
        }
    }

    public static void main(String[] args) {
        String encrypt = MPAESUtil.encrypt("18155907185", MPAESUtil.KEY.getBytes());
        System.out.println(encrypt);
    }

}

2024-04-14

今天来补充下sql里面的解析方法,形成sql和代码的加解密互通。

假设我上面的key=‘1111111111111111’(这里注意key必须是16位),机密内容为123

代码加密过程:

    public static void main(String[] args) {
        String encrypt = MPAESUtil.encrypt("123","1111111111111111".getBytes());
        System.out.println("加密结果:"+encrypt);
        String decrypt = MPAESUtil.decrypt(encrypt, "1111111111111111".getBytes());
        System.out.println("解密结果:"+decrypt);
    }

结果:

Sql加密过程:

加密sql

 SELECT to_base64(AES_ENCRYPT('123','1111111111111111'))

解密sql:

 SELECT AES_DECRYPT( from_base64 ('XtRDz3Z8+6VwWb4WUIqGBQ=='), '1111111111111111')

发现和上面的代码一致,这里就完成了代码与sql的加解密互通工作。但往后面如果有查询的话应该怎么办呢,之前是明文可以模糊查询,现在加密之后,存在数据库里都是密文了,无法直接进行模糊查询。结局方案是在sql里面就进行解密查询,示例代码如下:

<if test="ro.phone != null and ro.phone != ''">
            AND AES_DECRYPT( from_base64 (a.phone), '1111111111111111') like concat('%',#{ro.phone},'%')
</if>

就可以继续进行模糊查询啦。


总结

在开发过程中,各种工具必不可少,可以大大简化工作流程,提高工作效率(摸鱼效率),有小伙伴有不明白的地方,或者愿意互相分享的也可以私信我哦

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值