220407 - Spring Instagram clone (Image upload, Subscription)

Image

Domain

  1. user id
  2. caption
  3. post image url
public class Image {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String caption;
    private String postImageUrl; // Image will be saved as folder in server - insert path in DB

    @JoinColumn(name="userId")
    @ManyToOne
    private User user;

    private LocalDateTime createDate;

    @PrePersist
    public void createDate() {
        this.createDate = LocalDateTime.now();
    }

}

Dto is used to build caption, postImageUrl, user.

Service

Get the file path from application.yml, image name is made by UUID_{originalFileName}.

Therefore, image file and path are saved to image table(imageRepository).

@Transactional
public void imageUpload(ImageUploadDto imageUploadDto, PrincipalDetails principalDetails) {

    UUID uuid = UUID.randomUUID();
    String imageFileName = uuid + "_" + imageUploadDto.getFile().getOriginalFilename();

    Path imageFilePath = Paths.get(uploadFolder + imageFileName);

    // Communication, I/O -> can occur exception
    try {
        Files.write(imageFilePath, imageUploadDto.getFile().getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }

    // save to image table
    Image image = imageUploadDto.toEntity(imageFileName, principalDetails.getUser());
    imageRepository.save(image);

}

In controller, throw exception if image is not found.

Subscription

Domain

  1. user id
  2. from user
  3. to user
@Table(
        uniqueConstraints = {
                @UniqueConstraint(
                        name="subscribe_uk",
                        columnNames = {"fromUserId", "toUserId"}
                )
        }
)
public class Subscribe {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @JoinColumn(name="fromUserId")
    @ManyToOne
    private User fromUser;

    @JoinColumn(name="toUserId")
    @ManyToOne
    private User toUser;

    private LocalDateTime createDate;

    @PrePersist
    public void createDate() {
        this.createDate = LocalDateTime.now();
    }

}

('fromUser', 'toUser') set is unique. (use @uniqueConstraints)

Service

First in SubscribeRepository, make 'create, delete set' method. (by using native query)

public interface SubscribeRepository extends JpaRepository<Subscribe, Integer> {

    @Modifying // for INSERT, DELETE, UPDATE in native query
    @Query(value = "INSERT INTO subscribe(fromUserId,toUserId,createDate) VALUES(:fromUserId,:toUserId,now())", nativeQuery = true)
    void mSubscribe(int fromUserId, int toUserId); // 1(success, number of changed row), 0(not executed), -1(fail)

    @Modifying
    @Query(value = "DELETE FROM subscribe WHERE fromUserId=:fromUserId AND toUserId=:toUserId", nativeQuery = true)
    void mUnSubscribe(int fromUserId, int toUserId); // 1, -1

}

Back to service, access to repository and throw exception about any prob.

public class SubscribeService {

    private final SubscribeRepository subscribeRepository;

    @Transactional
    public void sub(int fromUserId, int toUserId) {
        try {
            subscribeRepository.mSubscribe(fromUserId, toUserId);
        } catch(Exception e) {
            throw new CustomApiException("Already subscribed");
        }
    }

    @Transactional
    public void unSub(int fromUserId, int toUserId) {
        subscribeRepository.mUnSubscribe(fromUserId, toUserId);
    }

}

apiController

Use ResponseEntity<> with PostMapping and DeleteMapping, call the service logic.

public class SubscribeApiController {

    private final SubscribeService subscribeService;

    @PostMapping("/api/subscribe/{toUserId}")
    public ResponseEntity<?> subscribe(@AuthenticationPrincipal PrincipalDetails principalDetails, @PathVariable int toUserId) {
        subscribeService.sub(principalDetails.getUser().getId(), toUserId);
        return new ResponseEntity<>(new CMRespDto<>(1, "Subscription success", null), HttpStatus.OK);
    }

    @DeleteMapping("/api/subscribe/{toUserId}")
    public ResponseEntity<?> unSubscribe(@AuthenticationPrincipal PrincipalDetails principalDetails, @PathVariable int toUserId) {
        subscribeService.unSub(principalDetails.getUser().getId(), toUserId);
        return new ResponseEntity<>(new CMRespDto<>(1, "Unsubscription success", null), HttpStatus.OK);
    }

}

좋은 웹페이지 즐겨찾기