Spring Boot Sping Boot 中的多个servletMap

kd3sttzy  于 2023-01-17  发布在  Spring
关注(0)|答案(6)|浏览(187)

有没有办法通过属性"context-path"为同一个Spring Boot MVC应用程序设置许多Map?我的目标是避免为URIMap创建许多"Dispatcherservlet"。
例如:

servlet.context-path =/, /context1, context2
csga3l58

csga3l581#

您可以创建@Bean注解方法返回ServletRegistrationBean,并在那里添加多个Map,这是更好的方式,因为Sping Boot 鼓励Java配置而不是配置文件:

@Bean
    public ServletRegistrationBean myServletRegistration()
    {
        String urlMapping1 = "/mySuperApp/service1/*";
        String urlMapping2 = "/mySuperApp/service2/*";
        ServletRegistrationBean registration = new ServletRegistrationBean(new MyBeautifulServlet(), urlMapping1, urlMapping2);

        //registration.set... other properties may be here
        return registration;
    }

在应用程序启动时,您将能够在日志中看到:

INFO  | localhost | org.springframework.boot.web.servlet.ServletRegistrationBean | Mapping servlet: 'MyBeautifulServlet' to [/mySuperApp/service1/*, /mySuperApp/service2/*]
2admgd59

2admgd592#

您只需要一个Dispatcherservlet,其根上下文路径设置为您想要的路径(可以是/mySuperApp)。
通过声明多个@RequestMaping,您将能够用同一个DispatcherServlet提供不同的URI。
以下是一个示例。将DispatcherServlet设置为/mySuperApp,其中@RequestMapping("/service1")@RequestMapping("/service2")将公开以下端点:
/mySuperApp/service1
/mySuperApp/service2
为一个servlet提供多个上下文不是Servlet规范的一部分。一个servlet不能从多个上下文提供服务。
您可以做的是将多个值Map到您请求的Map。
@请求Map({"/上下文1/服务1}",{"/上下文2/服务1}”)
我看没有别的办法了。

2w3kk1z5

2w3kk1z53#

您可以使用'server.contextPath'属性占位符来设置整个spring Boot 应用程序的上下文路径。(例如server.contextPath=/live/path1
此外,您还可以设置将应用于所有方法的类级上下文路径,例如:

@RestController
@RequestMapping(value = "/testResource", produces = MediaType.APPLICATION_JSON_VALUE)
public class TestResource{

@RequestMapping(method = RequestMethod.POST, value="/test", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<TestDto> save(@RequestBody TestDto testDto) {
...

有了这个结构,就可以使用/live/path1/testResource/test来执行save方法。

8zzbczxx

8zzbczxx4#

这类问题的答案似乎都没有提到,您通常可以通过在应用程序前面配置反向代理(例如nginx/apache httpd)来重写请求来解决这个问题。
但是,如果您必须在应用程序中执行此操作,则此方法有效(至少使用Spring Boot 2.6.2):https://www.broadleafcommerce.com/blog/configuring-a-dynamic-context-path-in-spring-boot.
它描述了创建一个过滤器,把它放在过滤器链的早期,基本上重写URL(就像反向代理可能做的那样),以便所有请求都到达同一个地方(即实际的servlet.context-path)。

oxiaedzo

oxiaedzo5#

我发现了一种替代https://www.broadleafcommerce.com/blog/configuring-a-dynamic-context-path-in-spring-boot中描述的过滤器的方法,它需要的代码更少。
这将使用RewriteValve(https://tomcat.apache.org/tomcat-9.0-doc/rewrite.html)重写上下文路径之外的url,例如,如果真实的上下文路径是“context 1”,则它会将/context 2/* Map到/context 1/*

@Component
public class LegacyUrlWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    private static final List<String> LEGACY_PATHS = List.of("context2", "context3");

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        RewriteValve rewrite = new RewriteValve() {
            @Override
            protected void initInternal() throws LifecycleException {
                super.initInternal();
                try {
                    String config = LEGACY_PATHS.stream() //
                            .map(p -> String.format("RewriteRule ^/%s(/.*)$ %s$1", p, factory.getContextPath())) //
                            .collect(Collectors.joining("\n"));
                    setConfiguration(config);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        factory.addEngineValves(rewrite);
    }
}

如果你需要使用HTTP重定向,那么需要做更多的工作(以避免sendRedirect中出现NullPointerException):

@Component
public class LegacyUrlWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    private static final List<String> LEGACY_PATHS = List.of("context2", "context3");

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        RewriteValve rewrite = new RewriteValve() {
            @Override
            protected void initInternal() throws LifecycleException {
                super.initInternal();
                try {
                    String config = LEGACY_PATHS.stream() //
                            .map(p -> String.format("RewriteRule ^/%s(/.*)$ %s$1 R=permanent", p, factory.getContextPath())) //
                            .collect(Collectors.joining("\n"));
                    setConfiguration(config);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void invoke(Request request, Response response) throws IOException, ServletException {
                if (request.getContext() == null) {
                    String[] s = request.getRequestURI().split("/");
                    if (s.length > 1 && LEGACY_PATHS.contains(s[1])) {
                        request.getMappingData().context = new FailedContext();
                    }
                }
                super.invoke(request, response);
            }

        };
        factory.addEngineValves(rewrite);
    }
}
bsxbgnwa

bsxbgnwa6#

我使用这种方法:

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

@Configuration
public class WebAppInitializer implements WebApplicationInitializer {
  @Override
  public void onStartup(ServletContext servletContext) {
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(AppConfig.class);
    rootContext.setServletContext(servletContext);

    ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(rootContext));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/mapping1/*");
    dispatcher.addMapping("/mapping2/*");

    servletContext.addListener(new ContextLoaderListener(rootContext));
  }
}

相关问题