Nexacro 공부를 위해 SpringBoot + Oracle + Nexacro 토이 프로젝트를 진행하기로 함
재고 및 물품 관리 시스템으로, 현재 재고 상태를 보여주는 대시보드를 제작할 예정
기술 스택
| Frontend | Nexacro N |
| Backend | SpringBoot 3.2.5 + MyBatis |
| DB | Oracle XE 21c (Docker) |
| 빌드 | Gradle |
❗JPA가 아닌 MyBatis를 선택한 이유
MyBatis는 직접 SQL문을 작성할 수 있고, DBMS별 문법을 세밀하게 제어할 수 있음
또한 Oracle과의 궁합도 좋기 때문에 Oracle 공부도 더 할겸 MyBatis를 선택함
💡 Nexacro 핵심 개념
Form
화면 하나 = Form 하나
React의 Page 컴포넌트와 비슷한 개념
Dataset
화면에서 데이터를 담는 그릇
SpringBoot API 응답을 받아서 저장하고, Grid 같은 컴포넌트에 연결
Dataset ← API 응답 데이터 저장
↓
Grid ← Dataset 바라보며 화면에 표시
Transaction
Nexacro에서 SpringBoot API를 호출하는 방식
일반적인 fetch/axios 대신 Nexacro 전용 통신 방식을 사용함
// Nexacro 방식
this.transaction(
"조회", // 트랜잭션 ID
"SVC::getDashboard.do", // 호출할 서비스 URL
"", // 전송할 Dataset (없으면 빈칸)
"dsDashboard=output", // 응답 받을 Dataset
"", // 파라미터
"fn_callBack" // 콜백 함수명
);
📌 Nexacro 설치
먼저 아래 링크에서 Nexacro 체험판과 라이선스를 다운 받음
https://www.tobesoft.com/product/nexacro
투비소프트
DEV.TOOL 비즈니스용 UI·UX 개발 소프트웨어의 공급부터 안정적 구축, 유지보수 수행까지 기업을 위한 서비스를 제공합니다.
www.tobesoft.com
설치 과정은 다른 거 건드릴 필요 없이 기본 세팅된 대로 설치하면 됨
Nexacro 라이브러리 다운로드
xapi 라이브러리와 uiadapter 라이브러리가 필요함
- xapi는 클라이언트(화면)와 서버 간의 데이터를 송수신하고 처리하기 위해 필요한 자바 기반 서버 모듈
- uiadapter는 넥사크로와 서버 간 데이터 구조 차이를 보완해주는 모듈
아래 링크에서 com/nexacro 폴더로 이동 후 xapi 라이브러리와 uiadapter 라이브러리 다운
https://mangosteen.tobesoft.co.kr/nexus/#browse/browse:maven-public
Nexus Repository Manager
mangosteen.tobesoft.co.kr
❗이때 SpringBoot 3로 프로젝트를 설정했다면 Nexacro 라이브러리는 반드시 jakarta 버전으로 다운받아야 함
jakarta 버전이 아닌 라이브러리를 다운 받으면 해당 라이브러리는 javax를 사용하기 때문에 java.lang.NoClassDefFoundError: javax/servlet/ServletOutputStream 오류가 발생함

📌 Nexacro 프로젝트 설정
상단 메뉴에서 새 프로젝트 생성

넥사크로 프로젝트와 스프링부트 프로젝트를 같은 폴더에 두지 않고 분리할 것이기 때문에 프로젝트 위치는 본인이 편한 경로로 지정하면 됨
프로젝트 이름 설정하고 Next 클릭

이후 설정은 본인이 만들고 싶은 화면대로 설정하면 됨
나는 간단한 개인 공부용 프로젝트기 때문에 Screen은 Desktop, 템플릿은 Full로 지정함


이후 Finish 눌러 프로젝트 생성
TypeDefinition 경로 설정
nexacro에서 script를 작성할 때마다 일일이 모든 경로를 작성하기 어려우므로, 자주 쓰는 경로의 경우 별칭을 지정하면 편함
TypeDefinition - Services 클릭

User Service에서 아래 내용 등록
- SVC - 백엔드 API 호출용. 본인의 로컬호스트 주소 e.g.) http://localhost:8080/
- nexacrolib - 넥사크로 엔진 라이브러리
prefixID의 경우 본인이 편한대로 작성해도 됨

