배움 __IL/TIL 1기

TIL : 86번째- 230407 [4-1-금]

Mo_bi!e 2023. 4. 7. 19:40

I. 들어가며 : 질문타임

1)

화살표함수를 연달아 쓰는 방식에서 

아래이미지와 같이 나누어서 이렇게 쓸 수잇어

 

 

2)

children안에 children 가능해

 

II. Vue.js

1. 들어가며

(1) 브리핑

1)

우리가 작성하는 하는건 SPA

게임처럼 완전 클라이언트 프로그램이 되었어. 클아이언트에게 전달되는 완전한 어플리케이션이야

 

2)

네트워크 항목중에 menus 는 데이터야!

이런경우 클라에서도 할 수있으니까 조금만 하면 오프라인 상태에서도 이용이 가능

 

3)

데이터를 담는 것으로서 구조화된 클래스가 있어

model, dto, vo, domain 이 있어

 

네가지는 다 실체는 같은걸까? -> 다 다르다! 다만 겹치는 경우도 있다

범위가 큰것이 있고 작은것이 있어

 

1. VO : value object 

값을 담는 오브젝트로서 범용적으로 그냥 쓰는거야 -> 구분해서 쓰기 싫은경우

 

 

2. model :  출력할것을 화면에 바인딩 할때

이 경우 model과 entity가 거의 같아 별도 패키지 만드는 경우가 거의 없어

그러면 entity는? DB에서 정규화 했잖아, 정규화하면 실제로 다루어야할 대상이 나와 단위별 다루어야할 값의 집합덩어리를 엔티티라고 해

 

테이블 단위가 곳 entity야 -> 그러면 두개가 동일해? -> 응 맞아

그런데 우리가 DB에서 가져올때 view 가 있잖아, 뷰도 마찬가지로 엔티티가 필요해

모델을 다루다 보면 실제로 만들어서 뷰를 담아주는걸 보면 딱히 모델을 만드는 경우가 보이지는 않아

우리가 딱히 만들지는 않았어

 

모델 패키지에다가 담는거야

 

3. DTO : data transfer object [ https://dkswnkk.tistory.com/500 ]

이건 원격으로 포함되는거야!

옛날에는 함수가 로컬에 사용되는 함수가 있는(로컬디비) 반면에,

원격디비는 소켓을 써야하는데, 이 소켓을 감추고 싶다. 즉 로컬인지 원격인지 알고싶지 않을 때, 숨기는 함수덩어리 하나를 만들었어

여기서 보면 그냥 함수같지만, 구현을 보면 소켓으로 데이터 받아서 와준는 함수

데이터 주는건 다른 곳에 있어 로컬함수인것 가정하면서 하는거야

 

프록시가짜야 -> 프록시 서버는 가짜서버야 진짜는 아냐

대리자 역할하는게 다 프록시야

그때는 데이터를 원격으로 보내야해서 저쪽 서버에서는 데이터가 메모리를 가지는데, 메모리가 주소가 갈 수없잖아

데이터를 국어영어수학 데이터가 있으면 줄 세우기 해! 시리얼리제이션

 

서버가 클라이언트로 보내잖아 반환할 때 DTO라고 해도 돼

entity가 중심이야 model로 가져갈 때 하는게 다를 때 똑같은 엔티티를 쓰는거야

DTO를 하려고했는데 구조가 DB와 다르지않아 DTO따로 만들필요가 없어

 

< 정리>

DAO : DB 의 data에 접근하기 위한 객체 (CRUD 수행)

DTO : 계층간 데이터 교환을 위한 객체 (getter,setter 만 가짐 + entity를 DTO로 변환함)

 

(2) list 페이지 만들기 : 쿼리스트링 방식

1) 

.html 로 된 주소를 바꾸자

위 쿼리스트링 / 아래 API

주소방식이 두가지인데,쿼리스트링 / 아래api 방식이야

 

위쪽 달라고하는 페이지를 명시하는게 원래 만든거야 

