파란하늘의 지식창고
Published 2023. 9. 19. 05:06
vaadin 사용해 보기 Study/Java
반응형

Vaadin 소개

https://vaadin.com/

vaadin은 ui component 구성을 제공해 주는 java기반 웹프레임워크이다.
Swing이나 AWT를 작성하는 것처럼 java 코드를 작성하면 요청에 대해 대응되는 web ui를 제공해 준다.
ui관련 html, javascript, css 작업을 따로 하지 않아도 되고 Java 대신 TypeScript를 사용할 수도 있다.

 

기본 기능은 open-source로 제공되며 생산성 향상을 위한 vaadin UI 관련 테스트 도구나 Advanced UI component는 유료로 제공된다.

 

Vue, Svelte 같은 Front-end Framework를 흥미를 가지고 공부해 보았지만 너무나 변화하는 속도가 빠르다 보니 다른 방법이 없을까 싶어 찾아보다가 vaadin을 사용하는 방법도 있겠다 싶어 한번 사용해 보았다.

 

vaadin은 Spring Boot와 같이 사용하기 좋다.
spring boot 기반의 프로젝트에서 web ui 부분만 vaadin으로 구성한다고 보면 될 것 같다.

 

설정

Spring Boot 기반의 프로젝트에 다음과 같이 vaadin dependency를 추가한다.

<dependencies>
    <dependency> 
        <groupId>com.vaadin</groupId> 
        <artifactId>vaadin-spring-boot-starter</artifactId> 
    </dependency> 
    <dependency> 
        <groupId>org.springframework.boot</groupId> 
        <artifactId>spring-boot-devtools</artifactId> 
        <optional>true</optional> 
    </dependency> 
</dependencies> 

<dependencyManagement> 
    <dependencies> 
        <dependency> 
            <groupId>com.vaadin</groupId> 
            <artifactId>vaadin-bom</artifactId> 
            <version>${vaadin.version}</version> 
            <type>pom</type> 
            <scope>import</scope> 
        </dependency> 
    </dependencies> 
</dependencyManagement>

잦은 수정을 좀 더 편하게 반영하기 위해 spring-boot-devtools를 사용하면 좋다.

 

추가적인 properties 설정은 다음과 같이 할 수 있지만 별다른 설정을 하지 않더라도 dependency 추가로 vaadin은 사용 가능하게 된다.
https://vaadin.com/docs/latest/configuration/properties

사용하기

Html 태그 작성

Html 작성과 관련한 JavaScript, Css 작성을 Java에서 한다고 생각하면 된다.

 

기본적으로 Html tag 관련한 class를 모두 제공하고 있다.

예를 들면 다음과 같은 Html 태그는

<div>
    <h1>무언가를 써보자</h1>
    <div>div태그 텍스트</div>
</div>

Vaadin은 Java로 다음과 같이 작성한다고 생각하면 된다.

Div div = new Div(); 
div.add(new H1("무언가를 써보자")); 

Div subDiv = new Div(); 
subDiv.setText("div태그 텍스트"); 
div.add(subDiv);

이런 식으로 기본적인 Html 태그를 Java class로 구성한다.

요청 처리

Spring에서는 Controller를 작성하고 @RequestMapping을 정의하여 요청에 대해 처리를 한다.

 

Vaadin을 사용하면 @Route를 사용하여 요청을 처리한다.

 

위의 예제를 "/test"라는 요청을 받으면 응답하도록 구성한다면 다음과 같이 구성하면 된다.

 

@Route("/test")
public class TestView extends Div { 

    public TestDiv() {
        add(new H1("무언가를 써보자"));

        Div subDiv = new Div();
        subDiv.setText("div태그 텍스트");
        add(subDiv);
    }
}

요청을 받아 처리할 class를 만들고 해당 요청에 대해 응답으로 구성될 최상위 Element로 Div를 extends 하였다.
@Route annotation으로 대응할 요청을 설정하고 생성자에서 element를 어떻게 구성할지를 정의하면 된다.

 

위의 예제의 경우 "/test" 요청에 대해 div tag를 가진 html 페이지를 응답한다.
(심플하게 <div>...</div> 내용만 응답하는 것은 아니고 vaadin이 처리한 여러 요소들을 가진 html 페이지를 응답한다.)

Layout 구성

Html 페이지를 구성하면 보통 Html element를 구성하고 Css에서 text-align, display, flex-wrap 같은 속성들을 사용하여 화면 배치를 정의한다.

 

또한 여러 요청에 대해 공통된 화면 구성을 제공하고 Form을 사용하는 경우 여러 input 요소들을 구성하기도 한다.

 

Vaadin은 이와 같은 경우들에 대응하는 Layout을 제공한다.

 

예를 들어 다음과 같이 2개의 Div를 가진 경우

