개발을 하다 보면 외부 API를 연동할 일이 생긴다. 

까먹지 않기 위해 끄적끄적!

 

예제코드

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

public class TestApi {
    public JSONObject ApiTest(){
        String data = "API 형식에 맞는 INPUT DATA";
        String url = "호출URL";

        JSONObject resultObject = new JSONObject(); // OUTPUT DATA 변수
        try{
            URL apiurl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection)apiurl.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("APIKey", "");  // API 보안키
            conn.setRequestProperty("Content-type","application/json");
            conn.setRequestProperty("Accept","application/json");
            conn.setDoInput(true);
            conn.setDoOutput(true);

            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            wr.write(data);
            wr.flush();
            wr.close();

            StringBuilder sb = new StringBuilder();
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {	// 200
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
                String line;
                while ((line = br.readLine()) != null) {
                    sb.append(line).append("");
                }
                br.close();
            }else {
                sb.append("{\"CODE\" : \""+conn.getResponseCode()+"\"");
                sb.append(", \"REASON\" : \""+conn.getResponseMessage()+"\"}");
            }

            JSONParser jsonParser  = new JSONParser();
            resultObject = (JSONObject)jsonParser.parse(sb.toString());
        } catch (Exception e){
            e.printStackTrace();
        }
        return resultObject;
    }
}

설명

data, url, 메소드 return값은 각자 형식에 맞게 설정!

 

setRequestMethod : GET, POST 요청방식 설정

setRequestProperty : Request header 값 설정

setDoInput :  InputStream으로 서버로부터 응답을 받겠다는 옵션.

setDoOutput : OutputStream으로  데이터를 넘겨주겠다는 옵션.

getResponseCode가 정상일땐 output을 받고, 아닐경우! 응답상태와 응답메세지 받기! 😁

<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/emn178/chartjs-plugin-labels/src/chartjs-plugin-labels.js"></script>

chartjs-plugin-labels을 사용하기 위한 설정

 

 

위와 같은 차트의 라벨에 세 자릿수마다 콤마를 찍고 싶었다.

 

https://chartjs-plugin-datalabels.netlify.app/guide/formatting.html

 

Formatting | chartjs-plugin-datalabels

Formatting Data Transformation Data values are converted to string ('' + value). If value is an object, the following rules apply first: value = value.label if defined and not null else value = value.r if defined and not null else value = 'key[0]: value[ke

chartjs-plugin-datalabels.netlify.app

공식문서와 구글 검색에서는 formatter를 사용하라고 한다.(필자가 못 찾는 걸 수도...)

type : 'pie' 설정이라 그런지. formatter는 먹히지 않았다.

 

2일의 뻘짓. .

// 기존코드
... // 생략
plugins: {
    labels: {
        render: 'value', .. // 생략
        }
    }
}

우연히 눈에 들어온 render = 'value'

// 변경코드
... // 생략
plugins: {
    labels: {
        render: function(data) {
        	console.log(data);
        	return data.value.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
        }, .. // 생략
    }
}

공식문서를 응용하여 함수를 만들어 파라미터를 콘솔로 찍어보니 dataset 객체가 마구 찍히고 있었다.

속는 셈 치고 위와 같이 코딩을 해보니 라벨에 콤마가 잘 찍혔다.

 

 

속이 뻥 뚫리는 기분이다. 🤣

엑셀 다운로드시 날짜 형식의 데이터가 포함되어 있었다.

뷰에서는 YYYY-MM-DD hh:mm (2022-10-20 08:41)으로 잘 보여졌는데, 같은 데이터를 엑셀 다운로드 한 결과 yyyy-mm-dd h:mm (2022-10-20 8:41) 형식으로 보여지고 있었다.

구글링은 해보던 중 mso-number-format를 알게 되었고, mso-number-format형식 중 날짜형식 포맷 방법을 찾아 보았다.

mso-number-format:"mm\/dd\/yy" Date7
mso-number-format:"mmmm\ d\,\ yyyy" Date9
mso-number-format:"m\/d\/yy\ h:mm\ AM\/PM" D -T AMPM
mso-number-format:"Short Date" 01/03/1998
mso-number-format:"Medium Date" 01-mar-98
mso-number-format:"d-mmm-yyyy" 01-mar-1998
mso-number-format:"Short Time" 5:16
mso-number-format:"Medium Time" 5:16 am
mso-number-format:"Long Time" 5:16:21:00

하지만, 내가 원하는 포맷 방식은 나오지 않았다.

반나절을 고민.... 또 고민.

결론적으론 날짜서식을 문자열서식으로 포맷해주었더니 원하는 방식으로 잘 출력된다!!

