배움 __IL/TIL 1기

TIL : 74번째- 230322 [3-3-수]

Mo_bi!e 2023. 3. 22. 18:56

※ Keep in mind

 본 내용은 웹개발과정의 강의 중 내용을 복습을 위해서 메모한 것에 불과한 것입니다. 이러한 연유로 강의내용을 오인한 나머지 오기재 및 불기재가 있을 수 있으니 '참고'만 해주시길 바랍니다. 저의 경우에도 본 내용을 단순하 읽은 것이 결코 저의 것이라고 생각하지 않습니다. 본 내용은 복습를 위한 초기 내지 중간 과정에 불과한 것이고, 이후에 내용을 보충 후 인출 및 설명하기 과정이 있어야 비로소 복습의 단추가 어느정도 마무리 되어간다고 볼 수 있습니다.

 따라서 당초에 본 내용은 비공개였습니다. 그럼에도 불구하고 본 내용을 공개한 점은 함께 공부하는 동료들과 나눔을 바탕으로 배움과 성장의 공진화라는 소기의 목적을 달성에 어느정도 도움이 될수 있기 때문이라고 생각합니다.

I. 들어가며

1. 추천메뉴관련 detail.html

(1) rcmd_menu DB 설계

1) 

추천은 N:M관계였어 메뉴와 사용자 관계야

예컨데

내가 시험을 출제를 하는데 문제를 등록해! 시험 출제하는사람이 문제를 등록했는지를 포함할 필요가없어

내가 예약했고, 예약자만 주문이 가능하면 주문자를 적을 필요가 없어

4형식 문항에서 같은 사람이 하는거라면 따로 누가했는지 할필요없이, 다른행위자이면 행위자를 기록할 필요가 있다

 

즉 관리자가 메뉴를 처음에 등록할 때 추천메뉴도 같이 등록하는데, 메뉴를 등록하는자가 이미 충분히 있는데 메뉴추천도 누가했는지를 컬럼으로 남길 필요가 없다.

 

 

2)

같은 메뉴에 추천 두번 필요X

 

추천메뉴인데 포함되는것으로서 

 

대리키는 없애고 두개가 PK가 되는거야

(includ_id는 추천에 포함되기 때문에 include야)

 

특정 메뉴(menu_id) 에다가 추천메뉴(include_id -> id )를 하는거야!

 

3)

이거 외 다른속성은 없나? 추천날짜라던지, 추천이유라던지, 궁합도라던지

필요 따라서 추가가 가능해!

 

 

(2) view 와 view select 

1)

그런데 추천리스트는 이름과 이미지가 같이 나와야해!

목록으로 나오는것에서 반복적으로 가져오는 작업에서 view를 만들면 돼!

 

우선 join을 해보자

이렇게 붙여주면돼!

select rm.*, m.name, m.img
from rcmd_menu rm
    left join menu m on rm.id = m.id;

left join 은 outter left join 이다

[좌측 집합 + 교집합] 으로 볼 수있다

 

이 방법 외에도 innner join을 이용해도 무난히 가능하다

 

추천해주는 id와 그 id 의 name을 해야해!

 

이거를 view 로 만들어주자

create view rcmd_menu_view
as
select rm.*, m.name, m.img
from rcmd_menu rm
		left join menu m on rm.id = m.id;

view를 만들어준다.

select * from rcmd_menu_view;

이렇게 하면 view 출력 돼!

 

 

2)

만들어진 table에다가 entity 를 만들어주자 한편 기존 것을 활용하고 싶으면 extends를 하자

그런데 rcmd는 기존것이 없어서 아예 새로 만들어야해!

package kr.co.rland.web.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RcmdMenu {
	private int id;
	private int menuId;
		
}
package kr.co.rland.web.entity;

import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

// 엔티티란 DB에서 담을녀석이다 .


@Data
@NoArgsConstructor
@AllArgsConstructor
public class RcmdMenuView extends RcmdMenu{
	
	private String img;
	private String name;
	
}

상속받아서 이용하자

 

- 나의 경우 MySQL 로 먼저 체크안하고 해서 unit테스트에서 오류가 계속 발생했었다.

 

 

3)

repository 선언하자

 package kr.co.rland.web.repository;

import java.util.List;

