Spring MVC @PathVariable с точкой (.) Усекается
Это продолжение вопроса Spring MVC @PathVariable становится усеченным
Весенний форум заявляет, что это исправлено (версия 3.2) как часть ContentNegotiationManager. см. ссылку ниже
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632
В моем приложении requestParameter с.com усекается.
Может ли кто-нибудь объяснить мне, как использовать эту новую функцию? как это настраивается в XML?
Примечание: весенний форум - #1 Spring MVC @PathVariable с точкой (.) Усекается
18 ответов
Насколько я знаю, эта проблема возникает только для пути переменной в конце запроса сопоставления.
Мы смогли решить эту проблему, определив дополнение регулярных выражений в отображении запроса.
/somepath/{variable:.+}
Spring считает, что все, что находится за последней точкой, является расширением файла, таким как .json
или же .xml
и поприветствуйте его, чтобы получить ваш параметр.
Так что если у вас есть /somepath/{variable}
:
/somepath/param
,/somepath/param.json
,/somepath/param.xml
или же/somepath/param.anything
приведет к параметру со значениемparam
/somepath/param.value.json
,/somepath/param.value.xml
или же/somepath/param.value.anything
приведет к параметру со значениемparam.value
если вы измените свое отображение на /somepath/{variable:.+}
как предложено, любая точка, включая последнюю, будет рассматриваться как часть вашего параметра:
/somepath/param
приведет к параметру со значениемparam
/somepath/param.json
приведет к параметру со значениемparam.json
/somepath/param.xml
приведет к параметру со значениемparam.xml
/somepath/param.anything
приведет к параметру со значениемparam.anything
/somepath/param.value.json
приведет к параметру со значениемparam.value.json
- ...
Если вы не заботитесь о распознавании расширений, вы можете отключить его, переопределив mvc:annotation-driven
автоматика:
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useSuffixPatternMatch" value="false"/>
</bean>
Итак, еще раз, если у вас есть /somepath/{variable}
:
/somepath/param
,/somepath/param.json
,/somepath/param.xml
или же/somepath/param.anything
приведет к параметру со значениемparam
/somepath/param.value.json
,/somepath/param.value.xml
или же/somepath/param.value.anything
приведет к параметру со значениемparam.value
примечание: отличие от конфигурации по умолчанию видно, только если у вас есть такое отображение somepath/something.{variable}
, см. выпуск проекта Resthub
если вы хотите сохранить управление расширениями, начиная с Spring 3.2, вы также можете установить свойство useRegisteredSuffixPatternMatch компонента Bean RequestMappingHandlerMapping, чтобы сохранить активацию распознавания СуффиксПаттерн, но ограниченную зарегистрированным расширением.
Здесь вы определяете только расширения json и xml:
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false"/>
<property name="favorParameter" value="true"/>
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
Обратите внимание, что mvc:annotation-driven принимает теперь опцию contentNegotiation для предоставления пользовательского компонента, но свойство RequestMappingHandlerMapping должно быть изменено на true (по умолчанию false) (см. https://jira.springsource.org/browse/SPR-7632).
По этой причине вам все равно придется переопределить все настройки mvc: annotation. Я открыл билет в Spring, чтобы попросить пользовательский RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253. Пожалуйста, проголосуйте, если вы заинтересованы в.
При переопределении будьте внимательны, если учесть также переопределение пользовательского управления выполнением. В противном случае все ваши пользовательские сопоставления исключений потерпят неудачу. Вам придется повторно использовать MessageCoverters с bean-компонентом списка:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<util:list id="messageConverters">
<bean class="your.custom.message.converter.IfAny"></bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</util:list>
<bean name="exceptionHandlerExceptionResolver"
class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
<property name="order" value="0"/>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<bean name="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService" />
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>
Я реализовал в проекте с открытым исходным кодом Resthub, частью которого я являюсь, набор тестов по этим предметам: см. https://github.com/resthub/resthub-spring-stack/pull/219/files & https://github.com/resthub/resthub-spring-stack/issues/217
Обновление для Spring 4: начиная с 4.0.1 вы можете использовать PathMatchConfigurer
(через ваш WebMvcConfigurer
), например
@Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
}
В xml это будет ( https://jira.spring.io/browse/SPR-10163):
<mvc:annotation-driven>
[...]
<mvc:path-matching registered-suffixes-only="true"/>
</mvc:annotation-driven>
В дополнение к ответу Мартина Фрея, это также можно исправить, добавив косую черту в значение RequestMapping:
/path/{variable}/
Имейте в виду, что это исправление не поддерживает ремонтопригодность. Теперь требуется, чтобы все URI имели косую черту - что может быть неочевидно для пользователей API / новых разработчиков. Потому что, вероятно, не все параметры могут иметь .
в них это также может создавать периодические ошибки
В Spring Boot Rest Controller я решил эти проблемы следующим образом:
RestController:
@GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(@PathVariable(value = "email") String email){
//code
}
И От Отдыха Клиента:
Get http://mywebhook.com/statusByEmail/abc.test@gmail.com/
Добавление ":.+" работало на меня, но не до тех пор, пока я не удалил внешние фигурные скобки.
значение = {"/username/ndomid:.+}"} не работает
значение = "/username/ enjid:.+}" работает
Надеюсь, я кому-то помог:)
/somepath/{variable:.+}
работает на Java requestMapping
тег.
Вот подход, основанный исключительно на конфигурации Java:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
public class MvcConfig extends WebMvcConfigurationSupport{
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
handlerMapping.setUseTrailingSlashMatch(false);
return handlerMapping;
}
}
Один из довольно простых способов обойти эту проблему - добавить косую черту...
например:
использовать:
/somepath/filename.jpg/
вместо:
/somepath/filename.jpg
В Spring Boot, регулярное выражение решает проблему, как
@GetMapping("/path/{param1:.+}")
Полное решение, включающее адреса электронной почты в именах путей для весны 4.2
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
<mvc:path-matching suffix-pattern="false" registered-suffixes-only="true" />
</mvc:annotation-driven>
Добавьте это в application-xml
Для меня
@GetMapping(path = "/a/{variableName:.+}")
работает, но только если вы также закодировали "точку" в URL-адресе запроса как "% 2E", тогда это работает. Но требует, чтобы все URL были такими... которые не являются "стандартной" кодировкой, хотя и допустимы. Чувствуется что-то вроде ошибки:|
Другой обходной путь, похожий на способ "косой черты", заключается в перемещении переменной, которая будет иметь точку "inline", например:
@GetMapping (path = "/ {variableName} / a")
теперь все точки будут сохранены, без изменений или регулярных выражений.
Если вы используете Spring 3.2.x и <mvc:annotation-driven />
, создай это маленькое BeanPostProcessor
:
package spring;
public final class DoNotTruncateMyUrls implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping)bean).setUseSuffixPatternMatch(false);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Затем поместите это в конфигурационный файл MVC xml:
<bean class="spring.DoNotTruncateMyUrls" />
Наконец я нашел решение в Spring Docs:
Чтобы полностью отключить использование расширений файлов, необходимо установить оба следующих параметра:
useSuffixPatternMatching(false), see PathMatchConfigurer favorPathExtension(false), see ContentNegotiationConfigurer
Добавление этого к моему WebMvcConfigurerAdapter
Внедрение решило проблему:
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
@Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseSuffixPatternMatch(false);
}
Если вы пишете и на обратной стороне, и на внешнем интерфейсе, другое простое решение - добавить "/" в конце URL-адреса впереди. Если это так, вам не нужно менять серверную часть...
somepath/myemail@gmail.com/
Будь счастлив!
Начиная с Spring 5.2.4 (Spring Boot v2.2.6.RELEASE)
PathMatchConfigurer.setUseSuffixPatternMatch
а также ContentNegotiationConfigurer.favorPathExtension
устарели ( https://spring.io/blog/2020/03/24/spring-framework-5-2-5-available-now и https://github.com/spring-projects/spring-framework/issues/24179).
Настоящая проблема заключается в том, что клиент запрашивает определенный тип мультимедиа (например,.com), а Spring по умолчанию добавил все эти типы мультимедиа. В большинстве случаев ваш контроллер REST будет создавать только JSON, поэтому он не будет поддерживать запрошенный выходной формат (.com). Чтобы решить эту проблему, у вас должно быть все в порядке, обновив контроллер отдыха (или конкретный метод) для поддержки формата вывода (@RequestMapping(produces = MediaType.ALL_VALUE
)) и, конечно, разрешить такие символы, как точка ({username:.+}
).
Пример:
@RequestMapping(value = USERNAME, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class UsernameAPI {
private final UsernameService service;
@GetMapping(value = "/{username:.+}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.ALL_VALUE)
public ResponseEntity isUsernameAlreadyInUse(@PathVariable(value = "username") @Valid @Size(max = 255) String username) {
log.debug("Check if username already exists");
if (service.doesUsernameExist(username)) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
return ResponseEntity.notFound().build();
}
}
Spring 5.3 и выше будут соответствовать только зарегистрированным суффиксам (типам носителей).
Простое решение: добавление регулярного выражения {q:.+} в @RequestMapping
@RequestMapping("medici/james/Site")
public class WebSiteController {
@RequestMapping(value = "/{site:.+}", method = RequestMethod.GET)
public ModelAndView display(@PathVariable("site") String site) {
return getModelAndView(site, "web site");
}
}
Теперь для ввода /site/jamesmedice.com «сайт» будет отображать правильный сайт Джеймса.
Если вы используете Spring 3.2+, вам поможет решение, приведенное ниже. Это будет обрабатывать все URL-адреса, что определенно лучше, чем применение шаблона регулярного выражения в сопоставлении URI запроса, чтобы разрешить. нравиться
/somepath/{variable:.+}
Определите bean-компонент в XML-файле
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useSuffixPatternMatch" value="false"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
Использование флагов можно найти в документации. Я ставлю отрывок, чтобы объяснить
Утверждается, что использование useRegisteredSuffixPatternMatch решает проблему. Из java-документа в классе
Если этот параметр включен, метод контроллера, сопоставленный с "/ users", также соответствует "/users.json", если ".json" является расширением файла, зарегистрированным с помощью предоставленного {@link #setContentNegotiationManager(ContentNegotiationManager)contentNegotiationManager}. Это может быть полезно для разрешения использования только определенных расширений URL, а также в случаях, когда "." в URL-пути может привести к неоднозначной интерпретации содержимого переменной пути (например, данные "/users/ {user}" и входящие URL-адреса, такие как "/users/john.j.joe" и "/users/john.j.joe".json").