mso-number-format:"\@" Text

mso-number-format 은 style에 지정해주면 된다!!

<td style='mso-number-format: \"@\";'>2022-10-20 08:46</td>

 

 

정보 마스킹 처리

 

- 실무에서 회원 이름을 마스킹 할 일이 생겼다. ( EX : 이름 → 이*, 이름이 → 이*이, 이름이다  이**다) 

 

SELECT
    IFNULL(
        CASE WHEN CHAR_LENGTH(name) > 2
             THEN CONCAT(SUBSTRING(name, 1, 1),LPAD('*', CHAR_LENGTH(name) - 2, '*'), SUBSTRING(NAME, CHAR_LENGTH(name), CHAR_LENGTH(name)))
             ELSE CONCAT(SUBSTRING(name, 1, 1),LPAD('*', CHAR_LENGTH(name) - 1, '*'))
        END, ''") AS mask_name
FROM 테이블명;

데이터의 길이가 가변적이기 때문에 CASE 문을 사용하여 변환.

CONCAT으로 문자열 합치기.

SUBSTRING으로 문자열 자르기.

LPAD를 사용하여 왼쪽으로 *으로 밀어주기!

 

위와 같은 방식으로 SUBSTRING의 시작위치와 종료위치를 변경하면 휴대폰 번호도 마스킹 가능하다!

 

게시판형 웹사이트를 구현하다 보면 검색 시작일 ~ 검색 종료일을 검색할 때 datePicker로 많이 사용한다.

지난번 프로젝트 때 다 만들어 놓았던 util 함수였는데, 내부망이라서 코드를 다 날려버렸다.

새로 시작한 프로젝트에서도 비슷한 유형의 검색을 하게 되어 추후 사용할지도 몰라 업로드한다.🤣

 

/* utils.js */

let utlls = {
    /**
     * 기준일자 default 셋팅
     * @param fromId
     * @param toId
     */
    searchDateSet : function (fromId = '#do_date', toId = '#do_date1') {
        let nowDate = new Date();
        let setMonth = (nowDate.getMonth()+1).toString();
        let setDay = nowDate.getDay().toString();
        let setDate = nowDate.getFullYear() + (setMonth < 10 ? '0' + setMonth : setMonth) + (setDay < 10 ? '0' + setDay : setDay);  // yyyymmdd
        if(fromId.indexOf('cpn_date') > Number(-1)) {
            setDate = nowDate.getFullYear() + '/' + (setMonth < 10 ? '0' + setMonth : setMonth);    // yyyy/mm
        }
        $(fromId).val(setDate);
        $(toId).val(setDate);
    },

    /**
     * 기준일자 데이트피커 포맷
     * @param fromId : 기준시작일
     * @param toId   : 기준종료일
     */
    datePickerFormat : function (fromId = '#do_date', toId = '#do_date1') {
       if(fromId.indexOf('cpn_date') > Number(-1)){
           $(fromId).datepicker({
               dateFormat: 'yy/mm'
           });
           $(toId).datepicker({
               dateFormat: 'yy/mm'
           });
       } else {
           $(fromId).datepicker({
               dateFormat: 'yymmdd'
           });
           $(toId).datepicker({
               dateFormat: 'yymmdd'
           });
       }
    },

    /**
     * 기준일자 value 체크
     * @param fromId
     * @param toId
     * @param obj
     */
    searchDateValidation : function (fromId = '#do_date', toId = '#do_date1', obj) {
        let fromDate = $(fromId).val();
        let toDate = $(toId).val();

        if(fromDate.replace("/", "") && toDate.replace("/", "") && fromDate > toDate) {
            if(obj.id.indexOf("1") == -1) { // 기준시작일
                alert('기준시작일은 기준종료일보다 빠를 수 없습니다.');
                $(fromId).val(toDate);
            }else {
                alert('기준종료일은 기준시작일보다 늦을 수 없습니다.');
                $(toId).val(fromDate);
            }
        }
    }
}

utils.js를 따로 작성해 주었다. 게시판 형일 경우 비슷하게 날짜를 포맷하는 경우가 많아. 그 경우 파라미터에 default id를 지정해 준다. 포맷 형식이 다른 id는 if문을 사용. * default id값에 #을 포함하여 넣는건 추천하지 않는다. 초보인지라.. 더 좋은 방법이 생각나면 코드 수정을 할 예정....... 피트백도 좋습니다.

 

<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript">
    $(function() {
        utlls.datePickerFormat('#cpn_date', '#cpn_date1');
        utlls.searchDateSet('#cpn_date', '#cpn_date1');
    });
</script>        
<body>
	<input type="text"  id="cpn_date"  readonly name="cpn_date" onchange="utlls.searchDateValidation('#cpn_date', '#cpn_date1', this);"> -
	<input type="text"  id="cpn_date1" readonly name="cpn_date1" onchange="utlls.searchDateValidation('#cpn_date', '#cpn_date1', this);">
</body>

html 코드는 간략하게 작성하였다.

샘플 이미지

 

restApi를 사용하다보면 전송할 데이터가 JSON 안에 배열을 넣어야 하는 데이터일 때가 종종 있다.

그래서 글을 한번 작성해 보려 한다.

 

let id = 'testId';
let key = 'testKey';

let testArr1 = [{"number":2,"color":'red'}];
let testArr2 = new Array();
let pushJson = {
  "number":3,
  "color":'blue'
};
testArr2.push(pushJson);

let params = {
  "id":id,
  "key":key,
  "arr1":testArr1,	// "arr1":[{"number":2,"color":'red'}] 가능
  "arr2":testArr2
};

console.log(params);

JSON 안에 배열 추가

json data 생성시 value값으로 배열을 넣어주기만 하면 된다.

배열 안에 JSON  추가

배열에 생성해논 JSON data를  push() 함수를 사용하여 추가해주었다.

 

params의 모양을 그려보면 아래와 같다.

{
  id: 'testId',
  key: 'testKey',
  arr1: [
    {
      number:2,
      color:'red'
    }
  ],
  arr2: [
    {
      number: 3,
      color: 'blue'
    }
  ]
}

 

console 이미지

 

현재 진행중인 프로젝트에서 파일경로를 취합할 일이 생겼다.

검색을 해보니, cmd로 단축어를 사용해서 검색하는 방법이 있었다.

추후, 또 사용할 일이 생길 수 있으니 남겨 놓으려 한다. (캡쳐를 남기려 했지만, 내부망으로 막혀있는 구조라... 글로만 씀 ㅠㅠ)

 

윈도우키 + R을 누르면 윈도우 실행창이 실행된다.

그곳에 'cmd' 확인

 

필요한 파일 리스트가 있는 디렉토리로 이동한다. 

드라이브 이동 - 드라이브명: (ex C:)

디렉토리 이동 - cd 디렉토리명

전 디렉토리 이동 - cd ..

디렉토리 파일 확인 - dir

 

파일명 목록

단축어 : dir /b

 

텍스트 파일에 파일명 목록내용 넣기

dir/b > 파일명.txt

 

경로 + 파일명 목록

단축어 : dir /s/b

원하는 확장자만 검색하고 싶을땐 dir /s/b *.확장자명 (ex : dir /s/b *.txt)

 

텍스트 파일에 경로+파일명 목록내용 넣기

dir /s/b > 파일명.txt

 

'IT > 이것저것' 카테고리의 다른 글

[Server] 서버의 구조 이해  (0) 2021.06.11

 

이미지를 올리기 전 미리보기를 구현해보자!

 

전체 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>

    <div id="previewDiv"></div>
    <input type="file" id="imgInput" onchange="readURL(this)">

    <script>
        function readURL(obj) {

            let reader = new FileReader();
            if(!obj.files.length) {
                return;
            }
            reader.readAsDataURL(obj.files[0]);
            reader.onload = function (e) {
                let img = $('<img />');
                $(img).attr('src', e.target.result);
                $('#previewDiv').append(img);
            }
        }
</script>
</body>
</html>

 

우선 제이쿼리를 사용하기 위해 링크를 걸어준다.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

 

body에 div를 선언하고, input 태그에 onchange 이벤트가 발생할 때 스크립트에 만들어 논 함수를 실행한다.

파라미터엔 this를 넣어준다.

this = 해당 태그의 객체

<div id="previewDiv"></div>
<input type="file" id="imgInput" onchange="readURL(this)">

 

파일에 이미지를 업로드하고 클릭을 하게 되면 readURL함수가 실행되고 매개변수로 객체를 받게 된다.

FileReader를 불러오고, 매개변수로 넘어온 값의 길이가 0일 경우 return

readAsDataURL() 함수를 통해 File에서 읽는다.

readAsDataURL() 읽어 온 후 onload가 실행되는데 이때 img태그를 생성하여, img태그에 src를 url로 넣어준 후 div에 img를 추가해준다.

function readURL(obj) {
            let reader = new FileReader();
            if(!obj.files.length) {
                return;
            }
            reader.readAsDataURL(obj.files[0]);
            reader.onload = function (e) {
                let img = $('<img />');
                $(img).attr('src', e.target.result);
                $('#previewDiv').append(img);
            }
        }

스프링에서 controller로 이동시 veiw에서 url로 파라미터를 전달할 수 있는데, 대표적 형태가 2가지 형태가 있다.

1유형 : http://www.test.com/board?seq=1
2유형 : http://www.test.com/board/1

 

@PathVariable 과 @RequestParam어노테이션은 url파라미터로 전달받은 value를 메서드의 파라미터로 받을 수 있게 해주는 어노테이션이다.

 

 

@RequestParam사용법

1유형 : http://www.test.com/board?seq=2
@GetMapping("/board")
public String save(@RequestParam("seq") int seq){
    .....
}

위와 같을 경우 int seq로 들어온 값은 1이 된다.

 

파라미터의 value로 null이 들어오는 것을 방지하기 위해선 아래와 같이 required 설정을 false로 한다. (defualt : true)

String형으로 데이터 타입을 변환한 이유는 seq가 ""이 들어올 경우 NumberFormatException이 발생하게 된다.

@GetMapping("/board")
public String save(@RequestParam(value = "seq", required = false) String seq){
    .....
}

 

 

@PathVariable 사용법

2유형 : http://www.test.com/board/1
@GetMapping("/board/{seq}")
public String save(@PathVariable int seq){
    .....
}

 

위와 같을 경우 int seq로 들어온 값은 1이 된다.

주의할 점은 URL에 특수문자나 구분기호 " , , ` , . " 등을 사용하면 인식을 못한다.

@GetMapping("/board/{seq}")
public String save(@PathVariable("seq") int num){
    .....
}

변수명을 바꿔서 사용하고 싶은 경우 @PathVariable('템플릿 변수명') url로 들어온 템플릿 변수명과 맵핑을 시켜주면 된다.

 

@RequestParam와 @PathVariable 복합 사용법

http://www.test.com/user/user?name=test
@PostMapping("/user/{category}")
public String save(@PathVariable("category") String category, @RequestParam(value = "name", required = false) String name){
    ....
}

위와 같이 코드를 실행하게 되면 category = user, name = test가 된다.

회원가입이나 value 체크를 할 때 정규식을 많이 사용하게 된다.

자주 사용할만한 함수를 모아서 한곳에 모아두면 편리해진다!

 

value 체크를 위한 js코드 ( join-util.js )


var joins = {
    /**
     * 공백체크
     * @param str
     * @returns {boolean}
     */
    nullCheck : function (str){
        if((!str)){
            return true;
        }
        return false;
    },
    /**
     * 아이디체크
     * @param str
     * @return {boolean}
     */
    idCheck : function (str){
        var check = /^[A-Za-z0-9+].{3,25}$/;
        if((!str) || (!check.test(str))){
            return true;
        }
        return false;
    },
    /**
     * 길이체크 : 2글자 이상 ~ 10글자 이하
     * @param str
     * @returns {boolean}
     */
    lenCheck : function (str){
        var check = /^[가-힣]{2,10}$/;
        if((!str) || (!check.test(str))){
            return true;
        }
        return false;
    },
    lenCheck2 : function (str){
        if((!str) || (str.length < 2)){
            return true;
        }
        return false;
    },
    /**
     * 숫자 확인
     * @param num
     * @return {boolean}
     */
    numberCheck : function (str){
        console.log(str);
        var check = /[0-9]/g;
        if((!str) || (!check.test(str))){
            return true;
        }
        return false;
    },

    /**
     * 이메일 형식 확인
     * @param str
     * @return {boolean}
     */
    emailCheck : function (str){
        var check = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+$/;;
        if((!str) || (!check.test(str))){
            return true;
        }
        return false;
    },

    /** 패스워드는 6 ~ 20자 이내 영문 대,소문자, 숫자, 특수문자 혼합 입력
     * 패스워드 형식 확인 : 영문/숫자/특수문자 조합 10자 이상
     * @param str
     * @return {boolean}
     */
    passwordCheck : function (str){
        var check = /^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-])(?=.*[!@#$%^*+=-])(?=.*[0-9]).{6,20}$/;
        if((!str) || (!check.test(str))){
            return true;
        }
        return false;
    },
    /**
     * 패스워드 재확인
     * @param str
     * @param str2
     * @return {boolean}
     */
    pwConfirmCheck : function (str, str2){
        if((!str2) || (str != str2)){
            return true;
        }
        return false;
    },
    /**
     * 전화번호 하이픈처리
     * @param obj
     */
    phoneKeyup : function (obj) {
        $(obj).val($(obj).val().replace(/[^0-9]/g, "").replace(/(^02|^0505|^1[0-9]{3}|^0[0-9]{2})([0-9]+)?([0-9]{4})$/, "$1-$2-$3").replace("--", "-"));
    },

    /**
     * 전화번호 확인 : hipen 포함
     * @param str
     * @returns {*}
     */
    phoneCheck : function (str){
        var check = /^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})$/;
        if((!str) || (!check.test(str))){
            return true;
        }
        return false;
    },

    /**
     * 전화번호 하이픈 제거 : DB 저장시
     * @param str
     * @return {*}
     */
    hyphenClear : function (str){
        return str.replaceAll("-", "");
    },


}

 

