Flink的常用算子以及實例

1.map

特性:接收一個數據,經過處理之后,就返回一個數據
在這里插入圖片描述

1.1. 源碼分析

  • 我們來看看map的源碼
    在這里插入圖片描述
    map需要接收一個MapFunction<T,R>的對象,其中泛型T表示傳入的數據類型,R表示經過處理之后輸出的數據類型
  • 我們繼續往下點,看看MapFunction<T,R>的源碼
    在這里插入圖片描述
    這是一個接口,那么在代碼中,我們就需要實現這個接口

1.2. 案例

那么我們現在要實現一個功能,就是從給一個文件中讀取數據,返回每一行的字符串長度。

我們要讀取的文件內容如下
在這里插入圖片描述

代碼貼在這里(為了讓打擊不看迷糊,導包什么的我就省略了)

public class TransformTest1_Base {public static void main(String[] args) throws Exception {// 1. 獲取執行環境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 將并行度設為1env.setParallelism(1);// 3. 讀取文件夾DataStreamSource<String> inputDataStream = env.readTextFile("C:\\Users\\Administrator\\IdeaProjects\\FlinkTutorial\\src\\main\\resources\\sensor");// 4. 將文件夾每一行的數據都返回它的長度// 在這里我們用匿名內部類的方式創建了一個MapFunction對象SingleOutputStreamOperator<Integer> dataStream = inputDataStream.map(new MapFunction<String, Integer>() {// 5. 重寫map方法,參數s是接收到的一個數據,我們只需要返回它的長度就行了。@Overridepublic Integer map(String s) throws Exception {return s.length();}});// 6. 打印輸出dataStream.print();// 7. 啟動執行環境env.execute();}
}

顯示
在這里插入圖片描述

1.3. 總結

map的使用范圍就是需要對的那個數據進行處理,并且每次返回一個數據的時候,map就比較方便了。

2. flatMap

  • 接收一個數據,可以返回多條數據

2.1. 源碼分析

在這里插入圖片描述
我們發現,它需要傳入一個FlatMapFunction的一個對象
在這里插入圖片描述

我們繼續點進去,看看FlatMapFunction的源碼,可以發現,FlatMapFunction<T,R>也是一個接口,并且接口里面的方法的返回值是一個Collector,也就是多個值的集合。

2.2. 案例

我們還是讀取那個文件,這次我們要做的處理是,將文件的每一行數據按照逗號隔開,給出代碼:

public class TransformTest2_Base {public static void main(String[] args) throws Exception {// 1. 獲取執行環境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 設置并行度env.setParallelism(1);// 3. 讀取文件夾DataStreamSource<String> dataStream = env.readTextFile("C:\\Users\\Administrator\\IdeaProjects\\FlinkTutorial\\src\\main\\resources\\sensor");// 4. 用匿名內部類的方式重寫FlatMapFuncction,將每行字符按","隔開SingleOutputStreamOperator<String> flatMapStream = dataStream.flatMap(new FlatMapFunction<String, String>() {@Overridepublic void flatMap(String s, Collector<String> collector) throws Exception {// 5. 分割一行字符,獲得對應的字符串數組String[] split = s.split(",");for (String slt : split) {// 6. 將這些數據返回collector.collect(slt);}}});// 7. 打印輸出處理后的數據flatMapStream.print();// 8. 啟動執行環境env.execute();}
}

可以看到執行的結果
在這里插入圖片描述

3. filter

聽這個名字就知道是個過濾器,用來過濾數據。
在這里插入圖片描述

3.1. 源碼分析

我們看看filer的源碼,繼承子FilterFunction,可以看到,這次泛型就只有一個值了,因為filter只允許返回的數據<=原來的數據,所以只做過濾,并不能改變數據蕾西,沒必要設置返回的類型
在這里插入圖片描述
我們繼續點進去,看看FilterFunction的源碼
在這里插入圖片描述
果不其然,也是一個接口,而里面的filter方法只有一個參數,并且返回的是一個boolean類型,若返回true則var1原樣返回,若返回false,則var1會被過濾掉。

3.2. 案例

我們還是讀取以上文件,這一次我們返回以"sensor_1"開頭的字符串,其余的一律不返回,給出代碼

public class TransformTest3_Base {public static void main(String[] args) throws Exception {// 1. 獲取執行環境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 設置并行度env.setParallelism(1);// 3. 讀取文件DataStreamSource<String> dataStream = env.readTextFile("C:\\Users\\Administrator\\IdeaProjects\\FlinkTutorial\\src\\main\\resources\\sensor");// 4. 用匿名內部類的方式重寫FilterFunctionSingleOutputStreamOperator<String> filterDataStream = dataStream.filter(new FilterFunction<String>() {@Overridepublic boolean filter(String s) throws Exception {// 5. 若s以"sensor_1"開頭,則返回truereturn s.startsWith("\"sensor_1\"");}});// 6. 打印處理后的數據filterDataStream.print();// 7. 啟動執行環境env.execute();}
}

4. 分組聚合

