본문 바로가기

JAVA

[JQGRID] Spring 설정과 Annotation을 이용한 jqGrid Component

개발을 하다보면,

반복적이고 행위와 중복적인 코드를 생산해낼 일이 수도 없이 많다. 

풀 스텍 개발자로서 흔히 웹에서 벌어지는 조회라는 단순한 업무에도 아주 많은 코드의 중복이나 행위로서 많은 시간적인 낭비나 효율이 떨어지는 상황이 발생하기 마련이다. 

그래서 고민해보았다. 


세계에서 범용적으로 사용하는 화면단 OpenSource인 jqGrid가 있다. 지금은 상용화가 일부 되었지만 최신 버전이 아니라면 무료로 제공받을 수 있다. 이 jqGrid는 실제로 업무에서 다양한 방법으로 사용될 수 있다. jqGrid 하나만 사용하더라도 목록형 형태로 이루어진 자료들을 조회, 입력, 수정, 삭제와 같은 행위 뿐만 아니라 병합, 합계 등 다양한 방법으로 활용할 수 있다.그것 전부의 모듈화는 힘들지만 내가 겪었던 그리고 많이 썼던 조회하기 위해 반드시 수행해야 했던 과정들을 컴포넌트화 하였다. 


jqGrid를 조회하기 위한 순서는 이렇다.


1.View에서 jqGrid를 표출할 돔 ID에 jqGrid를 생성하고 옵션을 설정한다. 필히 옵션에서 설정해주어야 할 부분이 존재하지만 그럴 필요 없는 것도 있다. 


2. 설정된 옵션의 URL은 text나 json이나 xml 방식으로 jqGrid에 표출할 데이터를 조회할 대상의 url을 기입한다. 


3. url에서 조회된 데이터는 json 형태로서 어떤 형태로든 간에 실제로 데이터베이스에서 조회된 결과를 한번 더 가공하는 과정을 거쳐야 한다. 


이런 일련의 과정중에서 가장 많이 그리고 비효율적이고 모듈화가 아닌 형태들이 많이 발견된다. 


1. 데이터베이스에서 가져온 데이터를 jqGrid 형태에 맞게 가공해야 한다. 


2. 모델 또한 그에 맞게 가공해야 하나 FM 방식으로 하려면 하드코딩 방식으로 기입 될 것이다. 


여기서 모델은 큰 문제가 되지 않지만 데이터를 가공하는 과정은 누구든 함수화하여 사용하고 있을지도 모른다. 허나 그 또한 비 효율적이다. 왜냐 간편하지 않고, 반복적이면서, 중복된 코드를 생산해내기 때문이다. 


또한, Grid ID를 어떤 값으로 할건지, 데이터 포맷은 어떻게 바꿔줄건지, jqGrid Cell에는 어떤 커스텀화 된 정보를 줄건지 같은 것들에 대해서는 모듈화 시킨다고 한들 많은 불편함과 IF 문을 만들어낼 것이다. 


그래서 만든 것이 jqGrid와 데이터베이스간에 관계를 만들어 출력하는 것이다. 


데이터베이스와 Grid간 데이터를 매핑 시켜줄 수 있는 긴밀한 연관관계에 있는 무언가를 찾았다. 그것은 'Domain'객체 였는데 Hibernate가 대세임에 따라 하나의 엔티티에는 하나의 Domain이 생성되어 있을 것이다. 그것의 Annotation에 힌트를 얻어서 Domain 객체의 변수에 Annotation을 설정하여 Grid를 생성할때 필요한 Model이랑 데이터를 구성하기로 하였다. 


Annotation


어노테이션을 커스텀 어노테이션을 생성할 수 있다. 


@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Grider {


이러한 형태로 구성할 수 있으며 이 클래스에는 리턴타입과, 함수명, 그리고 default 값을 지정해놓을 수 있다. 이렇게 Annotation 클래스가 완성되면 실제로 이렇게 사용된다. 


@Grider(label="com.ese.customCheck",align=Align.center, sort=true,format=Format.customCheckbox,hidden=false, width="10")

private int checkCustom;


여기서 설정할 수 있는 기능은 다음과 같다.


1. 셀 텍스트 정렬

2. 국제화 메시지 변환

3. 헤더의 정렬 여부

4. 컬럼 숨김 여부

5. 포맷 지원(Text, customCheckbox, checkbox, function, dateExp)

  - checkbox는 해당 컬럼의 결과가 Y,N일 경우 자동으로 체크 및 해제한다. 

  - Function은 해당 셀의 값에 버튼이나 사용자가 원하는 태그를 삽입할 수 있다. 

  - dateExp는 날짜형식의 데이터의 포맷을 조작하여 Grid 상에 조작된 포맷형태로 출력시킨다. 


Grider라는 Annotation 클래스와 맴버 함수를 통해 라벨 명이라든지 등 jqGrid에서 사용할 법만한 정보들을 셋팅한다. 

이 정보들은 jqGrid의 ColModel과 URL 정보를 통해 데이터를 가져와서 Mapping 할때 사용하는 정보들이 Annotation으로 구성된다. 


Annotation 정보는 아래의 함수에 의해 Parsing 되고 정재되어 jqGrid의ColModel 값으로 재탄생하게 된다. 


1. messageSource를 인자로 주는 경우


grimp.buildGrimpHeader(Dvsn.class, message, locale)


2. messageSource를 Bean 등록 시 주입하는 경우


grimp.buildGrimpHeader(Dvsn.class, locale)


Bean 생성 시 MessageSource를 등록시키는 경우는 내부적으로 Bean 생성 시에 MessageSource나 WebApplicationContext가 주입이 되어 있기 때문에 인자로 넘겨주지 않아도 된다.



그리고,

데이터베이스에서 조회된 값을 Grivo라는 객체의 생성자에 페이징 정보와 함께 주입한다. 


1. 자료의 리턴 자료구조가 Domain 객체 인 경우


new Grivo(paramMap, mapper.getDvsnDomain(paramMap));


리턴 자료형의 ArrayList<Domain> 일경우에는 Domain의 정보에서 해당 Grider 정보를 얻어올 수 있기 때문에 인자로 넘길 필요가 없다.



2. 자료의 리턴 자료구조가 HashMap 인 경우


new Grivo(Class<?> cls, paramMap, mapper.getDvsnDomain(paramMap));


리턴 자료형이 ArrayList<HashMap> 인 경우 Key값과 매핑할 수 있는 Domain 객체 정보를 매핑시켜주어야 하며, 매핑기준은 HashMap의 Key값과 Domain 객체의 변수명이다.


위에서 생성한 Grivo 객체를 아래의 함수에 주입시켜주면 jqGrid의 목록에 해당하는 json 형태의 데이터로 변환해준다. 


String grimp.buildGrimpToStr(grivo);

JSONObject grimp.buildGrimp(grivo);





Spring 설정


이 컴포넌트는 최초에 Bean으로 등록해주어야 한다


@Bean

private Grimp grimp() {

new Grimp(new MessageSource());

new Grimp(new WebApplicationContext());

new Grimp();

}