📌 SpringBoot 프로젝트 설정
앞서 다운 받았던 nexacro 관련 라이브러리를 스프링부트 프로젝트에 직접 추가해야 함
본인은 루트 폴더에 libs 폴더 생성 후 필요한 jar 파일들을 넣어두었음

의존성 추가
build.gradle에 로컬 jar 의존성 추가 및 라이브러리 관련 추가 의존성 추가
관련 내용은 https://naahy0co.tistory.com/83 참고
dependencies {
// 기존 의존성들 ...
// Nexacro 라이브러리 (로컬 jar)
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Nexacro XAPI 의존성
implementation 'jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.1.1'
implementation 'commons-lang:commons-lang:2.6'
}
로컬 jar에 대한 의존성을 새로 추가했으므로 gradle 빌드를 새로 해줘야 함
📌 SpringBoot - Nexacro 연동
SpringBoot CORS 설정 추가
Nexacro Studio에서 localhost로 API를 호출할 때 CORS 에러가 나기 때문에 미리 열어둬야 함
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}
Nexacro Config 작성
Spring MVC의 기본 JSON 기반 요청/응답 처리 체계를 Nexacro Dataset/XML 기반 처리 체계로 교체하는 설정 클래스
import com.nexacro.java.xapi.tx.PlatformType;
import com.nexacro.uiadapter.jakarta.core.context.ApplicationContextProvider;
import com.nexacro.uiadapter.jakarta.core.resolve.NexacroHandlerMethodReturnValueHandler;
import com.nexacro.uiadapter.jakarta.core.resolve.NexacroMappingExceptionResolver;
import com.nexacro.uiadapter.jakarta.core.resolve.NexacroMethodArgumentResolver;
import com.nexacro.uiadapter.jakarta.core.resolve.NexacroRequestMappingHandlerAdapter;
import com.nexacro.uiadapter.jakarta.core.view.NexacroFileView;
import com.nexacro.uiadapter.jakarta.core.view.NexacroView;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import java.util.List;
@Configuration
public class NexacroConfig extends WebConfig implements WebMvcRegistrations {
/**
* Spring Bean들을 Nexacro 내부에서도 참조할 수 있게 함
*/
@Bean
@Lazy(false)
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
/**
* SpringAdapter를 NexacroAdapter로 교체
* Spring MVC를 Nexacro용으로 교체
*/
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return new NexacroRequestMappingHandlerAdapter();
}
/**
* Controller 파라미터 해석기 등록
* Dataset --> Java 객체 변환기
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
NexacroMethodArgumentResolver nexacroResolver = new NexacroMethodArgumentResolver();
resolvers.add(nexacroResolver);
super.addArgumentResolvers(resolvers);
}
/**
* 응답 처리기
* Controller 반환값(NexacroResult)을 Nexacro Dataset/XML 응답으로 변환
*/
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
NexacroHandlerMethodReturnValueHandler returnValueHandler = new NexacroHandlerMethodReturnValueHandler();
// 실제 응답 생성기
NexacroView nexacroView = new NexacroView();
nexacroView.setDefaultContentType(PlatformType.CONTENT_TYPE_XML);
nexacroView.setDefaultCharset("UTF-8");
returnValueHandler.setView(nexacroView);
// 파일 다운로드 전용
NexacroFileView nexacroFileView = new NexacroFileView();
returnValueHandler.setFileView(nexacroFileView);
handlers.add(0, returnValueHandler); // 핸들러 순서 명시
super.addReturnValueHandlers(handlers);
}
/**
* 넥사크로플랫폼 에러 처리 ExceptionResolver 등록
* Exception → Nexacro 에러 응답
*/
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
NexacroView nexacroView = new NexacroView();
nexacroView.setDefaultContentType(PlatformType.CONTENT_TYPE_XML);
nexacroView.setDefaultCharset("UTF-8");
NexacroMappingExceptionResolver nexacroException = new NexacroMappingExceptionResolver();
nexacroException.setView(nexacroView);
nexacroException.setShouldLogStackTrace(true); // 서버 로그 출력
nexacroException.setShouldSendStackTrace(true); // 클라이언트(Nexacro)에도 스택트레이스 전달
nexacroException.setOrder(1);
resolvers.add(nexacroException);
super.configureHandlerExceptionResolvers(resolvers);
}
}
Nexacro 전용 Controller 추가
Nexacro는 JSON이 아닌 자체 포맷으로 통신함
기존 REST API Controller와 별도로 Nexacro 전용 Controller를 만들어야 한다
-> 컨트롤러가 NexacroResult를 반환하도록 작성
import com.example.inventory.domain.DashboardDto;
import com.example.inventory.mapper.DashboardNexacroMapper;
import com.example.inventory.service.DashboardService;
import com.nexacro.uiadapter.jakarta.core.data.NexacroResult;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
// 매핑용 URL은 원하는 내용으로 작성. 추후 nexacro script에 작성해야 하는 것만 알면 됨
@Controller
@ResponseBody
@RequestMapping("/nexacro")
@RequiredArgsConstructor
public class NexacroDashboardController {
private final DashboardService dashboardService;
@GetMapping("/dashboard")
public NexacroResult getDashboard() {
// 1.
DashboardDto dashboard = dashboardService.getDashboard();
// 2.
return DashboardNexacroMapper.toResult(dashboard); // DTO를 NexacroResult로 변환
}
}
- service에서 대시보드 정보를 받아와 DTO에 저장 (각 service와 DTO는 본인 프로젝트에 맞게 작성)
- 해당 DTO를 NexacroResult로 변환하는 Mapper 클래스
DashboardNexacroMapper
DTO를 Dataset으로 변환하여 NexacroResult에 해당 데이터셋 추가 후 반환하는 클래스
Nexacro는 Dataset 단위로 데이터를 주고받으므로, 각각의 데이터셋 정보는 분리해서 넘겨주는 것이 좋음
import com.example.inventory.domain.DashboardDto;
import com.example.inventory.domain.DashboardSummary;
import com.nexacro.uiadapter.jakarta.core.data.NexacroResult;
import java.util.List;
public class DashboardNexacroMapper {
public static NexacroResult toResult(DashboardDto dashboardDto) {
NexacroResult result = new NexacroResult();
// 요약 카드 - DataSet
// DashboardSummary는 아래 내용을 담은 DTO
DashboardSummary summary = new DashboardSummary(
dashboardDto.getTotalItemCount(),
dashboardDto.getTotalStockQty(),
dashboardDto.getLowStockCount(),
dashboardDto.getCategoryCount()
);
result.addDataSet("dsSummary", List.of(summary));
/**
* summary DTO를 새로 만들지 않고
* 아래처럼 직접 데이터셋 생성 후 일일이 붙이는 방법도 있음
* 관련 코드가 너무 길어지기 때문에 따로 DTO를 새로 선언한 것
DataSet dsSummary = new DataSet("dsSummary");
dsSummary.addColumn("totalItemCount", "INT");
dsSummary.addColumn("totalStockQty", "INT");
dsSummary.addColumn("lowStockCount", "INT");
dsSummary.addColumn("categoryCount", "INT");
int row = dsSummary.newRow();
dsSummary.set(row, "totalItemCount", dashboardDto.getTotalItemCount());
dsSummary.set(row, "totalStockQty", dashboardDto.getTotalStockQty());
dsSummary.set(row, "lowStockCount", dashboardDto.getLowStockCount());
dsSummary.set(row, "categoryCount", dashboardDto.getCategoryCount());
outData.addDataSet(dsSummary);
*/
// 카테고리별 재고
result.addDataSet(
"dsCategoryStock",
dashboardDto.getCategoryStocks()
);
... // 이후 위와 같이 필요한 Dataset을 각각 추가
return result;
}
}
모두 작성 후 실행했을 때 문제 없이 실행 되면 연동이 잘 된 것
📌 Nexacro 화면 작성
좌측 메뉴에서 FrameBase - Form_Work 클릭

