千家信息网

如何自定义guava cache存储token

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇内容介绍了"如何自定义guava cache存储token"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学
千家信息网最后更新 2026年11月02日如何自定义guava cache存储token

本篇内容介绍了"如何自定义guava cache存储token"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

项目模块分析

项目主要分为七大模块:用户模块、商品模块、订单模块、分类模块、购物车模块、收货地址模块以及支付模块。

功能分析

核心模块

高复用的服务响应对应的设计思想和封装

用户模块

解决横向越权和纵向越权的问题,用户密码使用MD5明文加密,guava缓存实现信息的存储,用户功能主要包括:注册、登录、检测用户名是否有效,密码的重置,更新用户信息等等...

用户忘记密码以及密码提示问题和答案设计

当用户忘记密码需要重置密码的时候,需要输入注册时设置的密码提示问题和问题答案,比如:你的生日是什么时候? 1996-08-28,修改密码的时候需要校验密保问题和答案时候相一致,shopping-mall_v1.0的时候,我们采用guava cache来存储一个forgetToken,比设置token的有效期为30分钟(可根据项目场景选择),在重置密码的时候需要传递参数有:username,password,forgetToken三个参数,这时候需要判断在guava获取tokenCache里面的token和传进来的forgetToken是否一致,满足一致条件才能重置密码成功!

