[toyproject] 웹 애플리케이션 만들기5 - 기능 만들기

한지연·2023년 7월 14일
0

오늘은 만들어 둔 기능들 중 사진 업로드, 좋아요 기능을 포스팅 하려고 한다. 사진 업로드 할 때 이미지 파일만 받을 수 있도록 하는 처리를 안 해뒀는데(이외에 또 살펴 보면 더 이런 저런 문제가 있을 것이다.) 아직 디버깅 하는 날이 아니기 때문에 바뀐 코드는 다음 포스팅 때 수정된 코드로 올리려고 한다.

front-end

const CustomIcon = styled(FavoriteIcon)({
    position: 'absolute',
    top: '18vh',
    left: '9vw',
    width: '2vw',
    height: '4vh',
    color: '#F5382E',
    cursor: 'pointer',
    '&: hover': {
        transform: 'scale(1.2)',
        transitionDuration: '0.1s',
    } 
});


const UploadInput = styled(TextField)({
    '& .css-9ddj71-MuiInputBase-root-MuiOutlinedInput-root' : {
        fontFamily: 'Orbit !important',
      }
});


const PhotoList = () => {

    const [open, setOpen] = useState<any>(false);
    const [data, setData] = useState<any>([]);
    const [uploadFile, setUploadFile] = useState<any>('');
    const [userId, setUserId] = useState<any>('');


    useEffect(() =>{
        setUserId(localStorage.getItem("userId"));
    }, []);


    const getData = async () => {
        axios.get('/photo/list')
        .then( payload => {
            if(payload.data){ 
                setData(payload.data);
            }
        })
        .catch(e => toast.error("데이터를 불러올 수  없습니다."));
    }

    useEffect(() => {
        getData();
    }, [open]);

    const likePhoto = async (req: any) => {
        
        await axios.get("/photo/like/"  + req)
        .then(
            payload => {
                if(payload.status === 200) {
                    toast.success("응원이 전달되었습니다❤️");
                }
            }
        )
        .catch(e => toast.error("응원을 전달할 수 없습니다. 다시 시도해주세요"));
        
    }

    const onChangeImg = (e: React.ChangeEvent<HTMLInputElement>) => {
        e.preventDefault();
        
        if(e.target.files){
          const uploadFile = e.target.files[0]
          setUploadFile(uploadFile);
        }
      }


    const uploadImage = async () => {
        if(!uploadFile) toast.error("선택된 파일이 없습니다. 이미지를 업로드해주세요");

        const formData = new FormData();

        formData.append("file", uploadFile);


        await axios({
            method: 'post',
            url: '/photo/upload/' + userId,
            data: formData,
            headers: {
                'Content-Type': 'multipart/form-data',
            }
        })
        .then(payload => {

            if(payload.status === 200) {
                toast.success("사진이 업로드 되었습니다.");
                setOpen(!open);
            }
        }
            )
        .catch( e => {
            toast.error("업로드 할 수 없습니다. 다시 시도해주세요");
    });
    }



    return <div className="main_contents">
    <div className="meeting-area">
        <div className="fix-text-area">
            <h1 className="color-darkgray">오늘 플로깅에 참여한 분들의 인증샷이에요</h1>
            <h3 className="color_grey">다른 사용자들의 줍깅을 응원해주세요, 무한으로 응원할 수도 있어요</h3>
        </div>
        <div className="add-meeting">
            <h4 className="color-darkgray">인증샷 올리기</h4>
            <AddCircleIcon sx={{ width: '2vw', height: '4vh', cursor: 'pointer', color: green[500]}}
                onClick = {() => setOpen(!open)}
            />
        </div>
        <div className="info-unit-meeting h50vh dis-grid over">
                {data?.map(
                    (unit: any, idx: any) => (
                <div className="photo basic_sort" key={idx}>
                <img className="photo-size" src={"/upload_image/" + unit.storedFileName} alt="image"/>
                <CustomIcon onClick={() => likePhoto(unit.id)}/>
                </div>
                    )
                )}
            
        </div>
    </div>
    {
        open && 
        <>
        <div className="modal-back">
        <div className="modal">
        <div className="close-area">
            <CloseIcon sx={{cursor: 'pointer'}}  onClick={() => setOpen(false)} />
        </div>
        <div className="upload-area basic_sort">
            
            <UploadInput type='file' name="upload_image" onChange={onChangeImg}
            />
        </div>
        <div className="close-area">
            <AddCircleIcon
            onClick = {uploadImage}
            sx={{ width: '2vw', height: '4vh', cursor: 'pointer', color: green[500]}} />
        </div>
        </div>
    </div>
        </>
    
    }

</div>

}

export default PhotoList;

back-end

  • Controller
@RestController
@RequestMapping("/photo")
@Slf4j
@RequiredArgsConstructor
public class PhotoController {
    private final PhotoService photoService;

    @PostMapping("/upload/{userId}")
    public void uploadFile(@PathVariable("userId") String userId,
                                @RequestPart MultipartFile file) throws IOException {
        log.info("multipartFile={}", file);

        photoService.uploadFile(userId, file);
    }

    @GetMapping("/list")
    public List<PhotoDto> photoList(){
        return photoService.list();
    }

