You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot中使用SSI拆分单页应用的jQueryUI Dialog代码?

解决Spring Boot中提取jQuery UI Dialog到单独文件并实现服务器端包含的问题

嘿,我完全理解你的困扰——嵌入式Tomcat的SSI配置确实有点繁琐,尤其是在Spring Boot的环境下。不过别担心,这里有几个更简便的方案,帮你把那些jQuery UI Dialog的div抽出来单独管理:

方案1:用Thymeleaf模板片段(最推荐)

如果你的项目还没用到模板引擎,Thymeleaf是Spring Boot默认支持的,上手很简单,而且能完美实现服务器端的片段包含:

  1. 添加Thymeleaf依赖(如果还没加):
    在pom.xml里加入:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
  2. 创建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>
    
  3. 在主页面引入片段:
    把原来的静态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的指令:

  1. 创建自定义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();
                }
            };
        }
    }
    
  2. 配置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());
        }
    }
    
  3. 在静态页面中使用自定义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来支持:

  1. 创建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);
            });
        }
    }
    
  2. 在页面中使用Tomcat的SSI指令:

    <!--#include virtual="/dialogs/user-edit-dialog.html"-->
    

    注意:这种方式下,你的静态文件还是放在src/main/resources/public,但Tomcat会在处理.html请求时解析SSI指令。不过这种方案可能会有缓存或者路径的问题,不如前两种灵活。


内容的提问来源于stack exchange,提问作者Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:11:56