Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Java CI with Gradle

on:
push:
branches: [ "develop_eh", "main" ]
pull_request:
branches: [ "develop_eh", "main" ]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: 'legal/FrontEnd/my-react-app/package-lock.json'

- name: Build with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: build -x test
build-root-directory: legal/BackEnd
49 changes: 49 additions & 0 deletions legal/BackEnd/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,52 @@ dependencies {
tasks.named('test') {
useJUnitPlatform()
}

// ============================================================
// 프론트엔드 빌드 자동화
// ============================================================

// Node.js 경로 (Windows)
def npmCommand = System.getProperty('os.name').toLowerCase().contains('windows') ? 'npm.cmd' : 'npm'
def frontendDir = file("${projectDir}/../FrontEnd/my-react-app")

// 1. 프론트엔드 npm install
task npmInstall(type: Exec) {
description = '프론트엔드 의존성 설치'
workingDir frontendDir
commandLine npmCommand, 'install'

// package.json이 변경되었을 때만 실행
inputs.file("${frontendDir}/package.json")
outputs.dir("${frontendDir}/node_modules")
}

// 2. 프론트엔드 빌드
task buildFrontend(type: Exec, dependsOn: npmInstall) {
description = '프론트엔드 빌드 (npm run build)'
workingDir frontendDir
commandLine npmCommand, 'run', 'build'

// src 폴더가 변경되었을 때만 재빌드
inputs.dir("${frontendDir}/src")
inputs.file("${frontendDir}/package.json")
outputs.dir("${frontendDir}/dist")
}

// 3. 빌드 결과물을 static 폴더로 복사
task copyFrontend(type: Copy, dependsOn: buildFrontend) {
description = '프론트엔드 빌드 결과물을 static 폴더로 복사'
from "${frontendDir}/dist"
into "${projectDir}/src/main/resources/static"
}

// 4. processResources 전에 프론트엔드 빌드 실행
processResources.dependsOn copyFrontend

// 5. clean 시 static 폴더의 빌드 결과물도 삭제 (선택적)
task cleanFrontend(type: Delete) {
description = 'static 폴더의 프론트엔드 빌드 결과물 삭제'
delete "${projectDir}/src/main/resources/static/assets"
delete "${projectDir}/src/main/resources/static/index.html"
}
clean.dependsOn cleanFrontend
Empty file modified legal/BackEnd/gradlew
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.oracle.Legal.controller;

import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import com.oracle.Legal.dto.BoonjangDto;
import com.oracle.Legal.service.BoonjangService;

import lombok.RequiredArgsConstructor;

/**
* 분쟁 유형 분류 API 컨트롤러
*
* [역할]
* - React 프론트엔드에서 호출하는 REST API 엔드포인트 제공
* - /api/boonjang 경로로 분쟁 데이터 저장 및 조회
*
* [엔드포인트]
* - POST /api/boonjang : 분쟁 내용 저장 및 분석
* - GET /api/boonjang : 분쟁 목록 조회
*
* [데이터 흐름]
* React → POST /api/boonjang → Controller → Service → Repository → DB
* ↓
* 분석 결과 반환
*/
@org.springframework.web.bind.annotation.RestController
@RequestMapping("/api/boonjang")
@RequiredArgsConstructor
public class BoonjangApiController {

private final BoonjangService boonjangService;

/**
* 분쟁 내용 분석 및 저장
*
* [요청 형식]
* POST /api/boonjang
* Content-Type: application/json
* {
* "boonjangInput": "분쟁 내용...",
* "clientCode": 1001 (선택, 로그인한 사용자)
* }
*
* [응답 형식]
* {
* "boonjangId": 1001,
* "classification": "민사",
* "subType": "소비자",
* "summary": "...",
* "keywords": ["#청약철회", ...],
* "judgment": "...",
* "relatedLaws": ["전자상거래법", ...]
* }
*/
@PostMapping
public ResponseEntity<BoonjangDto.Response> analyzeBoonjang(
@RequestBody BoonjangDto.Request request) {

BoonjangDto.Response result = boonjangService.analyze(request);
return ResponseEntity.ok(result);
}

/**
* 분쟁 목록 조회
*
* [응답 형식]
* [
* { "boonjangId": 1001, "boonjangInput": "...", "boonjangDate": "..." },
* ...
* ]
*/
@GetMapping
public ResponseEntity<List<BoonjangDto.Response>> getBoonjangList() {
List<BoonjangDto.Response> list = boonjangService.findAll();
return ResponseEntity.ok(list);
}
}
66 changes: 66 additions & 0 deletions legal/BackEnd/src/main/java/com/oracle/Legal/domain/Boonjang.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.oracle.Legal.domain;

import java.time.LocalDateTime;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 분쟁 엔티티
*
* [DB 테이블: BOONJANG]
* - BOONJANG_ID: 분쟁 ID (기본키, 시퀀스)
* - CLIENT_CODE: 회원 코드 (외래키)
* - BOONJANG_DATE: 등록 일시
* - BOONJANG_INPUT: 분쟁 내용 입력
* - BOONJANG_OUTPUT: 분석 결과 출력
*
* [원리]
* @Entity: JPA가 이 클래스를 DB 테이블과 매핑
* @Table: 실제 테이블 이름 지정
* @Id + @GeneratedValue: 기본키 자동 생성 전략
* @SequenceGenerator: Oracle 시퀀스 사용
*/
@Entity
@Table(name = "BOONJANG")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@SequenceGenerator(
name = "boonjang_seq_gen",
sequenceName = "BOONJANG_SEQ",
initialValue = 1,
allocationSize = 1
)
public class Boonjang {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "boonjang_seq_gen")
@Column(name = "BOONJANG_ID")
private Long boonjangId;

@Column(name = "CLIENT_CODE")
private Long clientCode;

@Column(name = "BOONJANG_DATE")
private LocalDateTime boonjangDate;

@Lob
@Column(name = "BOONJANG_INPUT")
private String boonjangInput;

@Lob
@Column(name = "BOONJANG_OUTPUT")
private String boonjangOutput;
}
76 changes: 76 additions & 0 deletions legal/BackEnd/src/main/java/com/oracle/Legal/dto/BoonjangDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.oracle.Legal.dto;

