從零開始的抽獎系統創作(2)

我們接著進行抽獎系統的完善。

前面我們完成了

1.結構初始化(統一結果返回之類的,還有包的分類)

2.加密(基于Hutool進行的對稱與非對稱加密)

3.用戶注冊

接下來我們先完善一下結構(統一異常處理)

1.統一異常處理

很簡單,@RestControllerAdvice+@ExceptionHandler即可

@RestControllerAdvice//可以捕獲全局拋出的異常
@ResponseBody
public class GlobalExceptionHandler {private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);//捕獲Service層的異常@ExceptionHandler(value = ServiceException.class)public CommonResult<?> serviceException(ServiceException e) {logger.error("serviceException :", e);//返回數據return CommonResult.error(GlobalErrorCodeConstant.INTERNAL_SERVICE_ERROR);}//捕獲Controller層的異常@ExceptionHandler(value = ControllerException.class)public CommonResult<?> controllerException(ControllerException e) {logger.error("controllerException :", e);//返回數據return CommonResult.error(GlobalErrorCodeConstant.INTERNAL_SERVICE_ERROR);}//捕獲全局的異常@ExceptionHandler(value = Exception.class)public CommonResult<?> exception(Exception e) {logger.error("exception :", e);//返回數據return CommonResult.error(GlobalErrorCodeConstant.INTERNAL_SERVICE_ERROR);}
}

這里使用@ExceptionHandler(value = 類名)的方式捕獲異常。

其他沒什么要特別注意的,補充GlobalErrorCodeConstant的異常種類

2.登錄模塊

這里提供短信驗證碼登錄的方式,因此我們要了解一下阿里短信服務

但是現在個人申請不到了,所以我們直接使用虛擬的驗證碼吧。

附一個申請成功后植入的代碼:

1.阿里短信代碼模塊:

依賴:

<dependency><groupId>com.aliyun</groupId><artifactId>dysmsapi20170525</artifactId><version>2.0.24</version>
</dependency>

短信服務工具類:

@Component
public class SMSUtil {private static final Logger logger = LoggerFactory.getLogger(SMSUtil.class);@Value(value = "${sms.sign-name}")private String signName;@Value(value = "${sms.access-key-id}")private String accessKeyId;@Value(value = "${sms.access-key-secret}")private String accessKeySecret;/*** 發送短信** @param templateCode 模板號* @param phoneNumbers 手機號* @param templateParam 模板參數 {"key":"value"}*/public void sendMessage(String templateCode, String phoneNumbers, String templateParam) {try {Client client = createClient();com.aliyun.dysmsapi20170525.models.SendSmsRequest sendSmsRequest = new SendSmsRequest().setSignName(signName).setTemplateCode(templateCode).setPhoneNumbers(phoneNumbers).setTemplateParam(templateParam);RuntimeOptions runtime = new RuntimeOptions();SendSmsResponse response = client.sendSmsWithOptions(sendSmsRequest, runtime);if (null != response.getBody()&& null != response.getBody().getMessage()&& "OK".equals(response.getBody().getMessage())) {logger.info("向{}發送信息成功,templateCode={}", phoneNumbers, templateCode);return;}logger.error("向{}發送信息失敗,templateCode={},失敗原因:{}",phoneNumbers, templateCode, response.getBody().getMessage());} catch (TeaException error) {logger.error("向{}發送信息失敗,templateCode={}", phoneNumbers, templateCode, error);} catch (Exception _error) {TeaException error = new TeaException(_error.getMessage(), _error);logger.error("向{}發送信息失敗,templateCode={}", phoneNumbers, templateCode, error);}}/*** 使用AK&SK初始化賬號Client* @return Client*/private Client createClient() throws Exception {// 工程代碼泄露可能會導致 AccessKey 泄露,并威脅賬號下所有資源的安全性。以下代碼示例僅供參考。// 建議使用更安全的 STS 方式,更多鑒權訪問方式請參見:https://help.aliyun.com/document_detail/378657.html。Config config = new Config().setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret);// Endpoint 請參考 https://api.aliyun.com/product/Dysmsapiconfig.endpoint = "dysmsapi.aliyuncs.com";return new Client(config);}}

配置:

### 短信 ##
## 短信 ##
sms.access-key-id="填寫??申請的"
sms.access-key-secret="填寫??申請的"
sms.sign-name="填寫??申請的"

代碼使用:

使用時傳入3個參數:

templateCode(模板號):SMS_465324787

phoneNumbers(手機號):傳入你申請的

templateParam(模版參數):發送驗證碼的格式設置為{"key":"value"}

使用時傳入一個map并將其序列化

2.驗證碼模塊

利用Hutool工具:(這工具真好用都不用手寫了)

//生成隨機驗證碼
public class CaptchaUtil {/*** 生成隨機驗證碼** @param length  幾位* @return*/public static String getCaptcha(int length) {// 自定義純數字的驗證碼(隨機4位數字,可重復)RandomGenerator randomGenerator = new RandomGenerator("0123456789", length);LineCaptcha lineCaptcha = cn.hutool.captcha.CaptchaUtil.createLineCaptcha(200, 100);lineCaptcha.setGenerator(randomGenerator);// 重新生成codelineCaptcha.createCode();return lineCaptcha.getCode();}}

3.Controller

基于手機號生成驗證碼并發送驗證碼? ?最后使用Redis緩存驗證碼用于校驗

