扩展RequestMappingHandlerMapping以注册备用URL模式

时间:2016-01-07 19:33:11

标签: java spring spring-mvc spring-boot

我们编写的Web应用程序需要双语网址。我们以前使用过“普通Spring / Spring MVC”,但我们已经开始转换到Spring boot。

在我们较早的Spring 3.x / 4.x应用程序中,我们通过展开大多数“autoconfig”来解决此问题,以覆盖 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;
}

这样,控制器的方法如下:

@RequestMapping(value = "/home")
public String homeView() {
    return "home";
}

会自动拥有“/ accueil”的第二个映射。从本质上讲,就好像这个方法实际上是这样注释的:

@RequestMapping(value = {"/home", "/accueil"})
public String homeView() {
    return "home";
}

正如我上面提到的,这需要解开很多“自动配置”,这使得设置更加复杂。

我们开始将Spring Boot用于新项目,我们的目标之一是降低配置的复杂性。我希望找到一种更简洁的方法来包含这个功能。

我尝试在Configuration类中创建自己的 RequestMappingHandlerMapping bean,但它没有被使用。事实上,无论如何,Spring似乎并不真的希望你覆盖这个类。

之后,我尝试抓住Spring Boot创建的 RequestMappingHandlerMapping ,遍历 handlerMethods 列表,并为已翻译的 PatternsRequestCondition添加新的 handlerMethods ,但是我从 RequestMappingHandlerMapping.getHandlerMethods()返回的地图是不可修改的,所以这也是一个死胡同。

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

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

提前致谢。

1 个答案:

答案 0 :(得分:2)

在尝试了许多不同的解决方案之后,这个解决方案似乎是最标准的&#34;是为URL使用单个属性文件。这就是我使用Spring Boot完成此任务的方法。

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

url.home=/home
url.start=/start

我在我的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";
    }

}

确保 urls.properties 属性文件在我的 application.properties 文件中列为属性源。

spring.messages.basename=messages,urls

这使我可以在Thymeleaf模板中访问这些网址。例如:

<a th:href="@{#{url.home}}">Home</a>

拥有 @PropertySource 注释还可以轻松访问测试用例中的网址,例如:

/**
 * 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());
    }

}

现在,当它需要翻译网址时,只需要发送urls.properties文件进行翻译。重要的是要注意,这仍然只是一个文件(没有_en和_fr变种),所以文件最终看起来像:

url.home=/home-accueil
url.start=/start-debut

我希望这有助于其他人。找出实现这项工作的最佳方法是痛苦的。

如果有其他人提出更好的方法来做到这一点(这并不需要太多的黑客攻击),请告诉我!

感谢。