springboot1.5.10相容高版本6.1.1elasticsearch

来源:https://www.cnblogs.com/tinyj/archive/2018/11/24/10014117.html
-Advertisement-
Play Games

1.引入依賴 2.配置信息: 3.es配置啟動類: 4.操作工具類: ...


1.引入依賴

<dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.plugin</groupId>
            <artifactId>transport-netty4-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>2.11.0</version>
        </dependency>

2.配置信息:

/**
 * 讀取client配置信息
 * @author 
 *
 */
@Configuration
@Getter
@Setter
public class ClientConfig {
    
    /** 
     * elk集群地址 
     */  
    @Value("${elasticsearch.ip}")
    private String esHostName;  
    /** 
     * 埠 
     */  
    @Value("${elasticsearch.port}")
    private Integer esPort;  
    /** 
     * 集群名稱 
     */  
    @Value("${elasticsearch.cluster.name}")
    private String esClusterName;  
  
    /** 
     * 連接池 
     */  
    @Value("${elasticsearch.pool}")
    private Integer esPoolSize;  
  
    
    /** 
     * 是否服務啟動時重新創建索引
     */  
    @Value("${elasticsearch.regenerateIndexEnabled}")
    private Boolean esRegenerateIndexFlag; 
    
    
    /** 
     * 是否服務啟動時索引數據同步
     */  
    @Value("${elasticsearch.syncDataEnabled}")
    private Boolean esSyncDataEnabled; 
}

3.es配置啟動類:

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;

/**
 * es配置啟動類
 * @author
 *
 */
@Configuration
public class ElasticsearchConfig {
    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticsearchConfig.class);
    
    @Autowired
    ClientConfig clientConfig;
    
    @Bean
    public TransportClient init() {
        LOGGER.info("初始化開始。。。。。");  
        TransportClient transportClient = null;
  
        try {  
            /**
             *  配置信息 
             *  client.transport.sniff   增加嗅探機制,找到ES集群 
             *  thread_pool.search.size  增加線程池個數,暫時設為5  
             */
            Settings esSetting = Settings.builder()
                    .put("client.transport.sniff", true) 
                    .put("thread_pool.search.size", clientConfig.getEsPoolSize())
                    .build();  
            //配置信息Settings自定義
            transportClient = new PreBuiltTransportClient(esSetting);
            TransportAddress transportAddress = new TransportAddress(InetAddress.getByName(clientConfig.getEsHostName()), clientConfig.getEsPort());
            transportClient.addTransportAddresses(transportAddress);  
  
  
        } catch (Exception e) {  
            LOGGER.error("elasticsearch TransportClient create error!!!", e);  
        }  
  
        return transportClient;  
    }  
    
    
}

4.操作工具類:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.bulk.BackoffPolicy;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;


public class ElasticsearchUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticsearchUtils.class);

    @Autowired
    private TransportClient transportClient;

    private static TransportClient client;

    @PostConstruct
    public void init() {
        client = this.transportClient;
    }

    /**
     * 創建索引以及設置其內容
     * @param index
     * @param indexType
     * @param filePath:json文件路徑
     */
    public static void createIndex(String index,String indexType,String filePath) throws RuntimeException {
        try {
                StringBuffer strBuf = new StringBuffer();
                //解析json配置
                ClassPathResource resource = new ClassPathResource(filePath);
                InputStream inputStream = resource.getInputStream();

                int len = 0;
                byte[] buf = new byte[1024];
                while((len=inputStream.read(buf)) != -1) {
                    strBuf.append(new String(buf, 0, len, "utf-8"));
                }
                inputStream.close();
                //創建索引
                createIndex(index);
                //設置索引元素
                putMapping(index, indexType, strBuf.toString());

        }catch(Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }


        /**
         * 創建索引
         *
         * @param index 索引名稱
         * @return
         */
        public static boolean createIndex(String index){

            try {
                if (isIndexExist(index)) {
                    //索引庫存在則刪除索引
                    deleteIndex(index);
                }
                CreateIndexResponse indexresponse = client.admin().indices().prepareCreate(index).setSettings(Settings.builder().put("index.number_of_shards", 5)
                        .put("index.number_of_replicas", 1)
                )
                        .get();
                LOGGER.info("創建索引 {} 執行狀態 {}", index , indexresponse.isAcknowledged());

                return indexresponse.isAcknowledged();
            }catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }

        }


    /**
     * 創建索引
     *
     * @param index 索引名稱
     * @param indexType 索引類型
     * @param mapping 創建的mapping結構
     * @return
     */
    public static boolean putMapping(String index,String indexType,String mapping) throws RuntimeException {
        if (!isIndexExist(index)) {
            throw new RuntimeException("創建索引庫"+index+"mapping"+mapping+"結構失敗,索引庫不存在!");
        }
        try {
            PutMappingResponse indexresponse = client.admin().indices().preparePutMapping(index).setType(indexType).setSource(mapping, XContentType.JSON).get();

            LOGGER.info("索引 {} 設置 mapping {} 執行狀態 {}", index ,indexType, indexresponse.isAcknowledged());

            return indexresponse.isAcknowledged();
        }catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }


    }

    /**
     * 判斷索引是否存在
     *
     * @param index
     * @return
     */
    public static boolean isIndexExist(String index) {
        IndicesExistsResponse inExistsResponse = client.admin().indices().exists(new IndicesExistsRequest(index))
                .actionGet();
        return inExistsResponse.isExists();
    }


    /**
     * 刪除索引
     *
     * @param index
     * @return
     */
    public static boolean deleteIndex(String index) throws RuntimeException{
        if (!isIndexExist(index)) {
            return true;
        }
        try {
            DeleteIndexResponse dResponse = client.admin().indices().prepareDelete(index).execute().actionGet();
            if (dResponse.isAcknowledged()) {
                LOGGER.info("delete index " + index + "  successfully!");
            } else {
                LOGGER.info("Fail to delete index " + index);
            }
            return dResponse.isAcknowledged();
        } catch (Exception e) {

            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 數據添加
     *
     * @param jsonObject
     *            要增加的數據
     * @param index
     *            索引,類似資料庫
     * @param type
     *            類型,類似表
     * @return
     */
    public static String addData(JSONObject jsonObject, String index, String type) {
        return addData(jsonObject, index, type, UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
    }

    /**
     * 數據添加,正定ID
     *
     * @param jsonObject
     *            要增加的數據
     * @param index
     *            索引,類似資料庫
     * @param type
     *            類型,類似表
     * @param id
     *            數據ID
     * @return
     */
    public static String addData(JSONObject jsonObject, String index, String type, String id)throws RuntimeException {
        try {
            IndexResponse response = client.prepareIndex(index, type, id).setSource(jsonObject).get();

            LOGGER.info("addData response status:{},id:{}", response.status().getStatus(), response.getId());

            return response.getId();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 批量數據添加,
     *
     * @param list
     *            要增加的數據
     * @param pkName
     *            主鍵id
     * @param index
     *            索引,類似資料庫
     * @param type
     *            類型,類似表
     * @return
     */
    public static <T> void addBatchData(List<T> list, String pkName, String index, String type) {
        if(list == null || list.isEmpty()) {
            return;
        }
        // 創建BulkPorcessor對象
        BulkProcessor bulkProcessor = BulkProcessor.builder(client, new BulkProcessor.Listener() {
            @Override
            public void beforeBulk(long paramLong, BulkRequest paramBulkRequest) {
                // TODO Auto-generated method stub
            }

            // 執行出錯時執行
            @Override
            public void afterBulk(long paramLong, BulkRequest paramBulkRequest, Throwable paramThrowable) {
                // TODO Auto-generated method stub
            }
            @Override
            public void afterBulk(long paramLong, BulkRequest paramBulkRequest, BulkResponse paramBulkResponse) {
                // TODO Auto-generated method stub
            }
        })
                // 1w次請求執行一次bulk
                .setBulkActions(1000)
                // 1gb的數據刷新一次bulk
                // .setBulkSize(new ByteSizeValue(1, ByteSizeUnit.GB))
                // 固定5s必須刷新一次
                .setFlushInterval(TimeValue.timeValueSeconds(5))
                // 併發請求數量, 0不併發, 1併發允許執行
                .setConcurrentRequests(1)
                // 設置退避, 100ms後執行, 最大請求3次
                .setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3)).build();

        for (T vo : list) {
            if(getPkValueByName(vo, pkName)!= null) {
                String id = getPkValueByName(vo, pkName).toString();
                bulkProcessor.add(new IndexRequest(index, type, id).source(JSON.toJSONString(vo), XContentType.JSON));
            }

        }
        bulkProcessor.close();
    }

    /**
     * 根據主鍵名稱獲取實體類主鍵屬性值
     *
     * @param clazz
     * @param pkName
     * @return
     */
    private static Object getPkValueByName(Object clazz, String pkName) {
        try {
            String firstLetter = pkName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + pkName.substring(1);
            Method method = clazz.getClass().getMethod(getter, new Class[] {});
            Object value = method.invoke(clazz, new Object[] {});
            return value;
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 通過ID 更新數據
     *
     * @param jsonObject
     *            要增加的數據
     * @param index
     *            索引,類似資料庫
     * @param type
     *            類型,類似表
     * @param id
     *            數據ID
     * @return
     */
    public static void updateDataById(JSONObject jsonObject, String index, String type, String id) throws RuntimeException {

        try{
            UpdateRequest updateRequest = new UpdateRequest();

            updateRequest.index(index).type(type).id(id).doc(jsonObject);

            client.update(updateRequest);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 批量數據更新,
     *
     * @param list
     *            要增加的數據
     * @param pkName
     *            主鍵id
     * @param index
     *            索引,類似資料庫
     * @param type
     *            類型,類似表
     * @return
     */
    public static <T> void updateBatchData(List<T> list, String pkName, String index, String type) {
        // 創建BulkPorcessor對象
        BulkProcessor bulkProcessor = BulkProcessor.builder(client, new BulkProcessor.Listener() {
            @Override
            public void beforeBulk(long paramLong, BulkRequest paramBulkRequest) {
                // TODO Auto-generated method stub
            }

            // 執行出錯時執行
            @Override
            public void afterBulk(long paramLong, BulkRequest paramBulkRequest, Throwable paramThrowable) {
                // TODO Auto-generated method stub
            }
            @Override
            public void afterBulk(long paramLong, BulkRequest paramBulkRequest, BulkResponse paramBulkResponse) {
                // TODO Auto-generated method stub
            }
        })
                // 1w次請求執行一次bulk
                .setBulkActions(1000)
                // 1gb的數據刷新一次bulk
                // .setBulkSize(new ByteSizeValue(1, ByteSizeUnit.GB))
                // 固定5s必須刷新一次
                .setFlushInterval(TimeValue.timeValueSeconds(5))
                // 併發請求數量, 0不併發, 1併發允許執行
                .setConcurrentRequests(1)
                // 設置退避, 100ms後執行, 最大請求3次
                .setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3)).build();

        for (T vo : list) {
            String id = getPkValueByName(vo, pkName).toString();
            bulkProcessor.add(new UpdateRequest(index, type, id).doc(JSON.toJSONString(vo), XContentType.JSON));
        }
        bulkProcessor.close();
    }


    /**
     * 通過ID獲取數據
     *
     * @param index
     *            索引,類似資料庫
     * @param type
     *            類型,類似表
     * @param id
     *            數據ID
     * @param fields
     *            需要顯示的欄位,逗號分隔(預設為全部欄位)
     * @return
     */
    public static Map<String, Object> searchDataById(String index, String type, String id, String fields) {

        GetRequestBuilder getRequestBuilder = client.prepareGet(index, type, id);

        if (StringUtils.isNotEmpty(fields)) {
            getRequestBuilder.setFetchSource(fields.split(","), null);
        }

        GetResponse getResponse = getRequestBuilder.execute().actionGet();

        return getResponse.getSource();
    }

    /**
     * 使用分詞查詢
     *
     * @param index
     *            索引名稱
     * @param type
     *            類型名稱,可傳入多個type逗號分隔
     * @param clz
     *            數據對應實體類
     * @param fields
     *            需要顯示的欄位,逗號分隔(預設為全部欄位)
     * @param boolQuery
     *            查詢條件
     * @return
     */
    public static <T> List<T> searchListData(String index, String type, Class<T> clz, String fields,BoolQueryBuilder boolQuery) {
        return searchListData(index, type, clz, 0, fields, null,  null,boolQuery);
    }

    /**
     * 使用分詞查詢
     *
     * @param index
     *            索引名稱
     * @param type
     *            類型名稱,可傳入多個type逗號分隔
     * @param clz
     *            數據對應實體類
     * @param size
     *            文檔大小限制
     * @param fields
     *            需要顯示的欄位,逗號分隔(預設為全部欄位)
     * @param sortField
     *            排序欄位
     * @param highlightField
     *            高亮欄位
     * @param boolQuery
     *            查詢條件
     * @return
     */
    public static <T> List<T> searchListData(String index, String type, Class<T> clz,
                                             Integer size, String fields, String sortField, String highlightField,BoolQueryBuilder boolQuery) throws RuntimeException{

        SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index);
        if (StringUtils.isNotEmpty(type)) {
            searchRequestBuilder.setTypes(type.split(","));
        }
        // 高亮(xxx=111,aaa=222)
        if (StringUtils.isNotEmpty(highlightField)) {
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            // 設置高亮欄位
            highlightBuilder.field(highlightField);
            searchRequestBuilder.highlighter(highlightBuilder);
        }
        searchRequestBuilder.setQuery(boolQuery);
        if (StringUtils.isNotEmpty(fields)) {
            searchRequestBuilder.setFetchSource(fields.split(","), null);
        }
        searchRequestBuilder.setFetchSource(true);

        if (StringUtils.isNotEmpty(sortField)) {
            searchRequestBuilder.addSort(sortField, SortOrder.DESC);
        }
        if (size != null && size > 0) {
            searchRequestBuilder.setSize(size);
        }
        searchRequestBuilder.setScroll(new TimeValue(1000));
        searchRequestBuilder.setSize(10000);
        // 列印的內容 可以在 Elasticsearch head 和 Kibana 上執行查詢
        LOGGER.info("\n{}", searchRequestBuilder);

        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();

        long totalHits = searchResponse.getHits().totalHits;
        if(LOGGER.isDebugEnabled()) {
            long length = searchResponse.getHits().getHits().length;

            LOGGER.info("共查詢到[{}]條數據,處理數據條數[{}]", totalHits, length);
        }


        if (searchResponse.status().getStatus() ==200) {
            // 解析對象
            return setSearchResponse(clz, searchResponse, highlightField);
        }

        return null;
    }


    /**
     * 高亮結果集 特殊處理
     *
     * @param clz
     *            數據對應實體類
     * @param searchResponse
     *
     * @param highlightField
     *            高亮欄位
     */
    private static <T> List<T> setSearchResponse(Class<T> clz, SearchResponse searchResponse, String highlightField) {
        List<T> sourceList = new ArrayList<T>();
        for (SearchHit searchHit : searchResponse.getHits().getHits()) {
            searchHit.getSourceAsMap().put("id", searchHit.getId());
            StringBuffer stringBuffer = new StringBuffer();
            if (StringUtils.isNotEmpty(highlightField)) {

                // System.out.println("遍歷 高亮結果集,覆蓋 正常結果集" + searchHit.getSourceAsMap());
                HighlightField highlight = searchHit.getHighlightFields().get(highlightField);
                if(highlight == null) {
                    continue;
                }
                Text[] text = highlight.getFragments();
                if (text != null) {
                    for (Text str : text) {
                        stringBuffer.append(str.string());
                    }
                    // 遍歷 高亮結果集,覆蓋 正常結果集
                    searchHit.getSourceAsMap().put(highlightField, stringBuffer.toString());
                }
            }

            T t = JSON.parseObject(JSON.toJSONString(searchHit.getSourceAsMap()), clz);
            sourceList.add(t);
        }

        return sourceList;
    }

}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文針對react navigation^3.0.0版本,版本不對的話,請不要看本文,直接看官方英文文檔 ​ 最近一直在學習RN,沒找到什麼好的視頻,所以一直看文檔,一路上來雖然遇到一些亂七八糟的bug,但是能比較友好的解決掉 直到我使用 ,這個官方文檔上說 的導航組件,搞的我心態爆照,調試了一下午 ...
  • 微服務的目標是通過將應用程式分解為可以獨立部署的小型自治服務來提高應用程式版本的速度。微服務架構也帶來了一些挑戰,這些模式可以幫助緩解這些挑戰。設計模式(design pattern)是對軟體設計中普遍存在(反覆出現)的各種問題,所提出的解決方案。當然微服務中的雲設計模式也是對微服務中普遍存在的問題... ...
  • 一.在Servlet中,表單提交的非字元串類型需要手動轉換 1.在struts中,表單提供的常見數據類型struts框架自動轉換,無需手動轉換 2.在某些情況下,某些自定義類型struts不能完成自動轉換,需要進行手動轉換,如果需要轉換的類型轉換頻率較高時,手動轉換的代碼增多,這時可以使用strut ...
  • 撩課Java+系統架構 視頻 點擊開始學習 81.Servlet的會話機制? 82.Filter是什麼?有什麼作用? 83.Listener是什麼?有什麼作用? 84.你瞭解過Servlet3.0嗎? 85.JSP和Servlet有哪些相同點和不同點? ...
  • 2018-11-24 22:57:33 問題說明 最近看到Spring事務,在學習過程中遇到一個很苦惱問題 搭建好Spring的啟動環境後出現了一點小問題 在啟動時候卻出現[java.lang.NullPointerException] 不過因為當時一個小小的疏忽 很low的問題 請往下看 ... ...
  • 從高位開始逐位輸出一個整數的各位數字:輸入一個整數,從高位開始逐位分割並輸出它的各位數字。 include int main(void) { int i,j,m,n,s,k,a,b=0; scanf("%d",&m); k=m; do { m=m/10; b++; }while(m!=0); for ...
  • 多線程 等待一次性事件 packaged_task用法 背景:不是很明白,不知道為瞭解決什麼業務場景,感覺std::asynck可以優雅的搞定一切,一次等待性事件,為什麼還有個packaged_task。 用法:和std::async一樣,也能夠返回std::future,通過調用get_futur ...
  • 轉載請註明出處: https://www.cnblogs.com/funnyzpc/p/9501376.html ``` 我先閑扯下,前天(也就是2018年11月16號)的某個時候,忽然有人在QQ上私聊我,一看是公司群以為是有人來慰問新人了,也沒弄清楚身份就調侃起來,就這樣: 問題是:我竟傻乎乎滴沒 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...