요새 트렌드는 api 달라는식이다 보니 url 표현방법이 아래와 같이 바뀐것이 있긴해

 

위에꺼는 당연히 쿼리값 넣는것이기 때문에 지원해주고

아래는 경로를 값으로 얻는 방법이야

둘다 할줄 알아야해!

 

 

2)

직접 하나씩 쏴주는 방식으로 바꿔주자

 

바인드 해주는것으로 단축으로 ':' 붙여서 해주자!

<section class="menu" v-for="m in list">
  <form class="">
      <h1>{{m.name}}</h1> 
      <div class="menu-img-box">
          <a  :href="'detail?id='+m.id"><img class="menu-img" :src ="'/image/product/'+ m.img"></a>
      </div>    
      <div class="menu-price">{{ m.price }}</div>

이렇게 하나씩 해주는거야!

 

3)

 

그런데 링크 들어가면 디테일 페이지가 들어가야해 

링크가 좀 이상해 

 

현재있는 위치에서 경로를 보여주는거야

<div class="menu-img-box">
  <routerLink  :to="'detail?id='+m.id"><img class="menu-img" :src ="'/image/product/'+ m.img"></routerLink>
</div>

a태그에서 routerLink로 바꿔주자 

 

<routerLink  :to="'detail?id='+m.id"><img class="menu-img" :src ="'/image/product/'+ m.img"></routerLink>
<a  :href="'detail?id='+m.id"><img class="menu-img" :src ="'/image/product/'+ m.img"></a>

routerLink 방식의 경우 가운데에 header, footer를 나두고, 가운데를 바꿔 끼우는방식이라면

아래 a 링크는 통째로로 페이지가 바뀌는방식이다

 

현재 우리는 SPA방식이기 때문에 당연하게도 routerLink를 써야해

이경우 바인딩하기위해서 :to 를하자 

 

(3) detail 페이지 만들기

1) 

url 에 있는 데이터를 받아와서 detail에서 뿌려주어야해!

<script>
    export default{
        data(){

            return{
    
            //전달할 쿼리 변수명을 여기에 쓸 수있어!
                id : this.$route.query.id
            };
        }
    }
</script>

<style scoped>
    @import url(/css/component/menu-detail.css);
    @import url(/css/component/nutrition-info.css);
</style>


<template>
       <main class="main-padding-none">
      <section>
         <h1 class="d-none">알랜드 메뉴 상세정보</h1>

         <section class="cart">
            <h1 class="d-none">장바구니</h1>
            <span class="text-title3">커피음료 : {{ id }}</span>
            <div class="icon icon-basket">1</div>

scripte에서 쿼리값을 받을 수 있는 방법이있어

 

id : 하고 라우터에 쿼리값 id 를 하면 저장이 돼! 그러고 나서 아래쪽 커피음료 : {{id}} 로 해주면 돼

 

 

2)

이제 데이터 가져올 수있다는것을 알았어

패치 해서 데이터를 가지고 와야해

 

postman 에서 필요한 데이터를 불러오는 방식이야

var requestOptions = {
  method: 'GET',
  redirect: 'follow'
};

fetch("http://localhost:8080/menus/617", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

get 요청은 기본요청이기 떄문에 request option을 따로 안해주어도 돼!

 

<script>
    export default{
        data(){

            return{
    
            //전달할 쿼리 변수명을 여기에 쓸 수있어!
                // id : this.$route.query.id
            };
        },
        mounted() {

            fetch(`http://localhost:8080/menus/${this.$route.query.id}`)
            .then(response => response.text())
            .then(result => console.log(result))
            .catch(error => console.log('error', error));
        },
    }
</script>

id를 굳이 안담아도 돼 괜히 부하가 될 수도있어

 

mounted () 생명주기 시점에 호출이 되는거야

이 경우 필요한 id 값은 백틱을 써서 넣어주는거야

그리고 그 값이 잘 출력 되었는지는 콘솔에 다 볼 수있어!

3)

