美文网首页
大熊猫分布式组件开发系列教程(二)

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

作者: 蛋皮皮652 | 来源:发表于2020-11-19 20:25 被阅读0次

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

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

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

package com.panda.base.jpa.dao;

public class SortParam {

private Stringkey;

    private Orderorder = Order.ASC;

    public StringgetKey() {

return key;

    }

    public void setKey(String key) {

this.key = key;

    }

    public OrdergetOrder() {

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 Stringkey;

    private Objectvalue;

    private Logiclogic = Logic.Contain;

    /**

    * 括号内部的连接方式

    */

    private LinkModeinnerLinkMode = 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 LinkModegetInnerLinkMode() {

return innerLinkMode;

    }

public void setInnerLinkMode(LinkMode innerLinkMode) {

this.innerLinkMode = innerLinkMode;

    }

public StringgetKey() {

return key;

    }

public void setKey(String key) {

this.key = key;

    }

public ObjectgetValue() {

return value;

    }

public void setValue(Object value) {

this.value = value;

    }

public LogicgetLogic() {

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 CacheEntityimplements Serializable {

private static final long serialVersionUID =2082223810638865724L;

    private T key; // key

    private V value;// 值

    private Longtimestamp;// 缓存的时候存的时间戳,用来计算该元素是否过期

    private int expire = Integer.MAX_VALUE; // 默认长期有效

    private Groupgroup;// 容器

    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 LonggetTimestamp() {

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 {

private ArrayBlockingQueue>queue;// 缓存队列

    private Integercapacity;

    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> 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 entity =queue.poll();

        // 如果有效期超过,返回null

        if (!entity.isExpire()) {

return null;

        }

return entity.getValue();

    }

/**

    * 返回头部元素并放到末尾

    *

    * @return

    */

    public V rPoll() {

CacheEntity entity =queue.poll();

        // 如果有效期超过,返回null

        if (!entity.isExpire()) {

return null;

        }

V object = entity.getValue();

        queue.offer(entity);

        return object;

    }

/**

    * 通过key寻找有效的缓存实体

    *

    * @param key

    * @return

    */

    private CacheEntityfind(T key) {

synchronized (queue) {

Iterator> 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 entity = find(key);

            if (entity !=null) {

queue.remove(entity);

            }

}

}

/**

    * 根据key获取

    *

    * @param key

    * @return

    */

    public V getValue(T key) {

CacheEntity entity = find(key);

        if (entity !=null && entity.isExpire()) {

return entity.getValue();

        }

return null;

    }

/**

    * 获取有效的缓存实体

    * 移除所有过期的缓存实体。

    *

    * @return

    */

    private List>getCacheEntities() {

List> keys =new ArrayList>();

        Iterator> iterator =queue.iterator();

        while (iterator.hasNext()) {

CacheEntity cacheEntity = iterator.next();

            if (cacheEntity.isExpire()) {

keys.add(cacheEntity);

            }

}

return keys;

    }

/**

    * 获取key列表

    *

    * @return

    */

    public ListgetKeys() {

List keys =new ArrayList();

        List> caches = getCacheEntities();

        for (CacheEntity cacheEntity : caches) {

keys.add(cacheEntity.getKey());

        }

return keys;

    }

/**

    * 获取值列表

    *

    * @return

    */

    public ListgetValues() {

List values =new ArrayList();

        List> caches = getCacheEntities();

        for (CacheEntity 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 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 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 IntegergetCapacity() {

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 Loggerlog = LoggerFactory.getLogger(GroupCacheFactory.class);

    // 数据容器

    private Mapcontainer;

    public GroupCacheFactory() {

container =new LinkedHashMap();

    }

/**

    * 如果组存在就返回,不存在就创建,保证不为null

*

    * @param key

    * @return

    */

    public Groupgroup(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 Groupgroup(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 LongusId;

    private StringuuId;

    private StringuserRole;

    private StringclientId;

    private LocalDateTimeloginTime;

    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 StringgetUuId() {

return uuId;

    }

public void setUuId(String uuId) {

this.uuId = uuId;

    }

public StringgetUserRole() {

return userRole;

    }

public void setUserRole(String userRole) {

this.userRole = userRole;

    }

public StringgetClientId() {

return clientId;

    }

public void setClientId(String clientId) {

this.clientId = clientId;

    }

public LocalDateTimegetLoginTime() {

return loginTime;

    }

public void setLoginTime(LocalDateTime loginTime) {

this.loginTime = loginTime;

    }

public static JwtSubjecttoSubject(String subStr) {

return JSON.parseObject(subStr, JwtSubject.class);

    }

@Override

    public StringtoString() {

return JSON.toJSONString(this);

    }

public LonggetUsId() {

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 Loggerlog = LoggerFactory.getLogger(JwtUtils.class);

    /**

    * @param userId  用户自增ID,没有可传null

    * @param uuId    用户uuId,没有可传null

    * @param userRole 用户身份分类,例如: ADMIN,USER

    * @param clientId 客户端标识。

    * @param expired  过期时间,毫秒。

    * @return

    */

    public static Stringtoken(Long userId, String uuId, String userRole, String clientId, long expired) {

JwtSubject jwtSubject =new JwtSubject(userId, uuId, userRole, clientId);

        return jwtToken(jwtSubject, expired);

    }

public static Stringtoken(Long userId, String uuId, String userRole, String clientId) {

return token(userId, uuId, userRole, clientId, TimeUtils.YEAR *10);

    }

public final static StringSECRET ="fadffdaldfkjafdja_k32423535";

    public static JwtSubjectverify(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 JwtSubjectdecode(String token) {

JWT jwt = JWT.decode(token);

        return JwtSubject.toSubject(jwt.getSubject());

    }

public static StringjwtToken(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单点登录系统。源码可以关注“蛋皮皮”公众号回复“大熊猫分布式组件”进行获取。

相关文章

网友评论

      本文标题:大熊猫分布式组件开发系列教程(二)

      本文链接:https://www.haomeiwen.com/subject/vxnliktx.html