前言
很久之前写过一篇就是自动填充接口参数的,利用的 HandlerMethodArgumentResolver 自定义注解
Springboot Controller接口默认自动填充 业务实体参数值_springboot设置入参默认值-CSDN博客
现在这一篇也差不多,达到的目的就是重新去给post请求的参数赋值、修改啥的。
不多说,开始。
正文
首先知道一点,post请求的参数,一旦取出来就没了,因为是流数据。
所以老样子,我们写多一个HttpServletRequestWrapper :
BodyReaderHttpServletRequestWrapper
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Map;
import java.util.Vector;
/**
* @Author : JCccc
* @CreateTime : 2020/3/27
* @Description :
**/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
/**
* 所有参数的集合
*/
private Map<String, String[]> parameterMap;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
BufferedReader reader = request.getReader();
body = readBytes(reader);
parameterMap = request.getParameterMap();
}
@Override
public BufferedReader getReader() throws IOException {
ServletInputStream inputStream = getInputStream();
if (null == inputStream) {
return null;
}
return new BufferedReader(new InputStreamReader(inputStream));
}
@Override
public Enumeration<String> getParameterNames() {
Vector<String> vector = new Vector<>(parameterMap.keySet());
return vector.elements();
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (body == null) {
return null;
}
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
return bais.read();
}
};
}
/**
* 通过BufferedReader和字符编码集转换成byte数组
*
* @param br
* @return
* @throws IOException
*/
private byte[] readBytes(BufferedReader br) throws IOException {
String str;
StringBuilder retStr = new StringBuilder();
while ((str = br.readLine()) != null) {
retStr.append(str);
}
if (StringUtils.isNotBlank(retStr.toString())) {
return retStr.toString().getBytes(StandardCharsets.UTF_8);
}
return null;
}
}
然后是我们这一期的核心,
DefaultDataFillHandlerMethodArgumentResolver
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.speediance.admin.auth.ShiroUtils;
import com.speediance.admin.dto.req.UserDefaultDataFill;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.Date;
import java.util.Objects;
@Component
public class DefaultDataFillHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(UserDefaultDataFill.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest( HttpServletRequest.class );
BodyReaderHttpServletRequestWrapper myRequestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
// 从Request的包装类中读取数据
BufferedReader reader = myRequestWrapper.getReader();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
JSONObject jsonObject = JSON.parseObject(sb.toString());
Object bean = BeanUtils.instantiateClass(parameter.getParameterType());
BeanWrapper beanWrapper = new BeanWrapperImpl(bean);
//重新赋值
for (String key : jsonObject.keySet()) {
beanWrapper.setPropertyValue(key,jsonObject.get(key));
}
Long userId = //比如从数据库查出来 或者从token解析出来;
//举例子给如入参自动填充 更新操作人
beanWrapper.setPropertyValue("updateUserId", userId);
return bean;
}
}
然后就是重写一个自定义注解 ,相当于需要填充数据或者进入到参数修改,我们采用它标注:
UserDefaultDataFill
import java.lang.annotation.*;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserDefaultDataFill {
}
然后就OK了,看看怎么用:
比如说一个更新接口,我们想默认填充上入参里面的 修改用户ID (简单举例,其余业务要修改值,赋值自己套用就可以)
然后可以看到我们的参数解析器里面的代码 (其实就是复制流拿出参数,修改完变成当前接口的bean):
OK,就到这。