    /*** 發送驗證碼* @param phoneNumber* @return*/@RequestMapping("/verification-code/send")public CommonResult<Boolean> verificationCode (String phoneNumber) {//日志打印logger.info("verificationCode  phoneNumber:{}", phoneNumber);verificationCodeService.sendVerificationCode(phoneNumber);return CommonResult.success(Boolean.TRUE);}

4.Service

    /*** 發送驗證碼* @param phoneNumber* @return*/public String sendVerificationCode(String phoneNumber);/*** 獲取驗證碼* @param phoneNumber* @return*/public String getVerificationCode(String phoneNumber);
    @Overridepublic String sendVerificationCode(String phoneNumber) {//校驗手機號if(!RegexUtil.checkMobile(phoneNumber)) {throw new ServiceException(ServiceErrorCodeConstant.PHONE_NUMBER_ERROR);}//生成隨機驗證碼  利用hutool生成String code = CaptchaUtil.getCaptcha(4);//發送驗證碼Map<String, String> map = new HashMap<>();map.put("code", code);smsUtil.sendMessage(PHONE_NUMBER_TEMPLATE_CODE, phoneNumber, JacksonUtil.writeValueAsString(map));//緩存驗證碼redisUtil.set(PHONE_NUMBER_PRE +phoneNumber, code, PHONE_NUMBER_TIMEOUT);return redisUtil.get(PHONE_NUMBER_PRE +phoneNumber);}@Overridepublic String getVerificationCode(String phoneNumber) {//校驗手機號if(!RegexUtil.checkMobile(phoneNumber)) {throw new ServiceException(ServiceErrorCodeConstant.PHONE_NUMBER_ERROR);}return redisUtil.get(PHONE_NUMBER_PRE +phoneNumber);}

Redis使用簡單介紹:

配置:

在Linux服務器上通過隧道開放Redis的6379端口號

在Linux上輸入命令啟動Redis:

service redis-server start

?可以在idea上下載插件Redis Helper

刷新后在右側找到插件點擊加號添加Redis服務?

1.名稱(隨便,便于標識)

2.本機就行

3.在Linux隧道綁定的端口號

4.Test測試驗證,出現綠色即成功連接Redis?

?Redis使用測試:

    @Testvoid redisTest() {stringRedisTemplate.opsForValue().set("key1", "value2");System.out.println("從redis中獲取value : " + stringRedisTemplate.opsForValue().get("key1"));}@Testvoid redisUtil() {
//        redisUtil.set("key2", "value2");
//        redisUtil.set("key3", "value3", 20L);
//        System.out.println("key2是否存在: " + redisUtil.hasKey("key2"));
//        System.out.println("key3是否存在: " + redisUtil.hasKey("key3"));//        redisUtil.delete("key2");
//        System.out.println("key2是否存在: " + redisUtil.hasKey("key2"));System.out.println("key3是否存在: " + redisUtil.hasKey("key3"));}

1.使用前注入StringRedisTemplate類

2.使用stringRedisTemplate.opsForValue().set("key1", "value2");添加元素

但是,每次使用都要注入StringRedisTemplate有點麻煩了,我們將其封裝成一個util工具。

@Configuration
public class RedisUtil {public static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);/*** StringRedisTemplate : 直接用String存儲讀取(可讀)* RedisTemplate : 先將被存儲數據轉換為字節數組(不可讀)  再存儲到Redis中 讀取時以字節數組讀取*/@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 設置值* @param key* @param value* @return*/public boolean set(String key,String value) {try{stringRedisTemplate.opsForValue().set(key, value);return true;}catch(Exception e) {logger.error("RedisUtil set 錯誤:({}, {})", key, value, e);return false;}}/*** 設置帶有過期時間的值* @param key* @param value* @param time  單位:秒* @return*/public boolean set(String key,String value, Long time) {try{stringRedisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);return true;}catch(Exception e) {logger.error("RedisUtil set 錯誤:({}, {}, {})", key, value, time, e);return false;}}/*** 獲取值* @param key* @return*/public String get(String key) {try{return StringUtils.hasText(key)? stringRedisTemplate.opsForValue().get(key): null;}catch(Exception e) {logger.error("RedisUtil set 錯誤:({})", key, e);return null;}}/*** 刪除值* @param key* @return*/public boolean delete(String... key) {try{if(key != null && key.length > 0) {if(key.length == 1) {stringRedisTemplate.delete(key[0]);}else {stringRedisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));}}return true;}catch(Exception e) {logger.error("RedisUtil delete 錯誤:({})", key, e);return false;}}/*** 查看Key是否存在* @param key* @return*/public boolean hasKey(String key) {return StringUtils.hasText(key)? stringRedisTemplate.hasKey(key): false;}}

該類提供了:

set:兩個,一個是傳入key:value? 。另一個是傳入key:value+過期時間

get:通過key獲取value

delete:通過key,進行批量刪除

hasKey:查看key是否存在

5.JWT令牌驗證

前面我們發送了驗證碼,在客戶端我們就要將該驗證碼輸入進行登錄,但還有一些用戶會采用手機號/郵箱+密碼的方式登錄。所以我們要開放兩個接口用于登錄。

登錄完后端會返回給前端一個token用于令牌校驗,使驗證碼登錄在多臺主機下都可以使用。

JWT本身沒什么說的,直接上代碼:

public class JWTUtil {private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class);/*** 密鑰:Base64編碼的密鑰*/private static final String SECRET = "SDKltwTl3SiWX62dQiSHblEB6O03FG9/vEaivFu6c6g=";/*** 生成安全密鑰:將一個Base64編碼的密鑰解碼并創建一個HMAC SHA密鑰。*/private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET));/*** 過期時間(單位: 毫秒)*/private static final long EXPIRATION = 60*60*1000;/*** 生成密鑰** @param claim  {"id": 12, "name":"張山"}* @return*/public static String genJwt(Map<String, Object> claim){//簽名算法String jwt = Jwts.builder().setClaims(claim)             // 自定義內容(載荷).setIssuedAt(new Date())      // 設置簽發時間.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) // 設置過期時間.signWith(SECRET_KEY)         // 簽名算法.compact();return jwt;}/*** 驗證密鑰*/public static Claims parseJWT(String jwt){if (!StringUtils.hasLength(jwt)){return null;}// 創建解析器, 設置簽名密鑰JwtParserBuilder jwtParserBuilder = Jwts.parserBuilder().setSigningKey(SECRET_KEY);Claims claims = null;try {//解析tokenclaims = jwtParserBuilder.build().parseClaimsJws(jwt).getBody();}catch (Exception e){// 簽名驗證失敗logger.error("解析令牌錯誤,jwt:{}", jwt, e);}return claims;}/*** 從token中獲取用戶ID*/public static Integer getUserIdFromToken(String jwtToken) {Claims claims = JWTUtil.parseJWT(jwtToken);if (claims != null) {Map<String, Object> userInfo = new HashMap<>(claims);return (Integer) userInfo.get("userId");}return null;}
}

提供了三個方法:

1.getJWT:通過傳入一個map生成token并返回。

2.parseJWT:將token解析為map數據

3.getUserIdFromToken:從token中獲取用戶ID(可能有用)

6.管理員登錄(兩種?式)

學習令牌的使?之后, 接下來我們通過令牌來完成??的登錄的流程

1. 登陸??把??名密碼提交給服務器.

2. 服務器端驗證??名密碼是否正確, 如果正確, 服務器?成令牌, 下發給客?端.

3. 客?端把令牌存儲起來(?如Cookie, local storage等), 后續請求時, 把token發給服務器

4. 服務器對令牌進?校驗, 如果令牌正確, 進?下?步操作

7.Controller

數據準備:

接收與返回的數據:

因為兩個登錄都含有統一數據,所以對公共的進行提取

//共有的字段
@Data
public class UserLoginParam implements Serializable {/*** 身份登錄信息* 可填可不填  不填代表都可以登錄*/private String mandatoryIdentity;
}

UserPasswordLoginParam:

@Data
@EqualsAndHashCode(callSuper = true)
public class UserPasswordLoginParam extends UserLoginParam{/*** 手機號或郵箱*/@NotBlank(message = "手機號或郵箱不能為空")private String loginName;/*** 密碼*/@NotBlank(message = "密碼不能為空")private String password;
}

UserMessageLoginParam:

@Data
@EqualsAndHashCode(callSuper = true)
public class UserMessageLoginParam extends UserLoginParam{/*** 登錄手機號*/@NotBlank(message = "手機號不能為空")private String loginMobile;/*** 驗證碼*/@NotBlank(message = "驗證碼不能為空")private String code;
}

UserLoginResult:

@Data
public class UserLoginResult implements Serializable {/*** 令牌*/@NotBlank(message = "令牌不能為空")private String token;/*** 身份信息*/@NotBlank(message = "身份信息不能為空")private String identity;
}

1.密碼登錄:

    /*** 密碼登錄* @param userLoginParam* @return*/@RequestMapping("/password/login")private CommonResult<UserLoginResult> passwordLogin(@Validated @RequestBody UserPasswordLoginParam userLoginParam) {logger.info("passwordLogin userLoginParam:{}", JacksonUtil.writeValueAsString(userLoginParam));//使用同一個接口完成登錄UserLoginDTO userLoginDTO = userService.login(userLoginParam);return CommonResult.success(convertToLoginResult(userLoginDTO));}

在數據庫返回的對象使用DTO,然后返回時用convertToLoginResult進行類型轉化。

    private UserLoginResult convertToLoginResult(UserLoginDTO userLoginDTO) {//校驗if(userLoginDTO == null) {throw new ControllerException(ControllerErrorCodeConstant.LOGIN_ERROR);}//數據轉化UserLoginResult userLoginResult = new UserLoginResult();userLoginResult.setToken(userLoginDTO.getToken());userLoginResult.setIdentity(userLoginDTO.getIdentity().name());return userLoginResult;}

2.短信驗證碼登錄

與之類似:

    /*** 短信驗證碼登錄* @param userLoginParam* @return*/@RequestMapping("/message/login")private CommonResult<UserLoginResult> messageLogin(@Validated @RequestBody UserMessageLoginParam userLoginParam) {logger.info("messageLogin userLoginParam:{}", JacksonUtil.writeValueAsString(userLoginParam));//使用同一個接口完成登錄  將接收參數改為公用參數extendsUserLoginDTO userLoginDTO = userService.login(userLoginParam);return CommonResult.success(convertToLoginResult(userLoginDTO));}

8.Sevice

通過Java14特性屬性校驗并賦值實現一個接口完成兩個登錄功能

    /*** 用戶登錄*   1.手機號/郵箱 + 密碼*   2.手機號 + 驗證碼* @param userLoginParam* @return*/@Overridepublic UserLoginDTO login(UserLoginParam userLoginParam) {UserLoginDTO userLoginDTO = null;//類型檢查與類型交換  java 14 版本及以上  實現校驗兩個登錄方式if(userLoginParam instanceof UserPasswordLoginParam loginParam) {//手機號/郵箱 + 密碼userLoginDTO = loginByPassword(loginParam);}else if(userLoginParam instanceof UserMessageLoginParam loginParam) {//手機號 + 驗證碼userLoginDTO = loginByShortMessage(loginParam);}else {throw new ServiceException(ServiceErrorCodeConstant.LOGIN_INFO_NOT_EXITS);}return userLoginDTO;}

DTO:

@Data
public class UserLoginDTO implements Serializable {/*** JWT令牌*/private String token;/*** 身份信息*/private UserIdentityEnum identity;
}

1.通過手機短信登錄

1.校驗手機號

        if(!StringUtils.hasText(loginParam.getLoginMobile())) {throw new ServiceException(ServiceErrorCodeConstant.PHONE_NUMBER_ERROR);}

2.通過手機號完成數據庫查詢

        UserDO userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));

3.校驗數據庫信息及身份(判斷是否是管理員)

        //校驗數據庫數據if(userDO == null) {throw new ServiceException(ServiceErrorCodeConstant.USER_INFO_IS_EMPTY);}else if(StringUtils.hasText(loginParam.getMandatoryIdentity())&& !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {//身份校驗不通過throw new ServiceException(ServiceErrorCodeConstant.IDENTITY_ERROR);}

4.獲取Redis中的驗證碼并于數據庫中的數據進行校驗?

        String code = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());if(!code.equals(loginParam.getCode())) {throw new ServiceException(ServiceErrorCodeConstant.VERIFICATION_CODE_ERROR);}

5.將數據封裝成一個token

        //塞入返回值(JWT)Map<String, Object> claim = new HashMap<>();claim.put("id", userDO.getId());claim.put("identity", userDO.getIdentity());String token = JWTUtil.getJwt(claim);

6.封裝成為DTO返回

        UserLoginDTO userLoginDTO = new UserLoginDTO();userLoginDTO.setToken(token);userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));return userLoginDTO;

2.通過手機號/郵箱+密碼登錄

1.校驗密碼

2.判斷是手機號還是郵箱

3.通過手機號/郵箱獲取數據庫信息

4.校驗 數據庫信息及身份信息

5.生成token

6.包裝成DTO返回

    /*** 通過手機號+密碼登錄* @param loginParam* @return*/private UserLoginDTO loginByPassword(UserPasswordLoginParam loginParam) {UserDO userDO = null;if(!StringUtils.hasText(loginParam.getPassword())) {throw new ServiceException(ServiceErrorCodeConstant.PASSWORD_EMPTY);}//判斷是手機號還是郵箱登錄if(RegexUtil.checkMobile(loginParam.getLoginName())) {//手機號//根據手機號查詢用戶表userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));}else if(RegexUtil.checkMail(loginParam.getLoginName())) {//郵箱登錄//根據郵箱查詢用戶表userDO = userMapper.selectByEmail(loginParam.getLoginName());}else {throw new ServiceException(ServiceErrorCodeConstant.LOGIN_NOT_EXITS);}//校驗登錄信息if(userDO == null) {throw new ServiceException(ServiceErrorCodeConstant.USER_INFO_IS_EMPTY);}else if(StringUtils.hasText(loginParam.getMandatoryIdentity())&& !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {//身份校驗不通過throw new ServiceException(ServiceErrorCodeConstant.IDENTITY_ERROR);}else if(!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())) {throw new ServiceException(ServiceErrorCodeConstant.PASSWORD_ERROR);}//塞入返回值(JWT)Map<String, Object> claim = new HashMap<>();claim.put("id", userDO.getId());claim.put("identity", userDO.getIdentity());String token = JWTUtil.getJwt(claim);UserLoginDTO userLoginDTO = new UserLoginDTO();userLoginDTO.setToken(token);userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));return userLoginDTO;}

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

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

相關文章

【vs2022的C#窗體項目】打開運行+sql Server改為mysql數據庫+發布

1. vs2022打開運行原sql Server的C#窗體項目更改為mysql數據庫 1.1. vs2022安裝基礎模塊即可 安裝1??vs核心編輯器2??.net桌面開發必選&#xff0c;可選均不安裝&#xff01;&#xff01;&#xff01; 為了成功連接mysql數據庫&#xff0c;需要安裝組件NuGet包管理器 安…

AI 編程 “幻覺” 風險頻發?飛算 JavaAI 硬核技術筑牢安全防線

AI 技術已深度融入編程領域&#xff0c;為開發者帶來前所未有的便利與效率提升。然而&#xff0c;AI 編程 “幻覺” 問題如影隨形&#xff0c;頻頻引發困擾&#xff0c;成為阻礙行業穩健發展的潛在風險。飛算 JavaAI 憑借一系列硬核技術&#xff0c;強勢出擊&#xff0c;為攻克…

數據庫----軟考中級軟件設計師(自用學習筆記)

目錄 1、E-R圖 2、結構數據模型 3、數據庫的三級模式結構 4、關系代數 5、查詢 6、SQL控制語句 7、視圖?編輯 8、索引 9、關系模式 10、函數依賴 11、通過閉包求候選碼 12、范式 13、無損連接和保持函數依賴 14、數據庫設計 15、數據庫的控制功能 16、數據庫…

【Qt】Qt常見控件的相關知識點

1.close退出槽函數 2.設置快捷鍵&#xff0c;QMenu 。 適用&字母就能設置快捷鍵&#xff0c;運行qt程序&#xff0c;最后就可以按Alt對應的字母進行快捷操作。 3.QMenuBar內存泄露問題 如果ui已經自動生成了menubar&#xff0c;我們再次生成一個新的菜單欄&#xff0c;而…

httpx[http2] 和 httpx 的核心區別及使用場景如下

httpx[http2] 和 httpx 的核心區別在于 HTTP/2 協議支持&#xff0c;具體差異及使用場景如下&#xff1a; 1. 功能區別 命令/安裝方式協議支持額外依賴適用場景pip install httpx僅 HTTP/1.1無通用請求&#xff0c;輕量依賴pip install httpx[http2]支持 HTTP/2需安裝 h2>3…

Spring Boot 中 MyBatis 與 Spring Data JPA 的對比介紹

一、核心概念 MyBatis 定義&#xff1a;基于 SQL 的持久層框架&#xff0c;提供靈活的 SQL 映射和自定義查詢能力。 特點&#xff1a; 開發者手動編寫 SQL&#xff08;XML 或注解&#xff09;。 支持動態 SQL、復雜查詢優化。 輕量級&#xff0c;對數據庫控制力強。 Spri…

k8s1.27集群部署mysql8.0雙主雙從

環境介紹&#xff1a; #節點分配 159m--->兩個master&#xff0c;生產環境建議&#xff0c;一個master一個節點。 160n-->slave-0 161n-->slaves-0 #存儲卷 pv-->放在節點上&#xff0c;沒用nfs/云存儲。hostpath方式存儲。pv的資源分配1G&#xff0c;較小&#…

vivado fpga程序固化

一般下載到fpga上的程序在掉電之后就會丟失&#xff0c;如果想要掉電之后程序不丟失&#xff0c;就需要將比特流文件固化到板載的flash上。 以下以我的7a100t開發板為例&#xff0c;介紹程序固化的流程 點擊OK就可以下載了。

RabbitMQ Topic RPC

Topics(通配符模式) Topics 和Routing模式的區別是: topics 模式使?的交換機類型為topic(Routing模式使?的交換機類型為direct)topic 類型的交換機在匹配規則上進?了擴展, Binding Key?持通配符匹配(direct類型的交換機路 由規則是BindingKey和RoutingKey完全匹配) 在top…

服務器死機了需要檢查哪些問題

在這個數字化的時代&#xff0c;服務器就像是我們信息世界的“大管家”&#xff0c;可要是它突然死機了&#xff0c;那可真是讓人頭疼。今天咱們就來聊聊&#xff0c;服務器死機了&#xff0c;到底需要檢查哪些問題。 一、硬件問題 電源供應&#xff1a;檢查電源是否穩定&…

【MySQL成神之路】運算符總結

MySQL運算符總結 MySQL提供了豐富的運算符&#xff0c;用于在SQL語句中進行各種計算和比較操作。這些運算符可以分為算術運算符、比較運算符、邏輯運算符、位運算符等幾大類。合理使用這些運算符可以構建復雜的查詢條件和計算表達式。 一、算術運算符 MySQL支持基本的算術運…

自用Vscode 配置c++ debug環境

前言 使用vscode配置c debug環境的好處 1、可以借助vscode方便輕量的擴展和功能 2、避免了傳統使用gdb 復雜按鍵以及不夠直觀的可視化 3、方便一次運行&#xff0c;斷點處查看變量&#xff0c;降低找bug難度 4、某大公司項目采用類似配置&#xff0c;經過實踐檢驗 配置c運行環…

創建一個使用 GPT-4o 和 SERP 數據的 RAG 聊天機器人

亮數據-網絡IP代理及全網數據一站式服務商屢獲殊榮的代理網絡、強大的數據挖掘工具和現成可用的數據集。亮數據&#xff1a;網絡數據平臺領航者https://www.bright.cn/?promogithub15?utm_sourceorganic-social-cn&utm_campaigncsdn 本指南將解釋如何使用 Python、GPT-4…

吳恩達 Deep Learning(1-36)ppt逐行理解

課程地址&#xff1a;(超爽中英!) 2024公認最好的【吳恩達深度學習】教程&#xff01;附課件代碼 Professionalization of Deep Learning_嗶哩嗶哩_bilibili 1.目錄 2.什么是神經網絡 3.用神經網絡進行監督學習 4.為什么深度學習會興起 7.二分分類 適用于二元分類問題的函數&…

三維點云的處理

1 點云原理 https://zh.wikipedia.org/wiki/%E9%BB%9E%E9%9B%B2 點云&#xff08;英語&#xff1a;point cloud&#xff09;是空間中點的數據集&#xff0c;可以表示三維形狀或對象&#xff0c;通常由三維掃描儀獲取。點云中每個點的位置都由一組笛卡爾坐標(X,Y,Z)描述[1]&…

鴻蒙HarmonyOS多設備流轉:分布式的智能協同技術介紹

隨著物聯網和智能設備的普及&#xff0c;多設備間的無縫協作變得越來越重要。鴻蒙&#xff08;HarmonyOS&#xff09;作為華為推出的新一代操作系統&#xff0c;其分布式技術為實現多設備流轉提供了強大的支持。本文將詳細介紹鴻蒙多設備流轉的技術原理、實現方式和應用場景。 …

Spring Boot- 2 (數萬字入門教程 ):數據交互篇

JDBC交互框架: Spring的JDBC操作工具: 依賴: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> JDBC的模版類:JdbcTemplate 引入Mysql的依賴 <depe…

在 Kotlin 中,什么是內聯函數?有什么作用?

在 Kotlin 中&#xff0c;內聯函數是一種通過 inline 關鍵字聲明的函數&#xff0c;其主要目的是優化高階函數&#xff08;即以函數作為參數或返回值的函數&#xff09;的性能。 內聯函數的函數體會在編譯時直接插入到調用處&#xff0c;從而避免函數調用的開銷&#xff0c;并…

LLM筆記(五)概率論

1. 隨機變量與概率分布&#xff1a;模型輸出的基礎 在LLM中&#xff0c;隨機變量最直觀的體現就是模型預測的下一個token。每個時刻&#xff0c;模型都會輸出一個概率分布&#xff0c;表示詞匯表中每個token可能是"下一個詞"的概率。 直觀理解 想象模型在處理句子…

LeetCode-滑動窗口-找到字符串中所有字母異位詞

LeetCode-滑動窗口-找到字符串中所有字母異位詞 ?? 關于專欄&#xff1a;專欄用于記錄 prepare for the coding test。 文章目錄 LeetCode-滑動窗口-找到字符串中所有字母異位詞&#x1f4dd; 找到字符串中所有字母異位詞&#x1f3af;題目描述&#x1f50d; 輸入輸出示例&am…