  • 注意:任何的聚合操作都有默認的分組,聚合是在分組的基礎上進行的。比如,對整體進行求和,那么分組就是整體。所以,在做聚合操作之前,一定要明確是在哪個分組上進行聚合操作
  • 注意:聚合操作,本質上是一個多對一(一對一是多對一的特殊情況)的操作。特別注意的是這個’一‘,可以是一個值(mean, sum等),同樣也可以是一個對象(list, set等對象)

4.1. 分組(keyBy)

在這里插入圖片描述
DataStream → KeyedStream:邏輯地將一個流拆分成不相交的分區,每個分區包含具有相同 key 的元素,在內部以 hash 的形式實現的。

  • 分組就是為了聚合操作做準備的,keyBy方法會將數據流按照hash實現,分別放在不同的分區,每個分區都可以進行聚合操作。
  • 我們可以用這個性質,計算每一個sensor溫度的最大值,我們為此將文件修改:
    在這里插入圖片描述
    分組之后的圖就是所有sensor_1在一個分區里,sensor_6,sensor_7,sensor_10在不同的三個分區,也就是有四個分區,而后三個分區中只有一條數據,所以最大值和最小值都只有一個
  • 在flink中,分組操作是由keyBy方法來完成的,我們來看看keyBy的源碼
    在這里插入圖片描述
    可以發現,keyBy可以對對象和元組進行聚合。

4.2. 聚合

這些算子可以針對 KeyedStream 的每一個支流做聚合。
? sum():對每個支流求和
? min():對每個支流求最小值
? max():對每個支流求最大值
? minBy()
? maxBy()
我們來看看max()的源碼
在這里插入圖片描述
這也是傳一個屬性名,也就是求對應的屬性名的最大值。

4.3. 實例演示

public class TransformTest1_RollingAggreation {public static void main(String[] args) throws Exception {// 1. 獲取執行環境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 設置并行度env.setParallelism(1);// 3. 讀取文件DataStreamSource<String> stringDataStreamSource = env.readTextFile("C:\\Users\\Administrator\\IdeaProjects\\FlinkTutorial\\src\\main\\resources\\sensor");// 4. 用map將每行數據變成一個對象SingleOutputStreamOperator<SensorReading> map = stringDataStreamSource.map(new MapFunction<String, SensorReading>() {@Overridepublic SensorReading map(String s) throws Exception {String[] split = s.split(",");return new SensorReading(split[0], new Long(split[1]), new Double(split[2]));}});// 5. 分組操作,以id屬性分組KeyedStream<SensorReading, Tuple> keyedstream = map.keyBy("id");// 6. 聚合操作,求每個分組的溫度最大值SingleOutputStreamOperator<SensorReading> resultStream = keyedstream.max("temperature");// 7. 打印輸出resultStream.print();// 8. 啟動執行環境env.execute();}
}

運行結果
在這里插入圖片描述
誒,這有人就要問了,不是求每一個分組的溫度最大值么?為什么sensor_1的這個分組所有的數據都有?
答:flink是一個流處理分布式框架,這是一條數據流,每來一個數據就得處理一次,所以輸出的都是當前狀態下的最大值。

4.4. reduce自定義聚合

在實際生產中,不可能讓我們完成這么簡單的操作就行了,所以我們需要更復雜的操作,而reduce就是滿足這個條件,它可以讓我們自定義聚合的方式。

