大熊猫分布式组件开发系列教程(二)

本文介绍了Java Base基础库的集成内容,包括定义SortParam和QueryParam类实现sql或hql拼接,base - util工具包中的加解密工具类、缓存实体和缓存组。还讲解了jwt权限认证的实体类和token加解密生成方法,后续将讲业务层封装及编写sso单点登录系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上节我们看到base基础库的base-common的一些基础注解,这些注解后续会有应用。接下来我们看一下base集成的一些内容。

我们都知道查询的时候用的查询条件和排序比较多,因此我定义了两个类来实现根据传入的参数就可实现sql或者hql的拼接。

SortParam实体,用来排序条件的拼装

package com.panda.base.jpa.dao;
public class SortParam {
    private String key;
    private Order order = Order.ASC;
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public Order getOrder() {
        return order;
    }
    public void setOrder(Order order) {
        this.order = order;
    }
    public SortParam() {
    }
    public SortParam(String key, Order order) {
        this.key = key;
        this.order = order;
    }
    public enum Order {
        ASC, DESC;
    }
}

QueryParam用来查询条件的sql拼装

 

package com.panda.base.jpa.dao;
public class QueryParam {
    private String key;
    private Object value;
    private Logic logic = Logic.Contain;
    /**
     * 括号内部的连接方式
     */
    private LinkMode innerLinkMode = LinkMode.And;
    public QueryParam(String key, Object value, Logic logic) {
        this.key = key;
        this.value = value;
        this.logic = logic;
    }
    public QueryParam(String key, Object value, Logic logic, LinkMode innerLinkMode) {
        this.key = key;
        this.value = value;
        this.logic = logic;
        this.innerLinkMode = innerLinkMode;
    }
    public QueryParam(String key, Object value) {
        this.key = key;
        this.value = value;
        this.logic = Logic.Equal;
    }
    public QueryParam() {
    }
    public LinkMode getInnerLinkMode() {
        return innerLinkMode;
    }
    public void setInnerLinkMode(LinkMode innerLinkMode) {
        this.innerLinkMode = innerLinkMode;
    }
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public Object getValue() {
        return value;
    }
    public void setValue(Object value) {
        this.value = value;
    }
    public Logic getLogic() {
        return logic;
    }
    public void setLogic(Logic logic) {
        this.logic = logic;
    }
    public enum Logic {
        Equal,
        NotEqual,
        Contain,
        StartWith,
        EndWith,
        In,
        NotIn,
        GreaterThan,
        GreaterThanAndEqual,
        LessThanAndEqual,
        LessThan,
        IsNull,
        IsNotNull
    }
    public enum LinkMode {
        And, Or;
    }
}

再来看看base-util下封装了哪些东西

工具包中含有一些加解密的工具类,另外还加了一个缓存实体和缓存组,缓存组的概念我这里解释一下。

/**
 * 概念:
 * 组缓存,在传统redis、memcached 这一类的缓存容器中,都是key-value类型的
 * 所谓的组缓存,就是在key-value的外层加一个标识
 * 用list来做比较,在redis中,list的结构是这样的,并且list的某一项不能设置存活时间:
 *  abc
 *      1
 *      2
 *      3
 *
 * 在GroupCache中结构是这样的   :
 * abc
 *  a 1 10
 *  b 2 5
 *  c 3 1
 * 第一行:a代表key,1代表value,10代表存活10秒,存活时间以秒为单位
 */

CacheEntity

package com.panda.base.utils.cache;
import java.io.Serializable;
/**
 * 缓存实体
 */
