蒼穹外賣心得體會

1 登錄認證

技術點:JWT令牌技術(JSON Web Token)

JWT(JSON Web Token)是一種令牌技術,主要由三部分組成:Header頭部、Payload載荷和Signature簽名。Header頭部存儲令牌的類型(如JWT)和使用的加密算法(如HS256)。Payload載荷包含具體信息,如用戶身份、權限、過期時間等聲明(Claims)。Signature簽名通過加密算法對Header和Payload進行簽名,用于驗證數據完整性和發行者身份。

在實際業務中,用戶登錄時,后端服務器接收客戶端請求并解析傳遞的登錄信息,驗證用戶名和密碼是否正確。若驗證成功,服務器生成JWT令牌返回給前端。后端無需存儲Token,只需保存密鑰(Secret Key)。后續請求時,服務器通過攔截器在請求前攔截,提取JWT并進行解析與驗證:首先檢查簽名是否有效(防止篡改),再校驗Payload中的聲明(如是否過期、權限是否有效)。驗證通過后,放行請求并執行業務邏輯。

Session與Token的對比

2 分頁查詢

PageHelper是一個基于MyBatis的分頁插件,通過攔截MyBatis的執行器實現分頁功能。

當調用 PageHelper.startPage() 設置分頁參數后,MyBatis 會通過其攔截器機制自動觸發分頁邏輯,動態修改后續的 SQL 語句以實現分頁。

分頁參數通過 ThreadLocal 存儲到當前線程的上下文中(PageContext),確保同一線程內的后續操作可獲取這些參數。PageHelper 在處理完當前 SQL 后,自動清除 ThreadLocal 中的分頁參數,因此同一線程后續的查詢不會被分頁,除非再次調用 startPage()

    /*** 分頁查詢套餐** @param setmealPageQueryDTO* @return*/@Overridepublic PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {int pageNum = setmealPageQueryDTO.getPage();int pageSize = setmealPageQueryDTO.getPageSize();PageHelper.startPage(pageNum, pageSize);Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);return new PageResult(page.getTotal(), page.getResult());}
-- 原始SQL
SELECT * FROM table;
-- 重寫后(MySQL示例)
SELECT * FROM table LIMIT offset, pageSize;

3 MVC當中的參數注解

1 @RequestBoby:綁定HTTP請求體,反序列化為java對象。-(JSON,XML)

2 @RequestParam:綁定查詢參數。(URL后-問號傳參,參數用???分隔,參數間用?&?連接。)

3 @PathVariable:綁定URL路徑變量。(URL中-路徑傳參,參數用用?{}?包裹,/連接。)

4 @RequestHeader :綁定HTTP請求頭。

5 @CookieValue:綁定Cookie

4 ThreadLocal

ThreadLocal是Java中的一個線程變量,它可以為每個線程提供一個獨立的變量副本。ThreadLocal實例是共享的,但每個線程通過它訪問的是自己的ThreadLocalMap中的值。

ThreadLocal的主要作用是在多線程的環境下提供線程安全的變量訪問。它常用于解決線程間數據共享的問題,特別是在并發編程中,當多個線程需要使用同一個變量時,可以使用ThreadLocal確保每個線程訪問的都是自己的變量副本,從而避免了線程安全問題。

ThreadLocal底層是通過ThreadLocalMap來實現的,每一個Thread(線程)對象中都存在一個ThreadLocalMap,Map的key為ThreadLocal對象,Map的value為需要緩存的值。

static修飾的ThreadLocal對象屬于類級別,在JVM的整個生命周期中僅初始化一次,后續所有的線程通過BaseContext.threadLocal訪問同一個ThreadLocal實例,但每個線程的變量副本獨立存儲,避免重復創建對象。

內存泄漏問題:當ThreadLocal對象使用完之后,應該將Entry對象(即key和value)回收。而線程對象是通過強引用指向ThreadLocalMap,ThreadLocalMap也是通過強引用指向Entry對象。在Entry中,key是弱引用,會觸發自動回收機制,但value是強引用不會自動回收,最終導致Entry整體無法被回收機制回收。最終導致線程池中的線程因ThreadLocalMap未清理而出現內存泄漏。解決方法是手動調用ThreadLocal的remove()方法,清除Entry對象。

package com.sky.context;public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}}

示例:

