使用拦截器处理繁琐的前置条件判定
背景
在开发过程中,为了提高程序的健壮性,对参数的校验是必不可少的,然而使用传统的方式进行参数校验时,导致程序中存在了if xxx return xxx;处理不够优雅。虽然jfinal提供了Validator,但是使用过于繁琐,对前后端分离不友好。 在guaua工具包中的Preconditions启发下,本人利用拦截器和自定义异常实现了一个较为优雅的参数校验方法。(注:未经全面测试,仅供参考)
正文(直接上代码)
- ParaExceptionInterceptor 自定义异常拦截器(仅拦截返回值为Ret的方法)
public class ParaExceptionInterceptor implements Interceptor {
@SuppressWarnings("unchecked")
private static final List<Class<? extends Exception>> DEFAULT_EXCPTIONS = Lists.newArrayList(ParaExcetion.class);
private static List<Class<? extends Exception>> getConfigWithExceptionConfig(Invocation inv) {
ExceptionConfig config = inv.getMethod().getAnnotation(ExceptionConfig.class);
if (config == null)
config = inv.getTarget().getClass().getAnnotation(ExceptionConfig.class);
if (config != null) {
Class<? extends Exception>[] value = config.value();
return Arrays.asList(value);
}
return DEFAULT_EXCPTIONS;
}
/**
* (non-Javadoc)
* Title: intercept
* Description:对指定异常进行拦截并封装为错误信息返回
* @param inv
* @see com.jfinal.aop.Interceptor#intercept(com.jfinal.aop.Invocation)
*/
@Override
public void intercept(Invocation inv) {
try {
inv.invoke();
} catch (Exception e) {
// 若返回值类型不是Ret则将异常继续往上抛
Class<?> returnType = inv.getMethod().getReturnType();
if (!(returnType.equals(Ret.class))) {
throw e;
}
List<Class<? extends Exception>> exceptionClasses = getConfigWithExceptionConfig(inv);
for (Class<? extends Exception> exceptionClass : exceptionClasses) {
if (Objects.equals(e.getClass(), exceptionClass) || Objects.equals(e.getClass().getSuperclass(), exceptionClass)) {
inv.setReturnValue(MRetKit.buildFail(e.getMessage()));
return;
}
}
throw e;
}
}
}
- ParaExcetion 自定义异常
public class ParaExcetion extends com.iipcloud.api.exception.ParaExcetion {
/** serialVersionUID */
private static final long serialVersionUID = 4888200095167386189L;
/**
* <p>Title: </p>
* <p>Description: </p>
*/
public ParaExcetion() {
super();
}
/**
* <p>Title: </p>
* <p>Description: </p>
* @param message
* @param cause
* @param enableSuppression
* @param writableStackTrace
*/
public ParaExcetion(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
/**
* <p>Title: </p>
* <p>Description: </p>
* @param message
* @param cause
*/
public ParaExcetion(String message, Throwable cause) {
super(message, cause);
}
/**
* <p>Title: </p>
* <p>Description: </p>
* @param message
*/
public ParaExcetion(String message) {
super(message);
}
/**
* <p>Title: </p>
* <p>Description: </p>
* @param cause
*/
public ParaExcetion(Throwable cause) {
super(cause);
}
}
- ExceptionConfig 异常注解
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
public @interface ExceptionConfig {
Class<? extends Exception>[] value();
}
- ParaCheckKit 配套工具类
public class ParaCheckKit {
private ParaCheckKit() {
super();
}
public static void requireFalse(boolean expression, String errMsgFormat, Object... args) {
requireTrue(!expression, String.format(errMsgFormat, args));
}
/**
* Title: checkPara
* Description: 检查表达式是否满足,若不满足则抛出异常
* Date: 2020年2月25日
* @param expression
* @param errMsg
* @throws IllegalParaException
*/
public static void requireTrue(boolean expression, String errMsg) {
if (!expression) {
throw new IllegalParaException(errMsg);
}
}
public static void requireTrue(boolean expression, String errMsgFormat, Object... args) {
if (!expression) {
throw new IllegalParaException(String.format(errMsgFormat, args));
}
}
/**
* Title: requireNotNull
* Description: 判断指定对象是否为空,为空则抛出异常
* Date: 2020年2月25日
* @param obj
* @param errMsg
* @throws IllegalParaException
*/
public static void requireNotNull(Object obj, String errMsg, Object... args) {
requireTrue(Objects.nonNull(obj), errMsg, args);
}
public static void requireNull(Object obj, String errMsg, Object... args) {
requireTrue(Objects.isNull(obj), errMsg, args);
}
/**
* Title: requireNotBlank
* Description:判断指定字符串是否为空,为空则抛出异常
* Date: 2020年2月25日
* @param str
* @param errMsg
* @throws com.iipmes.exception.IllegalParaException
*/
public static void requireNotBlank(String str, String errMsg, Object... args) {
requireTrue(StrKit.notBlank(str), errMsg, args);
}
public static void requireBlank(String str, String errMsg, Object... args) {
requireTrue(StrKit.isBlank(str), errMsg, args);
}
/**
* Title: requireNotEmpty
* Description:
* Date: 2020年2月25日
* @param obj
* @param errMsg
* @throws com.iipmes.exception.IllegalParaException
*/
public static void requireNotEmpty(Object obj, String errMsg, Object... args) {
requireTrue(IIPUtil.notEmpty(obj), errMsg, args);
}
public static void requireEmpty(Object obj, String errMsg, Object... args) {
requireTrue(IIPUtil.isEmpty(obj), errMsg, args);
}
/**
* Title: checkModel
* Description: 检查model中的指定字段是否为空,为空则抛出异常
* Date: 2020年2月25日
* @param model
* @param fields
*/
public static void checkModel(Model<? extends Model<?>> model, List<String> fields, String errMsg, Object... args) {
requireTrue(fieldNotEmpty(model, fields), errMsg, args);
}
public static boolean fieldNotEmpty(Model<? extends Model<?>> model, String... fields) {
return fieldNotEmpty(model, Arrays.asList(fields));
}
/**
* Title: fieldNotEmpty
* Description: 检查Model中指定的字段
* Date: 2020年2月25日
* @param model
* @param fields
* @return
*/
public static boolean fieldNotEmpty(Model<? extends Model<?>> model, List<String> fields) {
for (String field : fields) {
if (ObjectKit.isEmpty(model.get(field))) {
return false;
}
}
return true;
}
}
- 使用demo
@Before(ParaExceptionInterceptor.class)
public class DemoService {
public Ret doSomeThing(Record record, Model<? extends Model<?>> model) {
ParaCheckKit.requireNotNull(record.getStr("id"), "id can not be null");
ParaCheckKit.checkModel(model, Lists.newArrayList("id,name"), "id required, name required");
// do Something
return Ret.ok();
}
}
注意事项
-
配合静态方法导入更为舒爽
1.jpg
- 以上提供的只是一个简单的demo,适用于servce层,Controller层使用需要改动(默认无返回值,可自定义一个拦截器处理返回值返回给前端页面,下面是一个简单示例)。
public class ActionInterceptor implements Interceptor {
/**
* (non-Javadoc)
* <p>Title: intercept</p>
* <p>Description: </p>
* @param inv
* @see com.jfinal.aop.Interceptor#intercept(com.jfinal.aop.Invocation)
*/
@Override
public void intercept(Invocation inv) {
inv.invoke();
Class<?> returnType = inv.getMethod().getReturnType();
if (returnType.equals(Void.class)) {
return;
}
Object returnValue = inv.getReturnValue();
if (returnType.equals(String.class)) {
inv.getController().render((String) returnValue);
} else if (returnType.equals(Ret.class)) {
inv.getController().renderJson((Ret) returnValue);
} else {
inv.getController().renderJson(RetKit.buildOk(returnValue));
}
}
}
网友评论