[关闭]
@TedZhou 2020-10-15T03:26:55.000000Z 字数 5148 阅读 1108

Springboot thymeleaf使用外置template和static路径

java spring thymeleaf


Springboot开发的web项目打jar包部署时,如果希望template模板及static文件(js/css/img等)能单独更新,可以用下面的方法把它们从jar包分离出来。

工程目录结构调整

把static和template移到resources之外,比如和java目录平级。

  1. ├─src
  2. ├─main
  3. ├─java
  4. ├─resources
  5. └─application.properties
  6. ├─static
  7. └─templates
  8. └─test

在 application.properties 分别指定static和template的位置

  1. spring.mvc.static-path-pattern=/static/**
  2. spring.resources.static-locations=file:/pathto/yourproject/src/main/static/
  3. spring.thymeleaf.prefix=file:/pathto/yourproject/src/main/templates/
  4. #spring.thymeleaf.cache=false

html模板里引用static文件的方式

  1. <link rel="stylesheet" th:href="@{/static/subpath/afile.css}" />
  2. <script th:src="@{/static/subpath/afile.js}"></script>
  3. <img th:src="@{/static/subpath/afile.png}"/>

注:link favicon不知为何不能加static:(

把static和template合并,方便一起编辑

实践中发现,html模板和对应的静态文件(js,css,images等)分开在两处不方便编辑。尝试把他们合并到同一个文件夹下。首先只要修改下面两个配置都指向一个地方(比如webroot):

  1. spring.resources.static-locations=file:/pathto/yourproject/src/main/webroot/
  2. spring.thymeleaf.prefix=file:/pathto/yourproject/src/main/webroot/

只是这样会导致html模板也可以被用户直接访问,不太安全。需要调整一下security配置:
- 配置方法configure(WebSecurity webSecurity) :

  1. // 忽略静态资源改为只忽略特定类型的静态资源,目的是不忽略*.html模板
  2. //webSecurity.ignoring().antMatchers("/static/**");
  3. webSecurity.ignoring().antMatchers("/static/**/*.js");
  4. webSecurity.ignoring().antMatchers("/static/**/*.css");
  5. webSecurity.ignoring().antMatchers("/static/**/*.jpg");
  6. webSecurity.ignoring().antMatchers("/static/**/*.png");
  1. //禁止直接访问html模板
  2. httpSecurity.authorizeRequests().antMatchers("/static/**/*.html").denyAll()

Spring boot 处理 error

参考: https://www.cnblogs.com/hyl8218/p/10754894.html
Spring boot 处理 error 的基本流程:
Controller -> 发生错误 -> BasicErrorController -> 根据 @RequestMapping(produces) 判断调用 errorHtml 或者 error 方法,然后:
errorHtml -> getErrorAttributes -> ErrorViewResolver -> 错误显示页面
error -> getErrorAttributes -> @ResponseBody (直接返回JSON)

附:为静态文件加md5(避免浏览器缓存旧文件)

  1. spring.resources.chain.strategy.content.enabled=true
  2. spring.resources.chain.strategy.content.paths=/**

附一:content-path 相关处理

配置项

  1. server.servlet.context-path=/myweb

后端获取basePath

  1. public static String getWebBasePath() {
  2. RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
  3. if (requestAttributes == null) return null;//防止意外
  4. HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getResponse();
  5. if (request == null) return null;//防止意外
  6. return String.format("%s://%s:%s%s/", request.getScheme(), request.getServerName(), request.getServerPort(), request.getContextPath());
  7. }

在js里获取contentPath

  1. <script th:inline="javascript">
  2. var contextPath = /*[[${#request.contextPath}]]*/'';
  3. </script>

注:在html模板里使用th:href或th:src时带"@"符号会自动处理contentPath

附二:为thymeleaf模板设置全局静态变量

以配置第三方库路径为例

配置项

  1. basepath.lib=https://cdnjs.cloudflare.com/ajax/

配置 ThymeleafViewResolver

  1. @Resource
  2. private Environment env; //环境变量
  3. @Resource
  4. private void configureThymeleafStaticVars(ThymeleafViewResolver viewResolver) {
  5. if(viewResolver != null) {
  6. Map<String, Object> vars = new HashMap<>();
  7. vars.put("libBasePath", env.getProperty("basepath.lib"));//静态库配置
  8. viewResolver.setStaticVariables(vars);
  9. }
  10. }

使用libBasePath引入第三方库(比如vue.js)

  1. <script th:src="${libBasePath}+'libs/vue/2.6.10/vue.js'"></script>

附三:html模板共用head

common.html 里定义公用head

  1. <!DOCTYPE html>
  2. <html lang="zh" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  3. <head th:fragment="head">
  4. <meta charset="utf-8"/>
  5. <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no"/>
  6. <link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}">
  7. <link rel="stylesheet" th:href="${libBasePath}+'libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css'"/>
  8. <script th:src="${libBasePath}+'libs/vue/2.6.10/vue.js'"></script>
  9. <link th:href="@{/static/base.css}" rel="stylesheet"/>
  10. <script th:src="@{/static/base.js}"></script>
  11. <script th:inline="javascript">var contentPath = /*[[${#request.contextPath}]]*/'';</script>
  12. </head>
  13. <body>
  14. </body>
  15. <html>

index.html 里引用common::head

  1. <!DOCTYPE html>
  2. <html lang="zh" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <title>我的页面</title>
  5. <th:block th:include="common::head"></th:block>
  6. <link rel="stylesheet" th:href="@{/static/index.css}" />
  7. </head>
  8. <body>
  9. <script th:inline="javascript">
  10. var varForJs = /*[[${varForJs}]]*/{};
  11. </script>
  12. <script th:src="@{/static/index.js}"></script>
  13. <body>
  14. </html>

附四:使用thymeleaf简单制作vue组件

用tab-bar做例子

tabar.html

  1. <!DOCTYPE html>
  2. <html lang="zh" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  3. <body>
  4. <th:block th:fragment="tabar">
  5. <script type="text/x-template" id="tabar-tpl">
  6. <div class="nav nav-tabs">
  7. <a class="nav-item nav-link" href="#"
  8. v-for="(tabName,tabKey) in tabs" v-show="!!tabName"
  9. :class="{active: active == tabKey}"
  10. @click="onClick(tabKey, tabName)">{{tabName}}</a>
  11. <slot></slot>
  12. </div>
  13. </script>
  14. <script th:inline="javascript">
  15. Vue.component('tabar', {
  16. template: '#tabar-tpl',
  17. props:{
  18. tabs: [Object, Array],
  19. active: [String, Number],
  20. },
  21. data() {
  22. return {}
  23. },
  24. methods: {
  25. onClick(tabKey, tabName){
  26. this.$emit('click-tab', {key: tabKey, name: tabName})
  27. },
  28. }
  29. });
  30. </script>
  31. </th:block>
  32. </body>
  33. </html>

引入和使用

  1. <head>
  2. <th:block th:include="tabar::tabar"></th:block>
  3. </head>
  4. <body>
  5. <div id="root">
  6. <tabar :tabs="tabs" :active="activeTab" @click-tab="activeTab=$event.key"></tabar>
  7. </div>
  8. </body>
  9. <script>
  10. new Vue({
  11. el: '#root',
  12. data: {
  13. tabs: {a:'Tab A', b:'Tab B'},
  14. activeTab: 'a',
  15. },
  16. methods: {
  17. },
  18. });
  19. </script>
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注