Spring MVC - 如何检查是不是没有传递意外的查询字符串参数?

Posted

技术标签:

【中文标题】Spring MVC - 如何检查是不是没有传递意外的查询字符串参数?【英文标题】:Spring MVC - How to check that no unexpected query string parameters has been passed?Spring MVC - 如何检查是否没有传递意外的查询字符串参数? 【发布时间】:2012-04-18 02:31:45 【问题描述】:

我有一个用 Spring MVC 编写的 Web 服务。第三方开发人员可以使用它。 我们的方法有很多可选参数(在查询字符串中传递)。

我想确保所有查询字符串参数拼写正确并且没有拼写错误。 有没有简单的方法来做到这一点?方法签名示例:

 @RequestMapping(value = "/filter", method = RequestMethod.GET)
    @ResponseBody
    public List<MetricType> getMetricTypes(    
            @RequestParam(value = "subject", required = false) Long subjectId,
            @RequestParam(value = "area", required = false) Long areaId,
            @RequestParam(value = "onlyImmediateChildren", required = false) Boolean onlyImmediateChildren,   
            @RequestParam(value = "componentGroup", required = false) Long componentGroupId    
            ) throws Exception
    
        //Some code
    

如果有人使用“onlyImediateChildren=true”参数(拼写错误)而不是“onlyImmediateChildren=true”调用此方法,Spring MVC 将忽略输入错误的参数并假定“onlyImmediateChildren”为空。开发人员将获得稍微不正确的结果列表,并且不会注意到错误。此类问题可能普遍存在且难以诊断。我想检查查询字符串中没有错别字的参数以防止此类问题。

更新

可以从查询字符串中提取实际参数列表。然后可以将其与允许的参数列表进行比较。如果我对允许的参数列表进行硬编码,它将复制方法签名。我想知道从方法签名中提取允许的参数列表是否容易(例如通过 @RequestParam 注释)?

非常感谢

格言

【问题讨论】:

您使用的是哪个版本的 Spring? 你是说spring MVC吗?我使用名为“Spring-webmvc.3.0.5.Release.jar”的文件。 【参考方案1】:

您可以使用请求的getParameterMap 方法获取所有已提交参数的Map,并根据所有允许参数的列表验证密钥。您应该能够通过简单地将 request 对象添加到方法签名中来获取它,例如:

public List<MetricType> getMetricTypes(   
    HttpServletRequest request,
    @RequestParam(value = "subject", required = false) Long subjectId,
    ...
) throws Exception 

【讨论】:

谢谢!我要做的是避免硬编码/复制允许的参数列表。此列表已由方法签名指定。我想从方法签名中提取允许的参数列表。 你可以使用@RequestParam Map&lt;String, String&gt; paramMap方法参数而不是调用request.getParameterMap @MaximEliseev 最简单的方法是要求您的客户提供所有参数,但在不需要时将它们留空,此后您可以使用@RequestMappingparams 来确保只有给定的参数存在。或者,您可以扩展 AnnotationMethodHandlerAdapter(或其他一些相关的类;我不确定)来实现您的参数验证。 @beerbajay - 一个关于扩展 AnnotationMethodHandlerAdapter 的有趣想法。但是无论如何我都必须从方法签名中获取允许的参数。 第三种方法是使用 this answer 之类的东西来获取当前方法,然后使用反射来内省该方法。【参考方案2】:

您可以实现自己的HandlerInterceptor。在 preHandle 方法中,您可以获取所有带有 @RequestParameter 注释的 HandlerMethod 参数。这些将是请求中所有允许的参数。

【讨论】:

看起来很有趣。将尝试实施。我希望它会起作用。【参考方案3】:

Spring 将通过类型参数注入 url 字符串中存在的所有查询参数

@RequestParam Map&lt;String,String&gt; 在你的控制器方法中,如果存在的话。

@RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
 public HttpEntity<PagedResources<WebProductResource>> findAll(@RequestParam Map<String, String> allRequestParams)
...

然后您可以自己验证地图的键。对于一般的“企业”方式,请在此处查看我的答案:How to check spring RestController for unknown query params?

【讨论】:

【参考方案4】:

这是我对HandlerInterceptor 的实现,它只接受由参数注释明确定义的参数:

import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.HandlerInterceptor

/**
 * Interceptor which assures that only expected [RequestParam]s are send.
 */
@Component
class UnexpectedParameterHandler : HandlerInterceptor 

    override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean 
        if (handler is HandlerMethod) 
            val queryParams = request.parameterNames.toList()
            val expectedParams = handler.methodParameters
                .map  methodParameter ->
                    val requestParamName = methodParameter.getParameterAnnotation(RequestParam::class.java)?.name
                    val parameterName = methodParameter.parameter.name
                    requestParamName ?: parameterName
                

            val unknownParameters = queryParams.minus(expectedParams)
            if (unknownParameters.isNotEmpty()) 
                response.writer.write("unexpected parameter $unknownParameters")
                response.status = HttpStatus.BAD_REQUEST.value()
                return false
            
        

        return super.preHandle(request, response, handler)
    

【讨论】:

谢谢!请注意,这似乎有一个缺陷:如果您传递的查询参数恰好与确实存在的路径参数同名,则不会出现错误。我能够通过使用mapNotNull 而不是退回到methodParameter.parameter.name 来解决这个问题。 这似乎也干扰了 Spring Boot 内置的 BasicErrorController。 IE。对于确实存在但其无效(无效枚举值等)的查询参数,您最终会收到误导性错误消息。我现在正在检查 request.dispatcherType == DispatcherType.REQUEST 以防止这种情况发生。

以上是关于Spring MVC - 如何检查是不是没有传递意外的查询字符串参数?的主要内容,如果未能解决你的问题,请参考以下文章

Spring MVC中如何传递对象参数

在 Spring MVC 中导航 HTML 页面后,是不是有任何方法可以检查用户会话?

如何在 Spring-MVC 中将数据从视图传递到控制器?

Spring mvc 判断用户是不是存在

如何在spring mvc中将嵌套列表元素传递给控制器

如何使用 Spring MVC 在 post 方法中传递 List<String>?