Skip to content

Commit 7989d58

Browse files
authored
Merge pull request #842 from prgrms-be-devcourse/changhyeon/w3-1
[4기 - 황창현] Week 3-1 Thymeleaf를 이용하여 바우처 관리페이지 구현, ControllerAdvice를 통한 예외 처리
2 parents 0ee4ec1 + b6a4098 commit 7989d58

File tree

29 files changed

+920
-37
lines changed

29 files changed

+920
-37
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,23 @@ Type list to list all vouchers.
6363
- [x] 고객이 어떤 바우처를 보유하고 있는지 조회할 수 있어야 합니다.
6464
- [x] 고객이 보유한 바우처를 제거할 수 있어야 합니다.
6565
- [x] 특정 바우처를 보유한 고객을 조회할 수 있어야 합니다.
66+
67+
### 3주차 미션
68+
69+
**3-1**
70+
71+
- [x] Spring MVC를 적용해서 thymeleaf 템플릿을 설정해보세요.
72+
- [x] 커맨드로 지원했던 기능을 thymeleaf를 이용해서 관리페이지를 만들고 다음 기능을 지원가능하게 해보세요
73+
- [x] 조회페이지
74+
- [x] 상세페이지
75+
- [x] 입력페이지
76+
- [x] 삭제기능
77+
78+
**3-2**
79+
80+
- [ ] Spring MVC를 적용해서 JSON과 XML을 지원하는 REST API를 개발해보세요
81+
- [ ] 전체 조회기능
82+
- [ ] 조건별 조회기능 (바우처 생성기간 및 특정 할인타입별)
83+
- [ ] 바우처 추가기능
84+
- [ ] 바우처 삭제기능
85+
- [ ] 바우처 아이디로 조회 기능

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ dependencies {
1919
implementation 'org.springframework.boot:spring-boot-starter'
2020
testImplementation 'org.springframework.boot:spring-boot-starter-test'
2121
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
22+
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
23+
implementation 'org.springframework.boot:spring-boot-starter-web'
24+
implementation 'org.springframework.boot:spring-boot-starter-validation'
2225

2326
runtimeOnly 'com.h2database:h2'
2427

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.programmers.springweekly.controller;
2+
3+
import jakarta.servlet.RequestDispatcher;
4+
import jakarta.servlet.http.HttpServletRequest;
5+
import org.springframework.boot.web.servlet.error.ErrorController;
6+
import org.springframework.stereotype.Controller;
7+
import org.springframework.ui.Model;
8+
import org.springframework.web.bind.annotation.GetMapping;
9+
10+
@Controller
11+
public class CustomErrorController implements ErrorController {
12+
13+
// ControllerAdvice로 처리되지 않는 서블릿 수준의 예외와 404 에러 처리
14+
@GetMapping("/error")
15+
public String errorThrow(HttpServletRequest httpServletRequest, Model model) {
16+
Integer errorStatusCode = (Integer) httpServletRequest.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
17+
String errorMessage = (String) httpServletRequest.getAttribute(RequestDispatcher.ERROR_MESSAGE);
18+
19+
model.addAttribute("errorCode", errorStatusCode);
20+
21+
if (errorStatusCode == 404) {
22+
model.addAttribute("errorMsg", "요청하신 페이지를 찾을 수 없습니다.");
23+
return "errorPage";
24+
}
25+
26+
model.addAttribute("errorMsg", errorMessage);
27+
28+
return "errorPage";
29+
}
30+
31+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.programmers.springweekly.controller;
2+
3+
import com.programmers.springweekly.dto.customer.request.CustomerCreateRequest;
4+
import com.programmers.springweekly.dto.customer.response.CustomerListResponse;
5+
import com.programmers.springweekly.dto.customer.response.CustomerResponse;
6+
import com.programmers.springweekly.service.CustomerService;
7+
import jakarta.validation.Valid;
8+
import java.util.UUID;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.stereotype.Controller;
11+
import org.springframework.ui.Model;
12+
import org.springframework.web.bind.annotation.DeleteMapping;
13+
import org.springframework.web.bind.annotation.GetMapping;
14+
import org.springframework.web.bind.annotation.PathVariable;
15+
import org.springframework.web.bind.annotation.PostMapping;
16+
import org.springframework.web.bind.annotation.RequestMapping;
17+
18+
@Controller
19+
@RequiredArgsConstructor
20+
@RequestMapping("/view/customer")
21+
public class CustomerViewController {
22+
23+
private final CustomerService customerService;
24+
25+
@GetMapping
26+
public String getMenuPage() {
27+
return "customer/menu";
28+
}
29+
30+
@GetMapping("/save")
31+
public String getCreatePage() {
32+
return "customer/create";
33+
}
34+
35+
@PostMapping("/save")
36+
public String save(@Valid CustomerCreateRequest customerCreateRequest) {
37+
customerService.save(customerCreateRequest);
38+
39+
return "customer/menu";
40+
}
41+
42+
@GetMapping("/findAll")
43+
public String getFindAllPage(Model model) {
44+
CustomerListResponse customerListResponse = customerService.findAll();
45+
model.addAttribute("customerList", customerListResponse.getCustomerList());
46+
47+
return "customer/findAll";
48+
}
49+
50+
@GetMapping("/find/{id}")
51+
public String findById(@PathVariable("id") UUID customerId, Model model) {
52+
CustomerResponse customerResponse = customerService.findById(customerId);
53+
model.addAttribute("customer", customerResponse);
54+
55+
return "customer/find";
56+
}
57+
58+
@DeleteMapping("/delete/{id}")
59+
public String deleteById(@PathVariable("id") UUID customerId) {
60+
customerService.deleteById(customerId);
61+
62+
return "redirect:/view/customer/find";
63+
}
64+
65+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.programmers.springweekly.controller;
2+
3+
import org.springframework.stereotype.Controller;
4+
import org.springframework.web.bind.annotation.GetMapping;
5+
6+
@Controller
7+
public class HomeController {
8+
9+
@GetMapping("/")
10+
public String home() {
11+
return "home";
12+
}
13+
}

src/main/java/com/programmers/springweekly/controller/VoucherController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class VoucherController {
1919
public void save(VoucherCreateRequest voucherCreateRequest) {
2020
VoucherValidator.validateVoucher(
2121
voucherCreateRequest.getVoucherType(),
22-
String.valueOf(voucherCreateRequest.getDiscountAmount())
22+
voucherCreateRequest.getDiscountAmount()
2323
);
2424

2525
voucherService.save(voucherCreateRequest);
@@ -28,7 +28,7 @@ public void save(VoucherCreateRequest voucherCreateRequest) {
2828
public void update(VoucherUpdateRequest voucherUpdateRequest) {
2929
VoucherValidator.validateVoucher(
3030
voucherUpdateRequest.getVoucherType(),
31-
String.valueOf(voucherUpdateRequest.getDiscountAmount())
31+
voucherUpdateRequest.getDiscountAmount()
3232
);
3333

3434
voucherService.update(voucherUpdateRequest);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.programmers.springweekly.controller;
2+
3+
import com.programmers.springweekly.dto.voucher.request.VoucherCreateRequest;
4+
import com.programmers.springweekly.dto.voucher.response.VoucherListResponse;
5+
import com.programmers.springweekly.dto.voucher.response.VoucherResponse;
6+
import com.programmers.springweekly.service.VoucherService;
7+
import com.programmers.springweekly.util.validator.VoucherValidator;
8+
import jakarta.validation.Valid;
9+
import java.util.UUID;
10+
import lombok.RequiredArgsConstructor;
11+
import org.springframework.stereotype.Controller;
12+
import org.springframework.ui.Model;
13+
import org.springframework.web.bind.annotation.DeleteMapping;
14+
import org.springframework.web.bind.annotation.GetMapping;
15+
import org.springframework.web.bind.annotation.PathVariable;
16+
import org.springframework.web.bind.annotation.PostMapping;
17+
import org.springframework.web.bind.annotation.RequestMapping;
18+
19+
@Controller
20+
@RequiredArgsConstructor
21+
@RequestMapping("/view/voucher")
22+
public class VoucherViewController {
23+
24+
private final VoucherService voucherService;
25+
26+
@GetMapping
27+
public String getMenuPage() {
28+
return "voucher/menu";
29+
}
30+
31+
@GetMapping("/save")
32+
public String getCreatePage() {
33+
return "voucher/create";
34+
}
35+
36+
@PostMapping("/save")
37+
public String save(@Valid VoucherCreateRequest voucherCreateRequest) {
38+
VoucherValidator.validateVoucher(
39+
voucherCreateRequest.getVoucherType(),
40+
voucherCreateRequest.getDiscountAmount()
41+
);
42+
43+
voucherService.save(voucherCreateRequest);
44+
45+
return "voucher/menu";
46+
}
47+
48+
@GetMapping("/findAll")
49+
public String getFindAllPage(Model model) {
50+
VoucherListResponse voucherListResponse = voucherService.findAll();
51+
model.addAttribute("voucherList", voucherListResponse.getVoucherList());
52+
53+
return "voucher/findAll";
54+
}
55+
56+
@GetMapping("/find/{id}")
57+
public String findById(@PathVariable("id") UUID voucherId, Model model) {
58+
VoucherResponse voucherResponse = voucherService.findById(voucherId);
59+
model.addAttribute("voucher", voucherResponse);
60+
61+
return "voucher/find";
62+
}
63+
64+
@DeleteMapping("/delete/{id}")
65+
public String deleteById(@PathVariable("id") UUID voucherId) {
66+
voucherService.deleteById(voucherId);
67+
68+
return "redirect:/view/voucher/find";
69+
}
70+
71+
}

src/main/java/com/programmers/springweekly/docs/specification.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,46 @@ blacklist
206206
- 바우처 지갑에 있는 모든 리스트 조회(findAll)
207207
- 테스트 코드 구현
208208

209+
<hr>
210+
211+
### 3-1 Thymeleaf를 이용하여 바우처 관리페이지 구현
212+
213+
### 요약
214+
215+
- 고객, 바우처 CREATE, UPDATE, DELETE Web Controller 구현
216+
- CreateRequestDto에 Validation 적용.
217+
- Thymeleaf를 이용한 페이지 생성
218+
- ControllerAdvice를 통한 Global 예외 처리
219+
220+
### Voucher(web)
221+
222+
- 바우처 입력 기능
223+
- 바우처 삭제 기능
224+
- 바우처 전체 조회, 상세 조회 기능
225+
226+
### Customer(web)
227+
228+
- 고객 입력 기능
229+
- 고객 삭제 기능
230+
- 고객 전체 조회, 상세 조회 기능
231+
232+
### Validation
233+
234+
- Spring에서 제공하는 Validation을 사용하여 DTO단에서 RequestBody 값을 검증
235+
236+
### ControllerAdvice
237+
238+
- Controller, Serivce, Repository 등 Controller 하위 단에서 발생한 예외를 전역으로 잡는 ExceptionHandler 클래스 생성
239+
- 프로그램 내에서 발생할 것 같은 예외들을 모두 구분하여 로깅하고, 메세지를 페이지로 발송하여 Error페이지에 출력
240+
- 예외 별 상태 코드 적용
241+
- 발생할 것 같은 예외들을 모두 잡고 예상치 못한 예외가 발생했을 때 프로그램이 꺼지지 않도록 제일 하위에 최상위 Exception으로 예외 처리
242+
243+
### 웹 동작 화면(정상)
244+
![ezgif com-video-to-gif](https://github.com/prgrms-be-devcourse/springboot-basic/assets/92444744/c85de587-903e-493d-8fde-5e2d0ba3116b)
245+
246+
### 웹 동작 화면(에러)
247+
![ezgif com-video-to-gif (1)](https://github.com/prgrms-be-devcourse/springboot-basic/assets/92444744/36e41e81-6d1f-4298-8527-43ee10d43e11)
248+
249+
250+
209251

src/main/java/com/programmers/springweekly/domain/voucher/FixedAmountVoucher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class FixedAmountVoucher implements Voucher {
1111
public FixedAmountVoucher(UUID voucherId, long discountAmount) {
1212
VoucherValidator.validateVoucher(
1313
VoucherType.FIXED,
14-
String.valueOf(discountAmount)
14+
discountAmount
1515
);
1616

1717
this.voucherId = voucherId;

src/main/java/com/programmers/springweekly/domain/voucher/PercentDiscountVoucher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class PercentDiscountVoucher implements Voucher {
1111
public PercentDiscountVoucher(UUID voucherId, long discountAmount) {
1212
VoucherValidator.validateVoucher(
1313
VoucherType.PERCENT,
14-
String.valueOf(discountAmount)
14+
discountAmount
1515
);
1616

1717
this.voucherId = voucherId;

0 commit comments

Comments
 (0)