  • 我們來看看reduce的源碼
    在這里插入圖片描述
    reduce需要傳入的是一個ReduceFunction的對象,我們再來看看ReduceFunction是個什么東西
    在這里插入圖片描述
    var1是當前這個分組的狀態,var2是新加入的值,而reduce函數體就是我們要進行的操作,返回一個新的狀態。
    到這我就明白了,要是我們向實時獲取最大溫度的話,var1是之前的最大溫度,通過var1和var2的比較就能實現。

4.5. reduce實例

我們這一次要實現一個實時的溫度最大值,也就是返回的數據中的時間戳是當前的。

public class TransformTest1_Reduce {public static void main(String[] args) throws Exception {// 1. 獲取執行環境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 設置并行度env.setParallelism(1);// 3. 讀取文件DataStreamSource<String> dataStream = env.readTextFile("C:\\Users\\Administrator\\IdeaProjects\\FlinkTutorial\\src\\main\\resources\\sensor");// 4. 通過map將每行數據轉換為一個對象SingleOutputStreamOperator<SensorReading> map = dataStream.map(new MapFunction<String, SensorReading>() {@Overridepublic SensorReading map(String s) throws Exception {String[] split = s.split(",");return new SensorReading(split[0], new Long(split[1]), new Double(split[2]));}});// 5. 按對象的id分組KeyedStream<SensorReading, Tuple> keyStream = map.keyBy("id");// 6. reduce自定義聚合SingleOutputStreamOperator<SensorReading> reduce = keyStream.reduce(new ReduceFunction<SensorReading>() {@Overridepublic SensorReading reduce(SensorReading sensorReading, SensorReading t1) throws Exception {// 7. 獲取當前時間為止接收到的最大溫度return new SensorReading(sensorReading.getId(), System.currentTimeMillis(), Math.max(sensorReading.getTemperature(),t1.getTemperature()));}});// 8. 打印輸出reduce.print();// 9. 啟動運行環境env.execute();}
}

這一次的輸出我們就得你好好研究一下了。
在這里插入圖片描述
從這塊可以發現,我們獲取的都是當前的時間戳,而且時間戳也在改變,這一點很好理解,但是下面這個數據就很詭異了。
在這里插入圖片描述

  • 這兩塊的時間戳為什么沒有改變呢?這需要我們再來看看reduce方法了,reduce方法是傳入兩個參數,第一個是當前的狀態,第二個是新讀取的值,通過方法體的操作返回一個最新的狀態。
  • 仔細理解一下這句話,若我剛開始沒有數據的時候,那么哪來的狀態呢?所以reduce把接收到的第一個參數作為狀態,其中sensor_6,7,8這三個分區只有一個數據,所以直接拿來當作狀態。

5. 多流轉換算子

5.1. 分流操作(Split 和 Select)

  • Split能將流中的數據按條件貼上標簽,比如我把溫度大于30度的對象貼上一個high標簽,把溫度低于30度的貼上一個low標簽,標簽可以貼多個。那么就把流中的數據,按照標簽分類了(這里并沒有分流)
    在這里插入圖片描述
  • Select是按照標簽來分流
    在這里插入圖片描述
  1. split源碼
    在這里插入圖片描述
    可以發現,返回的是一個SplitStream,需要傳入一個選擇器,我們看看OutputSeclector的源碼
    在這里插入圖片描述
    傳入value,返回這個value對應的標簽,實現對這個value進行類似"分類"的操作。
  2. select源碼
    在這里插入圖片描述
    只需要接收一個或者多個標簽就能返回包含那個標簽對象的數據流。

5.2. 實例演示

