Spring & SpringBoot
[Spring] SpringBoot_게시글 수정하기 (JPA, MySQL)
예령 : )
2023. 1. 18. 18:03
기존 데이터를 수정하기 위해 jpa의 save() 메소드를 활용했었다.
✔️ 발생한 문제
- 게시물 수정 시 response 값의 created_at data가 null 값
- 게시물 수정 시 viewCnt(조회수) 값 초기화
코드 수정해야하는 이유
👉 추후 전체 게시글들을 생성시간 순으로 조회하면 생성시간이 null 값인 게시물은 가장 마지막에 조회되기 때문
✔️ stackoverflow 에서 찾은 비슷한 에러 상황
https://stackoverflow.com/questions/73051733/createddate-set-to-null-on-update-spring-data-jdbc
✔️ 해결을 위해 시도해본 것
- created_at 컬럼에 updatable = false 설정을 추가
- 로그를 찍어보며 변경 시점 체크 + Entity 에 update method 생성 (더티 체킹)
✔️ 각각의 결과
- db 에서는 기존 생성시간이 null 로 변경되지 않고 남아있게 됨 하지만 여전히 response 값에는 null 로 표현 (실패)
- data 수정 시 update 문에 포함되지 않음
- 원하는 형태의 response 구현 (성공)
게시물 수정 전 data
게시물 수정 후 data (문제 발생)
기존 코드
Controller
@Api(tags = {"post_rehoming_api"})
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/rehoming")
public class RehomingController {
private final RehomingServiceImpl rehomingService;
/* 4. 분양 글 수정 */
@ApiOperation(value = "분양게시물 수정", notes = "분양 게시물 수정")
@RequestMapping(value = "",method = RequestMethod.PUT)
public SuccessResponse updateRehoming(@AuthenticationPrincipal UserDetailsImpl userDetails,
@RequestPart List<MultipartFile> rehomingImg,
@RequestParam Long postId, @RequestPart RehomingReqDto rehomingDto) {
RehomingCommand rehomingCommand = rehomingDto.toCommand();
return SuccessResponse.success(rehomingService.updateRehoming(userDetails.getUser(), postId, rehomingCommand, rehomingImg), "OK");
}
}
RehomingService
public interface RehomingService {
RehomingResDto updateRehoming(User user, Long postId, RehomingCommand rehomingCommand, List<MultipartFile> rehomingImg);
}
RehomingServiceImpl
@RequiredArgsConstructor
@Service
public class RehomingServiceImpl implements RehomingService {
private final RehomingReader rehomingReader;
private final RehomingStore rehomingStore;
private final ImageUploadManager imageUploadManager;
private final CommonUtils commonUtils;
// 4. 분양 글 수정
@Override
public RehomingResDto updateRehoming(User user, Long postId, RehomingCommand rehomingCommand, List<MultipartFile> rehomingImg) {
// 4-1. 게시글 존재 유무 판단
Rehoming rehoming = rehomingReader.readRehomingById(postId);
rehomingReader.userChk(user.getId(), rehoming);
// 4-2. 게시글 수정
CategoryGroup category = rehomingReader.readCategoryById(rehomingCommand.getCategory());
PetCategory type = rehomingReader.readPetTypeById(rehomingCommand.getType());
Rehoming initRehoming = rehomingCommand.toUpdateEntity(user, postId, category, type);
Rehoming rehomingSave = rehomingStore.update(initRehoming);
// 4-3. 이미지 수정
imageUploadManager.updateImage(rehomingImg, postId, PostType.REHOMING);
return getResDto(user, postId, rehomingSave);
}
private RehomingResDto getResDto(User user, Long postId, Rehoming rehoming) {
List<String> imgList = imageUploader.createImgList(postId, PostType.REHOMING);
return new RehomingResDto(rehoming, imgList,
commonUtils.LikePostChk(postId, PostType.REHOMING, user),
commonUtils.BookmarkPostChk(postId, PostType.REHOMING, user),
commonUtils.getLikesCnt(postId, PostType.REHOMING),
commonUtils.getBookmarkCnt(postId, PostType.REHOMING));
}
}
RehomingStore
public interface RehomingStore {
Rehoming update(Rehoming rehoming);
}
RehomingStoreImpl
@RequiredArgsConstructor
@Component
public class RehomingStoreImpl implements RehomingStore {
private final RehomingRepository rehomingRepository;
@Override
public Rehoming update(Rehoming rehoming) {
return rehomingRepository.save(rehoming);
}
}
변경 후 코드
@RequiredArgsConstructor
@Service
public class RehomingServiceImpl implements RehomingService {
private final RehomingReader rehomingReader;
private final RehomingStore rehomingStore;
private final ImageUploadManager imageUploadManager;
private final CommonUtils commonUtils;
// 4. 분양 글 수정
@Override
public RehomingResDto updateRehoming(User user, Long postId, RehomingCommand rehomingCommand, List<MultipartFile> rehomingImg) {
// 4-1. 게시글 존재 유무 판단
Rehoming rehoming = rehomingReader.readRehomingById(postId);
rehomingReader.userChk(user.getId(), rehoming);
// 4-2. 게시글 수정
CategoryGroup category = rehomingReader.readCategoryById(rehomingCommand.getCategory());
PetCategory type = rehomingReader.readPetTypeById(rehomingCommand.getType());
Rehoming initRehoming = rehomingCommand.toUpdateEntity(user, postId, category, type);
rehoming.update(initRehoming);
// 4-3. 이미지 수정
imageUploadManager.updateImage(rehomingImg, postId, PostType.REHOMING);
return getResDto(user, postId, rehoming);
}
private RehomingResDto getResDto(User user, Long postId, Rehoming rehoming) {
List<String> imgList = imageUploader.createImgList(postId, PostType.REHOMING);
return new RehomingResDto(rehoming, imgList,
commonUtils.LikePostChk(postId, PostType.REHOMING, user),
commonUtils.BookmarkPostChk(postId, PostType.REHOMING, user),
commonUtils.getLikesCnt(postId, PostType.REHOMING),
commonUtils.getBookmarkCnt(postId, PostType.REHOMING));
}
}
Rehoming
@Getter
@Entity
@Table(name = "TB_REHOMING")
@Builder
@DynamicUpdate // 변경한 필드만 대응
public class Rehoming extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "REHOMING_ID")
private Long rehomingId;
@ManyToOne
@JoinColumn(name = "USER_ID")
private User user;
@Column(name = "TITLE")
private String title;
@Column(name = "DESCRIPTION", columnDefinition = "TEXT")
private String description;
@Column(name = "PET_NAME")
private String petName;
@Column(name = "PET_AGE")
private String petAge;
@ManyToOne
@JoinColumn(name = "CATEGORY_GROUP_ID")
private CategoryGroup category;
@ManyToOne
@JoinColumn(name = "PET_CATEGORY_ID")
private PetCategory type;
@Column(name = "GENDER")
private String gender;
@Column(name = "LOCATION")
private String location;
@Column(name = "PRICE")
private Long price;
@Column(name = "STATUS")
@Enumerated(EnumType.STRING)
private PostStatus status;
@Column(name = "POST_TYPE")
@Enumerated(EnumType.STRING)
private PostType postType;
@Column(name = "VIEW_CNT")
private int viewCnt;
public void update(Rehoming initRehoming) {
this.title = initRehoming.getTitle();
this.description = initRehoming.getDescription();
this.petName = initRehoming.getPetName();
this.petAge = initRehoming.getPetAge();
this.category = initRehoming.getCategory();
this.type = initRehoming.getType();
this.gender = initRehoming.getGender();
this.location = initRehoming.getLocation();
this.price = initRehoming.getPrice();
this.status = initRehoming.getStatus();
}
}
수정하니 잘 된다!
참고 자료
https://jojoldu.tistory.com/415
https://hello-backend.tistory.com/159
https://www.baeldung.com/spring-data-partial-update
더 공부해야 된다고 느낀 부분
영속성, 영속성 컨텍스트, 1차 캐시 등등 ,, !!