這篇文章中,Josh Juneau解釋了JSF 2.3的一些最新功能,包括新的API增強(qiáng)功能,CDI調(diào)整改進(jìn)等。
Latte coffee image via Shutterstock.
JavaServer Faces(JSF)一直是Java EE平臺上開發(fā)Web應(yīng)用程序中使用最廣泛的框架之一。該框架于2002年推出,允許程序員使用組件構(gòu)建Web視圖,而不是從頭開始構(gòu)建Web視圖,從而提供了構(gòu)建Web應(yīng)用程序的不同方法。組件允許程序員更多地關(guān)注應(yīng)用程序的業(yè)務(wù)邏輯,并且花費(fèi)更少的時(shí)間開發(fā)頁面操作和樣式,因?yàn)镴avaScript和CSS被抽象出來。JSF還提供了一種不同的方法來處理應(yīng)用程序狀態(tài),狀態(tài)管理由框架處理。
多年以來,JSF得到了加強(qiáng),使開發(fā)框架更加高效,并且與更新的Web技術(shù)保持一致。Facelets是框架的核心部分,允許程序員創(chuàng)建可輕松應(yīng)用于應(yīng)用程序中所有視圖的模板。引入了流程,提供了一種手段來跨越多個(gè)指定的視圖進(jìn)行更詳細(xì)的會話管理,允許組件和視圖通過AJAX包含更好的客戶端和服務(wù)器端互操作性。這些只是幫助將JSF框架改進(jìn)成為當(dāng)今頂級Web框架的一些改進(jìn)。
JSF的最新版本是2.3版,其中包含了許多新功能,從而使Java 8和其他現(xiàn)代Web框架得到了加速。由于有許多資源可以解釋如何使用JSF,本文將介紹JSF2.3發(fā)行版中包含的最新功能。此版本的重點(diǎn)是更好地與Java SE 8和CDI進(jìn)行對齊,還有一個(gè)基于社區(qū)請求的小型新功能集。
改進(jìn)的CDI對齊和易用性
也許JSF 2.3最受追捧和有用的補(bǔ)充之一是CDI對齊改進(jìn)。JSF 2.3提供了許多生產(chǎn)力增強(qiáng)功能,因?yàn)樵S多JSF工件現(xiàn)在可以輕松地注入到Java類和EL表達(dá)式中。多年來,JSF的一個(gè)難點(diǎn)就是要利用靜態(tài)輸入法和鏈接來獲取諸如FacesContext,RequestMap或FlowMap之類的一些組件。這些組件現(xiàn)在可以輕松地注入到類中,而不是實(shí)例化。或許程序員曾經(jīng)做過以下事情:
在JSF 2.3中,可以簡單地執(zhí)行以下操作:
如果在JSF視圖中的EL表達(dá)式的上下文中使用,可以執(zhí)行以下操作:
有許多需要CDI限定詞的組件。例如FlowMap注入,如下:
JSF Managed Bean的范圍在過去幾年似乎有點(diǎn)混亂,不過可以利用Managed Bean注釋以及CDI進(jìn)行范圍界定。隨著JSF 2.3的發(fā)布,托管Bean注釋已被棄用,因?yàn)镃DI現(xiàn)在是首選方法。這樣做有助于防止開發(fā)人員在混合Managed Bean和CDI范圍注釋時(shí)引入錯(cuò)誤,因?yàn)樗鼈儾荒芎芎玫墓餐l(fā)揮。因此,@ ManagedProperty注釋已被棄用。此版本引入了更新的@ManagedProperty注釋,允許相同的功能繼續(xù)可用。
網(wǎng)絡(luò)和WebSockets更新
WebSocket是通過TCP提供全雙工雙向通信的協(xié)議。它已經(jīng)成為不斷增長的異步環(huán)境中的標(biāo)準(zhǔn)通信協(xié)議。雖然JSF已經(jīng)很好地與WebSocket通信工作了很長時(shí)間,但2.3版本完全支持它,通過新的<f:websocket>標(biāo)簽使WebSockets成為一流的功能。新標(biāo)簽可以放置在一個(gè)視圖中,以便將服務(wù)器端通信推送到包含相同通道名稱的套接字的所有實(shí)例。當(dāng)接收到通信時(shí),可以調(diào)用一個(gè)消息處理JavaScript事件處理程序,從而提供客戶端功能。使用新標(biāo)簽的示例可能如下所示,當(dāng)接收到該消息時(shí),該標(biāo)簽只會顯示警報(bào):
WebSocket通信的服務(wù)器端能夠推送消息。JSF 2.3添加了javax.faces.push.PushContext,它是一個(gè)可注入的上下文,允許服務(wù)器推送到命名通道。
JSF 2.3中還有其他網(wǎng)絡(luò)和AJAX增強(qiáng)功能,其中包括:
使用新的<h:commandScript />組件從視圖執(zhí)行任意的服務(wù)器端方法。
通過PartialViewContext從服務(wù)器端方法執(zhí)行視圖中的JavaScript。
通過新引入的“命名空間”模式,使用AJAX更新多個(gè)表單。
驗(yàn)證和轉(zhuǎn)換增強(qiáng)
已經(jīng)為此版本提供了許多有用的驗(yàn)證和轉(zhuǎn)換增強(qiáng)功能,包括更好的Java SE 8對齊以及驗(yàn)證整個(gè)bean的能力。通過使用新的<f:validateWholeBean>標(biāo)簽,可以實(shí)現(xiàn)類級別的bean驗(yàn)證。通過在視圖中包含此標(biāo)記并使用bean驗(yàn)證組標(biāo)記至少一個(gè)輸入組件,可以驗(yàn)證整個(gè)bean,從而實(shí)現(xiàn)新的驗(yàn)證支持。
自從Java SE 8發(fā)布以來,大部分Java程序員都在使用新的Date-Time API。Java EE不得不使這個(gè)新的API可以繼續(xù)工作,并且隨著JSF2.3版本的向前推進(jìn),增強(qiáng)了<f:convertDateTime>轉(zhuǎn)換標(biāo)簽,以支持新的日期時(shí)間類型。例如,要使用java.time.LocalDate類,可以在視圖中使用以下內(nèi)容:
增強(qiáng)的<f:convertDateTime>支持以下日期時(shí)間類型:LocalDate,LocalTime,LocalDateTime,OffsetTime,OffsetDateTime和ZonedDateTime。
組件和API增強(qiáng)功能
自JSF成立以來,各種組件和API都出現(xiàn)了一些細(xì)微差別,有時(shí)使得開發(fā)很麻煩。為了解決這些問題,新版對底層API和組件的數(shù)量進(jìn)行了增強(qiáng)。例如,UIData和UIRepeat已被增強(qiáng),以支持Map和Iterable接口以及自定義類型。這些增強(qiáng)功能可以在DataTable和ui:repeat標(biāo)簽中支持java.util.Iterable類型,Maps和自定義數(shù)據(jù)類型。例如,DataTable中的地圖支持如下所示:
還有許多其他有用的增強(qiáng)功能,包括通過新標(biāo)簽在EL中使用常量的能力。多年以來,JSF已經(jīng)缺少了一些基本功能,例如在視圖中放置單選按鈕的功能。2.3版本通過提供以下功能減少了追查功能的數(shù)量:
通過<h:selectOneRadio>上的新組屬性提供獨(dú)立單選按鈕
在<h:column>中添加了styleClass屬性,以增強(qiáng)樣式支持
在<h:dataTable>上添加了rowClass屬性,以增強(qiáng)樣式支持
自動收集轉(zhuǎn)換<h:selectManyMenu>標(biāo)簽
結(jié)語
JSF 2.3提供了許多增強(qiáng)功能和新功能,使框架更輕松,更靈活。Oracle和Java社區(qū)的程序員聚集在一起,使此版本比原來計(jì)劃的更強(qiáng)大。本文列出的許多功能都來自于社區(qū)的要求,JSR 372專家組的社區(qū)成員完成了大量工作。
很長的一段時(shí)間中,Vue 官方都以簡單上手作為其推廣的重點(diǎn)。這確實(shí)給 Vue 帶來了非常大的用戶量,尤其是最追求需求開發(fā)效率, 往往不那么在意工程代碼質(zhì)量的國內(nèi)中小企業(yè)中,Vue 占據(jù)的份額極速增長。但是作為開發(fā)者自身,我們必須要認(rèn)清一個(gè)重點(diǎn),簡單易用從來不應(yīng)該在技術(shù)選型中占據(jù)很大的份額,可維護(hù)性才是。
以防萬一有的同學(xué)實(shí)在不看官方文檔,我先提一嘴,SFC 就是寫 Vue 組件的時(shí)候?qū)懙?vue文件,這一個(gè)文件就是一個(gè) SFC,全稱 Single File Component,也即單文件組件。
在開始說我個(gè)人的觀點(diǎn)之前,我們先來看幾個(gè)事實(shí):
一是:Vue3 的定義原生支持 JSX,并且 Vue3 源碼中有jsx.d.ts來便于使用 JSX。 不知道同學(xué)們看到這里會想到什么, 我的第一反應(yīng)是:社區(qū)對于 JSX 的需求聲音是不小的,所以會反向推動 Vue3 官方對于 JSX 的支持。
二是:AntDesign 的 vue3 版本,基本全部都是用 JSX 開發(fā)的,而且 Vue3 現(xiàn)在官方的 babel-jsx 插件就是阿里的人一開始維護(hù)的, 雖然我向來不喜歡阿里系的 KPI 推動技術(shù)方式,而且現(xiàn)在的 JSX 語法支持也不是很符合我的期望,但至少在使用 JSX 開發(fā)是更優(yōu)秀的選擇這點(diǎn)上,我還是很認(rèn)可 AntDesign 團(tuán)隊(duì)的。
OK,說這些呢,主要是先擺出一些事實(shí)作為依據(jù),讓有些同學(xué)可以不需要拿什么:
這些觀點(diǎn)來批斗我,首先我都會從客觀的角度來分析為什么,至少是我是能講出優(yōu)劣勢的理由的。
OK,前言差不多到這里,接下來咱給您分析分析,為什么你應(yīng)該選擇 JSX 來開發(fā) Vue。
其實(shí)第一點(diǎn)就已經(jīng)是殺手了,對于想要使用 TypeScript 來開發(fā) Vue3 應(yīng)用的同學(xué)來說,這簡直就是 SFC 無法克服的世界難題。
一句話概括:TypeScript 原生支持 JSX 語法,而基本無望 TS 官方能支持 SFC 的 template 語法。
TS 毫無疑問在前端社區(qū)的重要性越來越大,但凡未來對于代碼質(zhì)量有一定要求的前端團(tuán)隊(duì),都應(yīng)該會選擇使用 TS 來進(jìn)行開發(fā)。 而且現(xiàn)在基本上在 NPM 上都能看到包你都能找到對應(yīng)的 TS 定義,現(xiàn)在使用 TS 開發(fā)成本已經(jīng)只剩下你是不是會 TS 語法了,在這種情況下是否支持 TS 則是開發(fā)模式在未來走不走的遠(yuǎn)的重要原因。
目前 SFC 只能通過shim讓 TS 可以引入.vue文件,但是對于所有 SFC 的組件的定義都是一樣的:
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, {}, any>
export default component
}
也就是說你引入的 SFC 組件,TS 是不知道這個(gè)組件的 Props 應(yīng)該接收什么的。所以你無法享受到這些 TS 的優(yōu)勢:
當(dāng)然你會說既然 Vue 官方能開發(fā)處 SFC 的語法,自然會支持這些特性。我表示這當(dāng)然有可能,但是這個(gè)難度是非常大的,需要很多方面的支持,甚至可能需要 TS 官方團(tuán)隊(duì)愿意協(xié)助, 但是我想不到 TS 官方有什么理由來支持 SFC,因?yàn)檫@只是 Vue 自己創(chuàng)建的方言,在其他場景下是沒有使用的,TS 是面向全社區(qū)的,我覺得他們不會考慮主動來支持 SFC。
那么有同學(xué)要問了,JSX 不也是非原生的 JS 語法么,他怎么就能讓 TS 官方支持了呢,是不是 FB 和微硬之間有什么 PY 交易?
這就涉及第二點(diǎn)了,JSX 和靜態(tài)模板的靈活性區(qū)別。
很多人弄錯(cuò)了一個(gè)問題,就是覺得 SFC 的模板語法和 JSX 是一樣的,都是一種別人發(fā)明的語法,并不是 JS 原生的。這是事實(shí),但又有一些區(qū)別,這個(gè)區(qū)別主要是體現(xiàn)在對于 JSX 的認(rèn)知上。
一句話概括:JSX 并沒有擴(kuò)展 JS 的語法,他只是縮略了 JS 的寫法!其本質(zhì)就是 JS 的語法糖
就像 es6 給增加的語法糖,比如
const a=1
const b=2
const obj={ a, b }
// 其實(shí)就等價(jià)于
const obj={ a: a, b: b }
這種寫法并沒有擴(kuò)展 JS 的能力,只是簡便了寫法,JSX 也是一樣的。
JSX 其實(shí)就是方法調(diào)用,他和 JS 是有一對一對應(yīng)關(guān)系的,我們來看一個(gè)例子:
const element=<div id="root">Hello World</div>
這里的 JSX 語法編譯之后其實(shí)就是:
const element=createElement('div', { id: 'root' }, 'Hello World')
而 JSX 就是這些了,沒有什么更多的內(nèi)容,所以說 JSX 只是方便我們寫嵌套的函數(shù)調(diào)用的語法糖,而其本身沒有擴(kuò)展任何其他的內(nèi)容。
但是 SFC 就不一樣了。
SFC 定義的不僅是語法,更是文件。
SFC 的具體定義是單文件組件,它本身就是把一個(gè)文件看作一個(gè)單位,所以他的約束性是要大很多的,你必須具有固定的文件結(jié)構(gòu)才能使用 SFC,這做了很多的限制:
我們一點(diǎn)點(diǎn)來講
這個(gè)說實(shí)話非常非常不方便,很多時(shí)候我們寫一個(gè)頁面的時(shí)候其實(shí)經(jīng)常會需要把一些小的節(jié)點(diǎn)片段拆分到小組件里面進(jìn)行復(fù)用(如果你現(xiàn)在沒有這個(gè)習(xí)慣可能就是因?yàn)?SFC 的限制讓你習(xí)慣了全部寫在一個(gè)文件內(nèi))。
React 生態(tài)中豐富的 css-in-js 方案就是很好的例子,我們可以通過:
const StyledButton=styled('button', {
color: 'red',
})
如果我們這個(gè)頁面需要使用特定樣式的按鈕,通過這種方式在頁面文件里面封裝一下是非常常見的。因?yàn)闆]必要把這個(gè)組件拆分出去,他也不是一個(gè)可復(fù)用的組件,拆分出去了還要多一次import。
Vue 生態(tài)基本沒有 css-in-js 的成熟方案其實(shí)跟這個(gè)限制也很有關(guān)系。
再來一個(gè)例子,比如我們封裝了一個(gè) Input 組件,我們希望同時(shí)導(dǎo)出 Password 組件和 Textarea 組件來方便用戶根據(jù)實(shí)際需求使用,而這兩個(gè)組件本身內(nèi)部就是用的 Input 組件,只是定制了一些 props:
const Input={ ... }
export default Input
export const Textarea=(props)=> <Input multiline={true} {...props} />
export const Password=(props)=> <Input type="password" {...props} />
在 JSX 中可以非常簡單地實(shí)現(xiàn),但是如果通過 SFC,你可能就要強(qiáng)行拆成三個(gè)文件,另外為了方便,你可能還要增加一個(gè)index.js來導(dǎo)出這三個(gè)組件,你能想象這多了多少工作量么。
我不知道有多少同學(xué)看過 Vue 的 template 編譯出來之后的代碼,以我的經(jīng)驗(yàn)來說看過的可能不會超過 50%(樂觀估計(jì)),建議同學(xué)們?nèi)绻€不了解的,可以去嘗試看一下。
為什么要看這個(gè)呢?因?yàn)槟憧戳酥竽銜l(fā)現(xiàn),你在 template 里面寫的類似 HTMl 的內(nèi)容,其實(shí)跟 HTML 根本沒啥關(guān)系,他們也會被編譯成類似 JSX 編譯出來的結(jié)果。
{
render(h) {
return h('div', {on: {}, props: {}}, h('span'))
}
}
類似這樣的結(jié)果,而這里面h函數(shù)調(diào)用的結(jié)果就是一個(gè) VNode,是 Vue 中的節(jié)點(diǎn)的基礎(chǔ)單元。那么既然這些單元就是一個(gè)對象,其實(shí)理所當(dāng)然的,他們是可以作為參數(shù)傳遞的。 也就是說,理論上他們是可以通過props把節(jié)點(diǎn)當(dāng)作參數(shù)傳遞給其他組件的。
這個(gè)做法在 React 中非常常見,叫做renderProps,并且其非常靈活:
const Comp=()=> <Layout header={<MyHeader />} footer={<MyFooter />} />
但是因?yàn)?SFC 模板的限制,我們很難在 SFC 里面的 props 上寫節(jié)點(diǎn):
<template>
<Layout :header="<MyHeader/>"></Layout>
</template>
這樣寫是不行的,因?yàn)?SFC 定義了:header綁定接受的只能是 js 表達(dá)式,而<MyHeader/>顯然不是。
因?yàn)橥ㄟ^ props 傳遞不行,所以 Vue 才發(fā)明了 slot 插槽的概念
雖然我們一直再說 Vue 簡單,但是事實(shí)上ScopedSlots一度成為新手理解 Vue 的噩夢,很多同學(xué)都被這個(gè)繞來繞去的作用域整的死去活來。
我們看一個(gè)ScopedSlots的例子:
<template>
<Comp>
<template v-slot:scope="ctx">
<div>{{ctx.name}}</div>
</template>
</Comp>
</template>
這里ctx是Comp里面的屬性,通過這種方式傳遞出來,讓我們在當(dāng)前組件可以調(diào)用父組件里面的屬性。這簡直就是理解的噩夢,但是如果用 JSX 實(shí)現(xiàn)類似功能就非常簡單:
<Comp scope={name=> <div>{name}</div>} />
我們只是給一個(gè)叫做scope的 props 傳遞來一個(gè)函數(shù),這個(gè)函數(shù)接受一個(gè)name屬性,在Comp里面會調(diào)用這個(gè)函數(shù)并傳入name。 簡單來說我們傳入的就是一個(gè)構(gòu)建節(jié)點(diǎn)片段的函數(shù),就是這么簡單。
這就是因?yàn)?SFC 的模板的限制,導(dǎo)致靈活性不足,Vue 需要去創(chuàng)造概念,創(chuàng)造關(guān)鍵字來抹平這些能力的不足,而創(chuàng)造的概念自然就引入了學(xué)習(xí)成本。
所以其實(shí)我一直不認(rèn)可 Vue 比 React 好學(xué)的說法的,如果你真的認(rèn)真研究所有用法,并且總是嘗試用最合理的方式實(shí)現(xiàn)功能,那么 Vue 絕對不會比 React 簡單。
這個(gè)體現(xiàn)在兩個(gè)方面,一個(gè)是我們定義在全局的一些固定數(shù)據(jù)如果要在組件內(nèi)使用的話,就要通過this掛載到組件上。
比如我們緩存了一份城市數(shù)據(jù),這種數(shù)據(jù)基本上是不會改的,所以也沒必要掛載到組件上讓其能夠響應(yīng)式。但是在 SFC 里面這是做不到的, 因?yàn)槟0宓膱?zhí)行上下文是在編譯時(shí)綁定。你在模板里面訪問的變量,都會在編譯時(shí)自動綁定到this上,因?yàn)槟0逍枰幾g,其本身也是字符串不具有作用域的概念。
而這在 JSX 中則不復(fù)存在:
const citys=[]
const Comp=()=> {
return citys.map(c=> <div>{c}</div>)
}
另外一個(gè)方面則是在組件使用上,在 SFC 中,組件必須事先注冊,因?yàn)槲覀冊谀0謇锩鎸懙闹荒苁亲址荒苁蔷唧w某個(gè)組件變量。 那么模板中的組件和真實(shí)的組件對象只能通過字符串匹配來實(shí)現(xiàn)綁定。這帶來了以下問題:
在 JSX 中則沒有這些問題,因?yàn)?JSX 里面直接使用組件引用作為參數(shù):
const Comp={...}
const App=()=> <Comp />
其實(shí)上面能看出來,除了 SFC 本身的問題之外,Vue 使用字符串模板也會帶來很多的靈活性問題。 最直接的證據(jù),就是 Vue 使用了directive來擴(kuò)展功能(當(dāng)然這不是 Vue 發(fā)明的,老早的模板引擎就有類似問題)。
為什么說directive是不得已的選擇呢?因?yàn)殪o態(tài)模板缺失邏輯處理的能力。我們拿列表循環(huán)舉例,在 JS 中我們可以非常方便地通過map函數(shù)來創(chuàng)建列表:
const list=arr.map(name=> <span key={name}>{name}</span>)
而因?yàn)?JSX 本身就是函數(shù)調(diào)用,所以上面的代碼和 JSX 結(jié)合起來也非常自然:
const App=()=> (
<div>
<Header />
{arr.map(name=> (
<span key={name}>{name}</span>
))}
</div>
)
上面的例子對應(yīng)到 JS 如下:
const App=()=>
createElement('div', {}, [
<Header />,
arr.map(name=> createElement('span', { key: name }, name)),
])
這仍然是因?yàn)?JSX 只是 JS 的語法糖的原因,所有能在 JS 中實(shí)現(xiàn)的在 JSX 里面都能實(shí)現(xiàn)。
而 SFC 的模板是基于字符串編譯的,其本身就是一段字符串,我們不能直接在模板里面寫map來循環(huán)節(jié)點(diǎn),(當(dāng)然我們可以在可以接收表達(dá)式的地方寫,比如v-on里面)。
那么我們不能循環(huán)節(jié)點(diǎn),有需要這樣的功能來渲染列表,怎么辦呢?就是發(fā)明一個(gè)標(biāo)志來告訴編譯器這里需要循環(huán),在 Vue 中的體現(xiàn)就是v-for指令。
同學(xué)們可能要問了,既然 Vue 能實(shí)現(xiàn)v-for,為什么不直接實(shí)現(xiàn)表達(dá)式循環(huán)列表呢?他當(dāng)然也可以實(shí)現(xiàn),但是他肯定不會這么選,因?yàn)槌杀咎吡恕?他要這么做就相當(dāng)于他要實(shí)現(xiàn)一個(gè) JS 引擎,而其實(shí)里面很多內(nèi)容又是不必須的,一個(gè)v-for其實(shí)就能夠適用大部分情況了。
但有了v-for就需要v-if,那么后面還會需要其他各種能力,這就是一種方言的產(chǎn)生和發(fā)展的過程。
當(dāng)然指令也不僅僅是 JS 表達(dá)式的代替品,其本身也是增加了一些其他能力的,比如它能夠讓我們更方便地訪問 DOM 節(jié)點(diǎn), 但是嘛,我們用框架的理由不就是為了能夠盡可能的屏蔽 DOM 操作嘛~
以上就是我對應(yīng)該選擇使用 JSX 還是 SFC 進(jìn)行開發(fā)的分析,其實(shí)歸根到底 SFC 的問題在于其沒有擁抱 JS, 他的語法是自己發(fā)明的,他需要有一個(gè) JS 實(shí)現(xiàn)的 compiler 來讓其最終能在 JS 環(huán)境中運(yùn)行,這本質(zhì)上就是一種發(fā)明, 我們不能否認(rèn)發(fā)明確實(shí)有優(yōu)點(diǎn),但我們也不能只看有點(diǎn)不看問題,沒能擁抱 JS 自然就很難完全復(fù)用 JS 社區(qū)的優(yōu)勢 而 JS 社區(qū)一直在蓬勃發(fā)展,好用的工具一直在涌現(xiàn),而 SFC 想要使用 JS 社區(qū)的這些工具還要自己再實(shí)現(xiàn)一份,我們可以細(xì)數(shù)以下 SFC 做了哪些兼容
基本上常用的工具我們都需要等待 Vue 社區(qū)或者官方開發(fā)了插件之后才能運(yùn)行。而 JSX 因?yàn)橛?babel 和 typescript 的官方支持, 基本上所有新的 JS 生態(tài)工具原生都是支持的。
在這 Vue3 開始預(yù)備發(fā)力的階段,我們還是希望 Vue 社區(qū)能夠使用更優(yōu)秀更規(guī)范的方式來進(jìn)行開發(fā), 其實(shí)如果我們直接使用 JSX 開發(fā) Vue3,我們會發(fā)現(xiàn)很多時(shí)候我們都不需要用到emit、attrs這些概念, 甚至如果 Vue3 的 JSX 插件支持,我們甚至能夠拋棄slots。
但是因?yàn)?Vue3 一定要考慮兼容 Vue2,導(dǎo)致本身潛力很好的 Vue3 總是顯得縮手縮腳,這不得不說是一種遺憾。
首先,JSF 是一種規(guī)范,與 JSF 通常與之相比的所有其他技術(shù)相比,它具有重要優(yōu)勢。該規(guī)范是一個(gè)開放的過程,多年來一直伴隨著許多開發(fā)人員為 Web 應(yīng)用程序定義一個(gè)通用的可靠標(biāo)準(zhǔn)。這個(gè)規(guī)范過程最近發(fā)生在 Eclipse Foundation 中,它建立了遵循非常高質(zhì)量標(biāo)準(zhǔn)的規(guī)則。這是最大的優(yōu)勢之一,因?yàn)樗WC您的 Web 應(yīng)用程序構(gòu)建在一個(gè)堅(jiān)實(shí)的核心之上。當(dāng)然,其他 Web 框架也有大型社區(qū),但這些社區(qū)通常由一家公司代表,并不總是將開發(fā)人員考慮在內(nèi)。來自 Google 的 Angular 只是一個(gè)例子。
但回到 JSF。為什么 JSF 有時(shí)會被嘲笑為過時(shí)的技術(shù)?我個(gè)人是在 2001 年初開始使用 JSF 的。所以它顯然是一項(xiàng)古老的技術(shù)。我也是一個(gè)老開發(fā)者;-)。與此同時(shí),許多其他 Web 框架也在發(fā)展。其中許多基于 JavaScript,并遵循在瀏覽器中運(yùn)行的單頁范例 (SPA)。這個(gè)想法是將應(yīng)用程序邏輯移動到瀏覽器中以更快地獲取應(yīng)用程序。這個(gè)想法是在不是每個(gè)人都對 JSF 感到滿意的時(shí)候提出的,并且 JavaScript 開始流行起來。Java Server Faces——顧名思義——相反,是一個(gè)基于服務(wù)器的框架。這意味著應(yīng)用程序邏輯在服務(wù)器上執(zhí)行。這就是我們有很大不同的地方。當(dāng)時(shí),減少服務(wù)器負(fù)載是一個(gè)有效的論據(jù)。而且當(dāng)然,這在今天仍應(yīng)是一個(gè)可取的目標(biāo)。但是,以此作為反對 JSF 的論據(jù)的人通常是對無服務(wù)器功能贊不絕口的人。因此,我認(rèn)為我們今天不應(yīng)該將基于服務(wù)器的框架視為愚蠢的想法。
基于服務(wù)器的 Web 框架提供了一些優(yōu)勢。這樣,應(yīng)用邏輯和業(yè)務(wù)邏輯可以很容易地耦合。這是在 Jakarta EE 中實(shí)現(xiàn)的,主要是通過 CDI、EJB 和 JPA。這些技術(shù)是 JSF 組件的后端。Jakarta EE 對層的分離提供了非常清晰的理解,而 JSF 無縫地融入了這一概念。服務(wù)器端實(shí)現(xiàn)還對客戶端隱藏了應(yīng)用程序細(xì)節(jié)。相比之下,在 JavaScript SPA 中,大部分應(yīng)用程序邏輯通常在瀏覽器中不受保護(hù),這在某些情況下可能存在安全風(fēng)險(xiǎn)。
因此,在服務(wù)器端呈現(xiàn)應(yīng)用程序邏輯使負(fù)責(zé)后端和前端部分的開發(fā)人員更容易。這導(dǎo)致在許多情況下可以更快地開發(fā)應(yīng)用程序。從微服務(wù)架構(gòu)的角度來看,一個(gè) JSF 應(yīng)用程序?qū)?yīng)于Self-Contained Services的原則。這是微服務(wù)架構(gòu)中常用的一種模式。
由于 JSF 通常被稱為復(fù)雜和笨拙,我最近想知道這是否真的如此。我將我的一個(gè) Vue.js SPA 遷移到 JSF 4.0 并比較了生成代碼的復(fù)雜性。所以最后,我想通過一個(gè)例子來展示 JSF 的簡單性。(注意:我這里不比較 JavaScript 代碼和 Java)
在 JavaScript 框架中,您通常通過附加標(biāo)記將 HTML 標(biāo)記綁定到某些代碼。
<!-- Vue.js --><input type="text" name="userwebsite" v-model="userwebsite" placeholder="enter your website">Your Website is: <span>{{api}}</span>
SPA 框架解析標(biāo)簽 (v-model) 并從用 JavaScript 編寫的模型中放置正確的值。它還綁定輸入字段以跟蹤模型中的更改。
JSF 對應(yīng)項(xiàng)看起來并沒有太大不同:
<!-- JSF --><h:inputText value="#{userController.website}" pt:placeholder="enter your website" />Your Website is: <h:outputText value="#{userController.website}" />
在這里,您還將模型值綁定到輸入字段或輸出文本。但是代碼在服務(wù)器端用 Java 執(zhí)行,這通常等同于用 Java 編寫的后端代碼,也適用于 SPA。
開箱即用的 JavaScript Web 框架使用 Ajax。所以你通常不需要關(guān)心它。在上面的例子中,span,一個(gè)標(biāo)簽會在輸入值改變時(shí)自動更新。
在 JSF 中,您也使用 Ajax,但您可以更好地控制它的行為方式。您可以簡單地使用 f:ajax 標(biāo)記將頁面的一部分括起來以獲得相同的行為:
<!-- JSF --><f:ajax> <h:inputText value="#{userController.website}" pt:placeholder="enter your website" /> Your Website is: <h:outputText value="#{userController.website}" /><f:ajax>
另一個(gè)例子是鏈接。在 JavaScript 框架中,當(dāng)用戶單擊元素時(shí),您再次使用一種標(biāo)記來啟動渲染生命周期:
<!-- Vue.js --><li class="nav-item" v-on:click="showSection('search')"> <label>Search</label></li>
在您的showSectionJavaScript 代碼中實(shí)現(xiàn)一些業(yè)務(wù)邏輯,并負(fù)責(zé)處理數(shù)據(jù)和更改布局。
JSF 并沒有太大的不同:
<!-- JSF --><li class="nav-item"> <h:link outcome="search" > <label>Search</label></li>
該h:link標(biāo)記從名為“search.xhtml”的后端加載一個(gè)包含新布局的新頁面。所有模型綁定都在后臺后臺處理。對于用戶而言,行為沒有區(qū)別。
因此,正如您從標(biāo)記中看到的那樣,沒有太大區(qū)別,編寫 JSF 前端并不像在基于 JavaScript 的 Web 框架中那樣復(fù)雜。
我個(gè)人的結(jié)論是,JSF 為我在框架內(nèi)編寫代碼提供了更清晰、更一致的概念。后端邏輯和應(yīng)用程序設(shè)計(jì)結(jié)合在一種技術(shù)中,從而形成一種模式,也稱為自包含微服務(wù)。
對我來說,即使對于現(xiàn)代 Web 應(yīng)用程序來說,這也是一個(gè)有效的概念。而在服務(wù)器端計(jì)算應(yīng)用邏輯一點(diǎn)也不瘋狂。
使用 JSF 版本 4.0,您會發(fā)現(xiàn)一種現(xiàn)代且設(shè)計(jì)良好的 Web 技術(shù)嵌入到最新的Jakarta EE 10 框架中。
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。