<div>
    <div>div 1</div>
    <div>div 2</div>
</div>

Html 작성 시엔 동등한 위치의 Div들을 수평 배치를 하기 위해 Css에서 화면 구성을 정의해야 한다.

 

Vaadin을 사용하는 경우 제공되는 HorizontalLayout을 상속하여 다음과 같이 정의하면 된다.

@Route("/test") 
public class TestView extends HorizontalLayout { 

    public TestDiv() {
        add(new H1("무언가를 써보자"));

        Div subDiv = new Div();
        subDiv.setText("div1 태그 텍스트");

        Div subDiv2 = new Div();
        subDiv2.setText("div2 태그 텍스트");
        add(subDiv, subDiv2);
    }
}

이런 식으로 Vaadin에서 제공하는 HorizontalLayout, VerticalLayout, FormLayout 등 다양한 Layout을 사용하면 화면 배치를 위한 구성을 Css 정의를 생략하고 간단하게 할 수 있다.

요청 별 Layout 정의

일반적으로 요청에 대해 동일한 형태의 Layout을 구성하여 제공한다.
예를 들면 여러 요청에 대해 상단 navbar나 좌측 sidebar 메뉴 같은 Layout을 제공하는 경우가 일반적이다.

 

Vaadin을 사용하면 다음과 같이 구성하면 된다.

// layout 제공 class
public class CommonLayout extends AppLayout {

    public CommonLayout() {
        addToNavbar("navbar로 사용할 Component 추가");
        addToDrawer("sidebar로 사용할 Component 추가");
    }
}

// 요청 별 class
@Route(value = "/test", layout = CommonLayout.class)
public class TestView extends HorizontalLayout {
    // 생략
}

@Route(value = "/test2", layout = CommonLayout.class) 
public class TestView2 extends HorizontalLayout { 
    // 생략
}

Vaadin이 제공하는 AppLayout을 사용하여 Layout 화면 요소를 정의하고 요청마다 해당 Layout을 사용하도록 @Route annotation에 layout 속성을 정의하였다.

Component 사용

앞서 소개한 Html에 대응하는 class나 Layout에 대응하는 class 등 vaadin이 제공하는 요소들은 모두 com.vaadin.flow.component.Component 하위 클래스 들이다.
해당 클래스의 상속을 살펴보면 어떤 것들이 사용 가능한지 확인할 수 있다.

 

또한 vaadin 홈페이지에서도 제공하는 여러 Component들에 대해 확인할 수 있다.
https://vaadin.com/docs/latest/components

Spring 과의 연동

vaadin은 웹 요청 처리만 담당하고 Service, Repository는 Spring에서 담당한다.
(Spring의 Controller 역할만 Vaadin이 대체한다고 생각하면 된다.)

 

따라서 Spring의 Service bean을 Vaadin의 요청 처리에서 사용하려는 경우 다음과 같이 생성자로 전달받아 사용하면 된다.
https://vaadin.com/docs/latest/integrations/spring/routing

@Service
public class SomeService {

    public SomeDomain doSomething() {
        // 생략
    }
}

@Route("/test")
public class TestView extends HorizontalLayout {

    public TestView(SomeService someService) {
        // someService bean 사용하여 응답 화면에 쓰일 데이터 호출
    }
}

Spring Security와 연계

https://vaadin.com/docs/latest/security/enabling-security

Vaadin에서 Spiring Security를 사용할 수 있도록 설정을 추가한다.

@EnableWebSecurity
@Configuration
public class VaadinSecurityConfig extends VaadinWebSecurity {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		super.configure(http);
		setLoginView(http, "/login");
	}

}

Spring Security 사용하는 경우 Controller에서 사용하던 @PreAuthorize 같은 Spring Security 제공 annotation은 Vaadin의 @Route에서 사용할 수 없다.

 

대신 일반적으로 사용하는 jakarta annotation-api (구 javax annotation-api)인 @PermitAll , @DenyAll , @RolesAllowed 및 vaadin이 제공하는 @AnonymousAllowed를 사용할 수 있다.

기타 참고 사항

요청 별로 vaadin component가 생성된다. (prototype)
Spring은 singleton으로 사용한다.
이로 인해 Vaadin Component 구성 시 인스턴스 변수를 공유해서 사용해도 사용자 별 처리로 간주가 되지만 성능 상 그리 좋지 않아 보인다.

 

layout을 상속하여 구성하는 방식이 swing과 유사하고 유려하지 않은 편이다.

 

Spring과의 통합 설정은 아래 문서에서 참고하면 된다.
https://vaadin.com/docs/latest/integrations/spring
Spring 관련한 Vaadin properties는
vaadin-spring 모듈의 com.vaadin.flow.spring.VaadinConfigurationProperties 에서 확인할 수 있다.

 

