コンテンツにスキップ

ありがとうございます。

ここから 第15段階:教材ライブラリ強化(検索・分類・再利用・管理機能)設計 に進みます。

ここまでの設計では、教材は

1
2
3
4
5
6
Content
 └ ContentVersion
      ├ VideoContent
      ├ TextContent
      ├ QuizContent
      └ FileContent

として管理しています。

しかし、実際の教材運用では教師が増えると以下の問題が発生します。

  • 似た教材が大量に作成される

  • 目的の教材を探せない

  • コース横断で教材を再利用したい

  • 分野別・難易度別に整理したい

  • 管理者が教材品質を確認したい

そのため、今回は 教材ライブラリ機能 を拡張します。


第15段階 全体構成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
                    Content

                       |
          +------------+------------+

          Tag                     Category

          |                         |

     Java / Spring             プログラミング

          |

      ContentTag


                       |

                LessonContent

                       |

                 Course利用

1. 教材ライブラリの役割

教材ライブラリは、

「教材そのものを管理する場所」

です。

コースとは分離します。


正しい関係

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
教材ライブラリ

Javaとは
変数とは
Springとは


        ↓ 利用


コースA

Java基礎


        ↓ 利用


コースB

新人研修

NG設計

1
2
3
4
5
Course

 └ Lesson

      └ Content

だけにすると、

教材コピーが発生します。


2. 教材カテゴリ管理

カテゴリを追加します。

例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
プログラミング

 ├ Java

 ├ Spring

 └ Python


ビジネス

 ├ DX

 └ マネジメント

3. Categoryテーブル

階層構造にします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
CREATE TABLE content_categories (

    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    parent_id BIGINT,

    name VARCHAR(100) NOT NULL,

    sort_order INT,

    created_at DATETIME,

    updated_at DATETIME

);

4. Category Entity

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Entity
@Table(name="content_categories")
@Getter
@Setter
public class ContentCategory {


    @Id
    @GeneratedValue(
        strategy=GenerationType.IDENTITY
    )
    private Long id;


    private String name;


    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="parent_id")
    private ContentCategory parent;


    private Integer sortOrder;


    private LocalDateTime createdAt;


    private LocalDateTime updatedAt;

}

5. Contentとの関連

教材は1カテゴリを基本にします。

理由:

検索しやすく、管理しやすいためです。


追加:

1
2
@ManyToOne(fetch=FetchType.LAZY)
private ContentCategory category;

6. タグ管理

カテゴリ:

1
分類

タグ:

1
特徴

として分離します。


例:

教材:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Java入門


カテゴリ

Java


タグ

初心者

新人研修

プログラミング

7. Tagテーブル

1
2
3
4
5
6
7
8
9
CREATE TABLE tags (

    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    name VARCHAR(50) UNIQUE,

    created_at DATETIME

);

8. ContentTag中間テーブル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
CREATE TABLE content_tags (

    content_id BIGINT,

    tag_id BIGINT,

    PRIMARY KEY(
        content_id,
        tag_id
    )

);

9. Tag Entity

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Entity
@Table(name="tags")
@Getter
@Setter
public class Tag {


    @Id
    @GeneratedValue(
        strategy=GenerationType.IDENTITY
    )
    private Long id;


    private String name;


}

10. 教材検索機能

検索条件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
キーワード

教材種類

カテゴリ

タグ

作成者

状態

公開日時

11. SearchCondition拡張

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Data
public class ContentSearchCondition {


    private String keyword;


    private String contentType;


    private String status;


    private Long categoryId;


    private List<Long> tagIds;


    private Long authorId;


    private LocalDate fromDate;


    private LocalDate toDate;


    private Integer page=0;


    private Integer size=20;

}

12. MyBatis検索SQL

例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<select id="search">

SELECT

c.id,

cv.title,

cv.summary,

cat.name category_name,

u.username author_name


FROM contents c


JOIN content_versions cv

ON c.current_version_id=cv.id


LEFT JOIN content_categories cat

