Spring & SpringBoot

[Spring] SpringBoot_게시글 수정하기 (JPA, MySQL)

예령 : ) 2023. 1. 18. 18:03

기존 데이터를 수정하기 위해 jpa의 save() 메소드를 활용했었다.

 

✔️ 발생한 문제

  1. 게시물 수정 시 response 값의 created_at data가 null 값
  2. 게시물 수정 시 viewCnt(조회수) 값 초기화

     코드 수정해야하는 이유

     👉 추후 전체 게시글들을 생성시간 순으로 조회하면 생성시간이 null 값인 게시물은 가장 마지막에 조회되기 때문

 

✔️ stackoverflow 에서 찾은 비슷한 에러 상황

    https://stackoverflow.com/questions/73051733/createddate-set-to-null-on-update-spring-data-jdbc

 

✔️ 해결을 위해 시도해본 것

  1. created_at 컬럼에 updatable = false 설정을 추가
  2. 로그를 찍어보며 변경 시점 체크 + Entity 에 update method 생성 (더티 체킹)

✔️ 각각의 결과

  1. db 에서는 기존 생성시간이 null 로 변경되지 않고 남아있게 됨 하지만 여전히 response 값에는 null 로 표현 (실패)
    • data 수정 시 update 문에 포함되지 않음
  2. 원하는 형태의 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차 캐시 등등 ,, !!