标题党了,记得以前也有人反馈想把@ActionKey("/login") 里面的 / 去掉时,变为Controller路径的续接子级,有相对路径的感觉。波总说由于ActionKey历史问题,很多人并没有写前缀 / ,JF有自动补全 / ,如果变更规则的话会导致很麻烦的升级问题。今天看到又有人反馈这个问题,可能场景是不同,想着其实可以再加一个@PathKey ,搭配@Path也未尝不可。复用@Path也可以,但是可能需要再支持一下viewPath的值才是完善的,所以先加@PathKey吧
不多说上码:
拷贝ActionKey的代码,命名为PathKey:
import java.lang.annotation.*; @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface PathKey { String value(); }
再绑定一下Action:
继承ActionMapping类为MyActionMapping,覆写方法 buildActionMapping:加入 method.getAnnotation(PathKey.class)
import com.jfinal.aop.Interceptor; import com.jfinal.aop.InterceptorManager; import com.jfinal.config.Routes; import com.jfinal.core.*; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class MyActionMapping extends ActionMapping { public MyActionMapping(Routes routes) { super(routes); } protected void buildActionMapping() { mapping.clear(); Class<?> dc; InterceptorManager interMan = InterceptorManager.me(); for (Routes routes : getRoutesList()) { for (Routes.Route route : routes.getRouteItemList()) { Class<? extends Controller> controllerClass = route.getControllerClass(); Interceptor[] controllerInters = interMan.createControllerInterceptor(controllerClass); boolean declaredMethods = routes.getMappingSuperClass() ? controllerClass.getSuperclass() == Controller.class : true; Method[] methods = (declaredMethods ? controllerClass.getDeclaredMethods() : controllerClass.getMethods()); for (Method method : methods) { if (declaredMethods) { if (!Modifier.isPublic(method.getModifiers())) continue ; } else { dc = method.getDeclaringClass(); if (dc == Controller.class || dc == Object.class) continue ; } if (method.getAnnotation(NotAction.class) != null) { continue ; } Interceptor[] actionInters = interMan.buildControllerActionInterceptor(routes.getInterceptors(), controllerInters, controllerClass, method); String controllerPath = route.getControllerPath(); String methodName = method.getName(); ActionKey ak = method.getAnnotation(ActionKey.class); PathKey pk = method.getAnnotation(PathKey.class); String actionKey; if (ak != null) { actionKey = ak.value().trim(); if ("".equals(actionKey)) throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank."); if (!actionKey.startsWith(SLASH)) actionKey = SLASH + actionKey; } else if (pk != null){ actionKey = pk.value().trim(); if ("".equals(actionKey)) throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank."); if (!actionKey.startsWith(SLASH)) actionKey = controllerPath + SLASH + actionKey; } else if (methodName.equals("index")) { actionKey = controllerPath; } else { actionKey = controllerPath.equals(SLASH) ? SLASH + methodName : controllerPath + SLASH + methodName; } Action action = new Action(controllerPath, actionKey, controllerClass, method, methodName, actionInters, route.getFinalViewPath(routes.getBaseViewPath())); if (mapping.put(actionKey, action) != null) { throw new RuntimeException(buildMsg(actionKey, controllerClass, method)); } } } } routes.clear(); // support url = controllerPath + urlParas with "/" of controllerPath Action action = mapping.get("/"); if (action != null) { mapping.put("", action); } } }
JFinalConfig 子类配置的时候,需要设置一下:
@Override public void configConstant(Constants me) { me.setActionMapping(routes -> new MyActionMapping(routes)); }
好了,开始测试:
import com.jfinal.core.Controller; import com.jfinal.core.Path; @Path("/path/key") public class PathKeyController extends Controller { public void index(){ renderText("INDEX"); } public void a(){ renderText("A"); } @PathKey("/action/b") public void b(){ renderText("B"); } @PathKey("test/c") public void c(){ renderText("C"); } }
启动时打印一下看下:
@Override public void onStart() { System.out.println(JFinal.me().getAllActionKeys()); }
打印结果:
[/action/b, /path/key, /path/key/a, /path/key/test/c]
说明成功:
@PathKey("test/c") 不写 / 时会继承 @Path("/path/key") 的参数,拼接为:/path/key/test/c
@PathKey("/action/b") 写了 / 时, 就是顶级路由了。
好了,分享完毕。