之前我们平时在项目中遇到异常,用try-catch这种标准的捕获方式处理就可以解决问题,但是在每个接口中都这么写,这种重复造轮子的事情对于我们程序员当然是不太愿意的。
然而我们可以在springboot项目中利用@ControllerAdvice 这个注解可以更好的实现异常的捕获处理。
@ControllerAdvice,是spring3.2提供的新注解,从名字上就可以看出大体的意思是控制器增强。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
}
没有什么特别之处,该注解使用@Component注解,这样的话当我们使用
@ControllerAdvice注解内部可以使用@ExceptionHandler、@InitBinder、@ModelAttribute的方法应用到所有的@RequestMapping注解的方法。不过我们这里只使用@ExceptionHandler。
创建 ExceptionController,并添加 @ControllerAdvice注解。
package com.left.config;
import com.left.druid.utils.Exception.ErrorLogsUtil;
import com.left.enums.CodeEnums;
import com.left.pub.LpayException;
import com.left.pub.ResponseData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.method.annotation.MethodArgumentTypeMismatchException;
/**
* Created by pillar on 2017/3/27.
* qq 347637454
*/
@ControllerAdvice
public class ExceptionHandlers {
Logger logger = LoggerFactory.getLogger(ExceptionHandlers.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResponseData handle(Exception e) {
ErrorLogsUtil.error(e); //将异常写入数据库
if (e instanceof LpayException) {
LpayException pillarException = (LpayException) e;
return new ResponseData(pillarException.getStatus());
}else if (e instanceof MethodArgumentTypeMismatchException){
return new ResponseData(CodeEnums.PARAM_TYPE_ERROR,(Object)((MethodArgumentTypeMismatchException) e).getName());
}else {
logger.info(e.toString());
e.printStackTrace();
return new ResponseData(CodeEnums.ERROR);
}
}
}
其中ResponseData类为封装的统一返回对象。
ResponseData:
package com.left.pub;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.left.enums.CodeEnums;
import java.io.Serializable;
/**
*
* @date 2017/3/27
* qq 347637454
* 统一返回对象
*/
public class ResponseData implements Serializable{
/**
* 返回数据
*/
private Object data;
/**
* 错误描述
*/
private String msg;
private int code;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String sign;
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public ResponseData(CodeEnums status) {
this.msg = status.getMessage();
this.code = status.getCode();
}
public ResponseData() {
}
public ResponseData(Object data,String api_key){
this.data = data;
this.msg = CodeEnums.SUCCESS.getMessage();
this.code = CodeEnums.SUCCESS.getCode();
this.sign = api_key;
}
public ResponseData(CodeEnums enums,Object data) {
this.data = data;
this.msg = enums.getMessage();
this.code = enums.getCode();
}
public ResponseData(int code,String msg){
this.code =code;
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
@Override
public String toString() {
return "ResponseData{" +
"data=" + data +
", msg='" + msg + '\'' +
", code=" + code +
", sign='" + sign + '\'' +
'}';
}
}
其中还有句代码为将异常写入数据库,需要ErrorLogsUtil.java工具类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @Date 14:29 2018/05/29
* @Description 错误日志工具
*/
public class ErrorLogsUtil {
/**
* @param: [e]
* @return void
* @Description 打印错误日志并保存到数据库
*/
public static void error(Exception e) {
StackTraceElement stackTraceElement= e.getStackTrace()[0];
Connection con = null;
try {
Class.forName(MySqlConfig.driver);
con = (Connection) DriverManager.getConnection(MySqlConfig.url, MySqlConfig.username, MySqlConfig.password);
} catch (SQLException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
PreparedStatement ps = null;
String sql = "INSERT INTO itc_error_logs VALUES (UUID(), NOW(), ?, ?)";
try {
ps = con.prepareStatement(sql);
//打印日志,错在第几行
String errorInfo = e.toString()+",errorMassage:"+stackTraceElement+","+"errorLine:"+stackTraceElement.getLineNumber();
ps.setString(1, errorInfo);
ps.execute();
} catch (SQLException e1) {
e1.printStackTrace();
} finally {
try {
if(ps != null) {
ps.close();
}
if(con != null) {
con.close();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
}
MySqlConfig类:
import com.alibaba.druid.pool.DruidDataSource;
import com.left.druid.utils.DataSourceEnum;
import com.left.druid.utils.LocalThreadDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**********************************************
* @author pillar
* @date ${DATE}
**********************************************/
@Configuration
@MapperScan(basePackages = MySqlConfig.PACKAGE)
public class MySqlConfig{
static final String PACKAGE = "com.left";
@Value("${spring.datasource.url}")
public static String url;
@Value("${spring.datasource.username}")
public static String user;
@Value("${spring.datasource.password}")
public static String password;
@Value("${spring.datasource.driverClassName}")
public static String driverClass;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.filters}")
private String filters;
@Value("${spring.datasource.publicKey}")
private String publicKey;}
这样后台的异常信息就可以统一保存到数据库了。
最后如果你们公司的前端够闲的话,最好是做个前端页面展示,这样就不用连数据库查看,直接在前端展示,更为直观方便。