public class CacheEntity<T,V> implements Serializable {
    private static final long serialVersionUID = 2082223810638865724L;
    private T key; // key
    private V value;// 值
    private Long timestamp;// 缓存的时候存的时间戳,用来计算该元素是否过期
    private int expire = Integer.MAX_VALUE; // 默认长期有效
    private Group group;// 容器
    public CacheEntity(T key, V value, Long timestamp, int expire, Group group) {
        this.key = key;
        this.value = value;
        this.timestamp = timestamp;
        this.expire = expire;
        this.group = group;
    }
    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
    public Long getTimestamp() {
        return timestamp;
    }
    public T getKey() {
        return key;
    }
    public void setKey(T key) {
        this.key = key;
    }
    public V getValue() {
        return value;
    }
    public void setValue(V value) {
        this.value = value;
    }
    public int getExpire() {
        return expire;
    }
    public void setExpire(int expire) {

        this.expire = expire;
    }
    /**
     * 获取剩余时间
     *
     * @return
     */
    public int ttl() {
        return this.expire - getTime();
    }
    /**
     * 获取当前时间和元素的相差时间(存活时间)
     *
     * @return
     */
    private int getTime() {
        Long current = System.currentTimeMillis();
        Long value = current - this.timestamp;
        return (int) (value / 1000) + 1;
    }
    /**
     * 是否有效
     *
     * @return
     */
    public boolean isExpire() {
        if (getTime() > this.expire) {
            // 失效了就移除
            group.delete(key);
            return false;
        }
        return true;
    }
}

Group

package com.panda.base.utils.cache;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
/**
 * 组操作,内部数据有序队列
 */
public class Group<T, V> {
    private ArrayBlockingQueue<CacheEntity<T, V>> queue;// 缓存队列
    private Integer capacity;
    public Group(int capacity) {
        queue = new ArrayBlockingQueue<>(capacity);
        this.capacity = capacity;
    }
    /**
     * 尾部进。 如果容量已满,则移除距过期时间最短的
     *
     * @param object
     * @param second
     */
    public void push(T key, V object, int second) {
        // 放入队列
        if (!queue.offer(new CacheEntity(key, object, System.currentTimeMillis(), second, this))) {
            // 做一次清除
            getCacheEntities();
            if (!queue.offer(new CacheEntity(key, object, System.currentTimeMillis(), second, this))) {
                int ttf = Integer.MAX_VALUE;
                CacheEntity maxVtfCacheEntity = null;
                Iterator<CacheEntity<T, V>> iterator = queue.iterator();
                while (iterator.hasNext()) {
                    CacheEntity cacheEntity = iterator.next();
                    if (cacheEntity.ttl() < ttf) {
                        ttf = cacheEntity.ttl();
                        maxVtfCacheEntity = cacheEntity;
                    }
                }
                if (maxVtfCacheEntity != null && this.queue.remove(maxVtfCacheEntity))
                    queue.offer(new CacheEntity(key, object, System.currentTimeMillis(), second, this));
            }
        }
    }
    /**
     * 尾部进. 默认失效时间10分钟
     *
     * @param object
     */
    public void push(T key, V object) {
        push(key, object, 600);
    }
    /**
     * 返回并移除头部出
     *
     * @return
     */
    public V poll() {
        CacheEntity<T, V> entity = queue.poll();
        // 如果有效期超过,返回null
        if (!entity.isExpire()) {
            return null;
        }
        return entity.getValue();
    }
    /**
     * 返回头部元素并放到末尾
     *
     * @return
     */
    public V rPoll() {
        CacheEntity<T, V> entity = queue.poll();
        // 如果有效期超过,返回null
        if (!entity.isExpire()) {
            return null;
        }
        V object = entity.getValue();
        queue.offer(entity);
        return object;
    }
    /**
     * 通过key寻找有效的缓存实体
     *
     * @param key
     * @return
     */
    private CacheEntity find(T key) {
        synchronized (queue) {
            Iterator<CacheEntity<T, V>> iterator = queue.iterator();
            while (iterator.hasNext()) {
                CacheEntity entity = iterator.next();
                if (key.equals(entity.getKey())) {
                    return entity;
                }
            }
            return null;
        }
    }
    /**
     * 删除key
     *
     * @param key
     */
    public void delete(T key) {
        synchronized (queue) {
            CacheEntity<T, V> entity = find(key);
            if (entity != null) {
                queue.remove(entity);
            }
        }
    }
    /**
     * 根据key获取
     *
     * @param key
     * @return
     */
    public V getValue(T key) {
        CacheEntity<T, V> entity = find(key);
        if (entity != null && entity.isExpire()) {
            return entity.getValue();
        }
        return null;
    }
    /**
     * 获取有效的缓存实体
     * 移除所有过期的缓存实体。
     *
     * @return
     */
    private List<CacheEntity<T, V>> getCacheEntities() {
        List<CacheEntity<T, V>> keys = new ArrayList<CacheEntity<T, V>>();
        Iterator<CacheEntity<T, V>> iterator = queue.iterator();
        while (iterator.hasNext()) {
            CacheEntity cacheEntity = iterator.next();
            if (cacheEntity.isExpire()) {
                keys.add(cacheEntity);
            }
        }
        return keys;
    }
    /**
     * 获取key列表
     *
     * @return
     */
    public List<T> getKeys() {
        List<T> keys = new ArrayList<T>();
        List<CacheEntity<T, V>> caches = getCacheEntities();
        for (CacheEntity<T, V> cacheEntity : caches) {
            keys.add(cacheEntity.getKey());
        }
        return keys;
    }
    /**
     * 获取值列表
     *
     * @return
     */
    public List<V> getValues() {
        List<V> values = new ArrayList<V>();
        List<CacheEntity<T, V>> caches = getCacheEntities();
        for (CacheEntity<T, V> cacheEntity : caches) {
            values.add(cacheEntity.getValue());
        }
        return values;
    }
    /**
     * 查看元素存活时间,-1 失效,0 长期有效
     *
     * @param key
     * @return
     */
    public int ttl(T key) {
        CacheEntity entity = find(key);
        if (entity != null) {
            return entity.ttl();
        }
        return -1;
    }
    /**
     * 返回头部的元素
     *
     * @return
     */
    public V peek() {
        CacheEntity<T, V> entity = queue.peek();
        if (entity != null) {
            return entity.getValue();
        }
        return null;
    }
    /**
     * 设置元素存活时间
     *
     * @param key
     * @param second
     */
    public void expire(T key, int second) {
        CacheEntity entity = find(key);
        if (entity != null) {
            entity.setTimestamp(System.currentTimeMillis());
            entity.setExpire(second);
        }
    }
    /**
     * 查看key是否存在
     *
     * @param key
     * @return
     */
    public boolean exist(T key) {
        CacheEntity<T, V> entity = find(key);
        if (entity == null) return false;
        return entity.isExpire();
    }
    /**
     * 查看组是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return queue.isEmpty();
    }
    /**
     * 获取存活元素的大小
     *
     * @return
     */
    public int size() {
        return getCacheEntities().size();
    }
    /**
     * 获取容量
     *
     * @return
     */
    public Integer getCapacity() {
        return capacity;
    }
}

