2010-11-10 3 views
22

haben Ich habe Mappings kommentiert gut funktioniert durch meine Frühjahr mvc Web-App, aber sie sind Groß-und Kleinschreibung. Ich finde keinen Weg, um sie von der Groß-/Kleinschreibung abzuhalten. (Ich würde gerne diese eher in Spring MVC, passieren als Verkehr umleiten irgendwie)Wie kann ich Groß-und Kleinschreibung URLs in Spring MVC mit annotierten Zuordnungen

+0

Fügen Sie außerdem den Tag ‚Java‘ es wird Ihnen viel mehr Seitenaufrufe ergeben, die in der Regel mehr Antworten bedeutet. –

+0

ähnliche Frage mit detaillierter Antwort zu diesem Problem habe ich nach dem Sehen dieser Frage gefragt. http://stackoverflow.com/questions/12684183/case-insensitive-mapping-for-spring-mvc-requestmapping-annotations/12732550 –

Antwort

0

Nun, ich kann Ihre Frage nicht beantworten (Ich habe versucht, ich dachte, dass ich es heraus könnte out). Aber da Sie alle Antworten in 2 Tagen nicht erhalten haben, sind hier einige Leitungen mindestens:

Dieses Beispiel scheint darauf hinzudeuten, es ist möglich:

http://webcache.googleusercontent.com/search?q=cache:ELj-ZQ8G4z0J:www.springbyexample.org/examples/sdms-simple-spring-mvc-web-module.html+case+insensitive+requestmapping+spring&cd=3&hl=en&ct=clnk&client=firefox-a

Es verweist auf diese Klasse im Frühjahr

http://static.springsource.org/spring/docs/3.0.4.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/support/ControllerClassNameHandlerMapping.html

Meine Vermutung (und es ist nur, dass eine Vermutung), ist, dass Sie <mvc:annotation-driven/> und Umsetzung der einzelnen Bohnen mit den richtigen Parametern erweitern müssen mak e es case-insensitive. Siehe:

http://rapid-web.tumblr.com/post/296916668/what-does-annotation-driven-do

Ein letzter Hinweis, bemerkte ich woanders in der Lektüre, dass es, dass alle Pfade Standardfall zu senken, haben Sie festgestellt, dass /MyPath nicht von @RequestMapping("/mypath") behandelt wird?

Noch einmal, nur zum Nachdenken, so gut ich kann. Vielleicht bringt es Sie weit genug, um eine spezifischere Frage zu stellen, die Sie zur Antwort führt - so funktionieren diese Dinge manchmal. Viel Glück!

12

Nach this webpost müssen Sie sowohl eine HandlerMapping als auch eine HandlerAdapter in Spring MVC hinzufügen. Das Mapping ordnet die Anforderung einem entsprechenden Controller zu, und der Adapter ist dafür verantwortlich, die Anforderung mithilfe des Controllers auszuführen.

Sie müssen daher die PathMatcher für den Mapper und Adapter beide außer Kraft zu setzen.

Ex (alle @Controllers Groß- und Kleinschreibung machen):

New 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"/> 

hinzugefügt etwa gleich, dass < mvc:annotation-driven> würde machen. (Danke an David Parks für den Link)

+0

Arbeitete für mich .. danke! – Rahul

+3

Ersetzen Sie für Spring 3.1 AnnotationMethodHandlerAdapter mit RequestMappingHandlerAdapter. Sie verwenden diese neue Klasse in 3.1. – smat

1

Problem Bericht für solution by smat


In solution by smat gibt es einen kleinen Nebeneffekt (ich würde feder mvc die Schuld geben).

Zuerst scheint AntPathMatcher.doMatch() wahr/falsch zurückzugeben, abhängig von der Anforderungszuordnungszeichenfolge der angeforderten URL und Controller-Methode (das ist das einzige, was hier getan werden sollte).Aber diese Methode wird auch für einen anderen Zweck verwendet (der nicht in documentation geschrieben wird!). Ein weiterer Zweck besteht darin, entsprechende Werte für @PathVariable in der Controller-Methode zu sammeln. Diese Werte werden in Map<String, String> uriTemplateVariables (letzter Parameter) gesammelt. Diese gesammelten Werte werden verwendet, um als Parameterwert an die Controller-Methode zu übergeben.