프로젝트 생성 시 템플릿을 Full로 선택했기 때문에 빈 화면일 것
상단 메뉴에서 각 요소를 골라 화면을 꾸밀 수 있음
컴포넌트와 버튼 등을 추가하여 화면을 꾸미자
노란 원으로 표시된 것이 왼쪽부터 button, static, grid

데이터 연동이 잘 이루어지는지만 먼저 확인할 것이기 때문에 간단하게 static 4개와 grid 1개만 화면에 배치함
이때 각각의 static은 dsSummary의 내용을, grid는 dsCategoryStock 내용을 저장할 것 -> 위의 DashboardNexacroMapper에서 nexacroResult에 추가한 dataset 정보가 표시되는 것

각 컴포넌트의 아이디를 다음처럼 바꾼다. (static 컴포넌트의 경우 화면에 표시될 text도 아래처럼 변경)
| ID | 컴포넌트 | text |
| stTotalItem | Static | 0 개 |
| stTotalStock | Static | 0 개 |
| stLowStock | Static | 0 개 |
| stCategory | Static | 0 개 |
| grdCategory | Grid |
상단 메뉴에서 Dataset 클릭 후, 페이지 아무 곳이나 클릭하면 하단에 dataset이 추가됨


dataset을 더블 클릭하여 id와 열 정보를 아래처럼 입력

