SpringBoot 를 배워보자

Nuxt.js와 Spring Boot로 Oracle 저장 프로시저 소스 및 파라미터 조회하기

_Blue_Sky_ 2025. 3. 1. 21:07
728x90

Nuxt.js 프론트엔드와 Spring Boot 백엔드를 사용해 Oracle DB에서 특정 저장 프로시저의 소스 코드를 조회하고 화면에 표시하는 방법을 소개합니다.

 Spring Boot에서 저장 프로시저 소스 조회 API를 확장해서, 소스 코드와 함께 저장 프로시저의 파라미터 정보도 함께 반환하도록 수정하겠습니다. Oracle DB에서 파라미터 정보는 USER_ARGUMENTS 또는 ALL_ARGUMENTS 뷰를 통해 조회할 수 있습니다. 아래는 이를 반영한 코드입니다.

 
 
Spring Boot: 저장 프로시저 소스 + 파라미터 정보 조회
1. 프로젝트 설정 (pom.xml)
(이전과 동일, 변경 없음)
xml
 
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc8</artifactId>
        <version>21.1.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jdbc</artifactId>
    </dependency>
</dependencies>
2. application.properties
(이전과 동일, 변경 없음)
properties
 
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:ORCL
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
3. 비동기 설정 (AsyncConfig.java)
(이전과 동일, 변경 없음)
java
 
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfig {
}
4. 응답 DTO 추가 (ProcedureInfo.java)
파라미터와 소스를 함께 담을 DTO를 정의합니다.
java
 
public class ProcedureInfo {
    private String source;
    private List<Parameter> parameters;

    public ProcedureInfo(String source, List<Parameter> parameters) {
        this.source = source;
        this.parameters = parameters;
    }

    // Getters and Setters
    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public List<Parameter> getParameters() {
        return parameters;
    }

    public void setParameters(List<Parameter> parameters) {
        this.parameters = parameters;
    }

    public static class Parameter {
        private String name;
        private String dataType;
        private String inOut; // IN, OUT, IN OUT

        public Parameter(String name, String dataType, String inOut) {
            this.name = name;
            this.dataType = dataType;
            this.inOut = inOut;
        }

        // Getters and Setters
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDataType() {
            return dataType;
        }

        public void setDataType(String dataType) {
            this.dataType = dataType;
        }

        public String getInOut() {
            return inOut;
        }

        public void setInOut(String inOut) {
            this.inOut = inOut;
        }
    }
}
5. 컨트롤러 (ProcedureController.java)
java
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api")
public class ProcedureController {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping("/procedure-source/{procedureName}")
    @Async
    public CompletableFuture<ProcedureInfo> getProcedureSource(@PathVariable String procedureName) {
        // 비동기 작업 시뮬레이션 (1초 대기)
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return CompletableFuture.completedFuture(new ProcedureInfo("Error: Interrupted", null));
        }

        // 1. 저장 프로시저 소스 조회
        String sourceQuery = "SELECT TEXT FROM USER_SOURCE WHERE NAME = UPPER(?) AND TYPE = 'PROCEDURE' ORDER BY LINE";
        List<String> sourceLines = jdbcTemplate.query(sourceQuery, 
            (rs, rowNum) -> rs.getString("TEXT"), 
            procedureName.toUpperCase()
        );
        String source = sourceLines.isEmpty() ? null : String.join("\n", sourceLines);

        // 2. 파라미터 정보 조회
        String paramQuery = "SELECT ARGUMENT_NAME, DATA_TYPE, IN_OUT " +
                           "FROM USER_ARGUMENTS WHERE OBJECT_NAME = UPPER(?) AND OBJECT_TYPE = 'PROCEDURE'";
        List<ProcedureInfo.Parameter> parameters = jdbcTemplate.query(paramQuery, 
            (rs, rowNum) -> new ProcedureInfo.Parameter(
                rs.getString("ARGUMENT_NAME"),
                rs.getString("DATA_TYPE"),
                rs.getString("IN_OUT")
            ),
            procedureName.toUpperCase()
        );

        // 결과 반환
        if (source != null || !parameters.isEmpty()) {
            return CompletableFuture.completedFuture(new ProcedureInfo(source, parameters));
        } else {
            return CompletableFuture.completedFuture(new ProcedureInfo("{\"error\": \"Procedure not found\"}", null));
        }
    }
}

 
 
6. 테스트
예제 저장 프로시저
sql
 
CREATE OR REPLACE PROCEDURE SAMPLE_PROC (p_input IN VARCHAR2, p_output OUT NUMBER) AS
BEGIN
    p_output := LENGTH(p_input);
    DBMS_OUTPUT.PUT_LINE('Input length: ' || p_output);
END SAMPLE_PROC;
/
요청
bash
 
curl http://localhost:8080/api/procedure-source/SAMPLE_PROC
예상 응답 (성공 시)
json
 
{
    "source": "CREATE OR REPLACE PROCEDURE SAMPLE_PROC (p_input IN VARCHAR2, p_output OUT NUMBER) AS\nBEGIN\n    p_output := LENGTH(p_input);\n    DBMS_OUTPUT.PUT_LINE('Input length: ' || p_output);\nEND SAMPLE_PROC;",
    "parameters": [
        {
            "name": "P_INPUT",
            "dataType": "VARCHAR2",
            "inOut": "IN"
        },
        {
            "name": "P_OUTPUT",
            "dataType": "NUMBER",
            "inOut": "OUT"
        }
    ]
}
예상 응답 (실패 시)
json
 
{
    "source": "{\"error\": \"Procedure not found\"}",
    "parameters": null
}

코드 설명
  1. 소스 조회:
    • USER_SOURCE에서 TEXT 컬럼을 가져와 소스 코드를 구성합니다.
  2. 파라미터 조회:
    • USER_ARGUMENTS에서 ARGUMENT_NAME, DATA_TYPE, IN_OUT을 조회.
    • 저장 프로시저가 파라미터를 가지지 않더라도 소스만 있으면 결과 반환.
  3. DTO 활용:
    • ProcedureInfo 클래스와 내부 Parameter 클래스로 소스와 파라미터를 구조화.
    • JSON 직렬화가 자동으로 처리됨.
  4. 비동기 처리:
    • @AsyncCompletableFuture로 비동기 실행 유지.
    • Thread.sleep(1000)으로 FastAPI의 asyncio.sleep(1) 모방.

추가 개선 가능성
  • 에러 처리 강화:
    java
     
    if (source == null && parameters.isEmpty()) {
        return CompletableFuture.completedFuture(ResponseEntity.status(404).body(new ProcedureInfo("Procedure not found", null))).thenApply(ResponseEntity::getBody);
    }
    HTTP 상태 코드를 명시적으로 설정.
  • CORS 설정: Vue.js와 연동 시 필요 (이전 답변의 WebConfig 참고).

결론
Spring Boot로 저장 프로시저 소스와 파라미터 정보를 함께 조회하는 API를 구현했습니다. USER_SOURCEUSER_ARGUMENTS를 활용해 소스와 파라미터를 구조화된 JSON으로 반환하며, 비동기 처리를 유지했습니다. 추가 요청 있으면 말씀해주세요!
728x90