Study/Java

vaadin 사용해 보기 (2)

Bluesky_ 2023. 11. 4. 01:56
반응형

 

2023.09.19 - [Study/Java] - vaadin 사용해 보기

 

이전 글에 이어 사용하면서 익혔던 몇 가지 기능들을 정리해 보았다.

 

Vaadin을 학습해 보면서 최종적으로 느낀 점은 다음과 같다.

 

  • 실 라이브 서비스에 쓰일만한 라이브러리는 아니고 FE 관여 없는 관리툴 개발 시 쓰임이 있다.
  • java script 작성이나 css 설정의 단계가 생략되어 얼핏 좋아 보이지만 기반 지식을 염두에 두고 vaadin 코드를 작성해야 해서 오히려 학습의 난이도가 높아졌다.
    그냥 javascript 라이브러리나 css를 사용하는 게 더 좋다고 느꼈다.
  • Spring의 singleton 기반 bean 객체 관리와 다르게 prototype으로 코드가 처리되어서 성능이 떨어지고 Spring과 연계가 복잡해진다.
  • View Component, 기능 정의, Event 처리, 변수 처리 등의 영역 관리가 명확하게 나뉘어있지 않아 구현하려는 항목이 많아지면 코드 관리가 복잡해진다.

 


중첩 Layout 설정

layout 을 중첩으로 사용할 수 있다.

 

예를 들어 최상위 layout을 다음과 같이 정의하면

public class CommonLayout extends AppLayout {
	// layout 구현
}

 

특정 path 하위에서 사용하는 Layout을 지정할 때는 다음과 같이 @ParentLayout을 지정하여 하위 Layout을 선언할 수 있다.

 

@ParentLayout(CommonLayout.class)
public class BoardLayout extends Div implements RouterLayout {
	// Layout 구현
}

이 Layout을 사용하는 호출의 @Route 설정에 다음과 같이 호출하면 된다.

@Route(value = ":boardAlias/view/:boardArticleId", layout = BoardLayout.class)
public class BoardArticleView extends VerticalLayout {
	// 구현
}

 

해결하지 못한 부분

Layout을 사용하면서 layout을 사용하는 호출 contents 설정 이후의 코드 작성 (예: footer)를 layout 위치에 어떻게 설정하면 되는지 확인하지 못하였다.

@Route, @RoutePrefix, @RouteAlias로 주소 중첩 설정

https://vaadin.com/docs/latest/routing/additional-guides/route-templates#defining-route-templates-using-route-routealias-and-routeprefix

Spring이 Class의 @RequestMapping과 method의 @RequestMapping의 호출 경로 설정을 조합해서 사용한 것처럼 vaadin도 호출 주소를 조합하여 사용할 수 있다.

 

이는 앞서 설명한 중첩 Layout을 사용과 결합하여 다음과 같이 사용이 가능하다.

@RoutePrefix("board")
@ParentLayout(CommonLayout.class)
public class BoardLayout extends Div implements RouterLayout {
	// Layout 구현
}

@Route(value = ":boardAlias/view/:boardArticleId", layout = BoardLayout.class)
public class BoardArticleView extends VerticalLayout {
	// 구현
}

위와 같이 설정하면 @RoutePrefix와 @Route의 설정이 조합되어 `/board/:boardAlias/view/:boardArticleId` 주소로 호출을 하게 된다.

 

@RouteAlias는 다른 주소로 동일한 view를 호출하려고 하는 경우 같이 선언하여 사용하기 위해 제공된다.

@Route(value = ":boardAlias/view/:boardArticleId", layout = BoardLayout.class)
@RouteAlias(value = ":boardAlias/mobile_view/:boardArticleId", layout = BoardLayout.class)
public class BoardArticleView extends VerticalLayout {
	// 구현
}

 

Spring의 @RequestMapping은 동일 class의 class 선언과 method 선언을 조합하여 호출 경로를 정의하기 때문에 @RequestMapping annotation 하나만으로 조합을 처리하지만 vaadin의 layout구성은 개별 class를 layout 선언으로 참조하여 사용하기 때문에 @RoutePrefix + @Route 또는 @RoutePrefix + @RouteAlias로 경로를 정의한다.

 

또한 layout 선언으로 쓰이는 component도 @Route를 가지고 있다면 그 자체로 호출 처리를 한다.

예를 들어 위의 BoardLayout이 다음과 같이 선언되어 있다면

@Route("")
@RoutePrefix("board")
@ParentLayout(CommonLayout.class)
public class BoardLayout extends Div implements RouterLayout {
	// Layout 구현
}

@Route + @RoutePreifix로 정의되는 호출 경로인 "/board" 요청을 BoardLayout이 처리한다.

 

해결하지 못한 부분

