模板扩展指令(获取request或者session)

(以下分享人是:icaotw波总让转到分享,我就代劳了

比如说我想扩展一个指令,让页面上判断某个按钮用户是否有权限,想扩展一个指令,在页面上根据actionkey判断用户是否有访问该按钮的权限。

#if (permit(“/user/admin”))

<button >xxx</button>

#end

扩展一个指令,根据登录用户session取出所拥有的权限再和actionkey对比,在扩展指令中如何获取页面的session?

现在貌似只能用:

#if (permit(session.user,"/user/admin))先从页面传入user。

  • 使用 session 添加一个全局拦截器:
    me.add(new SessionInViewInterceptor())
    用的时候这样:#i(session.user)

    request 中的数据已经被自动注入进来了,可以直接使用,例如:
    setAttr("key", 123);
    用的时候这样:#(key)


  • jfinal template engine 做设计成可以独立于 java web 运行,所以 template engine 自身的接口不会与 Session 耦合,如果需要在自定义指令定使用,建议两个办法:

  • 1:添加拦截器 me.add(new SessionInViewInterceptor()),然后在自定义指令中通过 scope.get("session") 拿到它
    2:通过定义一个 Handler,使用一个 ThreadLocal 对每次请求进行 set ,然后在自定义指令中通过 threadLocal.get() 来拿到它。


  • 建议采用第一种方式

  • @JFinal 成功扩展了一个ifHasAuth指令,多谢波总指点迷津。上代码:

  • public class IfHasAuth extends Directive {
    
    private Expr valueExpr;
    
    public void setExprList(ExprList exprList) {
       this.valueExpr = exprList.getExprArray()[0];
    }
    
    @Override
    public void exec(Env env, Scope scope, Writer writer) {
        HttpSession session = (HttpSession) scope.get("session");
        if (null != session) {
        User user = (User) session.getAttribute("user");
        String actionKey = (String) valueExpr.eval(scope);
        if (auth(user, actionKey)) {
           stat.exec(env, scope, writer);
        }
      }
    }
    
    public boolean hasEnd() {
      return true;
    }
    
    /**
    * 判断用户是否有权限 
    * @param user --用户对象
    * @param actionKey --访问地址
    * @return
    */
    private boolean auth(User user, String actionKey) {
       if (user != null && StrKit.notBlank(actionKey)) {
          String authUrls = user.getStr("ress");
          for (String u : authUrls.split(",")) {
             if (actionKey.equals(u)) {
               return true;
             }
          }
       }
       return false;
    }

    页面上直接用

  • #ifHasAuth("/user/add")
    新增
    #end
    这样可以控制新增按钮是否显示。以上代码是否有改进空间,请波总指教


评论区

JFinal

2017-04-08 10:31

采用指令扩展的方式是最好的解决方案,以上分享代码已经很简洁了,要是在发贴的时候选择插入代码的方式加上代码高亮显示就更好了,建议对此贴子直接进行修改,可读性更好

感谢你的分享

macaque

2017-07-11 16:25

@JFinal 如果用户信息不是用Session呢,如何在自定义指令中获取当前用户 或者是request或action信息

macaque

2017-07-13 09:13

JFinal

2017-07-13 17:26

@macaque 用一个 handler 配合一个 ThreadLocal 解决就好

macaque

2017-07-20 09:07

@JFinal ThreadLocal 是在handler里做好呢 还是可以在interceptor里呢?handler会处理所有请求,我只需要action的信息就行

JFinal

2017-07-20 11:41

@macaque 拦截器里面做是不会生效的,因为拦截器只拦截 action,不拦截 render

最好的做法是类似于如下:
public class MyTemplateRender extends TemplateRender {
static ThreadLocal threadLocal = new ThreadLocal();

public MyTemplateRender(String view) {
super(view);
}

public void render() {
threadLocal.set(...);
try {
super.render();
} finally {
threadLocal.remove();
}
}

然后通过扩展 RenderFactory 来切换自己的 MyTemplateRender:
public class MyRenderFactory extends RenderFactory {
public Render getRender(String view) {
render new MyTemplateRender(view);
}
}

最后配置一下:
me.setRenderFactory(new MyRenderFactory());

Psbye

2017-08-31 17:57

@mark !

马小酱

2018-02-11 15:48

马克

板砖哥

2018-12-12 09:16

Dull

2019-09-24 17:26

那么问题来了,set的session值是可以被模板的#set()指令修改的吧 @JFinal