Tôi có ánh xạ chú thích hoạt động tốt thông qua ứng dụng web mvc mùa xuân của tôi, tuy nhiên, chúng phân biệt chữ hoa chữ thường. Tôi không thể tìm cách làm cho chúng trở nên không phân biệt chữ hoa chữ thường. (Tôi muốn thực hiện điều này xảy ra trong Spring MVC, thay vì chuyển hướng lưu lượng truy cập bằng cách nào đó)Làm thế nào tôi có thể có các URL không phân biệt dạng chữ trong Spring MVC với ánh xạ có chú thích
Làm thế nào tôi có thể có các URL không phân biệt dạng chữ trong Spring MVC với ánh xạ có chú thích
Trả lời
Vâng, tôi không thể trả lời câu hỏi của bạn (tôi đã thử, tôi nghĩ mình có thể tìm ra). Nhưng nhìn thấy như bạn vẫn chưa nhận được bất kỳ phản ứng trong 2 ngày, sau đây là một số dẫn ít nhất:
Ví dụ này dường như cho thấy nó có thể:
Nó tham chiếu lớp này trong mùa xuân
Tôi đoán là bạn cần mở rộng <mvc:annotation-driven/>
và triển khai từng hạt riêng với thông số chính xác e nó không phân biệt chữ hoa chữ thường. Xem:
http://rapid-web.tumblr.com/post/296916668/what-does-annotation-driven-do
Một lưu ý cuối cùng, tôi nhận thấy ở một nơi khác trong việc đọc mà nó nói rằng tất cả các đường dẫn mặc định để giảm trường hợp, có bạn xác minh rằng /MyPath
không được xử lý bởi @RequestMapping("/mypath")
?
Một lần nữa, chỉ cần thực phẩm cho suy nghĩ là tốt nhất tôi có thể làm. Có lẽ nó sẽ giúp bạn đủ xa để hỏi một câu hỏi cụ thể hơn dẫn bạn đến câu trả lời - đó là cách những điều này làm việc đôi khi. Chúc may mắn!
Theo this webpost bạn cần thêm cả HandlerMapping và HandlerAdapter trong Spring MVC. Ánh xạ ánh xạ yêu cầu tới một bộ điều khiển tương ứng và bộ điều hợp có trách nhiệm thực hiện yêu cầu bằng bộ điều khiển.
Do đó, bạn cần ghi đè số PathMatcher cho cả người lập bản đồ và bộ điều hợp.
Ex (sẽ làm cho tất cả case-insensitive @Controllers):
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"/>
gia tăng về tương tự mà < mvc:annotation-driven> sẽ làm. (Cám ơn David Parks cho liên kết)
Vấn đề báo cáo cho solution by smat
Trong solution by smat, có một chút tác dụng phụ (tôi sẽ đổ lỗi cho mùa xuân-MVC cho điều đó).
Lúc đầu, AntPathMatcher.doMatch()
có vẻ trả về true/false tùy thuộc vào chuỗi yêu cầu-url và chuỗi ánh xạ yêu cầu của bộ điều khiển (Đó là điều duy nhất nên được thực hiện tại đây).Nhưng, phương pháp này cũng được sử dụng cho một mục đích nữa (không được viết trong documentation!). Một mục đích khác là thu thập các giá trị tương ứng cho @PathVariable
trong phương pháp điều khiển. Các giá trị này được thu thập trong Map<String, String> uriTemplateVariables
(tham số cuối cùng) .Và các giá trị được thu thập này được sử dụng để chuyển sang phương thức điều khiển làm giá trị tham số.
Ví dụ, chúng tôi có điều khiển-phương pháp như thế này,
@RequestMapping("/code/{userCode}")
public String getCode(@PathVariable("userCode") String userCode) {
System.out.println(userCode);
}
và nếu chúng ta tiếp cận với URL, /code/AbD
sau đó với solution by smatAntPathMatcher.doMatch()
sẽ thu thập @PathVariable
giá trị trong Map<String, String> uriTemplateVariables
như userCode->abd
. Vì chúng ta sắp xếp chuỗi đường dẫn thấp hơn, các giá trị thu thập được cũng thấp hơn. Và giá trị này giá trị userCode thấp hơn được truyền cho bộ điều khiển của chúng tôi.
Nhưng, tôi biết ơn solution by smat mà phục vụ tốt cho tôi cho đến nay không có bất kỳ vấn đề khác.
Giải pháp
Giải Quyết vấn đề này bằng cách làm việc xung quanh solution by smat. Nếu không có con đường-vỏ thấp hơn hoặc chuỗi pattern trong mở rộng lớp AntPathMatcher
, tôi buộc phải mở rộng của tôi AntPathMatcher
sử dụng tùy chỉnh của tôi AntPathStringMatcher
. tuỳ chỉnh AntPathStringMatcher
của tôi phù hợp với trường hợp không phân biệt chữ hoa chữ thường mà không thay đổi trường hợp chuỗi thực.
Trong đoạn mã sau giải pháp hầu hết các mã được sao chép từ mã lớp gốc (mã Tôi muốn tùy chỉnh được ẩn cho lớp con vì tiếp cận tư nhân).
Tuỳ chỉnh 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);
}
}
Tuỳ chỉnh 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;
}
}
Trong mùa xuân 3.2+/Spring Boot, bây giờ bạn có thể thiết lập trường hợp phù hợp với URL không nhạy cảm bằng cách sử dụng cấu hình Java đơn giản.
Trước tiên, bạn cần phải tạo ra các CaseInsensitivePathMatcher.groovy hoặc Java lớp:
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)
}
}
Tiếp theo, để thực hiện điều này, bạn nên có một lớp chú thích với Springs @Configuration mở rộng lớp WebMvcConfigurerAdapter như hình dưới đây (Lưu ý rằng mã của tôi được chứa bên trong.lớp groovy):
@Configuration
public class ApplicationConfig extends WebMvcConfigurerAdapter
Sau đó, thêm 2 phương pháp sau để lớp:
/**
* 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()
}
}
Vậy là xong, bây giờ bạn sẽ có tất cả các thiết lập đối với trường hợp URL không nhạy cảm với cấu hình tối thiểu
Hai năm sau, nhưng vẫn ... 'WebMvcConfigurerAdapter' trong Mùa xuân 3.2 không có phương thức' configurePathMatch'. Phiên bản Spring tối thiểu không chính xác, có thể là 4,2 như được nêu trong các câu trả lời ở trên. Thông tin thêm về 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. Bạn có thể định cấu hình như sau:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
AntPathMatcher matcher = new AntPathMatcher();
matcher.setCaseSensitive(false);
configurer.setPathMatcher(matcher);
}
}
Ví dụ từ tệp bean trong Spring 4.2 và điều này CHỈ ĐƯỢC H SUP TRỢ 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. @RequestMapping chú thích trong Spring MVC
- 2. Spring MVC có hỗ trợ chú thích JSR 311 không?
- 3. spring mvc nhận tất cả các ánh xạ yêu cầu
- 4. Hibernate: Di chuyển từ ánh xạ tới chú thích - có thể trộn hbm và chú thích không?
- 5. Tôi có chú thích gì với XmlJavaTypeAdapters?
- 6. Testing Spring MVC chú thích mapppings
- 7. Chú thích @Nam trong Spring MVC
- 8. Chú thích @Cacheable của Spring có thể có cùng phạm vi với bean của phương thức được chú thích không?
- 9. Làm thế nào tôi có thể ánh xạ một ngày Java đến DATETIME trong mysql (theo mặc định là TIMESTAMP) với chú thích Hibernate
- 10. Hibernate + Spring MVC: cấu hình ánh xạ đối tượng
- 11. Tôi có thể chỉ định một cột phân biệt đối xử với ánh xạ bảng cho mỗi loại không?
- 12. Làm thế nào để có nhiều thực thể ánh xạ với một bảng?
- 13. Tên giao thức trong các URL có phân biệt chữ hoa chữ thường không?
- 14. Làm thế nào tôi có thể đọc json với chú thích với Json.NET
- 15. Trong Django, bạn có thể tự động ánh xạ URL để xem các phương thức không?
- 16. Tôi có thể đặt Subversion + TortoiseSVN không phân biệt chữ hoa chữ thường cho Windows không?
- 17. Làm thế nào tôi có thể tạo các chú thích Javadoc trong Eclipse?
- 18. JACKSON Ánh xạ cấu hình XML Nếu không có chú thích
- 19. Có sự khác biệt nào giữa tệp iostream được ánh xạ và tăng tệp ánh xạ interprocess không?
- 20. Các thuộc tính có thể ánh xạ trong hbm.xml có bị tạm thời không?
- 21. Vị trí của System.Web.MVC để tôi có thể phản ánh qua nó với phản xạ
- 22. làm cách nào tôi có thể ánh xạ hai cột trong truy vấn đường ray đơn
- 23. Spring MVC + Facelets, có thể không?
- 24. Spring MVC: Ánh xạ nhiều URL tới cùng một bộ điều khiển
- 25. Tôi có thể (lại) ánh xạ các lệnh Ex trong vim không?
- 26. Làm thế nào tôi có thể xuất ra một chú thích HTML trong Compojure/Hiccup?
- 27. URL không phân biệt chữ hoa chữ thường với mod_rewrite
- 28. Web mùa xuân: Bộ điều khiển có ánh xạ có chú thích - Nhận HttpServletRequest/dữ liệu biểu mẫu
- 29. Có thể tích hợp Spring MVC với Guice không?
- 30. Làm thế nào tôi có thể ánh xạ giữa hai enums bằng Automapper?
Ngoài ra, thêm thẻ 'Java' nó sẽ mang lại cho bạn nhiều lượt xem trang thường có nghĩa là nhiều câu trả lời hơn. –
câu hỏi tương tự với câu trả lời chi tiết về vấn đề này tôi đã hỏi sau khi nhìn thấy câu hỏi này. http://stackoverflow.com/questions/12684183/case-insensitive-mapping-for-spring-mvc-requestmapping-annotations/12732550 –