参数绑定时springmvc会对从前端传来的参数自动转化成方法定义的参数的类型,我们可自己定义此接口来实现自己的类型的转换。
HandlerMethodArgumentResolver是什么?它是springmvc提供的入参解析器,像平常应用的注解@RequestParam @PathVariable @ModelAttribute …等等修饰在@RequestMapping下的参数上都可以用HandlerMethodArgumentResolver来解析。
public interface HandlerMethodArgumentResolver {
// 参数是否符合条件,反回true会调用下面的方法
boolean supportsParameter(MethodParameter parameter);
// 对修饰的参数解析赋值等
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
有很多内置实现,我们可以去参考,例如:RequestParamMethodArgumentResolver.java
1.创建自定义注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonArg {
String value() default "";
}
2.创建自定义HandlerMethodArgumentResolver
public class JsonArgumentResolver implements HandlerMethodArgumentResolver {
private static final String JSON_BODY_ATTRIBUTE = "JSON_REQUEST_BODY";
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(JsonArg.class);
}
@Override
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory)
throws Exception {
String body = getRequestBody(webRequest);
String jsonPath = Objects.requireNonNull(
Objects.requireNonNull(parameter.getParameterAnnotation(JsonArg.class)).value());
Class<?> parameterType = parameter.getParameterType();
return JsonPath.parse(body).read(jsonPath, parameterType);
}
private String getRequestBody(NativeWebRequest webRequest) {
HttpServletRequest servletRequest = Objects.requireNonNull(
webRequest.getNativeRequest(HttpServletRequest.class));
String jsonBody = (String) servletRequest.getAttribute(JSON_BODY_ATTRIBUTE);
if (jsonBody == null) {
try {
jsonBody = IOUtils.toString(servletRequest.getInputStream());
servletRequest.setAttribute(JSON_BODY_ATTRIBUTE, jsonBody);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return jsonBody;
}
}
3.注册自定义HandlerMethodArgumentResolver
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
JsonArgumentResolver jsonArgumentResolver = new JsonArgumentResolver();
argumentResolvers.add(jsonArgumentResolver);
}
}
4.使用示例
@PostMapping("/process/custompojo")
public ResponseEntity process(
@JsonArg("firstName") String firstName,
@JsonArg("lastName") String lastName,
@JsonArg("address") AddressDto address) {
...
}
该节来自:https://www.baeldung.com/spring-mvc-json-param-mapping
参考:PageableHandlerMethodArgumentResolver.java
1.创建自定义类型
public class PageRequest {
private int page;
private int size;
private List<Order> orders;
public static class Order {
private String property;
private String direction;
}
}
2.创建自定义HandlerMethodArgumentResolver
public class PageRequestArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return PageRequest.class.equals(parameter.getParameterType());
}
@Override
public Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory)
throws Exception {
PageRequest.PageRequestBuilder builder = PageRequest.builder();
String page = webRequest.getParameter("page");
String pageSize = webRequest.getParameter("size");
String[] directionParameter = webRequest.getParameterValues("sort");
List<PageRequest.Order> allOrders = new ArrayList<>();
builder.page(Integer.valueOf(page))
.size(Integer.valueOf(pageSize))
.orders(allOrders);
if (ArrayUtil.isNotEmpty(directionParameter)) {
for (String part : directionParameter) {
if (part == null) {
continue;
}
String[] elements = Arrays.stream(part.split(",")) //
.toArray(String[]::new);
allOrders.add(PageRequest.Order.builder()
.property(elements[0])
.direction(elements.length > 1 ? elements[1] : "asc")
.build());
}
}
return builder.build();
}
}
3.注册自定义HandlerMethodArgumentResolver
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new PageRequestArgumentResolver());
}
}
4.使用示例
/api/v1/users?page=1&size=2&sort=name,email,asc
/api/v1/users?page=1&size=2&sort=name,desc&sort=email,asc&sort=jack,asc
@GetMapping
public void get(PageRequest page) {
log.info(page);
}
结果日志:
PageRequest(page=1, size=2,
orders=[PageRequest.Order(property=name, direction=desc),
PageRequest.Order(property=email, direction=asc),
PageRequest.Order(property=jack, direction=asc)])
1.创建自定义类型和自定义注解
public class CurrentUser {
private String id;
private String username;
private String displayName;
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
}
2.创建自定义HandlerMethodArgumentResolver
public class AuthInfoArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return CurrentUser.class.equals(parameter.getParameterType()) &&
parameter.hasParameterAnnotation(Auth.class);
}
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mvContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
if (request == null) {
return null;
}
// CurrentUser = from request
return CurrentUser.builder().id(StpUtil.getLoginId().toString()).build();
}
3.注册自定义HandlerMethodArgumentResolver
同上
4.使用示例
/api/v1/users
-hearder token
@RestController
public class HelloController {
@PostMapping
public void test(@RequestBody City city, @Auth CurrentUser user) {
...
对于单个简单类型到对象的转换,使用Converter实现。
为了封装一系列对象的转换逻辑,使用ConverterFactory实现。
对于任何数据,间接出现或需要应用其他逻辑来检索关联的数据,使用HandlerMethodArgumentResolver实现。