public class ThreadLocalExample {// 定義一個ThreadLocal變量private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();public static void main(String[] args) {// 線程A設置值Thread threadA = new Thread(() -> {threadLocal.set(100); // 線程A的值為100System.out.println("線程A的值:" + threadLocal.get()); // 輸出100});// 線程B嘗試獲取值Thread threadB = new Thread(() -> {System.out.println("線程B的值:" + threadLocal.get()); // 輸出null(未設置時默認值)threadLocal.set(200); // 線程B的值為200System.out.println("線程B的值:" + threadLocal.get()); // 輸出200});threadA.start();threadB.start();}
}

項目當中便可使用這個來存儲用戶的id值其可全局獲取,并且不需要多次實例化對象,在jwt校驗結束便可設置。

5 @JSONFormat

在業務需求當中可能會出現前端給我們傳遞過來的時間參數,其格式不一定符合我們變量的格式。

因此我們需要對前端的時間參數進行格式化,將前端傳遞的參數指定為pattern當中的參數格式。

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;

6 基于注解和AOP的公共字段填充

在業務開發中,由于存在大量數據表且字段重疊較多,我們可以使用AOP技術結合注解技術對公共字段進行填充,從而減少代碼的冗雜性。

首先,我們需要創建一個自定義注解,用于標記需要自動填充公共字段的方法。

注解:AutoFill

注解的目的作用在Mapper業務層,對那些需要對數據庫操作的進行字段填充。

package com.sky.annotation;import com.sky.enumeration.OperationType;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定義注解,用于標識需要自動填充的字段*/// 標識在方法上
@Target(ElementType.METHOD)
// 標識在運行時
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//數據庫操作類型 UPDATE INSERTOperationType value();}

然后,AOP切面攔截這些注解的方法

切面:AutoFillAspect

使用的是前置通知,目標方法執行前自動調用,攔截帶有@AutoFill的方法,業務當中通過反射的思想進行字段賦值。

package com.sky.aspect;import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.time.LocalDateTime;/*** 自定義切面,用于自動填充公共字段處理邏輯*/@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入點表達式 com.sky.mapper 包下的所有類中的所有方法并且有 @AutoFill 注解的方法*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut() {}/*** 前置通知,在目標方法執行前執行*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint) {log.info("開始進行公共字段自動填充...");// 通過方法簽名獲取方法上的注解MethodSignature signature = (MethodSignature) joinPoint.getSignature();AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); // 關鍵修改if (autoFill == null) {log.info("當前方法沒有 @AutoFill 注解,不需要自動填充");return;}OperationType operationType = autoFill.value();//數據庫操作類型//獲取當前杯攔截的方法的參數--實體對象Object[] args = joinPoint.getArgs();if (args == null || args.length == 0) {log.info("當前方法沒有參數,不需要自動填充");return;}Object entity = args[0];log.info("當前自動填充的實體對象:{}", entity.toString());//準備賦值的數據LocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();log.info("當前操作的用戶id:{}", currentId);//根據當前不同的操作類型,為對應的實體對象通過反射來賦值if (operationType == OperationType.INSERT) {//四個公共字段:createTime、createUser、updateTime、updateUser賦值try {//獲取當前實體類中的對應方法(使用本地的常量方法名)Method createTimeMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method createUserMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method updateTimeMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method updateUserMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通過反射為實體對象賦值createTimeMethod.invoke(entity, now);createUserMethod.invoke(entity, currentId);updateTimeMethod.invoke(entity, now);updateUserMethod.invoke(entity, currentId);log.info("為實體類 {} 賦值成功", entity);} catch (Exception e) {e.printStackTrace();}} else if (operationType == OperationType.UPDATE) {try {//兩個公共字段:updateTime、updateUser賦值Method updateTimeMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method updateUserMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);updateTimeMethod.invoke(entity, now);updateUserMethod.invoke(entity, currentId);log.info("為實體類 {} 賦值成功", entity);} catch (Exception e) {e.printStackTrace();}}}
}

示例:(這段代碼就實現了對公共字段的填充)

    /*** 新增套餐** @param setmeal*/@AutoFill(OperationType.INSERT)void insert(Setmeal setmeal);

7 個人感悟

在初次接觸項目時第一感覺就是覺得太復雜了,當時看見那么多的類文件,覺得自己肯定學不好也學不會,但是不斷的接觸才發現,是有其自己的一套方法,也是可以接受的,也能跟著照葫蘆畫瓢,其三層架構十分具有條理性的將代碼進行分割將業務代碼進行拆分,在這個項目當中解除了后端方面對基礎業務CRUD的實現,同時也有一些常見開發規范的學習,以及小程序端的開發,實現前后端的聯調實現業務的完整性,但是學習的過程也是有不足的很多實現的過程都是跟著老師進行開發的很多都沒有由自己開發實現,自己單獨分析接口文檔進行接口編寫的能力還是有所欠缺。在學習過程中也發現自己之前的遺漏點,也是一種學習的方法,遇到不會的再向前學習,再進行運用,

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903504.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903504.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903504.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