view에 가져와 사용을 해보자!

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <script src="/js/jquery-2.2.4.min.js"></script>
    <script src="/js/common/join-util.js"></script>
    <script src="/js/bootstrap.min.js"></script>

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" />
    <link href="/css/bootstrap.min.css" rel="stylesheet">


    <title>Title</title>
    <script type="text/javascript">
        function onChangeConfirm(obj, join, text) {
            if($(obj).val().trim().length > 0){
                if(join($(obj).val().trim())) {
                    $(obj).siblings().text(text);
                    confirmFail(obj);
                    return true;
                }else{
                    confirmSuccess(obj);
                    return false;
                }
            }else if($(obj).val().trim().length === 0){
                $(obj).removeClass('is-invalid');
                $(obj).removeClass('is-valid');
                $(obj).siblings().text("");
            }
        }

        function confirmFail(obj){
            $(obj).addClass('is-invalid');
            $(obj).siblings().addClass('invalid-feedback');
            $(obj).focus();
        }

        function confirmSuccess(obj){
            $(obj).removeClass('is-invalid');
            $(obj).addClass('is-valid');
        }
    </script>
</head>
<body>
<div class="form-group">
    <label for="userId" class="col-sm-2 control-label">아이디</label>
    <div class="col-sm-10">
        <input type="text" class="form-control" name="userId" id="userId" placeholder="아이디" data-minlength="4" required
               onchange="onChangeConfirm(this, joins.emailCheck, '이메일형식으로 입력해 주세요.')">
        <div class="float-right"></div>
    </div>
