지도 api, 채팅, 에디터 적용, build, 이미지 수정

keep_going·2023년 1월 5일
0

vue

목록 보기
11/13

// 파일명: BoardContentPage.vue_수정: 이미지 수정할때

const handleUpdate = async() => {
  const url =`/board101/updateimage.json?no=${state.no}`;
  const headers = {"Content-Type":"multipart/form-data"};
  const body = new FormData();
  body.append("title", state.row1.title);
  body.append("content", state.row1.content);
  body.append("writer", state.row1.writer);
  body.append("image", state.row1.img);
  const { data } = await axios.put(url, body, {headers});
  console.log('handleUpdate', data);
  if(data.status === 200) {
    handleData();
    state.div = 1;
  }
};

  • 지도 api 연동
    https://developers.kakao.com/
  • 가입하고 내 애플리케이션에서 애플리케이션 추가
  • 플랫폼에서 web을 선택후 쓰고 있는 도메인 주소 (ex)http://127.0.0.1:8080)를 입력한다.
  • 이후 앱키에서 js키를 필요한곳에(예제에서 앱키 쓰라고 되어 있는 곳) 사용하면 된다.

// 파일명: MapPage.vue

<template>
    <div>
        <h3>카카오맵</h3>
        <button @click="handleMarker()">마크추가</button>
        <div id="map" style="width:100%;height:650px;border:1px solid #cccccc;"></div>
    </div>
</template>

<script>
import { onMounted, reactive } from 'vue';

export default {
    setup () {
        
        const state = reactive({
            position :[],
            map : null,
        });

        const handleData = () => {
            const data = [
                { id : '부산시청', lat:35.179720031749106, lng:129.07503445971523},
                { id : '양정역', lat:35.17294521114157, lng:129.07124047592524},
                { id : '양정초', lat:35.175188120635205, lng:129.07129738705143},
                { id : '양정119', lat:35.174862971465764, lng:129.0766011760778},
                { id : '연제구청', lat:35.176188415298284, lng:129.07970802437305},
            ];

            state.position = data;
        };

        onMounted( () => {
          	// 수동으로 script 추가하기
            // 1. script 태그 만들어라
            let script = document.createElement("script");
          	// 2. script 태그에 추가해라(쿼리에 autoload=false와 개인 앱키를 넣어줌)
            script.setAttribute("src", "//dapi.kakao.com/v2/maps/sdk.js?autoload=false&appkey=fb21c6b62b932db3002e7d1407eebccf");
          	// 3. window에 추가해라
            document.head.appendChild(script);
          	// window에 kakao 추가 된것 확인. 예제에서 kakao로 시작되는 코드들 앞에 전부 window 붙여줘야함!
            console.log(window);
          
            // 스크립트가 로드될때 initMap 실행시켜라
          	script.onload = () => {
                window.kakao.maps.load( initMap );
            }

            handleData();
        });

        const initMap = () => {
            const container = document.getElementById('map');
            // window 콘솔 찍어보면 kakao밑에 maps있음. f붙은것들 함수라는뜻 LatLng는(a,b) 2개 들어가서 포지션 만들어짐
          	const position  = new window.kakao.maps.LatLng(35.17971, 129.07661);
          
            const options   = {
                center : position, // 위치
                level  : 5, // 배율. 크면 클수록 작게 나온다.
            }

            // Map도 (a,b) 2개 들어감
            state.map = new window.kakao.maps.Map(container, options);
          	
          	// 위치 표시하기 위한 marker 필요  
          	const markerOptions = {
                map : state.map,
                position :position
            }

            new window.kakao.maps.Marker(markerOptions);
        };

        const handleMarker = () => {
            // for문을 어디에서 돌려야 하는지 아직 익숙하지 않음..
          	// 냅다 변수안에서 돌리려고 하지 말고 함수 내에서 돌리고 그안에서 다시 변수 선언하면 되는구나!
            for(let tmp of state.position) {
                const position  = new window.kakao.maps.LatLng(
                    tmp.lat, tmp.lng);

                const markerOptions = {
                    map : state.map,
                    position :position
                }

                new window.kakao.maps.Marker(markerOptions);
            }
        };

        return {
            state,
            handleMarker
        };
    }
}
</script>

<style lang="css" scoped>

</style>

서버

  1. 웹서버(express) : RESTful(rest api)로 get, post, delete.
    데이터를 먼저 요청해야 받을 수 있다.
  2. 소켓서버(express mqtt) : ws(websocket)로 실시간 모니터링 가능.
    접속을 해놓으면 요청 없이 데이터가 먼저 오는 것도 가능.
    웹소켓은 아이디, 암호 기반
    mqtt(배달대행, 페이스북, 통신사), xmpp(카카오톡) 등이 존재
    ex) 배민 기사 위치 파악, 가게에서 기사 배정을 위해서 call 보낼때 기사는 따로 새로고침 안해도 call이 들어옴, 채팅, 아마존 재고파악, 코인 실시간 차트

