Tengo asignaciones anotadas que funcionan estupendamente a través de mi aplicación web spring mvc, sin embargo, distinguen entre mayúsculas y minúsculas. No puedo encontrar una manera de hacerlos insensibles a mayúsculas y minúsculas. (Me encantaría hacer que esto suceda dentro de Spring MVC, en lugar de redirigir el tráfico de alguna manera)¿Cómo puedo tener URLs insensibles a mayúsculas y minúsculas en Spring MVC con asignaciones anotadas?
Respuesta
Bueno, no puedo responder a su pregunta (lo intenté, pensé que podría resolverlo). Pero ya que usted no ha recibido ninguna respuesta en 2 días, aquí hay algunas pistas al menos:
Este ejemplo parece sugerir que es posible:
que hace referencia esta clase en la primavera
Mi conjetura (y es sólo eso, una suposición), es que se necesita para expandir <mvc:annotation-driven/>
y poner en práctica los granos individuales con los parámetros correctos para mak Es insensible a mayúsculas y minúsculas. Ver:
http://rapid-web.tumblr.com/post/296916668/what-does-annotation-driven-do
Una última nota, me di cuenta de algún otro lugar de la lectura que dice que todos los caminos por defecto a minúsculas, ¿ha verificado que /MyPath
no es manejado por @RequestMapping("/mypath")
?
Nuevamente, sólo pienso lo mejor que puedo hacer. Tal vez te lleve lo suficientemente lejos como para hacer una pregunta más específica que te lleve a la respuesta: así es como funcionan estas cosas a veces. ¡Buena suerte!
De acuerdo con this webpost necesita agregar un HandlerMapping y un HandlerAdapter en Spring MVC. El mapeo asigna la solicitud a un controlador correspondiente, y el adaptador es responsable de ejecutar la solicitud utilizando el controlador.
Por lo tanto, debe reemplazar el PathMatcher tanto para el asignador como para el adaptador.
Ex (hará que todos @Controllers mayúsculas y minúsculas):
Nueva Matcher:
public class CaseInsenseticePathMatcher extends AntPathMatcher {
@Override
protected boolean doMatch(String pattern, String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
System.err.println(pattern + " -- " + path);
return super.doMatch(pattern.toLowerCase(), path.toLowerCase(), fullMatch, uriTemplateVariables);
}
}
applicationContext.xml:
<bean id="matcher" class="test.CaseInsenseticePathMatcher"/>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="pathMatcher" ref="matcher"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="pathMatcher" ref="matcher"/>
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"/>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"/>
añadido aproximadamente la misma que < mvc:annotation-driven> haría hacer. (Gracias a David Parks para el enlace)
Problema informe para solution by smat
En solution by smat, hay un pequeño efecto secundario (que se lo culpa de primavera-mvc para eso).
Al principio, AntPathMatcher.doMatch()
parece devolver verdadero/falso en función de URL solicitada y la cadena de mapeo de solicitudes del método del controlador (Esto es lo único que se debe hacer aquí).Pero, este método también se usa para un propósito más (¡que no está escrito en documentation!). Otro objetivo es recopilar los valores correspondientes para @PathVariable
en el método del controlador. Estos valores se recopilan en Map<String, String> uriTemplateVariables
(último parámetro). Y estos valores recopilados se utilizan para pasar al método del controlador como valor del parámetro.
Por ejemplo, tenemos controlador-método como este,
@RequestMapping("/code/{userCode}")
public String getCode(@PathVariable("userCode") String userCode) {
System.out.println(userCode);
}
y si accedemos con URL, /code/AbD
luego con solution by smatAntPathMatcher.doMatch()
a recoger @PathVariable
valor en Map<String, String> uriTemplateVariables
como userCode->abd
. Como estamos realizando un encadenamiento inferior de la cadena de ruta, los valores recopilados también tienen una capa inferior. Y este valor de userCode de carcasa inferior se pasa a nuestro controlador.
Pero, estoy agradecido con solution by smat que me ha servido bien hasta ahora sin ningún otro problema.
Solución
resuelto este problema mediante el trabajo en torno solution by smat. Sin cadena de patrón inferior o cadena de patrón en la clase extendida AntPathMatcher
, obligué a mi AntPathMatcher
extendido a usar mi AntPathStringMatcher
personalizado. mi AntPathStringMatcher
personalizado hace la coincidencia case-insesitive sin cambiar el caso de la secuencia real.
En el siguiente código de solución, la mayor parte del código se copia del código de clase original (el código que quería personalizar estaba oculto para la subclase debido al acceso privado).
personalizada AntPathMatcher,
public class CaseInsensitivePathMatcher extends AntPathMatcher {
private final Map<String, CaseInsensitiveAntPathStringMatcher> stringMatcherCache = new ConcurrentHashMap<String, CaseInsensitiveAntPathStringMatcher>();
/**
* Actually match the given <code>path</code> against the given
* <code>pattern</code>.
*
* @param pattern
* the pattern to match against
* @param path
* the path String to test
* @param fullMatch
* whether a full pattern match is required (else a pattern match
* as far as the given base path goes is sufficient)
* @return <code>true</code> if the supplied <code>path</code> matched,
* <code>false</code> if it didn't
*/
protected boolean doMatch(String pattern, String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
if (path.startsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR) != pattern.startsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR)) {
return false;
}
String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, AntPathMatcher.DEFAULT_PATH_SEPARATOR);
String[] pathDirs = StringUtils.tokenizeToStringArray(path, AntPathMatcher.DEFAULT_PATH_SEPARATOR);
int pattIdxStart = 0;
int pattIdxEnd = pattDirs.length - 1;
int pathIdxStart = 0;
int pathIdxEnd = pathDirs.length - 1;
// Match all elements up to the first **
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String patDir = pattDirs[pattIdxStart];
if ("**".equals(patDir)) {
break;
}
if (!matchStrings(patDir, pathDirs[pathIdxStart], uriTemplateVariables)) {
return false;
}
pattIdxStart++;
pathIdxStart++;
}
if (pathIdxStart > pathIdxEnd) {
// Path is exhausted, only match if rest of pattern is * or **'s
if (pattIdxStart > pattIdxEnd) {
return (pattern.endsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR) ? path.endsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR) : !path
.endsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR));
}
if (!fullMatch) {
return true;
}
if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && path.endsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR)) {
return true;
}
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
return true;
} else if (pattIdxStart > pattIdxEnd) {
// String not exhausted, but pattern is. Failure.
return false;
} else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
// Path start definitely matches due to "**" part in pattern.
return true;
}
// up to last '**'
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String patDir = pattDirs[pattIdxEnd];
if (patDir.equals("**")) {
break;
}
if (!matchStrings(patDir, pathDirs[pathIdxEnd], uriTemplateVariables)) {
return false;
}
pattIdxEnd--;
pathIdxEnd--;
}
if (pathIdxStart > pathIdxEnd) {
// String is exhausted
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
return true;
}
while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
int patIdxTmp = -1;
for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
if (pattDirs[i].equals("**")) {
patIdxTmp = i;
break;
}
}
if (patIdxTmp == pattIdxStart + 1) {
// '**/**' situation, so skip one
pattIdxStart++;
continue;
}
// Find the pattern between padIdxStart & padIdxTmp in str between
// strIdxStart & strIdxEnd
int patLength = (patIdxTmp - pattIdxStart - 1);
int strLength = (pathIdxEnd - pathIdxStart + 1);
int foundIdx = -1;
strLoop: for (int i = 0; i <= strLength - patLength; i++) {
for (int j = 0; j < patLength; j++) {
String subPat = pattDirs[pattIdxStart + j + 1];
String subStr = pathDirs[pathIdxStart + i + j];
if (!matchStrings(subPat, subStr, uriTemplateVariables)) {
continue strLoop;
}
}
foundIdx = pathIdxStart + i;
break;
}
if (foundIdx == -1) {
return false;
}
pattIdxStart = patIdxTmp;
pathIdxStart = foundIdx + patLength;
}
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
if (!pattDirs[i].equals("**")) {
return false;
}
}
return true;
}
/**
* Tests whether or not a string matches against a pattern. The pattern may
* contain two special characters:<br>
* '*' means zero or more characters<br>
* '?' means one and only one character
*
* @param pattern
* pattern to match against. Must not be <code>null</code>.
* @param str
* string which must be matched against the pattern. Must not be
* <code>null</code>.
* @return <code>true</code> if the string matches against the pattern, or
* <code>false</code> otherwise.
*/
private boolean matchStrings(String pattern, String str, Map<String, String> uriTemplateVariables) {
CaseInsensitiveAntPathStringMatcher matcher = this.stringMatcherCache.get(pattern);
if (matcher == null) {
matcher = new CaseInsensitiveAntPathStringMatcher(pattern);
this.stringMatcherCache.put(pattern, matcher);
}
return matcher.matchStrings(str, uriTemplateVariables);
}
}
personalizada AntPathStringMatcher,
public class CaseInsensitiveAntPathStringMatcher {
private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?\\}|[^/{}]|\\\\[{}])+?)\\}");
private static final String DEFAULT_VARIABLE_PATTERN = "(.*)";
private final Pattern pattern;
private final List<String> variableNames = new LinkedList<String>();
/** Construct a new instance of the <code>AntPatchStringMatcher</code>. */
CaseInsensitiveAntPathStringMatcher(String pattern) {
this.pattern = createPattern(pattern);
}
private Pattern createPattern(String pattern) {
StringBuilder patternBuilder = new StringBuilder();
Matcher m = GLOB_PATTERN.matcher(pattern);
int end = 0;
while (m.find()) {
patternBuilder.append(quote(pattern, end, m.start()));
String match = m.group();
if ("?".equals(match)) {
patternBuilder.append('.');
}
else if ("*".equals(match)) {
patternBuilder.append(".*");
}
else if (match.startsWith("{") && match.endsWith("}")) {
int colonIdx = match.indexOf(':');
if (colonIdx == -1) {
patternBuilder.append(DEFAULT_VARIABLE_PATTERN);
variableNames.add(m.group(1));
}
else {
String variablePattern = match.substring(colonIdx + 1, match.length() - 1);
patternBuilder.append('(');
patternBuilder.append(variablePattern);
patternBuilder.append(')');
String variableName = match.substring(1, colonIdx);
variableNames.add(variableName);
}
}
end = m.end();
}
patternBuilder.append(quote(pattern, end, pattern.length()));
return Pattern.compile(patternBuilder.toString(), Pattern.CASE_INSENSITIVE); // this line is updated to create case-insensitive pattern object
}
private String quote(String s, int start, int end) {
if (start == end) {
return "";
}
return Pattern.quote(s.substring(start, end));
}
/**
* Main entry point.
*
* @return <code>true</code> if the string matches against the pattern, or <code>false</code> otherwise.
*/
public boolean matchStrings(String str, Map<String, String> uriTemplateVariables) {
Matcher matcher = pattern.matcher(str);
if (matcher.matches()) {
if (uriTemplateVariables != null) {
// SPR-8455
Assert.isTrue(variableNames.size() == matcher.groupCount(),
"The number of capturing groups in the pattern segment " + pattern +
" does not match the number of URI template variables it defines, which can occur if " +
" capturing groups are used in a URI template regex. Use non-capturing groups instead.");
for (int i = 1; i <= matcher.groupCount(); i++) {
String name = this.variableNames.get(i - 1);
String value = matcher.group(i);
uriTemplateVariables.put(name, value);
}
}
return true;
}
else {
return false;
}
}
En primavera 3.2+/Primavera de arranque, ahora se puede configurar caso de coincidencia insensible URL usando la configuración de Java simplificada.
Lo primero que necesita para crear la clase CaseInsensitivePathMatcher.groovy o Java:
import org.springframework.util.AntPathMatcher
class CaseInsensitivePathMatcher extends AntPathMatcher{
@Override
protected boolean doMatch(String pattern, String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
super.doMatch(pattern.toLowerCase(), path.toLowerCase(), fullMatch, uriTemplateVariables)
}
}
A continuación, para que esto suceda, usted debe tener una clase anotada con muelles @Configuration que amplía la clase WebMvcConfigurerAdapter como se muestra a continuación (Tenga en cuenta que mi código está dentro de.clases maravilloso):
@Configuration
public class ApplicationConfig extends WebMvcConfigurerAdapter
a continuación, añadir los 2 siguientes métodos para la clase:
/**
* Creates a patchMatcher bean that matches case insensitively
* @return PathMatcher
*/
@Bean
public PathMatcher pathMatcher() {
new CaseInsensitivePathMatcher()
}
/**
* Overrides the configurePathMatch() method in WebMvcConfigurerAdapter
* <br/>Allows us to set a custom path matcher, used by the MVC for @RequestMapping's
* @param configurer
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.pathMatcher = pathMatcher()
}
}
Eso es todo, ahora debería ser toda la disposición para el caso de URL insensibles con una configuración mínima
Dos años después, pero aún ... 'WebMvcConfigurerAdapter' en Spring 3.2 no tiene el método' configurePathMatch'. La versión mínima de Spring no es correcta, probablemente 4.2 como se indica en las respuestas anteriores. Más información en http://docs.spring.io/spring/docs/3.2.13.RELEASE/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.html – Alf
Spring 4.2 will support case-insensitive path matching. Puede configurarlo de la siguiente manera:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
AntPathMatcher matcher = new AntPathMatcher();
matcher.setCaseSensitive(false);
configurer.setPathMatcher(matcher);
}
}
Ejemplo de un archivo de frijol en la primavera de 4,2 y esto sólo es compatible con v4.2 +:
<mvc:annotation-driven validator="validator">
<mvc:path-matching path-matcher="pathMatcher" />
</mvc:annotation-driven>
...
<!--Set endpoints case insensitive, spring is case-sensitive by default-->
<bean id="pathMatcher" class="org.springframework.util.AntPathMatcher">
<property name="caseSensitive" value="false" />
</bean>
- 1. Urls insensibles a mayúsculas/minúsculas para Django?
- 2. URL insensibles a mayúsculas/minúsculas con mod_rewrite
- 3. Columnas de cadena insensibles a mayúsculas y minúsculas en SQLAlchemy?
- 4. ¿Conversión y sustitución de mayúsculas y minúsculas insensibles a Javascript?
- 5. Comparación de cadenas insensibles a mayúsculas y minúsculas C++
- 6. búsquedas LDAP insensibles a mayúsculas
- 7. Comparación de cadenas insensibles a mayúsculas o minúsculas
- 8. ¿Cómo hacer consultas de filtro insensibles a mayúsculas y minúsculas con Google App Engine?
- 9. make tags insensibles a las mayúsculas y minúsculas con django-taggit
- 10. PHP: parámetros insensibles a las mayúsculas
- 11. Diferencias insensibles a mayúsculas en Mercurial
- 12. Insensible a mayúsculas/minúsculas #define
- 13. ¿Cómo se hace el reemplazo de cadenas insensibles a mayúsculas/minúsculas con expresiones regulares?
- 14. ¿Cómo hacer una insensible a insensibles a mayúsculas y minúsculas y sin acentos en Oracle 10gR2 y JPA?
- 15. ¿Cómo consumir URLs REST usando Spring MVC?
- 16. Buscar coincidencias de palabras insensibles a mayúsculas y minúsculas en una línea
- 17. Convertir a mayúsculas y minúsculas en Java
- 18. Lucene, búsqueda sensible a mayúsculas y minúsculas
- 19. Valor de RequestParam en Spring MVC que no distingue entre mayúsculas y minúsculas
- 20. css mayúsculas y minúsculas
- 21. ¿Cómo puedo buscar mayúsculas y minúsculas en pgrep?
- 22. ordenación de lista insensible a mayúsculas y minúsculas, sin minúsculas?
- 23. insensibilidad a mayúsculas/minúsculas
- 24. Analizador-analizador Scala insensible a las mayúsculas y minúsculas
- 25. ¿Cómo puedo convertir todas las columnas en mi base de datos a mayúsculas y minúsculas
- 26. ¿Cómo puedo detectar mayúsculas y minúsculas en javascript?
- 27. MySQL mayúsculas y minúsculas consulta
- 28. Una lista insensible a mayúsculas y minúsculas
- 29. LINQ contiene insensible a mayúsculas y minúsculas
- 30. Búsqueda insensible a mayúsculas y minúsculas con $ en
También, agregar la etiqueta 'Java' se le dió mucha más páginas vistas que por lo general significa más respuestas. –
pregunta similar con respuesta detallada sobre este problema que he preguntado después de ver esta pregunta. http://stackoverflow.com/questions/12684183/case-insensitive-mapping-for-spring-mvc-requestmapping-annotations/12732550 –