中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何自定義guava cache存儲token

發布時間:2021-12-16 09:20:43 來源:億速云 閱讀:181 作者:iii 欄目:大數據

本篇內容介紹了“如何自定義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<String,String> localCache =
            //構建本地緩存,調用鏈的方式,initialCapacity是緩存的初始化容量,
            // maxSize是緩存設置的最大內存容量,expireAfterAccess設置緩存的有效期為12個小時
            CacheBuilder.newBuilder()
            .initialCapacity(1000)
            .maximumSize(10000)
            .expireAfterAccess(12, TimeUnit.HOURS)
                    //build里面要實現一個匿名內部類
                .build((new CacheLoader<String, String>() {
                    //這個方法是默認的數據加載實現,當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<OrderItemVO>),地址信息,創建訂單時需要校驗購物車商品的狀態/數量,比如是否已下架,是否庫存不足,校驗成功才允許下單,下單成功之后需要減庫存操作,需要遍歷每一個訂單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<Order> orderList = orderMapper.selectOrderStatusByCreateTime(Constant.OrderStatusEnum.NO_PAY.getCode(), dateToStr(closeDateTime));
        for (Order order : orderList) {
            List<OrderItem> 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<List<Integer>> selectCategoryAndChildrenById(Integer categoryId) {
        Set<Category> categorySet = Sets.newHashSet();
        this.findChildCategoryRecursive(categorySet, categoryId);
        //最后是返回categoryId
        List<Integer> 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<Category> findChildCategoryRecursive(Set<Category> categorySet, Integer categoryId) {
        Category category = categoryMapper.selectByPrimaryKey(categoryId);
        if (category != null) {
            categorySet.add(category);
        }
        //遞歸算法,查找子節點
        List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
        for (Category categoryItem : categoryList) {
            //自己調用自己
            findChildCategoryRecursive(categorySet, categoryItem.getId());
        }
        return categorySet;
    }


//mapper
<select id="selectCategoryChildrenByParentId" parameterType="int" resultMap="BaseResultMap">
    select <include refid="Base_Column_List"/> from tb_category
    where parent_id = #{parentId}
</select>

購物車模塊

購物車模塊核高復用的邏輯方法的封裝,商品總價的計算復用和封裝,使用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

“如何自定義guava cache存儲token”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

承德县| 澎湖县| 贞丰县| 贺州市| 锡林浩特市| 定兴县| 高唐县| 陆川县| 高邑县| 资讯| 涞源县| 萝北县| 长宁区| 遂平县| 昌邑市| 北碚区| 上犹县| 望都县| 车险| 黄陵县| 成武县| 北安市| 武安市| 丰顺县| 汶上县| 区。| 崇阳县| 乌兰浩特市| 大姚县| 天镇县| 兴山县| 鹤岗市| 望城县| 彝良县| 辽阳市| 永善县| 长葛市| 兰州市| 铁岭县| 江门市| 凤山县|