본문 바로가기
Web Programming/JavaScript

[Kendo Vue + SpringBoot + Oracle] 동적인 메뉴 아코디언 만들기(Creating a dynamic menu accordion)

by jaey0ng 2024. 1. 3.

kendo Vue의 treelist를 이용하여 만드는 예제입니다.

 

https://www.telerik.com/kendo-vue-ui/components/treelist/get-started/

 

Vue TreeList Component Getting Started - Kendo UI for Vue Docs & Demos

vue 2.6.11 or 3.0.0Contains the functionality necessary to define Vue components.@progress/kendo-licensingContains the internal infrastructure related to licensing.@progress/kendo-svg-iconsContains the SVG icons for the components@progress/kendo-vue-intlCo

www.telerik.com

kendo UI 라는 것은 화면 그리는 작업을 최소화할 수 있게 해주는 라이브러리입니다.
이미 그려진 것들을 copy&paste를 하면 화면 그리는 일은 끝나게 됩니다.
(약간의 수정은 필요합니다. 예제와 다른 칼럼명이라던가 등등)

 

다른 기능을 구현해 보실 분들은 공식홈페이지에서 코드를 들고 와서 수정하면 됩니다.

 

본격적으로 시작하겠습니다.

 

디비 컬럼부터 보여드리겠습니다.

메뉴 마스터 테이블 구조

메뉴 마스터 테이블의 컬럼들인데 메뉴 주소는 프로그램 관리 테이블을 만들어 거기에 넣는 것이 더 좋지만,
설명을 위한 예제이기 때문에 위처럼 만들었음을 미리 알려드립니다.

 

위의 링크에서 코드를 들고 와서 본인의 프로젝트에 파일을 생성한 후 붙여 넣기를 해줍니다.

 

<template>
    <div>
        <treelist :data-source="menus"
                  :filterable="true"
                  :sortable="true"
                  :selectable="'row'"
                  @change="handleRowChange">
            <treelist-column :field="'Name'" :width="50" :title="'메뉴'"></treelist-column>
        </treelist>
    </div>
</template>

<script>
import axios from 'axios';
import { TreeList, TreeListColumn } from '@progress/kendo-treelist-vue-wrapper';

export default {
    name: 'App',
    components: {
        'treelist': TreeList,
        'treelist-column': TreeListColumn
    },
    data() {
        return {
            menus: [],
        };
    },
    methods: {
        convertData(input) {
            return input.map(item => ({
                id: item.MENU_ID,
                parentId: item.PARENT_MENU_ID || null,
                Name: item.MENU_NM,
                Addr: item.MENU_ADDR,
            }));
        },
    },
    mounted() {
        
    },
}
</script>

 

필요 없는 부분 지우고, 필요한 부분은 남겨두었습니다.

 

위 테이블에서 메뉴를 조회하기 위한 함수를 넣어주겠습니다.

 

methods: {
    selMenu() {
        // 메뉴 조회
        axios.get(`/com/selMenu`) 
            .then(response => {
            this.menus = this.convertData(response.data);

            // 메뉴 데이터 확인 필요시 주석 제거
            // console.log("this.menus"+JSON.stringify(this.menus, null, 2));
            })
            .catch(error => {
            console.error('Error 조회 실패', error);
            })
    },
	...
},
mounted() {
    this.selMenu();
},

 

axios.get 함수를 이용해서 백엔드 api를 호출해 줍니다.

 

다음은 SpringBoot 코드입니다.

 

최대한 간단하게 구현을 한 것이기에 필요한 추가 기능이 있다 하시면 자유롭게 추가해 주시면 되겠습니다.

 

MenuController.java

package com.backend.vue.com.controller;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.backend.vue.com.service.MenuService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@ResponseBody
@RestController
@RequestMapping("/com")
public class MenuController {
	@Autowired
	MenuService menuService;
	
	@GetMapping(value= "/selMenu")
	public List<Map<String, Object>> selMenu() {
		List<Map<String, Object>> result = menuService.selMenu();
        return result;
	}
}

 

MenuService.java

package com.backend.vue.com.service;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.backend.vue.com.dao.MenuDao;

@Service
public class MenuService {
 
	@Autowired
	private MenuDao menuDao;
	
	public List<Map<String, Object>> selMenu() {
		return menuDao.selMenu();
	}
}

 

MenuDao.java

package com.backend.vue.com.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.backend.vue.com.service.LoginService;

@Repository
public class MenuDao {

    @Autowired
    private LoginService loginService;
	
    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
	
    public List<Map<String, Object>> selMenu() {
        // 권한체크
        List<Map<String, Object>> loginInfo = loginService.checkLoginInfo();

        if (loginInfo.size() > 0) {
            List<Map<String, Object>> menuList = new ArrayList<>();

            menuList = sqlSessionTemplate.selectList("MenuMapper.selMenu");
            return menuList;
        } else {
            return new ArrayList<>();
        }
    }
}

 

Dao 코드에서 권한체크라는 주석이 보이실 텐데요

로그인이 되어있을 경우에만 조회가 되게끔 선언한 거예요

관리자페이지의 경우 화면 오픈 시 바로 로그인하라고 나오겠지만,

한번 더 체크를 하여 페이지 접속을 제어한다고 생각하시면 되겠습니다.

 

혹은 로그인을 안 해도 메인화면은 보이지만, 서브페이지들은 못 보게 하고 싶을 때 유용하답니다

 

MenuMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper 
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="MenuMapper">
	<select id="selMenu" resultType="Map">
		SELECT MENU_ID         -- 메뉴 ID
		     , PARENT_MENU_ID  -- 상위 메뉴 ID
		     , MENU_NM         -- 메뉴명
		     , MENU_ADDR       -- 메뉴주소
		  FROM C##ECODEV.COMM_MENU_MST
		 ORDER BY MENU_ID
	</select>
</mapper>

 

메뉴 ID 는 1,2,3,4... N번째까지 순차적으로 따집니다.

상위 메뉴 ID는 트리구조일 때 부모 메뉴 ID를 뜻합니다.

 

예를 들어

MENU_ID: 1, PARENT_MENU_ID: null, MENU_NM: 부모

MENU_ID:2, PARENT_MENU_ID: 1, MENU_NM: 자식

이런 데이터가 있을 때

부모 메뉴 아래 자식메뉴가 있는 겁니다.

 


결과물

로그인을 하지 않았을 때

 

로그인을 하였을 때

 

테이블 데이터 상태

 


궁금하시거나, 따로 질문이 있으면 댓글 남겨주세요

더 좋은 방법이 있다면 댓글로 공유해 주시면 감사하겠습니다 !