//ibatis가 원래 이름이야!
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import kr.co.rland.web.entity.Menu;
import kr.co.rland.web.entity.MenuView;
import kr.co.rland.web.entity.RcmdMenu;
import kr.co.rland.web.entity.RcmdMenuView;

//이것을 구현한 구현체를 알아서 repo에 보내주는거야! 
@Mapper
public interface RcmdMenuRepository {
	
	List<RcmdMenuView> findViewAllByMenuId(int menuId);
	
	//추천에서는 몇개인지 알필요 없어
//	int count(
//			String query,
//			Integer categoryId,
//			Integer price
//			);
	
	//추천추가할수 있으니 넣기
	int insert(RcmdMenu rcmdmenu);
	
	//update 필요없어
//	int update(RcmdMenu rcmdmenu);
	void delete(long id);

}

Repositoy 에 대한 interface를 선언해주자

 

이 경우 몇개인지 알 필요가 없으니 count() 등은 제거해주고

update 비즈니스 로직은 실질적으로 update()가 아니라 delete()이기 때문에 update()를 제거한다

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.co.rland.web.repository.RcmdMenuRepository">
  
  <!-- 컬럼이름 매핑  -->
  	<resultMap id="RcmdMenuResultMap" type="RcmdMenu">
		  <!-- column은 sql에서 오는 컬럼이고 이후
		 	property로 Menu 자료형으로 들어온다-->
	 	<result property="menuId" column="menu_id"/>
	</resultMap>
	
  	<resultMap id="RcmdMenuViewResultMap" type="RcmdMenuView">
	 	<result property="menuId" column="menu_id"/>
	</resultMap>
  
  <!-- 아까는 한줄에 구현해야했는데, 이제 내려쓰기도 해도 되고부담이 없어! 주석도 돼! -->
  <!--  resultType 대신에 resultMap을 이용해-->
  
  <select id="findViewAllByMenuId" resultMap="RcmdMenuViewResultMap"> 
  <!-- resultType이 무엇이냐 modle을 넣어주자 -->
	   	select *
	  	from rcmd_menu_view
	  	where menu_id = #{menuId}
  </select>
  
  <insert id="insert" parameterType="RcmdMenu">
		insert into rcmd_menu(menu_id, id)
		values (#{menuID}, #{id})
  </insert>
  
  <delete id="delete" parameterType="RcmdMenu">
  		delete from menu where menu_id = #{menu_id}
  </delete>
  
</mapper>

상단의 resultMap은 쿼리문과 entity와의 차이를 매핑해주는것인데, menu_id 와 menuID 차이가 있다. 이런 경우를 위해서 이용되는 것이기 때문에 얘들만 설정해준다.

 

알아두기 parameterType -> 묶음단위

parameterType이 없으면 하나씩 인수로 넣어주면 돼

 

#{menu_id} 찾는 순서 : 속성명 --못찾으면--> getter 명으로 찾기

 

4)

unit test를 돌려보자!

package kr.co.rland.web.repository;

import static org.junit.jupiter.api.Assertions.*;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;

import kr.co.rland.web.entity.RcmdMenuView;

@AutoConfigureTestDatabase(replace = Replace.NONE)
@MybatisTest
class RcmdMenuRepositoryTest {
	
	@Autowired
	private RcmdMenuRepository repository;

	@Test
	void RcmdMenutest() {
		
		List<RcmdMenuView> menu = repository.findViewAllByMenuId(617);
		System.out.println(menu);
	}

}

추천된 3개의 메뉴가 출력되었다.

 

(3) view 와 insert

1)

먼저 query문으로 작동을 시켜보자 (꼭꼭)

insert into rcmd_menu(menu_id, id)
values (745 , 617);

2)

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.co.rland.web.repository.RcmdMenuRepository">
  
  <!-- 컬럼이름 매핑  -->
  	<resultMap id="RcmdMenuResultMap" type="RcmdMenu">
		  <result property="id" column="id"/>
		  <!-- column은 sql에서 오는 컬럼이고 이후
		 	property로 Menu 자료형으로 들어온다-->
	 	<result property="menuId" column="menu_id"/>
	</resultMap>


<insert id="insert" parameterType="RcmdMenu">
    insert into rcmd_menu(menu_id, id)
    values (#{menuID}, #{id})
</insert>

 

(4) view 와 delete

1)

