# 簡易Java Web教學 ### 前言 在撰寫Java Web時,新手很容易遇到一個問題,到底我要先寫哪一層? 沒有一個標準答案,但是若心中能有一個順序,一定能提升開發及構思的技能,我會建議從外到內寫會比較有一條龍的感覺,剛好在開發的過程中,會知道我現在還有沒加這個等等要記得補上。 ### 實作 我們以一個新增會員功能來做介紹。 ```text controller └─ CreateMemberController.java service └─input └─CreateMemberInput.java └─ CreateMemberService.java repository └─ MemberRepository.java └─ MemberJpaRepository.java domain └─ Member.java entity └─ MemberEntity.java ``` ### DB建置 準備一個會員的表 ```sql= CREATE TABLE member ( member_id INT PRIMARY KEY, name VARCHAR(30), email VARCHAR(255), password VARCHAR(255) ) ``` ### Enity Entity 僅負責與資料庫對應。 ```java= @Data @Builder @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "member") public class MemberEntity { @Id private String memberId; private String name; private String email; private String password; @PrePersist public void prePersist() { if (this.memberId == null) { this.memberId = UUID.randomUUID().toString(); } } public static MemberEntity fromDomain(Member member) { return MemberEntity.builder() .memberId(member.getMemberId()) .name(member.getName()) .email(member.getEmail()) .password(member.getPassword()) .build(); } public Member toDomain() { return Member.builder() .memberId(this.memberId) .name(this.name) .email(this.email) .password(this.password) .build(); } } ``` ### 撰寫Domain Domain 代表系統中的商業概念,透過轉換方法隔離,避免業務邏輯污染 Entity。 ```java= @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor @Slf4j public class Member { /** * 會員 id */ private String memberId; /** * 會員中文姓名 */ private String name; /** * 會員 email */ private String email; /** * 會員密碼 */ private String password; private Member(String name, String email, String password) { this.memberId = randomUUID().toString(); this.name = name; this.email = email; this.password = password; } public static Member create(String name, String email, String password) { return new Member(name, email, password); } } ``` ### 撰寫Controller 不寫商業邏輯,只負責接收參數,呼叫Service然後回傳結果 ```java= @RestController @RequestMapping("/api") @RequiredArgsConstructor public class CreateMemberController { private final CreateMemberService createMemberService; @PostMapping(value = "/v1/member/create") public ResponseEntity<BaseResponse> createMember( @RequestBody CreateMemberRequest req ) { createMemberService.execute( CreateMemberInput.builder() .name(req.getName()) .email(req.getEmail()) .password(req.getPassword()) .build() ); return ResponseEntity.ok(BaseResponse.success()); } } ``` ### Input ```java= @Getter @Builder public class CreateMemberInput { /** * 會員中文姓名 */ private String name; /** * 會員 email */ private String email; /** * 會員密碼 */ private String password; public void validate() { if (StringUtils.isEmpty(name)) { throw new IllegalArgumentException("請輸入名字"); } if (StringUtils.isEmpty(email)) { throw new IllegalArgumentException("請輸入Email"); } if (StringUtils.isEmpty(password)) { throw new IllegalArgumentException("請輸入密碼"); } } } ``` ### Service ```java= @Service @RequiredArgsConstructor @Slf4j public class CreateMemberService { private final MemberRepository memberRepository; /** * * 建立會員資料Service */ public void execute(CreateMemberInput input) { // validate input input.validate(); final Member member = Member.create(input.getName(), input.getEmail(), input.getPassword()); memberRepository.save(member); } } ``` ### Repository Repository 隔離資料存取細節,讓 Service 不直接依賴 JPA ```java= @Repository @RequiredArgsConstructor @Slf4j public class MemberRepository { private final MemberJpaRepository memberJpaRepository; public void save(Member member) { memberJpaRepository.save(MemberEntity.fromDomain(member)); } } ``` ### JPA ```java= public interface MemberJpaRepository extends JpaRepository<MemberEntity, String> { } ``` ### 總結 以上就是簡易的教學範例,若有任何問題或是教學有誤的地方,歡迎提出,謝謝!
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.