Translate

2018년 9월 17일 월요일

[jQuery] 채팅 스크롤 구현 (최하단 자동 포커싱 + 이동 버튼 및 안 읽은 수 표시)


Laptop
운영체제 Windows 10 Home 64bit
브라우저 Chrome 버전 68.0.3440.106

채팅창처럼 수시로 행이 늘어나는 table의 경우 몇몇 편의상의 스크롤 제어가 필요하다.
일단 기능 자체는 메신저 텔레그램에서 영감을 많이 얻었다.

수행하는 기능은
1. 새로운 행 추가 시 자동으로 부드럽게 최하단 스크롤
2. 이전 기록으로 (위로) 스크롤 시 다시 보던 위치로 이동할 수 있는 버튼 플로팅
3. 버튼이 떠있는 동안은 자동 스크롤이 되지 않음
4. 버튼이 떠있는 동안 새로운 라인이 추가될 시 안 읽은 수가 표시

html구조는 스크롤을 제어할 div안에 동적 table이 있고, 버튼은 div 두개를 써서 하나는 실제 보이는 버튼, 하나는 버튼이 숨김 상태일 때 가리기 위한 용도이다. 즉, 보임/숨김은 단순히 top 조정으로 제어된다.

결과물은 다음과 같다.
css는 기본적인 것 외에는 거의 적용하지 않았고, 버튼 디자인은 다른 소스를 참고한 것이니 세부적인 건 하단 참고 사이트 링크에서 확인하면 된다.






- 참고 사이트
동적 테이블 추가: https://qkrrudtjr954.github.io/jquery/2018/01/29/jquery-dynamic-table.html

스크롤 애니메이션: http://jamesdreaming.tistory.com/215

슬라이드 버튼: http://brilliantcoding.tistory.com/entry/JQuery-%EC%8A%A4%ED%81%AC%EB%A1%A4%EC%97%90-%EB%94%B0%EB%9D%BC-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C-%EB%90%98%EB%8A%94-%ED%97%A4%EB%8D%94-%EB%A7%8C%EB%93%A4%EA%B8%B0


2018년 9월 8일 토요일

[PostgreSQL] COPY FROM CSV 사용 시 Date, Time Format 지정하기



개발프로그램
Postgresql 9.6


csv파일의 값 형태가 컬럼형에 맞지 않아 직접 넣을 수 없을 때, 
formatting을 해야하는 경우가 있다.
예를 들면 timestamp형 데이터로 09:30:10을 넣어야 하는데
csv에 093010라고 적혀있어서 오류가 뜨는 경우이다.

결론만 말하자면 to_timestamp()를 이용하는 간편한 방법은 없다.

총 3가지가 있는데,
2, 3번의 경우 임시 데이터를 생성하므로 사용할 데이터가 대용량일 경우 
작업 PC의 하드 용량에 어느 정도 여유분이 필요하다는 주의사항이 있다.

사용할 table의 컬럼은 대충
test_table (
id INT4,
date DATE,
time TIMESTAMP)
라는 전제로 하겠다. (time 외 다른 컬럼에 별 의미는 없다)
csv 파일명은 test.csv, 테이블과 동일한 컬럼 형태에 ','로 구분됐다는 전제를 두겠다.


1. 초반에 VARCHAR형으로 선언한 후 ALTER문으로 TYPE 변경하기
일단 VARCHAR형으로 선언하면 문자열이기 때문에 어떤 형식이든 입력은 성공한다.
그리고 to_timestamp()를 써서 컬럼형을 변경하는 방법이다.

장점은 임시적인 컬럼이나 파일이 필요없다는 것,
단점은 동일한 형식의 csv파일을 추가적으로 COPY할 수 없기 때문에
필요할 때는 결국 2 또는 3번 방법을 이용해야 한다는 것이다.

(HEADER는 헤더를 없애고 읽는다는 뜻, ENCODING은 말 그대로 csv 파일의 인코딩이다.)
COPY test_table(id, date, time) FROM 'test.csv'
DELIMITER ','
CSV HEADER ENCODING 'UTF-8';