    @DeleteMapping("/delete/{photoNo}")
    public void deletePhoto(@PathVariable("photoNo") Long photoNo,
                            @RequestParam("userId") String userId) {
        photoService.delete(photoNo, userId);
    }

    @GetMapping("/like/{photoNo}")
    public void likePhoto(@PathVariable("photoNo") Long photoNo){
        photoService.like(photoNo);
    }
  • Service
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
public class PhotoService {

    private final PhotoListRepository photoListRepository;

    private final UserRepository userRepository;

    private final String fileDir = "내가 지정한 파일 저장소 위치";

    @Transactional
    public void uploadFile(String userId, MultipartFile file){

        User findUser = userRepository.findByUserStrId(userId);

        if(findUser == null ) throw new UserNotFoundException("유저 정보가 존재하지 않습니다");
        if(file.isEmpty()) throw new IllegalArgumentException("파일을 등록하지 않았습니다");


        String newFileName = createStoreFileName(file.getOriginalFilename());

        try{
            Files.write(Path.of(fileDir + newFileName), file.getBytes());
        }catch(Exception e){
            e.printStackTrace();
        }

        PhotoList savePhoto = new PhotoList
                (findUser,
                 newFileName,
                        fileDir + file.getOriginalFilename());
        photoListRepository.save(savePhoto);

    }

    public List<PhotoDto> list() {
        return photoListRepository.photoList().stream().map(
                photo -> new PhotoDto(
                        photo.getId(), photo.getUser().getUserId(),
                        photo.getImage(),
                        photo.getStoredFilename(),
                        photo.getLikes(),
                        photo.getUploadDate()
                )
        ).collect(Collectors.toList());
    }

    @Transactional
    public void delete(Long photoNo, String userId) {

        PhotoList photo = photoListRepository.findById(photoNo).orElseThrow(IllegalArgumentException::new);

        User user = userRepository.findByUserStrId(userId);

        if(user.getId() != photo.getUser().getId()) throw new IllegalArgumentException();

        photoListRepository.delete(photo);

    }

    @Transactional
    public void like(Long photoNo) {

        photoListRepository.findById(photoNo).orElseThrow(IllegalArgumentException :: new);

        photoListRepository.addCount(photoNo);

    }

    public Long mainCount() {
        return photoListRepository.mainCount();
    }


    public List<PhotoDto> userPhotoList(String userId) {

        User findUser = userRepository.findByUserStrId(userId);

        if(findUser == null) {
            throw  new UserNotFoundException("유저 정보를 찾을 수 없습니다.");
        }

        return photoListRepository.userPhotoList(findUser.getId());
    }

    private String createStoreFileName(String originalFileName) {
        String uuid = UUID.randomUUID().toString();
        String ext = extractExt(originalFileName);
        return uuid + "." + ext;
    }

    private String extractExt(String fileName) {
        int index = fileName.lastIndexOf(".");
        return fileName.substring(index +1);
    }

    public Long myPloggingCount(String userId) {

        User findUser = userRepository.findByUserStrId(userId);

        if(findUser == null) {
            throw  new UserNotFoundException("유저 정보를 찾을 수 없습니다.");
        }

        return photoListRepository.myPloggingCount(findUser.getId());
    }
}
  • Repository
public interface PhotoListRepository extends JpaRepository<PhotoList, Long>, PhotoCustomRepository {
}
public interface PhotoCustomRepository {

    void addCount(Long photoNo);

    Long mainCount();

    List<PhotoList> photoList();

    List<PhotoDto> userPhotoList(Long userNo);

    Long myPloggingCount(Long id);
}
@RequiredArgsConstructor
public class PhotoCustomRepositoryImpl implements PhotoCustomRepository{

    private final JPAQueryFactory queryFactory;

    @Override
    public void addCount(Long photoNo) {
        queryFactory
                .update(photoList)
                .set(photoList.likes ,photoList.likes.add(1)).where(photoList.id.eq(photoNo))
                .execute();
    }

    public Long mainCount() {
        DateTemplate<String> findData = Expressions.dateTemplate(
                String.class,
                "DATE_FORMAT({0}, {1})",
                photoList.uploadDate,
                ConstantImpl.create("%Y-%m-%d"));

        return queryFactory
                .selectFrom(photoList)
                .where(
                      findData.eq(Expressions.currentDate().stringValue())
                        )
                .fetchCount();
    }

    @Override
    public Long myPloggingCount(Long id) {
        return queryFactory.selectFrom(photoList).where(photoList.user.id.eq(id)).fetchCount();
    }

    @Override
    public List<PhotoList> photoList() {
        return queryFactory
                .selectFrom(photoList)
                .orderBy(photoList.uploadDate.desc())
                .fetch();
    }

    @Override
    public List<PhotoDto> userPhotoList(Long userNo) {
        List<PhotoList> data = queryFactory
                .selectFrom(photoList)
                .orderBy(photoList.uploadDate.desc())
                .where(photoList.user.id.eq(userNo))
                .fetch();

        return data.stream().map(
                photo -> new PhotoDto(
                        photo.getId(), photo.getUser().getUserId(),
                        photo.getImage(),
                        photo.getStoredFilename(),
                        photo.getLikes(),
                        photo.getUploadDate()
                )
        ).toList();
    }
}

Postman






profile
배우고 활용하는 것을 즐기는 개발자, 한지연입니다!

0개의 댓글