主頁 > 後端開發 > 一套前后臺全部開源的H5商城送給大家

一套前后臺全部開源的H5商城送給大家

2023-05-06 07:42:26 後端開發

博主給大家推薦一套全部開源的H5電商專案waynboot-mall,由博主在2020年開發至今,已有三年之久,那時候網上很多的H5商城專案都是半開源版本,要么沒有H5前端代碼,要么需要加群咨詢,屬實惡心,于是博主決定自己開發一套完整的移動端H5商城,包含一個管理后臺、一個前臺H5商城、一套后端介面,專案地址如下:

  • H5商城前端代碼:https://github.com/wayn111/waynboot-mobile
  • 運營后臺前端代碼:https://github.com/wayn111/waynboot-admin
  • 后端介面代碼:https://github.com/wayn111/waynboot-mall

歡迎大家關注這個專案,點個Star讓更多的人了解到這個專案,

一、簡介

waynboot-mall是一套全部開源的微商城專案,實作了一個商城所需的首頁展示、商品分類、商品詳情、sku組合、商品搜索、購物車、結算下單、訂單狀態流轉、商品評論等一系列功能,
技術上基于最新得Spring Boot3.0、Jdk17,整合了Redis、RabbitMQ、ElasticSearch等常用中間件,
貼近生產環境實際經驗開發而來,


二、技術特點

  1. 訂單金額計算使用BigDeciaml型別,支持小數點后兩位
  2. 支持微信內JsApi支付、H5網頁支付
  3. 商城介面代碼清晰、注釋完善、模塊拆分合理
  4. 使用Spring-Security進行訪問權限控制
  5. 使用jwt進行介面授權驗證
  6. ORM層使用Mybatis Plus提升開發效率
  7. 添加全域例外處理器,統一例外處理
  8. 使用Spring Boot admin進行服務監控
  9. 集成七牛云存盤配置,支持上傳檔案至七牛獲取cdn下載鏈接
  10. 集成常用郵箱配置,方便發送郵件
  11. 添加策略模式使用示例,優化首頁金剛區跳轉邏輯
  12. 拆分出通用的資料訪問模塊,統一Redis & Elastic配置與訪問
  13. 使用Elasticsearch高級客戶端依賴對Elasticsearch進行操作
  14. 支持商品資料同步Elasticsearch操作以及中文分詞搜索
  15. RabbitMQ生產者發送訊息采用異步confirm模式,消費者消費訊息時需手動確認確保訊息不丟失
  16. 下單處理程序引入RabbitMQ,異步生成訂單記錄,提高系統下單處理能力

三、商城設計

文專案目錄

|-- waynboot-monitor               // 監控模塊
|-- waynboot-admin-api             // 運營后臺api模塊,提供后臺專案api介面
|-- waynboot-common                // 通用模塊,包含專案核心基礎類
|-- waynboot-data                  // 資料模塊,通用中間件資料訪問
|   |-- waynboot-data-redis        // redis訪問配置模塊
|   |-- waynboot-data-elastic      // elastic訪問配置模塊
|-- waynboot-generator             // 代碼生成模塊
|-- waynboot-message-consumer      // 消費者模塊,處理訂單訊息和郵件訊息
|-- waynboot-message-core          // 消費者核心模塊,佇列、交換機配置
|-- waynboot-mobile-api            // h5商城api模塊,提供h5商城api介面
|-- pom.xml                        // maven父專案依賴,定義子專案依賴版本
|-- ...

技術亮點

2.1 庫存扣減

