學習秒殺系統-實現秒殺功能(商品列表,商品詳情,基本秒殺功能實現,訂單詳情)

文章目錄

  • 前言
  • 數據庫設計
  • 秒殺商品列表頁
  • 秒殺商品詳情
  • 實現簡單秒殺
  • 訂單詳情

前言

由于慕課課程中是先實現最基本的功能然后對其壓測,壓測那個地方出問題,然后在對其優化。所以本文記錄的也是實現的是簡單的秒殺功能沒有涉及到高并發的優化。

數據庫設計

1 商品表 包含所有商品的所有信息
2 訂單表 包含所有訂單的所有信息
3 秒殺商品表 包含秒殺商品的相關信息(id,商品id,商品庫存,秒殺價格,開始日期,結束日期)
4 秒殺訂單表 包含秒殺訂單的相關信息(id,訂單id,用戶id,商品id)
為什么要這樣設計?可不可以保留1和2 ,3和4在1和2中添加一個字段表示?
實際上這樣可行,但是不推薦,因為秒殺有很多種類型。今天秒殺,明天促銷,后天八折 豈不是每次搞一個活動都要去重新設計表和字段。而且還要修改后端相關代碼。這樣不利于維護和擴展。 其次我們單獨新建一個表,是因為秒殺是多個用戶同一時間下訂單所以并發量非常大我們需要單獨一個表在redis支撐后期。
詳細字段可以github上找一下。

秒殺商品列表頁

首頁秒殺商品列表頁其實就是將所有的秒殺商品信息查詢出來并返回。

首先在GoodsDao下 查詢滿足條件的內容

@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.miaosha_price from miaosha_goods mg left join goods g on mg.goods_id = g.id")public List<GoodsVo> listGoodsVo();

這里需要解釋一下可能的疑問點
1.左連接是什么意思?
左連接是保存左表的全部內容,然后按定義的連接條件與右表連接,若右表沒有連接規定的數據則對應的字段為null。
2.mg.goods_id = g.id 是連接條件還是查詢條件?
是連接條件,也就是按什么條件將兩表連接在一起。總不能亂拼,肯定按一定的條件拼接。若要再寫查詢條件后邊只需跟where,這里where作用的是連接后的表。
3.為什么選擇左連接?
其實左連接和右連接沒有區別,最重要的一點是如果你使用左連接則會保存左表的全部數據,所以左 表一般是右表的子集(或者比右表小),如果左表是更大的,右表是小的,則連接后會發現最后的數據表很多字段為null。在這里秒殺商品是商品的子集

查詢出來后我們要新建一個VO對象接受,因為查詢出來的字段不僅包含商品字段還會包含秒殺商品的相關字段
所以我們需要在VO目錄下新建一個對象

然后在GoodsService下定義

	@AutowiredGoodsDao goodsDao;public List<GoodsVo> listGoodsVo(){return goodsDao.listGoodsVo();}

最后在GoodsController類定義以下方法

    @RequestMapping("/to_list")public String list(Model model,MiaoshaUser user) {// 向goods_list頁面添加user對象,至于user是怎么攔截的可以看登錄功能model.addAttribute("user", user);//查詢商品列表List<GoodsVo> goodsList = goodsService.listGoodsVo();model.addAttribute("goodsList", goodsList);return "goods_list";}

實際上我們寫代碼是從controller層開始寫,這里只是方便展示從dao層開始寫。

package com.imooc.miaosha.vo;import java.util.Date;import com.imooc.miaosha.domain.Goods;public class GoodsVo extends Goods{private Double miaoshaPrice;private Integer stockCount;private Date startDate;private Date endDate;public Integer getStockCount() {return stockCount;}public void setStockCount(Integer stockCount) {this.stockCount = stockCount;}public Date getStartDate() {return startDate;}public void setStartDate(Date startDate) {this.startDate = startDate;}public Date getEndDate() {return endDate;}public void setEndDate(Date endDate) {this.endDate = endDate;}public Double getMiaoshaPrice() {return miaoshaPrice;}public void setMiaoshaPrice(Double miaoshaPrice) {this.miaoshaPrice = miaoshaPrice;}
}

疑問點?我們new一個GoodsVo對象可以訪問父類的private字段嗎?
不能,只能通過get方法訪問,即使子類繼承了父類。

隨后實現good_list前端頁面

<div class="panel panel-default"><div class="panel-heading">秒殺商品列表</div><table class="table" id="goodslist"><tr><td>商品名稱</td><td>商品圖片</td><td>商品原價</td><td>秒殺價</td><td>庫存數量</td><td>詳情</td></tr><tr  th:each="goods,goodsStat : ${goodsList}">  <td th:text="${goods.goodsName}"></td>  <td ><img th:src="@{${goods.goodsImg}}" width="100" height="100" /></td>  <td th:text="${goods.goodsPrice}"></td>  <td th:text="${goods.miaoshaPrice}"></td>  <td th:text="${goods.stockCount}"></td><td><a th:href="'/goods/to_detail/'+${goods.id}">詳情</a></td>  </tr>  </table>
</div>

前端的可以不用詳細了解,但是你必須得看懂前端的代碼,這個代碼就是循環將表格展示出來,循環的內容是我們后端添加的GoodsList對象。我們使用goods接受的對象,后邊的是狀態可以先不用管。 這里goodsName ,goodsImg貌似是父類的私有字段,為什么可以goods可以訪問?
實際上Thymeleaf 訪問的是 Java Bean 的 getter 方法,而不是直接訪問字段。
即使字段是 private 的,只要它有對應的 public getXxx() 方法(getter),Thymeleaf 就可以訪問到這個值。

秒殺商品詳情

前面商品列表前端中最后一行我們有一個超鏈接,是去點擊商品詳情的。我們需要將商品id通過路徑傳入。我們的需求是,點進去詳情后展示的有基本商品信息和秒殺倒計時以及秒殺按鈕。
第一步我們商品詳情頁面還是需要查詢出來具體的商品所以我們首先需要在GoodsController包下定義以下方法

方法中,首先根據商品id查詢具體商品信息 并添加到頁面中,其次,由于詳情頁需要展示秒殺的狀態所以我們要判斷此時秒殺的狀態。具體來說根據當前時間和秒殺時間判斷

 @RequestMapping("/to_detail/{goodsId}")public String detail(Model model,MiaoshaUser user,@PathVariable("goodsId")long goodsId) {model.addAttribute("user", user);GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);model.addAttribute("goods", goods);//獲取秒殺開始時間long startAt = goods.getStartDate().getTime();//獲取秒殺結束時間long endAt = goods.getEndDate().getTime();//獲取當前時間long now = System.currentTimeMillis();// 秒殺狀態 0是未開始 1是進行中 2是已結束int miaoshaStatus = 0;int remainSeconds = 0;//基本條件判斷if(now < startAt ) {//秒殺還沒開始,倒計時miaoshaStatus = 0;remainSeconds = (int)((startAt - now )/1000);}else  if(now > endAt){//秒殺已經結束miaoshaStatus = 2;remainSeconds = -1;}else {//秒殺進行中miaoshaStatus = 1;remainSeconds = 0;}model.addAttribute("miaoshaStatus", miaoshaStatus);model.addAttribute("remainSeconds", remainSeconds);return "goods_detail";}

1.查詢商品信息
在GoodsService下定義以下方法

	public GoodsVo getGoodsVoByGoodsId(long goodsId) {return goodsDao.getGoodsVoByGoodsId(goodsId);}

在GoodsDao下

@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.miaosha_price from miaosha_goods mg left join goods g on mg.goods_id = g.id where g.id = #{goodsId}")public GoodsVo getGoodsVoByGoodsId(@Param("goodsId")long goodsId);

其查詢代碼的含義是 按著查詢條件查詢拼接完成的代碼,參數我們需要傳遞到sql語句中所以需要用@param將參數傳遞過去

2.秒殺基本條件判斷
這里代碼中有注釋且邏輯較為簡單。我們只需記住后端傳給前端了秒殺商品的狀態和此刻的剩余時間。

3.前端邏輯處理

<div class="panel panel-default"><div class="panel-heading">秒殺商品詳情</div><div class="panel-body">//判斷user是否為空<span th:if="${user eq null}"> 您還沒有登錄,請登陸后再操作<br/></span><span>沒有收貨地址的提示。。。</span></div><table class="table" id="goodslist"><tr>  <td>商品名稱</td>  <td colspan="3" th:text="${goods.goodsName}"></td> </tr>  <tr>  <td>商品圖片</td>  <td colspan="3"><img th:src="@{${goods.goodsImg}}" width="200" height="200" /></td>  </tr><tr>  <td>秒殺開始時間</td>  <td th:text="${#dates.format(goods.startDate, 'yyyy-MM-dd HH:mm:ss')}"></td><td id="miaoshaTip">	<input type="hidden" id="remainSeconds" th:value="${remainSeconds}" /><span th:if="${miaoshaStatus eq 0}">秒殺倒計時:<span id="countDown" th:text="${remainSeconds}"></span></span><span th:if="${miaoshaStatus eq 1}">秒殺進行中</span><span th:if="${miaoshaStatus eq 2}">秒殺已結束</span></td><td><form id="miaoshaForm" method="post" action="/miaosha/do_miaosha">//點擊后會向地址/miaosha/do_miaosha post goods_id<button class="btn btn-primary btn-block" type="submit" id="buyButton">立即秒殺</button><input type="hidden" name="goodsId" th:value="${goods.id}" /></form></td></tr><tr>  <td>商品原價</td>  <td colspan="3" th:text="${goods.goodsPrice}"></td>  </tr><tr>  <td>秒殺價</td>  <td colspan="3" th:text="${goods.miaoshaPrice}"></td>  </tr><tr>  <td>庫存數量</td>  <td colspan="3" th:text="${goods.stockCount}"></td>  </tr></table>
</div>
</body>
<script>
$(function(){countDown();
});function countDown(){var remainSeconds = $("#remainSeconds").val();var timeout;//判斷基本條件if(remainSeconds > 0){//秒殺還沒開始,倒計時$("#buyButton").attr("disabled", true);timeout = setTimeout(function(){$("#countDown").text(remainSeconds - 1);$("#remainSeconds").val(remainSeconds - 1);//這里倒計時需要不斷地減少時間所以需要回調函數countDown();},1000);}else if(remainSeconds == 0){//秒殺進行中$("#buyButton").attr("disabled", false);if(timeout){clearTimeout(timeout);}$("#miaoshaTip").html("秒殺進行中");}else{//秒殺已經結束$("#buyButton").attr("disabled", true);$("#miaoshaTip").html("秒殺已經結束");}
}</script>
</html>

實現簡單秒殺

最后我們可以實現秒殺功能主要包含三部分
1減庫存 2下訂單 3寫入秒殺訂單.這三步必須在一個事務內部實現,因為如果有一個失敗了就只能全部失敗。

    @RequestMapping("/do_miaosha")public String list(Model model,MiaoshaUser user,@RequestParam("goodsId")long goodsId) {model.addAttribute("user", user);if(user == null) {return "login";}//判斷庫存,這里查詢goods有兩個目的一個是判斷庫存另一個是寫入商品相關信息。這里雖然是goods但是聯表查詢的goodsVoGoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);int stock = goods.getStockCount();if(stock <= 0) {model.addAttribute("errmsg", CodeMsg.MIAO_SHA_OVER.getMsg());return "miaosha_fail";}//判斷是否已經秒殺到了MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);if(order != null) {model.addAttribute("errmsg", CodeMsg.REPEATE_MIAOSHA.getMsg());return "miaosha_fail";}//減庫存 下訂單 寫入秒殺訂單OrderInfo orderInfo = miaoshaService.miaosha(user, goods);model.addAttribute("orderInfo", orderInfo);model.addAttribute("goods", goods);return "order_detail";}

判斷庫存這一步就是根據商品id查詢商品,隨后判斷庫存是否小于0。不過多贅述

第二部判斷用戶是否秒殺過此商品了?因為每個秒殺商品用戶只能秒殺一次,所以需要判斷。我們判斷訂單表中用戶是否秒殺此商品,因此我們的條件要有兩個一個是用戶id一個是商品id。缺一不可

@Select("select * from miaosha_order where user_id=#{userId} and goods_id=#{goodsId}")public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(@Param("userId")long userId, @Param("goodsId")long goodsId);

我們只需要在dao層加入相關代碼。

隨后就是核心代碼我們首先創建miaosha對象

package com.imooc.miaosha.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.imooc.miaosha.domain.MiaoshaUser;
import com.imooc.miaosha.domain.OrderInfo;
import com.imooc.miaosha.vo.GoodsVo;@Service
public class MiaoshaService {@AutowiredGoodsService goodsService;@AutowiredOrderService orderService;@Transactionalpublic OrderInfo miaosha(MiaoshaUser user, GoodsVo goods) {//減庫存 下訂單 寫入秒殺訂單goodsService.reduceStock(goods);//order_info maiosha_orderreturn orderService.createOrder(user, goods);}}

首先這是一個事務必須定義@Transactional
1.減庫存
在我們對應秒殺商品數據庫下的庫存–,首先我們需要知道是那個商品。

	public void reduceStock(GoodsVo goods) {MiaoshaGoods g = new MiaoshaGoods();g.setGoodsId(goods.getId());goodsDao.reduceStock(g);}

這里為啥要new一個秒殺商品呢?因為我們傳過來的參數是GoodsVo 在數據庫并沒有表對應此類型,所以需要new秒殺商品對象,隨后傳入商品的id,dao利用id對其更新庫存。其實我個人感覺對于此更新方法直接傳一個goodsId然后用@Param綁定不就好了為什么非要傳一個對象?
dao層的實現

@Update("update miaosha_goods set stock_count = stock_count - 1 where goods_id = #{goodsId}")public int reduceStock(MiaoshaGoods g);

疑問點:為什么更新操作的返回值是int?這是因為更新操作會返回更新成功的行數

生成訂單分為兩步1.寫orderinfo 2.寫秒殺order 具體業務邏輯

package com.imooc.miaosha.service;import java.util.Date;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.imooc.miaosha.dao.OrderDao;
import com.imooc.miaosha.domain.MiaoshaOrder;
import com.imooc.miaosha.domain.MiaoshaUser;
import com.imooc.miaosha.domain.OrderInfo;
import com.imooc.miaosha.vo.GoodsVo;@Service
public class OrderService {@AutowiredOrderDao orderDao;public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(long userId, long goodsId) {return orderDao.getMiaoshaOrderByUserIdGoodsId(userId, goodsId);}@Transactionalpublic OrderInfo createOrder(MiaoshaUser user, GoodsVo goods) {OrderInfo orderInfo = new OrderInfo();//將訂單相關信息寫入orderInfo.setCreateDate(new Date());orderInfo.setDeliveryAddrId(0L);orderInfo.setGoodsCount(1);orderInfo.setGoodsId(goods.getId());orderInfo.setGoodsName(goods.getGoodsName());orderInfo.setGoodsPrice(goods.getMiaoshaPrice());orderInfo.setOrderChannel(1);orderInfo.setStatus(0);orderInfo.setUserId(user.getId());//生成訂單,這里要獲取訂單id然后寫入秒殺訂單里面long orderId = orderDao.insert(orderInfo);//秒殺訂單信息吸入MiaoshaOrder miaoshaOrder = new MiaoshaOrder();miaoshaOrder.setGoodsId(goods.getId());miaoshaOrder.setOrderId(orderId);miaoshaOrder.setUserId(user.getId());//生成秒殺訂單orderDao.insertMiaoshaOrder(miaoshaOrder);return orderInfo;}}

隨后在dao層寫入代碼

@Insert("insert into order_info(user_id, goods_id, goods_name, goods_count, goods_price, order_channel, status, create_date)values("+ "#{userId}, #{goodsId}, #{goodsName}, #{goodsCount}, #{goodsPrice}, #{orderChannel},#{status},#{createDate} )")@SelectKey(keyColumn="id", keyProperty="id", resultType=long.class, before=false, statement="select last_insert_id()")public long insert(OrderInfo orderInfo);

疑問點:這里為什么也要加@Transactional ?外層不是加了嗎?
其實單說秒殺外層函數加@Transactional其實夠了,在里邊加注解是為了防止別的方法調用此函數時形成不一致的情況。

疑問點:插入訂單時如何返回訂單id的?
用Mybatis中SelectKey注解,具體解釋如下
@SelectKey(
keyColumn = “id”, // 數據庫中自增主鍵的列名
keyProperty = “id”, // Java 對象中對應的屬性名
resultType = long.class, // 主鍵的 Java 類型
before = false, // 表示在 insert 語句執行“之后”再執行 select last_insert_id()
statement = “select last_insert_id()” // 執行的 SQL 語句,用于獲取最近插入記錄的自增主鍵
)
在執行 @Insert 插入操作后,自動執行一條 SQL(這里是 select last_insert_id()),把插入成功后的自增主鍵值寫入你傳入對象(orderInfo)的某個屬性中(這里是 id)。

隨后在將相關信息寫入秒殺訂單表

	@Insert("insert into miaosha_order (user_id, goods_id, order_id)values(#{userId}, #{goodsId}, #{orderId})")public int insertMiaoshaOrder(MiaoshaOrder miaoshaOrder);

訂單詳情

最后我們返回的是訂單頁
我們只需要將后端的訂單信息和商品信息傳入到前端,前端按一定的形式展示即可。

<div class="panel panel-default"><div class="panel-heading">秒殺訂單詳情</div><table class="table" id="goodslist"><tr>  <td>商品名稱</td>  <td th:text="${goods.goodsName}" colspan="3"></td> </tr>  <tr>  <td>商品圖片</td>  <td colspan="2"><img th:src="@{${goods.goodsImg}}" width="200" height="200" /></td>  </tr><tr>  <td>訂單價格</td>  <td colspan="2" th:text="${orderInfo.goodsPrice}"></td>  </tr><tr><td>下單時間</td>  <td th:text="${#dates.format(orderInfo.createDate, 'yyyy-MM-dd HH:mm:ss')}" colspan="2"></td>  </tr><tr><td>訂單狀態</td>  <td ><span th:if="${orderInfo.status eq 0}">未支付</span><span th:if="${orderInfo.status eq 1}">待發貨</span><span th:if="${orderInfo.status eq 2}">已發貨</span><span th:if="${orderInfo.status eq 3}">已收貨</span><span th:if="${orderInfo.status eq 4}">已退款</span><span th:if="${orderInfo.status eq 5}">已完成</span></td>  <td><button class="btn btn-primary btn-block" type="submit" id="payButton">立即支付</button></td></tr><tr><td>收貨人</td>  <td colspan="2">XXX  18812341234</td>  </tr><tr><td>收貨地址</td>  <td colspan="2">北京市昌平區回龍觀龍博一區</td>  </tr></table>
</div>

今天這一節主要實現的是簡單的秒殺,后續還會進行優化。

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

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

相關文章

React 的常用鉤子函數在Vue中是如何設計體現出來的。

1、定義響應式數據&#xff1a; React 通過 useState 和 useReducer Vue 通過 ref 和 reactiveconst [state, setState] useState(initialState)const [state, dispatch] useReducer(reducer, initialState)2、定義緩存數據&#xff1a; React 通過 memo 和 useMemo useCal…

開源的 H.264/AVC 視頻編碼器庫-x264 的交叉編譯 和 程序測試

一、環境準備 安裝交叉編譯工具鏈 根據目標ARM架構選擇對應工具鏈&#xff08;如arm-linux-gnueabihf-&#xff09;&#xff1a;# Ubuntu/Debian系統 sudo apt-get install gcc-arm-linux-gnueabihf g-arm-linux-gnueabihf# 驗證安裝 arm-linux-gnueabihf-gcc --version或者手動…

自由學習記錄(69)

RectToPolar() 是 將直角坐標系 (笛卡爾坐標系) 的 uv 坐標&#xff0c;轉化為極坐標系&#xff08;θ&#xff0c;r&#xff09; uv - centerUV&#xff1a;將坐標原點平移&#xff0c;使 (0.5, 0.5) 變成原點。 r length(uv)&#xff1a;距離中心點的半徑&#xff08;從中…

Spring Boot 敏感信息入庫加密全面解決方案

Spring Boot 敏感信息入庫加密全面解決方案 在當今數據驅動的時代,保護用戶隱私數據已成為系統設計的必備要求。本文將詳細介紹 Spring Boot 應用中敏感數據加密存儲的完整方案,涵蓋從基礎實現到生產級落地的全流程。 一、加密方案選型 1.1 常見加密類型對比 加密類型特點…

docker0網卡沒有ip一步解決

正常查看ip的時候一直顯示沒有ip這里先刪除docker0網卡ip link delete docker0然后重啟服務systemctl restart docker再次查看顯示有ip了并且查看配置文件也是正常的cat /etc/docker/daemon.json {"registry-mirrors": ["https://docker.m.daocloud.io",&q…

MYSQL-索引篇

索引結構概述MySQL 的索引是在存儲引擎層實現的&#xff0c;不同的存儲引擎有不同的索引結構&#xff0c;主要包含以下幾種&#xff1a;索引結構描述BTree索引最常見的索引類型&#xff0c;大部分引擎都支持 B 樹索引Hash索引底層數據結構是用哈希表實現的&#xff0c;只有精確…

(純新手教程)HTML零基礎教學

&#xff08;下一章&#xff1a;python網絡爬蟲&#xff09;HTML 簡介HTML&#xff08;HyperText Markup Language&#xff0c;超文本標記語言&#xff09;是用于創建網頁的標準標記語言。什么是 HTML&#xff1f;HTML 不是編程語言&#xff0c;而是一種標記語言使用標簽來描述…

前端面試寶典---項目難點2-智能問答對話框采用虛擬列表動態渲染可視區域元素(10萬+條數據)

引言 在我參與智能問答項目中一個智能體回話并不會像豆包一樣&#xff0c;每次新建會話都是是從頭開始&#xff0c;而項目中你想創建新會話就像chatbox一樣&#xff0c;是點擊橡皮擦開啟新的聊天上下文&#xff0c;但是直接的聊天記錄依然存在&#xff0c;針對超過十萬&#xf…

Python元組:不可變數據的強大用法

文章目錄元組概念1.基本特性2.創建元組3.訪問元素4.元組的不可變性5.元組操作6.元組解包7.命名元組8.元組與列表的比較9.元組的優勢10.適用場景11.常用方法小結元組 概念 元組是 Python 中一個非常重要的內置數據結構&#xff0c;它與列表(list)相似但具有關鍵差異。下面我將…

若爾蓋濕地的花湖

花湖位于若爾蓋縣和甘肅的郎木寺之間的213國道旁&#xff0c;屬于若爾蓋濕地國家級自然保護區內。又名“梅朵湖”&#xff0c;因陽光照射下湖面色彩斑斕如絢麗的花瓣得名。花湖的大門是梯形高大石柱搭成&#xff0c;我們需要過天橋到對面檢票坐小交通。通過車窗看到一層一層的云…

50天50個小項目 (Vue3 + Tailwindcss V4) ? | DoubleClickHeart(雙擊愛心)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— DoubleClickHeart組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script se…

1-緒論-1-數據結構的基本概念

&#x1f389; 數據結構的魔法世界&#x1f4da;&#x1f468;?&#x1f393;“數據就像大海中的浪花&#xff0c;結構則是那神秘的洋流。掌握數據結構&#xff0c;就是掌握在信息海洋中自由航行的力量&#xff01;”引言&#xff1a;為什么要學數據結構&#xff1f;&#x1f…

linux網絡相關命令簡介

目錄 一、IP命令 1、Link或L:管理網絡接口(網卡) 2、Address或Addr,A:管理Ip地址 3、Route或R:管理路由表

教育培訓機構如何為課程視頻添加防盜錄的強水印?

在知識付費時代&#xff0c;教育培訓機構的課程視頻是核心資產&#xff0c;但盜錄、非法傳播等問題卻讓機構防不勝防。如何在不影響學員觀看體驗的前提下&#xff0c;為課程視頻添加“強效防盜水印”&#xff0c;精準追蹤泄露源頭&#xff1f;本文將為您揭秘高安全性水印的添加…

python的形成性考核管理系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持&#xff1a; 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具&#xff1a;Navicat/SQLyog等都可以 摘要 隨著…

A*算法詳解

A*算法詳解一、A*算法基礎概念1.1 算法定位1.2 核心評估函數1.3 關鍵數據結構二、A*算法的核心步驟三、啟發函數設計3.1 網格地圖中的啟發函數3.2 啟發函數的選擇原則三、Java代碼實現四、啟發函數的設計與優化4.1 啟發函數的可采納性4.2 啟發函數的效率影響4.3 常見啟發函數對…

.net winfrom 獲取上傳的Excel文件 單元格的背景色

需求&#xff1a;根據Excel某行標注了黃色高亮顏色&#xff0c;說明該行數據已被用戶選中(Excel文件中并沒有“已選中”這一列&#xff0c;純粹用顏色表示)&#xff0c;導入數據到數據庫時標注此行已選中直接上代碼&#xff1a;//選擇Excel文件private void btnBrowse_Click(ob…

OpenAI GPT-4o技術詳解:全能多模態模型的架構革新與生態影響

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; ?? 一、核心定義與發布背景 官方定位 GPT-4o&#xff08;“o”代表“…

? 構建真正的高性能即時通訊服務:基于 Netty 集群的架構設計與實現

引子 在前面的文章中&#xff0c;我們基于 Netty 構建了一套單體架構的即時通訊服務。雖然單體架構在開發初期簡單高效&#xff0c;但隨著用戶量的增長和業務規模的擴大&#xff0c;其局限性逐漸顯現。當面對高并發場景時&#xff0c;單體 Netty 服務很容易觸及性能天花板&…

原來時間序列挖掘這么簡單

先搞懂&#xff1a;啥是時間序列&#xff1f;簡單說&#xff0c;時間序列就是按時間順序記下來的數據。比如&#xff1a;你每天早上 8 點測的體重&#xff0c;連起來就是 “體重時間序列”&#xff1b;超市每天的銷售額&#xff0c;連起來就是 “銷售時間序列”&#xff1b;城市…