业务背景:
拦截请求,验证请求内容,如果不通过返回401,成功则转换请求内容为实际接口需要参数,并调用接口。
在springmvc下处理流程如下
1.filter拦截
2.保存输入流到byte[]
3.序列化
请求类型:post
请求格式:json
json格式:
{xxx:xxx,
body:xxx
}
//xxx是通用验证属性,body对应实际调用接口接收参数
简化版代码:
/**
*filter
*/
public class SignMvcFilter implements Filter {
@Override
public void init(FilterConfig filterconfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (servletrequest instanceof HttpServletRequest) {
requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) servletrequest);
}
if (requestWrapper == null)
filterchain.doFilter(servletrequest, servletresponse);
InfoPojo info = JSON.parseObject(requestWrapper.getInputStream(), InfoPojo.class);
//验证
if (SignValidate.validate(deviceInfo)) {
unauthor(servletresponse);
return;
}
filterchain.doFilter(requestWrapper, servletresponse);
}
//抛出401
private void unauthor(ServletResponse servletresponse) {
HttpServletResponse reponse = (HttpServletResponse) servletresponse;
reponse.setContentType(SignValidate.REPONSECONTENTTYPE);
reponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
@Override
public void destroy() {
}
}
/**
*保存输入流,因为需要取两次输入流,而request的输入流只能取一次并且无法reset
*/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String temp ="";
String s = "";
while((temp=request.getReader().readLine())!=null){
s =s+temp;
}
body = s.getBytes(SignValidate.CHARSET);
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readlistener) {
}
};
}
}
/**
*fastjson序列化
*/
public class MobileJsonHttpMessageConverter extends FastJsonHttpMessageConverter{
@Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return super.read(type, contextClass, inputMessage);
}
//对象转换,移除通用验证字段,保留接口对应数据,接口对应数据在info的body中
@Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
InfoPojo deviceInfo = (InfoPojo) super.readInternal(InfoPojo.class, inputMessage);
return JSON.parseObject(info.getBody(), clazz);
}
@Override
public void write(Object t, Type type, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
super.write(t, type, contentType, outputMessage);
}
@Override
protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
super.writeInternal(obj, outputMessage);
}
public MobileJsonHttpMessageConverter(){
super();
}
//需特殊处理的对象需继承BaseRequestDataPojo,BaseRequestDataPojo可以没有任何属性,只做标识
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return BaseRequestDataPojo.class.isAssignableFrom(clazz);
}
}
xml配置
<!--spring.xml配置-->
<mvc:message-converters register-defaults="true" >
<bean class="MobileJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
<!--filter配置在web.xml中-->
<filter>
<filter-name>authFilter</filter-name>
<filter-class> SignMvcFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>authFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
springmvc版本:3.2.8.RELEASE
fastjson版本:1.2.14