車載功能測試-車載域控/BCM控制器測試用例開發流程【用例導出方法+優先級劃分原則】

目錄 1 摘要2 位置燈手動控制簡述2.1 位置燈手動控制需求簡述2.2 位置燈手動控制邏輯交互圖 3 用例導出方法以及優先級原則3.1 用例導出方法3.1.1 用例導出方法介紹3.1.2 用例導出方法關鍵差異分析 3.2 優先級規則3.2.1 優先級劃分的核心原則3.2.2 具體等級定義與判定標準 3.3 …

Linux系統基礎:基礎指令簡介(網絡概念部分)

簡介&#xff1a;Linux 是一種開源的類 Unix 操作系統內核&#xff0c;由 Linus Torvalds 于 1991 年首次發布。經過多年發展&#xff0c;它已成為服務器、嵌入式設備和個人計算機領域的重要操作系統。 網絡基礎概念 初始協議 簡單來說&#xff0c;協議是一種約定&#xff0…

多模態(3):實戰 GPT-4o 視頻理解

最近&#xff0c;OpenAI 團隊的 GPT-4o 模型&#xff0c;在多模態方面的能力有了大幅提升&#xff0c;這次我們就使用 GPT-4o 完成一個視頻理解的實戰。 1. 環境搭建 1.1 安裝 FFmpeg 做視頻處理&#xff0c;我們需要用到 FFmpeg 這款功能強大的開源多媒體處理工具。FFmpeg…

(27)VTK C++開發示例 ---將點坐標寫入 STL文件

文章目錄 1. 概述2. CMake鏈接VTK3. main.cpp文件4. 演示效果 更多精彩內容&#x1f449;內容導航 &#x1f448;&#x1f449;VTK開發 &#x1f448; 1. 概述 此示例使用 vtkSTLWriter 將存儲在 vtkPolyData 對象中的 3D 幾何數據保存到 STL 文件&#xff0c;并讀取stl文件顯示…

2. python協程/異步編程詳解

目錄 1. 簡單的異步程序 2. 協程函數和協程對象 3. 事件循環 4. 任務對象Task及Future對象 4.1 Task與Future的關系 4.2 Future對象 4.3 全局對象和循環事件對象 5. await關鍵字 6. 異步上下文管理 7.異步迭代器 8. asyncio的常用函數 8.1 asyncio.run 8.2 asyncio.get…

智慧園區IOT項目與AI時代下的機遇 - Java架構師面試實戰

在互聯網大廠的Java求職者面試中&#xff0c;面試官通常會針對實際業務場景提出一系列問題。以下是關于智慧園區IOT項目及AI時代下的機遇的面試模擬對話。 第一輪提問 面試官&#xff1a;馬架構&#xff0c;請簡要介紹下智慧園區IOT項目的整體架構設計。 馬架構&#xff1a;…

論文導讀 - 基于特征融合的電子鼻多任務深度學習模型研究

基于特征融合的電子鼻多任務深度學習模型研究 原論文地址&#xff1a;https://www.sciencedirect.com/science/article/pii/S0925400524009365 引用此論文&#xff08;GB/T 7714-2015&#xff09;&#xff1a; NI W, WANG T, WU Y, et al. Multi-task deep learning model f…

AI超級智能體項目教程(二)---后端項目初始化(設計knif4j接口文檔的使用)

文章目錄 1.選擇JDK的版本和相關配置2.添加依賴信息2.1指定lombok版本信息2.2引入hutool工具類2.3了解knif4j依賴2.4引入knif4j依賴 3.contrller測試3.1完成yml文件配置3.2修改默認掃描路徑3.3controller具體的內容3.4配置接口和訪問路徑3.5如何訪問3.6調試接口3.6調試接口 1.選…

linux blueZ 第四篇:BLE GATT 編程與自動化——Python 與 C/C++ 實戰

本篇聚焦 BLE(Bluetooth Low Energy)GATT 協議層的編程與自動化實踐,涵蓋 GATT 基礎、DBus API 原理、Python(dbus-next/bleak)示例、C/C++ (BlueZ GATT API)示例,以及自動發現、讀寫特征、訂閱通知、安全配對與腳本化測試。 目錄 BLE GATT 基礎概念 BlueZ DBus GATT 模…

