通过注解@ControllerAdvice和@ExceptionHandler({Exception.class})捕获异常,利用注解@ModelAttribute获取请求参数
代码如下:
import org.apache.commons.io.IOUtils;
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;
/**
* 用于重复读取requestBody
*/
public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
private BufferedReader reader;
private ServletInputStream inputStream;
public ContentCachingRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
loadBody(request);
}
private void loadBody(HttpServletRequest request) throws IOException {
body = IOUtils.toByteArray(request.getInputStream());
inputStream = new RequestCachingInputStream(body);
}
public byte[] getBody() {
return body;
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (inputStream != null) {
return inputStream;
}
return super.getInputStream();
}
@Override
public BufferedReader getReader() throws IOException {
if (reader == null) {
reader = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
}
return reader;
}
private static class RequestCachingInputStream extends ServletInputStream {
private final ByteArrayInputStream inputStream;
public RequestCachingInputStream(byte[] bytes) {
inputStream = new ByteArrayInputStream(bytes);
}
@Override
public int read() throws IOException {
return inputStream.read();
}
@Override
public boolean isFinished() {
return inputStream.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readlistener) {
}
}
}
过滤器filter:
import org.springframework.stereotype.Component;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
public class LedgerReportFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
chain.doFilter(requestWrapper, response);
}
@Override
public void destroy() {
}
}
异常统一处理:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lenovo.lsump.ledger.ledgerpostingreportservice.domain.document.ExceptionLog;
import com.lenovo.lsump.ledger.ledgerpostingreportservice.domain.repository.mongo.ExceptionLogRepository;
import com.lenovo.lsump.ledger.ledgerpostingreportservice.filter.ContentCachingRequestWrapper;
import feign.FeignException;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {
private static String REQUESTBODY = "requestBodyMessage";
@Autowired
ExceptionLogRepository exceptionLogRepository;
@ExceptionHandler({Exception.class})
public Map<String, Object> handleException(HttpServletRequest req, Exception e) throws Exception {
try {
String uri = req.getRequestURI();
ExceptionLog exceptionLog = new ExceptionLog();
exceptionLog.setCreateDate(new Date());
Object body = req.getAttribute(REQUESTBODY);
if (body != null) exceptionLog.setRequestBody(body.toString());
exceptionLog.setUri(uri);
Map<String, String[]> parameterMap = req.getParameterMap();
if (!parameterMap.isEmpty()) {
ObjectMapper objectMapper = new ObjectMapper();
exceptionLog.setRequestParams(objectMapper.writeValueAsString(parameterMap));
}
Enumeration<String> headerNames = req.getHeaderNames();
Map<String, String> headers = new HashMap<>();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.put(headerName, req.getHeader(headerName));
}
if (!headers.isEmpty()) {
ObjectMapper objectMapper = new ObjectMapper();
exceptionLog.setRequestHeaders(objectMapper.writeValueAsString(headers));
}
exceptionLog.setMessage(e.toString());
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw, true));
exceptionLog.setStackTrace(sw.toString());
exceptionLogRepository.save(exceptionLog);
} catch (Exception ex) {
}
throw e;
}
/**
* 由于body在接口读取后无法获取,这里把body提前取出放到参数中,在上面处理异常时使用
*/
@ModelAttribute
public void getBobyInfo(HttpServletRequest request) {
//获取requestBody
try {
ContentCachingRequestWrapper requestWapper = null;
if (request instanceof HttpServletRequest) {
requestWapper = (ContentCachingRequestWrapper) request;
}
String body = IOUtils.toString(requestWapper.getBody(), request.getCharacterEncoding());
request.setAttribute(REQUESTBODY, body);
} catch (Exception e) {
}
}
@ExceptionHandler(FeignException.class)
public Map<String, Object> handleException(FeignException feignException, HttpServletResponse response) {
ObjectMapper objectMapper = new ObjectMapper();
try {
String message = feignException.getMessage();
if (!message.contains("{")) {
message = feignException.contentUTF8();
}
String originalBody = message;
Map<String, Object> map = objectMapper.readValue(originalBody, Map.class);
response.setStatus((Integer) map.get("status"));
return map;
} catch (Exception e) {
throw feignException;
}
}
}