自定义guava cache存储token
public class TokenCache {    //创建logback的logger    private static Logger logger = LoggerFactory.getLogger(TokenCache.class);    //生成token的前缀    public static final String TOKEN_PREFIX = "token_";    //声明一个静态的内存块,guava里面的本地缓存    public static LoadingCache localCache =            //构建本地缓存,调用链的方式,initialCapacity是缓存的初始化容量,            // maxSize是缓存设置的最大内存容量,expireAfterAccess设置缓存的有效期为12个小时            CacheBuilder.newBuilder()            .initialCapacity(1000)            .maximumSize(10000)            .expireAfterAccess(12, TimeUnit.HOURS)                    //build里面要实现一个匿名内部类                .build((new CacheLoader() {                    //这个方法是默认的数据加载实现,当get的时候,如果key没有对应的值,就调用这个方法进行加载                    @Override                    public String load(String key) throws Exception {                        //为什么要把return的null值写成字符串,因为到时候用null去.equal的时候,会报空指针异常                        return "null";                    }            }));    //添加本地缓存    public static void setKey(String key,String value){        localCache.put(key,value);    }    //得到本地缓存    public static String getValue(String key){        String value =null;        try {            value = localCache.get(key);            if ("null".equals(value)){                return null;            }            return value;        }catch (ExecutionException e){            logger.error("获取缓存getKey()方法错误",e);        }        return null;    }}

商品模块

POJO、VO抽象模型的设计,高效的分页以及动态排序,使用FTP服务对接,富文本上传商品图片信息,商品模块比较重要的就是商品的搜索以及动态排序和商品分页,比如:根据关键字后台进行模糊查询,根据价格升序/降序排列,商品的分页主要集成 pagehelper 分页插件来完成,改分页插件实现数据分页相对高效,实用起来也比较简单,我们只需要使用PageHelper.startPage(pageNum,pageSize) 即可实现

订单模块

安全漏洞解决方案,考虑电商商品订单号的生成规则,订单状态的分析和订单枚举常量的设计,订单的超时关单处理(延时队列)

创建订单OrderVO类的封装,封装返回创建订单的所有信息,包括:订单信息,订单明细信息(List),地址信息,创建订单时需要校验购物车商品的状态/数量,比如是否已下架,是否库存不足,校验成功才允许下单,下单成功之后需要减库存操作,需要遍历每一个订单Item,通过orderItem的productId获取到对应商品,执行product.getStock() - product.getQuantity();操作;

订单号的生成规则(时间戳+随机数的方式):
/**     * orderNo生成方式     *     * @return     */    private long generateOrderNo() {        //获取当前时间戳        long currentTime = System.currentTimeMillis();        //时间+[0,1000)之间的数即[0,999]        return currentTime + new Random().nextInt(1000);      }
定时关单,hour小时以内未付款的订单,进行自动关闭

相关实现逻辑:首先先获取前hour小时的订单,查询出这些订单里面为付款的订单,查询到这些订单之后,拿到即将关闭订里的商品和数量,取消订单时候库存需要加上商品数量(也就是库存还原),最后再设置订单状态。

 @Override public void closeOrder(int hours) {        //前hour小时的订单        Date closeDateTime = DateUtils.addHours(new Date(), -hours);        List orderList = orderMapper.selectOrderStatusByCreateTime(Constant.OrderStatusEnum.NO_PAY.getCode(), dateToStr(closeDateTime));        for (Order order : orderList) {            List orderItemList = orderItemMapper.getByOrderNo(order.getOrderNo());            for (OrderItem orderItem : orderItemList) {                //拿到即将要被关闭商品的和数量:一定要用主键where条件,防止锁表,同时必须支持MySQL的InnoDB引擎                Integer stock = productMapper.selectStockByProductId(orderItem.getProductId());                //考虑到已生成订单里的商品已被删除,这时候就不必更新了                if (stock == null) {                    continue;                }                Product product = new Product();                product.setId(orderItem.getProductId());                product.setStock(stock + orderItem.getQuantity());                productMapper.updateByPrimaryKeySelective(product);            }            orderMapper.closeOrderByOrderId(order.getId());            log.info("关闭订单orderNo:{}", order.getOrderNo());        }    }

分类模块

采用递归算法,复杂对象的排重,无限层级的树状结构的设计

获取分类子节点(平级):当父及分类parentId传0的时候,查找的是跟节点的子分类

获取分类id及递归子节点分类id(返回本身以及它下面的子节点,假设0->10->100->1000,0的下一级子孩子节点为10,10的下一级节点为100,100的下一级节点为1000,业绩是返回:0(本身)->10->100->100),设计到递归查询算法,算法设计如下:

/**  * 递归查询本节点的id以及孩子节点的id逻辑实现  *  * @param categoryId  * @return  */  @Override  public ServerResponse> selectCategoryAndChildrenById(Integer categoryId) {        Set categorySet = Sets.newHashSet();        this.findChildCategoryRecursive(categorySet, categoryId);        //最后是返回categoryId        List categoryIdList = Lists.newArrayList();        if (categoryId != null) {            for (Category categoryItem : categorySet) {                categoryIdList.add(categoryItem.getId());            }        }        return ServerResponse.createBySuccess(categoryIdList);    }/**  * 递归查询算法,自己调自己,我们使用Set集合做返回,可以排重,这里要重写Category的HashCode和equals  * 的两个方法为什么呢?当两个对象相同,即equals返回true,则他们的hashCode一定相同,但是当两个对象的  * hashCode相同,两个对象不一定相同,所以,得出结论当使用Set集合的时候,注意要重写equals和hashCode  * 两个方法。  */  private Set findChildCategoryRecursive(Set categorySet, Integer categoryId) {        Category category = categoryMapper.selectByPrimaryKey(categoryId);        if (category != null) {            categorySet.add(category);        }        //递归算法,查找子节点        List categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);        for (Category categoryItem : categoryList) {            //自己调用自己            findChildCategoryRecursive(categorySet, categoryItem.getId());        }        return categorySet;    }//mapper

购物车模块

购物车模块核高复用的逻辑方法的封装,商品总价的计算复用和封装,使用BigDecimal类型解决商业运算丢失精度的问题,购物车的单选/反选,全选/全反选功能,一个购物车里面包括多个商品,添加购物车时需要校验购买的每个商品数量是否超过库存,超过库存这时候,购买的数量不能设为用户选择的数量,而是选择库存数量,计算价格的时候也只能按照现有库存数量乘以单价的方式计算总额。

收货地址模块

数据绑定和对象绑定,越权问题的升级个巩固,删除地址的时候为了防止横向越权我们不能只传一个shippingId,因此不能世界使用mybatis生成的deleteByPrimaryKey()的方法来删除,试想:当用户处于登陆状态的时候,如果只需要传一个shippingId就能实现删除的时候,那当传的不是个人的shippingId就会产生越权问题,也就是所谓的横向越权,为了防止横向越权我们需要自定义一个方法将收获地址和用户绑定,比如:自定义deleteByUserIdAndShippingId()方法来实现。(地址的更新也是一样的道理)

支付模块

支付宝SDK源码解析,分析了支付宝支付Demo的支付流程,将支付宝集成到项目中,包括:支付二维码的生成,扫码支付,支付的逻辑是:

第一步:查看订单的支付状态,如果order.getStatus()<=Constant.OrderStatusEnum.PAID.getCode()时,才满足支付条件

第二步:支付,采用支付宝当面付,需要生成支付二维码,其实这一步的关键就是创建扫描支付的请求biulder,通过builder来设置请求参数,首先会调用需下单的接口,判断预下单是否生成,如果预下单成功之后,需要将订单的状态修改为已支付,接着下单成功之后,会返回支付二维码,这是集成支付的比较关键的一步,我们需要做的就是保存这个支付二维码并上传到ftp服务器,最后返回一个二维码访问地址qrUrl给前端展示给用户,用户扫描对应的支付二维码即可支付订单,支付完成之后需要作支付宝回调处理,更新对应的订单状态为已支付,更新订单的支付方式。

支付宝官方支付场景过程说明:

1. 用户扫码

2.调用alipay.trade.precreate()请求生成二维码连接 -> 将二维码连接转二维码图片

3. 输入支付密码完成支付 -> 返回支付成功信息 -> 若支付成功,则返回异步信息(商户返回success)

4.调用alipay.trade.query()查询订单状态 -> 但会查询结果 -> 若返回支付成功(code=10000),则流程结束

5.若未在指定时间内未完成支付 -> 调用alipay.trade.cancel进行交易关闭

"如何自定义guava cache存储token"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

支付 订单 模块 商品 时候 用户 密码 节点 生成 信息 数量 方法 缓存 二维 二维码 成功 库存 状态 问题 查询 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网 广州大一互联网络科技有限公司 互联网科技工作委员会 互联网佳科技有限公司 涨乐互联网科技 互联网科技开发公司 科技制造互联网公司 青岛互联网科技公司 为想互联网科技 远信互联网科技 伴你行互联网科技有限公司 郑州华宇互联网科技 互联网科技公司营业执照怎么办理 科技互联网的核心竞争力 互联网科技包装股份有限公司上市 宁波跨境商互联网科技有限公司 互联网科技接地气 北京品多多互联网科技有限公司 科技互联网专业务虚会材料 互联网高科技绘画 广东猪兼强互联网科技有限公司 苏州找大状互联网科技有限公司 互联网科技股票 兼蜜互联网科技 成都玖崟互联网科技有限公司乐商圈怎么样 科技互联网大厂 深圳育鹏互联网科技有限公司招聘 南通创西澳互联网科技有限公司 云南互联网科技学费 伍佰万互联网科技是干嘛的
0