訊聯云庫項目開發日志(一)

1、設計數據庫

2、寫基本框架

entity、controller、service、exception、utils、mapper

mapper層:

生成了一系列的CRUD方法

工具類:線程安全的日期工具類、???參數校驗工具類?

線程安全的日期工具類??:主要用于 ??日期格式化(format)和解析(parse)??,并解決了?SimpleDateFormat?的線程安全問題?

參數校驗工具類:主要用于檢查對象參數是否滿足“至少有一個非空字段”的條件,并提供了一些字符串輔助方法(如首字母大寫、判空)

3、登錄驗證碼校驗

這段代碼是一個 ??驗證碼生成與校驗?? 的接口,主要用于生成圖片驗證碼并存儲到?HttpSession?中,以便后續驗證用戶輸入的驗證碼是否正確?

  1. ??生成圖片驗證碼??

    • 使用?CreateImageCode?類創建一個 ??130x38 像素?? 的驗證碼圖片,包含 ??5 個隨機字符??,干擾線數量為 ??10??。
    • 生成的驗證碼字符串存儲在?code?變量中。
  2. ??設置 HTTP 響應頭??

    • 禁用緩存,確保每次請求都生成新的驗證碼:
      response.setHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0);
    • 設置響應類型為?image/jpeg,表示返回的是 JPEG 圖片:
      response.setContentType("image/jpeg");
  3. ??存儲驗證碼到 Session??

    • 根據?type?參數決定驗證碼的用途:
      • type=1:普通驗證碼(如登錄驗證),存儲到?Constants.CHECK_CODE_KEY
      • 其他情況(如郵箱驗證碼),存儲到?Constants.CHECK_CODE_KEY_EMAIL
  4. ??輸出驗證碼圖片??

    • 調用?vCode.write(response.getOutputStream())?將生成的圖片寫入 HTTP 響應流,返回給前端顯示。