import java.time.LocalDateTime;
import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 분쟁 DTO (Data Transfer Object)
*
* [원리]
* DTO는 계층 간 데이터 전송에 사용됩니다.
*
* Entity vs DTO:
* - Entity: DB 테이블과 1:1 매핑, JPA가 관리
* - DTO: API 요청/응답용, 필요한 필드만 포함
*
* 왜 분리하는가?
* 1. Entity에 민감한 필드가 있을 수 있음 (비밀번호 등)
* 2. API 응답에 Entity에 없는 추가 정보 포함 가능
* 3. Entity 변경이 API에 영향 주지 않음
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BoonjangDto {

// 기본 정보
private Long boonjangId;
private Long clientCode;
private LocalDateTime boonjangDate;
private String boonjangInput;
private String boonjangOutput;

// 분석 결과 (Entity에는 없지만 API 응답에 필요)
private String classification; // 분류 (민사, 형사 등)
private String subType; // 세부 유형 (소비자, 계약 등)
private String summary; // 요약
private List<String> keywords; // 키워드 태그
private String judgment; // 법률적 판단
private List<String> relatedLaws; // 관련 법령

/**
* 요청 DTO (내부 클래스)
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Request {
private String boonjangInput;
private Long clientCode; // 로그인한 사용자 코드 (선택)
}

/**
* 응답 DTO (내부 클래스)
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Response {
private Long boonjangId;
private String classification;
private String subType;
private String summary;
private List<String> keywords;
private String judgment;
private List<String> relatedLaws;
private String boonjangInput;
private LocalDateTime boonjangDate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.oracle.Legal.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.oracle.Legal.domain.Boonjang;

/**
* 분쟁 레포지토리
*
* [원리]
* JpaRepository를 상속하면 기본 CRUD 메서드가 자동 제공됩니다:
* - save(entity): INSERT 또는 UPDATE
* - findById(id): SELECT by ID
* - findAll(): SELECT ALL
* - deleteById(id): DELETE by ID
*
* 추가 메서드는 메서드 이름 규칙으로 자동 생성:
* - findByClientCode(code) → SELECT * FROM BOONJANG WHERE CLIENT_CODE = ?
* - findByBoonjangDateDesc() → SELECT * ... ORDER BY BOONJANG_DATE DESC
*/
@Repository
public interface BoonjangRepository extends JpaRepository<Boonjang, Long> {

/**
* 회원 코드로 분쟁 목록 조회
*
* [JPA 쿼리 메서드 규칙]
* findBy + 필드명 → WHERE 조건 자동 생성
*/
List<Boonjang> findByClientCode(Long clientCode);

/**
* 최신 순으로 전체 조회
*/
List<Boonjang> findAllByOrderByBoonjangDateDesc();
}
Loading
Loading