1. 程式人生 > 實用技巧 >spring boot 解決 @RequestBody只能讀取一次的問題

spring boot 解決 @RequestBody只能讀取一次的問題

  

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yicheplatform.shenzhen.constant.RedisConstants;
import com.yicheplatform.shenzhen.pojo.po.SysApiuser;
import com.yicheplatform.shenzhen.service.ISysApiuserService;
import com.yicheplatform.shenzhen.utils.ServletUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import static com.yicheplatform.shenzhen.exception.ErrorCodeEnum.getDesc;
import static com.yicheplatform.shenzhen.interceptor.ResponseData.buildStateFail;
import static com.yicheplatform.shenzhen.interceptor.SignUtils.getSign;
import static com.yicheplatform.shenzhen.interceptor.SignUtils.sortByKey;
import static com.yicheplatform.shenzhen.utils.MapAndStringUtils.getStringToMap;
import static com.yicheplatform.shenzhen.utils.MapRemoveNullUtil.removeNullValue;

/**
* @author puxiaozhe
* @description sign驗證
* @date 2020-08-08
**/
@Component
public class SignInterceptor implements HandlerInterceptor {

private static final Logger log = LoggerFactory.getLogger("SignInterceptor");

@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ISysApiuserService iSysApiuserService;

/**
* @param request:請求物件
* @param response:響應物件
* @param handler:處理物件:controller中的資訊
* @throws Exception
* @return:true表示正常,false表示被攔截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){


// 獲取body資訊轉換為Map
Map<String, String> newMap = null;
newMap = getStringToMap(getBody(request));

// 依次檢查傳入值是否存在
String appId = newMap.get("appId");
if (StringUtils.isBlank(appId)) {
ServletUtil.renderString(response, JSON.toJSONString(ResponseData.buildFail("appId 引數未傳入")));
return false;
}
String comId = newMap.get("comId");
if (StringUtils.isBlank(comId)) {
ServletUtil.renderString(response, JSON.toJSONString(ResponseData.buildFail("comId 引數未傳入")));
return false;
}
String sign = newMap.get("sign");
if (StringUtils.isBlank(sign)) {
ServletUtil.renderString(response, JSON.toJSONString(ResponseData.buildFail("sign 簽名未傳入")));
return false;
}
// 查詢快取中的值
StringBuffer redisKey = new StringBuffer(RedisConstants.REDIS_KEY_API_USER).append(":").append(appId).append(":").append(comId);
log.info("//快取key值:" + redisKey);
String secretKey = (String) redisTemplate.opsForValue().get(redisKey);
String signEncrypt = null;
// 獲取ve引數
String ve = newMap.get("ve");
// 移除map中空的value值
removeNullValue(newMap);
if (null == secretKey) {
// 資料庫中查詢私鑰
SysApiuser oldApiUser = iSysApiuserService.getOne(new QueryWrapper<SysApiuser>().lambda().eq(SysApiuser::getAppid, appId).eq(SysApiuser::getComid, comId));
if (null != oldApiUser) {
// 針對傳進的map排序
Map<String, String> signEncryptMap = sortByKey(newMap, ve);
// 獲取簽名
signEncrypt = getSign(signEncryptMap, oldApiUser.getSecretkey());
log.info("signEncrypt 新增至快取,key:" + redisKey + ",value:" + oldApiUser.getSecretkey());
redisTemplate.opsForValue().set(redisKey, oldApiUser.getSecretkey());
//後端MD5簽名校驗與前端簽名sign值比對
if (!signEncrypt.equals(sign)) {
log.info("簽名失敗,請核實");
ServletUtil.renderString(response, JSON.toJSONString(ResponseData.buildFail("簽名失敗,請核實")));
return false;
}
} else {
log.info("資料庫表中未配置相關使用者的資訊");
ServletUtil.renderString(response, JSON.toJSONString(ResponseData.buildFail("資料庫表中未配置相關使用者的資訊")));
return false;
}
} else {
// 針對傳進的map排序
Map<String, String> signEncryptMap = sortByKey(newMap, ve);
// 獲取簽名
signEncrypt = getSign(signEncryptMap, secretKey);
//後端MD5簽名校驗與前端簽名sign值比對
if ( null != signEncrypt && !signEncrypt.equals(sign)) {
log.info(getDesc(0x02) + " 簽名失敗,請核實");
ServletUtil.renderString(response, JSON.toJSONString(buildStateFail(getDesc(0x02) + " 簽名失敗,請核實")));
return false;
}
}
return true;
}

/**
* 獲取body資訊
* @param request
* @return
*/
private String getBody(HttpServletRequest request) {
InputStream is = null;
StringBuilder sb = new StringBuilder();
try {
is = request.getInputStream();
byte[] b = new byte[4096];
for (int n; (n = is.read(b)) != -1; ) {
sb.append(new String(b, 0, n));
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
}


——————————————————————————————————————————————————————————————————————————————————————————————



import com.yicheplatform.shenzhen.utils.CharsetUtils;
import com.yicheplatform.shenzhen.utils.MD5;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;


public class SignUtils {

/**
* 獲取key的方法
*
* @param inMap
* @param keys
* @return
*/
private static StringBuffer getKeys(Map<String, String> inMap, List<String> keys) {

StringBuffer sb = new StringBuffer();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
if (!key.equals("sign") && !StringUtils.isEmpty(key)) {
String value = null;
Object bytes = null;
boolean bl = false;
if (inMap.get(key) instanceof String) {
value = inMap.get(key);
} else {
bytes = inMap.get(key);
bl = true;
}
sb.append(key);
sb.append("=");
if (bl) {
sb.append(bytes);
} else {
sb.append(value == null ? "" : value);
}
sb.append("&");
}
}
return sb;
}


/**
* ascii 值升序排列
*
* @param map
* @return
*/
public static Map<String, String> sortByKey(Map<String, String> map, String ve) {
//建立一個帶有比較器的TreeMap
Map<String, String> treeMap = new TreeMap<>(String::compareTo);
//是否需要對引數進行編碼
if (ve != null && ve.equals("1")) {
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = urlEncode(entry.getKey());
treeMap.put(key, entry.getValue());
}
} else {
//將你的map傳入treeMap
treeMap.putAll(map);
}
return treeMap;
}

/**
* 獲取sign 簽名
*
* @param inMap
* @param secretKey
* @return
*/
public static String getSign(Map<String, String> inMap, String secretKey) {
List<String> keys = new ArrayList<String>(inMap.keySet());
Collections.sort(keys);
StringBuffer sb = null;
sb = getKeys(inMap, keys);
sb.append("requestKey").append("=").append(secretKey);
String sign = MD5.MD5Encode(sb.toString(), CharsetUtils.utf);
return sign;
}

/**
* 是否需要對引數進行編碼
*
* @param source
* @return
*/
public static String urlEncode(String source) {
return UriUtils.encode(source, StandardCharsets.UTF_8);
}


/**
* Object 轉陣列
*
* @param obj
* @return
*/
public static byte[] toByteArray(Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray();
oos.close();
bos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return bytes;
}


public static void main(String[] args) {

// System.out.println(urlEncode("傻瓜蛋bbbbsadghthas"));
// Map<String,String> map = new HashMap<>();
// map.put("digaln", "1");
// map.put("adgdge", "hello");
// map.put("fgfg", "abc");
// map.put("啥", "455456");
// map.put("zff", "72");
// map.put("sgfsge", "4242");
// map.put("bgsof", "424");
// System.out.println("排序前:" + map);
// Map<String, String> s = sortByKey(map,"2");
// String sign = getSign(s,"dgoigjoihagooaeag");
// System.out.println("排序後:" + s );

}

}


——————————————————————————————————————————————————————————————————————————————————————————————


import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;


/**
* @author puxiaozhe
* @description 繼承過濾器
* @date 2020-08-12
**/
@Component
@WebFilter(filterName="HttpServletRequestReplacedFilter",urlPatterns="/*")
public class HttpServletRequestReplacedFilter implements Filter {


@Override
public void init(FilterConfig arg0) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest) {
requestWrapper = new RequestReaderHttpServletRequestWrapper((HttpServletRequest) request);
}
//獲取請求中的流如何,將取出來的字串,再次轉換成流,然後把它放入到新request物件中。
// 在chain.doFiler方法中傳遞新的request物件
if (requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}

@Override
public void destroy() {

}
}


