1) domain ํด๋์ค ์์ฑ
๋๋ฉ์ธ
ํน์ ์ ๋ฌธ ๋ถ์ผ์์ ์ฌ์ฉ๋๋ ์ ๋ฌธ ์ง์
์คํ ๋ ์คํ์
ํด๋น ํด๋์ค๊ฐ ์ด๋ ์ฉ๋๋ก ์ฌ์ฉ๋ ๊ฒ์ธ์ง ๋ํ๋ด๋ ๊ฒ → ์์กด์ฑ ์ฃผ์ ํ ๋ ๋์์ด ๋๋ค.
ex) @RestController, @Service
User domain
์ฌ๊ธฐ์์๋ @Data annotation์ ์ฌ์ฉํ์ง๋ง @Data ์ฌ์ฉ์ ๋๋๋ก ์์ ํ๊ณ @Getter @Setter ๋ฑ์ ๋ฐ๋ก ์ง์ ํด์ฃผ๋ ๊ฒ์ด ์ข๋ค.
(@Data ๊ฐ์ ๊ฒฝ์ฐ๋ ํ๊บผ๋ฒ์ ๋ง์ ๊ธฐ๋ฅ์ ๋ถ๋ฌ์ค๊ธฐ๋ ํ๊ณ , @ToString์ ์๋ชป ์ฐ๋ฉด JPA์์ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๊ธฐ ๋๋ฌธ)
@Data @AllArgsConstructor
public class User {
private Integer id;
private String name;
private Date joinDate;
}
2) DAO + Service ํด๋์ค ์์ฑ
ํ์ง๋ง db ์ฐ๊ฒฐ์ ํ์ง ์๊ธฐ ๋๋ฌธ์ DAO ํด๋์ค๋ ํ์์๋ค. ๊ทธ๋ฌ๋ Service ํด๋์ค๋ง ๋ง๋ค์ด๋ณด๊ฒ ๋ค.
@Service
public class UserDaoService {
private static List<User> users = new ArrayList<>();
private static int usersCount = 3;
static {
users.add(new User(1, "minji", true, new Date()));
users.add(new User(2, "nitro", false, new Date()));
users.add(new User(3, "ewha", false, new Date()));
}
// ์ ์ฒด ์กฐํ
public List<User> findAll(){
return users;
}
// ์ ์ฅ
public User save(User user){
if (user.getId() == null){
user.setId(++usersCount);
}
users.add(user);
return user;
}
// ์ผ๋ถ ์กฐํ
public User findOne(int id){
for (User user : users){
if (user.getId() == id) return user;
}
return null;
}
public User deleteById(int id){
Iterator<User> iterator = users.iterator();
while(iterator.hasNext()){
User user = iterator.next();
if (user.getId() == id){
iterator.remove();
return user;
}
}
return null;
}
public User updateById(int id){
Iterator<User> iterator = users.iterator();
while(iterator.hasNext()){
User user = iterator.next();
if (user.getId() == id){
return user;
}
}
return null;
}
}
3) Controller ํด๋์ค ์์ฑ
์์กด์ฑ ์ฃผ์
- setter ๋ฉ์๋ / ์์ฑ์์ ๋งค๊ฐ๋ณ์ / @Autowired๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
- userController์์ service๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์์กด์ฑ ์ฃผ์ ํ๋ค.(์์ฑ์๋ฅผ ํตํ ์์กด์ฑ ์ฃผ์ )
=> DEBUG ๋ ๋ฒจ์ log์์ userController๋ฅผ ๊ฒ์ํ๋ฉด ์์กด์ฑ ์ฃผ์ ์ด ์๋ฃ๋์ด ์๋์ ๊ฐ์ ๋ฉ์์ง๊ฐ ๋ฌ๋ค.
'userController' via constructor to bean named 'userDaoService'
@RestController
public class UserController {
private UserDaoService service;
// ์์ฑ์๋ฅผ ํตํ ์์กด์ฑ ์ฃผ์
public UserController(UserDaoService service) {
this.service = service;
}
// GET users/10 -> String
// ๊ธฐ๋ณธ์ String์ด์ง๋ง ๋งค๊ฐ๋ณ์๋ก int ๋ฐ์ผ๋ฉด ์๋ ๋ณ๊ฒฝ
@GetMapping("/users/{id}")
public User retrieveUser(@PathVariable int id) {
User user = service.findOne(id);
if (user == null){
// ์ง์ ์ํฉ์ ๋ง๋ ์์ธ ํด๋์ค ์์ฑ
throw new UserNotFoundException(
String.format("ID[%s] is not found", id));
}
return user;
}
@PostMapping("/users")
// @RequestBody : ํ์ฌ variable์ด requestBody ํ์์ผ๋ก ๋ค์ด์ด์ ์๋ฆผ
public ResponseEntity<User> createUser(@RequestBody User user) {
User savedUser = service.save(user);
// ServletUriComponentBuilder -> ํ์ฌ ์์ฒญ์ URI๋ฅผ ์ป์ ์ ์๋ค.
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
// ResponseEntity -> HTTP ์ํ ์ฝ๋์ ์ ์กํ๊ณ ์ถ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ก
// HTTP 201 Created : ์์ฒญ์ด ์ฑ๊ณต์ ์ด์์ผ๋ฉฐ ๊ทธ ๊ฒฐ๊ณผ๋ก ์๋ก์ด ๋ฆฌ์์ค๊ฐ ์์ฑ๋จ
return ResponseEntity.created(location).build();
}
HTTP Status Code
- 2XX → OK
- 4XX → Client
- 5XX → Server
@ServletUriComponentsBuilder๋ฅผ ์ด์ฉํด ํธ์ถ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ ์ ์ ํ status code๋ฅผ ๋ฐํํจ
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user){
User savedUser = service.save(user);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).build();
}
HTTP Status Code๋ฅผ ์ด์ฉํ Exception Handling
customizedException์ ์ฌ์ฉํ๋ฉด ์ํฉ์ ๋ฐ๋ผ ์๋ง์ HTTP ์ํ ์ฝ๋์ ๋ฉ์์ง๋ฅผ ๋ฐํํ ์ ์๋ค.
๋ณดํต์ customizedExceptionHandler๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ customizedException์ ์ฌ์ฉํ๋ค.
์๋ ์ฝ๋์์๋ @ResponseStatus๋ฅผ ์ฌ์ฉํ์ง๋ง CustomizedResponseEntityExceptionHandler.class์์ UserNotFoundException์ด ๋ฐ์ํ์ ๋, Exception Response๋ฅผ ๋ฐํ(Http status code๋ ๋ฐํ)ํ๋ค.
=> ResponseStatus ์๋ต ๊ฐ๋ฅ
[Controller]
@GetMapping("/users/{id}")
public User retrieveUser(@PathVariable int id) {
User user = service.findOne(id);
if (user == null){
throw new UserNotFoundException(String.format("ID[%s] is not found", id));
}
return user;
}
[Exception]
@ResponseStatus(HttpStatus.NOT_FOUND) // ์๋ต ์ํ ์ฝ๋ ๊ฐ ์ง์
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message); // ex.getMessage()
}
}
Spring AOP(Aspect Oriented Programming)๋ฅผ ์ด์ฉํ Error Handling
์คํ๋ง ๋ถํธ ์ดํ๋ฆฌ์ผ์ด์ ๋ด์์ ๊ณตํต์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด์ผ ํ๋ ๋ก์ง์ด๋ ๋ฉ์๋ ์ถ๊ฐ
Aspect๋ก ๋ชจ๋ํํ๊ณ ํต์ฌ์ ์ธ ๋น์ฆ๋์ค ๋ก์ง์์ ๋ถ๋ฆฌํ์ฌ ์ฌ์ฌ์ฉ
1) ๊ธฐ๋ณธ Response ์์ ์ง์
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExceptionResponse {
private Date timestamp;
private String message;
private String details;
}
2) ์์ธ ์ฒ๋ฆฌ handler ์์ฑ
- @ControllerAdvice
- ๋ชจ๋ Controller๊ฐ ์คํ๋ ๋ annotation์ ๊ฐ์ง๊ณ ์๋ bean์ด ํญ์ ๋จผ์ ์คํ๋จ
[CustomizedResponseEntityExceptionHandler]
@RestController
@ControllerAdvice // ๋ชจ๋ @Controller๊ฐ ์คํ๋๊ธฐ ์ ์ ์คํ๋จ -> ์ ์ญ ๋ฐ์ ์์ธ ์ฒ๋ฆฌ ๊ฐ๋ฅ
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
ExceptionResponse exceptionResponse =new ExceptionResponse(
new Date(), ex.getMessage(), request.getDescription(false));
// ResponseEntity : http status code์ ์ ์กํ๊ณ ์ ํ๋ ๋ฐ์ดํฐ๋ฅผ ํจ๊ป ์ ์ก
return new ResponseEntity(exceptionResponse,
HttpStatus.INTERNAL_SERVER_ERROR);
}
3) ์ํฉ๋ณ custome Exception ์์ฑ
custom exception ์์ฑ ํ์๋ customizedExceptionHandler์ ๋ฃ์ด์ฃผ์ด์ผ ํ๋ค.
@ExceptionHandler(UserNotFoundException.class)
public final ResponseEntity<Object> handleUserNotFoundException(Exception ex, WebRequest request) {
ExceptionResponse exceptionResponse = new ExceptionResponse(
new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
}
'๐ฟ Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring Boot/RESTful] Response ๋ฐ์ดํฐ ํ์ ๋ฐํ(XML format) (0) | 2022.02.18 |
---|---|
[Spring Boot/RESTful] Validation API์ Internationalization (0) | 2022.02.18 |
[Spring Boot/RESTful] Spring Boot๋ก ๊ฐ๋ฐํ๋ RESTful Service (0) | 2022.02.17 |
[Spring Boot/RESTful] Web Service & Web Application (0) | 2022.02.17 |
[Error] Spring Boot(2.5x)์์ data.sql ์คํ ์ค๋ฅ(H2 database) (0) | 2022.02.02 |
๋๊ธ