Java 扩展RequestMappingHandlerMapping以注册备用URL模式
我们编写的web应用程序需要双语URL。我们以前使用过“纯Spring/SpringMVC”,但现在已经开始过渡到SpringBoot 在我们较旧的Spring 3.x/4.x应用程序中,我们通过展开大部分“自动配置”来覆盖getMappingPathPatterns以包含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) {
@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),请让我知道
谢谢