abbr 全稱是 abbreviations,意思是縮寫。應用場景也很簡單,為一些文章中的縮寫增加注釋。
以前在文章中對于縮寫的解釋經常會這么做:
DAU(Daily Active User),日活躍用戶數 ......
那我們用 abbr 標簽呢?
<abbr title="Daily Active User">
DAU
</abbr>
<span>,日活躍用戶數 ......</span>
展示的效果如下:
這個標簽就可以把全稱隱藏掉,弱化信息量,讓真正不知道該縮寫的用戶主動去獲取縮寫的具體意思,這個在 markdown 里經常會出現(xiàn)。
<mark/> 在 markdown 中也是很常用的,用于將包裹的文本高亮展示。
<mark>高亮文本</mark>
效果如下:
如果全文統(tǒng)一高亮樣式,可以專門對 mark 標簽進行樣式重置,這樣就不用對你用的每個 div 加一個 highlight 的類名了,又不語義化,又徒增文檔大小。
<sup/>和<sub/>分別表示上標和下標,在 markdown 中出現(xiàn)得也很頻繁,比如數學公式和引用。
<div>3<sup>[2]</sup></div>
<div>4<sub>2</sub></div>
效果如下:
上標和下標的樣式原理也比較簡單,主要就是利用了 vertical-align 的 top 和 sub 屬性值,然后將字號縮小,不過有現(xiàn)成的標簽,干嘛不用呢?
figure 是用于包裹其它標簽的內容的,然后再利用另一個標簽 figcaption ,可以對包裹的內容進行一個文本描述,例如:
<figure>
<img src="/media/cc0-images/elephant-660-480.jpg"
alt="大象">
<figcaption>這是一張大象的照片</figcaption>
</figure>
效果如下:
那要是圖片掛了呢?
再友好點處理,我們把 img 標簽的 alt 屬性去掉。
漂亮,終于把我一直厭煩的圖裂 icon 給干掉了,樣式還巨好看。
當然不止能包裹 img 標簽,其它任何都是可以的。
嘿嘿,給大家在本文來個實戰(zhàn),下面這個可以點擊,樣式也是利用了 figure 這個標簽。
我是figure標簽產生的
說到 <progress/> 這個標簽就很有意思了,去年有段時間我做的業(yè)務里涉及到了進度條,當時是前同事做的,然后有一些性能問題,我就在研究如何優(yōu)化,減少進度條改變帶來的性能問題。
雖然最后問題是解決了,但是也有幸收到了張鑫旭大佬的評論,他告訴我 progress 這個標簽就足夠了,既有語義化,又有進度條的功能,性能還好,兼容性也很不錯。后來經過一番嘗試,還真是,當時是我孤陋寡聞了,也安利給大家。
<!-- 進度條最大值為100,當前進度為60,即60% -->
<progress max="100" value="60"/>
瀏覽器自帶的樣式就已經很好看了,效果如下:
業(yè)務中我們也就可以通過控制 value 屬性,來改變進度條的進度了。
area 這個標簽也非常有意思,它的作用是為圖片提供點擊熱區(qū),可以自己規(guī)定一張圖的哪些區(qū)域可點擊,且點擊后跳轉的鏈接,也可以設置成點擊下載文件,我們來舉個例子:
<img src="example.png" width="100" height="100" alt="" usemap="#map">
<map name="map">
<area shape="rect" coords="0,0,100,50" alt="baidu" href="https://www.baidu.com">
<area shape="rect" coords="0,50,100,100" alt="sougou" href="https://www.sogou.com/">
</map>
area 一般要搭配 map 標簽一起使用,每個 area 標簽表示一個熱區(qū),例如上面代碼中,我們定義了兩個熱區(qū),熱區(qū)形狀都為rect(矩形),他們的熱區(qū)分別是:
我們都知道,默認的坐標軸是這樣的:
因此,我們劃分的兩個熱區(qū)就是:
最后再來看一下我們的實際效果:
i
details 字面意思是 "詳情",在 markdown 里也經常用,用該標簽包裹了的內容默認會被隱藏,只留下一個簡述的文字,我們點擊以后才會展示詳細的內容。
<details>
<p>我是一段被隱藏的內容</p>
</details>
效果如下:
這還沒有加任何一行的 js 代碼,我們點擊后,details 標簽上會多一個 open 的屬性,被隱藏的內容就展示出來了。
默認情況下,簡要文字為 "詳情",想要修改這個文字,要搭配 summary 標簽來使用。
<details>
<summary>點擊查看更多</summary>
<p>我是一段被隱藏的內容</p>
</details>
就搞定了!
瀏覽器自帶彈窗方法 alert、confirm、prompt,樣式固定且每個瀏覽器不同,同時還會阻塞頁面運行,除了這個還提供了一個 dialog 標簽,它的使用方式有點類似于現(xiàn)在各大組件庫的 Modal 組件了,瀏覽器還為該標簽提供了原生的 dom 方法:showModal、close,可以直接控制彈窗的展示和隱藏。
<dialog id="dialog">
<input type="text">
<button id="close">ok</button>
</dialog>
<button id="openBtn">打開彈框</button>
<script>
const dialog=document.getElementById('dialog')
const openBtn=document.getElementById('openBtn')
const closeBtn=document.getElementById('close')
openBtn.addEventListener('click', ()=> {
// 打開彈框
dialog.showModal()
})
closeBtn.addEventListener('click', ()=> {
// 隱藏彈框
dialog.close()
})
</script>
效果如下:
細心的你有沒有發(fā)現(xiàn),這原生的彈框還自帶背景蒙層,點擊是關閉不掉的,但起碼它不會阻塞頁面。
然后我們在彈窗展示時,也可以通過 esc 鍵來關閉彈窗。
datalist 是用于給輸入框提供可選值的一個列表標簽,類似咱們常用的 Select 組件。
我可以用其實現(xiàn)一個 "輸入聯(lián)想" 的功能。
<label> 輸入C開頭的英文單詞:</label>
<input list="c_words"/>
<datalist id="c_words">
<option value="China">
<option value="Click">
<option value="Close">
<option value="Const">
<option value="Count">
</datalist>
來試一試:
剛點擊時會把所有推薦的選項都列出來,然后根據后面輸入的內容,會過濾掉不匹配的選項,比如我輸入 cl,會過濾掉不是 cl 開頭的單詞,最后只剩下 Click 和 Close 了。
最后我發(fā)現(xiàn),他這個下拉框有點好看啊?為啥這原生的 input 框默認樣式那么丑,啥時候改改。
fieldset 標簽是用于分組管理 form 表單內的元素的,若 fieldset 設置了 disabled 屬性,則被其包裹的所有表單元素都會被禁用置灰,且不會隨著表單一起提交上去,是的就成了擺設。
什么意思呢?看個例子:
<form action="/example">
<fieldset disabled>
<legend>被禁用區(qū)域</legend>
<label>ID:</label>
<input type="text" name="id" value="1">
<label>郵箱:</label>
<input type="text" name="email" value="1234567@163.com">
</fieldset>
<label>名字:</label>
<input type="text" name="name">
<button type="submit">提交</button>
</form>
這里我們把 ID 和 郵箱 的表單包裹了起來,且設置了 disabled,只開放了一個 name 的輸入控件,此時界面如下:
可以看到除了 name 輸入框,其它的兩個輸入框都被禁用了,此時點提交會是什么樣子呢?
嗯,只提交了 name 字段。
這個標簽是在瀏覽器不支持或禁用了 javascript 時才展示的,大多用于對 js 強依賴的應用,比如現(xiàn)在大部分的 SPA 頁面,一旦不支持 javascript,頁面基本上什么內容都沒了,此時可以靠這個標簽做友好提示。
一般我們不需要特地去使用,大多都是在打包過程中自動插入到 html 靜態(tài)文件里去的,例如:
// init.js
const root=document.getElementById('root')
const button=document.createElement('button')
button.innerText='點擊出彈窗'
root.appendChild(button)
<!-- index.html -->
<script defer src="./init.js"></script>
<noscript>
不好意思,你的瀏覽器不支持或禁用了 JavaScript,請更換瀏覽器或啟用 JavaScript
</noscript>
<div id="root"></div>
未禁用 javascript 時,頁面是這樣的:
禁用了 javascript 時,是這樣的:
pring Boot 3.2 于 2023 年 11 月大張旗鼓地發(fā)布,標志著 Java 開發(fā)領域的一個關鍵時刻。這一突破性的版本引入了一系列革命性的功能,包括:
其中,虛擬線程是最近 Java 版本中引入的最具變革性的特性之一。正如官方文件所述:虛擬線程是輕量級線程,可減少編寫、維護和調試高吞吐量并發(fā)應用程序的工作量。線程是可以調度的最小處理單元。它與其他此類單位同時運行,并且在很大程度上獨立于其他此類單元運行。它是 java.lang.Thread 的一個實例。
有兩種線程:平臺線程和虛擬線程。平臺線程是作為操作系統(tǒng) (OS) 線程的瘦包裝器實現(xiàn)的。平臺線程在其底層操作系統(tǒng)線程上運行 Java 代碼,平臺線程在平臺線程的整個生命周期內捕獲其操作系統(tǒng)線程。因此,可用平臺線程數限制為操作系統(tǒng)線程數。與平臺線程一樣,虛擬線程也是 java.lang.Thread 的實例。
但是,虛擬線程不綁定到特定的操作系統(tǒng)線程。虛擬線程仍在操作系統(tǒng)線程上運行代碼。但是,當在虛擬線程中運行的代碼調用阻塞 I/O 操作時,Java 運行時會掛起虛擬線程,直到它可以恢復為止。與掛起的虛擬線程關聯(lián)的操作系統(tǒng)線程現(xiàn)在可以自由地對其他虛擬線程執(zhí)行操作。虛擬線程適用于運行大部分時間被阻塞的任務,通常等待 I/O 操作完成。但是,它們不適用于長時間運行的 CPU 密集型操作。
雖然人們普遍認為虛擬線程在 I/O 密集型方案中表現(xiàn)出色,但它們在 CPU 密集型任務中的性能仍然是一個問號。本系列文章深入探討了虛擬線程在各種用例中的潛在優(yōu)勢,從基本的“hello world”到靜態(tài)文件服務(I/O 密集型)、QR 碼生成(CPU 密集型)和多部分/表單數據處理(混合工作負載)等實際應用。
在本系列的開頭文章中,我們已經了解了虛擬線程與物理線程相比在最簡單(且不切實際)的 hello world 情況下的性能。物理線程和虛擬線程之間幾乎沒有任何性能或資源使用差異。在本文中,我們將更加“實用”,并針對靜態(tài)文件服務器情況進行比較。這絕對是一個常見且“真實世界”的案例。讓我們看看這次我們發(fā)現(xiàn)了什么。
如果大家正在做Spring Boot 2.3升級Spring 3.2,這里順手給大家推薦《Spring Boot 2.x 到 3.2 的升級指南》:https://www.didispace.com/spring-boot-2/10-5.html
所有測試均在配備 16G RAM、8 個物理內核和 4 個效率內核的 MacBook Pro M2 上執(zhí)行。測試工具是 Bombardier,它是更快的 HTTP 負載測試器之一(用 Go 編寫)。
軟件版本為:
除了主 Java 類之外,不需要編寫任何 Java 文件,靜態(tài)文件服務器只能通過配置就能發(fā)揮作用。
application.properties文件如下:
server.port=3000
spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=file:/Users/mayankc/Work/source/perfComparisons/static/
使用虛擬線程時,我們將通過添加以下行來啟用它們:
spring.threads.virtual.enabled=true
pom.xml內容:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
大小完全相同但數據不同的 100K 文件被放置在靜態(tài)資源目錄中。每個文件大小正好是 102400 字節(jié)。
文件的命名范圍為 1 到 100000。
使用 Bombardier 的修改版本,為每次運行生成隨機請求 URL: http://localhost:3000/static/<file-name>
為了確保結果一致,每個測試在開始數據收集之前都會經歷 5K 請求預熱階段。
然后,在不同范圍的并發(fā)連接級別(50、100 和 300)中仔細記錄測量結果,每個級別都承受 500 萬個請求工作負載。
除了簡單地跟蹤原始速度之外,我們還將采用詳細的指標框架來捕獲延遲分布(最小值、百分位數、最大值)和吞吐量(每秒請求數)。
CPU 和內存的資源使用情況監(jiān)控將補充此分析,從而提供不同工作負載下系統(tǒng)性能的全面了解。
結果以圖表形式呈現(xiàn)如下:
對靜態(tài)文件服務的分析表明,物理線程在性能和資源效率方面略勝一籌(與我們的預期相反)。
不過,這種受 I/O 限制的場景可能并不是充分發(fā)揮虛擬線程潛力的理想場所。涉及數據庫交互的任務可能會顯示出更多令人信服的優(yōu)勢。也許負載不足以讓虛擬線程發(fā)揮出最大的作用。為了找出答案,我們將在接下來的文章中介紹 URL短鏈(數據庫驅動)、二維碼生成(CPU受限)和混合工作負載場景(如表單數據處理),旨在揭示虛擬線程真正出類拔萃的案例。
來源:https://www.didispace.com/article/spring-boot/how-fast-spring-boot-3-2-virtual-thread.html
先,說說JSP/Servlet中的幾個編碼的作用。
在JSP/Servlet 中主要有以下幾個地方可以設置編碼,pageEncoding=“UTF-8”、contentType=“text/html;charset=UTF-8”、request.setCharacterEncoding(“UTF-8”)和response.setCharacterEncoding (“UTF-8”),其中前兩個只能用于JSP中,而后兩個可以用于JSP和Servlet中。
1、pageEncoding=“UTF-8"的作用是設置JSP編譯成Servlet時使用的編碼。
大家都知道,JSP在服務器上是會先被編譯成Servlet滴。所以pageEncoding=“UTF-8"的作用是告訴JSP編譯器將JSP文件編譯成Servlet時使用的編碼。通常,在JSP內部定義的字符串(直接在JSP中定義,而不是從瀏覽器提交的數據)出現(xiàn)亂碼的時候,很多都是由于該參數設置錯誤引起的。例如,你的JSP文件是以GBK為編碼保存的,而在JSP中卻指定pageEncoding=“UTF-8”,就會引起JSP內部定義的字符串為亂碼。
另外,該參數還有一個功能,就是在JSP中不指定contentType參數,也不使用response.setCharacterEncoding方法時,指定對服務器響應進行重新編碼的編碼。
2、contentType=“text/html;charset=UTF-8"的作用是指定對服務器響應進行重新編碼的編碼。
在不使用response.setCharacterEncoding方法時,用該參數指定對服務器響應進行重新編碼的編碼。服務器在將數據發(fā)送到瀏覽器前,對數據進行重新編碼時,使用的就是該編碼。
3、request.setCharacterEncoding(“UTF-8”)的作用是設置對客戶端請求進行重新編碼的編碼。
該方法用來指定對瀏覽器發(fā)送來的數據進行重新編碼(或者稱為解碼)時,使用的編碼。
4、response.setCharacterEncoding(“UTF-8”)的作用是指定對服務器響應進行重新編碼的編碼。
服務器在將數據發(fā)送到瀏覽器前,對數據進行重新編碼時,使用的就是該編碼。
其次,要說一說瀏覽器是怎么樣對接收和發(fā)送的數據進行編碼的
response.setCharacterEncoding(“UTF-8”)的作用是指定對服務器響應進行重新編碼的編碼。同時,瀏覽器也是根據這個參數來對其接收到的數據進行重新編碼(或者稱為解碼)。所以在無論你在JSP中設置response.setCharacterEncoding (“UTF-8”)或者response.setCharacterEncoding(“GBK”),瀏覽器均能正確顯示中文(前提是你發(fā)送到瀏覽器的數據編碼是正確的,比如正確設置了pageEncoding參數等)。讀者可以做個實驗,在JSP中設置 response.setCharacterEncoding(“UTF-8”),在IE中顯示該頁面時,在IE的菜單中選擇"查看(V)“à"編碼 (D)“中可以查看到是” Unicode(UTF-8)”,而在在JSP中設置response.setCharacterEncoding (“GBK”),在IE中顯示該頁面時,在IE的菜單中選擇"查看(V)“à"編碼(D)“中可以查看到是"簡體中文(GB2312)”。
瀏覽器在發(fā)送數據時,對URL和參數會進行URL編碼,對參數中的中文,瀏覽器也是使用response.setCharacterEncoding參數來進行URL編碼的。以百度和GOOGLE為例,如果你在百度中搜索"漢字”,百度會將其編碼為”%BA%BA%D7%D6”。而在GOOGLE中搜索 “漢字”,GOOGLE會將其編碼為”%E6%B1%89%E5%AD%97",這是因為百度的 response.setCharacterEncoding參數為GBK,而GOOGLE的的 response.setCharacterEncoding參數為UTF-8。
瀏覽器在接收服務器數據和發(fā)送數據到服務器時所使用的編碼是相同的,默認情況下均為JSP頁面的response.setCharacterEncoding參數(或者contentType和 pageEncoding參數),我們稱其為瀏覽器編碼。當然,在IE中可以修改瀏覽器編碼(在IE的菜單中選擇"查看(V)“à"編碼(D)“中修改),但通常情況下,修改該參數會使原本正確的頁面中出現(xiàn)亂碼。一個有趣的例子是,在IE中瀏覽GOOGLE的主頁時,將瀏覽器編碼修改為"簡體中文(GB2312)”,此時,頁面上的中文會變成亂碼,不理它,在文本框中輸入"漢字”,提交,GOOGLE會將其編碼為"%BA%BA%D7%D6",可見,瀏覽器在對中文進行URL編碼時,使用的就是瀏覽器編碼。
弄清了瀏覽器是在接收和發(fā)送數據時,是如何對數據進行編碼的了,我們再來看看服務器是在接收和發(fā)送數據時,是如何對數據進行編碼的。
對于發(fā)送數據,服務器按照response.setCharacterEncoding—contentType—pageEncoding的優(yōu)先順序,對要發(fā)送的數據進行編碼。
對于接收數據,要分三種情況。一種是瀏覽器直接用URL提交的數據,另外兩種是用表單的GET和POST方式提交的數據。
因為各種WEB服務器對這三種方式的處理也不相同,所以我們以Tomcat5.0為例。
無論使用那種方式提交,如果參數中包含中文,瀏覽器都會使用當前瀏覽器編碼對其進行URL編碼。
對于表單中POST方式提交的數據,只要在接收數據的JSP中正確request.setCharacterEncoding參數,即將對客戶端請求進行重新編碼的編碼設置成瀏覽器編碼,就可以保證得到的參數編碼正確。有讀者可能會問,那如何得到瀏覽器編碼呢?上面我們提過了,在默認請情況下,瀏覽器編碼就是你在響應該請求的JSP頁面中response.setCharacterEncoding設置的值。所以對于POST表單提交的數據,在獲得數據的JSP頁面中request.setCharacterEncoding要和生成提交該表單的JSP頁面的 response.setCharacterEncoding設置成相同的值。
對于URL提交的數據和表單中GET方式提交的數據,在接收數據的JSP中設置request.setCharacterEncoding參數是不行的,因為在Tomcat5.0中,默認情況下使用ISO- 8859-1對URL提交的數據和表單中GET方式提交的數據進行重新編碼(解碼),而不使用該參數對URL提交的數據和表單中GET方式提交的數據進行重新編碼(解碼)。要解決該問題,應該在Tomcat的配置文件的Connector標簽中設置useBodyEncodingForURI或者 URIEncoding屬性,其中useBodyEncodingForURI參數表示是否用request.setCharacterEncoding 參數對URL提交的數據和表單中GET方式提交的數據進行重新編碼,在默認情況下,該參數為false(Tomcat4.0中該參數默認為true); URIEncoding參數指定對所有GET方式請求(包括URL提交的數據和表單中GET方式提交的數據)進行統(tǒng)一的重新編碼(解碼)的編碼。 URIEncoding和useBodyEncodingForURI區(qū)別是,URIEncoding是對所有GET方式的請求的數據進行統(tǒng)一的重新編碼(解碼),而useBodyEncodingForURI則是根據響應該請求的頁面的request.setCharacterEncoding參數對數據進行的重新編碼(解碼),不同的頁面可以有不同的重新編碼(解碼)的編碼。所以對于URL提交的數據和表單中GET方式提交的數據,可以修改 URIEncoding參數為瀏覽器編碼或者修改useBodyEncodingForURI為true,并且在獲得數據的JSP頁面中 request.setCharacterEncoding參數設置成瀏覽器編碼。
下面總結下,以Tomcat5.0為WEB服務器時,如何防止中文亂碼。
1.對于同一個應用,最好統(tǒng)一編碼,推薦為UTF-8,當然GBK也可以。
2.正確設置JSP的pageEncoding參數
3.在所有的JSP/Servlet中設置contentType="text/html;charset=UTF-8"或response.setCharacterEncoding(“UTF-8”),從而間接實現(xiàn)對瀏覽器編碼的設置。
4.對于請求,可以使用過濾器或者在每個JSP/Servlet中設置request.setCharacterEncoding(“UTF-8”)。同時,要修改Tomcat的默認配置,推薦將useBodyEncodingForURI參數設置為true,也可以將URIEncoding參數設置為 UTF-8(有可能影響其他應用,所以不推薦)。
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。