说明文档更新:https://gitee.com/heHouHui/jfinal_validated/wikis/Home
提供异常统一扑捉实现IErrorRequestResponseAdvice类即可:
/** * @Auther: hehh * @Date: 2018/12/27 12:40 * @Description: 注意异常向下兼容 */ public interface IErrorRequestResponseAdvice<T extends Throwable,E extends Render>{ /**验证支持*/ boolean supports(T throwable); /**异常处理*/ E laterBodyWrite(T throwable,RenderManager renderManager,String[] urlPara,Action action,int code); }
提供响应处理链实现IResponseAdvice即可:
/** * @Auther: hehh * @Date: 2018/12/26 18:00 * @Description: 响应切面 */ public interface IResponseAdvice<T extends Render> { /** * 排序 * @return */ default int sort(){ return Integer.MAX_VALUE;} /** * 是否支持 * @param clazz 响应的render calss * @param t render * @return */ boolean supports(Class<? extends Render> clazz, Render t); /** * 处理响应 * @param rqquestBody 响应render * @param renderManager render工厂 * @param urlPara 请求url * @param action 请求action * @param controller 请求controller * @return */ T beforeBodyWrite(Render rqquestBody, RenderManager renderManager,String[] urlPara,Action action, Controller controller); }
实现方案替换actionHander在不干扰源代码的情况下,插入自定义功能
/** * @Auther: hehh * @Date: 2018/12/26 17:41 * @Description: */ public class ActionHandlerAdivce extends ActionHandler { private static final Log log = Log.getLog(ActionHandlerAdivce.class); /** 响应处理类 */ public static Map<Class<? extends Render>,List<? extends IResponseAdvice<? extends Render>>> responseAdviceMap = new ConcurrentHashMap(); /**异常处理器*/ public static Map<Class<? extends Throwable>,IErrorRequestResponseAdvice> errorAdviceMap = new ConcurrentHashMap<>(); /*** * 获取异常处理器 * @param aClass * @return */ private List<IErrorRequestResponseAdvice> getErrorAdvice(Class<? extends Throwable> aClass){ if(aClass == null){ return null; } List<Class<? extends Throwable>> temp = new ArrayList<>(); errorAdviceMap.keySet().forEach(new Consumer<Class<? extends Throwable>>() { @Override public void accept(Class<? extends Throwable> bClass) { if(bClass.isAssignableFrom(aClass) || bClass.equals(aClass)){ temp.add(bClass); } } }); if(CollUtil.isEmpty(temp)){return null;} List<Class<? extends Throwable>> sort = CollUtil.sort(temp, new Comparator<Class<? extends Throwable>>() { @Override public int compare(Class<? extends Throwable> o1, Class<? extends Throwable> o2) { return o1.isAssignableFrom(o2) ? -1 : 1; } }); if(CollUtil.isEmpty(sort)){return null;} List<IErrorRequestRequestAdvice> advice = new ArrayList<>(); sort.forEach(new Consumer<Class<? extends Throwable>>() { @Override public void accept(Class<? extends Throwable> cClass) { advice.add(errorAdviceMap.get(cClass)); } }); return advice; } /** * handle * 1: Action action = actionMapping.getAction(target) * 2: new Invocation(...).invoke() * 3: render(...) * * @param target * @param request * @param response * @param isHandled */ @Override public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { if (target.indexOf('.') != -1) { return ; } isHandled[0] = true; String[] urlPara = {null}; Action action = actionMapping.getAction(target, urlPara); if (action == null) { String qs = request.getQueryString(); String error = "404 Action Not Found: " + (qs == null ? target : target + "?" + qs); if (log.isWarnEnabled()) { log.warn(error); } List<IErrorRequestResponseAdvice> errorAdvice = getErrorAdvice(RenderException.class); Render render = renderManager.getRenderFactory().getErrorRender(404).setContext(request, response); if(CollUtil.isEmpty(errorAdvice)){ render.render(); return; }else{ throw new RenderException(error); } } /**跨域在前*/ if(!RequestBodyUtil.configurationCrossOrigin(action,request,response)){ renderManager.getRenderFactory().getJsonRender(new ErrorResult<>(Code.REST_ERROR,"请求错误")).setContext(request,response).render(); return; } RequestBodyUtil.resolutionBody(action,request);//解析body Controller controller = null; try { controller = controllerFactory.getController(action.getControllerClass()); if (injectDependency) {com.jfinal.aop.Aop.inject(controller);} CPI._init_(controller,action,request,response,urlPara[0]); //TODO 进入拦截器前 if (devMode) { if (ActionReporter.isReportAfterInvocation(request)) { new Invocation(action, controller).invoke(); ActionReporter.report(target, controller, action); } else { ActionReporter.report(target, controller, action); new Invocation(action, controller).invoke(); } } else { new Invocation(action, controller).invoke(); } Render render = controller.getRender(); if (render instanceof ForwardActionRender) { String actionUrl = ((ForwardActionRender)render).getActionUrl(); if (target.equals(actionUrl)) { throw new RuntimeException("The forward action url is the same as before."); } else { handle(actionUrl, request, response, isHandled); } return ; } if (render == null) { render = renderManager.getRenderFactory().getDefaultRender(action.getViewPath() + action.getMethodName()); } //TODO 响应前 执行响应处理链 if(MapUtil.isNotEmpty(responseAdviceMap)){ List<? extends IResponseAdvice<? extends Render>> iResponseAdvices = responseAdviceMap.get(render.getClass()); if(CollUtil.isNotEmpty(iResponseAdvices)){ for (IResponseAdvice<? extends Render> iResponseAdvice : iResponseAdvices) { if(iResponseAdvice.supports(render.getClass(),render)){ Render beforeRender = iResponseAdvice.beforeBodyWrite(render, renderManager, urlPara, action, controller); if(beforeRender == null){ throw new ResponseAdviceExceptor("响应处理异常:"+iResponseAdvice.getClass()+" beforeBodyWrite 方法不能返回 null."); } render = beforeRender; } } } } render.setContext(request, response, action.getViewPath()).render(); } catch (Exception e) { /**异常处理*/ List<IErrorRequestResponseAdvice> errorAdvice = getErrorAdvice(e.getClass()); if(CollUtil.isNotEmpty(errorAdvice)){ int code = e instanceof RenderException?404:(e instanceof ActionException?((ActionException)e).getErrorCode():500); errorAdvice.forEach(new Consumer<IErrorRequestRequestAdvice>() { @Override public void accept(IErrorRequestRequestAdvice iErrorRequestRequestAdvice) { if(iErrorRequestRequestAdvice.supports(e)){ Render render1 = iErrorRequestRequestAdvice.laterBodyWrite(e, renderManager, urlPara, action, code); if(render1 != null){ render1.setContext(request,response).render(); return; } } } }); }else{ //TODO 异常响应不处理 if(e instanceof RenderException){ if (log.isErrorEnabled()) { String qs = request.getQueryString(); log.error(qs == null ? target : target + "?" + qs, e); } }else if(e instanceof ActionException){ handleActionException(target, request, response, action, (ActionException)e); }else{ if (log.isErrorEnabled()) { String qs = request.getQueryString(); log.error(qs == null ? target : target + "?" + qs, e); } renderManager.getRenderFactory().getErrorRender(500).setContext(request, response, action.getViewPath()).render(); } } } finally { if (controller != null) { CPI._clear_(controller); } } } /** * 抽取出该方法是为了缩短 handle 方法中的代码量,确保获得 JIT 优化, * 方法长度超过 8000 个字节码时,将不会被 JIT 编译成二进制码 * * 通过开启 java 的 -XX:+PrintCompilation 启动参数得知,handle(...) * 方法(73 行代码)已被 JIT 优化,优化后的字节码长度为 593 个字节,相当于 * 每行代码产生 8.123 个字节 */ private void handleActionException(String target, HttpServletRequest request, HttpServletResponse response, Action action, ActionException e) { int errorCode = e.getErrorCode(); String msg = null; if (errorCode == 404) { msg = "404 Not Found: "; } else if (errorCode == 400) { msg = "400 Bad Request: "; } else if (errorCode == 401) { msg = "401 Unauthorized: "; } else if (errorCode == 403) { msg = "403 Forbidden: "; } if (msg != null) { if (log.isWarnEnabled()) { String qs = request.getQueryString(); msg = msg + (qs == null ? target : target + "?" + qs); if (e.getMessage() != null) { msg = msg + "\n" + e.getMessage(); } log.warn(msg); } } else { if (log.isErrorEnabled()) { String qs = request.getQueryString(); log.error(errorCode + " Error: " + (qs == null ? target : target + "?" + qs), e); } } e.getErrorRender().setContext(request, response, action.getViewPath()).render(); } }
加载处理器的IPlugin
/** * @Auther: hehh * @Date: 2018/12/26 09:08 * @Description: 处理响应 */ public class RequestAdivcePlugin implements IPlugin { /**初始化 响应处理器*/ private void initRequestAdivce(){ ThreadUtil.excAsync(new Runnable() { Set<Class<?>> validates = ClassUtil.scanPackageBySuper("",IResponseAdvice.class); @Override public void run() { if(CollUtil.isNotEmpty(validates)){ Map<ResponseAdviceMapSort,IResponseAdvice> responseAdviceMap = new HashMap<>(); validates.forEach(new Consumer<Class<?>>() { @Override public void accept(Class<?> aClass) { if(!ClassUtil.isAbstract(aClass) && !aClass.isInterface()){ Type t =aClass.getGenericInterfaces()[0]; //返回表示此类型实际类型参数的 Type 对象的数组 Type[]params = ((ParameterizedType) t).getActualTypeArguments(); Type param = params[0]; try { IResponseAdvice iResponseAdvice = (IResponseAdvice) aClass.newInstance(); ResponseAdviceMapSort eesponseAdviceMapSort = new ResponseAdviceMapSort(); eesponseAdviceMapSort.setAClass((Class<? extends Render>) TypeUtil.getClass(param)); eesponseAdviceMapSort.setSort(iResponseAdvice.sort()); responseAdviceMap.put(eesponseAdviceMapSort,iResponseAdvice); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } }); if(MapUtil.isNotEmpty(responseAdviceMap)){ for (ResponseAdviceMapSort responseAdviceMapSort : responseAdviceMap.keySet()) { Class<? extends Render> aClass = responseAdviceMapSort.getAClass(); if(!ActionHandlerAdivce.responseAdviceMap.containsKey(aClass)) { List<? extends IResponseAdvice<? extends Render>> responseAdvice = getResponseAdvice(aClass, responseAdviceMap); ActionHandlerAdivce.responseAdviceMap.put(aClass, responseAdvice); } } } } } },true); } /** * 初始化异常处理 */ private void initError(){ Thread thread = new Thread(new Runnable() { @Override public void run() { Set<Class<?>> validates = ClassUtil. scanPackageBySuper("",IErrorRequestResponseAdvice.class); if(CollUtil.isNotEmpty(validates)){ for (Class<?> aClass : validates) { Type t =aClass.getGenericInterfaces()[0]; //返回表示此类型实际类型参数的 Type 对象的数组 Type[]params = ((ParameterizedType) t).getActualTypeArguments(); Type param = params[0]; try { ActionHandlerAdivce. errorAdviceMap.put((Class<? extends Throwable>) TypeUtil.getClass(param), (IErrorRequestResponseAdvice)aClass.newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } }); thread.start(); } @Override public boolean start() { initRequestAdivce(); initError(); return true; } @Override public boolean stop() { return true; } /*** * 得到响应处理器 * @param clazz * @param <T> * @return */ private <T extends Render> List<IResponseAdvice<T>> getResponseAdvice(Class<T> clazz, Map<ResponseAdviceMapSort,IResponseAdvice> responseAdviceMap){ if(clazz == null || MapUtil.isEmpty(responseAdviceMap)) { return null; } /*** * 得到指定处理 T 的处理器 */ List<ResponseAdviceMapSort> filter = new ArrayList<>(); responseAdviceMap.forEach(new BiConsumer<ResponseAdviceMapSort, IResponseAdvice>() { @Override public void accept(ResponseAdviceMapSort responseAdviceMapSort, IResponseAdvice iResponseAdvice) { if (responseAdviceMapSort.getAClass(). isAssignableFrom(clazz) || responseAdviceMapSort.getAClass().equals(clazz)) { filter.add(responseAdviceMapSort); } } }); if(CollUtil.isEmpty(filter)){ return null; } /*** * 排序 */ List<ResponseAdviceMapSort> sort = CollUtil.sort(filter, new Comparator<ResponseAdviceMapSort>() { /**compare方法大于0,就把前一个数和后一个数交换, 也就是把大的数放后面了,即所谓的升序了*/ @Override public int compare(ResponseAdviceMapSort o1, ResponseAdviceMapSort o2) { return o1.getSort() - o2.getSort(); } }); List<IResponseAdvice<T>> temp = new ArrayList<>(); sort.forEach(new Consumer<ResponseAdviceMapSort>() { @Override public void accept(ResponseAdviceMapSort responseAdviceMapSort) { temp.add(responseAdviceMap.get(responseAdviceMapSort)); } }); return temp; } }
在config中替换原有的actionHander即可
/** * 配置处理器 如在规模开发中 定制Handler来实现自定义的url映射 */ public void configHandler(Handlers me) { me.setActionHandler(new ActionHandlerAdivce()); }
异常效果
异常(扑捉昨天的参数验证(action 与非action都可以))
** * @Auther: Administrator * @Date: 2018/10/8 16:40 * @Description: */ @Validated public class PoemsService extends BaseService<Poems> { public String aa(@Size(min = 5,msg = "名字长度不能小于5!") String aa){ return "xxx"; } }
部分验证代码
/**得到校验类*/ ValidateAbstract iValidate = ValidateAbstract.validates. get(parameterAnnotation.annotationType()); /**校验是否符合规则*/ if (iValidate.supports(method, parameter, parameterAnnotation.annotationType())) { /**校验*/ Result verify = iValidate.verify(parameterAnnotation, inv.getArg(i), method, parameter); /**code != 0 为失败 */ if (verify.getCode() != 0) { if (takeError != null && Result.class.isAssignableFrom(method.getReturnType())) { inv.setReturnValue(verify); return; } throw new ValidateException(verify.getMsg()); //TODO 不是action而又没接管就直接报错 } } }
扑捉
** * @Auther: hehh * @Date: 2018/12/27 13:56 * @Description: */ public class ValidateErrorAdvice implements IErrorRequestResponseAdvice<ValidateException,JsonRender>{ /** * 验证支持 * * @param throwable */ @Override public boolean supports(ValidateException throwable) { return true; } /** * 异常处理 * * @param throwable * @param renderManager * @param urlPara * @param action * @param code */ @Override public JsonRender laterBodyWrite(ValidateException throwable, RenderManager renderManager, String[] urlPara, Action action, int code) { return (JsonRender)renderManager.getRenderFactory(). getJsonRender(new ErrorResult<> (Code.PARAM_ERROR,throwable.getMessage())); } }
效果
响应效果
扑捉自定义的result
/** * @Auther: hehh * @Date: 2018/12/27 09:54 * @Description: 处理json 有数据响应 */ public class RequestJsonAdvice implements IResponseAdvice<JsonRender> { /** * 排序 * * @return */ @Override public int sort() { return 0; } /** * 是否支持 * * @param clazz 响应的render calss * @param jsonRender render * @return */ @Override public boolean supports(Class<? extends Render> clazz, Render jsonRender) { boolean b = jsonRender != null && jsonRender != null && jsonRender.getClass().equals(clazz); if(b){ JsonRender jsonRender1 = (JsonRender) jsonRender; if(StrKit.notBlank(jsonRender1.getJsonText())){ JSONObject object = new JSONObject(jsonRender1.getJsonText()); if(null == object.getInt("code")){ b = false; } } } return b; } /** * 处理响应 * * @param rqquestBody 响应render * @param renderManager render工厂 * @param urlPara 请求url * @param action 请求action * @param controller 请求controller * @return */ @Override public JsonRender beforeBodyWrite(Render rqquestBody, RenderManager renderManager, String[] urlPara, Action action, Controller controller) { JsonRender rqquestBody1 = (JsonRender) rqquestBody; System.out.println("============处理响应:"+rqquestBody1.getJsonText()); rqquestBody1 = new JsonRender("bbbbb"); return rqquestBody1; } }
原响应
@Validated @RequestBody public void index(@NotBlank(msg = "不能为空啊!!!") String name){ renderJson(ps.aa(name)); }
效果:
源码地址:https://gitee.com/heHouHui/jfinal_validated.git
有什么不对的地方,还请各位指正