</div>
<div class="form-group">
    <label for="userName" class="col-sm-2 control-label">이름</label>
    <div class="col-sm-10">
        <input type="text" class="form-control" name="userName" id="userName" placeholder="이름" data-minlength="2" required
               onchange="onChangeConfirm(this, joins.lenCheck, '이름은 두글자 이상 입력해 주세요.' )">
        <div></div>
    </div>
</div>
</body>
</html>

 

 

 

코드를 분석해 보자면..

<script src="/js/jquery-2.2.4.min.js"></script>

extarnal 방식 으로 JS파일을 불러온다.

 

 

<input type="text" class="form-control" name="userId" id="userId" placeholder="아이디" data-minlength="4" required
       onchange="onChangeConfirm(this, joins.emailCheck, '이메일형식으로 입력해 주세요.')">
<div class="float-right"></div>

input 태그에서 onchage이벤트 발생시 onchageConfirm 함수가 실행되고, 함수의 파라미터로 this(태그 자체), util안의 함수, 문자열을 받게 된다.

 

 

function onChangeConfirm(obj, join, text) {
    if($(obj).val().trim().length > 0){
        if(join($(obj).val().trim())) {
            $(obj).siblings().text(text);
            confirmFail(obj);
            return true;
        }else{
            confirmSuccess(obj);
            return false;
        }
    }else if($(obj).val().trim().length === 0){
        $(obj).removeClass('is-invalid');
        $(obj).removeClass('is-valid');
        $(obj).siblings().text("");
    }
}

 

onchageConfirm()

- $(obj).val() : this의 value

- join : util안의 함수(emailCheck) == 파라미터로 받았기 때문에 콜백 함수가 된다.

/**
 * 이메일 형식 확인
 * @param str
 * @return {boolean}
 */
emailCheck : function (str){
    var check = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+$/;;
    if((!str) || (!check.test(str))){
        return true;
    }
    return false;
}

if문 안에 함수의 파라미터로 $(obj).val()를 넣어주면 함수의 실행에 따라 boolean값을 반환 받게 된다.

 

true를 반환 받을 시

$(obj).siblings() : this의 형제요소 == <div class="float-right"></div> 의 text에 파라미터로 받은 문자열을 넣어주면, 조건 실행시 text가 보여지게 된다.

 

실행화면

 

+ Recent posts