이후 dataset을 마우스로 드래그하여 grid 컴포넌트에 놓으면 해당 ds가 grid 컴포넌트에 바인딩 됨
데이터셋이 바인딩 된 grid 컴포넌트를 더블 클릭하여, 표시될 텍스트를 아래처럼 변경해보자

Script 작성
페이지 하단을 보면 script 메뉴가 있을 것이다
해당 메뉴를 클릭하면 빈 화면이 뜰 건데, 그 화면에 아래 내용을 입력하면 됨
springBoot에서 받아온 정보를 form의 컴포넌트와 연결하는 것
// 화면 로드 시 자동 실행
this.Dashboard_onload = function(obj, e) {
this.fn_getDashboard();
}
// 대시보드 조회
this.fn_getDashboard = function() {
this.transaction(
"getDashboard", // 트랜잭션 ID
"SVC::nexacro/dashboard", // 서비스 URL - SpringBoot Controller
"", // 전송 Dataset (없음)
"dsSummary=dsSummary "
+ "dsCategoryStock=dsCategoryStock "
+ "추가 데이터셋 있으면 작성 ", // 수신 Dataset
"", // 파라미터
"fn_getDashboardCallBack" // 콜백 함수
);
}
// 조회 완료 콜백
this.fn_getDashboardCallBack = function(svcId, errorCode, errorMsg) {
if (errorCode < 0) {
alert("오류 발생: " + errorMsg);
return;
}
// 요약 카드 수치 업데이트
this.stTotalItem.set_text(this.dsSummary.getColumn(0, "totalItemCount") + " 개");
this.stTotalStock.set_text(this.dsSummary.getColumn(0, "totalStockQty") + " 개");
this.stLowStock.set_text(this.dsSummary.getColumn(0, "lowStockCount") + " 개");
this.stCategory.set_text(this.dsSummary.getColumn(0, "categoryCount") + " 개");
// Grid는 Dataset에 바인딩되어 있으면 자동으로 표시
}
📌 실행
상단의 launch 버튼을 눌러 화면을 실행해보자
해당 버튼을 누르면 어떤 화면이 뜰 건데, 뭐 건드릴 필요 없이 Run 실행하면 됨

연동이 잘 된 것을 확인할 수 있다.
일단 데이터가 잘 주고받아지는지 확인하려 했던 것이기 때문에 나머지 화면 구현은 나중에...

참고
https://123okk2.tistory.com/538#google_vignette
[Nexacro + Spring Boot] 넥사크로(1/3) - 프로젝트 생성 및 설정
다음 프로젝트에서 프론트엔드로 넥사크로를 사용하기로 결정했다. 처음 사용해보는 개발툴이라 열심히 연습하며 느낀 점은... 이번에야 이미 결정된 일이라 어쩔 수 없다지만 솔직히 이걸 두
123okk2.tistory.com
https://blog.naver.com/goodee0205/224071956196
[개발자국비교육]Mybatis vs JPA 어떤걸 선택하지?
웹 백엔드 개발을 하다 보면 데이터베이스와 연결하는 방식으로 MyBatis 또는 JPA를 많이 접하게 됩니...
blog.naver.com
'SpringBoot' 카테고리의 다른 글
| [SpringBoot] Flyway로 DB 마이그레이션 및 DDL 작성 (1) | 2026.06.08 |
|---|---|
| [SpringBoot] Swagger를 이용한 API 문서 자동화 (0) | 2026.05.31 |
| [AWS] SpringBoot + AWS EC2 Ubuntu 서버 생성 및 배포 (0) | 2026.04.07 |
| [AWS] RDS DB 인스턴스 생성(PostgreSQL) 및 SpringBoot 연동 (0) | 2026.04.07 |
| [SpringBoot] Spring Secutiry + JWT 기반 로그인 구현 (0) | 2026.01.22 |