관리 메뉴

SIMPLE & UNIQUE

3회차_2강 : 수정페이지를 구현한다. (text, 이미지, 파일) 본문

탈잉 강의 자료/react.js(프론트) + node.js(백앤드) 개발에서 배포까지

3회차_2강 : 수정페이지를 구현한다. (text, 이미지, 파일)

착한코딩 2020. 1. 16. 01:08

3_2 목표 : 이미 등록된 데이터를 수정페이지 form에 노출시키고, 수정기능을 등록페이지 로직과 동일하게 구현한다.

1. 등록페이지 react 파일에 수정 기능을 추가한다.

AdminSoftwareView.js 파일에 아래 소스를 붙여넣는다.

state에 수정에 필요한 변수들을 선언했고, node api를 호출해 기존에 저장한 데이터를 호출해 화면에 노출시키는 스크립트 코드가 추가됐다.

import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import axios from "axios";
import $ from 'jquery';

class SoftwareView extends Component {
    constructor(props) {
        super(props);
        this.state = {
            responseSwtoolInfo: '',//swtool 정보 response 변수
            append_SwtoolInfo: '', //swtool 정보 append 변수

            before_swtcode: props.match.params.swtcode, //swtool 정보 swtool 코드
            swtcode: '', //swtool 저장 swtool 코드
            swt_toolname: '', //swtool 정보 sw툴 명
            swt_demo_site: '',//swtool 정보 데모사이트
            swt_github_url: '',//swtool 정보 깃허브 주소
            swt_comments: '',//swtool 정보 설명
            swt_function: '',//swtool 정보 기능

            //파일, 이미지 업로드
            file: '',//메인 이미지 미리보기용 path
            file2: '',//라벨 이미지 미리보기용 path
            fileName: '',//메인 이미지명
            fileName2: '',//라벨 이미지명
            menualName: '',//메뉴얼명
            selectedFile: null, //업로드 대상 파일
        }
    }
    componentDidMount () {
        // SW Tool 정보 호출
        this.callSwToolInfoApi()
        if(this.state.before_swtcode == 'register'){
            $('.modifyclass').hide()
        }else{
            $('.saveclass').hide()
        }
    }

    //업로드할 파일 세팅
    handleFileInput(type, e){
        var id = e.target.id
        if(type =='file'){
            $('#imagefile').val(e.target.files[0].name)
        }else if(type =='file2'){
            $('#imagefile2').val(e.target.files[0].name)
        }else if(type =='manual'){
            $('#manualfile').val(e.target.files[0].name)
        }
        this.setState({
          selectedFile : e.target.files[0],
        })

        if(type =='manual'){
            setTimeout(function() {
                this.handlePostMenual(type, id ,e)
            }.bind(this),1
            );
        }else{
            setTimeout(function() {
                this.handlePostImage(type, id ,e)
            }.bind(this),1
            );
        }
    }

    //메뉴얼 업로드
    handlePostMenual(type, id, e){
        const formData = new FormData();
        formData.append('file', this.state.selectedFile);
    
        return axios.post("/api/upload?type=uploads/swmanual/", formData).then(res => {
            try {

                this.state.menualName = res.data.filename
                
                $('#upload_menual').prepend('<input id="is_MenualName" type="hidden" name="is_MenualName" value="'+this.state.menualName+'"}/>')
            } catch (error) {
                alert('작업중 오류가 발생하였습니다.', error, 'error', '닫기')
            }
        }).catch(error => {
            alert('작업중 오류가 발생하였습니다.', error, 'error', '닫기')
        })
    }    

    //이미지 업로드
    handlePostImage(type, id, e){
        const formData = new FormData();
        formData.append('file', this.state.selectedFile);
    
        return axios.post("/api/upload?type=uploads/image/", formData).then(res => {
            try {
                setTimeout(function() {
                    if(type =='file'){
                        this.state.file = '/image/'+res.data.filename
                        this.state.fileName = res.data.filename
                        $('#uploadimg').show()
                        $('#is_MainImg').remove()
                        $('#uploadimg').remove()
                        $('#upload_img').prepend('<img id="uploadimg" src="'+this.state.file+'"/>')
                        $('#upload_img').prepend('<input id="is_MainImg" type="hidden" name="is_MainImg" value="'+this.state.fileName+'"}/>')
                        
                    }else if(type =='file2'){
                        this.state.file2 = '/image/'+res.data.filename
                        this.state.fileName2 = res.data.filename
                        $('#uploadimg2').show()
                        $('#is_LabelImg').remove()
                        $('#uploadimg2').remove()
                        $('#upload_img2').prepend('<img id="uploadimg2" src="'+this.state.file2+'"/>')
                        $('#upload_img2').prepend('<input id="is_LabelImg" type="hidden" name="is_LabelImg" value="'+this.state.fileName2+'"}/>')
                    }
                }.bind(this),1000
                );

            } catch (error) {
                alert('작업중 오류가 발생하였습니다.')            
            }
        }).catch(error => {
            alert('작업중 오류가 발생하였습니다.')            
        })
    }


