티스토리 뷰
SpringBoot + MariaDB 5-3 프로필페이지 유저,사진 가져오기(양방향 매핑) Lazy와 Eager의 차이, 사진개수 표현
svdjcuwg4638 2023. 6. 12. 19:43프로필페이지 사진 불러오기
UserController
private final UserService userService;
@GetMapping("/user/{id}")
public String profile(@PathVariable int id,Model model) {
User userEntity = userService.회원프로필(id);
model.addAttribute("user",userEntity);
return "user/profile";
}
파라미터로 받아온 id를 이용하여 서비스에 넘겨 그 id에 해당하는 유저의 정보를 가져올것이다 프로필페이지에는 유저의 정보와 이미지가 필요하니 유저의 정보를 받아오는것은 당연하다.
UserService
public void 회원프로필(int userId) {
// select * from image where userid = :userId;
User userEntity = userRepository.findById(userId).orElseThrow(()->{
throw new CustomException("해당 프로필 페이지는 없는 페이지입니다.");
});
return userEntity;
}
sql명령문으로 한다면 위에 주석과 같이 명령하면 그유저에 대한 사진 조회가 가능하다 알아만 두고 우선 예외처리부터 해보자.
예외 생성
orElseThrow로 못찾았을시 CustomException을 발생시키고 메시지 한개만 전달
handler ex에 새로운 예외 클래스 추가
package com.cos.photogramstart.handler.ex;
public class CustomException extends RuntimeException{
// 시리얼번호는 객체를 구분할때 사용된다
private static final long serialVersionUID = 1L;
public CustomException(String massage) {
super(massage); // 메세지는 부모에게 넘김(Exception)
}
}
ControllerExceptionHandler에 등록
@ExceptionHandler(CustomException.class)
public String exception(CustomException e) {
return Script.back(e.getMessage());
}
없는 유저의 id로 해당 경로에 접하게 되면 alert창으로 우리가 정의한 메시지가 잘 나온다면 성공
하지만 위에서의 토대로 유저의 id만 가져온다면 프로필에 이름과 프로필 사진은 잘 나오겠지만 그사람이 등록한 사진이나 구독 정보를 가져올 수 가없다.
그렇기때문에 양방향 매핑이란걸 해야하는데 양방향 매핑에 대해서 알아보자
위와같이 image만 데이터를 받아왔다면 image만 보여줄 수있고 위 프로필은 데이터를 가져오지못한다 그래서 양방향 매핑을 이용해서 user, image, subscribe 3가지의 데이터를 묶어서 가져와야한다
select를 하여 user를 조회하면 영속성 컨텍스트에 그 유저의 정보가 저장되게 된다
user의 image도 같이 묶어서 영속성 컨텍스트에 저장을한다
영속화
밑과같이 User에 필드추가
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Image> images;
OneToMany
User의 클래스 그러니 User의 기준으로 생각을 해야한다 한명의 유저가 여러 이미지 소유가 가능하니 OneToMany가 된다.
mappedBy의 뜻은
나는 연관관계의 주인이 아니다. 그러므로 테이블에 만들지마
User를 Select할 때 해당 User의 id로 등록된 image들을 다 가져와
왼쪽은 Image클래스의 User필드인데 멤버필드의 user는 image테이블에 userId로 저장이 되어있다 (id만 저장이되어있음) 그래서 id와 일치하는 모든 사진을 가져올 수 있게된다.
fetch의 Lazy와 Eager의 차이
Lazy
User를 Select할 때 해당 User id로 등록된 image들을 가져오지마- 대신 getImages()함수의 image들이 호출될 때 가져와!!
Lazy 실행문
Hibernate:
select
user0_.id as id1_2_0_, user0_.bio as bio2_2_0_, user0_.createDate as createda3_2_0_,
user0_.email as email4_2_0_, user0_.gender as gender5_2_0_, user0_.name as name6_2_0_,
user0_.password as password7_2_0_, user0_.phone as phone8_2_0_, user0_.profileimageUrl as profilei9_2_0_,
user0_.role as role10_2_0_, user0_.username as usernam11_2_0_, user0_.website as website12_2_0_
from User user0_ where user0_.id=?
Hibernate:
select
images0_.userId as userid5_0_0_, images0_.id as id1_0_0_, images0_.id as id1_0_1_,
images0_.caption as caption2_0_1_, images0_.createDate as createda3_0_1_, images0_.postImageUrl as postimag4_0_1_,
images0_.userId as userid5_0_1_
from Image images0_ where images0_.userId=?
각각 따로 select가 실행되어 데이터를 가져오는 모습이다.
Eager
User를 Select할 때 해당 User id로 등록된 image들을 전부 Join해서 가져와
Eager 실행문
Hibernate:
select
user0_.id as id1_2_0_, user0_.bio as bio2_2_0_, user0_.createDate as createda3_2_0_,
user0_.email as email4_2_0_, user0_.gender as gender5_2_0_, user0_.name as name6_2_0_,
user0_.password as password7_2_0_, user0_.phone as phone8_2_0_, user0_.profileimageUrl as profilei9_2_0_,
user0_.role as role10_2_0_, user0_.username as usernam11_2_0_, user0_.website as website12_2_0_,
images1_.userId as userid5_0_1_, images1_.id as id1_0_1_, images1_.id as id1_0_2_,
images1_.caption as caption2_0_2_, images1_.createDate as createda3_0_2_, images1_.postImageUrl as postimag4_0_2_,
images1_.userId as userid5_0_2_
from User user0_ left outer join Image
images1_ on user0_.id=images1_.userId where user0_.id=?
위와같이 left join을 하여 명령문이 실행된 모습
(작성 안 할시 Lazy가 기본값이 됩니다.)
이미지 언제 들어올까?
public User 회원프로필(int userId) {
// select * from image where userid = :userId;
User userEntity = userRepository.findById(userId).orElseThrow(()->{
throw new CustomException("해당 프로필 페이지는 없는 페이지입니다.");
});
userEntity.getImages().get(0);
return userEntity;
}
위에 양방향 매핑 그림으로 보면 findById를 이용하여 아이디를 조회하게된다 이때 영속화가 되어 영속화 컨텍스트에 유저가 저장이되게됨
userEntity.getImages().get(0)를 하게되면 그때 image가 들어가게 된다.
이미지 렌더링
controller에서 model에 user라고 entity를 attribute에 저장하여 보내어 밑과 같이 사용하였다
근데 사진이 불러와 지지 않는다 왜냐하면 밑과같이 사진이름만있고 경로가 존재하지 않기때문이다.
경로를 붙여주는 작업을 해보자.
config패키지에 WebMvcConfig클래스 생성
package com.cos.photogramstart.config;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer{ // web 설정 파일
@Value("${file.path}")
private String uploadFolder;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
WebMvcConfigurer.super.addResourceHandlers(registry);
// C:/study/springboot/workspace/springbootwork/upload/
registry
.addResourceHandler("/upload/**") // jsp페이지에서/upload/** 이런 주소패턴이 나오면 발동
.addResourceLocations("file:///"+uploadFolder)
.setCachePeriod(60 * 10 * 6)
// 60초 10분 6 =1시간
.resourceChain(true)
.addResolver(new PathResourceResolver()); 등록해주는 함수
}
}
빈공간에 자동완성을 눌러 addresourcehandlers를 자동완성하고 안의 내용은 위와같이 채워준다
setCachpreiod와 resourceChain은 별로 신경쓰지 않아도 된다 다음에 또 쓸일이있다면 복사해서
addResourceHandler과 addResourceLocations만 신경써주면 다른대에 적용하는데도 어려움이 없을것이다.
이제 /upload/등록한것을 적용하면 사진이 잘 보이는것을 확인할 수 있다.
사진개수 보여주기
사진의 갯수를 보여주는 방법은 간단하다 우리가 images는 리스트이다 리스트의 사이즈만 el태그로 불러온다면 끝이다.
<div class="subscribe">
<ul>
<li><a href=""> 게시물<span>${user.images.size() }</span>
</a></li>
<li><a href="javascript:subscribeInfoModalOpen();"> 구독정보<span>2</span>
</a></li>
</ul>
</div>
하지만 사진 한개를 더 등록해보니 오류가 발생하였다 이 오류 처리는 다음글에서 알아보자.
'Spring Boot' 카테고리의 다른 글
SpringBoot + MariaDB 6-2 구독 구독정보 (스칼라쿼리) (0) | 2023.06.13 |
---|---|
SpringBoot + MariaDB 5-4 프로필페이지 open in view개념(Lazy, EAGER ) @Transactional을 걸어줘야하는 이유(select문에도) (0) | 2023.06.12 |
SpringBoot + MariaDB 5-2 프로필페이지 DB에업로드 및 유효성 검사 (1) | 2023.06.12 |
SpringBoot + MariaDB 5-1 프로필페이지 모델만들고 서버에 업로드하기 (외부에 uploadFile 저장하는 이유) (0) | 2023.06.12 |
SpringBoot + MariaDB 4-4 구독기능만들기 예외처리하기 (0) | 2023.06.12 |