mqtt

  • 토픽기반(주소체계)
    ex) 대한민국/부산/부산진구/010-0000-0000, 대한민국/부산/부산진구/010-0000-0006, 대한민국/울산/울산구/010-0000-0002
    식당에서 /대한민국 하면 세사람에게 /부산 하면 두사람에게 /울산 하면 한사람에게 콜이 간다.
    근거리 기반으로 다수의 사람에게 연락 주기에 좋다!

  • qos(0, 1, 2)(메세지 체계?) -> 네트워크 프레임 할때 자세히 배울 예정
    0은 중요하지 않은 정보. 안받아도 그러려니.. 비용이 적게 든다. ex) 배달기사 부를때 연락 한두명 빠져도 상관없다.
    2는 중요한 정보. 안받으면 계속 보낸다! 부하가 심해지고 비용이 많이 든다.
    카카오는 0에 가깝다! 메세지를 보낸 순간 안받으면 db에 저장해놓고 나중에 가져오는것...!

  • 소켓서버 연동위해 mqtt설치
    CMD> npm i precompiled-mqtt --save

  • 채팅으로 이미지 보낼때 실제 이미지 보낸게 아니라 src만 보낸것. 이미지는 서버에 존재.

  • 포트는 데이터가 들어오고 나가는 통로로써 1번부터 1024는 정해져있음. 몽고디비를 깔았으면 37017 오라클은 1521 뷰는 8080.. 이런식으로 정해짐.


// 파일명: ChatPage.vue

<template>
    <div>
        <h3>채팅</h3>
        <input type="text" @keyup.enter="handleSend()" v-model="state.message"/>

        <hr />
        <table>
            <tr v-for="tmp of state.output" :key="tmp">
                <td>{{tmp.topic}}</td>
				// 채팅에 태그 걸면 해석해서 볼수 있다.
                <td v-html="tmp.message"></td> 
            </tr>
        </table>
    </div>
</template>

<script>
import mqtt from 'precompiled-mqtt'; // 수동으로 import
import { reactive } from '@vue/reactivity'
import { onMounted } from '@vue/runtime-core';
export default {
    setup () {
        const state = reactive({
            client  : null,   // 서버 접속 객체
            message : '',

            output : [], //전송받은 메시지를 보관할 배열
            
            host    : '1.234.5.158',
            port    : 11884, // 포트는 데이터가 들어오고 나가는 통로
            options : {
                clean           : true,
                reconnectPeriod : 20000, // 20초 마다 접속, 너무 짧으면 성능 떨어진다. 1000이 1초
                clientId        : 'ds200_' + new Date().getTime(), // 접속하는 id는 고유해야하므로 시간도 붙여줌 ex) ds203_243543876684
                username        : 'ds606',
                password        : 'ds606',
            }
        });

        onMounted(()=>{
            handleConnect(); // 접속
            handleSubscribe(); // 구독설정
        });

        const handleConnect = () =>{
            try {
              	// host와 port가 변경되는 값은 아니지만 나중에 수정하는 경우를 고려해서 따로 변수 설정해둔걸 가져와서 쓰는것.
                // 실제로는 변수에다가 값을 하드 코딩하는게 아니라 백엔드에서 데이터 가져오도록 코딩한다!
                // ws://1.234.5.158:11884
                const url = `ws://${state.host}:${state.port}`;
                state.client = mqtt.connect(url, state.options); // url로 접속. option정보 이용해서

              	// 아래 3개는 서버가 알려주기를 기다리는것. 콜백! 
                state.client.on('connect', () => {
                    console.log('connect success');
                });

                state.client.on('error', (error) => {
                    console.log(`connect fail => ${error}`);
                });

                state.client.on('message', (topic, message) => {
                    console.log(`receive message => ${topic} => ${message}`);
                    //state.output.push({topic:topic, message:JSON.parse(message)}); push는 새로운 메세지가 뒤쪽에 붙음
                    state.output.unshift({topic:topic, message:JSON.parse(message)}); // unshift는 위에 붙음
                });
            }
            catch(e){
                console.log(e);
            }
        };

        const handleSubscribe = () => {
            // ex) /ds/class606/a는 받을수 있지만 /ds/class605는 못받음. /ds로 보낸건 받을수있음
            const topic = '/ds/class606/#';
            state.client.subscribe(topic, {qos:0}, (error, res) => {
                if(error) {
                    console.log(`subscribe fail => ${error}`);
                    return false;
                }
                console.log(`subscribe success => ${res}`);
            });
        };
      	// 메세지 안보내고 받기만 할꺼면 여기까지만 해도 반응한다!

        const handleSend = () => {
            const topic = '/ds/class606/ds200';
            //object => string으로 변경
            const payload = JSON.stringify( state.message );
            state.client.publish(topic, payload, 0, error => {
                if(error) {
                    console.log(`send fail => ${error}`);
                    return false;
                }
                console.log('send success');
            });
        };

        return {
            state,
            handleSend
        };
    }
}
</script>

