Back to posts

SpEL을 이용한 연산

SpEL로 사칙/논리/관계 연산을 중위표현식 그대로 평가하는 방법.

2024년 2월 18일

SpEL은 사칙/논리/관계 연산을 중위 표현식 그대로 평가할 수 있다.

  • 사칙연산: + - * /
  • 논리연산: & | !
  • 관계연산: > < == != in

괄호가 포함된 복잡한 표현도 가능하다.

Expression expression = parser.parseExpression("(#a or #b) and (!#c and !#d)");

평가 프로그램 구현

코드 예시는 다음과 같다.

@Test
void shouldEvaluation_withSpel() {
    // Evaluator 빈 생성 // 각각은 eval(ctx, factors) 메세지  구현 필요
    Map<String, Evaluator> factory = Map.of(
        "time", new TimeRangeEvaluator(),
        "threashhold", new ThreashholdEvaluator(),
        "text", new TextContainsEvaluator()
    );
 
    // 현재 컨텍스트. 조회를 해서 넣든, 도메인서비스를 넣든, 런타임에 평가할수 있도록 현재의 컨텍스트를 전달하는게 목표
    CurrentContext ctx = new CurrentContext(12, 10, "hello world");
 
    // SpEL 표현식 파싱 및 표현식
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    context.setVariable("a", factory.get("time").eval(ctx, 1, 23));    // 시간이 1~23시 사이
    context.setVariable("b", factory.get("threashhold").eval(ctx, 5)); // 카운트가 5를 초과
    context.setVariable("c", factory.get("text").eval(ctx, "제목1"));   // title에 제목1 포함
    context.setVariable("d", factory.get("text").eval(ctx, "제목2"));   // title에 제목2 포함
    Expression expression = parser.parseExpression("(#a or #b) and (!#c and !#d)");
 
    // 표현식 평가
    assertThat(expression.getValue(context, Boolean.class)).isTrue();
}

JSON 구문 예시

클라이언트로 전달받는 JSON 예시는 다음과 같다.

"evaluators" :
[
  {
    "var" : "a",
    "type" : "timeRange",
    "factor" : [0, 17]
  },
  {
    "var" : "b",
    "type" : "threashhold",
    "factor" : [10]
  }
]
"expression" : "(#a or #b) and (!#c and !#d)"