新接手的项目用了jfinal框架,发现系统有很多地方没有完善,例如事务配置方面,表单提交失败后,脏数据保存到数据库里;controller层返回json数据每个方法都加入try catch,有很多重复性代码,为了使得代码更加的简洁,着手优化一下系统代码,jfinal官方文档场景应用例子太少了。话不多说,动手就是干。。
在JFinalConfig类里增加配置
public void configInterceptor(Interceptors me) {
me.add(new SessionInViewInterceptor());
//自定义异常拦截器
me.add(new ExceptionInterceptor());
// 声明式事务 方法(可以通过正则 或者 直接方法名称)
me.add(new TxByMethodRegex("(.*save.*|.*update.*|.*start.*|.*do.*|.*apply.*|.*del.*)"));
//me.add(new TxByMethods("save","update"));
}
网上有些人说在方法上面加上注解@Before(Tx.class),但我在项目中没有写上,可以实现出错时事务回滚。
它的原理过程:
public void intercept(Invocation inv) {
Config config = getConfigWithTxConfig(inv);
if (config == null)
config = DbKit.getConfig();
Connection conn = config.getThreadLocalConnection();
// 下面这段支持嵌套事务,可以忽略不看
if (conn != null) {
try {
if (conn.getTransactionIsolation() < getTransactionLevel(config))
conn.setTransactionIsolation(getTransactionLevel(config));
inv.invoke();
return ;
} catch (SQLException e) {
throw new ActiveRecordException(e);
}
}
Boolean autoCommit = null;
try {
// 1. 建立数据库连接
conn = config.getConnection();
autoCommit = conn.getAutoCommit();
config.setThreadLocalConnection(conn);
// 2. 设置事务隔离级别
conn.setTransactionIsolation(getTransactionLevel(config)); // conn.setTransactionIsolation(transactionLevel);
// 3. 设置事务手动提交
conn.setAutoCommit(false);
// 4. 反射机制调用 savePost()
inv.invoke();
// 5. 事务提交
conn.commit();
} catch (NestedTransactionHelpException e) {
if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
LogKit.logNothing(e);
} catch (Throwable t) {
// 6. 若有异常就回滚
if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}
throw t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);
}
finally {
try {
if (conn != null) {
if (autoCommit != null)
conn.setAutoCommit(autoCommit);
conn.close();
}
} catch (Throwable t) {
LogKit.error(t.getMessage(), t); // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
}
finally {
config.removeThreadLocalConnection(); // prevent memory leak
}
}
}
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.core.JFinal;
import com.ucap.base.exception.NormalException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* 全局异常处理拦截器
*
*/
public class ExceptionInterceptor implements Interceptor {
private static final Logger log = LoggerFactory.getLogger(ExceptionInterceptor.class);
@Override
public void intercept(Invocation inv) {
Controller controller = inv.getController();
HttpServletRequest request = controller.getRequest();
try {
inv.invoke();
} catch (Exception e) {
//输入到日记文件
doLog(inv, e);
//判断是否ajax请求
String header = request.getHeader("X-Requested-With");
boolean isAjax = "XMLHttpRequest".equalsIgnoreCase(header);
String msg = formatException(e);
if (isAjax) {
msg = new StringBuilder().append("{\"status\":\"0\",\"message\":\"")
.append(msg).append("\"}").toString();
controller.renderJson(msg);
} else {
String redirctUrl = request.getHeader("referer");
if (StringUtils.isBlank(redirctUrl)) {
redirctUrl = request.getRequestURI();
}
controller.setAttr("message", msg);
controller.setAttr("redirctUrl", redirctUrl);
controller.render("/webpage/pc/failed.ftl");
}
}
}
private void doLog(Invocation ai,Exception e) {
//开发模式
if(JFinal.me().getConstants().getDevMode()){
e.printStackTrace();
}
//业务异常不记录
//if( e instanceof NormalException) return;
StringBuilder sb =new StringBuilder("\n---全局异常处理拦截---\n");
sb.append("Controller:").append(ai.getController().getClass().getName()).append("\n");
sb.append("Method:").append(ai.getMethodName()).append("\n");
sb.append("Exception Type:").append(e.getClass().getName()).append("\n");
sb.append("Exception Details:");
log.error(sb.toString(), e);
}
private static String formatException(Exception e){
String message = null;
Throwable ourCause = e;
while ((ourCause = e.getCause()) != null) {
e = (Exception) ourCause;
}
String eClassName = e.getClass().getName();
//一些常见异常提示
if("java.lang.NumberFormatException".equals(eClassName)){
message = "请输入正确的数字";
}else if (e instanceof NormalException || e instanceof RuntimeException) {
message = e.getMessage();
if(StringUtils.isBlank(message))message = e.toString();
}
//获取默认异常提示
if (StringUtils.isBlank(message)){
message = "系统繁忙,请稍后再试";
}
//替换特殊字符
message = message.replaceAll("\"", "'");
return message;
}
}
NormalException 为业务异常类,继承RuntimeException