為了輔助上述方法,因此創建了一個圖形驗證碼生成工具類??(CreateImageCode

package com.cjl.entity.dto;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;public class CreateImageCode {//圖片寬度private int width=160;//圖片高度private int height=40;//驗證碼字符個數private int codeCount=4;//驗證碼干擾線數private int lineCount=20;//驗證碼private String code=null;//驗證碼圖片bufferprivate BufferedImage  buffImg=null;Random random=new Random();public CreateImageCode(){createCode();}public CreateImageCode(int width, int height, int codeCount, int lineCount){this.width=width;this.height=height;this.codeCount=codeCount;this.lineCount=lineCount;createCode();}public CreateImageCode(int width, int height, int lineCount){this.width=width;this.height=height;this.lineCount=lineCount;createCode();}public CreateImageCode(int width, int height){this.width=width;this.height=height;createCode();}//生成圖片private void createCode(){int fontWidth=width/codeCount; //字體寬度int fontHeight=height-5; //字體高度int codeY=height-8; //驗證碼y坐標//創建圖像bufferbuffImg=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);Graphics g=buffImg.getGraphics();//設置背景顏色g.setColor(getRandColor(200,250));g.fillRect(0,0,width,height);//設置字體Font font=new Font("Fixedsys",Font.BOLD,fontHeight);g.setFont(font);//設置干擾線for(int i=0;i<lineCount;i++){int xs=random.nextInt(width);int ys=random.nextInt(height);int xe=xs+random.nextInt(width);int ye=ys+random.nextInt(height);g.setColor(getRandColor(1,255));g.drawLine(xs,ys,xe,ye);}//添加噪點float yawpRate=0.01f; //噪聲率int area=(int)(yawpRate*width*height); //像素個數for(int i=0;i<area;i++){int x=random.nextInt(width);int y=random.nextInt(height);buffImg.setRGB(x,y,random.nextInt(255));}String str1=RandomStr(codeCount); //隨機生成驗證碼this.code=str1;for(int i=0;i<codeCount;i++){String strRand=str1.substring(i,i+1);g.setColor(getRandColor(1,255));//g.drawString(a,x,y);//a是要畫出來的東西,x,y是坐標,基于要畫的東西最左側字符的基線g.drawString(strRand,i*fontWidth+3,codeY);}}//得到隨機字符private String RandomStr(int n){String str1="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";String str2="";int len=str1.length()-1;double r;for(int i=0;i<n;i++){r=(Math.random())*len;str2=str2+str1.charAt((int)r);}return str2;}//得到隨機顏色private Color getRandColor(int fc,int bc){if(fc>255) fc=255;if(bc>255) bc=255;int r=fc+random.nextInt(bc-fc);int g=fc+random.nextInt(bc-fc);int b=fc+random.nextInt(bc-fc);return new Color(r,g,b);}//畫干擾線private void shearY(Graphics g,int w1,int h1,Color color){int period=random.nextInt(40)+10; //50; //振幅boolean borderGap=true;int frames=20;int phase=7;for(int i=0;i<w1;i++){double d=(double)(period>>1)* Math.sin((double)i/period+ (6.2831853071795862D* (double)phase/frames));g.copyArea(i,0,1,h1,0,(int)d);if(borderGap){g.setColor(color);g.drawLine(i, (int)d, i, 0);g.drawLine(i, (int)d+h1, i, h1);}}}public void write(OutputStream sos) throws IOException {ImageIO.write(buffImg,"png",sos);sos.close();}public BufferedImage   getBuffImg(){return buffImg;}public String getCode(){return code.toLowerCase();}
}

最終達到的效果:

4、創建郵箱數據庫

依舊通過java生成器生成,不過,第一次遇見這種:

	<!-- 通用查詢結果列--><sql id="base_column_list">e.email,e.code,e.creat_time,e.status</sql><sql id="base_condition_filed"><if test="query.email != null and query.email!=''">and  e.email = #{query.email}</if><if test="query.code != null and query.code!=''">and  e.code = #{query.code}</if><if test="query.creatTime != null and query.creatTime!=''"><![CDATA[ and  e.creat_time=str_to_date(#{query.creatTime}, '%Y-%m-%d') ]]></if><if test="query.status != null">and  e.status = #{query.status}</if></sql><!-- 通用條件列--><sql id="base_condition"><where><include refid="base_condition_filed" /></where></sql><!-- 通用查詢條件列--><sql id="query_condition"><where><include refid="base_condition_filed" /><if test="query.emailFuzzy!= null  and query.emailFuzzy!=''">and  e.email like concat('%', #{query.emailFuzzy}, '%')</if><if test="query.codeFuzzy!= null  and query.codeFuzzy!=''">and  e.code like concat('%', #{query.codeFuzzy}, '%')</if><if test="query.creatTimeStart!= null and query.creatTimeStart!=''"><![CDATA[ and  e.creat_time>=str_to_date(#{query.creatTimeStart}, '%Y-%m-%d') ]]></if><if test="query.creatTimeEnd!= null and query.creatTimeEnd!=''"><![CDATA[ and  e.creat_time< date_sub(str_to_date(#{query.creatTimeEnd},'%Y-%m-%d'),interval -1 day) ]]></if></where></sql>

?<sql id="base_column_list"> ???我很好奇了這是什么

通過?<sql>?標簽定義可重用的 SQL 片段,并通過?<include>?標簽引用這些片段,從而提高代碼的復用性和可維護性。

當 MyBatis 啟動時,會解析這些?<sql>?片段并存儲在內存中,形成可重用的 SQL 模板。

1. ??片段注冊??
  • base_column_list?→ 字段列表模板
  • base_condition_filed?→ 基礎條件模板
  • base_condition?→ 完整 WHERE 條件(直接引用?base_condition_filed
  • query_condition?→ 擴展 WHERE 條件(引用?base_condition_filed?并追加模糊/范圍查詢)
2.邏輯關系

這段代碼的核心思想就是 ??將常用的 SQL 片段拆解成可復用的模塊??,通過 MyBatis 的?<sql>?和?<include>?機制實現 ??邏輯復用?? 和 ??動態拼接??。但它不僅僅是簡單的“代碼片段集合”,而是一種 ??模塊化 SQL 設計模式??

可能跟我一樣第一次遇見的同學看見這里就有點蒙圈了,沒事,我們來舉例?一個簡單的代碼來理解:

1. 定義可復用的 SQL 片段(樂高積木塊)
<!-- 基礎車體(相當于字段列表) -->
<sql id="base_car_body">id, brand, model, color
</sql><!-- 基礎輪子(相當于基礎條件) -->
<sql id="base_wheels"><if test="wheelSize != null">AND wheel_size = #{wheelSize}</if>
</sql>
2.組裝小車(簡單查詢)
<select id="selectBasicCar" resultType="Car">SELECT <include refid="base_car_body"/>  <!-- 插入車體 -->FROM cars<where><include refid="base_wheels"/>    <!-- 插入輪子條件 --></where>
</select>
3.生成的SQL??(當 wheelSize=18 時):
SELECT id, brand, model, color
FROM cars
WHERE wheel_size = 18

這樣是不是就好理解一點了!!

5、實現發送郵箱驗證碼接口?

就在主播寫這個接口的發送郵箱驗證的時候,命名mappers互相跳轉都沒有問題,困擾我一個多小時,結果發現沒有在??屬性配置文件添加mybatis.mapper-locations=classpath:mappers/*.xml,因此雖然我可以互相跳轉,但是代碼自己找不到sql映射,屬所以說寫代碼還是要規范

言歸正傳,

當我們寫完這個接口,我們要考慮很多因素,首先就是用戶輸入的驗證碼是不是正確的,要根據之前定義的checkCode方法來查看,其次就要考慮status的問題,如果賬戶已經被注冊了就沒有必要了要進行判斷,不僅如此,當用戶多次點擊發送的時候,我們只需要禁用之前的驗證碼,這個如何實現?

答案是在service層

@Update("update email_code set status=1 where email=#{email} and status=0")

為什么這樣就可以?我們來分析,當檢測到用戶未注冊的時候,代碼的流程走到這里來的時候,此時他的status就會變成1,也就是說每次發送新驗證碼前,會先執行?disableEmailCode?方法,將所有該郵箱未使用的驗證碼(status=0)標記為被使用了已禁用(status=1)。因此能保證最晚(最新)的那一個驗證碼才會生效

我們現在來發送郵件,???JavaMailSender??(Spring框架提供的郵件發送工具)來創建并發送一封簡單的電子郵件:

流程:

1.入口??:調用sendMailCode(email, code)方法,傳入收件人郵箱和驗證碼

2.獲取系統郵件模板

SysSettingDto sysSettingDto = redisComponent.getSysSetting();

設置郵件發送的格式:?

3.構建郵件內容
  • ??標題處理??:直接使用系統配置的標題

    helper.setSubject(sysSettingDto.getRegisterMailTitle());

  • ??內容格式化??:將驗證碼插入模板
    String.format("您好,您的郵箱驗證碼為:%s,15分鐘有效", "A1B2C3")

提問:有人就好奇了,redis一開始是空的哪來的模板??

答案是?

1. 嘗試從Redis讀取(此時返回null),發現為空時,創建默認配置

最后保存到Redis(無過期時間)?

整個發郵件的大致過程就是這樣,最后用戶會收到:

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

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

相關文章

langchain學習

無門檻免費申請OpenAI ChatGPT API搭建自己的ChatGPT聊天工具 https://nuowa.net/872 基本概念 LangChain 能解決大模型的兩個痛點&#xff0c;包括模型接口復雜、輸入長度受限離不開自己精心設計的模塊。根據LangChain 的最新文檔&#xff0c;目前在 LangChain 中一共有六大…

Protobuf工具

#region 知識點一 什么是 Protobuf //Protobuf 全稱是 protocol - buffers&#xff08;協議緩沖區&#xff09; // 是谷歌提供給開發者的一個開源的協議生成工具 // 它的主要工作原理和我們之前做的自定義協議工具類似 // 只不過它更加的完善&…

zst-2001 上午題-歷年真題 軟件工程(38個內容)

CMM 軟件工程 - 第1題 b 軟件工程 - 第2題 c 軟件工程 - 第3題 c 軟件工程 - 第4題 b 軟件工程 - 第5題 b CMMI 軟件工程 - 第6題 0.未完成&#xff1a;未執行未得到目標。1.已執行&#xff1a;輸入-輸出實現支持2.已管理&#xff1a;過程制度化&#x…

軟考架構師考試-UML圖總結

考點 選擇題 2-4分 案例分析0~1題和面向對象結合考察&#xff0c;前幾年固定一題。近3次考試沒有出現。但還是有可能考。 UML圖概述 1.用例圖&#xff1a;描述系統功能需求和用戶&#xff08;參與者&#xff09;與系統之間的交互關系&#xff0c;聚焦于“做什么”。 2.類圖&…

數據結構(七)——圖

一、圖的定義與基本術語 1.圖的定義 圖G由頂點集V和邊集E組成&#xff0c;記為G(V,E)&#xff0c;其中V(G)表示圖G中頂點的有限非空集&#xff1b;E(G)表示圖G中頂點之間的關系&#xff08;邊&#xff09;的集合 注意&#xff1a;線性表可以是空表&#xff0c;樹可以是空樹&…

Android7 Input(六)InputChannel

概述: 本文講述Android Input輸入框架中 InputChannel的功能。從前面的講述&#xff0c;我們知道input系統服務最終將輸入事件寫入了InputChannel&#xff0c;而input屬于system_server進程&#xff0c;App屬于另外一個進程&#xff0c;當Input系統服務想要把事件傳遞給App進行…

【 Redis | 實戰篇 秒殺實現 】

目錄 前言&#xff1a; 1.全局ID生成器 2.秒殺優惠券 2.1.秒殺優惠券的基本實現 2.2.超賣問題 2.3.解決超賣問題的方案 2.4.基于樂觀鎖來解決超賣問題 3.秒殺一人一單 3.1.秒殺一人一單的基本實現 3.2.單機模式下的線程安全問題 3.3.集群模式下的線程安全問題 前言&…

如何用URDF文件構建機械手模型并與MoveIt集成

機械手URDF文件的編寫 我們用urdf文件來描述我們的機械手的外觀以及物理性能。這里為了簡便&#xff0c;就只用了基本的圓柱、立方體了。追求美觀的朋友&#xff0c;還可以用dae文件來描述機械手的外形。 import re def remove_comments(text):pattern r<!--(.*?)-->…

《構建社交應用的安全結界:雙框架對接審核API的底層邏輯與實踐》

用戶生成內容如潮水般涌來。從日常的生活分享&#xff0c;到激烈的觀點碰撞&#xff0c;這些內容賦予社交應用活力&#xff0c;也帶來管理難題。虛假信息、暴力言論、侵權內容等不良信息&#xff0c;如同潛藏的暗礁&#xff0c;威脅著社交平臺的健康生態。內容審核機制&#xf…

39:分類器流程

第一步 創建支持向量機分類器 create_class_svm (7, rbf, KernelParam, Nu, |ClassNames|, one-versus-one, principal_components, 5, SVMHandle) 第二步 添加樣本到分類器里 for ClassNumber : 0 to |ClassNames| - 1 by 1 *列出目錄下的所有文件 list_files (ReadPath…

LangChain對話鏈:打造智能多輪對話機器人

LangChain對話鏈:打造智能多輪對話機器人 目錄 LangChain對話鏈:打造智能多輪對話機器人ConversationChain 是什么核心功能與特點基本用法示例內存機制自定義提示詞應用場景與其他鏈的結合`SequentialChain` 是什么![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/0…

el-select 結合 el-tree:樹形下拉數據

一、單選 <template><div class"selectTree-wapper"><el-selectv-model"selectValue"placeholder"請選擇"popper-class"custom-el-select-class"ref"selectRef"clearableclear"clearHandle">&…

BFS算法篇——從晨曦到星辰,BFS算法在多源最短路徑問題中的詩意航行(下)

文章目錄 引言一、01矩陣1.1 題目鏈接&#xff1a;https://leetcode.cn/problems/01-matrix/description/1.2 題目分析&#xff1a;1.3 思路講解&#xff1a;1.4 代碼實現&#xff1a; 二、飛地的數量2.1 題目鏈接&#xff1a;https://leetcode.cn/problems/number-of-enclaves…

Leetcode (力扣)做題記錄 hot100(49,136,169,20)

力扣第49題&#xff1a;字母異位詞分組 49. 字母異位詞分組 - 力扣&#xff08;LeetCode&#xff09; 遍歷數組&#xff0c;將每一個字符串變成char數組 然后排序&#xff0c;如果map里面有則將他的值返回來&#xff08;key是排序好的字符串&#xff09; class Solution {pu…

【自學30天掌握AI開發】第1天 - 人工智能與大語言模型基礎

自學30天掌握AI開發 - 第1天 &#x1f4c6; 日期和主題 日期&#xff1a;第1天 主題&#xff1a;人工智能與大語言模型基礎 &#x1f3af; 學習目標 了解人工智能的發展歷史和基本概念掌握大語言模型的基本原理和工作機制區分不同類型的AI模型及其特點理解AI在當前社會中的…

WebRTC 源碼原生端Demo入門-1

1、概述 我的代碼是比較新的&#xff0c;基于webrtc源碼倉庫的main分支的&#xff0c;在windows下把源碼倉庫下載好了后&#xff0c;用visual stdio 2022打開進行編譯調試src/examples/peerconnection_client測試項目,主要是跑通這個demo來入手和調試&#xff0c;純看代碼很難…

【LeetCode】刪除排序數組中的重復項 II

題目 鏈接 思路 雙指針 我好聰明啊&#xff0c;自己想出了這個雙指針的辦法&#xff0c;哈哈哈哈哈哈哈&#xff0c;太高興了 代碼 class Solution(object):def removeDuplicates(self, nums):""":type nums: List[int]:rtype: int"""nlen…

通義千問席卷日本!開源界“卷王”阿里通義千問成為日本AI發展新基石

據日本經濟新聞&#xff08;NIKKEI&#xff09;報道&#xff0c;通義千問已成為日本AI開發的新基礎&#xff0c;其影響力正逐步擴大&#xff0c;深刻改變著日本AI產業的格局。 同時&#xff0c;日本經濟新聞將通義千問Qwen2.5-Max列為全球AI模型綜合評測第六名&#xff0c;不僅…

第J7周:對于ResNeXt-50算法的思考

目錄 思考 一、代碼功能分析 1. 構建 shortcut 分支&#xff08;殘差連接的旁路&#xff09; 2. 主路徑的第一層卷積&#xff08;11&#xff09; 4. 主路徑的第三層卷積&#xff08;11&#xff09; 5. 殘差連接 激活函數 二、問題分析總結&#xff1a;殘差結構中通道數不一致的…

如何解決Jmeter中的亂碼問題?

在 JMeter 中遇到亂碼問題通常是由于字符編碼不一致導致的&#xff0c;常見于 HTTP 請求響應、參數化文件讀取、報告生成等場景。以下是系統化的解決方案&#xff1a; 1. HTTP 請求響應亂碼 原因&#xff1a; 服務器返回的字符編碼&#xff08;如UTF-8、GBK&#xff09;與 J…