Zum Beispiel haben wir Controller-Methode wie folgt,

@RequestMapping("/code/{userCode}") 
public String getCode(@PathVariable("userCode") String userCode) { 
    System.out.println(userCode); 
} 

und wenn wir mit URL zugreifen, /code/AbD dann mit solution by smatAntPathMatcher.doMatch() wird @PathVariable Wert in Map<String, String> uriTemplateVariables als userCode->abd sammeln. Da wir die Pfadzeichenfolge untergeordnet haben, sind die gesammelten Werte auch kleiner. Und dieser tiefer gelegte userCode-Wert wird an unseren Controller übergeben.

Aber ich bin dankbar solution by smat, die mir bisher ohne weitere Probleme gut gedient hat.


Lösung


dieses Problem gelöst, indem Arbeit um solution by smat tun. Ohne den Pfad des unteren Gehäuses oder die Musterzeichenfolge in der erweiterten Klasse AntPathMatcher habe ich meine erweiterte AntPathMatcher gezwungen, meine benutzerdefinierte AntPathStringMatcher zu verwenden. Meine benutzerdefinierte AntPathStringMatcher tut Case-Insitive-Matching, ohne den Fall der tatsächlichen Zeichenfolge zu ändern.

Im folgenden Lösungscode wird der Großteil des Codes aus dem ursprünglichen Klassencode kopiert (Code, den ich anpassen wollte, wurde wegen des privaten Zugriffs für die Unterklasse ausgeblendet).

Individuelle 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); 
} 

}

Individuelle 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; 
    } 
} 
0

Im Frühjahr 3.2+/Frühjahr-Boot können Sie jetzt Groß- und Kleinschreibung URL-Zuordnung einrichten Verwenden der vereinfachten Java-Konfiguration.

Zuerst müssen Sie die CaseInsensitivePathMatcher.groovy oder Java-Klasse erstellen:

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) 
    } 
} 

Als nächstes, damit dies geschieht, Sie eine Klasse haben sollte, mit Federn @Configuration kommentierten, die die WebMvcConfigurerAdapter-Klasse erweitert, wie unten dargestellt (Beachten Sie, dass mein Code darin enthalten ist.groovy Klassen):

@Configuration 
public class ApplicationConfig extends WebMvcConfigurerAdapter 

dann die folgenden zwei Methoden zur Klasse hinzufügen:

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


, dass es, sollten Sie jetzt mit minimaler Konfiguration

+0

Zwei Jahre später, aber immer noch ... 'WebMvcConfigurerAdapter' in Frühling 3.2 hat nicht die Methode' configurePathMatch'. Die minimale Spring-Version ist nicht korrekt, wahrscheinlich 4,2 wie in den Antworten oben angegeben. Weitere Informationen über http://docs.spring.io/spring/docs/3.2.13.RELEASE/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.html – Alf

12

die alle Setup für Groß- und Kleinschreibung URL sein Spring 4.2 will support case-insensitive path matching. Sie können es wie folgt konfigurieren:

@Configuration 
public class WebConfig extends WebMvcConfigurerAdapter { 
    @Override 
    public void configurePathMatch(PathMatchConfigurer configurer) { 
     AntPathMatcher matcher = new AntPathMatcher(); 
     matcher.setCaseSensitive(false); 
     configurer.setPathMatcher(matcher); 
    } 
} 
+0

Kennen Sie solche? Konfigurationen für Abfrageparameter? – M22an

+0

@ M22an Sorry, ich weiß es nicht. Ich denke, dass Sie die Funktion unter https://jira.spring.io anfordern können – npcode

1

Beispiel aus einer Bean-Datei in Spring 4.2 und dies wird nur dann unterstützt 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> 
Verwandte Themen