Wie kann ich URLs ohne Berücksichtigung der Groß-/Kleinschreibung in Spring MVC mit kommentierten Zuordnungen haben?

Lesezeit: 10 Minuten

Benutzer-Avatar
David

Ich habe Mappings mit Anmerkungen versehen, die über meine Spring-mvc-Web-App hervorragend funktionieren, jedoch wird zwischen Groß- und Kleinschreibung unterschieden. Ich kann keine Möglichkeit finden, Groß- und Kleinschreibung zu ignorieren. (Ich würde dies gerne in Spring MVC realisieren, anstatt den Datenverkehr irgendwie umzuleiten.)

  • Fügen Sie außerdem das Tag „Java“ hinzu, um viel mehr Seitenaufrufe zu erhalten, was normalerweise mehr Antworten bedeutet.

    – David Parks

    13. November 2010 um 9:09 Uhr

  • ähnliche Frage mit detaillierter Antwort zu diesem Problem, das ich gestellt habe, nachdem ich diese Frage gesehen habe. stackoverflow.com/questions/12684183/…

    – Zahid Riaz

    5. Oktober 2012 um 9:59 Uhr


Spring 4.2 unterstützt Pfadabgleich ohne Berücksichtigung der Groß-/Kleinschreibung. 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);
    }
}

  • Kennen Sie solche Konfigurationen für Abfrageparameter?

    – M22an

    11. November 2015 um 12:16 Uhr

  • @ M22an Entschuldigung, ich weiß es nicht. Ich denke, Sie können die Funktion unter anfordern jira.spring.io

    – npcode

    12. November 2015 um 3:45 Uhr

  • In Spring Boot 2 oder Spring 5 wird die WebMvcConfigurerAdapter ist veraltet. Stattdessen sollte man das implementieren WebMvcConfigurer direkt.

    – Abfahrtski

    30. März 2018 um 12:37 Uhr

  • Zwei Jahre später, aber immer noch… WebMvcConfigurerAdapter in Spring 3.2 hat die Methode nicht configurePathMatch. Die minimale Spring-Version ist nicht korrekt, wahrscheinlich 4.2, wie in den obigen Antworten angegeben. Mehr Infos auf docs.spring.io/spring/docs/3.2.13.RELEASE/javadoc-api/org/…

    – Alf

    26. April 2017 um 11:40 Uhr


  • Funktioniert ganz gut mit Spring 3.2.17 und höher. Das einzige, was im obigen Code fehlt, sind mehrere “return”-Anweisungen, die irrtümlich weggelassen wurden. Eine Lösung für Spring älter als 3.2.17 finden Sie unter: newmiancode.blogspot.com/2010/01/…

    – Gjera

    3. April 2019 um 13:42 Uhr


  • Danke für den Kommentar @Gjera. Sie haben Recht, dass es keine Rückgabeanweisungen gibt. Wie ich in den obigen Beispielen erwähnt habe, ist mein Code mit Groovy geschrieben, wodurch Sie das ‘return’ weglassen können und die letzte Codezeile, die in einer Methode ausgeführt wird, standardmäßig als return-Anweisung verwendet wird. Ich werde den Beitrag bearbeiten, um ihn ‘fett’ zu machen, damit er besser auffällt.

    – pczeus

    25. April 2019 um 15:00 Uhr

Entsprechend dieser Webbeitrag Sie müssen beide hinzufügen a HandlerMapping und ein HandlerAdapter im Frühjahr MVC. Die Zuordnung ordnet die Anforderung einem entsprechenden Controller zu, und der Adapter ist dafür verantwortlich, die Anforderung unter Verwendung des Controllers auszuführen.

Sie müssen daher die überschreiben PathMatcher sowohl für den Mapper als auch für den Adapter.

Bsp. (wird bei allen @Controllern die Groß-/Kleinschreibung ignorieren):

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

Etwa gleich hinzugefügt, dass <mvc:annotationsgesteuert> würde tun. (Danke an David Parks für den Link)

  • Für Spring 3.1 laden Sie AnnotationMethodHandlerAdapter durch RequestMappingHandlerAdapter. Sie verwenden diese neue Klasse in 3.1.

    – klein

    26. September 2012 um 12:52 Uhr

Benutzer-Avatar
Gemeinschaft


Problem Bericht zur Lösung durch smat


Bei der Lösung von smat gibt es einen kleinen Nebeneffekt (dafür würde ich spring-mvc verantwortlich machen).

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

Zum Beispiel haben wir eine Controller-Methode wie diese,

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

und wenn wir mit URL zugreifen, /code/AbD
dann mit Lösung von smat AntPathMatcher.doMatch() wird sammeln @PathVariable Wert ein Map<String, String> uriTemplateVariables als userCode->abd. Da wir die Pfadzeichenfolge in Kleinbuchstaben schreiben, werden auch die gesammelten Werte in Kleinbuchstaben geschrieben. Und das Der kleingeschriebene userCode-Wert wird an unseren Controller übergeben.

Aber ich bin dankbar für die Lösung von smat, die mir bisher ohne weitere Probleme gute Dienste geleistet hat.


Lösung


Dieses Problem wurde gelöst, indem die Lösung von smat umgangen wurde. Ohne klein geschriebenen Pfad oder Musterzeichenfolge in erweitert AntPathMatcher Klasse zwang ich meine verlängert AntPathMatcher meine Gewohnheit zu verwenden AntPathStringMatcher. mein Brauch AntPathStringMatcher führt einen case-unabhängigen Abgleich durch, ohne den Fall der tatsächlichen Zeichenfolge zu ändern.

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

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

}

Benutzerdefinierter 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;
    }
}

  • Für Spring 3.1 laden Sie AnnotationMethodHandlerAdapter durch RequestMappingHandlerAdapter. Sie verwenden diese neue Klasse in 3.1.

    – klein

    26. September 2012 um 12:52 Uhr

Benutzer-Avatar
Sherschon

Beispiel aus einer Bean-Datei in Spring 4.2 und dies wird NUR v4.2+ UNTERSTÜTZT:

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

1006480cookie-checkWie kann ich URLs ohne Berücksichtigung der Groß-/Kleinschreibung in Spring MVC mit kommentierten Zuordnungen haben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy