LoginSignup
0
2

【SE入門編】Spring Tool Suite 4を使ってWEBプロジェクトのメニュー画面を実装する。

Last updated at Posted at 2023-11-25

1. 前提条件

  • DBおよびWebプロジェクトの構築が完了していることが前提です。もし構築がまだ完了していない場合は、以下の記事を参照してください。

  • 今回の実装では、メニューの表示のみです。事前にSpringからMybatisを使用したCRUDの基本実装が理解されていること。

  • また、メニューの実装にはjquery用のプラグインであるjsTreeを採用しております、jsTreeの知識をある程度理解されていること。

  • OracleのSTART WITH ... CONNECT BYを使いこなせること。

DBの構築手順:

WEBプロジェクトの構築手順:

CRUDの基本実装:

このシリーズの完全版はこちら:

jsTreeの公式サイト:

この記事のソースコードはGitHubにアップロードしましたので、ぜひダウンロードして確認してください。

出来上がったメニューのイメージ:

image.png

2. データモデルの設計

テーブル設計の正規化原則に従って、メニュー関連テーブルは以下のように設計する。Demo用のDDLとDMLはgithubに上げてるのでぜひご参考して下さい。

後ほどSTART WITH ... CONNECT BYを利用するため、テーブル構造を十分に理解して下さい。

2.1.メニューの基本情報テーブル

image.png

2.2.カテゴリ/サブカテゴリ(メニュー/サブメニュー)テーブル

image.png

2.3.メニュー&カテゴリ関係テーブル

image.png

2.4.アイコンテーブル

image.png

2.5.ユーザーテーブル

image.png

2.6.ロールテーブル

image.png

2.7.ロールメニュー関係テーブル

image.png

各テーブルの説明は省略します。

3. メニューの実装、ソースの解説

プログラムの構成です、赤い線のファイルは今回追加したものです。

image.png

代表ソースだけを解説します。

3.1.PomにjsTreeライブラリを追加してください。

		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>jstree</artifactId>
			<version>3.3.12</version>
		</dependency>

3.2.UserMenuRepository.xmlを実装

ログインユーザーの権限により、見えるメニューだけ抽出するSQL文及び項目変換ソースを貼ります。

select id="selectMenuByUserID":jsTreeに必要な項目を抽出するSQL文。UNIONで結合された上半分がカテゴリ、下半分が機能。START WITH ... CONNECT BY ... を使ってツリーメニューのデータを抽出している。
#{userID}:パラメータ。ログインユーザーID。
com.example.demo.bean.TreeMenu:jsTree用ツリーメニューの項目Bean。
resultMap id="ResultTreeMenuMap":DB項目とjsTreeの項目の変換関係。

  <resultMap id="ResultTreeMenuMap" type="com.example.demo.bean.TreeMenu">
    <id column="CATEGORY" jdbcType="VARCHAR" property="id" />
    <result column="CATEGORY_NAME" jdbcType="VARCHAR" property="text" />
    <result column="CATEGORY_PID" jdbcType="VARCHAR" property="parent" />
    <result column="POSITION" jdbcType="VARCHAR" property="position" />
    <result column="ACTION" jdbcType="VARCHAR" property="action" />
    <result column="ICON_TYPE" jdbcType="VARCHAR" property="iconType" />
    <result column="ICON_IMAGE" jdbcType="VARCHAR" property="icon" />
    <result column="TYPE" jdbcType="VARCHAR" property="type" />
    <result column="LEVEL" jdbcType="VARCHAR" property="level" />
  </resultMap>
  <select id="selectMenuByUserID" parameterType="java.lang.String" resultMap="ResultTreeMenuMap">
		SELECT
		    T.CATEGORY,
		    T.CATEGORY_NAME,
		    T.CATEGORY_PID,
		    T.POSITION,
		    T.ACTION,
		    T.ICON_TYPE,
		    T.ICON_IMAGE,
		    T.TYPE,
		    LEVEL
		FROM
		    (
		        SELECT
		            C.CATEGORY,
		            C.CATEGORY_NAME,
		            C.CATEGORY_PID,
		            C.POSITION,
		            '#'  ACTION,
		            '01' ICON_TYPE,
		            I.ICON_IMAGE,
		            'C'  TYPE
		        FROM
		            CATEGORY C
		            LEFT JOIN ICON     I ON '01' = I.ICON_TYPE
		        UNION
		        SELECT
		            RM.MENU_ID,
		            M.MENU_NAME,
		            MC.CATEGORY,
		            M.POSITION,
		            NVL(M.ACTION,'#') ACTION,
		            M.ICON_TYPE,
		            I.ICON_IMAGE,
		            'M' TYPE
		        FROM
		                 USERS U
		            JOIN ROLE_MENU     RM ON U.ROLE = RM.ROLE
		            JOIN MENU          M ON RM.MENU_ID = M.MENU_ID
		            JOIN MENU_CATEGORY MC ON M.MENU_ID = MC.MENU_ID
		            JOIN CATEGORY      C ON MC.CATEGORY = C.CATEGORY
		            LEFT JOIN ICON          I ON M.ICON_TYPE = I.ICON_TYPE
		        WHERE
		                U.USER_ID = #{userID}
		            AND M.IS_AVAILABLE = '1'
		    ) T
		START WITH
		    T.CATEGORY_PID = '#'
		CONNECT BY
		    PRIOR T.CATEGORY = T.CATEGORY_PID
		ORDER SIBLINGS BY
		    POSITION
  </select>

