Item
은 ItemImg
를 여러개 가지는 1:N
구조를 갖고있다
다음과 같은 로직을 구성하는데 오류가 발생했다
- 카테고리에 해당하는
Item
목록List<Item>
조회하기- 조회된
Item
의ino
를List<Long>
형태로 생성- 생성된
List<Long>
으로ItemImg
조회
(해당하는 물품의 물품이미지 조회)- 3에서 조회된
ItemImg
오름차순으로 조회후 0번째에 해당하는iimageno
를 가져와imgurl
생성하기- 1의
List<Item>
을 불러와 Imageurl 넣어주기setImageurl
@GetMapping(value = "/selectitem.json")
public Map<String, Object> selectItemGET(
HttpServletRequest request,
@RequestParam(name = "page", defaultValue = "1") int page,
@RequestParam(name = "icateno", defaultValue = "1") Long icateno) {
Map<String, Object> map = new HashMap<>();
try {
// 페이지네이션 설정(0부터, 1페이지에 출력될 개수)
PageRequest pageRequest = PageRequest.of(page - 1, 12);
// 카테고리에 해당하는 아이템 가져오기 => 최신 등록순 정렬 + 페이지네이션
List<Item> itemList = ItemRepository.findByItemcateIcatenoOrderByRegdateDesc(icateno, pageRequest);
// ino를 long타입의 list로 만듬
List<Long> inoList = new ArrayList<>();
for (int i = 0; i < itemList.size(); i++) {
inoList.add(itemList.get(i).getIno());
}
for (int i = 0; i < inoList.size(); i++) {
// 조회된 물품에 해당하는 이미지
List<ItemImg> itemImg = ItemImgRepository.findByItem_inoOrderByIimagenoAsc(inoList.get(i));
if (itemImg.size() != 0) { // 이미지가 있는경우
System.out.println("0번째 itemimage");
System.out.println(itemImg.get(0));
// Imageurl 생성
String setImageurl = request.getContextPath()
+ "/api/item/image?ino=" + itemImg.get(0).getIimageno();
// i번째 itemList에 Imageurl 넣어주기
itemList.get(i).setImageurl(setImageurl);
} else { // 이미지가 없는경우
ItemDTO itemDTO = new ItemDTO();
itemDTO.setIno(itemList.get(i).getIno());
itemDTO.setName(itemList.get(i).getName());
itemDTO.setPrice(itemList.get(i).getPrice());
itemDTO.setRegdate(itemList.get(i).getRegdate());
itemDtolist.add(itemDTO);
}
}
map.put("status", 200);
map.put("itemList", itemList);
} catch (Exception e) {
map.put("status", -1);
map.put("result", e.getMessage());
}
return map;
}
생성한
Imageurl
를 넣어줄때 조회된List<Item>
를 다시 가져와 사용하지 않고
ItemDTO
를 새로 생성하여 필요한 컬럼만 담아List<ItemDTO>
형태로 반환해주었다
@GetMapping(value = "/selectitem.json")
public Map<String, Object> selectItemGET(
HttpServletRequest request,
@RequestParam(name = "page", defaultValue = "1") int page,
@RequestParam(name = "icateno", defaultValue = "1") Long icateno) {
Map<String, Object> map = new HashMap<>();
try {
// 페이지네이션 설정(0부터, 1페이지에 출력될 개수)
PageRequest pageRequest = PageRequest.of(page - 1, 12);
// 카테고리에 해당하는 아이템 가져오기 => 최신 등록순 정렬 + 페이지네이션
List<Item> itemList = ItemRepository.findByItemcateIcatenoOrderByRegdateDesc(icateno, pageRequest);
System.out.println("========================물품목록itemList==================");
System.out.println(itemList);
// ino를 long타입의 list로 만듬
List<Long> inoList = new ArrayList<>();
for (int i = 0; i < itemList.size(); i++) {
inoList.add(itemList.get(i).getIno());
}
System.out.println("========================물품목록itemList==================");
System.out.println(inoList);
List<ItemDTO> itemDtolist = new ArrayList<>();
for (int i = 0; i < inoList.size(); i++) {
System.out.println("*******inoList.get(i)******");
System.out.println(inoList.get(i));
// 조회된 물품에 해당하는 이미지
List<ItemImg> itemImg = ItemImgRepository.findByItem_inoOrderByIimagenoAsc(inoList.get(i));
System.out.println("*************itemImg.size()**********");
System.out.println(itemImg.size());
if (itemImg.size() != 0) { // 이미지가 있는경우
System.out.println("0번째 itemimage");
System.out.println(itemImg.get(0));
// itemList.get(i).getImageurl() = request.getContextPath() +
// "/api/item/image?ino=" + obj.getIimageno();
// Imageurl 생성
String Imageurl = request.getContextPath()
+ "/api/item/image?ino=" + itemImg.get(0).getIimageno();
//DTO 만들어서 넣어주기
ItemDTO itemDTO = new ItemDTO();
itemDTO.setIno(itemList.get(i).getIno());
itemDTO.setName(itemList.get(i).getName());
itemDTO.setPrice(itemList.get(i).getPrice());
itemDTO.setRegdate(itemList.get(i).getRegdate());
itemDTO.setImageurl(Imageurl);
itemDtolist.add(itemDTO);
} else {
ItemDTO itemDTO = new ItemDTO();
itemDTO.setIno(itemList.get(i).getIno());
itemDTO.setName(itemList.get(i).getName());
itemDTO.setPrice(itemList.get(i).getPrice());
itemDTO.setRegdate(itemList.get(i).getRegdate());
itemDtolist.add(itemDTO);
}
}
map.put("status", 200);
// map.put("itemList", itemList);
map.put("itemDtolist", itemDtolist);
} catch (Exception e) {
map.put("status", -1);
map.put("result", e.getMessage());
}
return map;
}
@JsonIgnore
: 이 어노테이션을 붙이면 json 데이터에 해당 프로퍼티는 null로 들어가게 된다.
즉, 데이터에 아예 포함이 안되게 된다.
@JsonManagedReference
와 @JsonBackReference
: 이 두개의 어노테이션이야 말로 순환참조를 방어하기 위한 Annotation이다.
부모 클래스에 @JsonManagedReference
를, 자식 클래스측 에 @JsonBackReference
어노테이션을 추가해주면 된다.
DTO 사용
: 위와 같은 상황이 발생하게 된 주 원인은 양방향 매핑이기도 하지만,
더 정확하게는 entity 자체를 response로 리턴했기 때문에 순환참조가 발생하는 것이다
entity 자체를 return하지 않고, dto 객체를 만들어 필요한 데이터만 옮겨 담아 client로 리턴하면
순환참조와 관련된 문제는 애초에 방어할 수 있다.
맵핑 재설정
: 사람마다 다르지만 양방향 맵핑이 꼭 필요한지 다시 한번 생각해볼 필요가 있다.
만약 양쪽에서 접근할 필요가 없다면 단방향 맵핑을 하면 자연스레 순환참조가 해결된다.