コンテンツにスキップ

ありがとうございます。

ここからは 第4段階:Spring Boot実装アーキテクチャ設計 に進みます。

今回は採用した「教材ライブラリ方式」を前提に、以下を設計します。

  • パッケージ構成

  • Entity設計方針(JPA)

  • Repository設計

  • MyBatis Mapper設計

  • DTO設計

  • Form設計

  • Service責務

  • Controller構成

  • Spring Security連携


1. 全体パッケージ構成

Spring Boot 3 + JPA + MyBatisでは、レイヤー単位で分離します。

 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
80
81
82
83
84
com.example.lms

├── LmsApplication.java
│
├── config
│   ├── SecurityConfig.java
│   ├── JpaConfig.java
│   └── MyBatisConfig.java
│
├── security
│   ├── CustomUserDetails.java
│   ├── CustomUserDetailsService.java
│   └── LoginUser.java
│
├── controller
│   ├── admin
│   ├── teacher
│   ├── student
│   └── common
│
├── service
│   ├── ContentService.java
│   ├── CourseService.java
│   ├── LearningService.java
│   └── ApprovalService.java
│
├── repository
│   ├── UserRepository.java
│   ├── ContentRepository.java
│   ├── CourseRepository.java
│   └── ...
│
├── mapper
│   ├── ContentMapper.java
│   ├── CourseMapper.java
│   ├── LearningMapper.java
│   └── SearchMapper.java
│
├── entity
│
│   ├── user
│   │   ├── User.java
│   │   └── Role.java
│   │
│   ├── content
│   │   ├── Content.java
│   │   ├── ContentVersion.java
│   │   ├── TextContent.java
│   │   ├── VideoContent.java
│   │   ├── QuizContent.java
│   │   └── Attachment.java
│   │
│   ├── course
│   │   ├── Course.java
│   │   ├── CourseVersion.java
│   │   ├── Section.java
│   │   ├── Lesson.java
│   │   └── LessonContent.java
│   │
│   └── learning
│       ├── Enrollment.java
│       └── LearningHistory.java
│
├── dto
│
│   ├── content
│   ├── course
│   ├── learning
│   └── user
│
├── form
│
│   ├── ContentCreateForm.java
│   ├── CourseCreateForm.java
│   └── QuizCreateForm.java
│
├── search
│
│   ├── ContentSearchCondition.java
│   └── CourseSearchCondition.java
│
└── exception
    ├── BusinessException.java
    └── GlobalExceptionHandler.java

2. JPA Entity設計方針

今回のシステムでは、

JPA担当

1
2
3
4
5
登録
更新
削除
単体取得
状態変更

を担当します。


MyBatis担当

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
一覧表示

検索

ツリー取得

集計

ランキング

ダッシュボード

を担当します。


3. User Entity

Spring Securityの中心になります。

 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
@Entity
@Table(name="users")
@Getter
@Setter
public class User {


    @Id
    @GeneratedValue
    private Long id;


    private String username;


    private String email;


    private String password;


    private boolean enabled;


    @CreatedDate
    private LocalDateTime createdAt;


}

Role

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Entity
public class Role {


    @Id
    private Long id;


    private String code;


}

UserとRoleは多対多です。

1
2
3
4
5
6
7
8
9
User

 *

 |

 *

Role

4. Content Entity

教材ライブラリの中心です。

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


    @Id
    private Long id;


    @Enumerated(EnumType.STRING)
    private ContentType type;


    @ManyToOne
    private User author;


    @OneToOne
    private ContentVersion currentVersion;


}

ContentType

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public enum ContentType {

    VIDEO,

    TEXT,

    QUIZ,

    FILE

}

5. ContentVersion

公開管理の中心です。

 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
@Entity
public class ContentVersion {


    @Id
    private Long id;


    private Integer versionNo;


    private String title;


    private String summary;


    @Enumerated(EnumType.STRING)
    private ContentStatus status;


    private LocalDateTime publishedAt;


}

ContentStatus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public enum ContentStatus {


    DRAFT,

    REVIEWING,

    APPROVED,

    PUBLISHED,

    REJECTED,

    ARCHIVED

}

6. 詳細コンテンツ

Text

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Entity
public class TextContent {


    @Id
    private Long id;


    @OneToOne
    private ContentVersion version;


    @Lob
    private String body;


    private String format;


}

Video

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Entity
public class VideoContent {