<style lang="css" scoped>

</style>

  • 에디터 사용을 위해 라이브러리 설치
  • quill 에디터는 태그를 속성으로 읽어오고 미리 입력된 값을 읽어오지 못하고... 반쪽만 사용되는 것 같음. ck 에디터로 사용.

https://vueup.github.io/vue-quill/

CMD> npm install @vueup/vue-quill@beta --save

CMD> npm install --save @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic


// 파일명: EditorPage.vue

<template>
    <div>
        <h3>Quill Editor</h3>
        {{ state }}
        
        <div style="width:700px">
            <ckeditor 
                :editor="state.editor" 
                v-model="state.editorData" 
                @ready="handleInit"></ckeditor>
        </div>

        <br /><br />
        
        <div style="width:500px">
            <QuillEditor theme="snow" toolbar="full" 
                v-model:content="state.content" style="height:200px;"></QuillEditor>
        </div>
    </div>
</template>

<script>
// npm install @vueup/vue-quill@beta --save
import { QuillEditor } from '@vueup/vue-quill';
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { reactive } from '@vue/reactivity';
import { watch } from '@vue/runtime-core';

// npm install --save @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import CKEditor from '@ckeditor/ckeditor5-vue';

export default {
    components :{
        QuillEditor,
        ckeditor : CKEditor.component,
    },
    setup () {
        const state = reactive({
            content : '',
            content1 : 'fgdfgdfgd',

            editor : ClassicEditor,
            editorData : '<p>미리추가된 내용</p>',
        });  
        
        watch(() => state.content, () => {
            console.log(state.content);
        },{
            immediate:true,
            deep:true,
        });

        // @ready => ckeditor 로딩시 호출됨.
        const handleInit = (editor) => {
            editor.editing.view.change(writer => {
                writer.setStyle("height", "300px", 
                    editor.editing.view.document.getRoot());
            });
        };

        return {
            state,
            handleInit
        };
    }
}
</script>

<style lang="scss" scoped>

</style>

build

  • 뷰 파일을 작성한 폴더 내 cmd 창에서 npm run build
  • dist 폴더가 생성되는데 그 안에는 html, css, js 파일만 존재!
  • 이 파일들을 그대로 긁어와서 vs code에서 백엔드의 public안에 바로 넣어준다.
  • 이후 아래 파일들 대로...
  • 최종적으로 서비스 할때는 프론트엔드 파일을 백엔드파일에 넣어야(build) 한다!

// 파일명: routes/index.js

var express = require('express');
var router = express.Router();

//127.0.0.1:3000/
router.get('/', async function(req, res, next) {
    // 현재 폴더 기준 public/index.html
   res.sendFile(path.join(__dirname, '../public', 'index.html'));
});

module.exports = router;

// 파일명: app.js_수정: build를 위해 만든 페이지 연결

// vue에서 build한 페이지를 표시
var indexRouter = require('./routes/index');
// vue에서 build한 페이지를 표시
app.use('/', indexRouter);

// 파일명: vue.config.js_수정: build시 용량 초과로 나오는것 해결

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,

// 이 부분 추가---------------------------
  configureWebpack:{
    performance: { 
      hints: false,
    },
    optimization:{
      minimize:true,
      splitChunks:{
        chunks: 'all',
      }
    }
  },
//----------------------------------------
  
  devServer :{
    proxy : {
      '/api' : {
        target : 'http://127.0.0.1:3000',
        changeOrigin : true,
        logLevel:'debug'
      },
      '/board101' : {
        target : 'http://1.234.5.158:23000',
        changeOrigin : true,
        logLevel:'debug'
      },
      '/item101' : {
        target : 'http://1.234.5.158:23000',
        changeOrigin : true,
        logLevel:'debug'
      },

      '/member101' : {
        target : 'http://1.234.5.158:23000',
        changeOrigin : true,
        logLevel:'debug'
      },
    }
  }
})
profile
keep going

0개의 댓글