728x90
리팩토링 하기전 소스코드
UserApiController
@PutMapping("/user/{id}")
public CMResDto<?> update(@PathVariable long id,
@Valid UserUpdateDto userUpdateDto,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails
){
User userEntity = userService.memberUpdate(id, userUpdateDto);
return new CMResDto<>(1,"회원수정완료",userEntity);// 응답시에 유저 엔티티의 모든 getter 함수가 호출되고 JSON으로 파싱하여 응답한다.
}
UserService
@Transactional
public User memberUpdate(long id, UserUpdateDto userUpdateDto,@AuthenticationPrincipal PrincipalDetails principalDetails){
//1 영속화
User userEntity=userRepository.findById(id).orElseThrow(()->{return new CustomVaildationApiException("찾을 수 없는 Id입니다");});
//2.영속화된 오브젝트를 수정 - 더티체킹 (업데이트완료)
userEntity.updateUser(
bCryptPasswordEncoder.encode(userUpdateDto.getPassword()),
userUpdateDto.getName(),
userUpdateDto.getWebsite(),
userUpdateDto.getBio(),
userUpdateDto.getPhone(),
userUpdateDto.getGender());
//3 principal 세션변경
principalDetails.setUser(userEntity);
return userEntity;
}
문제점: Entity의 모든 스팩이 노출이 되므로 비밀번호 등 필요없는 정보도 노출이 됨.
리팩토링 후 소스코드 (Dto를 별도로 생성해서 Service로직에서 Dto 반환)
UserUpdateDtoRes.java
package com.cos.photogramstart.web.dto.user;
import com.cos.photogramstart.domain.user.User;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Data
public class UserUpdateDtoRes {
private String name;
private String username;
private String website;
private String bio;
private String email;
private String phone;
private String gender;
public UserUpdateDtoRes(User user) {
this.name = user.getName();
this.username = user.getUsername();
this.website = user.getWebsite();
this.bio = user.getBio();
this.email = user.getEmail();
this.phone = user.getPhone();
this.gender = user.getGender();
}
}
UserApiController
@PutMapping("/user/{id}")
public CMResDto<?> update(@PathVariable long id,
@Valid UserUpdateDto userUpdateDto,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails
){
UserUpdateDtoRes userUpdateDtoRes = userService.memberUpdate(id, userUpdateDto, principalDetails);
return new CMResDto<>(1,"회원수정완료",userUpdateDtoRes);// 응답시에 유저 엔티티의 모든 getter 함수가 호출되고 JSON으로 파싱하여 응답한다.
}
UserService
@Transactional
public UserUpdateDtoRes memberUpdate(long id, UserUpdateDto userUpdateDto,@AuthenticationPrincipal PrincipalDetails principalDetails){
//1 영속화
User userEntity=userRepository.findById(id).orElseThrow(()->{return new CustomVaildationApiException("찾을 수 없는 Id입니다");});
//2.영속화된 오브젝트를 수정 - 더티체킹 (업데이트완료)
userEntity.updateUser(
bCryptPasswordEncoder.encode(userUpdateDto.getPassword()),
userUpdateDto.getName(),
userUpdateDto.getWebsite(),
userUpdateDto.getBio(),
userUpdateDto.getPhone(),
userUpdateDto.getGender());
//3 principal 세션변경
principalDetails.setUser(userEntity);
//4. dto에 Entity데이터 담아주기
UserUpdateDtoRes userUpdateDtoRes=new UserUpdateDtoRes(userEntity);
return userUpdateDtoRes;
}
공통응답DTO 클래스를 만들어서 code 및 Message , 데이터까지 넘겨주는 형식으로 진행하였습니다.
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CMResDto<T>{
private int code; // 1(성공),-1(실패)
private String message;
private T data;
}
RestApiController 리팩토링 완료. AOP 처리까지해서 전처리과정을 하나의 클래스로 처리
CommentApiController
package com.cos.photogramstart.web.api;
import com.cos.photogramstart.config.auth.PrincipalDetails;
import com.cos.photogramstart.domain.Comment.Comment;
import com.cos.photogramstart.handler.ex.CustomVaildationApiException;
import com.cos.photogramstart.handler.ex.CustomVaildationException;
import com.cos.photogramstart.service.CommentService;
import com.cos.photogramstart.web.api.dto.CommentResDto;
import com.cos.photogramstart.web.dto.CMResDto;
import com.cos.photogramstart.web.dto.comment.CommentDto;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequiredArgsConstructor
public class CommentApiController {
private final CommentService commentService;
@PostMapping("/api/comment")
public ResponseEntity<?> commentSave(@Valid @RequestBody CommentDto commentDto,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails){
CommentResDto commentResDto = commentService.applywrite(commentDto.getContent(), commentDto.getImageId(), principalDetails.getUser().getId());//content,imageId,userId
return new ResponseEntity<>(new CMResDto<>(1,"댓글쓰기성공",commentResDto), HttpStatus.CREATED);
}
@DeleteMapping("/api/comment/{id}")
public ResponseEntity<?> commentDelete(@PathVariable long id){
commentService.applyDelete(id);
return new ResponseEntity<>(new CMResDto<>(1,"삭제성공",null),HttpStatus.OK);
}
}
ImageApiController
package com.cos.photogramstart.web.api;
import com.cos.photogramstart.config.auth.PrincipalDetails;
import com.cos.photogramstart.domain.image.Image;
import com.cos.photogramstart.service.ImageService;
import com.cos.photogramstart.service.LikesService;
import com.cos.photogramstart.web.api.dto.ImageResDto;
import com.cos.photogramstart.web.dto.CMResDto;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequiredArgsConstructor
public class ImageApiController {
private final ImageService imageService;
private final LikesService likesServcie;
@GetMapping("/api/image")
public ResponseEntity<?> imageStory(@AuthenticationPrincipal PrincipalDetails principalDetails,
@RequestParam(value="offset",defaultValue = "0") int offset,
@RequestParam(value="limit",defaultValue = "100") int limit,
@PageableDefault(size=3,sort="id",direction = Sort.Direction.DESC)Pageable pageable){
List<Image> images = imageService.imageStory(principalDetails.getUser().getId(),offset,limit);
List<ImageResDto> collect = images.stream().map(i -> new ImageResDto(i)).collect(Collectors.toList());
return new ResponseEntity<>(new CMResDto<>(1,"성공",collect),HttpStatus.OK);
}
@PostMapping("/api/image/{imageId}/likes")
public ResponseEntity<?> likes(@AuthenticationPrincipal PrincipalDetails principalDetails,
@PathVariable long imageId){
likesServcie.likes(imageId,principalDetails.getUser().getId());
return new ResponseEntity<>(new CMResDto<>(1,"좋아요성공",null), HttpStatus.CREATED);
}
@DeleteMapping("/api/image/{imageId}/likes")
public ResponseEntity<?> unlikes(@AuthenticationPrincipal PrincipalDetails principalDetails,
@PathVariable long imageId){
likesServcie.cancellikes(imageId,principalDetails.getUser().getId());
return new ResponseEntity<>(new CMResDto<>(1,"좋아요취소성공",null), HttpStatus.OK);
}
}
SubscribeApiController
package com.cos.photogramstart.web.api;
import com.cos.photogramstart.config.auth.PrincipalDetails;
import com.cos.photogramstart.domain.subscribe.SubscribeRepository;
import com.cos.photogramstart.service.SubscribeService;
import com.cos.photogramstart.web.dto.CMResDto;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
public class SubscribeApiController {
private final SubscribeService subscribeService;
@PostMapping("/api/subscribe/{toUserId}")
public ResponseEntity<?> subscribe(@PathVariable long toUserId, @AuthenticationPrincipal PrincipalDetails principalDetails) {
subscribeService.subscribe(principalDetails.getUser().getId(), toUserId);
return new ResponseEntity<>(new CMResDto<>(1, "구독하기 성공!", null), HttpStatus.OK);
}
@DeleteMapping("/api/subscribe/{toUserId}")
public ResponseEntity<?> unsubscribe(@PathVariable long toUserId, @AuthenticationPrincipal PrincipalDetails principalDetails) {
subscribeService.unsubscribe(principalDetails.getUser().getId(), toUserId);
return new ResponseEntity<>(new CMResDto<>(1, "구독취소하기 성공!", null), HttpStatus.OK);
}
}
UserApiController
package com.cos.photogramstart.web.api;
import com.cos.photogramstart.config.auth.PrincipalDetails;
import com.cos.photogramstart.domain.subscribe.Subscribe;
import com.cos.photogramstart.domain.subscribe.SubscribeRepository;
import com.cos.photogramstart.domain.user.User;
import com.cos.photogramstart.handler.ex.CustomVaildationApiException;
import com.cos.photogramstart.handler.ex.CustomVaildationException;
import com.cos.photogramstart.service.SubscribeService;
import com.cos.photogramstart.service.UserService;
import com.cos.photogramstart.web.dto.CMResDto;
import com.cos.photogramstart.web.dto.subscribe.subscribeResponseDto;
import com.cos.photogramstart.web.dto.user.UserUpdateDto;
import com.cos.photogramstart.web.dto.user.UserUpdateDtoRes;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
@RestController
public class UserApiController {
private final UserService userService;
private final SubscribeService subscribeService;
@PostMapping("/api/user/{principalId}/profileImageUrl")
public ResponseEntity<?> profileImageUrlUpdate(@PathVariable long principalId,
MultipartFile profileImageFile,
@AuthenticationPrincipal PrincipalDetails principalDetails){
userService.profileimageupdate(principalId,profileImageFile,principalDetails);
return new ResponseEntity<>(new CMResDto<>(1,"프로필 사진변경 성공",null),HttpStatus.OK);
}
@GetMapping("/api/user/{pageUserId}/subscribe")
public ResponseEntity<?> subscribeList(@PathVariable long pageUserId,@AuthenticationPrincipal PrincipalDetails principalDetails){
List<subscribeResponseDto> subscribeResponseDtos=subscribeService.subscribeList(principalDetails.getUser().getId(),pageUserId);
return new ResponseEntity<>(new CMResDto<>(1,"구독자 정보 리스트 가져오기 성공",subscribeResponseDtos), HttpStatus.OK);
}
@PutMapping("/user/{id}")
public CMResDto<?> update(@PathVariable long id,
@Valid UserUpdateDto userUpdateDto,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails
){
UserUpdateDtoRes userUpdateDtoRes = userService.memberUpdate(id, userUpdateDto, principalDetails);
return new CMResDto<>(1,"회원수정완료",userUpdateDtoRes);// 응답시에 유저 엔티티의 모든 getter 함수가 호출되고 JSON으로 파싱하여 응답한다.
}
}
핵심결론: Controller는 호출하고 DTO로 반환시켜줘야함. Open in view를 꺼놓고 DTO를 서비스 로직에서
반환시켜놓고 Controller단에서는 호출 및 반환만 잘해주면 된다.
728x90
'photogram 리팩토링' 카테고리의 다른 글
photogram 스크롤시 페이징 처리 (0) | 2023.02.19 |
---|---|
photogram 리팩토링 일기 (0) | 2023.02.17 |