ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프로필 페이지 4
    Spring Boot/프로필 페이지 만들기 2021. 12. 16. 17:49

     

     

    사진 업로드 사이트에서 업로드 하면, 프로필 화면에 그 사진이 나타나도록 하겠다.

     

     

     

    <프로필 화면> - profile.jsp 파일

     

    UserController.java 파일에서 

     

    profil 메서드가 

    return "user/profile"; 할 때

    Model 객체에 이미지들을 담아서, 같이 리턴해주면 된다.

     

    요청 주소를 /user/{id} 로 해서

    /user/1 이런식으로 오면, 1번 유저의 프로필 화면이(profile.jsp)

    /user/2 이런 식으로 오면, 2번 유저의 프로필 화면(profile.jsp ) 이 나오도록 하겠다.

     

     

    <UserController.java> 파일

    	@GetMapping("/user/{id}")
    	public String profile(@PathVariable int id, Model model) {
    		User userEntity = userService.회원프로필(id);
    		model.addAttribute("user", userEntity);
    		return "user/profile";
    	}

     

     

     

    --------------------------

     

    UserController.java 파일에서 UserService.java 의 회원프로필 메서드를 요청해서 프로필 정보를 가져온다.

     

    <UserService.java > 파일

     

     

    	
    	@Transactional
    	public User 회원프로필(int userId) {
    	
    		User userEntity = userRepository.findById(userId).orElseThrow(()-> {
    			throw new CustomException("해당 프로필 페이지는 없는 페이지입니다.");
    		});
    		return userEntity;
    	}

    만약 없는 사용자의 프로필 페이지를 요청하면, 에러메세지를 보여주도록 처리

    3번 사용자가 데이터베이스에 없는데,

    3번 사용자의 프로필 화면을 요청 ( /user/3 이런식으로 주소 요청)하면 아래와 같은 에러메세지 나옴

     

     

     

    하지만, /user/1 이런 식으로

    데이터베이스에 있는 1번 유저 번호로 주소를 보내면 

    프로필 화면으로 잘 이동한다.

     

     

    이러한 에러 처리 위해 CustomException.java 파일 만듦

     

     

    public class CustomException extends RuntimeException{
    
    	private static final long serialVersionUID = 1L;
    	
    	public CustomException(String message) {
    		super(message);
    	}
    	
    }

     

    ControllerExceptionHandler.java 파일에 CustomException을 낚아채도록 아래와 같이 만듦

    	@ExceptionHandler(CustomException.class)
    	public String exception(CustomException e) {
    		return Script.back(e.getMessage());
    	}

    즉, CustomException 이 요청되면, ControllerExceptionHandler.java 에 처리해준대로, 아래 코드가 실행되서 리턴됨

    	return Script.back(e.getMessage());

     

    ----------------------------------------------------------------------------------------------------------------

     

     

     

     

     

     

     

    그런데, 프로필 화면으로 이동 시, 업로드한 이미지(image 정보) 뿐만 아니라

    게시물 수, 프로필 사진 등 user 관련 여러 데이터, 구독 정보(subscribe 정보)를 같이 들고 가야 하므로,

     

     

    user 데이터를 데이터베이스로부터 select 해서 영속성 컨텍스트에 넣을 때,

    image 정보도 같이 가져올 수 있도록 양방향 매핑 사용

     

     

     

    기존에, Image.java 파일에, 업로드한 유저 정보도 같이 넣기 위해,

     

    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    @Entity
    public class Image {
    
    	
    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	private int id;
    	private String caption; 
    	private String postImageUrl; 
    	
    	@JoinColumn(name = "userId")
    	@ManyToOne(fetch = FetchType.EAGER) 
    	private User user; 
    	
    	private LocalDateTime createDate;
    	
    	@PrePersist
    	public void createDate() {
    		this.createDate = LocalDateTime.now();
    	}
    
    }

     

    이 처럼 user 변수도 같이 넣었다.

    User.java 파일에서는 원래 image 변수를 사용하지 않았는데, 양방향 매핑을 위해 image 변수 추가

     

     

    <User.java> 파일

     

     

    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    @Entity
    public class User {
    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY) 
    	private int id;
    	
    	@Column(length = 100,  unique = true) 
    	private String username; 
    	@Column(nullable = false)
    	private String password;
    	@Column(nullable = false)
    	private String name;
    	private String website; 
    	private String bio; 
    	@Column(nullable = false)
    	private String email;
    	private String phone;
    	private String gender;
    	private String role; 
    	private String profileImageUrl;
    	
    	@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    	private List<Image> images; 
    	
    	private LocalDateTime createDate;
    	
    	@PrePersist 
    	public void createDate() {
    		this.createDate = LocalDateTime.now();
    	}
    
    }

     

     

    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)

    <1> @OneToMany : 한 명의 유저는 여러 개의 이미지 만듦

    mappedBy = "user" : Image.java 파일에서 User 객체 변수 이름, 즉 user 로 아래와 같이 사용했는데, 이 값을 넣어줘야 함

    private User user;

    <2> mappedBy 뜻 :

    1) 나는 연관관계의 주인이 아니다. 그러니 테이블(데이터베이스)에 칼럼 만들지 마라.

    (특히, images 변수가 List 타입이다. 그런데 데이터베이스에는 collection 타입이 없어서 이를 만들 수 없다.)

     

    2) User 를 select 할 때 해당 User id 로 등록된 image 들을 다 가져와(그런데 이 때, 위에서 fetch 타입에 따라 다양한 결과)

     

    즉, 연관관계의 주인은, image 테이블의 user 변수임.

    private User user;

     

    <3> fetch = FetchType.LAZY

     

    타입 LAZY : User 를 select 할 때 해당 User id 로 등록된 image들을 가져오지마라. 단, getImages() 함수 image들이 호출될 때 가져오기

     

    타입 EAGER : User 를 select 할 때 해당 User id 로 등록된 image 들을 전부 join 해서 가져오기

     

     

    LAZY 와 EAGER 전략에 대해 살펴보겠다.

     

    1) LAZY 전략 

    UserService.java 에서 아래와 같이 user를 select 할 떄,  images를 가져오지 않음

    			User userEntity = userRepository.findById(userId).orElseThrow(()-> {
    			throw new CustomException("해당 프로필 페이지는 없는 페이지입니다.");

     

    즉, 이 UserService.java 코드는, 사용자가 /user/{id}로 요청할 때 실행되는 코드이므로,

     

    사이트에서 /user/1 이렇게 요청을 해보고 sts(이클립스) 콘솔창에서 보면

    데이터베이스 쿼리를 볼 수 있는데,

    이런 식으로 쿼리가 나타나면서 맨 마지막에 보면 

    이런식으로, user 테이블에서만 select 했음을 알 수 있다.

     

     

    2) EAGER 전략

    그런데 만약 아래와 같이 EAGER 전략으로 바꾼뒤 

    	@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
    	private List<Image> images;

     

    사이트에서 /user/1 이렇게 요청을 하면

     

    이런식으로, image와 user가 join 되서 같이 가져왔음을 알 수 있다.

     

     

    3) LAZY 전략

    그러면 이제 다시, LAZY 전략으로 바꾼 다음 언제 images 정보를 가져오는지 살펴보겠다.

    	@Transactional
    	public User 회원프로필(int userId) {
    	
    		User userEntity = userRepository.findById(userId).orElseThrow(()-> {
    			throw new CustomException("해당 프로필 페이지는 없는 페이지입니다.");
    		});
    		
    		System.out.println("================");
    		userEntity.getImages().get(0);
    		return userEntity;
    	}

     ============== 를 기준으로

    위에에서는 user 데이터를 데이터베이스로부터 불러오고

    아래에서는 user 데이터에 있는 image 데이터를 불러온다. 

     

    그러면 sts(이클립스) 콘솔창에서 보면 

     

    이런식으로 =======를 기준으로

    위에서는 user 데이터만 가져오고(LAZY 전략을 사용했기 때문에, getImages() 를 사용하지 않는 한, user 데이터를 select 하면 user 데이터만 가져옴)

     

    아래에서는 images 데이터를 가져온 것을 알 수 있다. (getImages() 를 사용했기 때문에, user 테이블과 양방향 매핑하고 있는 images 데이터도 가져옴)

     

     

    더보기

    위에 나타난 쿼리의 끝까지 따라가보면, ========= 윗 부분에서는 아래와 같이 user 테이블로부터 데이터를 가져오고

    =========== 아래에서는 아래와 같이 image 테이블로부터 데이터를 가지고 왔음을 알 수 있다.

     

     

     

    여기서 get(0) 을 한 이유는,

    첫번째 데이터까지 가져오라는 뜻.

    getImages() 만 하는 것은, 객체를 호출하는 거임.

     

     

    이처럼 양방향 매핑은,

    controller 의 Model 객체로 jsp 파일에 데이터 전달 시

    user 정보만 전달하더라도 image 정보까지 같이 전달할 수 있게 됨

     

    참고 자료 : 이지업 강의 사이트 "스프링부트 SNS프로젝트 - 포토그램 만들기"

    'Spring Boot > 프로필 페이지 만들기' 카테고리의 다른 글

    프로필 페이지 7 - @JsonIgnoreProperties  (0) 2021.12.18
    프로필 페이지 5  (0) 2021.12.16
    프로필 페이지 3  (0) 2021.12.15
    프로필 페이지 2  (0) 2021.12.15
    프로필 페이지 1  (0) 2021.12.14

    댓글

Designed by Tistory.