Skip to content

Commit

Permalink
Merge pull request #11 from gutanbug/feat/banner
Browse files Browse the repository at this point in the history
Feat/banner
  • Loading branch information
gutanbug authored Apr 27, 2024
2 parents d901aed + 1960af3 commit 8850c7b
Show file tree
Hide file tree
Showing 27 changed files with 912 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.dku.council.domain.admin.controller;

import com.dku.council.domain.admin.dto.AdBannerPageDto;
import com.dku.council.domain.admin.service.AdBannerPageService;
import com.dku.council.domain.banner.model.dto.request.RequestCreateBannerDto;
import com.dku.council.domain.banner.model.dto.response.ResponseBannerDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Controller
@RequestMapping("/manage/ad-banner")
@RequiredArgsConstructor
public class AdBannerPageController {

private final AdBannerPageService service;

@GetMapping
public String adBanner(Model model, RequestCreateBannerDto dto) {
List<AdBannerPageDto> results = service.getAdBanner();
model.addAttribute("banners", results);
model.addAttribute("object", dto);
return "page/ad-banner/ad-banner";
}

@PostMapping("/create")
public String createAdBanner(HttpServletRequest request, RequestCreateBannerDto dto) {
service.createBanner(dto);
return "redirect:" + request.getHeader("Referer");
}

@PostMapping("/{adBannerId}/delete")
public String deleteAdBanner(HttpServletRequest request, @PathVariable Long adBannerId) {
service.deleteBanner(adBannerId);
return "redirect:" + request.getHeader("Referer");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.dku.council.domain.admin.dto;

import com.dku.council.domain.banner.model.BannerImage;
import com.dku.council.domain.banner.model.entity.Banner;
import com.dku.council.infra.nhn.s3.service.ObjectUploadContext;
import lombok.Getter;

@Getter
public class AdBannerPageDto {
private final Long id;
private final String bannerUrl;
private final String redirectUrl;
private final int viewCount;
private final int distinctViewCount;
private final int clickCount;

public AdBannerPageDto(Banner banner, BannerImage image, ObjectUploadContext context) {
this.id = banner.getId();
this.bannerUrl = context.getImageUrl(image.getFileId());
this.redirectUrl = banner.getBannerUrl();
this.viewCount = banner.getViewCount();
this.distinctViewCount = banner.getDistinctViewCount();
this.clickCount = banner.getClickCount();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.dku.council.domain.admin.service;

import com.dku.council.domain.admin.dto.AdBannerPageDto;
import com.dku.council.domain.banner.exception.BannerNotFoundException;
import com.dku.council.domain.banner.exception.InvalidBannerTypeException;
import com.dku.council.domain.banner.model.BannerImage;
import com.dku.council.domain.banner.model.dto.request.RequestCreateBannerDto;
import com.dku.council.domain.banner.model.dto.response.ResponseBannerDto;
import com.dku.council.domain.banner.model.entity.Banner;
import com.dku.council.domain.banner.repository.BannerImageRepository;
import com.dku.council.domain.banner.repository.BannerRepository;
import com.dku.council.infra.nhn.s3.model.ImageRequest;
import com.dku.council.infra.nhn.s3.service.ImageUploadService;
import com.dku.council.infra.nhn.s3.service.ObjectUploadContext;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional
public class AdBannerPageService {

private final ObjectUploadContext uploadContext;
private final ImageUploadService imageUploadService;

private final BannerRepository bannerRepository;
private final BannerImageRepository bannerImageRepository;

public List<AdBannerPageDto> getAdBanner() {
return bannerRepository.findAll().stream()
.map(banner -> {
BannerImage bannerImage = bannerImageRepository.findByBannerId(banner.getId())
.orElseThrow(BannerNotFoundException::new);
return new AdBannerPageDto(banner, bannerImage, uploadContext);
})
.collect(Collectors.toList());
}

@Transactional
public void createBanner(RequestCreateBannerDto dto) {
MultipartFile file = dto.getImage();
String redirectUrl = dto.getBannerUrl();
String originalImageName = file.getOriginalFilename();

if (!verifyImageExtension(originalImageName)) {
throw new InvalidBannerTypeException(originalImageName);
}

String imageId = imageUploadService.newContext()
.uploadImage(new ImageRequest(file), "banner")
.getImageId();

Banner banner = Banner.builder()
.startDate(LocalDateTime.parse(dto.getStartDate()))
.endDate(LocalDateTime.parse(dto.getEndDate()))
.bannerUrl(redirectUrl)
.build();

BannerImage bannerImage = BannerImage.builder()
.fileId(imageId)
.mimeType(file.getContentType())
.fileName(originalImageName)
.build();
bannerImage.changeBanner(banner);

bannerRepository.save(banner);
}

private boolean verifyImageExtension(String originName) {
if (originName == null) return false;

return originName.endsWith(".jpg") ||
originName.endsWith(".jpeg") ||
originName.endsWith(".png") ||
originName.endsWith(".gif") ||
originName.endsWith(".svg") ||
originName.endsWith(".webp");
}

@Transactional
public void deleteBanner(Long adBannerId) {
Banner banner = bannerRepository.findById(adBannerId)
.orElseThrow(BannerNotFoundException::new);
String fileId = banner.getImages().get(0).getFileId();

imageUploadService.newContext().deleteImage(fileId);
bannerRepository.delete(banner);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.dku.council.domain.banner.controller;

import com.dku.council.domain.banner.model.dto.response.ResponseBannerDto;
import com.dku.council.domain.banner.model.dto.response.ResponseBannerUrlDto;
import com.dku.council.domain.banner.service.BannerService;
import com.dku.council.global.util.RemoteAddressUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Tag(name = "배너", description = "배너 API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/banner")
public class BannerController {

private final BannerService bannerService;

/**
* 전체 배너 조회
*/
@PostMapping
public List<ResponseBannerDto> getBannerList(HttpServletRequest request) {
return bannerService.getBannerList(RemoteAddressUtil.getProxyableAddr(request));
}

/**
* 배너 URL 조회
* <p>배너 Id로 배너 URL을 조회합니다. 경로 Redirection는 새 창으로 해주세요.</p>
*
* @param id 배너 ID
* @return 배너 URL
*/
@GetMapping("/{id}")
public ResponseBannerUrlDto getBannerUrl(@PathVariable Long id, HttpServletRequest request) {
String result = bannerService.getBannerUrl(id, RemoteAddressUtil.getProxyableAddr(request));
return new ResponseBannerUrlDto(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.dku.council.domain.banner.exception;

import com.dku.council.global.error.exception.LocalizedMessageException;
import org.springframework.http.HttpStatus;

public class BannerNotFoundException extends LocalizedMessageException {

public BannerNotFoundException() {
super(HttpStatus.NOT_FOUND, "notfound.banner");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.dku.council.domain.banner.exception;

import com.dku.council.global.error.exception.LocalizedMessageException;
import org.springframework.http.HttpStatus;

public class InvalidBannerTypeException extends LocalizedMessageException {
public InvalidBannerTypeException(String imageName) {
super(HttpStatus.BAD_REQUEST, "invalid.banner-type", imageName);
}
}
48 changes: 48 additions & 0 deletions src/main/java/com/dku/council/domain/banner/model/BannerImage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.dku.council.domain.banner.model;

import com.dku.council.domain.banner.model.entity.Banner;
import com.dku.council.global.base.BaseEntity;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BannerImage extends BaseEntity {

@Id
@GeneratedValue
@Column(name = "banner_image_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "banner_id")
private Banner banner;

private String fileId;


private String mimeType;

private String fileName;

@Builder
private BannerImage(String fileId, String mimeType, String fileName) {
this.fileId = fileId;
this.mimeType = mimeType;
this.fileName = fileName;
}

public void changeBanner(Banner banner) {
if (this.banner != null) {
this.banner.getImages().remove(this);
}

this.banner = banner;
this.banner.getImages().add(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.dku.council.domain.banner.model.dto;

import com.dku.council.domain.banner.model.BannerImage;
import com.dku.council.infra.nhn.s3.service.ObjectUploadContext;
import lombok.Getter;
import org.springframework.http.MediaType;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Getter
public class BannerImageDto {

private final Long id;

private final String url;

private final String originalName;

private final String mimeType;

public BannerImageDto(ObjectUploadContext context, BannerImage image) {
this.id = image.getId();
this.url = context.getImageUrl(image.getFileId());
this.originalName = image.getFileName();

String imageMimeType = image.getMimeType();
this.mimeType = Objects.requireNonNullElse(imageMimeType, MediaType.APPLICATION_OCTET_STREAM_VALUE);
}

public static List<BannerImageDto> listOf(ObjectUploadContext context, List<BannerImage> entities) {
List<BannerImage> result = new ArrayList<>();

for (BannerImage entity : entities) {
result.add(entity);
}
return result.stream()
.map(image -> new BannerImageDto(context, image))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.dku.council.domain.banner.model.dto.request;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@RequiredArgsConstructor
public class RequestCreateBannerDto {
private final String bannerUrl;

private final MultipartFile image;

private final String startDate;

private final String endDate;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.dku.council.domain.banner.model.dto.response;

import com.dku.council.domain.banner.model.dto.BannerImageDto;
import com.dku.council.domain.banner.model.entity.Banner;
import com.dku.council.infra.nhn.s3.service.ObjectUploadContext;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.List;

@Getter
public class ResponseBannerDto {

private final Long id;

private final LocalDateTime startDate;

private final LocalDateTime endDate;

private final String bannerUrl;

private final List<BannerImageDto> images;

public ResponseBannerDto(Banner banner, ObjectUploadContext context) {
this.id = banner.getId();
this.startDate = banner.getStartDate();
this.endDate = banner.getEndDate();
this.bannerUrl = banner.getBannerUrl();
this.images = BannerImageDto.listOf(context, banner.getImages());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.dku.council.domain.banner.model.dto.response;

import lombok.Getter;

@Getter
public class ResponseBannerUrlDto {

private final String url;

public ResponseBannerUrlDto(String url) {
this.url = url;
}
}
Loading

0 comments on commit 8850c7b

Please sign in to comment.