2010-01-16 9 views
14

मैं एनोटेशन-संचालित नियंत्रकों के साथ स्प्रिंग एमवीसी (3.0) का उपयोग कर रहा हूं। मैं संसाधनों के लिए आरईएसटी-पूर्ण यूआरएल बनाना चाहता हूं और को यूआरएल के अंत में फ़ाइल एक्सटेंशन की आवश्यकता नहीं है (लेकिन अभी भी वैकल्पिक रूप से अनुमति नहीं है) (लेकिन कोई विस्तार नहीं होने पर HTML सामग्री प्रकार मानें)। यह स्प्रिंग एमवीसी के साथ आउट-ऑफ-द-बॉक्स काम करता है जब तक कि फ़ाइल नाम में कोई बिंदु नहीं है (अवधि/पूर्ण-रोक)।"फ़ाइल नाम" भाग में एकाधिक बिंदुओं के साथ आरईएसटी-पूर्ण यूआरएल बनाने की कोशिश कर रहा है - स्प्रिंग 3.0 एमवीसी

हालांकि मेरे कुछ यूआरएल नाम में बिंदुओं के साथ पहचानकर्ता की आवश्यकता है। जैसे इस तरह:

http://company.com/widgets/123.456.789.500 

इस मामले वसंत में विस्तार .500 के लिए एक सामग्री प्रकार के लिए लग रहा है और इसलिए त्रुटियों कोई भी पाता है। मैं .html को अंत में जोड़ने, पहचानकर्ता को एन्कोड करने या पीछे की ओर स्लैश जोड़ने जैसे कार्य-आस-पास का उपयोग कर सकता हूं। मैं इनके साथ किसी से भी खुश नहीं हूं लेकिन शायद .html जोड़ने के साथ रह सकता हूं।

मैंने वसंत में डिफ़ॉल्ट फ़ाइल एक्सटेंशन पहचान को ओवरराइड करने का असफल तरीके से देखा है।

क्या किसी दिए गए नियंत्रक विधि या यूआरएल पैटर्न आदि के लिए फ़ाइल एक्सटेंशन डिटेक्शन को अनुकूलित या अक्षम करना संभव है?

उत्तर

10

@PathVariable यूआरएल में बिंदुओं की बात आती है जब पैटर्न मिलान थोड़ा सा गड़बड़ है (SPR-5778 देखें)। false पर useDefaultSuffixPattern प्रॉपर्टी सेट करके, आप इसे कम twitchy (लेकिन अधिक picky) बना सकते हैं, और डॉट-भारी यूआरएल पर बेहतर नियंत्रण प्राप्त कर सकते हैं।

यदि आपने पहले से ही अपने संदर्भ में DefaultAnnotationHandlerMapping स्पष्ट रूप से घोषित नहीं किया है (और अधिकांश लोग इसे आपके लिए स्पष्ट रूप से घोषित नहीं करते हैं), तो आप इसे स्पष्ट रूप से जोड़ सकते हैं और उस संपत्ति को सेट कर सकते हैं।

+0

यह चाल है, धन्यवाद स्काफमैन। लेकिन यह ऐप का एक और हिस्सा तोड़ दिया ... सामग्री नेगोशिएटिंग व्यूसेसोल्वर जो जैक्सन के लिए ".json" एक्सटेंशन को मैप करता है अब काम नहीं करता है। कोई राय कि इसे कैसे ठीक किया जाए? – nickdos

+0

".json" सहित URL के साथ स्पष्ट रूप से मेरे नियंत्रक विधि को जोड़कर सामग्री के साथ समस्या को हल किया गया है। जैसे एनोटेशन का उपयोग करके: @RequestMapping (value = "/search.json", method = RequestMethod.GET)। क्या इसका कोई अच्छा समाधान है? – nickdos

+0

क्या आपने '@RequestMapping (value ="/search * ") की कोशिश की है? – skaffman

12