——————————————————————————————————————————————————————————————————————————————————————————————



import org.springframework.util.StreamUtils;

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;

/**
* @author puxiaozhe
* @description 繼承HttpServletRequestWrapper類
* @date 2020-08-12
**/
public class RequestReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

private byte[] requestBody = null;//用於將流儲存下來

public RequestReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException{
super(request);
requestBody = StreamUtils.copyToByteArray(request.getInputStream());
}

@Override
public ServletInputStream getInputStream() throws IOException {

final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);

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) {

}
};
}

@Override
public BufferedReader getReader() throws IOException{
return new BufferedReader(new InputStreamReader(getInputStream()));
}

}


import com.yicheplatform.shenzhen.utils.ClientUtils;
import lombok.Data;

import java.io.Serializable;

/**
* @Description:
* @Author: zhangdonghai
* @Date: Create in 2020/6/29
*/
@Data
public class ResponseData<T> implements Serializable {

private static final long serialVersionUID = 1L;

private String message;//錯誤提示中文

private T obj;//資料資訊/錯誤詳細資訊

private Integer state;

public ResponseData() {
}

public ResponseData(String msg, Integer state, Object result) {
}

public ResponseData(Integer state, String message, T obj) {
this.state = state;
this.message = message;
this.obj = obj;
}

public static ResponseData buildOk() {
return new ResponseData(ClientUtils.STATE_SUCCESS, ClientUtils.OK_MSG, null);
}

public static ResponseData buildOk(String msg) {
return new ResponseData(ClientUtils.STATE_SUCCESS, msg, null);
}

public static ResponseData buildOk(String msg, Object obj) {
return new ResponseData(ClientUtils.STATE_SUCCESS, msg, obj);
}

public static ResponseData buildOk(Object result) {
return new ResponseData(ClientUtils.STATE_SUCCESS, ClientUtils.OK_MSG, result);
}

public static ResponseData buildFail(String message,int state,Object o) {
return new ResponseData( message, ClientUtils.STATE_FAIL, null);

}

public static ResponseData buildStateFail(String message) {
return new ResponseData(ClientUtils.STATE_SYSTEM_ERROR,message,null);
}

public static ResponseData buildFail(String msg) {
return new ResponseData(ClientUtils.STATE_FAIL, msg, null);
}

public static ResponseData buildFail(String msg, Object result) {
return new ResponseData(ClientUtils.STATE_FAIL, msg, result);
}

public static ResponseData buildFail(int state, String msg,Object o) {
return new ResponseData(ClientUtils.STATE_FAIL, msg, null);
}

public static ResponseData buildFail(String msg, Integer state, Object result) {
return new ResponseData(msg, ClientUtils.STATE_FAIL, result);
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public T getObj() {
return obj;
}

public void setObj(T obj) {
this.obj = obj;
}

}