ALTER TABLE test_table ALTER COLUMN time TYPE TIME USING (to_timestamp(time_char, 'HH24MISS')); 


2. VARCHAR형 임시 컬럼 생성 후 본래 컬럼에 다시 UPDATE하기
예를 들어 time_char라는 임시 컬럼을 만들고 거기에 csv의 자료형을 넣고,
본래 써야 할 time 컬럼은 null로 둔 뒤
UPDATE문을 써서 변경하는 방법이다.

time_char은 이후에 컬럼을 제거해도 되지만
이후에 또 동일한 형식의 csv파일을 추가적으로 COPY할 수도 있을 경우에는
일단 냅두고 UPDATE문에 null 조건을 달아 동일한 작업을 하면 되지 않을까 싶다.

COPY test_table(id, date, time_char) FROM 'test.csv'
DELIMITER ','
CSV HEADER ENCODING 'UTF-8';

UPDATE dtg_data SET time = to_timestamp(time_char, 'HH24MISS');


3. csv 파일 자체를 해당 포맷에 맞게 변환하기
데이터의 용량이 클 경우 무조건 이 방법을 택하기를 권한다.
실제로 나는 csv파일만 약 30GB인 파일들로 작업을 했는데,
하나당 COPY에도 약 3일이 걸리고 UPDATE에도 마찬가지로 3일정도가 걸려서
실제로 많은 시간을 소모했으나
이 방법을 마지막에서야 깨닫고 시도해보니 훨씬 시간이 단축되었다.
(하지만 COPY할때 걸리는 3일은 어쩔 수가 없었던...)

언어는 무얼 쓰든 자유이나, 나는 이전에 Python으로 csv 관련 작업을 한 적이 있어 익숙한 편이라 이것을 택했다.

지금 예제의 프로그램을 써보자면 (csv파일의 위치는 C:/ 바로 아래라고 하자)

import csv
with open('C:\\test.csv', 'r') as csvfile:
    reader = csv.DictReader(csvfile)
    with open('C:\\test2.csv', 'w', newline='') as csvfile2:
        writer = csv.writer(csvfile2, delimiter = ',')
        writer.writerow(reader.fieldnames)
        for row in reader:
            split_time = row['time']
            time = split_time[0] + split_time[1] + ':' + split_time[2] + split_time[3] + ':' + split_time[4] + split_time[5]
            row['time'] = time
            writer.writerow(row.values())

test2의 newline='' 속성은 개행을 없앤다는 뜻이다.
쓰지 않을 경우 각 행들이 모두 한 줄씩의 공백(즉 엔터를 두번 친 모양)을 가진 채 생긴다.

단순히 time값을 한글자씩 쪼개어 사이사이에 ':'를 입력하고 time행을 수정,
그 후 행 단위로 csv를 입력해나가는 간단한 프로그램이다.

이렇게 하면 포맷이 설정된 새로운 test2.csv라는 파일이 형성된다.
(정확히는 측정하지 못했으나 30GB 처리 소요시간이 2~3시간쯤으로 추정된다.)

그리고 앞의 예제들과 마찬가지로 COPY를 쓰면 된다.

COPY test_table(id, date, time) FROM 'test2.csv'
DELIMITER ','
CSV HEADER ENCODING 'UTF-8';

데이터 추가시에도 이와 같이 새로운 csv 파일을 생성하고, COPY하면 된다.

참고 사이트: https://www.postgresql.org/message-id/55BA474E.7080605%40aklaver.com

2018년 9월 7일 금요일

[JSP] _jspService(HttpServletRequest, HttpServletResponse) is exceeding the 65535 bytes limit error 해결법


Laptop
운영체제 Windows 10 Enterprise 64bit
개발프로그램 Eclipse Photon (4.8.0)

말 그대로 서블릿 java 파일이 제한인 65535 bytes (약 64KB)를 초과하여 생기는 현상이다.

해결법은 실행 중인 서버의 web.xml 파일에서

<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>