GroupCacheFactory简单的内存缓存实现,现group概念,一个group里面是个有序的集合, 集合支持key-value expire弥补redis list的不足。

 

package com.panda.base.utils.cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedHashMap;
import java.util.Map;
public class GroupCacheFactory {
    private final static Logger log = LoggerFactory.getLogger(GroupCacheFactory.class);
    // 数据容器
    private Map<String, Object> container;
    public GroupCacheFactory() {
        container = new LinkedHashMap<String, Object>();
    }
    /**
     * 如果组存在就返回,不存在就创建,保证不为null
     *
     * @param key
     * @return
     */
    public Group group(String key, int capacity) {
        Group group = null;
        Object entry = container.get(key);
        if (entry != null) {
            group = (Group) entry;
        } else {
            group = new Group(capacity);
            container.put(key, group);
        }
        return group;
    }
    /**
     * 如果组存在就返回,不存在就创建,默认容量1000
     *
     * @param key
     * @return
     */
    public Group group(String key) {
        return this.group(key, 100000);
    }
    public void clearExpiredCache() {
        container.keySet().forEach(key -> {
            log.debug("Cache:   key=" + key + "  size=" + ((Group) container.get(key)).size());
        });
    }
}

接着就是jwt权限认证的一个实体类和获取token加解密的生成方法。

1.JwtSubject

