[Spring Data JPA Tutorial] 7. JPA CRUD - 2. 회원수정, 삭제 API 만들기

2021. 9. 2. 23:11Spring/Spring Data JPA Tutorial

반응형
  1. PUT. 회원수정(전체 데이터)
    1. service Method
    2. Controller 에 Put api 추가
    3. API 테스트
  2. PATCH. 회원수정(일부 데이터)
    1. service Method
    2. Controller 에 Patch api 추가
    3. API 테스트
  3. DELETE. 회원삭제
    1. delete Query Method
    2. dquery Method 및 service Method 생성
    3. dController 에 Delete api 추가
    4. API 테스트

1. PUT. 회원 수정(전체 데이터)

HTTP method 중 PUT은 리소스를 업데이트 할때 사용합니다.
리소스 업데이트는 리소스 전체 정보를 수정하는 경우와 일부 데이터만 수정하는 경우가 있는데
PUT은 전체 정보를 수정하고자 할 때 이용합니다.

PK를 이용하여 엔티티 정보를 조회한 후, 리소스를 수정한 후 save() 메서드를 통해 변경사항을 저장하면 됩니다.

1.1. service Method

이전에 생성했었던 UserRepositoryfindById 메서드를 이용하여 엔티티를 조회한 후, RequestBody에 들어있는 값을 엔티티에 반영합니다.

이 메서드를 종료 할 시 수정된 정보가 commit 또는 rollback 되도록 @Transactional 설정을 합니다.

@Transactional
@RequiredArgsConstructor
@Service
public class UserService {

	private final UserRepository userRepository;

	...

	@Transactional
	public int update(long id, final UserRequest u) {
		Optional<User> oUser = userRepository.findById(id);
		if(oUser.isPresent())
			return 0;

		User user = oUser.get();
		user.setBirthDate(u.getBirthDate());
		user.setEmail(u.getEmail());
		user.setName(u.getName());
		user.setPassword(u.getPassword());
		user.setPhoneNumber(u.getPhoneNumber());
		user.setSex(u.getSex());
		user.setType(u.getType());
		userRepository.save(user);
		return 1;
	}

}

PK로 조회결과가 존재할 경우에만 업데이트하도록 설정하였습니다.


1.2. Controller 에 Put api 추가

@PutMapping 설정을 한 api를 추가합니다.

@RequiredArgsConstructor
@RequestMapping(path = "/api/users")
@RestController
public class UserController {

	private final UserService userService;

	...

	@PutMapping("/{id}")
	public Map<String, Object> update(@PathVariable("id") long id, @RequestBody @Valid final UserRequest user) {
		Map<String, Object> response = new HashMap<>();

		int res = userService.update(id, user);
		if(res > 0) {
			response.put("result", "SUCCESS");
		} else {
			response.put("result", "FAIL");
			response.put("reason", "일치하는 회원 정보가 없습니다. 사용자 id를 확인해주세요.");
		}

		return response;
	}

}

별도의 VO 생성 없이 기존에 생성했었던 Entity Class 를 이용하여 메서드를 구성하였습니다.

1.3. API 테스트

HTTPie 를 이용하여 api를 테스트를 합니다.

관련 포스팅
HTTPie - 사용자 친화적인 Command-line HTTP client


HTTPie를 이용하여 POST api 테스트를 해보았습니다.

http PUT :8989/api/users/2 email=coco@coco.com sex=1 name=코코 birthDate=950201 phoneNumber=01088889999 type=1 password=1

23

컨트롤러 메서드에서 모든 RequestBody안의 모든 값이 @NotNull 이도록 @Valid 설정하였기 때문에, RequestBody 중 하나의 값이라도 없을 경우 아래와 같이 에러가 나며
모든 값이 들어있을 경우 정상적으로 수정됩니다.

만일 일치하는 회원정보가 없을 경우 아래와 같이 Reponse를 보냅니다.

24


2. PATCH. 회원 수정(일부 데이터)

HTTP method 중 PATCH는 리소스 중 일부 데이터를 수정 할때 사용합니다.

우리가 정의한 User Entity는 updated_at 컬럼을 제외한 모든 컬럼이 null을 허용하지 않도록 설계하였기 때문에 RequestBody 내의 항목이 null 또는 white space일 경우 수정되지 않도록 만듭니다.

StringUtils유틸을 이용하면 빈문자열이거나 기타 white space가 담긴 문자열에 대한 처리를 간단히 처리할 수 있습니다.

public class StringUtils {

    public static boolean isBlank(final CharSequence cs) {
        int strLen;
        if (cs == null || (strLen = cs.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    public static boolean isNotBlank(final CharSequence cs) {
        return !isBlank(cs);
    }

}
StringUtils.isNotBlank(null)      = false
StringUtils.isNotBlank("")        = false
StringUtils.isNotBlank(" ")       = false
StringUtils.isNotBlank("test")     = true
StringUtils.isNotBlank("  test  ") = true

2.1. service Method

StringUtils.isNotBlank 메서드를 이용하여 값이 들어있는 경우에만 수정되도록 메서드를 정의합니다.

@Transactional
@RequiredArgsConstructor
@Service
public class UserService {

	private final UserRepository userRepository;

	...

	@Transactional
	public int partialUpdate(long id, final UserRequest u) {
		Optional<User> oUser = userRepository.findById(id);
		if(oUser.isPresent())
			return 0;

		User user = oUser.get();
		if(StringUtils.isNotBlank(u.getBirthDate())) user.setBirthDate(u.getBirthDate());
		if(StringUtils.isNotBlank(u.getEmail())) user.setEmail(u.getEmail());
		if(StringUtils.isNotBlank(u.getName())) user.setName(u.getName());
		if(StringUtils.isNotBlank(u.getPassword())) user.setPassword(u.getPassword());
		if(StringUtils.isNotBlank(u.getPhoneNumber())) user.setPhoneNumber(u.getPhoneNumber());
		if(StringUtils.isNotBlank(u.getSex())) user.setSex(u.getSex());
		if(StringUtils.isNotBlank(u.getType())) user.setType(u.getType());
		userRepository.save(user);
		return 1;
	}

}

2.2. Controller 에 Patch api 추가

RequestBody로 이용되는 UserRequest DTO 는 Null값을 허용해야하기 때문에, @Valid 설정을 하지 않습니다.

@RequiredArgsConstructor
@RequestMapping(path = "/api/users")
@RestController
public class UserController {

	private final UserService userService;

	...

	@PatchMapping("/{id}")
	public Map<String, Object> partialUpdate(@PathVariable("id") long id, @RequestBody final UserRequest user) {
		Map<String, Object> response = new HashMap<>();

		int res = userService.partialUpdate(id, user);
		if(res > 0) {
			response.put("result", "SUCCESS");
		} else {
			response.put("result", "FAIL");
			response.put("reason", "일치하는 회원 정보가 없습니다. 사용자 id를 확인해주세요.");
		}

		return response;
	}

}

2.3. API 테스트

PATCH를 통해 type값을 수정한 결과입니다.

http PATCH :8989/api/users/2 type=2

25


3. User 삭제 (DELETE)

3.1. delete Query Method

Spring Data JPA Reference Document에는 조회에 이용되는 Query Method 이외에도 수정에 관한 쿼리 메서드 사용방법도 명시되어있습니다.

참고: 6.3.8. Modifying Queries - Derived Delete Queries


```java public interface UserRepository extends Repository {

void delete(User user);

void deleteByEmail(long roleId);

@Modifying
@Query("delete from User u where u.role.id = ?1")
void deleteInBulkByRoleId(long roleId);
}

**deleteBy** 이하에 where 절 조건을 설정한 Query Method를 설정할 수 있으며, 이는 직접 **@Query** 로 JPQL을 설정한 것과 동일하게 작동됩니다.

또한, 엔티티를 넣어서 삭제할 수 있습니다.
<br>


###  <div id="a03-2">3.2. query Method 및 service Method 생성</div>
<p class="mume-header " id="div-ida03-232-query-method-및-service-method-생성div"></p>


```java
public interface UserRepository extends Repository<User, Long> {

	...
	void delete(User user);

}

delete Query Method를 생성하고

@Transactional(readOnly = true)
@RequiredArgsConstructor
@Service
public class UserService {

	private final UserRepository userRepository;
	...

	@Transactional
	public int delete(long id) {
		Optional<User> oUser = userRepository.findById(id);
		if(oUser.isPresent()) {
			userRepository.delete(oUser.get());
			return 1;
		}
		return 0;
	}
}

Id를 이용하여 User 엔티티를 조회한 후 조회된 엔티티를 제거합니다.

3.3. Controller 에 Delete api 추가

@DeleteMapping("/{id}")
public Map<String, Object> delete(@PathVariable("id") long id) {
	Map<String, Object> response = new HashMap<>();

	if(userService.delete(id) > 0) {
		response.put("result", "SUCCESS");
	} else {
		response.put("result", "FAIL");
		response.put("reason", "일치하는 회원 정보가 없습니다. 사용자 id를 확인해주세요.");
	}

	return response;
}

3.4. API 테스트

26

2번 사용자를 제거한 후 다시 조회할 시, 회원정보가 조회되지 않습니다.


CRUD api를 모두 만든 후의 demo 프로젝트 구조입니다.

02

++ End

이번 포스팅에서는 User 엔티티의 PK인 id를 이용하여 조회한 사용자를 수정하거나 삭제하는 방법을 알아보았습니다.

다음시간에는 Dynamic Query 조회 방법을 알아볼 것입니다.

GitHub에서 demo 프로젝트(v1.0.3)를 다운받아 볼 수 있습니다.


++ Reference

728x90
반응형