Spring 기반 vaadin starter tempalte은 https://start.vaadin.com/app 여기에서 확인할 수 있는데 회원 가입을 해야 customize가 가능하다.

 

vaadin은 lumo를 Default Theme로 사용한다.
https://vaadin.com/docs/latest/styling/lumo
여기에서 살펴볼 수 있다.
https://demo.vaadin.com/lumo-editor/

 

Grid 같은 Component에서 사용하는 데이터 처리 객체는 record를 사용할 수 없다.
수정 변경을 가정하고 제공되기 때문에 불변 객체는 지원하지 않는다.

 

grid editor에서 대상이 lombok의 getter, setter를 사용하고 있는 경우 변경 시 변경 대상 domain의 identity 확인을 위해 @EqualsAndHashCode(of="대상필드")를 명시해주어야 한다.
https://vaadin.com/forum/thread/18453090/grid-with-editor-can-t-save-changed-data

 

Input element와 item 간 binder를 사용하여 연계 처리를 한다.

 

binder의 getbean / setbean과 readBean / writeBean의 차이를 염두에 두어야 한다.

 

get/set은 버퍼링 되지 않고 상태가 즉시 저장되기 때문에 필드 변경 시 유효성 검사가 발생하며
read/write는 버퍼링 되고 바로 반영하지 않기 때문에 변경 시 validation 체크를 하지 않고 이후 writeBean을 하는 시점에 체크를 한다.
또한 바로 반영이 아니기 때문에 writeBean으로 반영을 해주어야 변경이 적용된다.

 

Spring Session을 사용하는 경우 문제가 있는 듯하다.
https://vaadin.com/blog/microservices-high-availability
https://vaadin.com/forum/thread/17277282/spring-boot-vaadin-flow-spring-session-redis-spring-security-sessi
https://vaadin.com/docs/latest/tools/kubernetes/session-replication
https://github.com/vaadin/spring/issues/340

 

소감

vaadin을 사용하면서 느낀 점은 여러 가지를 공부하면서 사용해 본 것들이 섞여있다는 것이다.
ui component를 찾아볼 땐 tailwindcss를 사용하는 것 같고 java에서 component를 작성할 땐 swing을 만드는 것 같다.
HTML, CSS, JavaScript 작업 없이 Java 로만 Vaadin을 사용한다 해도 결국 기본적인 지식은 있어야 활용을 할 수 있다.

 

Spring과 결합하여 사용할 수 있지만 vaadin은 prototype의 범위로 코드가 구성되어 있다 보니 인스턴스 변수 사용 방식에 차이가 있다는 걸 염두에 두고 개발을 해야 한다.
Spring의 sington 사용이 익숙한 나에겐 어색하게 느껴지는 부분이다.

 

Ui component의 기본적인 기능은 무료로 사용이 가능하지만 좀 더 세세하게 구성하려고 하면 유료 버전의 ui component를 사용해야 한다.
직접 구성할 수야 있겠지만 복잡하고 관리가 어려울 듯싶다.
vaadin의 결재 유도 포인트인 거 같기도 하다..

 

UI를 구성하는 과정에 수많은 변경을 시도해야 하는데 Java기반이다 보니 변경 시마다 application reload 비용이 너무 크다.
DevTools를 사용한다 해도 무겁고 느리긴 매한가지이고 세이브마다 reload 되는 것이 부담이다.
이런 부분은 vite 같은 것을 사용하는 FE 개발이 훨씬 작업 시간 단축에 장점이 많은 것 같다.

 

다만 grid의 사용과 같이 다량의 데이터의 처리를 표현하는 부분은 오히려 html, javascript로 작성하는 것보다 훨씬 높은 편의성을 제공해 준다.
대량의 테이블 데이터를 보여줄 때 별다른 작업을 하지 않아도 스크롤 시 데이터를 분할하여 호출하여 렌더링 시간을 단축해 준다.

 

그 외에도 PWA, Web Push 같은 기능의 구현은 의외로 훨씬 쉬워 보였다.

 

Ui component의 공통화 처리는 javascript의 FE Framework에서도 동일하게 제공되는 기능이지만 컴파일 체크가 확실한 java로 작성하는 것이 명확하다는 느낌을 받았다.
(java가 더 익숙해서 그런 걸 수도 있다.)

 

BE와 FE 영역이 분리되어 개발하는 일반적인 방식의 경우 BE에선 API를 제공하고 FE에서 이를 받아 화면을 처리하는 과정의 코드를 작성해야 하는데
Vaadin을 사용하면 이러한 연계 과정의 코드 작성 비용이 사라지는 장점이 있다.
FE와 협업하여 개발하는 경우가 아니라면 Vaadin을 사용하는 것이 유지보수하기 좋을 것 같다.

반응형
profile

파란하늘의 지식창고

@Bluesky_

도움이 되었다면 광고를 클릭해주세요