站點搭建完成後,編寫頁面時通常會有以下幾個需求javascript
一、嵌套靜態頁面時有很大一部分通用代碼,如css、js這部分能夠使用thymeleaf的局部片斷代碼塊組成css
二、這些靜態資源默認放在程序中,但後期可能會爲了節省服務器系統資源作動靜分離,或架在CDN上,因此須要有獨立的靜態資源站點設計,目前我是單獨搭建了nginx作靜態資源站html
三、編寫Controller時有一部分的公用代碼能夠提出BaseController基類來提供,簡化子類代碼,統一代碼規範java
根據這幾個需求,設計以下解決方案jquery
先看一下個人項目結構,靜態資源站存放純公用的資源,各站點又提供了各自的私有資源存放nginx
一、首先須要動態配置靜態資源站URL,因此咱們使用Enum來實現web
SysConfigEnum枚舉類,其中http://localhost:8800是我搭建nginx作靜態服務器地址,咱們站點多了一點,你們能夠簡化spring
/** * 程序枚舉 */ public interface SysConfigEnum { /** * 動態站點地址 */ enum SiteUrl { AdminBase(""), AgentBase(""), AdminFlight(""), AgentFlight(""), AdminHotel(""), AgentHotel(""), private String url; SiteUrl(String value) { this.url = value; } public String getUrl() { return this.url; } } /** * 靜態資源地址 */ enum StaticUrl { Common("http://localhost:8800/content/", "20180801"), PlatformAdmin("http://localhost:8800/content/admin/content/", "20180801"), PlatformAgent("http://localhost:8800/content/agent/content/", "20180801"), ProductBaseAdmin("/admin/content/", "20180801"), ProductBaseAgent("/agent/content/", "20180801"), ProductFlightAdmin("/admin/content/", "20180801"), ProductFlightAgent("/agent/content/", "20180801"), ProductHotelAdmin("/admin/content/", "20180801"), ProductHotelAgent("/agent/content/", "20180801"); private String url; private String ver; StaticUrl(String url, String ver) { this.url = url; this.ver = ver; } public String getUrl() { return this.url; } public String getVer() { return "?v=" + this.ver; } } }
二、有一個Model實體來標明當前站點的靜態資源Url和Verbootstrap
StaticModel實體裏面標明瞭Common全局通用靜態資源,Platform平臺通用靜態資源,Product產品站點內部靜態資源安全
get、set方法作了一點修改,因爲屬性類型是枚舉,set直接設置,get時拆分開,便於作擴展
/** * 靜態資源實體 */ public class StaticModel { private SysConfigEnum.StaticUrl common; private SysConfigEnum.StaticUrl platform; private SysConfigEnum.StaticUrl product; public void setCommon(SysConfigEnum.StaticUrl common) { this.common = common; } public void setPlatform(SysConfigEnum.StaticUrl platform) { this.platform = platform; } public void setProduct(SysConfigEnum.StaticUrl product) { this.product = product; } public String getCommonUrl() { return this.common.getUrl(); } public String getCommonVer() { return this.common.getVer(); } public String getPlatformUrl() { return this.platform.getUrl(); } public String getPlatformVer() { return this.platform.getVer(); } public String getProductUrl() { return this.product.getUrl(); } public String getProductVer() { return this.product.getVer(); } }
三、靜態資源的信息準備好後咱們要把它寫在每一個頁面上,action到page由model來傳遞,那咱們就要在每個action時都設置一下這個model,那咱們新建一個BaseController基類來實現
Model、ModelMap、Map<>都是同一個BindingAwareModelMap實例,因此我是用了Model,你們也能夠各自更換
在基類中提供request、response、model來給子類使用,簡化子類單獨注入的操做,@ModelAttribute註解的方法,會在每個action執行以前執行【多個ModelAttribute之間沒有執行順序是亂序的】
import com.ysl.ts.common.StaticModel; import com.ysl.ts.common.SysConfigEnum; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Controller基類Admin * @author TaiYongHai */ public class BaseController { //request是線程安全的,能夠自動注入 @Autowired private HttpServletRequest request; //response是非線程安全的,使用本地線程控制 private ThreadLocal<HttpServletResponse> response = new ThreadLocal<>(); //model是非線程安全的,使用本地線程控制 private ThreadLocal<Model> model = new ThreadLocal<>(); /* HttpServletRequest req HttpServletResponse res Model m action方法中的這些參數Servlet會自動幫你填充 */ /** * 獲取Request * @return */ protected final HttpServletRequest getRequest() { return this.request; } /** * 注入Response * @param res */ @ModelAttribute private void setResponse(HttpServletResponse res) { this.response.set(res); } /** * 獲取Response * @return */ protected final HttpServletResponse getResponse() { return response.get(); } /** * 注入Model * @param m */ @ModelAttribute private void setModel(Model m) { this.model.set(m); } /** * 獲取Model * (Model、ModelMap、Map<>將使用BindingAwareModelMap做爲模型對象的實現, * 都是同一個BindingAwareModelMap實例,因此都共享同一份數據) * @return */ protected final Model getModel() { return model.get(); } //@ModelAttribute註解的方法,會在每個action執行以前執行【多個ModelAttribute之間沒有執行順序是亂序的】 //設置靜態資源參數 @ModelAttribute private void setStaticParams(Model m) { StaticModel staticModel = new StaticModel(); staticModel.setCommon(SysConfigEnum.StaticUrl.Common); staticModel.setPlatform(SysConfigEnum.StaticUrl.PlatformAdmin); staticModel.setProduct(SysConfigEnum.StaticUrl.ProductBaseAdmin); //存入Model中 m.addAttribute("yslTsStatic", staticModel); } }
四、子類繼承BaseController能夠直接使用提供的model等對象
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Controller @RequestMapping("/admin/home") @Component("AdminHome") public class HomeController extends BaseController { @RequestMapping("/index") public String index() { //直接使用基類提供的對象 HttpServletRequest request = super.getRequest(); HttpServletResponse response = super.getResponse(); Model model = super.getModel(); return "/admin/home/index"; } }
五、後臺完成了,前臺渲染頁面時的公用部分使用 th:fragment 佈局代碼塊來實現
<html xmlns:th="http://www.thymeleaf.org"> <!-- header 放在<head>標籤內,並在其下方寫css --> <div th:fragment="header" th:remove="tag"> <div th:replace="~{/admin/layout/fragments :: metaLib}"></div> <div th:replace="~{/admin/layout/fragments :: cssLib}"></div> <div th:replace="~{/admin/layout/fragments :: cssAssist}"></div> </div> <!-- footer 放在<body>標籤內,並在其下方寫js --> <div th:fragment="footer" th:remove="tag"> <div th:replace="~{/admin/layout/fragments :: jsLib}"></div> <div th:replace="~{/admin/layout/fragments :: jsAssist}"></div> </div> <!-- 引入變量包 --> <!--/*@thymesVar id="yslTsStatic" type="com.ysl.ts.common.StaticModel"*/--> <!-- meta信息 --> <div th:fragment="metaLib" th:remove="tag"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="renderer" content="webkit"/> <meta name="Author" content="EB.Group"/> </div> <!-- 引入css --> <div th:fragment="cssLib" th:remove="tag"> <link rel="icon" th:href="@{${yslTsStatic.getCommonUrl()}+'img/favicon.ico'+${yslTsStatic.getCommonVer()}}" type="image/x-icon"/> <link rel="stylesheet" th:href="@{${yslTsStatic.getCommonUrl()}+'css/bootstrap.min.css'+${yslTsStatic.getCommonVer()}}"/> </div> <!-- 全局css --> <div th:fragment="cssAssist" th:remove="tag"> <style> body { overflow: hidden; } </style> </div> <!-- 引入js --> <div th:fragment="jsLib" th:remove="tag"> <script type="text/javascript" th:src="@{${yslTsStatic.getCommonUrl()}+'js/jquery-1.9.1.min.js'+${yslTsStatic.getCommonVer()}}"></script> <script type="text/javascript" th:src="@{${yslTsStatic.getPlatformUrl()}+'js/ysl-ts-common.js'+${yslTsStatic.getPlatformVer()}}"></script> </div> <!-- 全局js --> <div th:fragment="jsAssist" th:remove="tag"> <script type="text/javascript"> console.log("jsAssist"); </script> </div> </html>
六、其餘頁面引入佈局頁的代碼塊
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>管理後臺</title> <div th:replace="~{/admin/layout/fragments :: header}"></div> <!-- 從這裏如下寫頁面獨立的css --> </head> <body> <h1>歡迎</h1> <div th:replace="~{/admin/layout/fragments :: footer}"></div> <!-- 每一個頁面能夠引入本身獨有的js --> <script type="text/javascript" th:src="@{${yslTsStatic.getProductUrl()}+'js/test.js'+${yslTsStatic.getProductVer()}}"></script> <!-- 從這裏如下寫頁面獨立的js --> <script type="text/javascript"> console.log("page js"); </script> </body> </html>
好,到此這個解決方案就完成了,若有什麼不足還望指點