springmvc请求参数异常统一处理,结合钉钉报告信息定位bug位置
参考之前一篇博客:springmvc请求参数异常统一处理
1、ExceptionHandlerController
package com.oy.controller; import java.text.MessageFormat;
import java.util.ResourceBundle; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; import com.alibaba.fastjson.JSONObject; import com.oy.exception.ForbiddenException;
import com.oy.exception.JwebException;
import com.oy.utils.ErrCode;
import com.oy.utils.Response;
import com.oy.utils.UtilFunctions; @ControllerAdvice
public class ExceptionHandlerController { @ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public JSONObject runtimeExceptionHandler(RuntimeException ex) {
UtilFunctions.log.error("runtimeExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
UtilFunctions.reportError("runtimeExceptionHandler: " + ex.toString(), ex);
JSONObject response = new JSONObject();
response.put("message", "Internal Server Error");
return response;
} @ExceptionHandler(NullPointerException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public JSONObject nullPointerExceptionHandler(NullPointerException ex) {
UtilFunctions.log.error("nullPointerExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
UtilFunctions.reportError("runtimeExceptionHandler: " + ex.toString(), ex);
JSONObject response = new JSONObject();
response.put("message", "Internal Server Error");
return response;
} /*----- REQUEST ERROR -----*/
@ExceptionHandler({ ForbiddenException.class })
@ResponseStatus(HttpStatus.FORBIDDEN)
@ResponseBody
public JSONObject requestForbidden(ForbiddenException ex) {
UtilFunctions.log.error("ForbiddenExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
JSONObject response = new JSONObject();
response.put("message", ex.getMessage());
return response;
} @ExceptionHandler({ TypeMismatchException.class })
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public JSONObject requestTypeMismatch(TypeMismatchException ex) {
UtilFunctions.log.error("TypeMismatchExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
JSONObject response = new JSONObject();
// response.put("message", "Bad Request");
// response.put("message", "Bad Request, parameter type of " + ex.getPropertyName() + " need be " + ex.getRequiredType()); if (Double.class.equals(ex.getRequiredType()) || Integer.class.equals(ex.getRequiredType())) {
response.put("message", "Bad Request, " + ex.getValue() + " not a number");
} else {
String strTemplate = "Bad Request, {0} is invalid, a type of {1} is needed";
response.put("message", MessageFormat.format(strTemplate, ex.getValue(), ex.getRequiredType().getName()));
}
return response;
} @ExceptionHandler({ MissingServletRequestParameterException.class })
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public JSONObject requestMissingServletRequest(MissingServletRequestParameterException ex) {
UtilFunctions.log.error("MissingServletRequestParameterExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
JSONObject response = new JSONObject();
// response.put("message", "Bad Request");
String strTemplate = "Bad Request, param:{0} is required, type:{1}";
response.put("message", MessageFormat.format(strTemplate, ex.getParameterName(), ex.getParameterType()));
return response;
} @ExceptionHandler({ NoSuchRequestHandlingMethodException.class })
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public JSONObject NoSuchRequestHandlingMethodExceptionHandler(NoSuchRequestHandlingMethodException ex) {
UtilFunctions.log.error("NoSuchRequestHandlingMethodExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
JSONObject response = new JSONObject();
response.put("message", "Not Found");
return response;
} /*----- REQUEST ERROR -----*/
@ExceptionHandler({ HttpMessageNotReadableException.class })
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public JSONObject requestNotReadable(HttpMessageNotReadableException ex) {
UtilFunctions.log.error("HttpMessageNotReadableExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
JSONObject response = new JSONObject();
response.put("message", "Bad Request");
return response;
} @ExceptionHandler({ HttpRequestMethodNotSupportedException.class })
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ResponseBody
public JSONObject request405(HttpRequestMethodNotSupportedException ex) {
UtilFunctions.log.error("HttpRequestMethodNotSupportedExceptionHandler, msg: {}, exception: {}", ex.toString(), ex);
JSONObject response = new JSONObject();
// response.put("message", "Method Not Allowed");
response.put("message", ex.getMessage());
return response;
} @ExceptionHandler({ JwebException.class })
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public JSONObject jwebExceptionHandler(JwebException ex, HttpServletRequest request) {
UtilFunctions.log.error("jwebExceptionHandler, info: {}, exception: {}", ex.getMessage(), ex);
UtilFunctions.reportError("jwebExceptionHandler, " + ex.toString(), null);
//JSONObject response = new JSONObject();
//response.put("code", ErrCode.SER_INTERNAL_ERR);
//response.put("message", ex.getMessage());
//response.put("message", "The system is busy. Please try again later.");
ResourceBundle resourceBundle = (ResourceBundle) request.getAttribute("resourceBundle");
String message = UtilFunctions.getMessage(resourceBundle, "SYSTEM_BUSY");
return new Response(ErrCode.SER_INTERNAL_ERR, message).toJson();
}
}
2、springmvc全局异常捕获,整合钉钉打印异常相关信息
public class UtilFunctions {
public static Logger log = LoggerFactory.getLogger("jweb");
public static void reportError(String msg, Exception err) {
if (err != null) {
log.error("msg:{}, err:{}", msg, err);
}
JSONObject content = new JSONObject();
//content.put("content", "hostname:" + Config.HOSTNAME + "\n" + "errMsg:" + msg);
content.put("content", "hostname:" + Config.HOSTNAME + "\n" + "errMsg:" + msg + "\n" + getStackTraceInfo(err));
JSONObject obj = new JSONObject();
obj.put("msgtype", "text");
obj.put("text", content.toString());
String query = obj.toString();
try {
URL url = new URL("https://oapi.dingtalk.com/robot/send?access_token=" + Config.DINGTOKEN);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.connect();
try (OutputStream os = connection.getOutputStream()) {
os.write(query.getBytes("UTF-8"));
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String printStackTraceToString(Throwable t) {
if (t == null) {
return "";
}
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.getBuffer().toString();
} finally {
if (sw != null) {
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (pw != null) {
pw.close();
}
}
}
public static String getStackTraceInfo(Throwable t) {
String stackTraceInfo = "";
String stackTrace = printStackTraceToString(t);
String regex = "at com.oy(\\S*)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(stackTrace);
while (matcher.find()) {
stackTraceInfo += matcher.group() + "\n";
// UtilFunctions.log.info("===== matcher.group:{}" + matcher.group());
}
return stackTraceInfo;
}
}
3、测试
3.1、代码出现RuntimeException,比如 int a = 1/0; 钉钉报告信息:
hostname:APC058
errMsg:runtimeExceptionHandler:java.lang.ArithmeticException:/by zero
at com.oy.controller.TradeController.getOrder(TradeController.java:220)
通过钉钉报告信息可以定位bug位置是TradeController#getOrder()方法220行。
3.2、手动抛出JwebException
注意:不要轻易抛出JwebException,即使时try...catch...捕获异常时。因为抛出JwebException,则程序交给ExceptionHandlerController来统一处理,并且程序中断。
需要根据业务来判断,比如需求:登陆成功后记录登陆信息,要记录ip及国家城市信息,如果查询不到城市信息,如果抛出JwebException,则导致登陆失败,这是不可以的。此种情况可以记录log,发送钉钉。
if (true) {
String errMsg = MessageFormat.format("TradeController#getOrder error, tradeOrder:{0}, uid:{1}, hashId:{2}", tradeOrder, uid, hashId);
throw new JwebException(errMsg);
}
钉钉报告信息:
hostname:APC058
errMsg:jwebExceptionHandler, com.oy.exception.JwebException:TradeController#getOrder error, tradeOrder:null, uid:222, hashId:xxx
通过钉钉报告信息可以定位bug位置是TradeController#getOrder()方法,tradeOrder为null。
4、其他
4.1、上面ExceptionHandlerController中捕获JwebException后,通过注解@ResponseStatus(HttpStatus.OK)给前端返回http状态码200,并返回json数据:
{
"code": 50005,
"message": "The system is busy. Please try again later!"
}
4.2、前面代码中ResourceBundle是用来支持国际化的。
4.3、将异常栈信息保存为一个字符串
public static String printStackTraceToString(Throwable t) {
if (t == null) {
return "";
}
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.getBuffer().toString();
} finally {
if (sw != null) {
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (pw != null) {
pw.close();
}
}
}
4.4、从异常栈信息中截取需要的数据
@Test
public void test3() {
try{
int a = 1/0;
} catch(Exception e) {
System.out.println(printStackTraceToString(e));
getStackTraceInfo(e);
}
} public static String getStackTraceInfo(Throwable t) {
String stackTraceInfo = ""; String stackTrace = printStackTraceToString(t);
String regex = "com.oy.Hello(\\S*)";
// String regex = "at (\\S*)$"; // 截取异常栈最后一句。$表示字符串结尾
Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(stackTrace);
while (matcher.find()) {
stackTraceInfo += matcher.group();
System.out.println("=====matcher.group:{}" + matcher.group());
}
return stackTraceInfo;
}
springmvc请求参数异常统一处理,结合钉钉报告信息定位bug位置的更多相关文章
- springmvc请求参数异常统一处理
1.ExceptionHandlerController package com.oy.controller; import java.text.MessageFormat; import org.s ...
- SpringMVC请求参数接收总结
前提 在日常使用SpringMVC进行开发的时候,有可能遇到前端各种类型的请求参数,这里做一次相对全面的总结.SpringMVC中处理控制器参数的接口是HandlerMethodArgumentRes ...
- SpringMVC请求参数接收总结(一)
前提 在日常使用SpringMVC进行开发的时候,有可能遇到前端各种类型的请求参数,这里做一次相对全面的总结.SpringMVC中处理控制器参数的接口是HandlerMethodArgumentRes ...
- SpringMVC请求参数总结
前提 在日常使用SpringMVC进行开发的时候,有可能遇到前端各种类型的请求参数,这里做一次相对全面的总结.SpringMVC中处理控制器参数的接口是HandlerMethodArgumentRes ...
- 2.5万字长文简单总结SpringMVC请求参数接收
这是公众号<Throwable文摘>发布的第22篇原创文章,暂时收录于专辑<架构与实战>.暂定下一篇发布的长文是<图文分析JUC同步器框架>,下一篇发布的短文是&l ...
- springmvc请求参数异常处理
接着上一篇<springmvc 通过异常增强返回给客户端统一格式>讲通过spring ControllerAdvice对各种异常进行拦截处理,统一格式返回给客户端. 接下来我们更精细的讲, ...
- springmvc 请求参数解析细节
springmvc 的请求流程,相信大家已经很熟悉了,不熟悉的同学可以参考下资料! 有了整体流程的概念,是否对其中的实现细节就很清楚呢?我觉得不一定,比如:单是参数解析这块,就是个大学问呢? 首先,我 ...
- SpringMVC请求参数注解两个小问题
今天遇到使用SpringMVC请求注解遇到的两个小问题: 如果用@requestBody注解,则请求体内容类型一般要为application/json,如果其类型为multipart/form-dat ...
- SpringMVC请求参数和响应结果全局加密和解密
前提 前段时间在做一个对外的网关项目,涉及到加密和解密模块,这里详细分析解决方案和适用的场景.为了模拟真实的交互场景,先定制一下整个交互流程.第三方传输(包括请求和响应)数据报文包括三个部分: 1.t ...
随机推荐
- 关于confusion_matrix()返回的矩阵的索引顺序(类别顺序)
转载至:https://blog.csdn.net/m0_38061927/article/details/77198990 1.混淆矩阵 混淆矩阵是机器学习中总结分类模型预测结果的情形分析表,以矩阵 ...
- 【Qt开发】Qt5.7串口开发
QT5有专门的串口类: QSerialPort:提供访问串口的功能 QSerialPortInfo:提供系统中存在的串口的信息 具体使用方法: 1.在pro文件中加入: QT += seria ...
- switch-case分支结构总结
1,格式 switch(表达式){ case 常量1:执行语句1: case 常量1:执行语句1: ... ... case 常量n:执行语句n: default:执行语句:} 2,说明: 根据swi ...
- hdoj4507(数位dp)
题目链接:https://vjudge.net/problem/HDU-4507 题意:定义如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关—— 1.整数中某一位是7: 2.整数的每一位 ...
- 一篇文章看懂Java并发和线程安全(一)
一.前言 长久以来,一直想剖析一下Java线程安全的本质,但是苦于有些微观的点想不明白,便搁置了下来,前段时间慢慢想明白了,便把所有的点串联起来,趁着思路清晰,整理成这样一篇文章. 二.导读 1.为什 ...
- Android快捷键大全
参考来源:https://mp.weixin.qq.com/s/T809p17Wt8XHkbLwcQf9ow 1,Ctrl + J 快捷代码列表 2,Ctrl+Alt+O 这个快捷键可以自动导包或删 ...
- [LeetCode] 223.矩形面积
题目链接: https://leetcode-cn.com/problems/rectangle-area 难度:中等 通过率:41.3% 题目描述: 在 二维 平面上计算出两个 由直线构成的 矩形重 ...
- Python中的四种数据结构
Python中的内置数据结构(Built-in Data Structure):列表list.元组tuple.字典dict.集合set,涵盖的仅有部分重点. 目录: 一.列表list 二.元组tup ...
- 编辑器IDE之VSCode
很多时候面临换项目组,公司内部换等等,需要清除之前的权限,电脑更换等... 确实很烦人,所以记录也是给自己下次更加快速方便的使用 插件安装 个人常用的一些插件,发现好用的会更新 插件名 功能 vsco ...
- postgresql 相关操作
1.root 用户,执行 service postgresql restart service postgresql start --启动 2.查看数据库状态 /etc/init.d/postgre ...