를 찾아 아래 소스를 추가해준다.

<init-param>
            <param-name>mappedfile</param-name>
            <param-value>false</param-value>
</init-param>

만약  Eclipse + Tomcat 이라면 다음과 같이 바로 찾을 수 있다.


servlet-name값이 default인 것도 있으니 헷갈리지 않게 주의...(그걸로 몇 시간 헤맸다)


원리를 대충 설명하자면 
jsp 내에 html코드가 들어갈 경우 (모든 html인지, jsp와 혼합된 html만인지는 모르겠다)

out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");

이런 식으로  out.write로 변환해 버리는 구조로 되어있는데, 이것을 out.write("\r\n<!DOCTYPE html>\r\n<html>\r\n<head>\r\n"); 처럼 한줄로 바꾸는 별거 아닌 설정이다.

덤으로 마찬가지로 용량을 줄이기 위한 다른 설정들은 다음과 같다.

<init-param>
 <param-name>genStringAsCharArray</param-name>
 <param-value>true</param-value>
</init-param>
<init-param>
 <param-name>trimSpaces</param-name>
 <param-value>true</param-value>
</init-param>

하지만 이것들도 String을 char배열로 바꾸거나 공백을 없애는 등 소소한 설정들이고

사실 가장 적절한 해결법은 jsp 소스에서 최대한 참조로 뺄 수 있는 걸 빼는 거지만 규모가 크다면 매우 번거로운 작업이므로...



참고 사이트:
http://s4-ba.hatenablog.jp/entry/2016/06/19/095937 https://docs.oracle.com/cd/E19146-01/821-1489/ggkhi/index.html

2018년 9월 2일 일요일

[Blogger / Blogspot / 구글 블로그] 로그인 시에만 보이는 태그 만들기 (글쓰기, 글수정 등)




내 블로그로 예를 들어보면 위가 로그인 전, 아래가 로그인 후이다.

자세히 차이점을 찾아보면 왼쪽메뉴 최하단의 글쓰기와 각 글 옆의 펜모양이 보일 것이다.
이렇게 로그인 시에만, 즉 자신에게만 보이는 버튼을 만들어 보자.

사실 기본 블로그 테마들을 이용하면 상단에 navbar라는 게 있어서 글쓰기 버튼에 대한 고민은 하지 않아도 되고,
글 수정 버튼도 기본적으로 있지만,
나처럼 외부 템플릿을 불러왔는데 이것들이 없을 경우에 참고하면 좋은 글이다.

그리고 위치 지정의 경우 스스로의 블로그에 대한 html 소스를 대략 알고 있어야 가능해서,
소스에 대해서만 설명하겠다.

우선 글쓰기 버튼은, 확인해야할 사항이 하나 있다.
blogger.com으로 들어가서 글쓰기 버튼을 누르고 URL을 복사해온다.

https://www.blogger.com/blog/post/edit/★
같은 형식일텐데, ★ 부분은 랜덤한 숫자처럼 보이는 걸로 봐선 아마 계정별로 다를 것이다.

그리고 원하는 위치에 다음 소스를 붙히면 된다. (href 속성 안에 URL를 붙이면 된다)
<span class='item-control blog-admin'>
    <a target='_blank' href='https://www.blogger.com/blog/post/edit/★'>글쓰기</a>
</span>


두번째로 수정 버튼은, 사실 기본 테마에서 그대로 가져온 소스긴 하지만 어쨌든 적어보자면

<b:include data='post' name='postQuickEdit'/>
<b:if cond='data:post.editUrl'>
   <span expr:class='&quot;item-control &quot; + data:post.adminClass'>
       <a target='_blank' expr:href='data:post.editUrl' expr:title='data:top.editPostMsg'>
           <img alt='' class='icon-action' height='18' src='http://img2.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/>
       </a>
   </span>
</b:if>

이건 내부적으로 blogger 자체 태그를 쓰는거라 따로 변경해줄 부분은 없다.
여기도 문자로 바꾸고 싶다면 img 태그 대신 문자를 그대로 쓰면 된다.