
簡(jiǎn)介eWebEditor在線文本編輯器 v0.1.4 For JSP 是面向JSP開(kāi)發(fā)者的富文本編輯組件主要解決網(wǎng)頁(yè)內(nèi)容錄入、排版與多媒體插入問(wèn)題適合后臺(tái)管理、內(nèi)容發(fā)布等頁(yè)面集成可視化編輯能力。壓縮包共264個(gè)文件以186個(gè)gif界面素材、27個(gè)css樣式、21個(gè)htm示例頁(yè)為主輔以jsp、js、class、xml及jar等運(yùn)行文件整體約796KB便于部署到現(xiàn)有JSP工程試用。已有173人學(xué)習(xí)說(shuō)明其在傳統(tǒng)JSP項(xiàng)目中仍具參考價(jià)值。它提供字體字號(hào)、顏色、加粗斜體等格式化操作支持圖片上傳、多媒體鏈接、超鏈接與郵件鏈接并保留HTML源碼編輯入口呂海鵬修改版對(duì)性能與穩(wěn)定性有所優(yōu)化。通過(guò)API調(diào)整布局、擴(kuò)展插件并處理XSS等安全問(wèn)題適合理解老式JSP富文本編輯器集成與二次開(kāi)發(fā)。1. 拿到 eWebEditor v0.1.4 For JSP 就先別急著解壓上個(gè)月幫人收拾一套老后臺(tái)需求只有一句新聞發(fā)布頁(yè)要能貼圖、能調(diào)字號(hào)。翻出來(lái)的是 eWebEditor在線文本編輯器 v0.1.4 For JSP 這個(gè)包ewebeditor014jsp.rar解壓出來(lái)一堆 jsp 文件。對(duì)方態(tài)度很輕松說(shuō)扔進(jìn) Tomcat 就完事了結(jié)果訪問(wèn)直接 404日志里干凈得像什么也沒(méi)發(fā)生。這套環(huán)境的坑就在這它不連數(shù)據(jù)庫(kù)、不需要編譯、配置散在幾個(gè)文件里任何一個(gè)路徑寫(xiě)錯(cuò)表現(xiàn)都是白屏或者 404特別容易讓人懷疑包本身是壞的。它適合還在維護(hù) JSP 后臺(tái)、只想補(bǔ)一個(gè)輕量編輯入口的人如果你手上是前后端分離的項(xiàng)目硬塞進(jìn)去會(huì)很別扭。2. 環(huán)境清單JDK、Tomcat 與 eWebEditor v0.1.4 的版本取舍2.1 JDK 先用 8別拿高版本硬頂老 JSP 組件第一道坎從來(lái)不是代碼寫(xiě)得對(duì)不對(duì)而是運(yùn)行時(shí)版本。eWebEditor v0.1.4 這個(gè)年代的包里面引用的還是javax.servlet.*這套命名空間很多輔助類也依賴 JDK 自帶的 XML、加密相關(guān) API。JDK 8 是最后一批把這些東西放在標(biāo)準(zhǔn)庫(kù)里的版本往上走就開(kāi)始拆模塊常見(jiàn)的報(bào)錯(cuò)是NoClassDefFoundError: javax/xml/bind/DatatypeConverter這種看著像包缺文件實(shí)際是運(yùn)行時(shí)不給你了。我一般先確認(rèn)機(jī)器上裝了什么# 看當(dāng)前默認(rèn) JDK以及機(jī)器上還裝了哪些 java -version update-alternatives --list java 2/dev/null || ls /usr/lib/jvm第一條輸出里那行1.8.0_xxx就是我們要的。如果只有 11 或 17別急著卸裝一個(gè) 8 并存用update-alternatives --config java切過(guò)去就行。要注意 Tomcat 啟動(dòng)腳本讀的是JAVA_HOME光切java命令不夠# 讓 Tomcat 明確用 JDK 8而不是跟著 shell 的默認(rèn)走 export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export JRE_HOME$JAVA_HOME/jre $CATALINA_HOME/bin/shutdown.sh $CATALINA_HOME/bin/startup.shJAVA_HOME指向 JDK 根目錄JRE_HOME指向它下面的 jre兩個(gè)都寫(xiě)是為了兼容老版本的 catalina.sh有些發(fā)行版只認(rèn)JRE_HOME。改完別用service tomcat restart那個(gè)腳本未必繼承你當(dāng)前 shell 的環(huán)境變量直接用 Tomcat 自帶的 startup/shutdown 最穩(wěn)。還有一步值得做看看包里到底有沒(méi)有預(yù)編譯的 class。純 JSP 的包是沒(méi)有的有的話就要留意字節(jié)碼版本。# 解壓后統(tǒng)計(jì) class 文件并看它們的字節(jié)碼主版本號(hào) find ./ewebeditor -name *.class | wc -l find ./ewebeditor -name *.class -exec javap -verbose {} \; 2/dev/null \ | grep major version | sort -umajor version48 對(duì)應(yīng) JDK 1.449 是 550 是 651 是 752 是 8。如果輸出是 48 或 49JDK 8 跑起來(lái)沒(méi)問(wèn)題高版本 JDK 也認(rèn)這些老字節(jié)碼所以字節(jié)碼本身很少是致命傷真正的雷是前面說(shuō)的標(biāo)準(zhǔn)庫(kù)拆分和第三方 jar 缺失。這一步的價(jià)值在于當(dāng)你后面遇到UnsupportedClassVersionError能立刻判斷是版本不夠還是版本太高而不是盲目換 JDK 試。2.2 Tomcat 選 8.5 還是 9命名空間決定生死這一條幾乎每年都有人踩Tomcat 10 開(kāi)始把javax.servlet整體換成了jakarta.servlet所有老 JSP 應(yīng)用的import全部失效部署上去就是一片 500。所以選型范圍很明確8.5 和 9 都能用10 及以上直接排除。兩者之間我偏向 8.5 的最后一個(gè)版本。原因不玄學(xué)8.5 對(duì)老 JSP 的容錯(cuò)更好JSP 編譯器的默認(rèn)行為更接近這個(gè)包出生的年代而 9 在一些 EL 表達(dá)式和標(biāo)簽庫(kù)的解析上更嚴(yán)格老頁(yè)面里那種不規(guī)范的寫(xiě)法容易被判死。當(dāng)然如果服務(wù)器上已經(jīng)有 9 在跑別的應(yīng)用也別為了它單獨(dú)降級(jí)先在 9 上試能起來(lái)就留著。判斷當(dāng)前 Tomcat 版本很簡(jiǎn)單# 版本號(hào)在啟動(dòng)腳本里不用啟動(dòng)服務(wù)也能看 $CATALINA_HOME/bin/version.sh輸出里Server version和Servlet Spec兩行最關(guān)鍵Servlet 規(guī)范是 3.1 就說(shuō)明是 8.5 或 9是 5.0/6.0 就是 10 以上那就得換。另外順手確認(rèn)conf/server.xml里沒(méi)有開(kāi)啟allowLinking之類的特殊選項(xiàng)老應(yīng)用對(duì)這些很敏感。2.3 解壓前三件事編碼、目錄層級(jí)、只讀屬性rar 包在 Linux 上解壓最常見(jiàn)的翻車是文件名亂碼。這種包多半在 Windows 下用 GBK 打的包直接unrar x出來(lái)會(huì)看到一堆問(wèn)號(hào)和方框JSP 文件名一旦變成亂碼Tomcat 就找不到入口頁(yè)表現(xiàn)同樣是 404。所以我一般不在 Linux 上直接解要么先用 7-Zip 在本地解開(kāi)再傳上去要么解壓時(shí)把 locale 臨時(shí)指過(guò)去。# 先列目錄確認(rèn)壓縮包內(nèi)部的層級(jí)結(jié)構(gòu) unrar l ewebeditor014jsp.rar | head -40看輸出有幾個(gè)細(xì)節(jié)第一包內(nèi)是不是已經(jīng)有一層ewebeditor014jsp/頂層目錄如果有解壓后別再套一層同名目錄否則訪問(wèn)路徑要多一級(jí)這是 404 的高發(fā)原因第二文件名里有沒(méi)有中文有的話優(yōu)先換平臺(tái)解壓第三注意有沒(méi)有.htaccess、Thumbs.db這類無(wú)關(guān)文件刪掉省得干擾。解壓本身# -o 覆蓋-x 后面可以跟排除規(guī)則這里先全解 mkdir -p /opt/apps cd /opt/apps unrar x -o /tmp/ewebeditor014jsp.rar-o表示無(wú)條件覆蓋同名文件重復(fù)解壓時(shí)不會(huì)卡在交互提示上。解壓完先ls -R | head -60掃一眼確認(rèn)入口 jsp、靜態(tài)資源目錄、上傳目錄都在再往下走。這個(gè)習(xí)慣救過(guò)我很多次包不完整的時(shí)候越早發(fā)現(xiàn)越省事。3. 部署落地把 eWebEditor 掛進(jìn) Tomcat 的完整步驟3.1 目錄歸位與權(quán)限預(yù)設(shè)部署位置只有兩種選擇塞進(jìn)webapps讓 Tomcat 自動(dòng)部署或者放在外部目錄用 Context 顯式掛載。前者省事后者便于升級(jí)和備份我個(gè)人傾向后者尤其這種老包哪天要換版本外部目錄換個(gè)軟鏈就行不用動(dòng) Tomcat 本體。# 統(tǒng)一放到 /opt/apps/ewebeditor屬主交給運(yùn)行 Tomcat 的賬號(hào) sudo mv /opt/apps/ewebeditor014jsp /opt/apps/ewebeditor sudo chown -R tomcat:tomcat /opt/apps/ewebeditor # 目錄 755、文件 644上傳目錄單獨(dú)放寬 sudo find /opt/apps/ewebeditor -type d -exec chmod 755 {} \; sudo find /opt/apps/ewebeditor -type f -exec chmod 644 {} \; sudo chmod 775 /opt/apps/ewebeditor/UploadFile 2/dev/null || true屬主必須和 Tomcat 進(jìn)程的實(shí)際運(yùn)行賬號(hào)一致很多人用 root 起 Tomcat那chown成 root 才對(duì)判斷方法是ps -ef | grep tomcat看第一列。權(quán)限給 777 是典型的圖省事做法能跑但不該做上傳目錄可執(zhí)行意味著別人傳個(gè) jsp 上來(lái)就能被訪問(wèn)到這是老編輯器最容易被盯上的地方后面 4.3 會(huì)給一個(gè)約束辦法。3.2 兩種 context 配置方式選一種就行外部目錄掛載的標(biāo)準(zhǔn)做法是在conf/Catalina/localhost/下建一個(gè)和應(yīng)用同名的 xml!-- 文件名必須是 ewebeditor.xml和訪問(wèn)路徑保持一致 -- Context docBase/opt/apps/ewebeditor reloadablefalse crossContextfalse /docBase寫(xiě)絕對(duì)路徑指向解壓后的根目錄reloadablefalse是刻意的老應(yīng)用的類加載器在熱重載時(shí)經(jīng)常出問(wèn)題改配置就重啟別圖快。文件名ewebeditor.xml直接決定訪問(wèn)前綴也就是http://ip:8080/ewebeditor/。另一種方式是把整個(gè)目錄拷進(jìn)webapps/ewebeditorTomcat 啟動(dòng)時(shí)自動(dòng)掃描部署。這種方式的問(wèn)題在于路徑和 Tomcat 安裝目錄綁死遷移機(jī)器要重新拷一遍而且webapps下東西多了以后啟動(dòng)變慢。如果堅(jiān)持用這種方式記得關(guān)掉自動(dòng)部署的監(jiān)聽(tīng)避免啟動(dòng)時(shí)反復(fù)掃描!-- conf/server.xml 的 Host 節(jié)點(diǎn)里把 autoDeploy 關(guān)掉 -- Host namelocalhost appBasewebapps unpackWARstrue autoDeployfalse改完server.xml一定要重啟不是 reload。這一步之后如果訪問(wèn)還是 404先看logs/catalina.out里有沒(méi)有Context [] startup failed有的話基本是docBase路徑寫(xiě)錯(cuò)或者目錄權(quán)限不對(duì)。3.3 入口頁(yè)與 web.xml 的注冊(cè)純 JSP 版本的 eWebEditor 通常不需要額外的 servlet 映射訪問(wèn)入口 jsp 就能打開(kāi)編輯頁(yè)面。但如果你拿到的包里有WEB-INF/web.xml里面可能已經(jīng)寫(xiě)好了一些初始化參數(shù)這時(shí)候要做的是確認(rèn)它有沒(méi)有被正確讀取而不是另寫(xiě)一份。!-- WEB-INF/web.xml 里通常只需要補(bǔ)一個(gè)歡迎頁(yè)讓根路徑能落到入口 -- web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee version3.1 display-nameewebeditor/display-name welcome-file-list welcome-fileewebeditor.jsp/welcome-file /welcome-file-list /web-appversion3.1對(duì)應(yīng) Servlet 3.1也就是 Tomcat 8.5/9 的規(guī)范寫(xiě)高了容器可能拒絕加載。welcome-file里的文件名要和實(shí)際入口頁(yè)完全一致大小寫(xiě)敏感Linux 上EWEBEDITOR.JSP和ewebeditor.jsp是兩個(gè)文件。改完 web.xml 之后重啟然后用 curl 探一下?tīng)顟B(tài)碼比開(kāi)瀏覽器快# 只看響應(yīng)頭確認(rèn) 200 還是 404/500 curl -I http://127.0.0.1:8080/ewebeditor/ewebeditor.jsp返回 200 說(shuō)明路徑通了404 說(shuō)明 context 沒(méi)起來(lái)或者文件名不對(duì)500 就要去logs/localhost.*.log里找堆棧了。這一步是分水嶺過(guò)了它剩下的都是配置細(xì)節(jié)。4. 配置參數(shù)上傳目錄、樣式與請(qǐng)求體大小4.1 上傳目錄的定位與寫(xiě)入驗(yàn)證老編輯器的上傳路徑經(jīng)常是寫(xiě)死在配置里的相對(duì)路徑比如UploadFile相對(duì)于應(yīng)用根目錄。這意味著它跟著docBase走應(yīng)用搬到哪上傳文件就跟著到哪備份的時(shí)候別漏掉。先確認(rèn)配置里寫(xiě)的是哪個(gè)目錄不同包的位置不一樣常見(jiàn)的是根目錄下一個(gè)配置文件或者入口 jsp 頂部的變量區(qū)。找到之后做一次寫(xiě)入驗(yàn)證不要等用戶上傳失敗才查# 用 Tomcat 的運(yùn)行賬號(hào)試寫(xiě)能寫(xiě)才算配好 sudo -u tomcat touch /opt/apps/ewebeditor/UploadFile/.write_test sudo -u tomcat rm -f /opt/apps/ewebeditor/UploadFile/.write_test如果第二條命令報(bào)Permission denied說(shuō)明前面的 chown 沒(méi)生效或者 SELinux 攔了。CentOS 系上還要看一眼上下文# 只讀排查用確認(rèn)目錄的安全上下文類型 ls -Zd /opt/apps/ewebeditor/UploadFile正常的應(yīng)該是httpd_sys_rw_content_t之類允許寫(xiě)的類型如果是user_home_t那就是 SELinux 在攔用chcon -R -t httpd_sys_rw_content_t修一下別圖省事直接setenforce 0那等于把整臺(tái)機(jī)器的防護(hù)關(guān)了。4.2 請(qǐng)求體大小與連接器參數(shù)上傳失敗還有一種原因跟權(quán)限無(wú)關(guān)請(qǐng)求體超了 Tomcat 的默認(rèn)上限。老版本 Connector 上有maxPostSize默認(rèn) 2MB現(xiàn)在隨便一張手機(jī)照片就超。改在conf/server.xml的 Connector 節(jié)點(diǎn)Connector port8080 protocolHTTP/1.1 connectionTimeout20000 URIEncodingUTF-8 maxPostSize20971520 maxSwallowSize20971520 redirectPort8443 /maxPostSize是表單 POST 體的上限單位字節(jié)20971520 就是 20MBmaxSwallowSize控制的是超限之后容器還愿意吞掉多少數(shù)據(jù)不設(shè)的話客戶端可能收到連接重置而不是一個(gè)干凈的 413。URIEncodingUTF-8是給 GET 參數(shù)用的老包默認(rèn)可能按 ISO-8859-1 解中文標(biāo)題會(huì)變問(wèn)號(hào)這一條改完能省掉后面一堆亂碼排查。順便把 JSP 頁(yè)面的編碼也對(duì)齊入口頁(yè)頂部那行page指令是關(guān)鍵% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %contentType管響應(yīng)頭pageEncoding管 JSP 源文件本身的讀取編碼兩個(gè)必須一致只改一個(gè)還是亂碼。如果源文件實(shí)際是 GBK 保存的你寫(xiě) UTF-8 會(huì)直接編譯報(bào)錯(cuò)那就得先用編輯器轉(zhuǎn)碼再傳不要硬改指令。4.3 上傳目錄的訪問(wèn)約束前面提過(guò)上傳目錄可執(zhí)行是這類編輯器的老毛病。約束辦法是在應(yīng)用的WEB-INF/web.xml里加一條安全約束禁止直接訪問(wèn)上傳目錄下的腳本文件!-- 放在 web-app 節(jié)點(diǎn)內(nèi)禁止通過(guò) URL 訪問(wèn)上傳目錄里的 jsp -- security-constraint web-resource-collection web-resource-nameupload-script-deny/web-resource-name url-pattern/UploadFile/*.jsp/url-pattern url-pattern/UploadFile/*.jspx/url-pattern /web-resource-collection auth-constraint/ /security-constraint空的auth-constraint/表示不允許任何角色訪問(wèn)效果是直接 403。注意url-pattern只匹配一層如果上傳目錄下面還有子目錄要么再補(bǔ)規(guī)則要么在應(yīng)用層限制上傳時(shí)的擴(kuò)展名白名單。這條不是可選項(xiàng)尤其是這套環(huán)境掛在公網(wǎng)的時(shí)候。5. 避坑排查eWebEditor v0.1.4 部署里最常見(jiàn)的五個(gè)坑5.1 訪問(wèn) 404日志里什么都沒(méi)有現(xiàn)象瀏覽器打開(kāi)http://ip:8080/ewebeditor/返回 404catalina.out里看不到任何和應(yīng)用相關(guān)的記錄。原因九成是 context 根本沒(méi)加載??赡苁莄onf/Catalina/localhost/ewebeditor.xml文件名和訪問(wèn)路徑不一致也可能是docBase指向的目錄里沒(méi)有入口頁(yè)Tomcat 加載了空 context 但不報(bào)錯(cuò)。還有一種情況是包內(nèi)本身有一層同名目錄實(shí)際入口在/opt/apps/ewebeditor/ewebeditor014jsp/ewebeditor.jsp。解決先ls /opt/apps/ewebeditor確認(rèn)入口頁(yè)在不在第一層不在就把內(nèi)容上提一層。再確認(rèn) xml 文件名然后重啟看日志里有沒(méi)有Deploying context字樣。這一步用curl -I看狀態(tài)碼比開(kāi)瀏覽器快得多。5.2 500 報(bào) UnsupportedClassVersionError現(xiàn)象頁(yè)面直接 500日志里是java.lang.UnsupportedClassVersionError: xxx has been compiled by a more recent version of the Java Runtime。原因包里的 class 是用更高版本 JDK 編的而當(dāng)前運(yùn)行時(shí)是 JDK 8?;蛘叻催^(guò)來(lái)包是老的但跑在 JDK 17 上報(bào)的是另一類NoClassDefFoundError。前者是版本不夠后者是標(biāo)準(zhǔn)庫(kù)被拆走。解決用 2.1 里的javap -verbose看主版本號(hào)52 就必須 JDK 8 以上48 就 JDK 8 足夠。確認(rèn)是標(biāo)準(zhǔn)庫(kù)缺失的把對(duì)應(yīng)模塊的 jar 補(bǔ)進(jìn)WEB-INF/lib別去改 Tomcat 的啟動(dòng)參數(shù)加--add-opens那是給新應(yīng)用用的老包補(bǔ) jar 更直接。5.3 上傳圖片成功但回顯是紅叉現(xiàn)象點(diǎn)上傳提示成功磁盤(pán)上也能看到文件但編輯器里顯示不出來(lái)。原因編輯器回填的 URL 用的是絕對(duì)路徑或者寫(xiě)死的 context 名應(yīng)用部署前綴一變就對(duì)不上。也可能是上傳目錄被前面的安全約束一刀切禁掉了圖片請(qǐng)求返回 403。解決F12 看那個(gè)紅叉請(qǐng)求的實(shí)際 URL如果多了或少了一級(jí)前綴改配置文件里的路徑拼接部分如果是 403把 4.3 的規(guī)則收窄到只禁腳本擴(kuò)展名別把圖片一起禁了。5.4 中文文件名變亂碼或上傳后文件名是一串?dāng)?shù)字現(xiàn)象上傳中文名文件落到磁盤(pán)上變成%E4%B8%AD%E6%96%87.jpg或者一串時(shí)間戳。原因前者是請(qǐng)求編碼沒(méi)對(duì)齊URIEncoding和 JSP 的pageEncoding有一處沒(méi)改后者是編輯器本身的命名策略很多老版本默認(rèn)按時(shí)間戳重命名屬于正常行為不是故障。解決編碼問(wèn)題按 4.2 里兩處一起改改完必須重啟。命名策略要看配置里有沒(méi)有「保留原文件名」的開(kāi)關(guān)沒(méi)有的話就接受時(shí)間戳命名反而避免了中文文件名在跨平臺(tái)遷移時(shí)的麻煩。5.5 部署到 Tomcat 10 直接一片 500現(xiàn)象換到新服務(wù)器Tomcat 是 10 或 11應(yīng)用一起來(lái)所有頁(yè)面都 500日志里是java.lang.NoClassDefFoundError: javax/servlet/Servlet。原因Tomcat 10 起全面切到j(luò)akarta.servlet命名空間老包的 import 全部失效這不是配置能解決的。解決把 Tomcat 降到 9 或 8.5別試圖改源碼里的 import改一處會(huì)牽出一串。如果這臺(tái)機(jī)器上還有別的應(yīng)用必須用 Tomcat 10那就裝兩個(gè) Tomcat 實(shí)例用不同端口各自跑各自的這是最省事的隔離方式。6. 驗(yàn)證跑通從入口頁(yè)到一次真實(shí)保存配置改完不等于裝好我習(xí)慣走一條固定鏈路驗(yàn)證每一步都能定位到具體環(huán)節(jié)。# 第一步入口頁(yè)狀態(tài)碼 curl -s -o /dev/null -w %{http_code}\n http://127.0.0.1:8080/ewebeditor/ewebeditor.jsp # 第二步靜態(tài)資源能不能取到路徑按實(shí)際 js 目錄調(diào)整 curl -s -o /dev/null -w %{http_code}\n http://127.0.0.1:8080/ewebeditor/js/ewebeditor.js # 第三步模擬一次上傳目錄可寫(xiě)性檢查不經(jīng)過(guò)編輯器 sudo -u tomcat test -w /opt/apps/ewebeditor/UploadFile echo writable三條都通再去瀏覽器里做真實(shí)操作打開(kāi)入口頁(yè)輸入一段帶中文的正文插一張圖保存然后回到列表頁(yè)看內(nèi)容有沒(méi)有完整回顯。中間任何一步卡住對(duì)照下面這張表定位驗(yàn)證項(xiàng)期望結(jié)果失敗時(shí)優(yōu)先看入口頁(yè)狀態(tài)碼200context 配置、文件名大小寫(xiě)靜態(tài)資源200 且 Content-Type 正確目錄權(quán)限、context 前綴上傳目錄可寫(xiě)輸出 writable屬主、SELinux 上下文中文正文保存回顯不亂碼pageEncoding、URIEncoding圖片回顯請(qǐng)求返回 200安全約束、URL 拼接還有一個(gè)容易被忽略的點(diǎn)驗(yàn)證要在重啟之后做。很多配置項(xiàng)是啟動(dòng)時(shí)讀取的改完不重啟你驗(yàn)證的其實(shí)是舊配置白忙一場(chǎng)。從那以后我每次部署這類老 JSP 包都強(qiáng)制走一遍「先確認(rèn) JDK、再看 Tomcat 命名空間、最后跑三條 curl」不管對(duì)方說(shuō)得多輕松。老包不難裝難的是它出問(wèn)題的時(shí)候不給線索把驗(yàn)證做在前面比事后翻日志省太多時(shí)間。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取