<script>
export default{
    data(){

        return{

        //전달할 쿼리 변수명을 여기에 쓸 수있어!
            // id : this.$route.query.id
            menu : null
        };
    },
    mounted() {

        fetch(`http://localhost:8080/menus/${this.$route.query.id}`)
        .then(response => response.json())
        .then(menu => this.menu = menu)
        .catch(error => console.log('error', error));


    },
}

여기서 받아온 파일(response)을 data() 가 아니라 json()으로 바꿔준다

바꿔준 것을 menu이름의 모델객체에 담아준다.

<header>
  <h1 class="d-none">{{menu.name}}</h1>
  <div class="img-div">
     <!-- <img alt="" th:src="'/image/menu/'+${menu.img}" src="https://images.unsplash.com/photo-1515442261605-65987783cb6a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80"> -->
     <img alt="" src="https://images.unsplash.com/photo-1515442261605-65987783cb6a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80">
  </div>
</header>

{{menu.name}} 로 해서 하면 될까?

하지만 다음과 같은 null 오류가 발생해 

 

4)

생명주기상 mounted()는 다큐먼트 객체안에 붙여줄 때 만들어주는거 

화면에 먼저 바인딩하고나서, 데이터를 출력하는건 말이 이상해

그렇다면 created()로 데이터 가져오고나서 출력하면돼

created(){

    fetch(`http://localhost:8080/menus/${this.$route.query.id}`)
    .then(response => response.json())
    .then(menu => this.menu = menu)
    .catch(error => console.log('error', error));


},

다음과 같은 같은 오류가 그래도 발생해 

그런데 출력은 잘돼! 왜 그럴까? 이게 비동기생명주기 관련된거야!

 

5)

이거와 의미가 비슷한게 보여져야만 수치를 바꿀수 있다.

 

만약 표현 하고자하는 것이 데이터라면 모르겠는데,

created mounted 둘다 해도 되는데, mounted 해야하는게 style, js, image도 입혀지고 좀 더 바람직한 상황이야

그래도 오류가 있으면 v-if를 이용해서 하는게 좋아 (혹은 아래에서 나올것 처럼 menu에 빈객체 넣어주기도 돼!)

<script>
export default{
    data(){

        return{

        //전달할 쿼리 변수명을 여기에 쓸 수있어!
            // id : this.$route.query.id
            menu : null
        };
    },
    beforeCreate(){
        //undefiend 아직 menu 모델이 올라가기도 전 상태
        console.log(`beforeCreate menu : ${this.menu}`);
    },

    created() {
        //null
        console.log(`created menu : ${this.menu}`);
    },

    beforeMount() {
        console.log(`beforeMount menu : ${this.menu}`);
    },

    mounted() {
        console.log(`created menu : ${this.menu}`);

        // let a = `http://localhost:8080/menus/${this.$route.query.id}`;
        // console.log(a);
        // let b = a.json();
        // console.log(b);
        // let c = (this.menu = b);
        // console.log(c);


        fetch(`http://localhost:8080/menus/${this.$route.query.id}`)
        .then(response => response.json())
        .then(menu => this.menu = menu)
        .catch(error => console.log('error', error));
    },

    updated() {
        console.log(`updated menu : ${this.menu}`);
    },

}
</script>

mounted() 된 경우가 가장 좋아

<header>
 <h1 class="text-title2" v-if="menu">{{menu.name}}</h1>
 <span class="text-normal">4,500원</span>
</header>

menu 가 존재할 때 binding하게끔 하면 오류가 발생하지 않아

updated 할 때 에는 객체가 올라간다.

 

6)

화면에 출력되고, 데이터로 업데이트 하는거야

 

- reactive 

front MVC는 다 리액티브야

뷰, 앵귤로 모든것이 리액티브야 화면이 다시 갱신되는데, 화면이 바뀔 때 얘가 실행되는거야

 

- 그런데 v-if 는 매 구문마다 해야하는건가?