    // SW Tool 정보 호출
    callSwToolInfoApi = async () => {
        //SW Tool List 호출
        axios.post('/api/Swtool?type=info', {
            is_Swtcode: this.state.before_swtcode,
        })
        .then( response => {
            try {
                this.setState({ responseSwtoolInfo: response });
                this.setState({ append_SwtoolInfo: this.SwToolInfoAppend() });

                $('#is_Swt_toolname').val(this.state.swt_toolname)
                $('#is_Swt_demo_site').val(this.state.swt_demo_site)
                $('#is_Giturl').val(this.state.swt_github_url)
                $('#is_Comments').val(this.state.swt_comments)
                $('#is_Swt_function').val(this.state.swt_function)
                
                $('#upload_img').prepend('<img id="uploadimg" src="'+this.state.file+'"/>')
                $('#upload_img').prepend('<input id="is_MainImg" type="hidden" name="is_MainImg" value="'+this.state.fileName+'"}/>')
                
                $('#upload_img2').prepend('<img id="uploadimg2" src="'+this.state.file2+'"/>')
                $('#upload_img2').prepend('<input id="is_LabelImg" type="hidden" name="is_LabelImg" value="'+this.state.fileName2+'"}/>')
                
                $('#imagefile').val(this.state.fileName)
                $('#imagefile2').val(this.state.fileName2)
                $('#manualfile').val(this.state.menualName)

                if($('#uploadimg').attr('src').indexOf("null") > -1){
                    $('#uploadimg').hide()
                }
                if($('#uploadimg2').attr('src').indexOf("null") > -1){
                    $('#uploadimg2').hide()
                }
            } catch (error) {
                alert('작업중 오류가 발생하였습니다.')
            }
        })
        .catch( error => {alert('작업중 오류가 발생하였습니다.');return false;} );
    }

    // SW Tool 정보 append
    SwToolInfoAppend = () => {
        let result = []
        var SwToolInfo = this.state.responseSwtoolInfo.data
        
        if(this.state.before_swtcode != 'register'){
            var data = SwToolInfo.json[0]

            this.state.swt_toolname = data.swt_toolname
            this.state.swt_demo_site = data.swt_demo_site
            this.state.swt_github_url = data.swt_github_url
            this.state.swt_comments = data.swt_comments
            this.state.swt_function = data.swt_function

            this.state.file = '/image/'+data.swt_big_imgpath
            this.state.fileName = data.swt_big_imgpath
            $('#imagefile').val(data.swt_big_imgpath)
            
            this.state.file2 = '/image/'+data.swt_imagepath
            this.state.fileName2 = data.swt_imagepath
            $('#imagefile2').val(data.swt_imagepath)
                
            this.state.menualName = data.swt_manual_path
        }
            result.push(
                <table class="table_ty1">
                    <tr>
                        <th>
                            <label for="is_Swt_toolname">툴 이름<span class="red">(*)</span></label>
                        </th>
                        <td>
                            <input type="text" name="is_Swt_toolname" id="is_Swt_toolname" class="" />
                        </td>
                    </tr>
                    <tr>
                        <th>
                            <label for="is_Swt_demo_site">데모 URL<span class="red">(*)</span></label>
                        </th>
                        <td>
                            <input type="text" name="is_Swt_demo_site" id="is_Swt_demo_site" class="" />
                        </td>
                    </tr>
                    <tr>
                        <th>
                            <label for="is_Giturl">Github URL<span class="red">(*)</span></label>
                        </th>
                        <td>
                            <input type="text" name="is_Giturl" id="is_Giturl" class="" />
                        </td>
                    </tr>
                    <tr>
                        <th>
                            <label for="is_Comments">설명<span class="red">(*)</span></label>
                        </th>
                        <td>
                            <textarea name="is_Comments" id="is_Comments" rows="" cols=""></textarea>
                        </td>
                    </tr>
                    <tr class="div_tb_tr fileb">
                        <th>
                            메뉴얼 파일 #1
                        </th>
                        <td class="fileBox fileBox_w1">
                            <label for="uploadBtn1" class="btn_file">파일선택</label>
                            <input type="text" id="manualfile" class="fileName fileName1" readonly="readonly" placeholder="선택된 파일 없음"/>
                            <input type="file" id="uploadBtn1" class="uploadBtn uploadBtn1" onChange={e => this.handleFileInput('manual',e)}/>	
                            <div id="upload_menual">
                            </div>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            메인 이미지
                        </th>
                        <td className="fileBox fileBox1">
                            <label htmlFor='imageSelect' className="btn_file">파일선택</label>
                            <input type="text" id="imagefile" className="fileName fileName1" readOnly="readonly" placeholder="선택된 파일 없음"/>
                            <input type="file" id="imageSelect" className="uploadBtn uploadBtn1" onChange={e => this.handleFileInput('file',e)}/>
                            <div id="upload_img">
                            </div>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            라벨 이미지
                        </th>
                        <td className="fileBox fileBox2">
                            <label htmlFor='imageSelect2' className="btn_file">파일선택</label>
                            <input type="text" id="imagefile2" className="fileName fileName1" readOnly="readonly" placeholder="선택된 파일 없음"/>
                            <input type="file" id="imageSelect2" className="uploadBtn uploadBtn1" onChange={e => this.handleFileInput('file2',e)}/>
                            <div id="upload_img2">
                            </div>
                        </td>
                    </tr>
                    <tr>
                        <th>
                            <label for="is_Swt_function">상세 기능<span class="red">(*)</span></label>
                        </th>
                        <td>
                            <textarea name="is_Swt_function" id="is_Swt_function" rows="" cols=""></textarea>
                        </td>
                    </tr>
                </table>
            )
        return result
    }