庫存扣減操作是在下單操作扣級訓是在支付成功時扣減?(ps:扣減庫存使用樂觀鎖機制 where goods_num - num >= 0

  1. 下單時扣減,這個方案屬于實時扣減,當有大量下單請求時,由于訂單數小于請求數,會發生下單失敗,但是無法防止短時間大量惡意請求占用庫存,
    造成普通用戶無法下單
  2. 支付成功扣減,這個方案可以預防惡意請求占用庫存,但是會存在多個請求同時下單后,在支付回呼中扣減庫存失敗,導致訂單還是下單失敗并且還要退還訂單金額(這種請求就是訂單數超過了庫存數,無法發貨,影響用戶體驗)
  3. 還是下單時扣減,但是對于未支付訂單設定一個超時過期機制,比如下單時庫存減一,生成訂單后,對于未在15分鐘內完成支付的訂單,
    自動取消超期未支付訂單并將庫存加一,該方案基本滿足了大部分使用場景
  4. 針對大流量下單場景,比如一分鐘內五十萬次下單請求,可以通過設定虛擬庫存的方式減少下單介面對資料庫的訪問,具體來說就是把商品庫存快取到redis中,
    下單時配合lua腳本原子的get和decr商品庫存數量(這一步就攔截了大部分請求),執行成功后在扣減實際庫存

2.2 首頁查詢

首頁商品展示介面利用多執行緒技術進行查詢優化,將多個sql陳述句的排隊查詢變成異步查詢,介面時長只跟查詢時長最大的sql查詢掛鉤

// 使用CompletableFuture異步查詢
List<CompletableFuture<Void>> list = new ArrayList<>();
CompletableFuture<Void> f1 = CompletableFuture.supplyAsync(() -> iBannerService.list(Wrappers.lambdaQuery(Banner.class).eq(Banner::getStatus, 0).orderByAsc(Banner::getSort)), homeThreadPoolTaskExecutor).thenAccept(data -> {
    String key = "bannerList";
    redisCache.setCacheMapValue(SHOP_HOME_INDEX_HASH, key, data);
    success.add(key, data);
});
CompletableFuture<Void> f2 = CompletableFuture.supplyAsync(() -> iDiamondService.list(Wrappers.lambdaQuery(Diamond.class).orderByAsc(Diamond::getSort).last("limit 10")), homeThreadPoolTaskExecutor).thenAccept(data -> {
    String key = "categoryList";
    redisCache.setCacheMapValue(SHOP_HOME_INDEX_HASH, key, data);
    success.add(key, data);
});
list.add(f1);
list.add(f2);
// 主執行緒等待子執行緒執行完畢
CompletableFuture.allOf(list.toArray(new CompletableFuture[0])).join();

2.3 中文分詞搜索

ElasticSearch搜索查詢,查詢包含搜索關鍵字并且是上架中的商品,在根據指定欄位進行排序,最后分頁回傳

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
MatchQueryBuilder matchFiler = QueryBuilders.matchQuery("isOnSale", true);
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("name", keyword);
MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery("keyword", keyword);
boolQueryBuilder.filter(matchFiler).should(matchQuery).should(matchPhraseQueryBuilder).minimumShouldMatch(1);
searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));
// 按是否新品排序
if (isNew) { 
    searchSourceBuilder.sort(new FieldSortBuilder("isNew").order(SortOrder.DESC));
}
// 按是否熱品排序
if (isHot) {
    searchSourceBuilder.sort(new FieldSortBuilder("isHot").order(SortOrder.DESC));
}
// 按價格高低排序
if (isPrice) {
    searchSourceBuilder.sort(new FieldSortBuilder("retailPrice").order("asc".equals(orderBy) ? SortOrder.ASC : SortOrder.DESC));
}
// 按銷量排序
if (isSales) {
    searchSourceBuilder.sort(new FieldSortBuilder("sales").order(SortOrder.DESC));
}
// 篩選新品
if (filterNew) {
    MatchQueryBuilder filterQuery = QueryBuilders.matchQuery("isNew", true);
    boolQueryBuilder.filter(filterQuery);
}
// 篩選熱品
if (filterHot) {
    MatchQueryBuilder filterQuery = QueryBuilders.matchQuery("isHot", true);
    boolQueryBuilder.filter(filterQuery);
}

searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.from((int) (page.getCurrent() - 1) * (int) page.getSize());
searchSourceBuilder.size((int) page.getSize());
List<JSONObject> list = elasticDocument.search("goods", searchSourceBuilder, JSONObject.class);

