我是个java小白,在近期的开发中,有这样一个任务,拦截请求,统一对请求进行token的验证,由于特殊原因,工程全部采用post请求。想到的就是拦截器、Filter、aop。
由于要求尽量使用spring组件,所以排除Filter,由于工程的URL没有统一规范,所以aop也排除,最后使用了拦截器,在使用的过程中会出现Required request body is missing错误,经过查找资料发现是request body中获取参数时使用流获取,但是request的流只能使用一次,给出的办法就是在获取流之前对流进行复制。具体实现见下面代码。
1:首先自定义一个类继承HttpServletRequestWrapper,用来备份流
public class BufferedServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] buffer;
public BufferedServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
InputStream is = request.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buff[] = new byte[1024];
int read;
while ((read = is.read(buff)) > 0) {
baos.write(buff, 0, read);
}
this.buffer = baos.toByteArray();
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new BufferedServletInputStream(this.buffer);
}
// 对外提供读取流的方法
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}
2:在spring配置文件中自定义拦截器组件
/doctorWebLoginAccount/doctorLogin/app
/doctorWebLoginAccount/doctorLogin/web
/ws
/fileUpload/uploadPicture
/fileUpload/uploadSignature
/doctor/registe
/hospitalAndDepartment/findHospital
/hospitalAndDepartment/findDepartment
/hospDoctorTreatment/usageSelect
/chiefComplaint/symptom
/initialDiagnose/list
/doctor/patientInfo
/doctor/updateAccountInfo
/doctor/getMessageCode
/doctor/storeBaseInfo
/doctor/storeBaseGoods/list
/doctor/checkPhoneNum
/storeBaseGoods/pageList
3:定义拦截的实现类
public class ValidateTokenInterceptor implements HandlerInterceptor{
//不拦截的请求
private String[] excludeMapping;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//不需要过滤的请求
for(String exclude : excludeMapping){
if(request.getRequestURI().endsWith(exclude)){
return true;
}
}
BufferedServletRequestWrapper requestWrapper = new BufferedServletRequestWrapper(request);
//在这边替换流,使用工具类GetRequestJsonUtils获取json参数
JSONObject json = GetRequestJsonUtils.getRequestJsonObject(requestWrapper);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
logger.info("返回视图之前!");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
logger.info("请求结束之后!");
}
public void setExcludeMapping(String[] excludeMapping) {
this.excludeMapping = excludeMapping;
}
}
4:最后自定义一个Filter(spring请求的链式执行顺序为Filter-->拦截器-->controller)用来备份流
public class TranslateRequestWrapper implements Filter{
/**
* 销毁
*/
@Override
public void destroy() {
}
/**
* 过滤
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ServletRequest requestWrapepr = null;
if(request instanceof HttpServletRequest){
requestWrapepr = new BufferedServletRequestWrapper((HttpServletRequest)request);
}
if(requestWrapepr == null){
chain.doFilter(request, response);
}else{
chain.doFilter(requestWrapepr, response);
}
}
/**
* 初始化
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
5:附上从流中读取参数的工具类
public class GetRequestJsonUtils {
public static JSONObject getRequestJsonObject(HttpServletRequest request) throws IOException {
String json = getRequestJsonString(request);
return JSONObject.parseObject(json);
}
/***
* 获取 request 中 json 字符串的内容
*
* @param request
* @return : byte[]
* @throws IOException
*/
public static String getRequestJsonString(HttpServletRequest request)
throws IOException {
String submitMehtod = request.getMethod();
// GET
if (submitMehtod.equals("GET")) {
if(StringUtils.isNotEmpty(request.getQueryString())){
return new String(request.getQueryString().getBytes("iso-8859-1"),"utf-8").replaceAll("%22", "\"");
}else{
return new String("".getBytes("iso-8859-1"), "utf-8").replaceAll("%22", "\"");
}
// POST
} else {
return getRequestPostStr(request);
}
}
/**
* 描述:获取 post 请求的 byte[] 数组
*
* 举例:
*
* @param request
* @return
* @throws IOException
*/
public static byte[] getRequestPostBytes(HttpServletRequest request)
throws IOException {
int contentLength = request.getContentLength();
if(contentLength<0){
return null;
}
byte buffer[] = new byte[contentLength];
for (int i = 0; i < contentLength;) {
int readlen = request.getInputStream().read(buffer, i,
contentLength - i);
if (readlen == -1) {
break;
}
i += readlen;
}
return buffer;
}
/**
* 描述:获取 post 请求内容
*
* 举例:
*
* @param request
* @return
* @throws IOException
*/
public static String getRequestPostStr(HttpServletRequest request)
throws IOException {
byte buffer[] = getRequestPostBytes(request);
String charEncoding = request.getCharacterEncoding();
if (charEncoding == null) {
charEncoding = "UTF-8";
}
return new String(buffer, charEncoding);
}
}
这样就不会出现request body si missing