[英]Spring Boot - How to get all request params in a map in 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.