3.3.TreeMenu.javaを実装

jsTree用ツリーメニューの項目を説明します。

	private String id; // メニューID
	private String parent; // 親メニューID
	private String text; // メニュー名
	private String iconType; // メニューアイコンコード
	private String icon; // メニューアイコンのパス
	private String position; // メニュー表示順番
	private String action; // メニューURL、jsTree用項目ではない
	private String target; // URLを開くフレームやウインドウを指定する
	private String type; // C:カテゴリ;M:メニュー、jsTree用項目ではない
	private String level; // メニューの階層、jsTree用項目ではない
	private Map<String,String> a_attr; // actionのURLを格納する

3.4.MenuController.javaを実装

		List<TreeMenu> treeMenu = userService.selectMenuByUserID(userID);
		// SQLから取得したTreeMenuデータは、そのままではjsTreeでの使用に適していません。以下のような加工が必要です。
		treeMenu.forEach(menu -> {
			Map<String, String> href = new HashMap<>();
			href.put("href", menu.getAction());
			menu.setA_attr(href); // jsTreeの中に<A>を生成するため
		});
		model.addObject("treeMenu", treeMenu);

3.5.menu.htmlを実装

jquery及びjstreeのリソースをリンクする

<link rel="stylesheet" type="text/css" th:href="@{/webjars/jstree/3.3.12/themes/default/style.min.css}">
<script type="text/javascript" th:src="@{/webjars/jquery/3.6.0/dist/jquery.min.js}"></script>
<script type="text/javascript" th:src="@{/webjars/jstree/3.3.12/jstree.min.js}"></script>

ツリーメニューを生成する

	$(function(){
		$('#treeMenu')
		  // listen for event
		  .on('changed.jstree', function (e, data) {
			  console.log(data.changed.selected);
			  console.log(data.changed.deselected);
			  
			  var obj = data.instance.get_node(data.selected[0]);
			  if(obj && data.instance.is_leaf(obj) && "#" != obj.a_attr.href){
				  window.open(obj.a_attr.href, obj.id);// メニューをクリックする時、新たなWindowでURLを開く
			  } else {// カテゴリをクリックする時、カテゴリをオープン/クローズ
				  if(data.instance.is_open(obj)){
					  data.instance.close_node(obj);
				  } else {
					  data.instance.open_node(obj);
				  }
			  }
		  })
		  // create the instance
		  .jstree({ 
			 'core' : {
			    "animation" : 0,
			    "check_callback" : true,
			    "themes" : { "stripes" : true },
			    'data' : /*[[${treeMenu}]]*/
			 },
			 "plugins" : [
				    "changed", "state", "types", "wholerow"
				  ]
			 });
	});

jstreeの使い方についての説明は今回省けます、興味がある方は公式サイトをご参考下さい。

4. 完成

下図は以下のURLを叩いた結果です。
左(ADMIN権限):http://localhost:8000/menu?userID=ADMIN
中(管理職権限):http://localhost:8000/menu?userID=DEMO001
右(スタッフ):http://localhost:8000/menu?userID=DEMO002

まだ改善の余地がありますが(例えば空のカテゴリを表示しないなど)、とりあえず権限に基づいてメニューが表示されるようになりました。
image.png

おわりに

全体のソースコードはGitHubにアップロードしましたので、ぜひダウンロードして確認してください。

また、この記事では一部のソースコードしか説明していませんが、説明を希望する特定の部分があればリクエストしていただければと思います。詳細や特定の質問についてお知らせいただければ、それに基づいて訂正や説明を提供できます。

次回はメイン画面(フレーム分割) を実装していきたいと思います、お楽しみして待ってください。

それではまた。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2