Springboot項(xiàng)目打包后詭異的頁面丟失問題

前言

在做公司的一個(gè)項(xiàng)目阱当,使用springboot加thymeleaf,由于開發(fā)過程中一直是在idea中進(jìn)行糜工,并且頁面顯示良好弊添,因此覺得功能使用是沒有問題的,但是昨天下午在用maven打包之后捌木,例行測(cè)試時(shí)發(fā)現(xiàn)了很奇怪的問題:
部分頁面無法打開油坝,出現(xiàn)了500錯(cuò)誤;另外一些頁面則顯示正常钮莲,于是開始排查問題所在

1.定位錯(cuò)誤原因

12:08:26 [http-nio-8084-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template "/mgm/reward/batch", template might not exist or might not be accessible by any of the configured Template Resolvers] with root cause
org.thymeleaf.exceptions.TemplateInputException: Error resolving template "/mgm/reward/batch", template might not exist or might not be accessible by any of the configured Template Resolvers
       at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:870)
       at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:607)
       at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
       at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072)
       at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:354)
       at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:187)
       at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1325)
       at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1069)
       at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1008)
       at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
       at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
       at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
       at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
       at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
       at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
       at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
       at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
       at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
       at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
       at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
       at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
       at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
       at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
       at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
       at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
       at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
       at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
       at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
       at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
       at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
       at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
       at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
       at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
       at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
       at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468)
       at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
       at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
       at java.lang.Thread.run(Unknown Source)

根據(jù)打印出來的堆椕庾辏可以看到是在ThymeleafViewResolver渲染頁面時(shí)發(fā)現(xiàn)無法找到目標(biāo)文件,問題找到了崔拥,但是在idea中又能正常使用极舔,這個(gè)現(xiàn)象很奇怪

2.網(wǎng)上查查有沒有遇到同樣問題的

然后還真找到了一個(gè)類似的問題:
Error resolve template in a jar-stackoverflow
根據(jù)被采納的回答來看,有兩種情況會(huì)導(dǎo)致出現(xiàn)這種問題:

  • 返回視圖路徑以/開頭链瓦,例如 /test/hello
  • 在thymeleaf頁面中拆魏,引入的頁面以/開頭盯桦,例如:<footer th:replace="/index::footer"></footer>
    在將出問題的頁面和正常的頁面對(duì)比后,發(fā)現(xiàn)是第一種情況導(dǎo)致的問題渤刃,將多余的/刪除拥峦,問題解決

3.為什么多余的/會(huì)導(dǎo)致jar運(yùn)行出問題而idea模式下沒問題呢?

打開idea卖子,進(jìn)入debug模式略号,在跑出異常的TemplateManagerparseAndProcess()方法加上斷點(diǎn),查看程序運(yùn)行堆棧:

classpath-error.jpg

可以看到洋闽,在有/條件下玄柠,斷點(diǎn)那一行templateResolutionresource屬性全路徑是templates//mgm/reward/batch.html,這個(gè)文件路徑肯定是沒法找到對(duì)應(yīng)的文件路徑的诫舅。


作為對(duì)比羽利,下圖是正常路徑

classpath.jpg

這里算是找到出問題的緣由了,就是因?yàn)榉祷芈窂讲粚?duì)導(dǎo)致在最后視圖渲染時(shí)由于找不到對(duì)應(yīng)文件刊懈,拋出異常这弧,resolveTemplate()方法如圖:
exception-reason.jpg

在最后一段,找不到文件的話虚汛,默認(rèn)拋出TemplateInputException


其實(shí)到這里也只能算是確認(rèn)了jar模式下匾浪,視圖解析異常的原因;那么同樣的代碼為什么idea能正常運(yùn)行不拋出異常呢泽疆?
在前面的stackoverflow有一個(gè)解釋:

reason.jpg

說是因?yàn)閕dea在啟動(dòng)時(shí)户矢,是從文件系統(tǒng)中加載資源,對(duì)于//,文件系統(tǒng)是支持這種尋址的殉疼,但是在jar的內(nèi)部資源加載就無法使用這種模式了梯浪,到此原因終于確認(rèn)了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瓢娜,一起剝皮案震驚了整個(gè)濱河市挂洛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌眠砾,老刑警劉巖虏劲,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異褒颈,居然都是意外死亡柒巫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門谷丸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堡掏,“玉大人,你說我怎么就攤上這事刨疼∪洌” “怎么了鹅龄?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長亭畜。 經(jīng)常有香客問我扮休,道長,這世上最難降的妖魔是什么拴鸵? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任玷坠,我火速辦了婚禮,結(jié)果婚禮上宝踪,老公的妹妹穿的比我還像新娘侨糟。我一直安慰自己,他們只是感情好瘩燥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著不同,像睡著了一般厉膀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上二拐,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天服鹅,我揣著相機(jī)與錄音,去河邊找鬼百新。 笑死企软,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的饭望。 我是一名探鬼主播仗哨,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铅辞!你這毒婦竟也來了厌漂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤斟珊,失蹤者是張志新(化名)和其女友劉穎苇倡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體囤踩,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旨椒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堵漱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片综慎。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖怔锌,靈堂內(nèi)的尸體忽然破棺而出寥粹,到底是詐尸還是另有隱情变过,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布涝涤,位于F島的核電站媚狰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏阔拳。R本人自食惡果不足惜崭孤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糊肠。 院中可真熱鬧辨宠,春花似錦、人聲如沸货裹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弧圆。三九已至赋兵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間搔预,已是汗流浹背霹期。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拯田,地道東北人历造。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像船庇,于是被迫代替她去往敵國和親吭产。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容