标题党了,记得以前也有人反馈想把@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") 写了 / 时, 就是顶级路由了。
好了,分享完毕。