    // 저장 버튼 클릭시 validate check
    submitClick = async (type, e) => {

        this.Swt_toolname_checker = $('#is_Swt_toolname').val();
        this.Swt_demo_site_checker = $('#is_Swt_demo_site').val();
        this.Giturl_checker = $('#is_Giturl').val();
        this.Comments_checker = $('#is_Comments').val();
        this.Swt_function_checker = $('#is_Swt_function').val();

        this.fnValidate = (e) => {

            // ## Swt_toolname check start 
            if(this.Swt_toolname_checker === '') {
                $('#is_Swt_toolname').addClass('border_validate_err');
                alert('툴 이름을 다시 확인해주세요.')
                return false;
            }
            $('#is_Swt_toolname').removeClass('border_validate_err');

            // ## Swt_demo_site check start 
            if(this.Swt_demo_site_checker === '') {
                $('#is_Swt_demo_site').addClass('border_validate_err');
                alert('데모 URL을 다시 확인해주세요.')
                return false;
            }
            $('#is_Swt_demo_site').removeClass('border_validate_err');

            // ## Giturl check start 
            if(this.Giturl_checker === '') {
                $('#is_Giturl').addClass('border_validate_err');
                alert('Github URL을 다시 확인해주세요.')
                return false;
            }
            $('#is_Giturl').removeClass('border_validate_err');

            // ## Comments check start 
            if(this.Comments_checker === '') {
                $('#is_Comments').addClass('border_validate_err');
                alert('설명을 다시 확인해주세요.')
                return false;
            }
            $('#is_Comments').removeClass('border_validate_err');

            // ## Swt_function check start 
            if(this.Swt_function_checker === '') {
                $('#is_Swt_function').addClass('border_validate_err');
                alert('상세기능을 다시 확인해주세요.')
                return false;
            }
            $('#is_Swt_function').removeClass('border_validate_err');

            var date = new Date()
            var y_str = date.getFullYear().toString();

            var month = date.getMonth()+1
            var m_str = month.toString();

            var day = date.getDate()
            var d_str = day.toString();

            var hour = date.getHours()
            var min = date.getMinutes()
            var sec = date.getSeconds()

            // 프로젝트 코드생성
            this.state.swtcode = 'USW'+y_str+m_str+d_str+hour+min+sec
            
            $('#is_Swtcode').val(this.state.swtcode)

            return true;
        }

        //유효성 체크
        if(this.fnValidate()){
            //software Tools 저장
            //form type To Json
            var jsonstr = $("form[name='frm']").serialize();
            //특수문자 깨짐 해결
            jsonstr = decodeURIComponent(jsonstr);
            var Json_form = JSON.stringify(jsonstr).replace(/\"/gi,'')
            Json_form = "{\"" +Json_form.replace(/\&/g,'\",\"').replace(/=/gi,'\":"')+"\"}";
        
            try {
                const response = await fetch('/api/Swtool?type='+type, {
                    method: 'POST',
                    headers: {
                    'Content-Type': 'application/json',
                    },
                    //한글 디코딩
                    body: Json_form,
                });
                const body = await response.text();
                if(body == "succ"){
                    if(type == 'save'){
                        alert('Software Tools 등록이 완료되었습니다.')
                    }else if(type == "modify"){
                        alert('Software Tools 수정이 완료되었습니다.')
                    }
                    // 저장 후 리스트페이지로 이동
                    setTimeout(function() {
                        // datasource 정보 호출
                        window.location.href = 'http://localhost:3000/AdminSoftwareList';
                        }.bind(this),1500
                    );
                }else{
                    alert('작업중 오류가 발생하였습니다.')
                }  
            } catch (error) {
                alert('작업중 오류가 발생하였습니다.')
            }
        }//fnValidate end
    };

     render () {
        return (
            <section class="sub_wrap">
                <article class="s_cnt mp_pro_li ct1">
                    <div class="li_top">
                        <h2 class="s_tit1">Software Tools 등록/수정</h2>
                    </div>
                    <div class="bo_w re1_wrap re1_wrap_writer">
                        <form name="frm" id="frm" action="" onsubmit="" method="post" >
                            <input id="is_Email" type="hidden" name="is_Email" value={this.state.admin_userid} />
                            <input id="is_Swtcode" type="hidden" name="is_Swtcode" value={this.state.swtcode} />
                            <input id="is_beforeSwtcode" type="hidden" name="is_beforeSwtcode" value={this.state.before_swtcode} />
                            
                            <article class="res_w">
                                <p class="ment" style={{"text-align": "right"}}>
                                    <span class="red">(*)</span>표시는 필수입력사항 입니다.
                                </p>
                                <div class="tb_outline">
                                    {this.state.append_SwtoolInfo}

                                    <div class="btn_confirm mt20" style={{"margin-bottom": "44px"}}>
                                        <Link to={'/AdminSoftwareList'} className="bt_ty bt_ty1 cancel_ty1">취소</Link>
                                        <a href="javascript:" className="bt_ty bt_ty2 submit_ty1 saveclass" onClick={(e) => this.submitClick('save', e)}>저장</a>
                                        <a href="javascript:" className="bt_ty bt_ty2 submit_ty1 modifyclass" onClick={(e) => this.submitClick('modify', e)}>수정</a>
                                    </div>

                                </div>
                            </article>
                        </form>	
                    </div> 
                </article>
            </section>
        );
    }
}

export default SoftwareView;

2. node 경로에 등록된 데이터를 불러오고, 새로운 데이터로 수정하는 함수와 쿼리를 작성한다.

SwtoolModule.js 파일을 아래와 같이 수정한다.
tool 상세페이지에 노출한 데이터를 호출하는 mapper를 호출하는 로직(m_typ=info)

새로운 데이터를 수정하는 로직(m_typ=modify)을 추가했다.

var express = require('express');
var router = express.Router();
const bodyParser = require('body-parser');

router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));

