Java 扩展RequestMappingHandlerMapping以注册备用URL模式

Java 扩展RequestMappingHandlerMapping以注册备用URL模式,java,spring,spring-mvc,spring-boot,Java,Spring,Spring Mvc,Spring Boot,我们编写的web应用程序需要双语URL。我们以前使用过“纯Spring/SpringMVC”,但现在已经开始过渡到SpringBoot 在我们较旧的Spring 3.x/4.x应用程序中,我们通过展开大部分“自动配置”来覆盖getMappingPathPatterns以包含URL的翻译版本,从而解决了这个问题。例如: @Override protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {

我们编写的web应用程序需要双语URL。我们以前使用过“纯Spring/SpringMVC”,但现在已经开始过渡到SpringBoot

在我们较旧的Spring 3.x/4.x应用程序中,我们通过展开大部分“自动配置”来覆盖getMappingPathPatterns以包含URL的翻译版本,从而解决了这个问题。例如:

@Override
protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {
    Set<String> unilingualPatterns = super.getMappingPathPatterns(info);
    Set<String> bilingualPatterns = new HashSet<String>();
    for (String pattern : unilingualPatterns) {
        bilingualPatterns.add(pattern);
        // Create the French and English URLs.
        // "resolver" translates the english URL to French.
        final String fraURL = resolver.convertUrl(pattern, Locale.CANADA_FRENCH);

        if (!pattern.equals(fraURL)) {
            bilingualPatterns.add(fraURL);
        }
    }

    return bilingualPatterns;
}
url.home=/home
url.start=/start
<a th:href="@{#{url.home}}">Home</a>
/**
 * DemoController test class.
 *
 * @since 1.0.0
 */
public class DemoControllerTest extends AbstractMockMvcTest {

    @Value("${url.home}")
    private String urlHome;

    /**
     * Test get username.
     *
     * @throws Exception Exception
     */
    @Test
    public void getUsername() throws Exception {
        // Request.
        resultActions = mockMvc.perform(get(urlHome));
        // Verify response.
        resultActions.andExpect(status().isOk());
    }

}
将自动具有“/accueil”的第二个映射。本质上,该方法的注释如下:

@RequestMapping(value = "/home")
public String homeView() {
    return "home";
}
@RequestMapping(value = {"/home", "/accueil"})
public String homeView() {
    return "home";
}
正如我前面提到的,这需要展开大量的“自动配置”,这使得设置更加复杂

我们开始在新项目中使用SpringBoot,我们的目标之一是降低配置的复杂性。我希望找到一种更干净的方式来包含这个功能

我尝试在一个配置类中创建自己的RequestMappingHandlerMappingbean,但没有得到使用。事实上,Spring似乎并不真的希望您无论如何重写这个类

之后,我尝试获取Spring Boot创建的RequestMappingHandlerMapping,遍历handlerMethods列表,并为已翻译的模式RequestCondition添加新的方法,但我从RequestMappingHandlerMapping.getHandlerMethods()返回的映射是不可修改的,因此这也是一条死胡同

我觉得我走错了路。我发现当使用Spring时,如果我的解决方案变得复杂(就像这个),那么我就做错了,我只需要找到“简单的方法”

如果有人知道我如何手动添加新的HandlerMethods(基本上是复制现有的HandlerMethods,但是使用翻译后的URL模式),那就太棒了


提前感谢。

在尝试了许多不同的解决方案后,似乎“最标准”的解决方案是对URL使用单个属性文件。这就是我如何用Spring Boot完成的

首先,我在scr/main/resources下创建了一个名为urls.properties的新属性文件,该文件将包含我的应用程序的URL,例如:

@Override
protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {
    Set<String> unilingualPatterns = super.getMappingPathPatterns(info);
    Set<String> bilingualPatterns = new HashSet<String>();
    for (String pattern : unilingualPatterns) {
        bilingualPatterns.add(pattern);
        // Create the French and English URLs.
        // "resolver" translates the english URL to French.
        final String fraURL = resolver.convertUrl(pattern, Locale.CANADA_FRENCH);

        if (!pattern.equals(fraURL)) {
            bilingualPatterns.add(fraURL);
        }
    }

    return bilingualPatterns;
}
url.home=/home
url.start=/start
<a th:href="@{#{url.home}}">Home</a>
/**
 * DemoController test class.
 *
 * @since 1.0.0
 */
public class DemoControllerTest extends AbstractMockMvcTest {

    @Value("${url.home}")
    private String urlHome;

    /**
     * Test get username.
     *
     * @throws Exception Exception
     */
    @Test
    public void getUsername() throws Exception {
        // Request.
        resultActions = mockMvc.perform(get(urlHome));
        // Verify response.
        resultActions.andExpect(status().isOk());
    }

}
我在我的WebConfig配置文件中添加了一个@PropertySource注释:

/**
 * Web configuration.
 *
 * Since 1.0.0
 */
@Configuration
@PropertySource("classpath:i18n/urls.properties")
public class WebConfig extends WebMvcConfigurerAdapter {

    /**
     * Locale resolver.
     *
     * @return <code>LocaleResolver</code>
     */
    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(Locale.CANADA);
        return localeResolver;
    }

    /**
     * Locale change interceptor.
     *
     * @return <code>LocaleChangeInterceptor</code>
     */
    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
        localeChangeInterceptor.setParamName("lang");
        return localeChangeInterceptor;
    }

    /** {@inheritDoc} */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
        registry.addInterceptor(localeChangeInterceptor());
    }

}
这使我能够访问控制器中的这些属性

/**
 * Demo API controller.
 *
 * @since 1.0.0
 */
@Controller
@RequestMapping("${url.home}")
public class DemoController {

    /**
     * Demo GET method binding.
     *
     * @return <code>String</code>
     */
    @RequestMapping(method = RequestMethod.GET)
    public String getHome() {
        return "home";
    }

}
并确保在我的应用程序.properties文件中将url.properties属性文件列为属性源

spring.messages.basename=messages,urls
这使我能够在my Thymeleaf模板中访问这些URL。例如:

@Override
protected Set<String> getMappingPathPatterns(RequestMappingInfo info) {
    Set<String> unilingualPatterns = super.getMappingPathPatterns(info);
    Set<String> bilingualPatterns = new HashSet<String>();
    for (String pattern : unilingualPatterns) {
        bilingualPatterns.add(pattern);
        // Create the French and English URLs.
        // "resolver" translates the english URL to French.
        final String fraURL = resolver.convertUrl(pattern, Locale.CANADA_FRENCH);

        if (!pattern.equals(fraURL)) {
            bilingualPatterns.add(fraURL);
        }
    }

    return bilingualPatterns;
}
url.home=/home
url.start=/start
<a th:href="@{#{url.home}}">Home</a>
/**
 * DemoController test class.
 *
 * @since 1.0.0
 */
public class DemoControllerTest extends AbstractMockMvcTest {

    @Value("${url.home}")
    private String urlHome;

    /**
     * Test get username.
     *
     * @throws Exception Exception
     */
    @Test
    public void getUsername() throws Exception {
        // Request.
        resultActions = mockMvc.perform(get(urlHome));
        // Verify response.
        resultActions.andExpect(status().isOk());
    }

}
现在,当需要翻译URL时,只需要发送url.properties文件进行翻译。需要注意的是,这仍然只是一个文件(没有_en和_fr变体),因此该文件最终看起来像:

url.home=/home-accueil
url.start=/start-debut
我希望这对其他人有帮助。要想找到使这项工作成功的最佳方法是一件痛苦的事情

如果其他人想出了一个更好的方法来做这件事(不需要太多的破解Spring),请让我知道

谢谢