그러면 더 큰 범위의 태그안에(전체영역) 넣어주면 돼

 

- if 랑 비슷한건데 v-show 는 오류가 떠

안보이고 싶으면 show(보이든 안보이든 처리는 O ) / 아예 처리를 안하고 싶을 떄 if 

 

 

 

7)

- menu 를 null 이 아니라 {} 객체로 선언하면 어떻게 될까?

data(){

    return{

    //전달할 쿼리 변수명을 여기에 쓸 수있어!
        // id : this.$route.query.id
        menu : {}
    };
},

null보다는 {} 가 나아

이렇게 하면 조건처리 안해도 돼!

 

(4) list 페이지 만들기 : 라우터링크 방식

1)

아까 처리할 때 쿼리 스트링 했잖아

url 표현할때 경로를 id 로 가져가잖아

 

<list.vue>

  <div class="menu-img-box">
     <routerLink  :to="'./'+m.id"><img class="menu-img" :src ="'/image/product/'+ m.img"></routerLink>
      <!-- <routerLink  :to="'detail?id='+m.id"><img class="menu-img" :src ="'/image/product/'+ m.img"></routerLink> -->
      <!-- <a  :href="'detail?id='+m.id"><img class="menu-img" :src ="'/image/product/'+ m.img"></a> -->
  </div>

먼저 routerLink의 방식을 바꾸자!

 

<main.js>

const routes = [
  //별도로 빼주기!
      { path : '/index', component : Index},

      { path: '/', component: Layout
      , children:[
          { path : 'menu/list', component : MenuList},
          { path : 'menu/:id', component : MenuDetail},
          { path : 'about', component : About},
      ] 
      },
      
      { path: '/admin', component: AdminLayout
      , children:[
        { path : 'index', component: Adminindex},
        { path : 'menu/list', component: Adminlist},
      ] 
      },
  ]

그러고 나서 다음과 같이 detail 을 :id 로 바꾸어주자!

 

 

<detail.vue>

mounted() {
    console.log(`created menu : ${this.menu}`);

    // let a = `http://localhost:8080/menus/${this.$route.query.id}`;
    // console.log(a);
    // let b = a.json();
    // console.log(b);
    // let c = (this.menu = b);
    // console.log(c);

    // fetch(`http://localhost:8080/menus/${this.$route.query.id}`)
    fetch(`http://localhost:8080/menus/${this.$route.params.id}`)
    .then(response => response.json())
    .then(menu => this.menu = menu)
    .catch(error => console.log('error', error));
},

queryparam 방식으로 바꿔준다. 

(여기서 param이란 url 에 있는 포함된 변수를 의미한다)

주소가 이렇게 나와

 

(4) NewMenuList.vuw

1) 들어가며

적당한 interface로 주고받는등 서로 커뮤니케이션 하게하는 약속된 데이터전달기법이 있어!

그게 아닌방법으로는 접근못하게해서 고립화라는 서로 영향을 주지않게끔 하는 차단할 수있는 방법이 필요할거 같아

 

component 만드는경우 component사이에서 관계를 가지는것에서 도구가 3가지가 있어

첫번째 속성 / 두번째 메소드 / 세번째 이벤트

이거 세가지만 있으면 둘 사이아 아무런 문제없이 데이터 주고받게 하는등이 가능해

 

 

2)

지금 component가 하나 더 생겼어!(새로운메뉴들) 메뉴 리스트의 한 부분을 담당하는거야! 캡슐화의 기본은 책임을 나누는 것!

컴포넌트가 나눠져 있으니까 목록이 있으면 자기가 해야지

그럴거면은 주체가 되는건 아냐! 각각의 컴포넌트가 패치하자나 그러면 문서가 동기화가 어려워져

그래서 우리는 데이터 가져오는거는 페이지 담당하는 메인을 알아야해

이제 데이터 가져올거면 무슨데이터인지 알아야해

이제는 신규메뉴도 같이 합쳐야해 ! view 에 binding된 데이터잖아 이거를 model로 보아야해