kafka與flume的整合、spark-streaming

kafka與flume的整合 前期配置完畢&#xff0c;開啟集群 需求1&#xff1a; 利用flume監控某目錄中新生成的文件&#xff0c;將監控到的變更數據發送給kafka&#xff0c;kafka將收到的數據打印到控制臺&#xff08;三個node01中運行&#xff09; 1.在kafka中建立topic kafka…

redis高級進階

1.redis主從復制 redis主從復制1 2.redis哨兵模式 嗶哩嗶哩視頻 redis哨兵模式1 redis哨兵模式2 redis哨兵模式3 3.redis分片集群 redis分片集群1 redis分片集群2 redis分片集群3

uniapp: 低功耗藍牙(BLE)的使用

在微信小程序中實現藍牙對接藍牙秤的重量功能&#xff0c;主要依賴微信小程序提供的低功耗藍牙&#xff08;BLE&#xff09;API。以下是一個清晰的步驟指南&#xff0c;幫助你完成從連接藍牙秤到獲取重量數據的開發流程。需要注意的是&#xff0c;具體實現可能因藍牙秤的協議和…

3D架構圖軟件 iCraft Editor 正式發布 @icraft/player-react 前端組件, 輕松嵌入3D架構圖到您的項目

安裝 pnpm install icraft/player-react --saveimport { ICraftPlayer } from "icraft/player-react";export default function MyScene() {return <ICraftPlayer srcyour-scene.iplayer />; }icraft/player-react 為開發者提供了一站式的3D數字孿生可視化解決…

云數據中心整體規劃方案PPT(113頁)

1. 引言 概述&#xff1a;云數據中心整體規劃方案旨在構建彈性、高效的云計算基礎設施&#xff0c;通過軟件定義數據中心&#xff08;SDDC&#xff09;實現資源虛擬化與管理自動化。 2. 技術趨勢與背景 技術革新&#xff1a;隨著云計算、虛擬化及自動化技術的發展&#xff0c…

(六)機器學習---聚類與K-means

到本篇文章&#xff0c;我們先對前幾篇所學習的算法進行一個回顧&#xff1a; 而本篇文章我們將會介紹聚類以及K-means算法。 分類問題回歸問題聚類問題各種復雜問題決策樹√線性回歸√K-means√神經網絡√邏輯回歸√嶺回歸密度聚類深度學習√集成學習√Lasso回歸譜聚類條件隨機…

在html中如何創建vue自定義組件(以自定義文件上傳組件為例,vue2+elementUI)

1、先上代碼&#xff1a;vueUpload.js var dom <div class"upload-file"><el-upload :action"uploadFileUrl" :before-upload"handleBeforeUpload" :file-list"fileList" :limit"limit":on-error"handleUpl…

計算機基礎:二進制基礎14,二進制加法

專欄導航 本節文章分別屬于《Win32 學習筆記》和《MFC 學習筆記》兩個專欄&#xff0c;故劃分為兩個專欄導航。讀者可以自行選擇前往哪個專欄。 &#xff08;一&#xff09;WIn32 專欄導航 上一篇&#xff1a;計算機基礎&#xff1a;二進制基礎13&#xff0c;十六進制與二進…

可視化圖解算法: 判斷是不是二叉搜索樹(驗證二叉搜索樹)

1. 題目 描述 給定一個二叉樹根節點&#xff0c;請你判斷這棵樹是不是二叉搜索樹。 二叉搜索樹滿足每個節點的左子樹上的所有節點的值均嚴格小于當前節點的值&#xff1b;并且右子樹上的所有節點的值均嚴格大于當前節點的值。 數據范圍&#xff1a;節點數量滿足 1≤n≤10^4…

Markdown轉WPS office工具pandoc實踐筆記

隨著DeepSeek、文心一言、訊飛星火等AI工具快速發展&#xff0c;其輸出網頁內容拷貝到WPS Office過程中&#xff0c;文檔編排規整的格式很難快速復制。 注&#xff1a;WPS Office不支持Markdown格式&#xff0c;無法識別式樣。 在這里推薦個免費開源工具Pandoc&#xff0c;實現…

python的turtle庫實現四葉草

實現代碼&#xff1a; import turtle turtle.pencolor(‘green’) turtle.fillcolor(‘green’) turtle.begin_fill() turtle.circle(100,90) turtle.left(90) turtle.circle(100,90) turtle.right(180) turtle.circle(100, 90) turtle.left(90) turtle.circle(100,90) tu…