SpringBoot SpEL 문법 문맹 퇴치 및 조회 매 뉴 얼 의 실현

19528 단어 SpringBootSpEL 문법
Spring 표현 식 언어 는 SpEL 이 라 고 약칭 합 니 다.Ognl 과 유사 한 대상 그림 네 비게 이 션 언어 입 니 다.(ognl 에 익숙 하지 않 은 학생 들 은 Ognl 시리즈 박문 을 참고 할 수 있 습 니 다)
SEEL 은 Spring 에 풍부 한 상상 공간 을 제공 합 니 다.기본 적 인 표현 식 조작 외 에 도 지원 합 니 다.
  • bean 대상 방문
  • 호출 방법,접근(수정)클래스(대상)속성
  • 계산 식
  • 정규 일치
  • ...
  •  I.문법 백과
    다음 내용 은 모두 공식 문서 에서 나온다.https://docs.spring.io/spring-framework/docs/5.2.1.RELEASE/spring-framework-reference/core.html#expressions
    1.표현 식
    스 펠 지원 문자열,숫자 값(int,real,hex),boolean 및 null 등 기본 형식,인 스 턴 스 는 다음 과 같 습 니 다.
    
    ExpressionParser parser = new SpelExpressionParser();
    
    // evals to "Hello World"
    String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();
    
    // double   
    double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();
    
    // evals to 2147483647
    int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
    
    boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
    
    Object nullValue = parser.parseExpression("null").getValue();
    문자열 은 작은 따옴표 로 포함 되 어야 합 니 다.부동 소수점 은 기본적으로 double 형식 이 고 null 로 null object 를 표시 합 니 다.
    출력 결과
    str: Hello World
    double: 6.0221415E23
    int: 2147483647
    bool: true
    null: null
    2. Inline List
    {}을 통 해 List 표현 식 을 표시 합 니 다.빈 목록 은{}으로 직접 표시 합 니 다.
    
    ExpressionParser parser = new SpelExpressionParser();
    // Integer  
    List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue();
    System.out.println("list: " + numbers);
    
    // List    List
    List<List> listlOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue();
    System.out.println("List<List> : " + listlOfLists);
    출력 결과
    list: [1, 2, 3, 4]
    List : [[a, b], [x, y]]
    3. Inline map
    {key:value}은 map 표현 식 을 표시 하고 빈 맵 은{:}으로 표시 합 니 다.
    
    private void map() {
      ExpressionParser parser = new SpelExpressionParser();
      Map map = (Map) parser.parseExpression("{txt:'Nikola',dob:'10-July-1856'}").getValue();
      System.out.println("map: " + map);
      Map mapOfMaps =
          (Map) parser.parseExpression("{txt:{first:'Nikola',last:'Tesla'},dob:{day:10,month:'July',year:1856}}")
              .getValue();
      System.out.println("Map<Map>: " + mapOfMaps);
    }
    
    출력 결과
    map: {txt=Nikola, dob=10-July-1856}
    Map: {txt={first=Nikola, last=Tesla}, dob={day=10, month=July, year=1856}}
    4.배열
    배열 은 new 구조 방법 을 통 해 이 루어 질 수 있 으 며,아래 표 시 된 ary[index]방식 으로 배열 의 요 소 를 방문 할 수 있 습 니 다.
    
    private void array() {
       ExpressionParser parser = new SpelExpressionParser();
       int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue();
       System.out.println("array: " + JSON.toJSONString(numbers1));
    
       // Array with initializer
       int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue();
       System.out.println("array: " + JSON.toJSONString(numbers2));
    
       // Multi dimensional array
       int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue();
       System.out.println("array: " + JSON.toJSONString(numbers3));
    
    
       int[] nums = new int[]{1, 3, 5};
       EvaluationContext context = new StandardEvaluationContext();
       context.setVariable("num", nums);
    
       //             
       Integer numVal = parser.parseExpression("#num[1]").getValue(context, Integer.class);
       System.out.println("numVal in array: " + numVal);
    }
    
    
    출력 은 다음 과 같 습 니 다.
    array: [0,0,0,0]
    array: [1,2,3]
    array: [[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]
    numVal in array: 3
    5.표현 식
    Spel 은 자바 문법 에서 일반적인 비교 판단,산수 연산,3 원 표현 식,유형 판단,matches 정규 일치 등 기본 표 표현 식 을 지원 합 니 다.
    다음은 간단 한 실례 를 드 리 겠 습 니 다.
    
    public void expression() {
      ExpressionParser parser = new SpelExpressionParser();
      //   
      System.out.println("1+2= " + parser.parseExpression("1+2").getValue());
      //   
      System.out.println("1<2= " + parser.parseExpression("1<2").getValue());
      System.out.println("true ? hello : false > " + parser.parseExpression("3 > 2 ? 'hello': 'false' ").getValue());
      // instanceof   ,      , T    
      System.out.println("instance : " + parser.parseExpression("'a' instanceof T(String)").getValue());
      //     
      System.out.println("22         :" + parser.parseExpression("22 matches '\\d{2}'").getValue());
    }
    
    출력 결과
    1+2= 3
    1<2= true
    true ? hello : false > hello
    instance : true
    22.두 자리 숫자 인지 여부:true
    6.Type 과 정적 클래스
    Class 대상 을 가 져 오 거나 정적 구성원/방법 에 접근 하려 면 T()문법 을 통 해 이 루어 질 수 있 습 니 다.
    예 를 들 어 우 리 는 정적 클래스 가 있다.
    
    public static class StaClz {
      public static String txt = "    ";
    
      public static String hello(String tag) {
        return txt + " : " + tag;
      }
    }
    
    
    정적 속성 txt 에 접근 하려 면 표현 식 을 T(com.git.hui.boot.spel.demo.BasicSpelDemo.StaClz)로 쓸 수 있 습 니 다.txt 는 괄호 안에 완전한 서명 이 있 음 을 주의 하 십시오.접근 정적 방법 유사
    
    public void type() {
      // class,   
      ExpressionParser parser = new SpelExpressionParser();
      String name =
          parser.parseExpression("T(com.git.hui.boot.spel.demo.BasicSpelDemo.StaClz).txt").getValue(String.class);
      System.out.println("txt: " + name);
    
      String methodReturn =
          parser.parseExpression("T(com.git.hui.boot.spel.demo.BasicSpelDemo.StaClz).hello" + "('   blog')")
              .getValue(String.class);
      System.out.println("static method return: " + methodReturn);
    
      // class   
      Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
      System.out.println("class: " + stringClass.getName());
    }
    
    
    출력 결 과 는 다음 과 같다.
    txt:정적 속성
    static method return:정적 속성:회색 blog
    class: java.lang.String
    위의 쓰기 방법 은 T(String)를 중점적으로 보십시오.여기 있 는 String 은 완전한 패키지 경 로 를 사용 하지 않 습 니 다.즉,java.lang 패키지 아래 에 있 는 클래스 는 전체 패키지 이름 을 생략 할 수 있 습 니 다.우리 가 평소에 코드 를 쓸 때 도 표시 할 필요 가 없 는 import java.lang.*
    7.구조 방법
    위 에서 array 를 소개 할 때 new 를 사용 하여 배열 대상 을 만 드 는 것 을 소 개 했 습 니 다.물론 다른 일반 대상 을 직접 구성 할 수도 있 습 니 다.예 를 들 어 우리 가 새로운 테스트 클래스 를 만 드 는 것 과 같 습 니 다.
    
    public static class Person {
      private String name;
    
      private int age;
    
      public Person(String name, int age) {
        this.name = name;
        this.age = age;
      }
    
      public String getName() {
        return name;
      }
    
      public int getAge() {
        return age;
      }
    
      @Override
      public String toString() {
        return "Person{" + "txt='" + name + '\'' + ", age=" + age + '}';
      }
    }
    SpEl 을 통 해 대상 의 인 스 턴 스 를 만 듭 니 다.
    
    public void construct() {
      ExpressionParser parser = new SpelExpressionParser();
      Person person = parser.parseExpression("new com.git.hui.boot.spel.demo.BasicSpelDemo.Person('   ', 20)")
          .getValue(Person.class);
      System.out.println("person: " + person);
    }
    
    출력 결 과 는 다음 과 같 습 니 다.
    person:Person{txt='회색',age=20}
    구조 방법 중 클래스 의 전체 서명 에 주의 하 십시오.
    8.변수 참조
    세심 한 파트너,위 에서 배열 의 구성원 들 이 보 여 주 는 인 스 턴 스 를 소개 합 니 다.예 를 들 어'\#num[1]'이 num 앞 에\#가 있 습 니 다.이것 은 문법 정의 입 니 다.\#수식 적 인 표현 변수 접근 이 있 습 니 다.
    이 소절 을 이해 하려 면 먼저 Evaluation Context 를 이해 해 야 합 니 다.우리 의 SpEL 표현 식 해석 에서 getValue 는 하나의 매개 변수 가 바로 이 Context 입 니 다.당신 은 그 를 대상 을 포함 하 는 문맥 로 간단하게 이해 할 수 있 습 니 다.우 리 는 SpEL 의 문법 을 통 해 Context 중의 일부 구성원,구성원 방법 속성 등 을 방문 할 수 있 습 니 다.
    일반적인 조작 과정 은 다음 과 같다.
  • context.setVariable("person", person); Evaluation Context 에 멤버 변 수 를 삽입 합 니 다
  • parser.parseExpression(xxx).getValue(context)는 SpEL 표현 식 을 해석 합 니 다.context 는 전 삼 으로 넣 어야 합 니 다
  • 간단 한 실례
    
    public void variable() {
      ExpressionParser parser = new SpelExpressionParser();
      Person person = new Person("   blog", 18);
      EvaluationContext context = new StandardEvaluationContext();
      context.setVariable("person", person);
    
      String name = parser.parseExpression("#person.getName()").getValue(context, String.class);
      System.out.println("variable name: " + name);
    
      Integer age = parser.parseExpression("#person.age").getValue(context, Integer.class);
      System.out.println("variable age: " + age);
    }
    
    
    출력 결 과 는 다음 과 같다.
    variable name:회색 블 로그
    variable age: 18
    친구 알림,방문 대상 의 개인 Field/method 에 이상 을 던 집 니 다.
    9.함수
    Context 의 변 수 는 우리 가 흔히 볼 수 있 는 기본 유형,일반적인 대상 을 제외 하고 방법 일 수도 있 습 니 다.setVariable 에서 설정 한 구성원 유형 은 method 이면 됩 니 다.
    
    public void function() {
      try {
        ExpressionParser parser = new SpelExpressionParser();
        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
        //         ,   method  
        context.setVariable("hello", StaClz.class.getDeclaredMethod("hello", String.class));
    
        String ans = parser.parseExpression("#hello('   ')").getValue(context, String.class);
        System.out.println("function call: " + ans);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    
    
    출력 결 과 는 다음 과 같다.
    function call:정적 속성:회색
    10.bean 접근
    Spring 에서 어떤 대상 이 가장 흔 합 니까?물론 bean 입 니 다.그러면 우 리 는 SpEL 을 통 해 bean 의 속성,호출 방법 을 직접 방문 할 수 있 습 니까?
    bean 대상 에 접근 하려 면 Evaluation Context 에 bean 대상 이 포함 되 어야 합 니 다.
    context.setBeanResolver(new BeanFactory Resolver(applicationContext)와 같은 BeanResolver 를 통 해 이 루어 집 니 다.
    그 다음 에 bean 에 접근 하 는 접 두 사 는@기호 로 수식 합 니 다.
    이 장면 을 보 여주 기 위해 서 는 먼저 일반적인 Bean 대상 을 만 듭 니 다.
    
    @Data
    @Component
    public class BeanDemo {
    
      private String blog = "https://spring.hhui.top";
    
      private Integer num = 8;
    
      public String hello(String name) {
        return "hello " + name + ", welcome to my blog " + blog + ", now person: " + num;
      }
    }
    
    
    이어서 우 리 는 응용 프로그램 Context 를 가 져 와 야 하기 때문에,응용 프로그램 ContextAware 에서 계승 할 수 있 도록 테스트 클래스 를 조금 바 꿀 수 있 습 니 다
    
    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
    }
    
    
    public void bean() {
      ExpressionParser parser = new SpelExpressionParser();
      StandardEvaluationContext context = new StandardEvaluationContext();
      context.setBeanResolver(new BeanFactoryResolver(applicationContext));
    
      //   bean  
      BeanDemo beanDemo = parser.parseExpression("@beanDemo").getValue(context, BeanDemo.class);
      System.out.println("bean: " + beanDemo);
    
      //   bean  
      String ans = parser.parseExpression("@beanDemo.hello('   blog')").getValue(context, String.class);
      System.out.println("bean method return: " + ans);
    }
    위의 표기 법 은 이전의 것 과 큰 차이 가 없 으 며,실제 출력 결 과 는 다음 과 같다.
    bean: BeanDemo(blog=https://spring.hhui.top, num=8)
    bean method return:안녕하세요 회색 블 로그,내 블 로그 에 오신 것 을 환영 합 니 다  https://spring.hhui.top , now person: 8
    11. ifElse
    SpEL 은 3 원 표현 식 을 지원 합 니 다.위 표현 식 에서 도 인 스 턴 스 를 제공 합 니 다.
    
    public void ifThenElse() {
      //      ,? :
      ExpressionParser parser = new SpelExpressionParser();
      String ans = parser.parseExpression("true ? '  ': '  '").getValue(String.class);
      System.out.println("ifTheElse: " + ans);
    }
    
    출력 결 과 는 다음 과 같다.
    ifTheElse:정 답
    12. elvisxx != null ? xx : yy => xx?:yy
    이것 도 우리 가 자주 만 나 는 장면 에 속 합 니 다.xx 가 null 이면 yy 로 돌아 갑 니 다.그렇지 않 으 면 xx 로 바로 돌아 갑 니 다.간략화 표기 법 은 elvis 표기 법:xx?:yy
    
    public void elvis() {
      // xx != null ? xx : yy => xx?:yy
      ExpressionParser parser = new SpelExpressionParser();
      EvaluationContext context = new StandardEvaluationContext();
      context.setVariable("name", null);
      String name = parser.parseExpression("#name?:'Unknown'").getValue(context, String.class);
      System.out.println("elvis-before " + name);
    
      context.setVariable("name", "Exists!");
      name = parser.parseExpression("#name?:'Unknown'").getValue(context, String.class);
      System.out.println("elvis-after " + name);
    }
    
    
    출력 결 과 는 다음 과 같다.
    elvis-before Unknown
    elvis-after Exists!
    13.보안 표현 식
    자바 에서 가장 흔히 볼 수 있 고 가장 싫어 하 는 것 은 NPE 의 문제 입 니 다.SpEL 에서 도 당연히 이런 상황 이 발생 할 수 있 습 니 다.그러나 SpEL 에서 비 공 판단 을 하면 우아 하지 않 습 니 다.SpEL 은 xx 를 제공 합 니까?npexx == null ? null : xx.yy => xx?.yy
    예 를 들 어 설명 하 다.
    
    public void safeOperate() {
      //  npe  , xx == null ? null : xx.yy => xx?.yy
      ExpressionParser parser = new SpelExpressionParser();
      Person person = new Person(null, 18);
    
      String name = parser.parseExpression("name?.length()").getValue(person, String.class);
      System.out.println("safeOperate-before: " + name);
    
      person.name = "   blog";
      name = parser.parseExpression("name?.length()").getValue(person, String.class);
      System.out.println("safeOperate-after: " + name);
    }
    출력 결 과 는 다음 과 같다.
    safeOperate-before: null
    safeOperate-after: 7
    14.용기 캡 처
    용 기 를 옮 겨 다 니 며 부분 집합 을 가 져 옵 니 다.jdk 8 Stream 의 filter 용법 에 해당 합 니 다.문법 형식 은 다음 과 같 습 니 다.
    xx.?[expression],괄호 안에 있 는 표현 식 은 boolean 으로 돌아 가 야 합 니 다.
    예 를 들 어 설명 하 다.
    
    public void collectionSelection() {
      //     ,         
      // xx.?[expression] ,    expression      ,        ,      filter
      List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 4, 6, 7, 8, 9));
      ExpressionParser parser = new SpelExpressionParser();
    
      EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
      context.setVariable("list", list);
      //   #this            
      List<Integer> subList = (List<Integer>) parser.parseExpression("#list.?[#this>5]").getValue(context);
      System.out.println("subList: " + subList);
    
    
      Map<String, Integer> map = new HashMap<>();
      map.put("a", 1);
      map.put("b", 10);
      map.put("c", 4);
      map.put("d", 7);
      context.setVariable("map", map);
      //       key, value    map k,v
      Map subMap = parser.parseExpression("#map.?[value < 5]").getValue(context, Map.class);
      System.out.println("subMap: " + subMap);
    
      subMap = parser.parseExpression("#map.?[key == 'a']").getValue(context, Map.class);
      System.out.println("subMap: " + subMap);
    }
    출력 결 과 는 다음 과 같다.
    subList: [6, 7, 8, 9]
    subMap: {a=1, c=4}
    subMap: {a=1}
    주의 하 다.
  • 목록 표현 식 에서\#this 를 통 해 목록 의 모든 요 소 를 가리 킬 수 있 습 니 다
  • map 표현 식 에서 key,value 를 통 해 각각 map 의 k,v
  • 를 가리킨다.
    15.용기 맵
    하나의 집합 을 특정한 규칙 을 통 해 다른 집합 으로 비 추 는 것 은 jdk 8 Stream 의 map 용법 에 해당 합 니 다.문법 은 다음 과 같 습 니 다.
    xx.![expression],표현 식 계산 결 과 를 출력 용기 의 구성원 으로 합 니 다.
    예 를 들 면 아래 와 같다.
    
    public void collectionProjection() {
      //       ,       ,   lambda  map  
      // xx.![expression]
    
      List<Integer> list = new ArrayList<>(Arrays.asList(1, 3, 4, 6, 7, 8, 9));
      ExpressionParser parser = new SpelExpressionParser();
      EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
      context.setVariable("list", list);
    
      //   #this            
      List newList = parser.parseExpression("#list.![#this * 2]").getValue(context, List.class);
      System.out.println("newList: " + newList);
    
    
      Map<String, Integer> map = new HashMap<>();
      map.put("a", 1);
      map.put("b", 10);
      map.put("c", 4);
      map.put("d", 7);
      context.setVariable("map", map);
      List newListByMap = parser.parseExpression("#map.![value * 2]").getValue(context, List.class);
      System.out.println("newListByMap: " + newListByMap);
    }
    출력 결 과 는 다음 과 같 습 니 다.
    newList: [2, 6, 8, 12, 14, 16, 18]
    newListByMap: [2, 20, 8, 14]
    16.표현 식 템 플 릿
    SpEL 은 다음 문장 과 같은 글자 의 양 과 표현 식 을 함께 사용 하 는 사용자 정의 표현 식 템 플 릿 도 제공 합 니 다.
    
    "random number is #{T(java.lang.Math).random()}"
    
    그 중에서\#{T(java.lang.Math).random()}은 SpEL 표현 식 이 고 왼쪽 은 일반 문자열 입 니 다.이 표기 법 은@Value 주해 의 속성 표기 법 에서 도 흔히 볼 수 있 습 니 다.물론 위의 표기 법 을 통 해 이 문 구 를 직접 실행 하면 오류 가 발생 할 수 있 습 니 다.이 럴 때 ParserContext 를 지정 해 야 합 니 다.
    예 를 들 어 설명 하 다.
    
    public void template() {
      //   ,          ,   #{}         
      ExpressionParser parser = new SpelExpressionParser();
      String randomPhrase = parser.parseExpression("random number is #{T(java.lang.Math).random()}",
          ParserContext.TEMPLATE_EXPRESSION).getValue(String.class);
      System.out.println("template: " + randomPhrase);
    }
    
    출력 결 과 는 다음 과 같다.
    template: random number is 0.10438946298113871
    17.소결
    SpEL 은 매우 강력 한 표현 식 언어 에 속 합 니 다.제 개인 적 인 느낌 으로 는 OGNL 과 비슷 합 니 다.문맥 에 Spring 의 문맥 이 포함 되 어 있 을 때 모든 bean 을 방문 할 수 있 습 니 다.그리고 문법 규범 을 통 해 여러 가지 일 을 할 수 있 습 니 다.
    이전 프로젝트 를 추천 합 니 다.https://github.com/liuyueyi/quick-fixognl 을 이용 하여 applicationContext 와 결합 하여 원 하 는 대로 제어 응용 프로그램의 모든 bean 대상 을 방문 할 수 있 습 니 다.
    II.기타
    0.항목
    공사:https://github.com/liuyueyi/spring-boot-demo
    원본 코드:https://github.com/liuyueyi/spring-boot-demo/spring-boot/013-spel
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기