원격에 있어 이 모델이 dto 라고해도 되고 모델이라고 해도돼

 

원격서버있으면 dto / Vue 에 binding된 것은 model

 

dto 에다가 entity를 새로 만들자

package kr.co.rland.web.dto;

import java.util.Date;
import java.util.List;

import kr.co.rland.web.entity.MenuView;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MenuListData {

	private List<MenuView> list;
	private List<MenuView> newMenuList;
	
}

 listnewMenuList 두개를 만들어 왜냐하면 api에서 데이터를 보내줄 때 그 형식을 만들기위해서 해준거다

하지만 본 방식 외 hashMap방식도 가능하다

//@CrossOrigin(origins = "http://localhost:5173/")
@RestController("apiMenuController")
@RequestMapping("menus")
public class MenuController {
	
	@Autowired
	private MenuService service;

        @GetMapping
        public List<MenuView> getList(
                    @RequestParam(name = "p", defaultValue = "1") int page, 
                    @RequestParam(name = "c", required = false)	Integer categoryId, 
                    @RequestParam(name = "q", required = false)  String query		) {

        //		List <Menu> list = service.getList();
            List <MenuView> list = service.getViewList(page, categoryId, query);
            List <MenuView> newMenuList = service.getViewList(page, categoryId, query);


            MenuListData data = new MenuListData();
            data.setList(list);
            data.setNewMenuList(newMenuList);

            return list ;

        };

dto로 자료형을 만들었어... 

데이터형태가 고정되고 여러번 쓰는거라면 만들기는 하지만, 무조건 만드는거 아냐

@RestController("apiMenuController")
@RequestMapping("menus")
public class MenuController {
	
	@Autowired
	private MenuService service;
	
	//rest 가 아니면 문서에 대한 url이 돼
	//사용자에게 갈 데이터 구조야!
	//사용자는 restConroller 에 요청하면 사용자가 받는건 데이터
	
	//나중에 메소드가 아니라 공통분모에 몰아주자!
	
	@GetMapping
//	public List<MenuView> getList(
	public Map<String, Object> getList(
				@RequestParam(name = "p", defaultValue = "1") int page, 
				@RequestParam(name = "c", required = false)	Integer categoryId, 
				@RequestParam(name = "q", required = false)  String query		) {
		
//		List <Menu> list = service.getList();
		List <MenuView> list = service.getViewList(page, categoryId, query);
		List <MenuView> newMenuList = service.getViewList(2, categoryId, query);
		
		
//		MenuListData data = new MenuListData();
//		data.setList(list);
//		data.setNewMenuList(newMenuList);
		
		Map<String, Object> data = new HashMap<>();
		data.put("list", list);
		data.put("newMenuList", newMenuList);
			
		return data ;
		
	};

이럴 때는 map이나 list 등으로 가능해!

 

3)

여기를 보면 아까  list 에다가 담겼던  list 와 newMenuList가 모두 담겼어

 

4)

<script>
import NewMenuList from './NewMenuList.vue'

    export default{
        data(){
            return{
                list : [{}, {}, {}, {}],
                newList :[]
            }
        },
        mounted() {
            fetch("http://localhost:8080/menus")
            .then(response => {
               return response.json();
            })
            .then(data =>{
               this.list = data.list;
               this.newList = data.newList;
        });
      },
      components : {NewMenuList}
   }

</script>

response 에서 json 으로 변환한것을 받고,

data를 받고나서,  각각에 넣어주는 방식이야

 

 

 


1. 보충

 

 

 

 

2. 회고 

 

 

 

 

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

TIL : 88번째- 230411 [4-2-화]  (0) 2023.04.11
TIL : 87번째- 230410 [4-2-월]  (0) 2023.04.10
TIL : 83번째- 230404 [4-1-화]  (0) 2023.04.04
TIL : 82번째- 230403 [4-1-월]  (0) 2023.04.03
TIL : 81번째- 230331 [3-4-금]  (0) 2023.03.31