A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

本帖最后由 大山哥哥 于 2021-7-13 11:22 编辑

        今天我们来看一个SPEL表达式的使用案例,通过它来讲解几种常见的SPEL表达式语法。                在spring security注解@PreAuthorize中使用的SpEL表达式有一个较为复杂的写法:
[Java] 纯文本查看 复制代码
    @PreAuthorize("hasRole('ROLE_USER') and 'admin' == authentication.principal.username")
        其中的hasRole('ROLE_USER')'admin' == authentication.principal.username分别采用的是SpEL表达式写法。
        那么这些SpEL代表什么意思呢?又有那些常用的SpEL表达式写法呢?我们挑选几个例子来统一演示,同时也可以说明上述表达式分别代表什么意义。
        我们先准备两个类,为下面的语法测试做准备:
[Java] 纯文本查看 复制代码
public class AppContextBean {
    private String appName;
    private AuthUser user;//用户对象

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public AuthUser getUser() {
        return user;
    }

    public void setUser(AuthUser user) {
        this.user = user;
    }
}

public class AuthUser {
    private String username;

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
}



下面,我们来使用SpEL的几个语法:
  • 字符串
[Java] 纯文本查看 复制代码
/**
     * 普通字符串
     */
    @Test
    public void string(){
        ExpressionParser parse = new SpelExpressionParser();
        Expression expression = parse.parseExpression("'你好SPEL'");
        Object value = expression.getValue();
        System.out.println(value);
    }

  • 对象属性调用
[Java] 纯文本查看 复制代码
    /**
     * 对象属性调用
     * 创建AppContextBean对象,该对象中有两个属性,分别是字符串类型的appName和AuthUser对象类型的user
     */
    @Test
    public void objectAttr(){
        //构建AuthUser对象
        AuthUser user = new AuthUser();
        user.setUsername("宙斯");
        //构建对象
        AppContextBean appContext = new AppContextBean();
        appContext.setAppName("SPEL应用");
        appContext.setUser(user);

        //使用SPEL表达式来读取对象中的属性值
        ExpressionParser parse = new SpelExpressionParser();
        EvaluationContext context=new StandardEvaluationContext(appContext);

        //读取appContext对象中的用户名称 其中"user"读取的是AppContextBean这个对象的user属性对象,"user.username"读取的是user对象的username属性值
        Expression expression = parse.parseExpression("user.username");
        //设置获取值的上下文环境
        Object value = expression.getValue(context);
        System.out.println("当前AppContextBean中用户名为:" + value);

        //执行结果如下:
//        当前AppContextBean中用户名为:宙斯
    }

  • 方法调用
[Java] 纯文本查看 复制代码
    /**
     * 普通方法调用
     * 演示调用AppContextBean中的getAppName方法
     */
    @Test
    public void invokeMethod(){
        //构建AppContextBean对象
        AppContextBean appContext = new AppContextBean();
        appContext.setAppName("SPEL应用");

        ExpressionParser parse = new SpelExpressionParser();
        EvaluationContext context=new StandardEvaluationContext(appContext);

        Expression expression = parse.parseExpression("getAppName()");
        Object value = expression.getValue(context);
        System.out.println(value);

        //执行结果如下:
//        SPEL应用
    }

  • 变量
[Java] 纯文本查看 复制代码
/**
     * 方法传参使用
     * 获取某个入参对象的属性值
     */
    @Test
    public void variable(){
        //构建解析器
        ExpressionParser parse = new SpelExpressionParser();
        //构建AuthUser对象
        AuthUser user = new AuthUser();
        user.setUsername("影魔");
        //构建对象
        AppContextBean appContextBean = new AppContextBean();
        appContextBean.setAppName("SPEL应用");
        appContextBean.setUser(user);

        //设置解析环境
        EvaluationContext context=new StandardEvaluationContext();
        //设置变量(参数)
        context.setVariable("appContext",appContextBean);
        //!!注意,此处的"#appContext"的语法是 #变量名,即,获取上下文环境中变量名为appContext的值——appContextBean对象。
        //"#appContext.appName"则是获取appContextBean对象的appName属性值
        Expression appNameParse = parse.parseExpression("#appContext.appName");
        //从上下文环境中得到该SPEL表达式运行的结果
        Object appName = appNameParse.getValue(context);

    //"#appContext.user.username"则是获取appContextBean对象user属性的username值
        Expression usernameParse = parse.parseExpression("#appContext.user.username");
        //从上下文环境中得到该SPEL表达式运行的结果
        Object username = usernameParse.getValue(context);

        System.out.println("当前APPNAME是:" + appName + ", 用户名是:" + username);

        //执行结果如下:
//        当前APPNAME是:SPEL应用, 用户名是:影魔
    }

  • 判断
[Java] 纯文本查看 复制代码
    /**
     * 判断
     */
    @Test
    public void cal(){
        ExpressionParser parse = new SpelExpressionParser();
        //判断2>1 返回boolean类型
        Expression expression = parse.parseExpression("2 > 1");
        Object value = expression.getValue();
        System.out.println("判断2>1:" + value);

        expression = parse.parseExpression("2 == 1");
        value = expression.getValue();
        System.out.println("判断2 == 1:" + value);

        //执行结果如下:
//        判断2>1:true
//        判断2 == 1:false
    }

  • 多判断条件拼接
[Java] 纯文本查看 复制代码
    /**
     * 多判断条件拼接
     */
    @Test
    public void calConcat(){

        ExpressionParser parse = new SpelExpressionParser();
        //2>1和2==1的判断结果“或”拼接 返回boolean类型
        Expression expression = parse.parseExpression("2 > 1 or 2 == 1"); //其中or也可以使用||
        Object value1 = expression.getValue();
        System.out.println("2 > 1 or 2 == 1:" + value1);

        //2>1和2==1的判断结果“与”拼接 返回boolean类型
        expression = parse.parseExpression("2 > 1 and 2 == 1");//其中and也可以使用&&
        Object value2 = expression.getValue();
        System.out.println("2 > 1 and 2 == 1:" + value2);

        //执行结果如下:
//        2 > 1 or 2 == 1:true
//        2 > 1 and 2 == 1:false
    }


        学习到这里,大家应该可以想得到    @PreAuthorize("hasRole('ROLE_USER') and 'admin' == authentication.principal.username") 中的SPEL表达式的作用了吧?我们通过一个截图来说明:
        
        大家也可以思考一下下面的代码中的SPEL所表达的判断:
[Java] 纯文本查看 复制代码
    //SPEL表达式如下:
//    #userId == authentication.principal.username or hasRole('ROLE_ADMIN')
    @PreAuthorize("#userName == authentication.principal.username or hasRole('ROLE_ADMIN')")
    void changeUserPassword(@RequestParam("userName") String userName ){
        //代码执行段
    }




0 个回复

您需要登录后才可以回帖 登录 | 加入黑马