    @Id
    private Long id;


    @OneToOne
    private ContentVersion version;


    private String videoType;


    private String videoId;


    private String videoUrl;


}

Quiz

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Entity
public class QuizContent {


    @Id
    private Long id;


    @OneToOne
    private ContentVersion version;


    private String question;


    private boolean multipleAnswer;


    private Integer answerCount;


}

7. Attachment

共通ファイル管理です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Entity
public class Attachment {


    @Id
    private Long id;


    @ManyToOne
    private ContentVersion version;


    private String originalName;


    private String storagePath;


    private String mimeType;


}

8. Course側 Entity

Course

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Entity
public class Course {


    @Id
    private Long id;


    private String title;


    @ManyToOne
    private User teacher;


    @OneToOne
    private CourseVersion currentVersion;


}

CourseVersion

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


    @Id
    private Long id;


    private Integer versionNo;


    private String description;


    private String status;


}

Section

無限階層です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Entity
public class Section {


    @Id
    private Long id;


    @ManyToOne
    private CourseVersion courseVersion;


    @ManyToOne
    private Section parent;


    private String title;


}

Lesson

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


    @Id
    private Long id;


    @ManyToOne
    private Section section;


    private String title;


}

LessonContent

教材配置テーブルです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Entity
public class LessonContent {


    @Id
    private Long id;


    @ManyToOne
    private Lesson lesson;


    @ManyToOne
    private Content content;


    private Integer displayOrder;


}

9. Repository設計

ContentRepository

1
2
3
4
public interface ContentRepository
        extends JpaRepository<Content,Long>{

}

用途:

  • 教材登録

  • 更新

  • 削除

  • 単体取得


10. MyBatis Mapper設計

例えば教材一覧。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Mapper
public interface ContentMapper {


List<ContentListDto> search(
 ContentSearchCondition condition
);


ContentDetailDto findDetail(
 Long id
);


}

SQLが複雑になる部分はMyBatisです。

例:

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

 c.id,

 cv.title,

 u.name,

 COUNT(lc.id)

FROM content c

JOIN content_version cv

JOIN users u

LEFT JOIN lesson_content lc

GROUP BY c.id

11. DTO設計

画面用はEntityを直接渡しません。

例:

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


private Long id;


private String title;


private String type;


private String authorName;


private String status;


}

12. Form設計

入力専用です。

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


@NotBlank
private String title;


@NotBlank
private String body;


private String format;


}

13. Service責務

ここが一番重要です。

ContentService

担当:

  • 教材作成

  • Version作成

  • 更新

  • 申請

  • 公開

例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Transactional
public void requestReview(Long contentId){

    ContentVersion version =
       repository.findCurrentVersion(contentId);


    version.changeStatus(REVIEWING);

}

CourseService

担当:

  • コース作成

  • セクション管理

  • レッスン配置

  • 教材配置


ApprovalService

担当:

  • 承認

  • 差戻し

  • 履歴保存


14. Controller構成

教師

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/teacher/content

GET    /list

GET    /create

POST   /create

POST   /{id}/review


/teacher/course

GET    /list

POST   /create

管理者

1
2
3
4
5
6
7
/admin/approval

GET

POST /approve

POST /reject

受講者

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/student/course

GET /list


/student/learning

GET /lesson/{id}

POST /complete

15. Spring Security権限

Role

1
2
3
4
5
6
7
ROLE_ADMIN

ROLE_TEACHER

ROLE_MENTOR

ROLE_STUDENT

制御例:

1
2
3
@PreAuthorize(
"hasRole('TEACHER')")
@PostMapping("/content/create")

現時点の完成アーキテクチャ

 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
教師

↓

ContentService

↓

ContentRepository(JPA)

↓

ContentVersion

↓

ApprovalService

↓

公開


受講者

↓

CourseMapper(MyBatis)

↓

DTO

↓

Thymeleaf

ここまでで Spring Boot実装開始可能な設計レベルになりました。

次の段階では、いよいよ実装に近づけて、

第5段階:MySQL DDL設計 + ER図 + Entity完全版

を作成します。

内容は以下になります。

  1. 全テーブルDDL

  2. PK/FK設計

  3. Enum値一覧

  4. Index設計

  5. JPA Entity完全コード

  6. MyBatis Mapper対象一覧

この段階まで進めると、そのままSpring Bootプロジェクトを作成できます。