카테고리 없음

JSP 모듈화

yjyj0101 2025. 5. 1. 21:34

// DataController.java
@RestController
@RequestMapping("/api")
public class DataController {
    
    @GetMapping("/products/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable String id) {
        Product product = productService.findById(id);
        return ResponseEntity.ok(product);
    }
    
    @GetMapping("/users")
    public ResponseEntity<List<User>> getUsers(
        @RequestParam(required = false) String department) {
        
        List<User> users = userService.getUsersByDepartment(department);
        return ResponseEntity.ok(users);
    }
}

 

<%-- parentComponent.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" %>
<div id="parentContainer">
    <h2>제품 정보 조회</h2>
    <input type="text" id="productIdInput" placeholder="제품 ID 입력">
    <button id="loadBtn">조회</button>
    
    <div id="productDetailContainer"></div>
    <div id="relatedProductsContainer"></div>
</div>

<script>
$(function() {
    // API 호출 함수
    function fetchProductData(productId) {
        return $.ajax({
            url: '/api/products/' + productId,
            method: 'GET',
            dataType: 'json'
        });
    }
    
    // 자식 컴포넌트 로드 함수
    function loadChildComponents(productData) {
        // 제품 상세 정보 컴포넌트 로드
        $('#productDetailContainer').load('/components/productDetail.jsp', 
            { productJson: JSON.stringify(productData) },
            function() {
                console.log('제품 상세 컴포넌트 로드 완료');
            }
        );
        
        // 연관 제품 컴포넌트 로드
        if (productData.relatedProducts && productData.relatedProducts.length > 0) {
            $('#relatedProductsContainer').load('/components/relatedProducts.jsp', 
                { productsJson: JSON.stringify(productData.relatedProducts) }
            );
        }
    }
    
    // 조회 버튼 클릭 이벤트
    $('#loadBtn').click(function() {
        const productId = $('#productIdInput').val().trim();
        if (!productId) return;
        
        fetchProductData(productId)
            .done(function(productData) {
                loadChildComponents(productData);
            })
            .fail(function(xhr) {
                alert('제품 조회 실패: ' + xhr.responseJSON?.message || xhr.statusText);
            });
    });
});
</script>

 

<%-- productDetail.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<script>
// JSON 파싱 유틸리티 (XSS 방지)
function safeJsonParse(jsonStr) {
    try {
        const decoded = jsonStr.replace(/&quot;/g, '"')
                              .replace(/&#39;/g, "'")
                              .replace(/&lt;/g, '<')
                              .replace(/&gt;/g, '>');
        return JSON.parse(decoded);
    } catch (e) {
        console.error('JSON 파싱 오류', e);
        return null;
    }
}

// 제품 데이터 파싱
const product = safeJsonParse('${fn:escapeXml(param.productJson)}');
</script>

<div class="product-detail" data-product-id="${product.id}">
    <h3>${product.name}</h3>
    <div class="price-section">
        <span class="price">${product.price.toLocaleString()}원</span>
        <c:if test="${product.discountRate > 0}">
            <span class="discount">${product.discountRate}% 할인</span>
        </c:if>
    </div>
    <div class="description">
        ${product.description}
    </div>
    
    <div class="actions">
        <button class="btn-cart" data-product-id="${product.id}">장바구니</button>
        <button class="btn-buy" data-product-id="${product.id}">구매하기</button>
    </div>
</div>

<script>
$(function() {
    // 이벤트 핸들러 등록
    $('.btn-cart').click(function() {
        const productId = $(this).data('product-id');
        addToCart(productId);
    });
    
    $('.btn-buy').click(function() {
        const productId = $(this).data('product-id');
        startPurchase(productId);
    });
    
    // 부모 컴포넌트와 통신
    $(document).on('productUpdated', function(event, updatedProduct) {
        if (updatedProduct.id === product.id) {
            $('.price').text(updatedProduct.price.toLocaleString() + '원');
            // 기타 UI 업데이트
        }
    });
});

// 장바구니 추가 함수
function addToCart(productId) {
    $.post('/api/cart', { productId: productId })
     .done(function() {
         alert('장바구니에 추가되었습니다');
     })
     .fail(function(xhr) {
         alert('오류: ' + xhr.responseJSON?.message);
     });
}
</script>
<%-- relatedProducts.jsp --%>
<script>
const relatedProducts = JSON.parse('${fn:escapeXml(param.productsJson)}'
    .replace(/&quot;/g, '"')
    .replace(/&#39;/g, "'")
);
</script>

<div class="related-products">
    <h4>함께 보면 좋은 상품</h4>
    <div class="product-list">
        <c:forEach items="${relatedProducts}" var="product">
            <div class="product-item" data-product-id="${product.id}">
                <img src="${product.thumbnailUrl}" alt="${product.name}">
                <div class="info">
                    <h5>${product.name}</h5>
                    <p>${product.price.toLocaleString()}원</p>
                </div>
            </div>
        </c:forEach>
    </div>
</div>

<script>
$(function() {
    $('.product-item').click(function() {
        const productId = $(this).data('product-id');
        
        // 부모 컴포넌트에 이벤트 전달
        $(document).trigger('relatedProductSelected', {
            productId: productId,
            source: 'relatedProducts'
        });
    });
});
</script>

 

- 부모/자식 컴포넌트 통신

// 부모 컴포넌트에서 이벤트 리스너 등록
$(document).on('relatedProductSelected', function(event, data) {
    // 연관 제품 선택 시 해당 제품 다시 로드
    fetchProductData(data.productId)
        .done(loadChildComponents);
});

// 자식 컴포넌트에서 이벤트 발생 예시
$(document).trigger('productUpdated', {
    id: "P1001",
    price: 120000,
    // 기타 업데이트 필드
});