簡體   English   中英

如何檢查Spring RestController的未知查詢參數?

[英]How to check spring RestController for unknown query params?

我有一個基本的休息控制器參數。

如果查詢字符串包含我沒有定義的參數,我該如何拒絕連接?

@RestController
@RequestMapping("/")
public class MyRest {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public String content(@PathVariable id, @RequestParam(value = "page", required = false) int page) {
        return id;
    }
}

localhost:8080/myapp/123?pagggge=1

目前,當調用此url時,該方法僅使用id執行,並且未知的paggge參數被忽略。 一般來說這很好,但我如何驗證它們以及返回HTTP狀態代碼?

您可以按照自己的方式獲取所有參數並進行處理。 引用彈簧文檔:

在Map <String,String>或MultiValueMap <String,String>參數上使用@RequestParam注釋時,將使用所有請求參數填充地圖。

在您的控制器方法中,您可以包含@RequestParam Map<String, String>類型的參數@RequestParam Map<String, String>以訪問傳入的所有查詢參數。通用ArgsChecker服務類可用於檢查用戶是否傳入了無效參數。 如果是這樣,您可以拋出一個異常,該異常可以由@ControllerAdvice類處理。

@RestController
@ExposesResourceFor(Widget.class)
@RequestMapping("/widgets")
public class WidgetController {


@Autowired
ArgsChecker<Widget> widgetArgsChecker;

    @RequestMapping(value = "", method = RequestMethod.GET, produces = {"application/hal+json"})
    public HttpEntity<PagedResources<WidgetResource>> findAll(@RequestParam @ApiIgnore Map<String, String> allRequestParams, Pageable pageable, PagedResourcesAssembler pageAssembler) {
        Set<String> invalidArgs = widgetArgsChecker.getInvalidArgs(allRequestParams.keySet());
        if (invalidArgs.size() > 0) {
            throw new QueryParameterNotSupportedException("The user supplied query parameter(s) that are not supported: " + invalidArgs + " . See below for a list of query paramters that are supported by the widget endpoint.", invalidArgs, widgetArgsChecker.getValidArgs());

        }

ArgsChecker可以定義如下:

import com.widgetstore.api.annotation.Queryable;
import lombok.Getter;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class ArgsChecker<T> {
    @Getter
    private Set<String> validArgs;

    private ArgsChecker(){};

        public ArgsChecker(Class<T> someEntityClass){
    validArgs= FieldUtils.getFieldsListWithAnnotation(someEntityClass,Queryable.class)
            .stream()
            .map(Field::getName)
            .collect(Collectors.toSet());
    validArgs.add("page");
    validArgs.add("size");

}

public Set<String> getInvalidArgs(final Set<String> args){
    Set<String> invalidArgs=new HashSet<>(args);
    invalidArgs.removeAll(validArgs);
    return invalidArgs;



    }
   }

,它使用反射來查找使用“@Queryable”注釋注釋的字段:

package com.widgetstore.api.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Queryable {
} 

現在,使用該批注標記要查詢的域類的字段:

@Getter
@Setter
public class Widget {
    @Queryable 
    private String productGuid;
    @Queryable 
    private String serialNumber;

    private String manufacturer;

現在確保在應用程序啟動時創建ArgsChecker bean:

@SpringBootApplication
public class StartWidgetApi{

public static void main(String[] args){
    SpringApplication.run(StartWidgetApi.class);
}


@Bean(name="widgetArgsChecker")
public ArgsChecker<Widget> widgetArgsChecker(){
    return new ArgsChecker<Widget>(Widget.class);
}

//Other ArgsCheckers of different types may be used by other controllers.
@Bean(name="fooArgsChecker")
public ArgsChecker<Foo> fooArgsChecker(){
    return new ArgsChecker<Foo>(Foo.class);
 }
}

最后,

定義一個@ControllerAdvice類,它將偵聽應用程序拋出的異常:

package com.widgetstore.api.exception;


import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@ControllerAdvice
@RequestMapping(produces = "application/json")
@ResponseBody
public class RestControllerAdvice {


    @ExceptionHandler(QueryParameterNotSupportedException.class)
    public ResponseEntity<Map<String,Object>> unrecogonizedParameter(final QueryParameterNotSupportedException e){
        Map<String,Object> errorInfo = new LinkedHashMap<>();
        errorInfo.put("timestamp",new Date());
        errorInfo.put("errorMessage",e.getMessage());
        errorInfo.put("allowableParameters",e.getValidArgs());
        return new ResponseEntity<Map<String, Object>>(errorInfo,HttpStatus.BAD_REQUEST);
    }



}

,並定義QueryParameterNotSupportedException:

import lombok.Getter;

import java.util.Set;

@Getter
public class QueryParameterNotSupportedException extends RuntimeException{
    private Set<String> invalidArgs;

    private Set<String> validArgs;

    public QueryParameterNotSupportedException(String msg, Set<String> invalidArgs, Set<String> validArgs){
        super(msg);
        this.invalidArgs=invalidArgs;
        this.validArgs=validArgs;
    }

}

現在,當用戶點擊/小部件時?someUnknownField = abc&someOtherField = xyz他會得到一個json響應

 {"timestamp": 2017-01-10'T'blahblah, "errorMessage": "The user supplied query parameter(s) that are not supported: ["someUnknownField","someOtherField"]. See below for a list of allowed query parameters." ,
"allowableParameters": ["productGuid","serialNumber"]
}

在方法參數中添加HttpServletRequest request ,do

String query = request.getQueryString()

在方法體中並驗證。

我想分享一種不同的方式,因為我發現ametiste的答案太過手工而且mancini0過於冗長。

假設您使用Spring框架驗證API將請求參數綁定到對象ApiRequest

@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request) {
    binder.setAllowedFields(ApiRequest.getAllowedRequestParameters());
}

@RequestMapping("/api")
public String content(@Valid ApiRequest request, BindingResult bindingResult) {
    return request.getId();
}

使用以下ApiRequest定義。

public class ApiRequest {
    private String id;

    public static String[] getAllowedRequestParameters() {
        return new String[]{
            "id"
        };
    }

}

然后你可以使用BindingResult來檢查是否有任何意外的請求參數,如下所示:

    String[] suppressedFields = bindingResult.getSuppressedFields();
    if (suppressedFields.length > 0) {
        // your code here
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM