@TedZhou
2020-10-15T11:26:55.000000Z
字数 5148
阅读 1404
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=true
spring.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/
@Resource
private Environment env; //环境变量
@Resource
private 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>