一般从前台接收到的参数都是JSON之类的通用格式,或者通过@RequestBody自动映射实体类。但是如果想要将拿到的数据直接自动转换成一个非普通类实体,而不是拿到以后自己再封装。这时候最好就自定义一个注解,针对所需要的格式自动封装。
实现方法如下:
首先声明一个注解:(Dson为一个基于JSON格式的自定义二次封装类,对JSON格式进行空参判断,忽略引号,可以简易方法直接取值)
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestDson {
}
接下来写一个映射器,相当于上面自定义注解的实现方法。继承 AbstractMessageReaderArgumentResolver 类,实现其中两个方法,supportsParameter是判断该注解是否可以生效,true的话进入下面实现方法中进行实现,实现方法中resolveArgument进行处理后就传到@RequestBody中过一遍后传到Controller中进行逻辑处理。
package com.miracle.qaodo.config;
import com.miracle.dson.Dson;
import com.miracle.qaodo.annotation.RequestDson;Q
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @Author Diuut
* @Date 2020/4/28 14:45
*/
@Configuration
@EnableWebFlux
@Slf4j
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
List<HttpMessageReader<?>> readers = new ArrayList<HttpMessageReader<?>>();
//添加Http消息编解码器
readers.add(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
//消息编解码器与Resolver绑定
configurer.addCustomResolver(new DsonHandlerArgumentResolver(readers));
}
static class DsonHandlerArgumentResolver extends AbstractMessageReaderArgumentResolver {
public DsonHandlerArgumentResolver(List<HttpMessageReader<?>> readers) {
super(readers);
}
protected DsonHandlerArgumentResolver(List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry adapterRegistry) {
super(messageReaders, adapterRegistry);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean hasParameterAnnotation = parameter.hasParameterAnnotation(RequestDson.class);
// log.info("supportsParameter: {}", hasParameterAnnotation);
return hasParameterAnnotation;//绑定注解
}
@Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
RequestDson annotation = parameter.getParameterAnnotation(RequestDson.class);
Assert.state(annotation != null, "No KIMBody annotation");
ServerHttpRequest request = exchange.getRequest();
if ("POST".equals(request.getMethodValue())) {
return request.getBody()
.collectList()
.map(list -> {
StringBuffer str = new StringBuffer();
for (DataBuffer buf : list) {
str.append(buf.toString(StandardCharsets.UTF_8));
DataBufferUtils.release(buf);
}
log.info("post请求 request:{}", str);
String decode = "";
try {
int flag = 5; //decode重试解码次数
String decodeStr = "";
String temp=str.toString();
do {
flag--;
decodeStr=decode;
decode = URLDecoder.decode(temp, "UTF-8");
// log.info("post请求 decode:{}", decode);
temp=decode;
if (decode.contains("+")) {
break;
}
} while (!StringUtils.pathEquals(decodeStr, decode) && flag > 0);
//URLDecoder.decode会导致+ 转为 空格
} catch (Exception e) {
log.warn(str+"url转码失败");
}
log.info("post请求 decode:{}", decode);
return Dson.fromString(decode);
});
} else if ("GET".equals(request.getMethodValue())) {
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
// log.info("queryParams:{}", queryParams);
Map<String, String> map = queryParams.toSingleValueMap();
log.info("get请求 request:{}", map);
Dson dson = null;
for (Map.Entry<String, String> entry : map.entrySet()) {
if (entry.getKey().startsWith("{")) {
Dson tmp = Dson.fromMap(entry.getKey());
if (dson == null) {
dson = Dson.fromMap("{}");
}
dson.putAll(tmp._Value());
} else if (entry.getKey().startsWith("[")) {
Dson tmp = Dson.fromArray(entry.getKey());
if (dson == null) {
dson = Dson.fromArray("[]");
}
dson.addAll(tmp._Value());
} else {
if (dson == null) {
dson = Dson.fromMap("{}");
}
dson.put(entry.getKey(), entry.getValue());
}
}
if (dson == null) {
dson = Dson.fromMap("{}");
}
return Mono.just(dson);
}
return null;
}
}
}
使用方法的话同在@RequestBody的位置替换为@RequestDson,即可从前台直接传Dson格式的数据到后台中直接使用。 以上。