  • 我們這一次要把讀取到的數據分成三條流,一條是high(高于30度),一條是low(低于30度),一條是all(所有的數據)。代碼:
public class TransformTest4_MultipleStreams {public static void main(String[] args) throws Exception {// 1. 獲取執行環境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 設置并行度env.setParallelism(1);// 3. 讀取文件DataStreamSource<String> dataStream = env.readTextFile("C:\\Users\\Administrator\\IdeaProjects\\FlinkTutorial\\src\\main\\resources\\sensor");// 4. 通過map將每行數據轉換為一個對象SingleOutputStreamOperator<SensorReading> map = dataStream.map(new MapFunction<String, SensorReading>() {@Overridepublic SensorReading map(String s) throws Exception {String[] split = s.split(",");return new SensorReading(split[0], new Long(split[1]), new Double(split[2]));}});// 5. 按條件貼標簽SplitStream<SensorReading> split = map.split(new OutputSelector<SensorReading>() {@Overridepublic Iterable<String> select(SensorReading value) {return value.getTemperature() > 30 ? Collections.singletonList("high") : Collections.singletonList("low");}});// 6. 按標簽選擇,生成不同的數據流DataStream<SensorReading> high = split.select("high");DataStream<SensorReading> low = split.select("low");DataStream<SensorReading> all = split.select("high", "low");high.print("high");low.print("low");all.print("all");env.execute();}
}

5.3. 合流操作Connect 和 CoMap

在這里插入圖片描述
DataStream,DataStream → ConnectedStreams:連接兩個保持他們類型的數
據流,兩個數據流被 Connect 之后,只是被放在了一個同一個流中,內部依然保持各自的數據和形式不發生任何變化,兩個流相互獨立。
在這里插入圖片描述
ConnectedStreams → DataStream:作用于 ConnectedStreams 上,功能與 map和 flatMap 一樣,對 ConnectedStreams 中的每一個 Stream 分別進行 map 和 flatMap處理。
類似于一國兩制,看似兩條流合并在了一起,其實內部依舊是按照自己的約定運行,類型并沒有改變。

  1. connect源碼
    在這里插入圖片描述
    將當前調用者的流和參數中的流合并,返回一個ConnectedStreams<T,R>類型
    在這里插入圖片描述
    我們再來看看ConnectionStreams<T,R>中的map方法,其中要傳的是一個CoMapFunction<IN1,IN2,R>的對象,最重要的就是這個類,我們來看看這個類
    在這里插入圖片描述
    這個CoMapFunction<IN1,IN2,R>和之前的MapFunction不太一樣,這里要重寫的方法有兩個,map1和map2,一個是針對IN1的,一個是針對IN2的,R就是返回類型。
    這下全明白了,在這個方法內部,對這兩條流分別操作,合成一條流。

5.4. 實例演示

public class TransformTest5_MultipleStreams {public static void main(String[] args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);// 1. 讀取文件DataStreamSource<String> dataStreamSource = env.readTextFile("C:\\Users\\Administrator\\IdeaProjects\\FlinkTutorial\\src\\main\\resources\\sensor");// 2. 將每行數據變成一個對象SingleOutputStreamOperator<SensorReading> map = dataStreamSource.map(new MapFunction<String, SensorReading>() {@Overridepublic SensorReading map(String s) throws Exception {String[] split = s.split(",");return new SensorReading(split[0], new Long(split[1]), new Double(split[2]));}});// 3. 將數據打上標簽SplitStream<SensorReading> split = map.split(new OutputSelector<SensorReading>() {@Overridepublic Iterable<String> select(SensorReading value) {return value.getTemperature() > 30 ? Collections.singletonList("high") : Collections.singletonList("low");}});// 4. 按照高溫和低溫的標簽分成兩條流DataStream<SensorReading> high = split.select("high");DataStream<SensorReading> low = split.select("low");// 5. 將high流的數據轉換為二元組SingleOutputStreamOperator<Tuple2<String, Double>> tuple2SingleOutputStreamOperator = high.map(new MapFunction<SensorReading, Tuple2<String, Double>>() {@Overridepublic Tuple2<String, Double> map(SensorReading sensorReading) throws Exception {return new Tuple2<>(sensorReading.getId(), sensorReading.getTemperature());}});// 6. 將tuple2SingleOutputStreamOperator和low連接ConnectedStreams<Tuple2<String, Double>, SensorReading> connect = tuple2SingleOutputStreamOperator.connect(low);// 7. 調用map傳參CoMapFunction將兩條流合并成一條流objectSingleOutputStreamOperatorSingleOutputStreamOperator<Object> objectSingleOutputStreamOperator = connect.map(new CoMapFunction<Tuple2<String, Double>, SensorReading, Object>() {// 這是處理high流的方法@Overridepublic Object map1(Tuple2<String, Double> value) throws Exception {return new Tuple3<>(value.getField(0), value.getField(1), "temp is too high");}// 這是處理low流的方法@Overridepublic Object map2(SensorReading value) throws Exception {return new Tuple2<>(value.getTemperature(), "normal");}});objectSingleOutputStreamOperator.print();env.execute();}
}

5.5. 多條流合并(union)

之前我們只能合并兩條流,那我們要合并多條流呢?這里我們就需要用到union方法。
在這里插入圖片描述

  • Connect 與 Union 區別:
  1. Union 之前兩個流的類型必須是一樣,Connect 可以不一樣,在之后的 coMap中再去調整成為一樣的。
  2. Connect 只能操作兩個流,Union 可以操作多個。

若我們給出以下代碼:

high.union(low,all);

那么high,low,all三條流都會合并在一起。

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

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

相關文章

計算機提示vcruntime140_1.dll丟失的解決方法

在使用Windows操作系統時&#xff0c;有時候我們可能會遇到一些應用程序無法正常運行的問題&#xff0c;出現錯誤提示&#xff0c;其中之一可能就是缺少或損壞了vcruntime140_1.dll文件。在遇到這種情況時&#xff0c;我們可以嘗試修復vcruntime140_1.dll文件來解決問題。 先科…

后端 springboot 給 vue 提供參數

前端 /** 發起新增或修改的請求 */requestAddOrEdit(formData) {debuggerif(formData.id undefined) {formData.id }getAction(/material/getNameModelStandard, {standard: this.model.standard,name: this.model.name,model: this.model.model}).then((res) > {if (res …

《零基礎7天入門Arduino物聯網-06》程序基礎-編程語言是什么

配套視頻課程&#xff1a;《零基礎學Arduino物聯網&#xff0c;入門到進階》 配套課件資料獲取&#xff1a;微聯實驗室 配套學習套件購買&#xff1a;淘寶搜索店鋪【微聯實驗室】 程序基礎-編程語言是什么 程序是什么 程序設計可以理解為是用計算機語言創造出一系列指令的過程…

Shell 基本運算符

Shell 基本運算符 Shell 和其他編程語言一樣&#xff0c;支持多種運算符&#xff0c;包括&#xff1a; 算數運算符關系運算符布爾運算符字符串運算符文件測試運算符 原生bash不支持簡單的數學運算&#xff0c;但是可以通過其他命令來實現&#xff0c;例如 awk 和 expr&#…

HuggingFace開源的自然語言處理AI工具平臺

HuggingFace是一個開源的自然語言處理AI工具平臺&#xff0c;它為NLP的開發者和研究者提供了一個簡單、快速、高效、可靠的解決方案&#xff0c;讓NLP變得更加簡單、快速、高效、可靠。 Hugging Face平臺主要包括以下幾個部分&#xff1a; Transformers&#xff1a;一個提供了…

期權定價模型系列【5】—ETF期權數據

1.前言 對期權定價模型進行研究時&#xff0c;往往需要匹配的實際數據&#xff0c;國內上市時間超過兩年、主流的ETF期權包括華夏上證50ETF期權、滬深300ETF期權等&#xff0c;其對應的標的資產分別為華夏上證50ETF、華泰柏瑞滬深300ETF、嘉實滬深300ETF。 2.上證50ETF期權合約…

淺析基于視頻匯聚與AI智能分析的新零售方案設計

一、行業背景 近年來&#xff0c;隨著新零售概念的提出&#xff0c;國內外各大企業紛紛布局智慧零售領域。從無人便利店、智能售貨機&#xff0c;到線上線下融合的電商平臺&#xff0c;再到通過大數據分析實現精準推送的個性化營銷&#xff0c;智慧零售的觸角已經深入各個零售…

數組常用方法總結

數組常用方法總結 一.獲取數組長度1.1 使用length 二.數組轉字符串2.1 Arrays是什么2.2 使用toString() 三. 數組拷貝3.1 使用 copyOf()3.2 copyOfRange() 四.數組排序4.1使用 sort() 五. 數組逆序六. 判斷兩個數組是否相等6.1 使用equals() 一.獲取數組長度 1.1 使用length p…

ArrayList

目錄 1.ArrayList簡介 2.ArrayList的構造 2.1ArrayList() 2.2ArrayList(Collection c) 2.3ArrayList(int initialCapacity) 3.ArrayList常見操作 4.ArrayList的遍歷的遍歷 1.ArrayList簡介 在集合框架中&#xff0c; ArrayList 是一個普通的類&#xff0c;實現了 List…

【jenkins】jenkins流水線構建打包jar,生成docker鏡像,重啟docker服務的過程,在jenkins上一鍵完成,實現提交代碼自動構建的功能

【jenkins】jenkins流水線構建打包jar&#xff0c;生成docker鏡像&#xff0c;重啟docker服務的過程&#xff0c;在jenkins上一鍵完成&#xff0c;實現提交代碼自動構建&#xff0c;服務重啟&#xff0c;服務發布的功能。一鍵實現。非常的舒服。 1. 啟動腳本 shell腳本 這是 s…

MySQL 中 不等于 會過濾掉 Null 的問題

null值與任意值比較時都為fasle not in 、"!"、"not like"條件過濾都會過濾掉null值的數據 SELECT * from temp; SELECT * from temp where score not in (70); 返回null解決方法: SELECT * from temp where score not in (70) or score is null;SELECT…

迅捷視頻工具箱:多功能音視頻處理軟件

這是一款以視頻剪輯、視頻轉換、屏幕錄像等特色功能為主&#xff0c;同時附帶有視頻壓縮、視頻分割、視頻合并等常用視頻處理功能為主的視頻編輯軟件。該軟件操作簡單易用&#xff0c;即使沒有視頻處理經驗的用戶也可以輕松上手。將視頻添加到工具箱對應功能后&#xff0c;簡單…

zookeeper-安裝部署

詳情可以查看添加鏈接描述 1.安裝jdk apt-get install openjdk-8-jdk2.安裝單機zookeeper # 下載 #https://downloads.apache.org/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1.tar.gz # 用這個包啟動的時候會報錯Error: Could not find or load main class org.apach…

【OFDM系列】DFT為什么能求頻率幅度譜?DFT后的X[k]與x(n)幅度的關系?DFT/IDFT底層數學原理?

文章目錄 問題引入鋪墊一些小公式DFT公式證明DFT公式分解為4部分先考慮k10的情況:再考慮k1≠0的情況: DFT計算后&#xff0c;X(k)與x(n)的關系&#xff1a; Matlab FFT示例代碼IDFT公式證明Matlab調用FFT/IFFT并繪圖 問題引入 上面是DFT和IDFT的公式&#xff0c;IDFT先不談。在…

django實現文件上傳

在django中實現文件上傳有三種方法可以實現&#xff1a; 自己手動寫使用Form組件使用ModelForm組件 其中使用ModelForm組件實現是最簡單的。 1、自己手寫 先寫一個上傳的頁面 upload_file.html enctype"multipart/form-data 一定要加這個&#xff0c;不然只會上傳文件名…

HTTPS 的加密流程

目錄 一、HTTPS是什么&#xff1f; 二、為什么要加密 三、"加密" 是什么 四、HTTPS 的工作過程 1.對稱加密 2.非對稱加密 3.中間人攻擊 4.證書 總結 一、HTTPS是什么&#xff1f; HTTPS (Hyper Text Transfer Protocol Secure) 是基于 HTTP 協議之上的安全協議&…

四、Controller 配置總結、RestFul 風格

文章目錄 一、Controller 配置總結二、RestFul 風格2.1 使用 RequestMapping 的 method 屬性指定請求類型 三、擴展&#xff1a;小黃鴨調試法 一、Controller 配置總結 實現 Controller 控制器的方式 實現 Controller 接口&#xff0c;重寫 handleRequest 方法實現 控制器實現 …

Markdown編輯器 Mac版Typora功能介紹

Typora mac是一款跨平臺的Markdown編輯器&#xff0c;支持Windows、MacOS和Linux操作系統。它具有實時預覽功能&#xff0c;能夠自動將Markdown文本轉換為漂亮的排版效果&#xff0c;讓用戶專注于寫作內容而不必關心格式調整。 Typora Mac版除了支持常見的Markdown語法外&#…

騰訊云輕量服務器測評:2核 2G 4M

騰訊云輕量2核2G4M服務器&#xff0c;4M帶寬下載速度可達512KB/秒&#xff0c;系統盤為50GB SSD盤&#xff0c;300GB月流量&#xff0c;地域節點可選上海、廣州和北京&#xff0c;騰訊云百科分享騰訊云2核2G4M輕量應用服務器配置性能表&#xff1a; 目錄 騰訊云輕量2核2G4M服…