MVC 패턴

MELIES·2025년 4월 3일

레시픽(Recipick)의 MVC 구조

레시픽은 전통적인 서버 사이드 MVC 패턴을 사용

  1. Model: CartVO, OrderVO와 같은 데이터 모델 클래스와 CartMapper, CartService와 같은 비즈니스 로직 계층이 모델 역할

  2. View: JSP 파일들이 뷰를 담당하며, JSTL 태그를 사용해 서버에서 전달받은 데이터를 표시

  3. Controller: CartController, CheckoutController 같은 클래스들이 컨트롤러 역할을 하며, 요청을 받아 적절한 서비스를 호출하고, 결과를 뷰에 전달

Spring MVC 프레임워크의 전형적인 사용 방식으로, 요청-응답 사이클이 서버에서 완결되는 방식

서버 사이드 렌더링(SSR)

처음에 컨트롤러가 요청을 받아 서버에서 JSP로 페이지를 렌더링
(예를 들면 shop-cart.jsp에서 전체 페이지를 서버에서 렌더링하여 클라이언트에게 전송)

클라이언트 사이드 업데이트(Ajax)

사용자 상호작용(장바구니 수량 변경, 삭제 등)에 따라 jQuery를 사용한 Ajax로 부분 업데이트
예를 들어 $('.bi-x').click(function() 에서 Ajax 호출로 장바구니 항목 삭제

초기 페이지 로드는 서버에서 처리하므로 SEO에 유리
부분 업데이트는 클라이언트에서 처리하므로 사용자 경험 향상 (불필요한 새로고침 등의 동작이 필요 없음)
서버와의 통신 횟수 감소

Model

// 데이터 모델 (Model)
public class CartVO {
    private int cart_id;           
    private int member_id;         
    private int ing_id;     		
    private int recipe_id;         
    private int qty;              
    // ...
}

public class OrderVO {
    private int oh_id;
    private int memberId;
    private double price;
    private String orderState;
    // ...
}

View

<!-- 뷰 (View) - JSP 파일 -->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div class="container">
    <div class="row">
        <c:forEach var="item" items="${cartItems}">
            <!-- 데이터 표시 -->
        </c:forEach>
    </div>
</div>

Controller

// 컨트롤러 (Controller)
@Controller
public class CartController {
    @Autowired
    private CartService cartService;

    @GetMapping("/shop-cart")
    public String shopCart(Model model, HttpSession session) {
        // 모델에서 데이터를 가져와 뷰로 전달
        List<CartVO> cartItems = cartService.getCartItems(memberId);
        model.addAttribute("cartItems", cartItems);
        return "cart/shop-cart"; // 뷰 이름 반환
    }
    
    @PostMapping("/cart/delete")
    @ResponseBody
    public Map<String, Object> deleteCartItem(@RequestParam("cart_id") int id, @RequestParam("type") int type) {
        // 모델 업데이트 로직
        cartService.deleteCartItem(id, type);
        // ...
    }
}

솔픽(Solpick)의 MVC 구조

솔픽은 백엔드 API와 프론트엔드 React를 분리한 조금 더 현대적인 웹 아키텍처를 사용

  1. Model:

    • 백엔드에서 Point, Member 등의 JPA 엔티티와 DTO 클래스들이 데이터 모델을 정의
    • PointService, MemberService 등이 비즈니스 로직을 담당
  2. Controller:

    • 백엔드의 PointController, RecipeController 등이 RESTful API 엔드포인트를 제공하며, 데이터를 JSON 형태로 반환
  3. View:

    • React 컴포넌트들(PointHistoryList.js, MyPageContent.js 등)이 사용자 인터페이스를 담당
    • React 컴포넌트는 API 호출 결과를 받아 렌더링하는 역할을 함

레시픽과 다르게 백엔드와 프론트엔드를 명확히 분리하여 각 부분이 독립적이다. API 서버는 데이터만 제공하고, 클라이언트가 UI 렌더링을 담당하는 방식

Model

// 엔티티 (Model)
@Entity
@Table(name = "point")
public class Point {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @Column(name = "user_id", nullable = false)
    private Integer userId;
    
    // ...
}

// DTO (Model의 일부)
@Data
@Builder
public class PointHistoryResponseDTO {
    private Integer pointId;
    private String date;
    private String description;
    private Integer amount;
    private String type;
}

Controller (백엔드 API)

@RestController
@RequestMapping("/api/points")
public class PointController {
    @Autowired
    private PointService pointService;

    @GetMapping("/summary")
    public ResponseEntity<PointSummaryResponseDTO> getPointSummary() {
        // 사용자 인증 처리
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        Map<String, Object> claims = (Map<String, Object>) principal;
        Integer userId = /* 사용자 ID 추출 */;
        
        // 모델에서 데이터 가져오기
        PointSummaryResponseDTO summary = pointService.getPointSummaryByUserId(userId);
        return ResponseEntity.ok(summary);
    }
}

View (React 프론트엔드)

// React 컴포넌트 (View)
const PointHistoryList = ({ pointHistory = [] }) => {
    // 데이터 가공 로직
    const groupedPoints = useMemo(() => {
        // 날짜별로 포인트 내역 그룹화
        // ...
    }, [pointHistory]);

    // UI 렌더링
    return (
        <div className="point-list">
            {groupedPoints.map(([date, points], groupIndex) => (
                <div key={date} className="point-group">
                    <div className="point-date-header">{date}</div>
                    {points.map((point, index) => (
                        <PointHistoryItem
                            key={`${date}-${index}`}
                            description={point.description}
                            amount={point.amount}
                            date={point.date}
                            type={point.type}
                        />
                    ))}
                </div>
            ))}
        </div>
    );
};


두 서비스 모두 데이터(Model), 표현(View), 제어 로직(Controller)을 분리하는 MVC의 원칙을 준수하며 구현했다. 레시픽은 서버에서 전체 MVC 사이클을 처리하는 반면, 솔픽은 백엔드(Model+Controller)와 프론트엔드(View)로 역할을 분리했다. 솔픽의 방식이 더 현대적인 방식이다.

profile
42 Seoul

0개의 댓글