본문 바로가기
업무 기록/WEB

프로젝트 요약 정리 SpringBoot 와 Node ExpressJs

by code2772 2023. 10. 21.

[ 목차 ]

    728x90
    반응형

    들어가며

    회사에서 하는 프로젝트는 SpringBoot 와 Node ExpressJs 를 사용하고 있다. 보안적인 기능은 제외하고 웹프로젝트를 간단하게 설명하겠다.  기존 코드는 회사에서 직접 사용하는 코드는 아니고 개인적으로 회사코드를 이해하기 위해 개인적으로 공부한 코드이다.

     

    위 프로젝트는 Spring Boot 부분은 서버 사이드 코드로 데이터베이스와 상호 작용하고 비즈니스 로직을 처리하며, Node.js 부분은 클라이언트 사이드 코드로 사용자 인터페이스를 처리하고 서버와 통신한다. Spring Boot와 Node.js가 서로 협력하여 전체 애플리케이션을 구성하는 기능을 가지고 있다.

    간단하게 업데이트하는 기능인 코드 실행 부분을 설명해보겠다.

     

     

    Node.js 부분

    프론트 .ejs 등록부분 예시

    하단 코드는 가장 먼저 사용자가 보는 코드 프론트 단이다. 여기에 직접 <%=blockList[i].phoneNumber%> 이런식으로 HTML 페이지에 블러온 데이터를 받아올 수 있는데 여기서는 블럭단이 리스트로 많이나와 좀 다르게 js에서 넣기로 하였다. 데이터를 받아오는 방식은 로그인한 아이디의 정보를 세션값을로 불러와 사용하고 있다. 여기서는 그 부분은 생략한다.

      <div class="popup rejection_popup">
          <div class="popup-content" style="width:20%; transform: translate(-50%, -50%);">
              <div class="popup_inner">
                <h1>수정</h1>
                  <div class="list">
                      <ul>
                          <li style="height:70px; vertical-align : middle; margin-top:20px; margin-bottom:20px; ">
                              <label for="title" class="title">기존</label>
                              <div class="txt_area">
                                  <input type="text" id="phonreject_id" name="phonreject_id" maxlength="20" autocomplete="off" style="background-color: #dadada;">
                              </div>
                          </li>
      <li style="height:40px; vertical-align : middle; margin-top:20px; margin-bottom:20px">
                              <label for="upload_img" class="title">수정</label>
                              <div class="txt_area">
                                  <input type="text" id="phonreject_key" name="phonreject_key" maxlength="20" autocomplete="off">
                              </div>
                          </li>
                      </ul>
                  </div>
              </div>
              <div class="btn_area pt_10">
                  <button type="button" class="basic-btn01 btn-purple-bg" id="btnPhoneReg">전송</button>
                  <button type="button" class="basic-btn01 btn-gray-bd popup_close">닫기</button>
              </div>
          </div>
      </div>

     

    JS 부분

    $(document).ready(function() {
    // 수정 버튼 클릭 이벤트 처리
    $("button[name='chk_reject']").click(function() {
      // 해당 줄에 있는 정보 가져오기
      var phoneIdx = $(this).attr('phone_idx');
      var phoneNumber = $(this).attr('phone_number');
      var memo = $(this).attr('memo');
      var regType = $(this).attr('reg_type');
      
      // 팝업 열기
      openRejectionPopup(phoneIdx, phoneNumber, memo, regType);
    });
      
    // 팝업 열기
    function openRejectionPopup(phoneIdx, phoneNumber, memo, regType) {
      // 팝업 내부의 입력 필드에 정보 설정
      $("#phonreject_id").val(phoneNumber);
      $("#phonreject_id").prop("readonly", true);
      $("#phonreject_key").val(""); // 수정할 번호 필드 초기화
      
      // 팝업 열기
      $(".rejection_popup").show();
      
      // 팝업 닫기 버튼 이벤트 처리
      $(".popup_close").click(function() {
    $(".rejection_popup").hide();
      });
      
      // 팝업의 "등록" 버튼 이벤트 처리
      $("#btnPhoneReg").click(function() {
    // 수정할 번호를 가져오고 이 정보를 서버에 전달하는 코드 추가
    var modifiedPhoneNumber = $("#phonreject_key").val();
    // 여기에 수정된 정보를 서버로 전달하는 코드를 추가하세요.
    console.log("수정할 번호: " + modifiedPhoneNumber);
      
    // 팝업 닫기
    $(".rejection_popup").hide();
      });
    }
      });

    처음 HTML 단에서 기존 번호를 보여주고 수정할 내용을 작성하고 서버로 보내기 위한 내용이다. 

     

    $("#btnPhoneReg").click(function (e) {
      var phonreject_key = $('#phonreject_key').val().trim();
    
      if (!phonreject_key) {
        $.alert("수신거부번호를 입력해주세요.", { title: '알림' });
        return;
      }
    
      if (!isMobile(phonreject_key)) {
        $.alert("휴대폰 형식에 맞지 않습니다.", { title: '알림' });
        $('#phonreject_key').val("");
        return;
      }
    
      var jsonArray = [];
      var jsonObj = {};
    
      jsonObj.phoneNumber = (phonreject_key == null) ? "" : phonreject_key;
      jsonObj.memo = "";
    
      jsonArray.push(jsonObj);
    
      $.confirm('수정 하시겠습니까?', {
        em: '',
        title: '확인',
        callEvent: function () {
          // 4. 수정한 데이터를 서버로 전송
          $.ajax({
            url: "/UpBlock",
            type: "POST",
            dataType: 'json',
            data: {
              csrf: csrf,
              block: JSON.stringify(jsonArray),
              modifiedPhoneNumber: phonreject_key, // 수정된 번호 전달
            },
            beforeSend: function () {
              $('.wrap-loading').removeClass('display-none');
            },
            complete: function () {
              $('.wrap-loading').addClass('display-none');
            }
          })
          .done(function (result) {
            if (result.code == "200") {
              $.alert("정상적으로 등록되었습니다.", {
                title: '알림',
                callEvent: function () {
                  $(location).attr('href', '/rejection/view');
                }
              });
            } else {
              $.alert(result.message, {
                title: '알림',
                callEvent: function () {
                  $(location).attr('href', '/rejection/view');
                }
              });
            }
    
            init();
          })
          .fail(function (error) {
            console.log(error);
            $.alert("등록에 실패했습니다.", { title: '알림' });
            init();
          });
        },
        cancelEvent: function () {
          init();
        }
      });
    });

    버튼(#btnPhoneReg)을 클릭했을 때, 수정한 데이터를 서버로 전송하도록 추가된 부분이다. 클라이언트에서 서버로 수정한 내용을 전송하는데, 수정된 내용은 modifiedPhoneNumber 파라미터로 서버로 전달된다.

     

     

    var express = require('express');
    var router = express.Router();
    const request = require('request');
    const common = require('../../config/common');
    
    let time_out = 20000;
    
    router.get('/', function (req, res, next) {
      // 처리할 내용이 있다면 추가
    });
    
    router.post('/', function (req, res, next) {
      // 1. 사용자 로그인 확인
      if (req.session.logined) {
        // 세션 유지
        next();
      } else {
        // 로그인되지 않은 경우 세션 파괴 및 리디렉션
        req.session.destroy();
        res.redirect('/');
      }
    },
    function (req, res, next) {
      // 2. 인증 토큰 갱신
      request({
        uri: `${common.serverUrl}/auth/refresh`,
        method: 'POST',
        timeout: time_out,
        headers: {
          'Authorization': `Bearer ${req.session.access_token}`,
          'Content-Type': 'application/json',
        },
        body: {
          accessToken: req.session.access_token,
          refreshToken: req.session.refresh_token,
        },
        json: true
      }, function (error, response, result) {
        if (error) {
          // 오류 발생
          console.log(error);
          res.json({ code: "500", message: "갱신에 실패했습니다." });
        } else {
          if (result.code == "200") {
            // 갱신 성공
            req.session.access_token = result.data.accessToken;
            next();
          } else {
            // 갱신 실패
            res.json({ code: result.code, message: result.message });
            req.session.cid = result.data.cid;
            req.session.user_id = result.data.user_id;
          }
        }
      });
    },
    function (req, res, next) {
      // 3. 수정할 데이터를 서버로 전송
      const modifiedPhoneNumber = req.body.modifiedPhoneNumber;
      req.session.no080 = result.data.no080;
      var block = (req.body.block == null) ? "" : req.body.block;
    
      request({
        uri: `${common.serverUrl}/update`,
        method: 'POST',
        timeout: time_out,
        headers: {
          'Authorization': `Bearer ${req.session.access_token}`,
          'Content-Type': 'application/json',
        },
        body: {
          user_id: req.session.user_id,
          phone_number: modifiedPhoneNumber,
          no080: req.session.no080,
        },
        json: true
      }, function (error, response, result) {
        if (error) {
          // 오류 발생
          console.log(error);
          res.json({ code: "500", message: "갱신에 실패했습니다." });
        } else {
          if (result.code == "200") {
            // 갱신 성공
            res.json({ code: result.code, message: result.message, data: result.data });
          } else {
            // 갱신 실패
            res.json({ code: result.code, message: result.message });
          }
        }
      });
    });
    
    module.exports = router;

    Spring Boot 에 필요 데이터를 보내주는 부분이다.

    Express.js 라우터: /UpBlock 엔드포인트를 정의하며, POST 요청을 처리한다. 클라이언트에서의 요청을 받아 처리하고, 서버로 데이터를 전달한다.

     


     Spring Boot 부분

    선언부분은 제외하고 진행되는 간단한 부분만 정리하였다.

     

    Controller 부분

     HTTP 요청을 처리하고 RESTful 앤드포인트를 노출한다.

    @PostMapping("update")
        public ResponseVO updateBlock(@RequestBody List<BlockInfoVO> blockInfos,  Errors errors) throws  IOException {
         if(errors.hasErrors()){
             for (ObjectError error: errors.getAllErrors()) {
             System.out.println(error.getDefaultMessage());
             }
             return new ResponseVO("500", "Error");
            }
         String userId = ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
         try {
        
         return blockListService.updateBlockList(userId,  blockInfos);
         }catch (Exception e) {
         e.printStackTrace();
         return new ResponseVO("401", "갱신을 실패하였습니다.");
         }
        }

    해당 로그인한 유저 정보를 불러오고 문제가 없는 경우  blockListService.updateBlockList(userId,  blockInfos); 이 정보를 서비스 단으로 보내고  문제가 있는경우 코드와 에러를 미리 선언한 ResponseVO 의 형식에 맞게 에러코드와 내영을 콘솔에 보여준다.

     

    Service 부분  

    @Transactional("mainTransaction")
    public ResponseVO updateBlockList(String userId, List<BlockInfoVO> blockInfos) {
    AccountVO account = userProxy.selectAccountInfo(userId);
    if (account == null) {
    return new ResponseVO("500", "잘못된 접근입니다.");
    }
    // if (account.getNo080() == null) {
    // return new ResponseVO("500", "차단리스트를 작성할 수 없습니다.");
    // }
    
    if (account.getNo080() == null) {
    for(BlockInfoVO blockInfo: blockInfos)
    oracleBlockListProxy.deleteBlock(account.getMgwDbName(), userId, blockInfo);
    oracleBlockListProxy.insertBlockList(account.getMgwDbName(), userId, "00000000000", blockInfos);
    } else {
    for (String dbName: dbNames) {
    List<String> userIds = oracleBlockListProxy.selectUserNo080(dbName, account.getNo080());
    for (String id: userIds) {
    for(BlockInfoVO blockInfo: blockInfos)
    oracleBlockListProxy.deleteBlock(dbName, id, blockInfo);
    oracleBlockListProxy.insertBlockList(account.getMgwDbName(), id, "00000000000", blockInfos);
    }
    }
    }
    for(BlockInfoVO blockInfo: blockInfos)
    oracleBlockListProxy.deleteBlock(account.getMgwDbName(), userId, blockInfo);
    
    
    
    return new ResponseVO("200", "SUCCESS");
    }

    로직을 처리하고 업데이트를 하는 부분이다. 기존 Update 문으로 수정을 하면 되지만 해당 참고한 코드의 테이블을 보니 수정할 번호가 PK 로 되어있고 그렇다고 새로운 테이블을 만들게 되면 기존 데이터 관리나 문제가 있어 수정을 하면 Delete후 기존 등록방식으로 Insert를 하기위해 서비스단에서 oracleBlockListProxy.deleteBlockinsertBlocklist를 수행하게 하였다.

     

    DAO 부분

    // 수정 기능 -> 삭제하고 새로 만들어야 한다.
        public void deleteBlock(String dbName,String no080, BlockInfoVO blockInfo) {
         String sql = "DELETE FROM TBL_BLOCKLIST "
         + " WHERE "
         + "  ID = ?"
         + " AND "
         + "  NO_080 = ?" 
         + " AND "
         + " DA_ADDR = ?";
        
            
         jdbcTemplate.update(
         sql,
         blockInfo.getPhoneIdx(),
         no080,
         blockInfo.getPhoneNumber()
        
         );
        }
    
        public void insertBlockList(String dbName, String userId, String no080, List<BlockInfoVO> blockInfos) {
        
         System.out.println("no080:" + no080);
         String sql =  "MERGE INTO " 
              + dbName + ".TBL_CPMREJECTNUM V "
              + " USING (SELECT ? as ID,  ? as DA_ADDR FROM  DUAL) X "
              + " ON (V.ID = X.ID  AND V.DA_ADDR = X.DA_ADDR ) "
              + " WHEN MATCHED THEN " //  -- 존재하는 경우 실행   
              + " UPDATE SET "
              + "  CDATE = SYSDATE, FLAG = 'W' "
              + " WHEN NOT MATCHED THEN " // -- 존재하지 않는 경우 실행
              + " INSERT "
              + " (L.CALLNUM, V.DA_ADDR, V.ID, V.CDATE, V.FLAG) "
              + "  VALUES   ('" + no080 + "', X.DA_ADDR, X.ID, SYSDATE, 'A') ";
    
            
            int result[] = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
    
                @Override
                public void setValues(PreparedStatement ps, int i)
                    throws SQLException {
    
                 BlockInfoVO blockInfo = blockInfos.get(i);
         ps.setString(1, userId);
         ps.setString(2, blockInfo.getPhoneNumber());
         // ps.setString(3, no080);
                }
    
                @Override
                public int getBatchSize() {
                    return blockInfos.size();
                }
            });
        }

     

    기존 테이블을 보니 사용자 아이디난 번호만으로는 동일한 내용이 겹처 3개의 조건으로 일치하면 삭제 후 새로 등록하는 쿼리를 작성하였다. 



    간단하게 업무를 위해 공부한 내용이다.

    반응형