@TedZhou
2020-10-15T03:26:55.000000Z
字数 5148
阅读 2329
java spring thymeleaf
Springboot开发的web项目打jar包部署时,如果希望template模板及static文件(js/css/img等)能单独更新,可以用下面的方法把它们从jar包分离出来。
把static和template移到resources之外,比如和java目录平级。
├─src│ ├─main│ │ ├─java│ │ ├─resources│ │ │ └─application.properties│ │ ├─static│ │ └─templates│ └─test
spring.mvc.static-path-pattern=/static/**spring.resources.static-locations=file:/pathto/yourproject/src/main/static/spring.thymeleaf.prefix=file:/pathto/yourproject/src/main/templates/#spring.thymeleaf.cache=false
<link rel="stylesheet" th:href="@{/static/subpath/afile.css}" /><script th:src="@{/static/subpath/afile.js}"></script><img th:src="@{/static/subpath/afile.png}"/>
注:link favicon不知为何不能加static:(
实践中发现,html模板和对应的静态文件(js,css,images等)分开在两处不方便编辑。尝试把他们合并到同一个文件夹下。首先只要修改下面两个配置都指向一个地方(比如webroot):
spring.resources.static-locations=file:/pathto/yourproject/src/main/webroot/spring.thymeleaf.prefix=file:/pathto/yourproject/src/main/webroot/
只是这样会导致html模板也可以被用户直接访问,不太安全。需要调整一下security配置:
- 配置方法configure(WebSecurity webSecurity) :
// 忽略静态资源改为只忽略特定类型的静态资源,目的是不忽略*.html模板//webSecurity.ignoring().antMatchers("/static/**");webSecurity.ignoring().antMatchers("/static/**/*.js");webSecurity.ignoring().antMatchers("/static/**/*.css");webSecurity.ignoring().antMatchers("/static/**/*.jpg");webSecurity.ignoring().antMatchers("/static/**/*.png");
//禁止直接访问html模板httpSecurity.authorizeRequests().antMatchers("/static/**/*.html").denyAll()
参考: https://www.cnblogs.com/hyl8218/p/10754894.html
Spring boot 处理 error 的基本流程:
Controller -> 发生错误 -> BasicErrorController -> 根据 @RequestMapping(produces) 判断调用 errorHtml 或者 error 方法,然后:
errorHtml -> getErrorAttributes -> ErrorViewResolver -> 错误显示页面
error -> getErrorAttributes -> @ResponseBody (直接返回JSON)
spring.resources.chain.strategy.content.enabled=truespring.resources.chain.strategy.content.paths=/**
server.servlet.context-path=/myweb
public static String getWebBasePath() {RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();if (requestAttributes == null) return null;//防止意外HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getResponse();if (request == null) return null;//防止意外return String.format("%s://%s:%s%s/", request.getScheme(), request.getServerName(), request.getServerPort(), request.getContextPath());}
<script th:inline="javascript">var contextPath = /*[[${#request.contextPath}]]*/'';</script>
注:在html模板里使用th:href或th:src时带"@"符号会自动处理contentPath
以配置第三方库路径为例
basepath.lib=https://cdnjs.cloudflare.com/ajax/
@Resourceprivate Environment env; //环境变量@Resourceprivate void configureThymeleafStaticVars(ThymeleafViewResolver viewResolver) {if(viewResolver != null) {Map<String, Object> vars = new HashMap<>();vars.put("libBasePath", env.getProperty("basepath.lib"));//静态库配置viewResolver.setStaticVariables(vars);}}
<script th:src="${libBasePath}+'libs/vue/2.6.10/vue.js'"></script>
<!DOCTYPE html><html lang="zh" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><head th:fragment="head"><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no"/><link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}"><link rel="stylesheet" th:href="${libBasePath}+'libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css'"/><script th:src="${libBasePath}+'libs/vue/2.6.10/vue.js'"></script><link th:href="@{/static/base.css}" rel="stylesheet"/><script th:src="@{/static/base.js}"></script><script th:inline="javascript">var contentPath = /*[[${#request.contextPath}]]*/'';</script></head><body></body><html>
<!DOCTYPE html><html lang="zh" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><head><title>我的页面</title><th:block th:include="common::head"></th:block><link rel="stylesheet" th:href="@{/static/index.css}" /></head><body><script th:inline="javascript">var varForJs = /*[[${varForJs}]]*/{};</script><script th:src="@{/static/index.js}"></script><body></html>
用tab-bar做例子
<!DOCTYPE html><html lang="zh" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><body><th:block th:fragment="tabar"><script type="text/x-template" id="tabar-tpl"><div class="nav nav-tabs"><a class="nav-item nav-link" href="#"v-for="(tabName,tabKey) in tabs" v-show="!!tabName":class="{active: active == tabKey}"@click="onClick(tabKey, tabName)">{{tabName}}</a><slot></slot></div></script><script th:inline="javascript">Vue.component('tabar', {template: '#tabar-tpl',props:{tabs: [Object, Array],active: [String, Number],},data() {return {}},methods: {onClick(tabKey, tabName){this.$emit('click-tab', {key: tabKey, name: tabName})},}});</script></th:block></body></html>
<head><th:block th:include="tabar::tabar"></th:block></head><body><div id="root"><tabar :tabs="tabs" :active="activeTab" @click-tab="activeTab=$event.key"></tabar></div></body><script>new Vue({el: '#root',data: {tabs: {a:'Tab A', b:'Tab B'},activeTab: 'a',},methods: {},});</script>