如何在Spring Boot中使用SSI拆分单页应用的jQueryUI Dialog代码?
嘿,我完全理解你的困扰——嵌入式Tomcat的SSI配置确实有点繁琐,尤其是在Spring Boot的环境下。不过别担心,这里有几个更简便的方案,帮你把那些jQuery UI Dialog的div抽出来单独管理:
方案1:用Thymeleaf模板片段(最推荐)
如果你的项目还没用到模板引擎,Thymeleaf是Spring Boot默认支持的,上手很简单,而且能完美实现服务器端的片段包含:
添加Thymeleaf依赖(如果还没加):
在pom.xml里加入:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>创建Dialog片段文件:
在src/main/resources/templates/fragments/dialogs目录下新建你的Dialog文件,比如user-edit-dialog.html,内容就是单独的Dialog div:<div id="userEditDialog" title="编辑用户" class="ui-dialog-content"> <!-- 你的Dialog内容 --> <form> <label>用户名:<input type="text" name="username"></label> </form> </div>在主页面引入片段:
把原来的静态html文件移到src/main/resources/templates下(因为Thymeleaf默认从这里加载),然后在需要引入Dialog的地方用Thymeleaf的th:insert指令:<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <!-- 你的CSS、JS引用 --> </head> <body> <!-- 主页面内容 --> <button id="openEditDialog">打开编辑对话框</button> <!-- 引入Dialog片段 --> <div th:insert="~{fragments/dialogs/user-edit-dialog :: #userEditDialog}"></div> <script> // 初始化jQuery UI Dialog $(function() { $("#userEditDialog").dialog({autoOpen: false}); $("#openEditDialog").on("click", function() { $("#userEditDialog").dialog("open"); }); }); </script> </body> </html>
方案2:用Spring MVC自定义资源转换器(不换模板引擎)
如果不想改成模板页面,只想用原来的静态html,可以自定义一个资源转换器来解析SSI-like的指令:
创建自定义ResourceTransformer:
import org.springframework.core.io.Resource; import org.springframework.web.servlet.resource.ResourceTransformer; import org.springframework.web.servlet.resource.ResourceTransformerChain; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.regex.Matcher; import java.util.regex.Pattern; public class SsiResourceTransformer implements ResourceTransformer { private static final Pattern SSI_INCLUDE_PATTERN = Pattern.compile("<!--#include file=\"(.*?)\"-->"); @Override public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain chain) throws IOException { String content = new BufferedReader( new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) .lines() .reduce("", String::concat); Matcher matcher = SSI_INCLUDE_PATTERN.matcher(content); StringBuilder sb = new StringBuilder(); while (matcher.find()) { String includePath = matcher.group(1); Resource includedResource = resource.createRelative(includePath); if (includedResource.exists()) { String includedContent = new BufferedReader( new InputStreamReader(includedResource.getInputStream(), StandardCharsets.UTF_8)) .lines() .reduce("", String::concat); matcher.appendReplacement(sb, includedContent); } else { matcher.appendReplacement(sb, "<!-- 无法找到包含文件:" + includePath + " -->"); } } matcher.appendTail(sb); // 返回修改后的资源 return new ByteArrayResource(sb.toString().getBytes(StandardCharsets.UTF_8)) { @Override public String getFilename() { return resource.getFilename(); } }; } }配置WebMvcConfigurer:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**") .addResourceLocations("classpath:/public/") .resourceChain(true) .addTransformer(new SsiResourceTransformer()); } }在静态页面中使用自定义include指令:
在src/main/resources/public/index.html里这样写:<!-- 主页面内容 --> <button id="openEditDialog">打开编辑对话框</button> <!-- 引入Dialog文件 --> <!--#include file="dialogs/user-edit-dialog.html"-->然后把Dialog文件放在
src/main/resources/public/dialogs/user-edit-dialog.html即可。
方案3:配置嵌入式Tomcat启用SSI(如果坚持用原生SSI)
如果你一定要用Tomcat的原生SSI,也可以配置嵌入式Tomcat来支持:
创建Tomcat自定义配置类:
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Configuration; import org.apache.catalina.Context; import org.apache.catalina.ssi.SSIServlet; @Configuration public class TomcatSsiConfig implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { factory.addContextCustomizers((Context context) -> { // 注册SSI Servlet context.addServlet("ssi", new SSIServlet()).addMapping("*.html"); // 启用SSI,允许所有指令 context.setAllowSsi(true); context.setSsiEnabled(true); }); } }在页面中使用Tomcat的SSI指令:
<!--#include virtual="/dialogs/user-edit-dialog.html"-->注意:这种方式下,你的静态文件还是放在
src/main/resources/public,但Tomcat会在处理.html请求时解析SSI指令。不过这种方案可能会有缓存或者路径的问题,不如前两种灵活。
内容的提问来源于stack exchange,提问作者Thomas

