일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 일
- 광명파티룸
- 스컬킹점수
- 해외여행
- 파티룸
- 개발자
- 구로파티룸
- 스컬킹
- 부천파티룸
- 스컬킹점수계산
- 옥길파티룸
- 가장존경하는인물
- 옥길그릭요거트
- 옥길요거트
- 웹개발
- 코딩
- 옥길동파티룸
- mysql
- 휴식
- 부천공간대여
- 보드게임점수
- MBTI
- 스페이스우일
- 취미
- 보드게임점수계산
- 존경하는위인
- 옥길동요거트
- 착한코딩
- 그릭요거트
- 서울파티룸
- Today
- Total
SIMPLE & UNIQUE
3회차_3강 : ALERT 디자인을 수정하고, 삭제기능을 구현한다. Source tree를 사용해 git에 소스를 업로드한다. 본문
3회차_3강 : ALERT 디자인을 수정하고, 삭제기능을 구현한다. Source tree를 사용해 git에 소스를 업로드한다.
착한코딩 2020. 1. 16. 01:413_3 목표 : 사이트 레이아웃에 어울리는 alert 디자인을 적용하고, 리스트페이지에서 삭제 기능을 구현한다. git 서버에 업로드하지 말아야 하는 파일들을 이해한다.
1. sweetalert2 패키지를 설치해 alert 디자인을 수정한다.
react 경로 C:\Users\ljung\OneDrive\문서\taling0102\client 에서 아래 명령어로 패키지를 설치한다.
npm install --save sweetalert2
참고 : https://sweetalert2.github.io/#native_link#
AdminSoftwareView.js 파일을 아래와 같이 수정한다. 수정이나 저장 버튼을 눌렀을때 하단에
알림창(sweetalertSucc)이 뜨도록 수정했다. (sweetalert으로 검색하면 나오는 부분).
기본함수인 sweetalert()은 일반적인 스크립트 알림함수인 alert()과 동일하게 사용하면 된다.
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import axios from "axios";
import $ from 'jquery';
import Swal from 'sweetalert2'
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'){
this.sweetalertSucc('Software Tools 등록이 완료되었습니다.', false)
}else if(type == "modify"){
this.sweetalertSucc('Software Tools 수정이 완료되었습니다.', false)
}
// 저장 후 리스트페이지로 이동
setTimeout(function() {
// datasource 정보 호출
window.location.href = 'http://localhost:3000/AdminSoftwareList';
}.bind(this),1500
);
}else{
alert('작업중 오류가 발생하였습니다.')
}
} catch (error) {
alert('작업중 오류가 발생하였습니다.')
}
}//fnValidate end
};
//alert 기본 함수
sweetalert = (title, contents, icon, confirmButtonText) => {
Swal.fire({
title: title,
text: contents,
icon: icon,
confirmButtonText: confirmButtonText
})
}
//alert 성공 함수
sweetalertSucc = (title, showConfirmButton) => {
Swal.fire({
position: 'bottom-end',
icon: 'success',
title: title,
showConfirmButton: showConfirmButton,
timer: 1000
})
}
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;
아래와 같이 알림창이 노출될 것이다.
알림창이 노출되는 시간이 1초가 넘어서, 리스트로 redirect 되는 시간을 timeout 1.5초를 걸어두었다.
2. tool 리스트 페이지에서 삭제버튼에서 호출할 함수를 추가한다.
AdminSoftwareList.js 파일을 아래와 같이 수정한다. 삭제 버튼을 누르면, 삭제할 tool 코드를 node api로 전달하는 코드가 추가되었다. 1. 에서 추가한 sweetalert으로 삭제 alert을 구현했다. 삭제가 완료되면 callSwToolListApi() 를 호출해 삭제 이후의 리스트를 불러온다.
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import axios from "axios";
import Swal from 'sweetalert2'
class SoftwareList extends Component {
constructor(props) {
super(props);
this.state = {
responseSwtoolList: '',//swtool 리스트 response 변수
append_SwtoolList: '', //swtool 리스트 append 변수
}
}
componentDidMount() {
// SW Tool 리스트 호출
this.callSwToolListApi()
}
// SW Tool 리스트 호출
callSwToolListApi = async () => {
//SW Tool List 호출
axios.post('/api/Swtool?type=list', {
})
.then( response => {
try {
this.setState({ responseSwtoolList: response });
this.setState({ append_SwtoolList: this.SwToolListAppend() });
} catch (error) {
alert('작업중 오류가 발생하였습니다.');
}
})
.catch( error => {alert('작업중 오류가 발생하였습니다.');return false;} );
}
// SW Tool 리스트 append
SwToolListAppend = () => {
let result = []
var SwToolList = this.state.responseSwtoolList.data
for(let i=0; i<SwToolList.json.length; i++){
var data = SwToolList.json[i]
var date = data.reg_date
var year = date.substr(0,4)
var month = date.substr(4,2)
var day = date.substr(6,2)
var reg_date = year +'.'+month+'.'+day
result.push(
<tr class="hidden_type">
<td>{data.swt_toolname}</td>
<td>{data.swt_function}</td>
<td>{reg_date}</td>
<td>
<Link to={'/AdminSoftwareView/'+data.swt_code} className="bt_c1 bt_c2 w50_b">수정</Link>
<a href="#n" class="bt_c1 w50_b" id={data.swt_code} toolname={data.swt_toolname} onClick={(e) => this.deleteSwtool(e)}>삭제</a>
</td>
</tr>
)
}
return result
}
// 리스트에서 툴삭제
deleteSwtool = (e) => {
//삭제 권한 부여
var event_target = e.target
var tmp_this = this
this.sweetalertDelete('정말 삭제하시겠습니까?', function() {
axios.post('/api/Swtool?type=delbefore', {
is_SwtCd : event_target.getAttribute('id')
})
.then( response => {
tmp_this.callSwToolListApi()
})
})
}
//alert 삭제 함수
sweetalertDelete = (title, callbackFunc) => {
Swal.fire({
title: title,
text: "",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes'
}).then((result) => {
if (result.value) {
Swal.fire(
'Deleted!',
'삭제되었습니다.',
'success'
)
}else{
return false;
}
callbackFunc()
})
}
render () {
return (
<section class="sub_wrap" >
<article class="s_cnt mp_pro_li ct1 mp_pro_li_admin">
<div class="li_top">
<h2 class="s_tit1">Software Tools 목록</h2>
<div class="li_top_sch af">
<Link to={'/AdminSoftwareView/register'} className="sch_bt2 wi_au">Tool 등록</Link>
</div>
</div>
<div class="list_cont list_cont_admin">
<table class="table_ty1 ad_tlist">
<tr>
<th>툴 이름</th>
<th>기능</th>
<th>등록일</th>
<th>기능</th>
</tr>
</table>
<table class="table_ty2 ad_tlist">
{this.state.append_SwtoolList}
</table>
</div>
</article>
</section>
);
}
}
export default SoftwareList;
SwtoolModule.js에 삭제 모듈을 추가하고, delete 쿼리가 있는 mapper id를 연결해준다.
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);
}
}else if(m_typ == 'delbefore'){
//Swtool 관리자 삭제
try {
// Mysql Api 모듈(CRUD)
var dbconnect_Module = require('./dbconnect_Module');
//Mysql 쿼리 호출정보 입력
req.body.mapper = 'SwToolsMapper';//mybatis xml 파일명
req.body.crud = 'delete';//select, insert, update, delete 중에 입력
req.body.mapper_id = 'deleteSwToolsInfo';
router.use('/', dbconnect_Module);
next('route')
} catch (error) {
console.log("Module > dbconnect error : "+ error);
}
}
});
module.exports = router;
SwToolsMapper.xml에 tool 삭제시에 실행될 delete 쿼리를 추가한다.
<?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>
<delete id="deleteSwToolsInfo">
DELETE FROM rtrod.rtrod_swtool
WHERE swt_code = #{is_SwtCd}
</delete>
</mapper>
파일을 추가하고 삭제 버튼을 누르면 아래와 같은 단계로 alert이 노출되고, 삭제한 데이터가 반영되어 리스트에 노출된다.
3. Source tree를 설치 후, gitignore 파일을 설정하고 소스를 업로드한다.
다운로드 경로 : https://www.sourcetreeapp.com/
설치 방법 참고 : https://jintan.tistory.com/47
react, node 코드를 git 레파지토리에 업로드 때 주의사항으로는
gitignore 파일을 꼭 설정한 후에, 파일들을 올려야한다.
아래 두 경로에는 npm 패키지들이 설치되는 경로이다.
개발을 진행할수록 로컬 환경에 따라 패키지 파일들이 조금씩 변하는데,
ignore파일에 추가하지 않는다면 이때마다 수백개가 넘은 파일들의 변경점이 추적될 것이다.
그리고 package.json에 필요한 패키지들이 다 적혀있기 때문에, node경로와 react 경로에서 npm install 한 번씩 해주면
package.json파일을 참조해서 웬만한 패키지들은 설치된다.
# Dependency directories
node_modules/
client/node_modules/
추가로 비밀키, AWS 키, DB 연결정보 등 보안상의 이유로 노출되면 안되는 정보가 담긴 파일들을 추가해준다.
3-1) github.com 에 접속해 Repository를 생성한다.
3-2) gitignore 파일을 생성한다.
.gitignore 글자를 클릭한다.
# Dependency directories
node_modules/
client/node_modules/
추적하지 않을 폴더 경로를 작성하고 Commit한다.
Code 탭을 선택하면 아래와 같이 .gitignore 파일이 추가된 것을 확인할 수 있다.
3-3) Source tree를 실행해 로컬 Repository를 생성한다.
로컬 경로(C:\Users\ljung\OneDrive\문서) 사용할 폴더(taling_github2)를 생성하고, 아래와 같이 원격과 로컬 repository 주소를 입력한다.
[클론] 버튼을 누르면 아래 화면과 같이 github.com에서 커밋한 .gitignore 파일만 추적되는 것을 확인할 수 있다.
3-4) git으로 관리할 폴더/파일들을 세팅한다.
왼쪽 : 새로 생성된 repository / 오른쪽 : 기존 workspace
repository의 .gitignore 폴더 안에있던 .gitignore 파일을 repository경로로 꺼내고, .gitignore폴더는 삭제한다.
기존 workspace에 있는 폴더, 파일들을 이동시키는데 node_modules 폴더는 옮기지 않는다.
(client 폴더 안에 node_modules도 옮기지 않는다)
cmd 창을 열어 node 경로에서 npm install 명령어를
react 경로(../client)에서 yarn install 명령어를 실행한다.
// node 경로에서
npm install
// react 경로에서
yarn install
install을 마치면 node경로와 react경로에 node_modules 폴더가 생성된다.
3-5) Source tree에서 새로 추가된 파일들을 commit > push 한다.
다시 Source tree로 돌아와서 커밋하지 않는 변경사항을 보면, Repository에 추가된 파일들을 확인할 수 있다.
이때 .gitignore 파일에 작성한 /node_modules 경로와 하위 파일들을 추적되지 않아야 한다.
새로 추가된 폴더/파일들을 스테이지에 올려 Commit 한다.
로컬에서 Commit 된 파일들을 원격경로에 Push한다.
github.com 에서 repository를 확인해보면, push한 파일들 리스트를 확인할 수 있다.
'탈잉 강의 자료 > react.js(프론트) + node.js(백앤드) 개발에서 배포까지' 카테고리의 다른 글
4회차_2강 : EC2 서버에 소스파일을 전송 후, 클라우드 서버를 구동한다. (0) | 2020.01.27 |
---|---|
4회차_1강 : EC2 서버 인스턴스를 생성하고, SFTP, SSH 을 사용할 수 있게 세팅한다. (0) | 2020.01.22 |
3회차_2강 : 수정페이지를 구현한다. (text, 이미지, 파일) (0) | 2020.01.16 |
3회차_1강 : 등록페이지를 구현한다. (text, 이미지, 파일) (2) | 2020.01.16 |
2회차_2강 : AWS 가입, RDS mysql 인스턴스를 구동하고 스키마와 테이블을 생성한다. (0) | 2020.01.07 |