GVKun编程网logo

带有点(。)的Spring MVC @PathVariable被截断(springmvc pathvariable url地址)

12

最近很多小伙伴都在问带有点和。的SpringMVC@PathVariable被截断这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展java–SpringMVC3.0:String是

最近很多小伙伴都在问带有点。的Spring MVC @PathVariable被截断这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展java – Spring MVC 3.0:String是@PathVariable的首选类型吗?、Spring @Pathvariable、spring mvc @PathVariable、Spring MVC @PathVariable被截断等相关知识,下面开始了哦!

本文目录一览:

带有点(。)的Spring MVC @PathVariable被截断(springmvc pathvariable url地址)

带有点(。)的Spring MVC @PathVariable被截断(springmvc pathvariable url地址)

Spring论坛指出,它已作为ContentNegotiationManager的一部分进行了修复(3.2版)。请参阅下面的链接。
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632

在我的应用程序中,带有.com的requestParameter被截断了。

谁能解释我如何使用此新功能?如何在xml上进行配置?

注意:Spring论坛-#1带有点(。)的Spring MVC @PathVariable被截断

答案1

小编典典

据我所知,这个问题只出现在requestmapping末尾的pathvariable中。

我们可以通过在requestmapping中定义regex插件来解决这一问题。

/somepath/{variable:.+}

答案2

小编典典

Spring认为最后一个点后面的任何东西都是文件扩展名(例如.json或).xml,然后对其进行结构化以检索您的参数。

因此,如果您有/somepath/{variable}

  • /somepath/param/somepath/param.json/somepath/param.xml/somepath/param.anything将导致具有值的PARAMparam
  • /somepath/param.value.json/somepath/param.value.xml否则/somepath/param.value.anything将导致带有值的参数param.value

如果将映射更改/somepath/{variable:.+}为建议的值,则任何点(包括最后一个点)都将被视为参数的一部分:

  • /somepath/param 会带来有价值的参数 param
  • /somepath/param.json会带来有价值的参数 param.json
  • /somepath/param.xml 会带来有价值的参数 param.xml
  • /somepath/param.anything会带来有价值的参数 param.anything
  • /somepath/param.value.json 会带来有价值的参数 param.value.json

如果您不关心扩展名识别,则可以通过覆盖mvc:annotation-drivenautomagic来禁用它:

<bean id="handlerMapping">    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>    <property name="useSuffixPatternMatch" value="false"/></bean>

因此,如果您有/somepath/{variable}:

  • /somepath/param/somepath/param.json/somepath/param.xml或/somepath/param.anything将导致具有值的PARAMparam

  • /somepath/param.value.json/somepath/param.value.xml否则/somepath/param.value.anything将导致带有值的参数param.value
    注意:与默认配置的区别仅在有类似的映射时可见somepath/something.{variable}

如果要保持扩展管理,从Spring 3.2开始,还可以设置RequestMappingHandlerMapping bean的useRegisteredSuffixPatternMatch属性,以保持激活suffixPattern识别,但仅限于已注册的扩展。

在这里,您仅定义json和xml扩展名:

<bean id="handlerMapping">    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>    <property name="useRegisteredSuffixPatternMatch" value="true"/></bean><bean id="contentNegotiationManager">    <property name="favorPathExtension" value="false"/>    <property name="favorParameter" value="true"/>    <property name="mediaTypes">        <value>            json=application/json            xml=application/xml        </value>    </property></bean>