शायद, यह एक बदसूरत हैक है, मैं सिर्फ वसंत @ एमवीसी की विस्तारशीलता का पता लगाने के लिए चाहता था। यहां एक अनुकूलित PathMatcher है। यह पैटर्न में $ का उपयोग करता है, अंत में मार्कर के रूप में - यदि पैटर्न इसके साथ समाप्त होता है, तो मार्कर हटा दिया जाता है और पैटर्न को डिफ़ॉल्ट मैचर द्वारा मेल किया जाता है, लेकिन यदि पैटर्न में $ मध्य में है (उदा। ...$.*), तो इस तरह का पैटर्न मेल नहीं खाता है।

public class CustomPathMatcher implements PathMatcher { 
    private PathMatcher target; 

    public CustomPathMatcher() { 
     target = new AntPathMatcher(); 
    } 

    public String combine(String pattern1, String pattern2) { 
     return target.combine(pattern1, pattern2); 
    } 

    public String extractPathWithinPattern(String pattern, String path) { 
     if (isEncoded(pattern)) { 
      pattern = resolvePattern(pattern); 
      if (pattern == null) return ""; 
     } 
     return target.extractPathWithinPattern(pattern, path); 
    } 

    public Map<String, String> extractUriTemplateVariables(String pattern, 
      String path) { 
     if (isEncoded(pattern)) { 
      pattern = resolvePattern(pattern); 
      if (pattern == null) return Collections.emptyMap(); 
     } 
     return target.extractUriTemplateVariables(pattern, path); 
    } 

    public Comparator<String> getPatternComparator(String pattern) { 
     final Comparator<String> targetComparator = target.getPatternComparator(pattern); 
     return new Comparator<String>() { 
      public int compare(String o1, String o2) { 
       if (isEncoded(o1)) { 
        if (isEncoded(o2)) { 
         return 0; 
        } else { 
         return -1; 
        } 
       } else if (isEncoded(o2)) { 
        return 1; 
       } 
       return targetComparator.compare(o1, o2); 
      }   
     }; 
    } 

    public boolean isPattern(String pattern) { 
     if (isEncoded(pattern)) { 
      pattern = resolvePattern(pattern); 
      if (pattern == null) return true; 
     } 
     return target.isPattern(pattern); 
    } 

    public boolean match(String pattern, String path) { 
     if (isEncoded(pattern)) { 
      pattern = resolvePattern(pattern); 
      if (pattern == null) return false; 
     } 
     return target.match(pattern, path); 
    } 

    public boolean matchStart(String pattern, String path) { 
     if (isEncoded(pattern)) { 
      pattern = resolvePattern(pattern); 
      if (pattern == null) return false; 
     } 
     return target.match(pattern, path); 
    } 

    private boolean isEncoded(String pattern) { 
     return pattern != null && pattern.contains("$"); 
    } 

    private String resolvePattern(String pattern) { 
     int i = pattern.indexOf('$'); 
     if (i < 0) return pattern; 
     else if (i == pattern.length() - 1) { 
      return pattern.substring(0, i); 
     } else { 
      String tail = pattern.substring(i + 1); 
      if (tail.startsWith(".")) return null; 
      else return pattern.substring(0, i) + tail; 
     } 
    } 
} 

कॉन्फ़िग:

<bean id = "pathMatcher" class = "sample.CustomPathMatcher" /> 

<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name = "pathMatcher" ref="pathMatcher" /> 
</bean> 

<bean class = "org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> 
    <property name = "pathMatcher" ref="pathMatcher" /> 
</bean> 

और उपयोग (दिए गए "/hello/1.2.3", value "1.2.3" है):

@RequestMapping(value = "/hello/{value}$", method = RequestMethod.GET) 
public String hello(@PathVariable("value") String value, ModelMap model) 

संपादित करें:: अब "पिछला स्लैश कोई फर्क नहीं पड़ता" नियम

+0

इस कोड के लिए धन्यवाद - वास्तव में उपयोगी है। सोचा था कि मैं किसी और को इस का उपयोग करते हुए, जिन्हें आप निकालना चाहिए करने के लिए उल्लेख करें आपके MVC config से अगर ऊपर कस्टम pathMatcher विन्यास जोड़ने। –

3