delete 는 실질적으로 update라는 것(비즈니스 로직에서는 update이지만 dao에서는 delete()이다)

 

2)

<delete id="delete" parameterType="RcmdMenu">
    delete from menu where menu_id = #{menu_id}
</delete>

2. 추천메뉴  관련 Controller, service  & detail.html 수정

(1) Controller 와 service

1) Controller

@Controller 
@RequestMapping("/menu")
public class MenuController {
	@Autowired
	private MenuService service; // 메뉴가 주인인 곳에서의 service
	
	@Autowired
	private CategoryService categoryservice;
	//다른 곳에서의 주인은... 이름 더 붙이기!
	
	@Autowired
	private RcmdMenuService rcmdMenuService;

@RequestMapping("detail")	//주소와 같게 해주면
public String detail(
        long id, Model model) {

    Menu menu = service.getById(id);
    List<RcmdMenuView> rcmdMenuServices = rcmdMenuService.getViewListMenuId((int) id);

    model.addAttribute("menu", menu);
    model.addAttribute("rcmdMenuServices",rcmdMenuServices);

    return "menu/detail";
}
}

controller 에서  추천메뉴서비스를 선언한다

이에대해서 값을 받아서 model 객체에다가 담아준다.

 

2) service

package kr.co.rland.web.service;

import java.util.List;

import kr.co.rland.web.entity.RcmdMenuView;

//메뉴 컨트롤러에서 사용이 될거야
public interface RcmdMenuService {

	List<RcmdMenuView> getViewListMenuId(int menuId);
	
}

interface를 선언해준다.

 

3) service impl

package kr.co.rland.web.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import kr.co.rland.web.entity.RcmdMenuView;
import kr.co.rland.web.repository.MenuRepository;
import kr.co.rland.web.repository.RcmdMenuRepository;

@Service
public class DefaultRcmdMenuService implements RcmdMenuService {

	@Autowired
	private RcmdMenuRepository repository;
	
//	public void setRepository(RcmdMenuRepository repository) {
//		this.repository = repository;
//	}
	
	@Override
	public List<RcmdMenuView> getViewListMenuId(int menuId) {
		// TODO Auto-generated method stub
		
		return repository.findViewAllByMenuId(menuId);
	}

}

앞서 구현한 repository연결해서 이용한다

 

(2) detail.html 수정

1)

<a th:each="r : ${rcmdMenuServices}"
href="detail" 
th:href="@{detail(id=${r.id})}"
>

먼저 th:ecah 를 해주고 그 값을 받아서 <a>태그에다가 뿌려주자!

 

2)

<img class="image-view-round" 
    src="https://images.unsplash.com/photo-1515442261605-65987783cb6a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" 
    th:src="@{/image/menu/{img}(img=${r.img})}"
    alt="">
<span th:text="${r.name}">아몬드 쿠키</span>
</a>

그리고 img와 이름에다가 차례대로 뿌려주면된다.

 

3)

<div>
    <a th:each="r : ${rcmdMenuServices}"
        href="detail" 
        th:href="@{detail(id=${r.id})}"
      >
        <img class="image-view-round" 
            src="https://images.unsplash.com/photo-1515442261605-65987783cb6a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" 
            th:src="@{/image/menu/{img}(img=${r.img})}"
            alt="">
        <span th:text="${r.name}">아몬드 쿠키</span>
    </a>

</div>

그 결과 다음과 같이 출력이 된다.

아래쪽에 추천된 것을 이용해서 이름과 이미지가 출력이 된다.


1. 보충

 

 

 

 

 

2. 회고 

1) lombok을 쓰니 entity 바뀌어도 손쉽게 이용할 수 있어서 유용하다

 

2) 양면전술로서 접근하는것도 유용한것 같다

 

3) 받아온 data들을 타임리프를 이용해서 뿌려주는것이 흥미롭다.

'배움 __IL > TIL 1기' 카테고리의 다른 글

TIL : 76번째- 230324 [3-3-금]  (0) 2023.03.24
TIL : 75번째- 230323 [3-3-목]  (0) 2023.03.23
TIL : 73번째- 230321 [3-3-화]  (0) 2023.03.21
TIL : 72번째- 230320 [3-3-월]  (0) 2023.03.21
TIL : 71번째- 230317 [3-2-금]  (0) 2023.03.17