router.post('/', (req, res, next) => {
  var m_typ = req.query.type;
  if(m_typ == 'list'){
    //Swtool 리스트 조회
    try {
      // Mysql Api 모듈(CRUD)
      var dbconnect_Module = require('./dbconnect_Module');
  
      //Mysql 쿼리 호출정보 입력
      req.body.mapper = 'SwToolsMapper';//mybatis xml 파일명
      req.body.crud = 'select';//select, insert, update, delete 중에 입력
      req.body.mapper_id = 'selectSwToolsList';
      
      router.use('/', dbconnect_Module);
      next('route')
    } catch (error) {
      console.log("Module > dbconnect error : "+ error);      
    }
  }else if(m_typ == 'save'){
    //Swtool 관리자 저장
    try {
      // Mysql Api 모듈(CRUD)
      var dbconnect_Module = require('./dbconnect_Module');
  
      //Mysql 쿼리 호출정보 입력
      req.body.mapper = 'SwToolsMapper';//mybatis xml 파일명
      req.body.crud = 'insert';//select, insert, update, delete 중에 입력
      req.body.mapper_id = 'insertSwToolsInfo';
      
      router.use('/', dbconnect_Module);
      next('route')
    } catch (error) {
      console.log("Module > dbconnect error : "+ error);      
    }
  }else if(m_typ == 'info'){
    //Swtool 정보 조회
      try {
        // Mysql Api 모듈(CRUD)
        var dbconnect_Module = require('./dbconnect_Module');
    
        //Mysql 쿼리 호출정보 입력
        req.body.mapper = 'SwToolsMapper';//mybatis xml 파일명
        req.body.crud = 'select';//select, insert, update, delete 중에 입력
        req.body.mapper_id = 'selectSwToolsInfo';
        
        router.use('/', dbconnect_Module);
        next('route')
      } catch (error) {
        console.log("Module > dbconnect error : "+ error);      
      }
  }else if(m_typ == 'modify'){
    //Swtool 관리자 수정
    try {
      // Mysql Api 모듈(CRUD)
      var dbconnect_Module = require('./dbconnect_Module');
  
      //Mysql 쿼리 호출정보 입력
      req.body.mapper = 'SwToolsMapper';//mybatis xml 파일명
      req.body.crud = 'update';//select, insert, update, delete 중에 입력
      req.body.mapper_id = 'updateSwToolsInfo';
      
      router.use('/', dbconnect_Module);
      next('route')
    } catch (error) {
      console.log("Module > dbconnect error : "+ error);      
    }
  }
});