मुझे एक ही समस्या थी और मैं भी नहीं तोड़ता इसे कस्टम PathMatcher द्वारा हल किया। मेरा समाधान कुछ एक्स्ट्राव प्रस्तावित करने के लिए कुछ आसान है। मेरे PathMatcher भी एक निजी अंतिम AntPathMatcher लक्ष्य है, और यह प्रतिनिधियों इसे करने के लिए सभी कॉल्स अपरिवर्तित, मैच के लिए छोड़कर() विधि:

@Override 
public boolean match(String pattern, String path) { 
    return pattern.endsWith(".*") ? false : target.match(pattern, path); 
} 

यह काम करता है क्योंकि वसंत जोड़कर नियंत्रकों से मिलान करने की कोशिश करता है समाप्त करने के लिए "।" । उदाहरण के लिए, पथ मैपिंग "/ विगेट्स/{आईडी}" और यूआरएल "/ विजिजेट्स/1.2.3.4" के साथ, स्प्रिंग पहले मैच दोबारा कोशिश करता है "/ विजेट्स/{आईडी}।" और उसके बाद "/ विजेट्स/{id} "। पहला मैच होगा, लेकिन यह आईडी के लिए केवल "1.2.3" छोड़ देता है।

मेरा पैचमैचर विशेष रूप से "। *" समाप्त होने वाले पैटर्न को अस्वीकार करता है, इस प्रकार पहला प्रयास विफल रहता है और दूसरे मैचों में विफल रहता है।

यदि आप ContentNegotiatingViewResolver का उपयोग कर रहे हैं तो आप अभी भी अनुरोध पैरामीटर "प्रारूप" का उपयोग कर URL में सामग्री प्रकार निर्दिष्ट कर सकते हैं (यदि पक्ष पैरामीटर सत्य पर सेट है)।

-jarppe

6
<!-- language: lang-java --> 

@Controller public class MyController { @RequestMapping(value="/widgets/{preDot}.{postDot}") public void getResource(@PathVariable String preDot, @PathVariable String postDot) { String fullPath = preDot + "." + postDot; //... } }

// से ऊपर कोड /widgets/111.222.333.444

+0

अच्छा, सरल समाधान का – Jayz

1

skaffman के जवाब देने के लिए जोड़ने के लिए, यदि आप <mvc:annotation-driven/> उपयोग कर रहे हैं से मेल खाना चाहिए और आप करना चाहते हैं उपयोग DefaultSuffixPattern मान को ओवरराइड करें, आप निम्न के साथ <mvc:annotation-driven> टैग को प्रतिस्थापित कर सकते हैं:

<!-- Maps requests to @Controllers based on @RequestMapping("path") annotation values --> 
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> 
    <property name="order" value="1" /> 
    <property name="useDefaultSuffixPattern" value="false" /> 
</bean> 

<!-- Enables annotated @Controllers --> 
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> 
4

स्प्रिंग 3.2 बदल गया है, और आप स्पष्ट RequestMappingHandlerMapping सेम पर गुण सेट है कि, या तो (यदि MVC नाम स्थान का उपयोग नहीं) से पता चलता or by using a BeanPostProcessor जैसे निम्नलिखित (आप स्कैन या यह दृष्टांत की आवश्यकता होगी):

@Component 
public class IncludeExtensionsInRequestParamPostProcessor implements BeanPostProcessor { 
    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
     if (bean instanceof RequestMappingHandlerMapping) { 
      RequestMappingHandlerMapping mapping = (RequestMappingHandlerMapping)bean; 
      mapping.setUseRegisteredSuffixPatternMatch(false); 
      mapping.setUseSuffixPatternMatch(false); 
     } 
     return bean; 
    } 

    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) { return bean; } 
} 

आप अपने @RequestMapping पर :.* को भी जोड़ सकते हैं, उदाहरण के लिए "/{documentPath:.*}"(see JIRA comment)

2

जेएफवाई: वसंत 4 में यह समस्या इस प्रकार तय की गई है: WebMvcConfigurerAdapter।

@Configuration 
class MvcConfiguration extends WebMvcConfigurerAdapter { 

@Override 
public void configurePathMatch(PathMatchConfigurer configurer) { 
    configurer.setUseSuffixPatternMatch(false); 
} 
} 

या WebMvcConfigurationSupport के माध्यम से here की तरह समर्थन करें।

संबंधित मुद्दे