In the last blog, we have learned the overview process how a Java server with Spring handle request.
But in our daily usage, we are sometimes very confused about how to pass argument in, i.e. the conversion rule between the request string and our method parameters.
So, today, we focus on common problem we met when use Spring MVC.
Request Parameter
@RequestParam
is very common in our controller, which means this method parameter should interpreted from URL.
From @RequestParam
doc:
If the method parameter type is Map and a request parameter name is specified, then the request parameter value is converted to a Map assuming an appropriate conversion strategy is available.
If the method parameter is Map<String, String> or MultiValueMap<String, String> and a parameter name is not specified, then the map parameter is populated with all request parameter names and values.
@GetMapping("/foo")
public String test(@ReqestParam Map<String, String> m) {
}
Boolean
Saying we have following example, SpringMVC can correctly interprets ?bar=true
, ?bar=1
, or ?bar=yes
as being true, and ?bar=false
, ?bar=0
, or ?bar=no
as being false.
@RequestMapping(value = "/foo/{id}", method = RequestMethod.GET)
@ResponseBody
public Foo getFoo(
@PathVariable("id") String id,
@RequestParam(value="bar", required = false, defaultValue = "true")
boolean bar)
{
...
}
Furthermore, True/false
and yes/no
values ignore case.
Array
If we need an array from request parameter, we can do like following:
url?param=value1¶m=value2¶m=value3
@RequestMapping(value="/schedule", method = RequestMethod.POST)
public void action(@RequestParam("param") String[] param)
Complex Object
Although it is rare, we can send an object in URL, this question show the answer:
foo?page=1&prop1=x&prop2=y&prop3=z
public @ResponseBody List<MyObject> myAction(
@RequestParam(value = "page", required = false) int page,
MyObject myObject)
Notice that the complex object should not be annotated, or spring can’t transform it. By the way, sending object in this may not so useful.
Object With Customized Name
In more complex cases, we can customize the name of resulted object from this answer:
search?my-val-1=foo&my-val-2=bar
public class RequestParams {
@JsonProperty(value = "my-val-1")
private String myVal1;
}
Request Body
@RequestBody
annotated parameter is expected to hold the entire body of the request and bind to one object.
From doc:
The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request. Optionally, automatic validation can be applied by annotating the argument with @Valid.
The HttpMessageConverter
for request body has many sub-class which implement this interfaces and we focus only on json converter because we only interact with the web browser which use js.
In the MappingJackson2HttpMessageConverter
, spring will use Jackson’s ObjectMapper
to finish the job of mapping from json to java class.
If you want to customize the process of deserialize json, you need to provide your own class:
@RequestMapping(...)
public Object createRole(@RequestBody Role role) {
}
@JsonDeserialize(using = RoleDeserializer.class)
public class Role {
// ......
}
public class RoleDeserializer extends JsonDeserializer<Role> {
@Override
public Role deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// .................
return something;
}
}
Mis
400 Bad Request Debug
Even though we can find the conversion process by reading source code as the last blog do, this process is so much time consuming and isn’t the best option.
In order to debug the situation when 400 bad request happens, we have two ways to tell which method and parameter conversion goes wrong:
- use log level
TRACE
- use controller advice with exception handler
@ControllerAdvice
public class ControllerConfig {
private static final Logger logger = LoggerFactory.getLogger(ControllerConfig.class);
// exception handler class type to match
@ExceptionHandler(TypeMismatchException.class)
public void handle(Exception e) { // the parameter class is very essential or spring will not match this handler
logger.warn("Returning HTTP 400 Bad Request", e);
}
}
Valid Character in URL
http://localhost:8080/testRequest?a={one:1,two:2}&b=asdf
The parse of request parameter is done by container, in this case is embedded tomcat, which follows the RFC 3986 and RFC 7230.
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:472) ~[tomcat-embed-core-8.5.14.jar:8.5.14]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-embed-core-8.5.14.jar:8.5.14]
...
Ref
- Binding a list in request param
- Complex object as get param
- Map RequestBody to multiple parameter?
- Bad Request Debug
Written with StackEdit.
评论
发表评论