2.4 訂單編號

訂單編號生成規則:秒級時間戳 + 加密用戶ID + 今日第幾次下單

  1. 秒級時間戳:時間遞增保證唯一性
  2. 加密用戶ID:加密處理,回傳用戶ID6位數字,可以防并發訪問,同一秒用戶不會產生2個訂單
  3. 今日第幾次下單:便于運營查詢處理用戶當日訂單
/**
 * 回傳訂單編號,生成規則:秒級時間戳 + 加密用戶ID + 今日第幾次下單
 *
 * @param userId 用戶ID
 * @return 訂單編號
 */
public static String generateOrderSn(Long userId) {
        long now = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
        return now + encryptUserId(String.valueOf(userId), 6) + countByOrderSn(userId);
}

/**
 * 計算該用戶今日內第幾次下單
 *
 * @param userId 用戶ID
 * @return 該用戶今日第幾次下單
 */
public static int countByOrderSn(Long userId) {
        IOrderService orderService = SpringContextUtil.getBean(IOrderService.class);
        return orderService.count(new QueryWrapper<Order>().eq("user_id", userId)
        .gt("create_time", LocalDate.now())
        .lt("create_time", LocalDate.now().plusDays(1)));
}

/**
 * 加密用戶ID,回傳num位字串
 *
 * @param userId 用戶ID
 * @param num    長度
 * @return num位加密字串
 */
private static String encryptUserId(String userId, int num) {
        return String.format("%0" + num + "d", Integer.parseInt(userId) + 1);
}

2.5 異步下單

下單流程處理程序,通過rabbitMQ異步生成訂單,提高系統下單處理能力

  1. 用戶點擊提交訂單按鈕,后臺生成訂單編號和訂單金額跳轉到訂單支付頁面,并將訂單編號等資訊發送rabbitMQ訊息(生成訂單編號,還未生成訂單)
  2. 訂單消費者接受到訂單訊息后,獲取訂單編號生成訂單記錄(訂單創建成功,用戶待支付)
  3. 下單頁面,前端根據訂單編號輪詢訂單介面,訂單已創建則跳轉支付頁面,否則提示下單失敗(訂單創建失敗)
  4. 支付頁面,用戶點擊支付按鈕時,后臺呼叫微信/支付寶下單介面后,前端喚醒微信/支付寶支付,用戶輸入密碼
  5. 用戶支付完成后在微信/支付寶下回呼通知里更新訂單狀態為已支付(訂單已支付)
  6. 用戶支付完成后,回傳支付狀態查看頁面,

2.6 設計模式

金剛區跳轉使用策略模式進行代碼撰寫

1.定義金剛位跳轉策略介面以及跳轉列舉類

public interface DiamondJumpType {

    List<Goods> getGoods(Page<Goods> page, Diamond diamond);

    Integer getType();
}

// 金剛位跳轉型別列舉
public enum JumpTypeEnum {
    COLUMN(0),
    CATEGORY(1);

    private Integer type;

    JumpTypeEnum(Integer type) {
        this.type = type;
    }

    public Integer getType() {
        return type;
    }

    public JumpTypeEnum setType(Integer type) {
        this.type = type;
        return this;
    }
}

2.定義策略實作類,并使用@Component注解注入spring

// 分類策略實作
@Component
public class CategoryStrategy implements DiamondJumpType {

    @Autowired
    private GoodsMapper goodsMapper;

    @Override
    public List<Goods> getGoods(Page<Goods> page, Diamond diamond) {
        List<Long> cateList = Arrays.asList(diamond.getValueId());
        return goodsMapper.selectGoodsListPageByl2CateId(page, cateList).getRecords();
    }

    @Override
    public Integer getType() {
        return JumpTypeEnum.CATEGORY.getType();
    }
}

// 欄目策略實作
@Component
public class ColumnStrategy implements DiamondJumpType {

    @Autowired
    private IColumnGoodsRelationService iColumnGoodsRelationService;

    @Autowired
    private IGoodsService iGoodsService;

    @Override
    public List<Goods> getGoods(Page<Goods> page, Diamond diamond) {
        List<ColumnGoodsRelation> goodsRelationList = iColumnGoodsRelationService.list(new QueryWrapper<ColumnGoodsRelation>()
                .eq("column_id", diamond.getValueId()));
        List<Long> goodsIdList = goodsRelationList.stream().map(ColumnGoodsRelation::getGoodsId).collect(Collectors.toList());
        Page<Goods> goodsPage = iGoodsService.page(page, new QueryWrapper<Goods>().in("id", goodsIdList).eq("is_on_sale", true));
        return goodsPage.getRecords();
    }

    @Override
    public Integer getType() {
        return JumpTypeEnum.COLUMN.getType();
    }
}

3.定義策略背景關系,通過構造器注入spring,定義map屬性,通過key獲取對應策略實作類

@Component
public class DiamondJumpContext {

    private final Map<Integer, DiamondJumpType> map = new HashMap<>();

    /**
     * 由spring自動注入DiamondJumpType子類
     *
     * @param diamondJumpTypes 金剛位跳轉型別集合
     */
    public DiamondJumpContext(List<DiamondJumpType> diamondJumpTypes) {
        for (DiamondJumpType diamondJumpType : diamondJumpTypes) {
            map.put(diamondJumpType.getType(), diamondJumpType);
        }
    }

    public DiamondJumpType getInstance(Integer jumpType) {
        return map.get(jumpType);
    }
}

4.使用,注入DiamondJumpContext物件,呼叫getInstance方法傳入列舉型別

@Autowired
private DiamondJumpContext diamondJumpContext;

@Test
public void test(){
    DiamondJumpType diamondJumpType=diamondJumpContext.getInstance(JumpTypeEnum.COLUMN.getType());
}

四、演示圖

商城登陸 商城注冊
商城首頁 商城搜索
搜索結果展示 金剛位跳轉
商品分類 商品詳情
商品sku選擇 購物車查看
確認下單 選擇支付方式
商城我的頁面 我的訂單串列
添加商品評論 查看商品評論
后臺登陸 后臺首頁
后臺會員管理 后臺評論管理
后臺地址管理 后臺添加商品
后臺商品管理 后臺banner管理
后臺訂單管理 后臺分類管理
后臺金剛區管理 后臺欄目管理

五、在線體驗

演示地址:http://121.4.124.33/mall

最后說兩句waynboot-mall作為博主的開源專案集大成者,對于沒有接觸過商城專案的小伙伴來說是非常具有幫助和學習價值的,看完這個專案你能了解到一個商城專案的基本全貌,提前避坑,

感謝大家閱讀,希望這篇文章能為你提供價值,公眾號【waynblog】每周分享技術干貨、開源專案、實戰經驗、高效開發工具等,您的關注將是我的更新動力??,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/551721.html

標籤:其他

上一篇:go測驗庫之apitest

下一篇:返回列表

標籤雲
其他(158485) Python(38118) JavaScript(25401) Java(18023) C(15222) 區塊鏈(8261) C#(7972) AI(7469) 爪哇(7425) MySQL(7162) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5335) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4565) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2432) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1965) Web開發(1951) HtmlCss(1932) python-3.x(1918) 弹簧靴(1913) C++(1912) xml(1889) PostgreSQL(1874) .NETCore(1857) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 一套前后臺全部開源的H5商城送給大家

    博主給大家推薦一套全部開源的H5電商專案waynboot-mall。由博主在2020年開發至今,已有三年之久。那時候網上很多的H5商城專案都是半開源版本,要么沒有H5前端代碼,要么需要加群咨詢,屬實惡心。于是博主決定自己開發一套完整的移動端H5商城,包含一個管理后臺、一個前臺H5商城、一套后端介面。 ......

    uj5u.com 2023-05-06 07:42:26 more
  • go測驗庫之apitest

    前言 使用go語言做開發差不多快一年了,主要用來寫后端Web服務,從一開始吐槽他的結構體,比如創建個復雜的JSON格式資料,那是相當的痛苦。還有 err 處理寫的巨麻煩。 當然,go 也有爽的地方,創建個線協程簡直太簡單了。 到后來慢慢接受,覺得效率還行,因為是靜態強型別語言,在修改完專案代碼之后, ......

    uj5u.com 2023-05-06 07:41:31 more
  • Java8 Stream流的合并

    最近的需求里有這樣一個場景,要校驗一個集合中每個物件的多個Id的有效性。比如一個Customer物件,有3個Id:id1,id2,id3,要把這些Id全部取出來,然后去資料庫里查詢它是否存在。 @Data @AllArgsConstructor public class Customer { pri ......

    uj5u.com 2023-05-06 07:41:25 more
  • 【Visual Leak Detector】在 VS 高版本中使用 VLD

    說明 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。 本篇介紹如何在 VS 高版本中使用 vld2.5.1。同系列文章目錄可見 《記憶體泄漏檢測工具》目錄 1. 使用前的準備 參考本人另一篇博客 安裝 Visual Leak Detector 下載 vld-2.5.1-setup.exe 并 ......

    uj5u.com 2023-05-06 07:41:21 more
  • 掌握這些GitHub搜索技巧,你的開發效率將翻倍!

    作為開發it行業一員,學習借鑒他人專案是很有必要的,所以我們一般都會從github或者 Gitee 上面去參考借鑒他人的專案來學習增加自己的專案經驗 但是github你真的用對了嘛,他的功能其實很強大!!! githu專案搜索 關鍵字搜索 在Github搜索欄中輸入與您感興趣的技術相關的關鍵詞,例如 ......

    uj5u.com 2023-05-06 07:39:36 more
  • MyBatis 配置詳解

    (MyBatis 配置詳解) mybatis-config.xml 核心組態檔 mybatis-config.xml 包含的內容如下 configuration(配置) properties(屬性) settings(設定) typeAliases(型別別名) typeHandlers(型別處理器 ......

    uj5u.com 2023-05-06 07:38:56 more
  • C++容器(vector、deque、list、map)

    ##(1) vector:將元素置于一個動態陣列中,可以隨機存盤元素(也就是用索引直接存取)。 陣列尾部添加或洗掉元素非常迅速。但在中部或頭部就比較費時。 *代碼演示:* 取: at在下標越界時會拋出例外,我們能捕獲例外進行處理;而[]下標越界會讓程式直接終止; 建構式: cbegin, cend ......

    uj5u.com 2023-05-06 07:38:22 more
  • 1分鐘了解C語言正確使用位元組對齊及#pragma pack的方法

    ? C/C++編譯器的預設位元組對齊方式為自然對界。即在預設情況下,編譯器為每一個變數或是資料單元按其自然對界條件分配空間。 在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序存盤(成員之間可能有插入的空位元組),第一個成員的地址和整 ......

    uj5u.com 2023-05-06 07:37:55 more
  • boot-admin整合Liquibase實作資料庫版本管理

    Liquibase 和 Flyway 是兩款成熟的、優秀的、開源/商業版的資料庫版本管理工具,鑒于 Flyway 的社區版本對 Oracle 資料庫支持存在限制,所以 boot-admin 選擇整合 Liquibase 提供資料庫版本管理能力支持。 Liquibase 開源版使用 Apache 2. ......

    uj5u.com 2023-05-06 07:37:48 more
  • NSIS官方認證插件集成安裝包

    本次制作的集成安裝包集成了NSIS官方wiki認證的所有插件(無法下載或者嚴重過時的除外),翻譯了部分比較冷門插件的使用說明。額外集成了關于皮膚,按鈕美化以及用于視窗子類化等少數幾個優秀的第三方插件。所有插件皆為當前能得到的最新版本。 由于兼容性原因,在不干擾正常使用的情況下強烈建議將nsis升級為 ......

    uj5u.com 2023-05-06 07:37:38 more