ON c.category_id=cat.id


JOIN users u

ON c.author_id=u.id


<where>


<if test="keyword != null">

AND (

cv.title LIKE CONCAT('%',#{keyword},'%')

OR

cv.summary LIKE CONCAT('%',#{keyword},'%')

)

</if>


<if test="categoryId != null">

AND c.category_id=#{categoryId}

</if>


<if test="status != null">

AND cv.status=#{status}

</if>


</where>


ORDER BY

cv.updated_at DESC


LIMIT #{size}

OFFSET #{offset}


</select>

13. 教材利用数表示

教師画面:

1
2
3
4
5
6
7
8
9
教材一覧

--------------------------------

Javaとは

利用数:5コース

--------------------------------

SQL:

1
2
3
4
5
6
7
SELECT

COUNT(*)

FROM lesson_contents

WHERE content_id=?

14. 教材詳細画面改善

表示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Javaとは


--------------------------------

カテゴリ

Java


タグ

初心者
新人研修


利用コース

・Java基礎
・新人研修


作成者

山田先生


Version

3


状態

公開中

--------------------------------

15. 教材お気に入り

将来的に便利な機能です。

対象:

  • 教師

  • 受講者


Favoriteテーブル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
CREATE TABLE content_favorites (

id BIGINT AUTO_INCREMENT PRIMARY KEY,

user_id BIGINT,

content_id BIGINT,

created_at DATETIME,

UNIQUE(
user_id,
content_id
)

);

16. 教材評価

教材品質改善用です。

例:

1
2
3
★★★★★

説明が分かりやすい

Reviewテーブル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
CREATE TABLE content_reviews (

id BIGINT AUTO_INCREMENT PRIMARY KEY,

user_id BIGINT,

content_id BIGINT,

rating INT,

comment TEXT,

created_at DATETIME

);

17. 教材ダッシュボード

管理者向け:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
教材数

----------------

総教材

520


公開中

430


審査中

20


利用回数

1200

18. DashboardMapper

集計系はMyBatisです。

1
2
3
4
5
6
7
8
@Mapper
public interface DashboardMapper {


    DashboardSummaryDto summary();


}

DTO

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Data
public class DashboardSummaryDto {


    private Integer totalContents;


    private Integer publishedContents;


    private Integer reviewContents;


    private Integer totalEnrollments;


}

19. 教材再利用機能

重要です。

教師が教材を探して、

1
この教材を使う

を押します。

処理:

1
2
3
4
5
6
7
Content

↓

LessonContent

登録

Service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Transactional
public void reuseContent(
        Long lessonId,
        Long contentId){


    LessonContent relation =
        new LessonContent();


    relation.setLesson(
        lessonRepository
        .getReferenceById(
            lessonId
        )
    );


    relation.setContent(
        contentRepository
        .getReferenceById(
            contentId
        )
    );


    repository.save(
        relation
    );

}

20. 教材ライブラリ画面

URL:

1
/teacher/library

画面:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
----------------------------------

教材検索

[Java        ]

カテゴリ

[プログラミング]


種類

[動画]


検索


----------------------------------

Javaとは

動画

公開中


利用数

5


[利用する]

----------------------------------

21. 現在の完成構造

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
                Content

                  |

        +---------+---------+

     Category              Tag



                  |

            LessonContent

                  |

                Lesson

                  |

                Course

第15段階終了時点

追加された機能:

✅ 教材ライブラリ
✅ カテゴリ階層管理
✅ タグ管理
✅ 高度検索
✅ 教材再利用
✅ 利用状況確認
✅ お気に入り設計
✅ 教材評価設計
✅ 管理ダッシュボード準備


次の 第16段階 では、管理者機能を強化します。

内容:

  1. 管理者ダッシュボード

  2. ユーザー管理

  3. ロール管理

  4. 教師管理

  5. 教材承認一覧改善

  6. 監査ログ検索

  7. システム設定管理

  8. Spring Security + 権限詳細設計

へ進みます。