package com.panda.base.utils.jwt;
import com.alibaba.fastjson.JSON;
import java.time.LocalDateTime;
public class JwtSubject {
    private Long usId;
    private String uuId;
    private String userRole;
    private String clientId;
    private LocalDateTime loginTime;
    private JwtSubject() {
    }
    public JwtSubject(Long usId, String userRole, String clientId) {
        this(usId, null, userRole, clientId);
    }
    public JwtSubject(String uuId, String userRole, String clientId) {
        this(null, uuId, userRole, clientId);
    }
    public JwtSubject(Long usId, String uuId, String userRole, String clientId) {
        this.usId = usId;
        this.uuId = uuId;
        this.userRole = userRole;
        this.clientId = clientId;
        this.loginTime = LocalDateTime.now();
    }
    public String getUuId() {
        return uuId;
    }
    public void setUuId(String uuId) {
        this.uuId = uuId;
    }
    public String getUserRole() {
        return userRole;
    }
    public void setUserRole(String userRole) {
        this.userRole = userRole;
    }
    public String getClientId() {
        return clientId;
    }
    public void setClientId(String clientId) {
        this.clientId = clientId;
    }
    public LocalDateTime getLoginTime() {
        return loginTime;
    }
    public void setLoginTime(LocalDateTime loginTime) {
        this.loginTime = loginTime;
    }
    public static JwtSubject toSubject(String subStr) {
        return JSON.parseObject(subStr, JwtSubject.class);
    }
    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
    public Long getUsId() {
        return usId;
    }
    public void setUsId(Long usId) {
        this.usId = usId;
    }
}

根据jwt实体生成token以及对token反解密,JwtUtils

 

package com.panda.base.utils.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.panda.base.utils.TimeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
public class JwtUtils {
    private final static Logger log = LoggerFactory.getLogger(JwtUtils.class);
    /**
     * @param userId   用户自增ID,没有可传null
     * @param uuId     用户uuId,没有可传null
     * @param userRole 用户身份分类,例如: ADMIN,USER
     * @param clientId 客户端标识。
     * @param expired  过期时间,毫秒。
     * @return
     */
    public static String token(Long userId, String uuId, String userRole, String clientId, long expired) {
        JwtSubject jwtSubject = new JwtSubject(userId, uuId, userRole, clientId);
        return jwtToken(jwtSubject, expired);
    }
    public static String token(Long userId, String uuId, String userRole, String clientId) {
        return token(userId, uuId, userRole, clientId, TimeUtils.YEAR * 10);
    }
    public final static String SECRET = "fadffdaldfkjafdja_k32423535";
    public static JwtSubject verify(String jwtToken) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).withIssuer("auth0").build();
            JWT jwt = (JWT) verifier.verify(jwtToken);
            return JwtSubject.toSubject(jwt.getSubject());
        } catch (InvalidClaimException e) {
            log.error("InvalidClaimException e"+e.getMessage());
        } catch (JWTVerificationException e) {
            log.error("JWTVerificationException e"+e.getMessage());
        } catch (UnsupportedEncodingException e) {
            log.error("UnsupportedEncodingException e"+e.getMessage());
        }
        return null;
    }
    public static JwtSubject decode(String token) {
        JWT jwt = JWT.decode(token);
        return JwtSubject.toSubject(jwt.getSubject());
    }
    public static String jwtToken(JwtSubject subject, long expireTime) {
        try {
            /* 获取一分钟前的时间,作为token的产生时间,防止服务器时间不一致,导致token校验失败 */
            Calendar beforeTime = Calendar.getInstance();
            beforeTime.add(Calendar.MINUTE, -1);// 1分钟之前的时间
            Date beforeD = beforeTime.getTime();
            /* 计算token过期 */
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(calendar.getTimeInMillis() + expireTime);
            String token = JWT.create()
                    .withSubject(subject.toString())
                    .withIssuedAt(beforeD)
                    .withExpiresAt(calendar.getTime())
                    .withIssuer("auth0")
                    .sign(Algorithm.HMAC256(SECRET));
            return token;
        } catch (JWTCreationException exception) {
            log.error("生成jwtToken异常", exception);
        } catch (UnsupportedEncodingException e) {
            log.error("生成jwtToken异常", e);
        }
        return null;
    }
    public static void main(String[] args) {
        System.out.println("long max is " + Long.MAX_VALUE);
        System.out.println("int max is " + Integer.MAX_VALUE);
        System.out.println("short max is " + Short.MAX_VALUE);
        JwtSubject subject = new JwtSubject(32434L, "234242342535435345345345253243", "ANONYMITY", "default");
        String token = jwtToken(subject, TimeUtils.YEAR * 10);
        System.out.println(token);
        System.out.println(verify(token));
    }
}

运行main方法我们看运行结果

基于这些我们在后边的权限框架中就可以专注业务实现了。

本节内容就到这,下一篇我会讲讲每个业务层的基础封装以及auth权限框架编写sso单点登录系统。源码可以关注“蛋皮皮”公众号回复“大熊猫分布式组件”进行获取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值