请注意,mvc:annotation-driven现在接受contentNegotiation选项以提供自定义bean,但必须将RequestMappingHandlerMapping的属性更改为true(默认为false)(参见https://jira.springsource.org/browse/SPR-7632)。

因此,您仍然必须覆盖所有mvc:annotation驱动的配置。我开了一张去Spring的票,要求自定义RequestMappingHandlerMapping:https : //jira.springsource.org/browse/SPR-11253。如果您感兴趣,请投票。

覆盖时,请谨慎考虑自定义执行管理覆盖。否则,所有自定义Exception映射将失败。您将必须使用list bean重用messageCoverters:

<bean id="validator"/><bean id="conversionService"/><util:list id="messageConverters">    <bean></bean>    <bean></bean>    <bean></bean>    <bean></bean>    <bean></bean>    <bean></bean>    <bean></bean>    <bean></bean></util:list><bean name="exceptionHandlerExceptionResolver">    <property name="order" value="0"/>    <property name="messageConverters" ref="messageConverters"/></bean><bean name="handlerAdapter">    <property name="webBindingInitializer">        <bean>            <property name="conversionService" ref="conversionService" />            <property name="validator" ref="validator" />        </bean>    </property>    <property name="messageConverters" ref="messageConverters"/></bean><bean id="handlerMapping"></bean>

我在我参与的开源项目Resthub中实现了针对这些主题的一系列测试:请参阅https://github.com/resthub/resthub-spring-stack/pull/219/files和https:// github.com/resthub/resthub-spring-stack/issues/217

java – Spring MVC 3.0:String是@PathVariable的首选类型吗?

java – Spring MVC 3.0:String是@PathVariable的首选类型吗?

请原谅我在这里提出这样一个简单的问题,因为我是 Spring MVC 3.0的新手.我一直在阅读spring source website的文档几次.这是我在下面的问题中引用的代码片段: –
@RequestMapping("/pets/{petId}")
public void findPet(@PathVariable String petId,Model model) {    
// implementation omitted
}

如果我打算使用基于这个例子的URI模板,那么将@PathVariable类型设置为String总是比较好,即使我期望它是其他类型,例如int?文档说@PathVariable注释可以是任何简单类型,但如果Spring无法将无效petId转换为int(例如,用户输入一些字符而不是数字),它将抛出一个TypeMismatchException.

那么,验证器什么时候开始发挥作用?我是否将所有@PathVariable类型保留为String并使用验证器对String值执行验证,如果没有验证错误,则将String显式转换为所需类型?

谢谢.

解决方法

>让@PathVariable成为您期望的类型,不一定是String >有一个很好的自定义错误页面.如果用户决定在URL中写入内容,他应该知道“后果”.

Spring @Pathvariable

Spring @Pathvariable

先记录下@PathVariable的用法吧:

@RequestMapping("/demo/{id}")
    @ResponseBody
    public User getUser(@PathVariable("id")Integer id, HttpServletRequest request){
        System.out.println(request.getAttribute(RequestMappingHandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE));
        List<User> list=new ArrayList<>();
        list.add(new User(0,"A"));
        list.add(new User(1,"B"));
        list.add(new User(2,"C"));
        list.add(new User(3,"D"));
        User user = list.get(id);
        return user;
}

使用方式一:就像上面那样{}代表占位符,匹配URL中/ /两个之间的内容,通过@PathVariable进行解析

使用方式二:通过request的RequestMappingHandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE这个属性获取到一个Map,然后根据上面的key进行取值

 

 

有时候很好奇Spring @Pathvariable怎么解析的,好像无论多少个 {} 都能正确的映射,看起来好像没那么难。 但是我脑子不太行,尝试分析分析看看吧。

就像以前做笔试题:正确答案在下面,虽然我肯定写不出来,但是能看懂也挺为难我哈哈哈哈。

image

 

就像给定两个输入, pattern是标准路径 ,就像 /url/{id} , 而lookupPath就是请求路径,就像/url/19 ;

如果pattern和lookupPath一样,就直接返回,这个不难理解,常规URL映射都是这么映射的;

考虑到实际情况以及简化分析,useSuffixPatternMatch 默认为 true , fileExtensions 默认为空 ,以不带后缀名形式分析 ,那就会进入AntPathMatcher分析;

protected boolean doMatch(String pattern, String path, boolean fullMatch, Map<String, String> uriTemplateVariables) {
         //pattern为标准路径 /url/{id}   path为请求request路径/url/19  
         //fullMatch默认为true ; uriTemplateVariables默认为null
         //pathSeparator默认为 / 
        //path和pattern刚开始都是/ 开头, 肯定是false ; 这一步算是规则校验  路径不以/开头的 直接返回false
	if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
		return false;
	}
         //标准路径/url/{id}分隔成字符串数组 pattDirs 
	String[] pattDirs = tokenizePattern(pattern);
         //isPotentialMatch方法:
         //请求路径 和 @RequestMapping路径匹配 从头匹配刚开始就不相等直接返回false 
         //解析过程前面相等遇到 { * ?类型返回true 这里逻辑等等再具体描述
	if (fullMatch && this.caseSensitive && !isPotentialMatch(path, pattDirs)) {
		return false;
	}
         //请求路径拆分成字符串数组pathDirs 
	String[] pathDirs = tokenizePath(path);

	int pattIdxStart = 0;
	int pattIdxEnd = pattDirs.length - 1;
	int pathIdxStart = 0;
	int pathIdxEnd = pathDirs.length - 1;

	//循环遍历是否 请求路径字符数组 和 @RequestMapping路径数组 正则匹配
        //{id}的正则表达式被解析为 (.*) 肯定可以匹配上
        //字符数组只要有一个元素没匹配上就返回false
	while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
		String pattDir = pattDirs[pattIdxStart];
		if ("**".equals(pattDir)) {
			break;
		}
		if (!matchStrings(pattDir, pathDirs[pathIdxStart], uriTemplateVariables)) {
			return false;
		}
		pattIdxStart++;
		pathIdxStart++;
	}
         //上面如果匹配完成,pathIdxStart=pathIdxEnd+1  pattIdxStart=pattIdxEnd+1
	if (pathIdxStart > pathIdxEnd) {
		// Path is exhausted, only match if rest of pattern is * or **''s
		if (pattIdxStart > pattIdxEnd) {
                         // /url/{id}   /url/19 就匹配上了到这里 返回true
			return (pattern.endsWith(this.pathSeparator) ? path.endsWith(this.pathSeparator) :
					!path.endsWith(this.pathSeparator));
		}
		if (!fullMatch) {
			return true;
		}
		if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && path.endsWith(this.pathSeparator)) {
			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 pattDir = pattDirs[pattIdxEnd];
		if (pattDir.equals("**")) {
			break;
		}
		if (!matchStrings(pattDir, 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;
}

 

isPotentialMatch:进一步的过滤规则

private boolean isPotentialMatch(String path, String[] pattDirs) {
       // path 请求路径 pattDirs标准路径以 / 分隔出来的字符数组
	if (!this.trimTokens) {
                 //请求路径转成char数组
		char[] pathChars = path.toCharArray();
		int pos = 0;
		for (String pattDir : pattDirs) {
                  //请求路径中第一次从0开始找到/的位置,下次就从上次找到的位置开始找下一个/
			int skipped = skipSeparator(path, pos, this.pathSeparator);
			pos += skipped;
                  //skipSegment从pathChars找出跳过pattDir的长度
			skipped = skipSegment(pathChars, pos, pattDir);
                 //skipped最理想情况等于pattDir的长度 但是通常通配符形式这里都是小于
  //比如映射中包含demo,路径为do,这时候skipped也是2 也会返回true,但是之后的正则表达式校验无法通过      
			if (skipped < pattDir.length()) {
				if (skipped > 0) {
					return true;
				}
                          return (pattDir.length() > 0) && isWildcardChar(pattDir.charAt(0));
			}
                 //skipped ==pattDir长度,全匹配上直接匹配下一个/之后内容
			pos += skipped;
		}
	}
	return true;
}

//函数作用  待匹配路径字符数组  pos 代表 /所在的下一个位置  prefix标准路径
//标准路径包含wildcardChar { ? *  返回skipped 其他都会返回0 
private int skipSegment(char[] chars, int pos, String prefix) {
	int skipped = 0;
	for (char c : prefix.toCharArray()) {
		if (isWildcardChar(c)) {
			return skipped;
		}
		else if (pos + skipped >= chars.length) {
			return 0;
		}
		else if (chars[pos + skipped] == c) {
			skipped++;
		}
	}
	return skipped;
}

 

Spring考虑的很全面,最简单的 /url/{id}   /url/19这种类型匹配完成了;

转换完成以后,存入request域:以HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE作为KEY存储

代码位置:org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch

image

 

另外还一种特殊写法:{name:正则表达式校验}  比如我只希望URL中id为纯数字 \d*即可

image

补充:如果正则匹配不了,抛出的错误是404页面找不到.    带:与不带:的区别在于,不带:就默认使用 .* 匹配,其他用法没差别.

image

 

 

差点忘记记录Spring如何解析@PathVariable注解?

Spring专门的接口HandlerMethodArgumentResolver用来解析方法入参,而PathVariableMethodArgumentResolver就是用来解析 @PathVariable注解的。

image

而请求参数绑定到 方法入参的方式:

可以看到也是从request属性域HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE中取值,key就是@PathVariable(“yourname”)中的yourname取值.

image

spring mvc @PathVariable

spring mvc @PathVariable

您能给我一个简短的解释和@PathVariable在Spring MVC 中使用的示例吗?请附上您输入网址的方式?
我正在努力获取正确的URL以显示jsp页面。谢谢。

答案1

小编典典

假设您想写一个URL来获取一些命令,您可以说

www.mydomain.com/order/123

其中123是orderId。

所以现在您将在spring mvc控制器中使用的url看起来像

/order/{orderId}

现在可以将订单ID声明为路径变量

@RequestMapping(value = " /order/{orderId}", method=RequestMethod.GET)public String getOrder(@PathVariable String orderId){//fetch order}

如果您使用网址www.mydomain.com/order/123,则spring会将orderId变量填充为值123

另请注意,PathVariable与requestParam不同,因为pathVariable是URL的一部分。使用请求参数的相同网址看起来像
www.mydomain.com/order?orderId=123

API DOC
Spring官方参考

Spring MVC @PathVariable被截断

Spring MVC @PathVariable被截断

如何解决Spring MVC @PathVariable被截断?

尝试对@RequestMapping参数使用正则表达式:

RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")

解决方法

spring

我有一个控制器,可提供对信息的RESTful访问:

@RequestMapping(method = RequestMethod.GET,value = Routes.BLAH_GET + "/{blahName}")
public ModelAndView getBlah(@PathVariable String blahName,HttpServletRequest request,HttpServletResponse response) {

我遇到的问题是,如果我使用带有特殊字符的路径变量访问服务器,则会被截断。例如: http:// localhost:8080 / blah-server / blah / get / blah2010.08.19-02:25:47

参数blahName将为blah2010.08

但是,对request.getRequestURI()的调用包含所有传入的信息。

任何想法如何防止Spring截断@PathVariable?

今天关于带有点。的Spring MVC @PathVariable被截断的介绍到此结束,谢谢您的阅读,有关java – Spring MVC 3.0:String是@PathVariable的首选类型吗?、Spring @Pathvariable、spring mvc @PathVariable、Spring MVC @PathVariable被截断等更多相关知识的信息可以在本站进行查询。

本文标签: