Spring - Усечение переменной пути после точки - аннотация

Я пытаюсь настроить конечную точку REST, которая позволяет запрашивать пользователя по их адресу электронной почты. Адрес электронной почты является последней частью пути, поэтому Spring обрабатывает [email protected] как значение [email protected] и усекает расширение .com.

Я нашел аналогичный вопрос здесь Spring MVC @PathVariable с точкой (.) усекается Однако у меня есть конфигурация, основанная на аннотации, с использованием AbstractAnnotationConfigDispatcherServletInitializer и WebMvcConfigurerAdapter. Поскольку у меня нет xml-конфигурации, это решение не будет работать для меня:

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="useDefaultSuffixPattern" value="false" />
</bean>

Я также пробовал это решение, которое использует регулярное выражение, но оно не сработало.

@RequestMapping(value = "user/by-email/{email:.+}")

Кто-нибудь знает, как отключить усечение шаблона суффикса без xml?

Ответ 1

Точка в переменной пути в конце URI вызывает два неожиданных поведения (неожиданно для большинства пользователей, кроме тех, которые знакомы с огромным количеством свойств конфигурации Spring).

Первая (которая может быть исправлена ​​с использованием регулярного выражения {email:.+}) заключается в том, что конфигурация по умолчанию Spring соответствует всем расширениям пути. Поэтому настройка отображения для /api/{file} будет означать, что Spring сопоставляет вызов /api/myfile.html аргументу String myfile. Это полезно, если вы хотите, чтобы /api/myfile.html, /api/myfile.md, /api/myfile.txt и другие указывали на один и тот же ресурс. Однако мы можем отключить это поведение во всем мире, не прибегая к хакерству регулярных выражений на каждой конечной точке.

Вторая проблема связана с первым и правильно зафиксирована @masstroy. Когда /api/myfile.* указывает на ресурс myfile, Spring предполагает, что расширение пути (.html, .txt и т.д.) Указывает, что ресурс должен быть возвращен с определенным форматом. Такое поведение также может быть очень полезно в некоторых ситуациях. Но часто это будет означать, что объект, возвращенный сопоставлением метода, не может быть преобразован в этот формат, а Spring выдаст HttpMediaTypeNotAcceptableException.

Мы можем отключить их с помощью следующего (предполагая Spring Boot):

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

  @Override
  public void configurePathMatch(PathMatchConfigurer configurer) {
    // turn off all suffix pattern matching
    configurer.setUseSuffixPatternMatch(false);
    // OR
    // turn on suffix pattern matching ONLY for suffixes
    // you explicitly register using
    // configureContentNegotiation(...)
    configurer.setUseRegisteredSuffixPatternMatch(true);
  }

  @Override
  public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(false);
  }
}

Подробнее о Консолидация контента.

Ответ 3

Я нашел решение для этого, используя ContentNegotiationConfigurer bean из этой статьи: http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc

Я добавил следующую конфигурацию в свой класс WebConfig:

@EnableWebMvc
@Configuration
@ComponentScan(basePackageClasses = { RestAPIConfig.class })
public class WebConfig extends WebMvcConfigurerAdapter {    
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false);
        configurer.defaultContentType(MediaType.APPLICATION_JSON);
    }
}

Установив .favorPathExtension(false), Spring больше не будет использовать расширение файла для переопределения accepts mediaType запроса. Javadoc для этого метода читает Indicate whether the extension of the request path should be used to determine the requested media type with the highest priority.

Затем я настроил свое @RequestMapping с помощью регулярного выражения

@RequestMapping(value = "/user/by-email/{email:.+}")

Ответ 4

Для пользователей Java-Config:

С помощью Spring 4 вы можете просто отключить эту функцию:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

  @Override
  public void configurePathMatch(PathMatchConfigurer configurer) {
    configurer.setUseSuffixPatternMatch(false);
  }

}

Затем во всей области приложения точки будут считаться точками.