module.exports = router;

SwToolsMapper.xml 파일을 아래와 같이 수정한다. tool 리스트가 아닌 1개의 데이터만 가져오는 select 쿼리와
새로운 데이를 update 해주는 쿼리가 추가됐다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="SwToolsMapper">  
  <select id="selectSwToolsList">
      SELECT 
        swt_code
        , swt_toolname
        , swt_function
        , swt_imagepath
        , swt_big_imgpath
        , swt_comments
        , swt_demo_site
        , swt_manual_path
        , swt_github_url
        , reg_date
      FROM rtrod.rtrod_swtool
      ORDER BY update_date DESC
      <if test="startRow != null && startRow != ''">
        limit ${startRow}, ${endRow}
      </if>
  </select>

  <insert id="insertSwToolsInfo"> 
    INSERT INTO rtrod.rtrod_swtool
    (
        swt_code
        , swt_toolname
        , swt_function
        , swt_comments
        , swt_demo_site
        , swt_github_url
        <if test="is_LabelImg != null && is_LabelImg != ''">
          , swt_imagepath
        </if>
        <if test="is_MainImg != null && is_MainImg != ''">
          , swt_big_imgpath
        </if>
        <if test="is_MenualName != null && is_MenualName != ''">
          , swt_manual_path
        </if>
        , reg_date
        , reg_user
        , update_date
        , update_user
    )
    VALUES (
      #{is_Swtcode}
      , #{is_Swt_toolname}
      , #{is_Swt_function}      
      , #{is_Comments}
      , #{is_Swt_demo_site}
      , #{is_Giturl}
      <if test="is_LabelImg != null && is_LabelImg != ''">
        , #{is_LabelImg}
      </if>
      <if test="is_MainImg != null && is_MainImg != ''">
        , #{is_MainImg}
      </if>
      <if test="is_MenualName != null && is_MenualName != ''">
        , #{is_MenualName}
      </if>
      , DATE_FORMAT(now(), '%Y%m%d%H%i%s')
      , #{is_Email}
      , DATE_FORMAT(now(), '%Y%m%d%H%i%s')
      , #{is_Email}
    )
  </insert>
  
  <select id="selectSwToolsInfo">
      SELECT 
        swt_code
        , swt_toolname
        , swt_function
        , swt_imagepath
        , swt_big_imgpath
        , swt_comments
        , swt_demo_site
        , swt_manual_path
        , swt_github_url
        , reg_date
      FROM rtrod.rtrod_swtool
      <if test="is_Swtcode != null && is_Swtcode != ''">
        WHERE swt_code = #{is_Swtcode}
      </if>
  </select>
  
  <update id="updateSwToolsInfo"> 
    UPDATE rtrod.rtrod_swtool
    SET
        swt_toolname = #{is_Swt_toolname}
        , swt_function = #{is_Swt_function}
        , swt_comments = #{is_Comments}
        , swt_demo_site = #{is_Swt_demo_site}
        , swt_github_url = #{is_Giturl}
        <if test="is_LabelImg != null && is_LabelImg != ''">
          , swt_imagepath = #{is_LabelImg}
        </if>
        <if test="is_MainImg != null && is_MainImg != ''">
          , swt_big_imgpath = #{is_MainImg}
        </if>
        <if test="is_MenualName != null && is_MenualName != ''">
          , swt_manual_path = #{is_MenualName}
        </if>
        , update_date = DATE_FORMAT(now(), '%Y%m%d%H%i%s')
        , update_user = #{is_Email}
    WHERE swt_code = #{is_beforeSwtcode}
  </update>

</mapper>

3. 수정이 정상적으로 동작하는지 확인한다.

상세페이지에서 데이터 수정 후, 리스트로 돌아와 다시 상세페이지로 진입하면 수정된 데이터를 확인할 수 있다.

 

Comments