여기까지 보면 언뜻 간결해 보이지만 하위 구현 없이 layout만 쓰는 경우 layout이 사용할 contents 부분은 어떻게 구성할지 이런 부분은 찾아보지 못했다.

 

Security 관련 annotation 사용 전파가 안되었음

 

route처리나 layout은 조합해서 사용이 되지만 security와 관련된 @AnonymousAllowed, @RolesAllowed("ROLE_USER") 같은 선언은 layout에서 하위 route 호출로 전파가 되지 않는 듯했다.

이로 인해 호출하는 view가 많아지면 많아질수록 권한 관리 설정 부분이 불편하게 느껴졌다.

 

Spring 연계 다국어 처리

https://vaadin.com/docs/latest/advanced/i18n-localization

 

vaadin은 다국어 처리를 하려면 I18NProvider를 설정하면 된다.

 

따라서 만약 Spring의 다국어 메시지를 사용하려는 경우 Spring 쪽에서 messageSourceAccessor bean을 따로 선언하여 다국어 처리를 한 후

@Bean
MessageSourceAccessor messageSourceAccessor(MessageSource messageSource) {
    return new MessageSourceAccessor(messageSource);
}

 

해당 다국어 메시지를 사용하는 I18NProvider을 구현하면 된다.

@Component
public class MyI18NProvider implements I18NProvider {
	
	private static final long serialVersionUID = 1L;
	
	private MessageSourceAccessor messageSourceAccessor;
	
	public GateI18NProvider(MessageSourceAccessor messageSourceAccessor) {
		this.messageSourceAccessor = messageSourceAccessor;
	}

	@Override
	public List<Locale> getProvidedLocales() {
		return List.of(Locale.KOREA, Locale.US);
	}

	@Override
	public String getTranslation(String key, Locale locale, Object... params) {
		return messageSourceAccessor.getMessage(key, params, locale);
	}

}

사용은 vaadin component를 구현한 class에서 다음과 같이 getTranslation method를 호출하면 된다.

writeButton.setText(getTranslation("board.button.write"));

Locale 설정은 다음과 같이 하면 된다.

VaadinSession.getCurrent().setLocale(locale);

Select 메뉴로 Locale 목록을 보여주고 선택하는 경우 지정하는 예제는 다음과 같다.

I18NProvider i18nProvider = VaadinService.getCurrent().getInstantiator().getI18NProvider();

Select<Locale> localeSelect = new Select<>(e -> {
    var locale = e.getValue();
    localeResolver.setLocale(VaadinServletRequest.getCurrent().getHttpServletRequest(), VaadinServletResponse.getCurrent().getHttpServletResponse(), locale);
    VaadinSession.getCurrent().setLocale(locale);
});
localeSelect.setItems(i18nProvider.getProvidedLocales());
localeSelect.setItemLabelGenerator(Locale::getDisplayLanguage);
localeSelect.setValue(VaadinSession.getCurrent().getLocale());

Maven 사용 시 빌드 설정 

https://vaadin.com/docs/latest/configuration/maven

 

vaadin을 사용하는 application을 빌드할 때 vaadin의 결과물도 같이 빌드하도록 설정이 필요하다.

 

maven을 사용하는 경우 vaadin-maven-plugin 설정을 해주어야 한다.

<plugin>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-maven-plugin</artifactId>
    <version>${vaadin.version}</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-frontend</goal>
                <goal>build-frontend</goal>
            </goals>
            <phase>compile</phase>
        </execution>
    </executions>
    <configuration>
        <forceProductionBuild>true</forceProductionBuild>
        <ciBuild>true</ciBuild>
    </configuration>
</plugin>

Grid component 사용 시 Spring Data의 Page와 연동

Spring Data를 사용하여 다음과 같이 Page 데이터를 내려주는 경우

public interface BoardArticleClient {
	Page<BoardArticle> findByBoardAlias(@RequestParam String boardAlias, Pageable pageable);
}

 

해당 데이터를 표로 보여주는 vaadin의 Grid component를 사용할 때 이 Spring Data의 Page에 대한 VaadinSpringDataHelpers를 다음과 같이 사용할 수 있다.

var boardArticleGrid = new Grid<>(BoardArticle.class);
boardArticleGrid.setColumns("id", "title", "createdDate");

boardArticleGrid.setItems(q -> boardArticleClient.findByBoardAlias(boardAlias, VaadinSpringDataHelpers.toSpringPageRequest(q)).stream());

Vaadin을 사용하면서 가장 강력한 장점으로 보이는 부분이 화면에 보이는 ui에 데이터를 처리할 때 lazy loading이나 paging 처리를 별다른 코딩을 하지 않더라도 구현해 준다는 것이었다

 

데이터가 많으면 화면 렌더링에 부하가 생기는데 vaading이 페이징 호출을 알아서 처리해 주어 복잡하게 관련 스크립트를 작성할 필요가 없었다.

 

반응형