반응형

이더리움 계열의 코인은 대표적으로 이더리움, 이더리움 클래식, 익스팬스 등이 있다.

RPC연결을 하여 월렛을 컨트롤 하기 위해서는 코어에 접근해서 블록을 syncing 해줘야한다.

 

그런 것을 지원해주는 것은 대표적으로 Go-ethereum(geth)과 Parity이다.

 

Geth

Geth는 이더리움 재단(Ethereum Foundation)이 제공하는 공식 클라이언트 소프트웨어로써, Go언어로 개발되었다.

Geth를 처음 시작하면 네트워크 내의 다른 이더리움 클라이언트(노드node라고도 불림)에 연결하는 작업을 먼저 시작하고 블록체인의 전체 사본을 내려받게 된다.

 

Geth는 블록체인의 복사본을 최신 상태로 유지하기 위해 끊임없이 다른 노드와 통신한다. 또한 블록을 채굴하고, 블록체인에 트랜잭션을 추가하고 블록의 트랜잭션을 검증하며 트랜잭션을 실행할 수도 있다. 그리고 RPC를 통해 상호작용할 수 있는 API를 노출하여 서버 역할을 하기도 한다.

 

Parity

패리티(Parity)는 이더리움 프로토콜의 또 다른 구현체이며, 러스트(Rust) 프로그래밍 언어로 개발되었다. 현재 Parity Inc. 라는 기업에서 운영하고 있다.

이더리움 네트워크에 접속할 수 있는 클라이언트 소프트웨어를 개발하는 길은 누구에게나 열려 있으며, C++, 파이썬 및 다른 언어로 작성된 클라이언트도 있다.

 

 

위 2개의 이더리움 프로토콜에 대해서 개발자의 측면에서 설치하고 통신하는 법을 설명해보겠다. (리눅스 기반)

 

코인거래소에서 일해본 개발자라면 알듯이 코인을 상장하려면 아래의 과정을 따라야 한다.

 

1. 해당 코인의 RPC API를 지원하는 소프트웨어를 확인하고 그것을 서버 PC에 설치

2. 그 소프트웨어를 알맞은 명령어를 입력하여 실행하여, 지갑 저장 디렉토리, 체인 db 디렉토리를 설정

 (실행 명령어는 보통 bitcoind, parity, geth 등 simple함.)

3. 블록 syncing이 정상적으로 완료되면, 직접 코딩하거나 RPC 라이브러리를 활용하여 서버 PC의 해당 port에 연결

4. 정상적으로 통신이 되면 Web3j같은 RPC 라이브러리에서 제공하는 명령어를 통하여 입출금, 잔액 조회 등의  행동을 함

 

다음화에서는 Geth에 대해서 설치하고 API연결하는 법을 알아본다.

 

 

반응형
반응형

1. SQL Injection

1) ID 입력란에 'or 1=1#', 비밀번호에 pwpwpw 나 아무것이나 치면 True가 뜨면서 admin으로 로그인이 성공함.

  해결책) 유효성 검사를 통해 특수 문자, 기호를 아이디 란에 입력하지 못하게끔 해야함.

 

2. 웹사이트에 malware 업로드

1) 웹사이트에 php 명령문을 먹는 malware 파일을 게시판에 업로드 함.

2) 업로드가 성공하면 그 파일이 업로드 된 경로를 찾아 들어감

3) 그 뒤 주소창에서 ?cmd=cat/etc/passwd를 입력하면 malware php파일 안에서 명령문이 먹으면서 비밀번호들이 유출 됨.

해결책: 파일을 업로드 시 jpg라던지 pdf 라던지의 확장자명을 강제하며 파일 업로드 권한을 아무에게나 주지 않는다.

 

3. 피싱

1) 피싱파일을 리눅스 환경에서 작성. 

2) 이메일로 보내고 피해자가 파일을 실행함. 이 때 견적서 라던지 회사 파일이라던지 사회공학적 기법으로 접근

3) 확장자는 pdf지만 실행하면 나의 리눅스 환경에서 파일이 실행되었다고 연결이 뜸

4) 그 뒤 cmd 환경에서 내가 원하는 대로 피해자의 컴퓨터를 조작 가능.

   하지만 피해자가 컴퓨터를 종료하면 그 pdf파일을 다시 실행하지 않는 이상 원격조종이 안되기 때문에 컴퓨터가 시작될 때마다 악성파일을 실행시키게끔 레지스트리를 설정 해놓아야함.

 

해결책: 의심되는 메일은 열어 보지말며, 의심되는 파일은 다운받지않는다. 그리고 방화벽으로 외부 통신을 차단한다.

반응형
반응형

1. IDS/IPS

- 침입탐지시스템(IDS, Intrusion Detection System)은 ID 절차를 자동화하기 위해 이벤트를 수집, 분석, 처리, 저장하기 위한 기능을 수행한다.

 

• IDS는 다음과 같은 공통적인 기능들을 수행한다.


- 식별된 이벤트와 관련한 정보를 기록한다.
- 식별된 이벤트 중 중요도에 따라 관리자에게 공지한다.
- 특정 기간, 조건을 기반으로한 보고서를 생성한다.

 

 

- 침입방지시스템(IPS, Intrusion Prevention System)은 IDS의 기능과 더불어 식별된 이벤트를 처리 후 차단하는 기능을 수행한다.

 

* MF2: UTM솔루션 / Snort: IDS / SniperOne: IPS

 

2. Snort

- 시그니처 기반 NIDS의 엔진으로 사용되는 대표적인 오픈소스이다. \

- IDS가 수행해야할 기능들에 대한 구성 요소를 포함한다.

- 네트워크 데이터에 대한 수집, 해석, 전처리, 탐지, 로깅, 처리, 저장 등의 기능을 보유한다.

- 주요 기능들을 디코더, 탐지 엔진에 의해 처리한다.

- 탐지 엔진은 정의된 룰셋에 의해 패킷 데이터를 식별, 탐지 후 이벤트를 생성, 로깅한다.


• Snort의 구성은 스니퍼, 패킷 로거, NIDS 모드로 구분한다.


• 스니퍼 모드는 네트워크 데이터를 수집하고 데이터 스트림을 출력한다.


• 패킷 로거 모드는 Snort가 설치된 NIDS 시스템의 하드디스크에 패킷을 기록한다.


• NIDS 모드는 사용자 기반의 룰셋에 의한 네트워크 데이터를 분석하고 처리한다.

 

 

3. 스위치와 라우터

- L2 Ethernet Header를 참조해서 스위칭 하는 장비를 스위치라고 하며 L3 IP Header를 참조해서 스위칭하는 장비를 라우터라고 함.

라우터

- 스위치의 성능이 좋아져 IP Packet을 스위칭하게되는데 이를 L3 스위치라고 함. (라우터와 동일)

L3 스위치

 

 

 

 

4. 방화벽 (firewall)

• 방화벽은 네트워크나 호스트 간 네트워크 트래픽 흐름을 통제하거나 모니터링하는 시스템이다. • 조직의 정보는 대부분 컴퓨터에 저장되기에 정보 보안을 위해 불법적인 접근을 차단해야 한다.

 

• 방화벽은 단일 시스템을 기준으로 외부 인터넷에서의 접근을 제한시키는 것이 사용 목적이다.

 

• 조직은 외부와 내부 네트워크 사이에 방화벽을 설치함으로 불필요하거나 악의적인 트래픽을 거부 혹은 차단한다.

 

• 방화벽의 기능은 접근 통제, 사용자 인증, 감사 및 로그, 프록시, 주소 변환 등을 보유한다.

 

 

• 방화벽은 침입 차단의 대상 네트워크 계층에 아래와 같이 분류 할 수 있다.
- 패킷 필터 방화벽(Packet Filtering Firewall) 

- 상태 기반 패킷 검사 방화벽(Stateful Packet Inspection Firewall) 

- 애플리케이션 수준 방화벽 - 프록시 서버(Proxy-Server) 

- 회선-레벨 게이트웨이(Circuit-level Gateway)

 

방화벽 솔루션 예) Forty gate 등 다수

 

프록시(Proxy) 란? 
프록시란 ‘대리'라는 뜻을 가지고 있는데, 네트워크 기술에서는 프로토콜에 있어서 대리 응답 등을 행하는 개념이다.
보안 분야에서 주로 보안상의 이유로 직접 통신할 수 없는 두 점 사이에서 통신을 할 경우 그 사이에서 중계기로서 대리로 통신을 수행하는 기능을 가리켜 ‘프록시(Proxy)’, 그 중계 기능을 하는 것을 “프록시 서버(Proxy Server)라고 한다.
반응형
반응형

1. UTM(통합 위협 관리, Unified Threat Management)

 - Firewall, VPN, IPS, Anti-virus, Anti-DDoS, 웹필터링 등 다양한 보안기능을 단일 어플라이언스 형태로 통합하여 관리 복잡성을 최소화하고 복합적인 위협요소를 효율적으로 방어하기 위한 통합보안 솔루션

 

- 여러 기능을 수행함으로써 관리의 편의성과 관리비용의 절감을 가져오는 장점이 있는 반면 단일 전용 장비 대비 기능과 성능, 신뢰성에 대한 이슈가 요구 된다.

 

- 단순히 비인가 IP 차단 뿐만 아니라 침입방지시스템(IPS) 기능까지 지원하고 해킹에 대한 탐지, 차단 역할도 수행하게 되며, 이외에도 애플리케이션 필터링, URL 필터링, 안티바이러스(네트워크) 등의 보안 기능을 탑재하고 있다.

 

솔루션 예: MF2

 

UTM의 주요 기능

 

2. WAF (Web Application Firewall)

 •  웹 방화벽은 일반적인 네트워크 방화벽(Firewall)과는 달리 웹 애플리케이션 보안에 특화되어 개발된 솔루션을 의미한다.

 

 •  웹 방화벽의 기본 역할은 그 이름에서도 알 수 있듯, SQL Injection, Cross-Site Scripting(XSS)등과 같은 웹 공격을 탐지하고 차단하는 것이다.


 • 최근의 웹 방화벽은 직접적인 웹 공격 대응 이 외에도, 정보유출 방지 솔루션, 부정 로그인 방지 솔루션, 웹 사이트 위변조 방지 솔루션 등으로 여러가지 기능을 가지고 있다.

 

솔루션 예) MOD Security

 

3. DLP (data Loss Prevention)

기업 구성원과 프로세스, 기술의 결합을 통해 고객 또는 직원에 대한 개인 신원확인 정보(PII), 재무제표, 마케팅 계획과 같은 기업 정보, 제품 계획, 소스 코드와 같은 지적재산(IP)을 포함하는 기밀 정보 등이 기업 밖으로 유출되는 것을 방지하기 위한 솔루션이다.

 

 • 최근 여러 가지 정보 유출 사건이 언론을 통해 알려지면서 정보 손실 방지에 대한 중요성이 대두 되었으며, DLP는 IT 보안만의 문제가 아닌 기업 경영진의 선결과제로 부각되고 있다.


 • 외부의 악의적인 공격으로 인해 정보가 손실되는 경우도 있지만 일반 직원들의 부주의와 기업 프로세스 위반이 원인이 되어 정보가 손실되는 경우가 더 많다.

 

PII(Personally Identifiable Information)란? PII는 개인을 식별할 수 있는 정보를 의미하는데, 나 자신을 증명할 수 있는 이름, 주소, 주민번호, 운전면허 번호, 지문 정보, 신용카드 번호, 생일, 유전자 정보, 전화번호와 같은 정보가 이에 해당한다.

IP(Intellectual Property rights)란? 지식 재산권 또는 지적 재산권을 의미하는 IP는 인간의 창조적 활동 또는 경험 등을 통해 창출하거나 발견한 지식, 정보, 기술이나 표현, 표시 그 밖의 무형적인 것으로서 재산적 가치가 실현될 수 있는 지적창작물에 부여된 재산에 관한 권리를 의미한다.

 

솔루션 예) Somansa, Saferzone

 

DLP 솔루션의 목적

1. 개인 정보 보호

2. 지적 재산권 보호

3. 정보의 가시성 - DLP는 엔드포인트, 네트워크 및 클라우드에서 정보의 이동을 읽고 추적할 수 있도록 해준다.

 

 

DLP와 DRM과의 차이점

 

4. APT 솔루션

시그니처 기반으로 탐지되지 않는 고도화된 공격, 즉 제로데이 공격같이 패턴이 아직 업로드 되지 않았거나, 알려지지 않은 공격에는 취약할 수밖에 없다. 그래서 등장한 제품이 APT 대응 솔루션이다.

 

• APT 솔루션은 신종 APT/악성코드 공격을 탐지/방어하는 솔루션으로 최근 발생하고 있는 랜섬웨어, 자료 유출 사고, 네트워크 마비 등 보안 사고를 미연에 방지하기 위한 정보 보안 시스템이다.


• 사용자단의 행위 기반 방어 제품(EDR)과 네트워크 패킷 분석 기능을 연계로 사용하여 오탐을 최소화하고 정확한 탐지 및 대응을 하는 것이 목적이다.

 

APT 솔루션의 대응 방법

• 네트워크 APT 대응 솔루션은 네트워크 영역에서 완성된 파일이나 데이터를 확인하기 어렵기 때문에 평소의 활동과 비교하거나 네트워크 접속 유형, C&C 서버와의 통신, APT 감염 사이트 접속 등을 분석하는 형태로 탐지를 진행한다.


• Email APT 대응 솔루션은 APT 공격의 주요 침입로로 이메일이 활용되고 있는 점에서 착안해 이메일 보안에 특화된 기능을 제공한다. 보통 이메일 보안 솔루션 독자적으로 또는 전문 장비와 연동해 탐지율을 높이는 방법으로 이메일을 통해 내부로 유입되는 악성코드 및 유해 요소를 차단한다.


• Endpoint APT 대응 솔루션은 주로 안티바이러스(Anti Virus)를 통해 운영된다. 기본적인 골자는 패턴과 시그니처 기반의 백신과 큰 차이 없으나 APT를 고려한 기능이 추가돼 있다. 그 기능으로 동적 분석 기술과 C&C 서버 통신 차단 등의 기능을 대표적으로 꼽을 수 있다.

 

5. ESM 솔루션

Enterprise Security Management(기업 보안 관리)의 약자로, 기업과 기관의 보안정책을 반영, 다양한 보안시스템을 관제, 운영, 관리함으로써 조직의 보안목적을 효율적으로 실현시키는 시스템이다.

 

• 방화벽, 침입 탐지 시스템, 가상 사설망 등의 여러 보안 시스템으로부터 발생한 각종 이벤트를 관리, 분석, 통보 대응 및 보안 정책을 등이 여기에 포함된다


• 또한 기업이 보유한 IT 보안 인프라에 대해 가용성, 무결성, 보안성을 보장하기 위한 전사적인 보안관리 시스템이기도 하다.

 

ESM 솔루션의 주요 기능

 

ESM 솔루션 – 도입 효과

• 각종 보안 솔루션의 알람 및 로그 정보를 중앙 집중화 된 시스템에서 통합관제 및 관리하여, 보안 시스템 관리의 효율성 증대


• 소수의 특정 관리 인원을 할당하여 관리를 담당하게 할 수 있어 비용 효율적인 보안 관리 가능


• 보안 관리자의 교육 시간과 숙달 시간을 최소화


• 각종 로그 정보에 대한 통합 관리를 통해 사전 예방책 마련 가능


• 통계 처리 기능을 이용하여 주기적인 시스템 상태 분석 가능


• 표준화된 보안관리 정책/절차의 수립


• 문제 발생 후 사후조치에서 예방적인 보안관리 체계로의 수립

 

6. SIM (Security Information and Event Management)

빅데이터의 방대한 정보 속에서 단순한 로그 수집 및 분석이 아닌 사후에 추적 등이 가능하도록 상관분석과 포렌식 기능을 제공해주는 지능적 위협에 대한 조기 경고 모니터링 체계이다.


• 기존의 ESM(Enterprise Security Management)의 역할을 보안 영역에서 기업 전반으로 확대시키고, 기업 컴플라이언스 대응 기능을 추가하였다.


• 기업 내 정보시스템의 보안 정보 및 이벤트 관리를 통해 내부 및 외부 위협을 모니터링 함으로써 외부의 공격은 물론, 내부 정보유출 또한 방지한다.


• 네트워크, 하드웨어 및 응용 프로그램에 의해 생성된 보안 경고의 실시간 분석이 가능하다.

 

SIM 솔루션의 필요성

• 기업의 보안정책 중 외부 해킹 공격에 대한 효과적인 차단과 탐지, 모니터링 등의 전체 운영관리, 심층분석, 대규모 확장성, 통합 뷰의 관한 니즈가 증대하였다.


• 매일 생성되는 빅데이터급의 로그 증가로 인한 효율적인 로그 관리 및 분석이 필요해졌다.


• 최근 외부 해킹으로 대량의 개인정보 유출 및 대규모 시스템 장애 사고가 빈번히 발생하는데, ESM과 같은 보안 체계는 APT(Advanced Persistent Threat) 공격 같은 장기적이고 지속적인 특정 표적대상 공격에는 대책 없이 피해가 발생하며 사회공학적 해킹(Social Engineering Hacking)도 함께 동원하기 때문에 사전 탐지가 어려운 상황이다.

 

 

 

반응형
반응형

1. 정보보호의 기본 3대 요소 (C, I, A)

기밀성(비밀성) - Confidentialty

 - 정보는 소유자의 인가에 의해서만 접근이 허용되어야 한다.

 - 인가되지 않은 정보의 공개는 금지되어야 한다.

 

무결성 - Integrity

 - 정보의 정확성, 완전성이 보장되어야 한다.

 - 비인가자에 의한 정보의 변경, 삭제, 생성 등이 발생하지 않아야 한다.

 

가용성 - Availability

 - 정당한 권한이 주어진 사용자에게 정보 서비스가 거부되어서는 안된다.

 - 데이터 백업, 중복성 유지 등을 통해 가용성을 확보한다.

 

 

 

2. 침해 발생 유형

침해 발생 시 대응 순서

 탐지/Assessment -> 헌팅 -> 격리 -> 복구

 

* 위협 탐지: 어떤 위협을 탐지할 것인지 미리 정책 또는 알고리즘이 존재하는 상태에서 동일하게 매칭되는 알람이 발생할 경우 액션을 취하는 것.

* 위협 헌팅: 어떤 위험이 존재하는지 모르는 상태에서 숨어있는 위협을 찾아내는 과정

 

3. APT 공격

 

과거의 해킹방식은 불특정 다수를 대상으로 무차별적 공격을 퍼붓는 것이었음. 하지만 APT 공격은 특정 개인 또는 조적을 타깃으로 삼고, 정보를 파악한 후에 미끼를 던져 침투하는 지능적인 방식.

 

APT 공격 4단계

 1) 타깃에 대해 파악한 정보를 바탕으로 취약점을 찾아내 침투

 2) 내부 시스템에 대한 정보를 검색

 3) 서버 제어권을 획득하여 무력화된 시스템 상의 데이터를 수집

 4) 공격자의 근거지로 수집한 데이터를 전송해 유출

 

APT 공격의 예방

 1) 출처가 명확하지 않은 메일은 열람 금지

 2) 윈도우와 보안시스템을 최신버전으로 유지

 3) 백신프로그램으로 주기적으로 검사

 

4. 맨디언트 (Mandiant)

 - 침해사고 발생 시 조사하고 복구해주는 컨설팅업체 

 - 미공군 특수 수사 요원과 서트(AFCERT) 출신으로 구성

 - 침해진단 서비스, 침해대응 서비스, M&A 리스크 평가 등 다양한 서비스 제공

 

5. 공격자의 Attack Life Cycle

* 스피어 피싱: 무작위로 메일을 보내 정보를 빼내는 것이 피싱이라면, 한 개인이나 조직을 노리는 피싱 공격을 스피어 피싱이라고 함.

* 사회공학 기법: 사내망 침투에 성공하면 직원 행세하며 정보를 수집함. 누가 중요한 정보를 다루는지, 그 사람이 무슨 시스템을 쓰는지 파악함. 이런 식으로 공격 대상의 사회적 맥락을 파악하고 맞춤으로 공격하는 방식을 사회공학 공격이라고 부름. 

 

6. 시스템 및 로그분석

이미징: 주로 FTK Imager 사용

 

* 포렌식 분석: 디지털기기를 매개체로 하여 발생한 특정 행위의 사실관계를 분석하는 것. 디지털 포렌식이라고도 함.

 

7. 침해 재발 방지 방안

침해 단계에 따라 단계 별 대응은 아래와 같다.

인적, 프로세스, 기술적 보안을 아래와 같이 관리해야 한다.

* VPN(Virtual Private Network)은 인터넷에서 2대 이상의 컴퓨터를 로컬 네트워크처럼 연결할 수 있는 보안 터널이다.

일부 국가는 정치적 성향에 따라 특정 웹사이트를 방문하는 사용자를 추적하는데 VPN을 이용하면 세계 어딘가에 위치한 다른 서버를 통해 전송돼 로컬 추적과 해킹 시도를 막는 역할을 한다.

또 액세스한 웹사이트나 서비스에 진짜 인터넷 프로토콜 주소를 감추는 효과가 있다.

VPN을 사용하면 DDOS 공격에 훨씬 안전하다.

 

 

 

반응형
반응형

아까 작성하였던 contentView.jsp에서 수정하기와 삭제하기를 활성화해보겠다.

 

1. 뷰페이지 경로 설정

 

contentView.jsp를 수정해준다.

수정하기를 클릭하면 submit이 되고 삭제버튼을 누르면, /delete?bNO=1처럼 url이 변경된다.

이를 컨트롤러에서 조정해주면 된다.

또한 글번호는 input hidden으로 해줘서 submit이 되었을 때 글번호를 HttpServletRequest에 잘 저장되도록 한다.

 

contentView.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>글내용 보기</title>
</head>
<body>
		<div align="center">
			<h2>글내용 확인</h2>
			<hr width="500" color="green" />
			<table width="500" cellpadding="0" cellspacing="0" border="1">
			<form action="modify" method="post">
			<!-- 값을 보내기 위해 No.는 히든값으로 숨겨둠 -->
			<input type="hidden" name="bNo" value="${contentView.bNo }" />
		
			<tr>
				<td>번호</td>
				<td>${contentView.bNo}</td>
			</tr>
			<tr>
				<td>조회수</td>
				<td>${contentView.bHit}</td>
			</tr>
						<tr>
				<td>작성자</td>
				<td><input type="text" name="bName" value="${contentView.bName }"></td>
			</tr>
						<tr>
				<td>제목</td>
				<td><input type="text" name="bSubject" value="${contentView.bSubject}"></td>
			</tr>
						<tr>
				<td>내용</td>
				<td><textarea rows = "10" name="bContent">${contentView.bContent}</textarea></td>
			</tr>
			<tr>
				<td colspan="2" align="center"><input type="submit" value="수정하기" />
								&nbsp;&nbsp;&nbsp;<a href="list">목록보기</a>
								&nbsp;&nbsp;&nbsp;<a href="delete?bNo=${contentView.bNo}">삭제</a>
								&nbsp;&nbsp;&nbsp;<a href="#">답변</a>
				</td>
			</tr>
			
			
			</form>
			
			
			</table>
			
			
		</div>
		</body>
</html>

 

2. 컨트롤러 설정

BController.java에 리퀘스트맵핑 modify와 delete를 추가한다.

둘다 리턴은 리다이렉트 list로 해준다.

 

BController.java

@RequestMapping(value="/modify", method=RequestMethod.POST)
	//@RequestMapping("/modify")
	public String modify(HttpServletRequest request, Model model) {
		System.out.println("-----modify() 호출");
		
		model.addAttribute("request", request);//model에 글제목, 글내용 들의 정보 주입
		//System.out.println(request);
		
		cmd = new ModifyCmd();
		cmd.service(model);
		
		return "redirect:list";
	}
	
	
	@RequestMapping("/delete")
	public String delete(HttpServletRequest request, Model model) {
		System.out.println("------delete() 호출------");
		
		model.addAttribute("request", request);//model에 글제목, 글내용 들의 정보 주입
		cmd = new DeleteCmd();
		cmd.service(model);
		
		
		return "redirect:list";
	}

 

3. command 클래스 설정

위 컨트롤러에서 메소드를 정의 해줬으므로 bbsCommand패키지에 ModifyCmd.java와 DeleteCmd.java 두 파일을 생성한다.

자바파일은 앞이 대문자로 시작해주는 것에 주의한다.

 

modify와 delete 모두 비슷하다.

받아온 모델을 맵으로 바꾸고 그맵을 HttpServletRequest로 형변환 한뒤 그 안의 bName, bContent 같은 정보를 꺼내어 String으로 저장해준다.

 

그리고 그 객체들을 파라미터로 하여 bDAO의 메소드를 실행시킨다.

bDAO의 메소드는 Cmd 코드를 작성한 뒤 작성해준다.

 

아래 코드를 복사붙여넣기 하자.

 

ModifyCmd.java

package com.spring.bbsCommand;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.ui.Model;

import com.spring.bbsDAO.BDAO;

public class ModifyCmd implements Bcmd {

	@Override
	public void service(Model model) {
		Map<String, Object> map = model.asMap(); //model을 맵형태로 변환
		HttpServletRequest request = (HttpServletRequest) map.get("request");
		//HttpServeltRequest 작동원리
		//사용자가 input에 값을 입력하고 submit을 한다. -> input값의 내용들이 HttpServletRequest에 저장이 된다.
		//서블릿리퀘스트에 저장된 내용을 request.getParameter()와 model.addAttribute()로 view에 뿌려줄 수 있다.
		
		//
		String bNo = request.getParameter("bNo");
		String bName = request.getParameter("bName");
		String bSubject = request.getParameter("bSubject");
		String bContent = request.getParameter("bContent");
		
		BDAO bDAO = new BDAO();
		bDAO.modify(bNo, bName, bSubject, bContent); //위에서 정의한 파라미터를 넣어줌
		
	}
}

 

 

DeleteCmd.java

package com.spring.bbsCommand;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.ui.Model;

import com.spring.bbsDAO.BDAO;

public class DeleteCmd implements Bcmd {

	@Override
	public void service(Model model) {
		
		Map<String, Object> map = model.asMap();
		HttpServletRequest request = (HttpServletRequest)map.get("request");
		
		String bNo = request.getParameter("bNo");
		BDAO bDAO = new BDAO();
		bDAO.delete(bNo);
	}
	
}

 

4. DAO 설정

이번 챕터의 하이라이트이다.

 

BDAO에서 쿼리문을 실행시켜주는 메소드를 만든다. 다행히도 이번포스팅에서는 VO 패키지는 건들지 않는다.

DAO 설정 또한 전 챕터처럼 connection과 preparedStatement를 사용한다.

 

매우 많은 오타를 유발하므로 복사 붙여넣기 또는 crtl+T를 활용하는 것을 추천한다.

 

아래 코드를 BDAO.java에 추가한다.

 

//modify 메소드
	public void modify(String bNo, String bName, String bSubject, String bContent) {
		
		//커넥션과 프리페어드스테이트먼트를 초기에 null로 설정
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		
		try {
			connection = dataSource.getConnection();
			System.out.println("커넥션 확보!! -----------");
			
			String sql = "update mvc_bbs set bName=?, bSubject=?, bContent=? where bNo=?";
			preparedStatement = connection.prepareStatement(sql);//프리페어드스테이트먼트에 접속
			
			//물음표가 4개이므로 1에서 4까지 setString 해줌
			preparedStatement.setString(1, bName);
			preparedStatement.setString(2, bSubject);
			preparedStatement.setString(3, bContent);
			preparedStatement.setInt(4, Integer.parseInt(bNo));
			
			int n = preparedStatement.executeUpdate();//추후 사용
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				//자원반납
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();
				
			} catch (Exception e2){
				e2.printStackTrace();
			}
		}
	}//modify()
	
	
	//delete 메소드
	public void delete(String bNo) {
		Connection connection  = null;
		PreparedStatement preparedStatement = null;
		try {
			connection = dataSource.getConnection();
			
			String sql = "delete from mvc_bbs where bNo = ?";
			System.out.println("asdasd");
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setInt(1, Integer.parseInt(bNo));
			
			int n = preparedStatement.executeUpdate();//추후 사용
			
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();				
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}

 

 

코딩은 이제 끝났다.

내용보기에서 삭제 버튼을 누르면 삭제된 뒤 list페이지로 리다이렉트 된다.

참고 이 delete query문은 현업에선 거의 안쓰이고, 대신에 안보이게 숨긴다. 

 

예를 들어 1번글을 삭제한다고 할 때, delete from mvc_bbs where bNo=1 << 이렇게 쓰지 않고,

use 열 하나를 추가한다.

그리고 update mvc_bbs set use='N' where bNo=1 로 지정하여 리스트에는 use가 N인 행은 보이지 않게 한다.

 

다음으로 수정을 해보자.

아래는 1번 글이다.

 

 

저 내용 부분에 '11111111111111'을 적은 뒤 수정하기 버튼을 누르면 리스트페이지로 나가지고,

다시 들어오면 아래와 같이 수정되어 있는 것을 볼 수 있다.

 

하지만 실제 게시판에는 저런 식으로 수정되는 것이 아니라 처음에는 read만 되게끔했다가 수정버튼을 누르면 수정할 수 있게 바뀐다.

 

그리고 수정 확인을 누르면 반영되면서 다시 read only상태로 바뀐다. 이것은 jquery나 자바스크립트로 textarea 속성을 클릭할 때 바꿔주게 만들면 된다.

 

예를 들어 수정하기를 누르면 readonly="true", 수정이 끝난 뒤 확인버튼을 누르면 readonly="false"가 되는 식으로 하면 된다.

 

 

수정, 삭제까지 한 부분은 아래 파일에 올려 놓았다.

springBBS 수정과 삭제까지.zip
0.07MB

 

 

 

이로써 기본적인 CRUD 기능은 끝났다.

 

다음 챕터에서는 댓글달기 기능을 해본다.

 

 

 

반응형
반응형

리스트 페이지가 보여지지만 현재 클릭했을 때 아무 것도 보이지 않는다.

 

클릭하면 제목, 내용, 작성자, 조회수 등이 뜨게끔 수정해보겠다.

 

수정 후 리스트 페이지는 이렇게 떠야 한다.

 

1.  컨트롤러작성

아래 코드를 BController.java에 삽입해 준다.

	@RequestMapping("/contentView")
	public String contentView(HttpServletRequest request, Model model) {
		
		System.out.println("-------- contentView() 호출 ----------");
		
		model.addAttribute("request", request);
		//HttpServletRequest로 전 전 페이지 정보를 가져와 request에 저장함.
		
		cmd = new ContentCmd(); //bbsCommand에 ContentCmd를 불러와 cmd에 저장
		
		cmd.service(model);//model 파라미터를 service메소드에 넣어서 동작
		
		return "contentView";
	}

 

2. list.jsp 파일 수정

위의 ContentCmd.java를 만들어 주기 전에 리스트 페이지를 수정한다.

 

테이블 안에서 내용을 보여주는 td태그 안의 내용만 수정한다.

<table border="1" cellpadding="0" cellspacing="0" width="500">
		<tr>
			<td>번호</td>
			<td>제목</td>
			<td>작성자</td>
			<td>날짜</td>
			<td>조회수</td>
		</tr>
				<!-- 게시글 목록 가져오기 -->
		<c:forEach items="${list}" var="vo">	
		<!-- ListCmd에서 만들었던 모델 list를 컨트롤러를 통해 받아온다.-->
		<tr>
			<td>${vo.bNo}</td>
			<!-- 제목을 클릭하면 페이지가 넘어가면서 번호 정보를 가져온다. -->
			<td><a href="contentView?bNo=${vo.bNo}">${vo.bSubject}</a></td>
			<td>${vo.bName}</td>
			<td>${vo.bDate}</td>
			<td>${vo.bHit}</td>
		</tr>
		</c:forEach>
		<tr>
			<td colspan="5" align="center"><a href="writeForm">글쓰기</a></td>
		</tr>
		
	</table>

 

3. Cmd 작성

bbsCommand 패키지에 ContentCmd.java 파일을 생성

 

그 뒤 아래의 코드를 입력

 

ContentCmd.java

package com.spring.bbsCommand;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.ui.Model;

import com.spring.bbsDAO.BDAO;
import com.spring.bbsVO.BVO;

public class ContentCmd implements Bcmd {

	@Override
	public void service(Model model) {
		//모델을 받아 맵형태로 바꿔줌.
		Map<String, Object> map = model.asMap();
		
		//1번글을 클릭하면 1번, 2번글을 클릭하면 2번을 전달받아야 함. 컨트롤러의 리퀘스트가 맵안에 있다. 이것을  HttpServletRequest로 저장
		HttpServletRequest request = (HttpServletRequest)map.get("request");
		
		String bNo = request.getParameter("bNo");
		
		//dao 불러오기
		BDAO dao = new BDAO();
		
		//조회수증가와 내용가져옴
		BVO bVo = dao.contentView(bNo);
		
		//모델에 추가
		model.addAttribute("contentView", bVo);
	}

}

 

4. BDAO에 contentView 추가

위에서 dao의 contentview() 메소드를 사용하였으므로 BDAO에 그 메소드를 정의해줘야한다.

 

BDAO.java에 contentView메소드를 추가

public BVO contentView(String bbsNo) {
	//return하는 bVo가 VO에서 가져온 것이므로 BVO를 타입으로 사용함
	//String bbsNo가 	bNo임
	
		//조회수 로직으로
		addHit(bbsNo);
		
		BVO bVo = null;
		
		//많이 보던 형식 커넥션, 프리페어드, 리절트셋.  데이타소스  >> 그뒤 sql
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		
		try {
			connection = dataSource.getConnection();
			
			String sql = "select * from mvc_bbs where bNo = ?";
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setInt(1, Integer.parseInt(bbsNo));
			resultSet = preparedStatement.executeQuery();
			
			if(resultSet.next()) {
				int bNo = resultSet.getInt("bNo");
				String bName = resultSet.getString("bName");
				String bSubject = resultSet.getString("bSubject");
				String bContent = resultSet.getString("bContent");
				Timestamp bDate = resultSet.getTimestamp("bDate");
				
				int bHit = resultSet.getInt("bHit");
				int bGroup = resultSet.getInt("bGroup");
				int bStep = resultSet.getInt("bStep");
				int bIndent = resultSet.getInt("bIndent");
				
				//값을 가져왔으니 bVo에
				
				bVo = new BVO(bNo, bName, bSubject, bContent, bDate, bHit, bGroup, bStep, bIndent);
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			//finally에 클로즈 처리
			
			try {
				if(resultSet != null) resultSet.close();
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();
				
				
			} catch (Exception e2) {
				e2.printStackTrace();
			}
			
			
		}
		
		return bVo;
	}//contentView()

 

5. BDAO에 클릭하면 조회수가 증가 하는 메소드를 만든다.

 

BDAO.java에 아래 코드 입력

//조회수 늘어나는 로직
	private void addHit(String bNo) {
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		
		try {
			connection = dataSource.getConnection();
			String sql = "update mvc_bbs set bHit = bHit + 1 where bNo = ?";
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setString(1, bNo); //1은 첫번째 물음표 값을 입력
			
			int n = preparedStatement.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();
				
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}//addHit()

 

6. contentView.jsp 생성

그 뒤 view폴더에 contentView.jsp를 만들어 아래코드를 입력

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>글내용 보기</title>
</head>
<body>
		<div align="center">
			<h2>글내용 확인</h2>
			<hr width="500" color="green" />
			<table width="500" cellpadding="0" cellspacing="0" border="1">
			<form action="" method="post">
			<tr>
				<td>번호</td>
				<td>${contentView.bNo}</td>
			</tr>
			<tr>
				<td>조회수</td>
				<td>${contentView.bHit}</td>
			</tr>
						<tr>
				<td>작성자</td>
				<td><input type="text" name="bName" value="${contentView.bName }"></td>
			</tr>
						<tr>
				<td>제목</td>
				<td><input type="text" name="bSubject" value="${contentView.bSubject}"></td>
			</tr>
						<tr>
				<td>내용</td>
				<td><textarea rows = "10" name="bContent">${contenctView.bContent}</textarea></td>
			</tr>
			<tr>
				<td colspan="2" align="center"><input type="submit" value="수정하기" />
								&nbsp;&nbsp;&nbsp;<a href="list">목록보기</a>
								&nbsp;&nbsp;&nbsp;<a href="#">삭제</a>
								&nbsp;&nbsp;&nbsp;<a href="#">답변</a>
				</td>
			</tr>
			
			
			</form>
			
			
			</table>
			
			
		</div>
		</body>
</html>

 

수정하기는 아직 만들지 않았다.

클릭하면 조회수가 1씩 증가하는 것을 볼 수 있다.

 

내용 보여주는 곳 까지 파일로 저장해놨으니 아래 참조

 

springBBS 내용보여주는 곳 까지.zip
0.06MB

반응형
반응형

아래 코드를 ajaxtest.json 파일에 저장한다.

참고로 확장자명이 json이 아닌 js로 해도 무방하다.

 

{
    "aaa": [
        {
            "aab1": "이정수",
            "aab2": "이한수",
            "2ban": "정수향"
        }
    ],


    "bbb": [
        {
            "bbc1": "이선태",
            "bbc2": "이한아"
        }
    ],
    
    
    
    "아하": [
        {
            "aab1": "이정수",
            "aab2": "이한수",
            "2ban": "정수향"
        }
    ],



    "1아하": [
        {
            "aab1": "이정수",
            "aab2": "이한수",
            "하타루": "정수향",
            "1하타루": "1정수향"
        }
    ]
}

 

 

JSON의 형태는 우선 중괄호 {}를 써주고 그안에 카테고리 명을 쓴 뒤 :를 써주고 중괄호를 다시 써서 그안에 키, 밸류값을 넣어준다.

 

아래형태 처럼

{
    "1하하": [
        {
            "aab1": "이정수",
            "aab2": "이한수",
            "2ban": "정수향"
        }
    ]
}

 

그 다음, 아래 코드를 ajaxtest.html 에 넣어준다.

<html>

<head>
    <meta charset="utf-8">
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>

<body>
    <script>
        $(function() {
            
 
            $.ajax({ type: 'get' , 
                    url: 'ajaxtest.json' , 
                    dataType : 'json' , 
                    success: function(data) {
                console.log("접속 성공");
                 
                    } 
                   });
       
        });

    </script>
</body>


</html>

 

위 코드를 실했을 때, 제대로  json 파일을 가져온다면 

아래와 같이 뜬다.

 

 

이제 json의 파일을 가져오는 예제를 해보겠다.

 

 

1. 최상위의 키들을 가져오고 싶을 때 (예:   [aaa, bbb, 아하, 1아하])

 

   console.log("접속 성공"); 아래에 아래와 같이 써준다.

 console.log(Object.keys(data));  

 

 

성공한다면 아래와 같이 나온다.

여기서 aaa만 선택하고 싶을 경우, 첫번째 배열에 있으므로 배열을 선택해준다.

  console.log(Object.keys(data)[0]);  

 

그러면 결과는 aa가 나온다. 

2. "1아하" 같이 최상위 키의 밸류들을 가져오고 싶을 때 

 

아래처럼 입력해준다.

 

console.log(data["1아하"]);

하지만

배열형태로 뜬다.

크롬 console에서는 클릭하면 보이지만, undefined 상태이다. 왜냐하면 1아하 아래는 배열인데 정확한 배열명을 입력해주지 않았기 때문이다.

 

따라서 첫번째 배열을 [0]으로 지정해주면 정상적으로 뜬다.

console.log(data["1아하"][0]);

 

 

여기서 맨마지막 1정수향이 나오도록 해보자

 

  console.log(data["1아하"][0].1하타루);

 

원칙적으로 위코드를 넣어주면 되지만 에러가 뜰것이다.

왜냐면 첫번째 문자가 숫자라서 그렇다.

 

첫번째 문자가 한글이어도 상관없지만 숫자면 제대로 읽어오지 않는다.

 

그럼 1을 빼고 그냥 "하타루"를 입력해본다.

 

console.log(data["1아하"][0].하타루);  

 

 

 

정상적으로 값을 반환해줌을 알 수 있다.

 

 

 

 

 

 

 

 

반응형
반응형

스프링 프레임워크에서 myBatis사용하여 mySQL db연동하는 방법

 

결론적으로 아래와 같이 파일구성이 되야한다.

 

 

예제파일-----

 

jdbcTest2.zip
0.03MB

--------

 

그럼 차근차근 진행해본다.

 

 

1. src/main/resources에 파일 생성

 

1) mybatis-config.xml 파일 생성

 

아래 코드를 mybatis-config.xml에 넣는다.

 

이 파일을 생성하여야 log dependency를 넣었을 때 오류가 나지 않는다.

 

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

</configuration>

 

2) log4jdbc.log4j2.properties 파일 생성

 

아래코드를 log4jdbc.log4j2.properties에 넣는다.

log4jdbc에 접속시켜주는 역할을 한다.

 

log4jdbc.log4j2.properties

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

 

3) logback.xml 생성

 

레벨을 설정해주는 파일이다.

 

아래코드를 logback.xml에 넣는다.

 

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>

    log4jdbc-log4j2
	<logger name="jdbc.sqlonly"        level="DEBUG"/>
    <logger name="jdbc.sqltiming"      level="INFO"/>
    <logger name="jdbc.audit"          level="WARN"/>
    <logger name="jdbc.resultset"      level="ERROR"/>
    <logger name="jdbc.resultsettable" level="ERROR"/>
    <logger name="jdbc.connection"     level="INFO"/>
</configuration>

 

아래와 같이 파일들이 생성된다.

2. dependency 주입

 

pom.xml에 스프링, jdbc, 로그 관련 의존성을 주입한다.

 

아래 코드를 pom.xml에 붙여넣기한다.

<!-- db 연결 관련 -->
		<!-- spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
			<!-- mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.38</version>
		</dependency>
			<!-- MyBatis 관련 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.3.1</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.5</version>
		</dependency>
				<!-- log 관련 -->
		<dependency>
			<groupId>org.bgee.log4jdbc-log4j2</groupId>
			<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
			<version>1.16</version>
		</dependency>	
        
        				<!-- sprint-test 관련-->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.2.5.RELEASE</version>
		</dependency>

 

그리고 <properties>태그안에 org.springframework-version을 4.2.3으로 변경시킨다.

	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>4.2.3.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>

 

 

3. VO와 DAO 생성

 

1) VO 생성

com.mysql.domain에 memberVO.java를 생성하여 아래 코드들을 넣는다.

 

MemberVO.java

package com.mysql.domain;

import java.sql.Date;

public class memberVO {

	String userid;
	String userpw;
	String username;
	String email;
	Date regdate;
	Date updatedate;
	
	public String getUserid() {
		return userid;
	}
	public void setUserid(String userid) {
		this.userid = userid;
	}
	public String getUserpw() {
		return userpw;
	}
	public void setUserpw(String userpw) {
		this.userpw = userpw;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public Date getRegdate() {
		return regdate;
	}
	public void setRegdate(Date regdate) {
		this.regdate = regdate;
	}
	public Date getUpdatedate() {
		return updatedate;
	}
	public void setUpdatedate(Date updatedate) {
		this.updatedate = updatedate;
	}
	@Override
	public String toString() {
		return "MemberVO [userid=" + userid + ", userpw=" + userpw + ", username=" + username + ", email=" + email
				+ ", regdate=" + regdate + ", updatedate=" + updatedate + "]";
	}
}

 

2) DAO 생성

 

DAO는 데이터베이스와 연결시켜주는 역할을 한다.

 

1) com.mysql.persistence에 memberDAO.java를 생성하여 아래 코드들을 넣는다.

 

MemberDAO.java

package com.mysql.persistence;

import com.mysql.domain.MemberVO;

// 타입만 명세
	public interface MemberDAO extends GenericDAO<MemberVO, String> {

	}// interface


 

2) com.mysql.persistence에 memberDAOImpl.java를 생성하여 아래 코드들을 넣는다.

 

MemberDAOImpl.java

package com.mysql.persistence;

import org.springframework.stereotype.Repository;
import com.mysql.domain.MemberVO;


@Repository
public class MemberDAOImpl extends GenericDAOImpl<MemberVO, String> implements MemberDAO {

}

 

3) com.mysql.persistence에 GenericDAO.java를 생성하여 아래 코드들을 넣는다.

 

GenericDAO.java

package com.mysql.persistence;

import java.util.List;

public interface GenericDAO<E, K> {

	public K getTime();
	public void register(E vo);
	public E get(K userid);
	public List<E> getList();
	// 아래는 등록, 조회 구현 이후에 할 것임..
	//public void update();
	//public void delete();
	
}// interface

 

4) com.mysql.persistence에 GenericDAOImpl.java를 생성하여 아래 코드들을 넣는다.

 

GenericDAOImpl.java

package com.mysql.persistence;


import java.util.List;
import javax.inject.Inject;
import org.apache.ibatis.session.SqlSession;

// GenericDAO 인터페이스의 추상클래스들을 오버라이딩 해주어야 한다.
// 즉, 여기서 DB와 연결을 하고 SQL문을 처리해주어야 하므로 sessionTemplate을 인스턴스 변수로 갖고서 
// 이를 통해 CRUD 작업을 처리해주면 된다.
public abstract class GenericDAOImpl<E, K> implements GenericDAO<E, K> {

	@Inject
	private SqlSession sqlSession;
	
	private static final String namespace = 
			"com.mysql.mapper.MemberMapper";
	
	@Override
	public K getTime() {
		return sqlSession.selectOne(namespace + ".getNow");
	}

	@Override
	public void register(E vo) {
		sqlSession.insert(namespace + ".register", vo);
	}

	@Override
	public E get(K userid) {
		return sqlSession.selectOne(namespace + ".get", userid);
	}

	@Override
	public List<E> getList() {
		return sqlSession.selectList(namespace + ".getList");
	}

}// class

 

5) com.mysql.persistence에 TimeDao.java를 생성하여 아래 코드들을 넣는다.

 

TimeDAO.java

package com.mysql.persistence;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.inject.Inject;
import javax.sql.DataSource;

import org.springframework.stereotype.Repository;


@Repository
public class TimeDAO {

	@Inject
	private DataSource ds;
	
	
	public String getTime() throws Exception{
		
		Connection conn = ds.getConnection();
		PreparedStatement pstmt = conn.prepareStatement("select now()");
		
		ResultSet rs = pstmt.executeQuery();
		
		rs.next();
		return rs.getString(1);
		
	}// getTime()
	
	
}

 

4. root-context 코드 추가

 

root-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
		
		
	<!-- JDBC의 연결을 처리하는 기능을 가진 DataSource -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
		<property name="url" value="jdbc:log4jdbc:mysql://127.0.0.1:3306/book_ex"></property>
		<property name="username" value="zerock"></property>
		<property name="password" value="12351235"></property>
	</bean>

	<!-- SqlSessionFactoryBean 생성 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 		<!-- mybatis-config.xml 파일이 스프링이 동작할 때 같이 동작하도록 설정한 것. -->
		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
		<property name="dataSource" ref="dataSource"></property>
		<property name="mapperLocations" value="classpath:mappers/**/*.xml"></property>
	</bean>

	<!-- sqlSession 을 SqlSessionTemplate으로 만든다. -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory" />
	</bean>


	<!-- 스프링이 관리하는 패키지에 com.mysql.persistence 를 추가한다. -->
	<context:component-scan base-package="com.mysql.persistence" />
	
</beans>

 

5. mapper 추가

 

resources에 mappers라는 패키지를 추가한 뒤에 memberMapper.xml 파일을 만든다.

 

그 뒤 아래 코드를 붙여넣는다.

 

memberMapper.xml 

<?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="com.mysql.mapper.MemberMapper">

	<!-- 이거에 접근할 때 namespace.id 로 접근한다. -->
	<!-- resultType은 자바의 타입과 매핑되는 것이 있다. 여기선 string이 java.lang.String과 매핑 -->
	<select id="getNow" resultType="string">
		select now()   <!-- 세미콜론 쓰면 안됨 -->
	</select>
	
	<insert id="register">
		insert into tbl_member(userid, userpw, username, email)
		values( #{userid} , #{userpw}, #{username}, #{email} );
	</insert>
	
	<!-- 
			XML Mapper를 작성할 때 매번 resultType을 패키지까지 포함된 클래스명을 작성하는 일이 번거롭다면
			MyBatis의 설정 파일인 mybatis-config.xml을 사용해서 다음과 같이 <typeAliases>를 작성하면된다.
			<typeAliases>
				<package name = "org.zerock.domain"/>
			</typeAliases>		
	-->
	<select id="get" resultType="com.mysql.domain.MemberVO">
		select *
		from tbl_member
		where userid = #{userid}
	
	</select>
	
	<select id="getList" resultType="com.mysql.domain.MemberVO">
		select *
		from tbl_member;
	</select>
</mapper>

 

 

6. src/test/java 폴더의 controller 패키지에 자바파일들 추가

 

AbstractTest.java

package com.mysql.controller;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/* 모든 테스트 파일이 상속할 추상클래스
 * - 어노테이션 자동 추가
 * - Logger 
 * */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
public abstract class AbstractTest {

	protected static final Logger logger = 
			LoggerFactory.getLogger(AbstractTest.class);

}

 

ApplicationContextTest.java

package com.mysql.controller;
/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class ApplictationContextTest extends AbstractTest{

	@Inject
	private ApplicationContext ctxt;
	
	
	@Test
	public void test() {
		logger.info(""+ctxt);
		
	}// test()

}// class

 

DataSourceConnectionTest.java

/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */
package com.mysql.controller;

import static org.junit.Assert.fail;

import java.sql.SQLException;

import javax.inject.Inject;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class DataSourceConnectionTest extends AbstractTest{
	
	@Inject
	private DataSource ds;
	
	@Test
	public void test() throws SQLException {
		logger.info(""+ds.getConnection());
	}// test()

}// class

 

MemberDAOImplTest.java

/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */
package com.mysql.controller;

import javax.inject.Inject;

import org.junit.Test;
import com.mysql.domain.MemberVO;
import com.mysql.persistence.MemberDAO;

public class MemberDAOImplTest extends AbstractTest{

	@Inject
	private MemberDAO dao;
	
	@Test
	public void test() {
		logger.info(""+dao);
	}
	
	@Test
	public void getTimeTest() {
		logger.info(""+dao.getTime());
	}
	
	@Test
	public void registerTest(){
		MemberVO vo = new MemberVO();
		vo.setUserid("fff");
		vo.setUserpw("cccc");
		vo.setUsername("ejg");
		vo.setEmail("ej@g.com");
		
		// DB에 넣고 DB테이블에서 직접 확인해봐야 한다.
		dao.register(vo);
	}
	
//	@Test
//	public void getTest(){
//		logger.info(""+dao.get("wjheoid"));
//	}
//	
//	@Test
//	public void getListTest(){
//		logger.info(""+dao.getList());
//	}
	
}// class

 

SqlSessionFactoryBeanTest.java

/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */
package com.mysql.controller;

import javax.inject.Inject;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class SqlSessionFactoryBeanTest extends AbstractTest{

	@Inject
	SqlSessionFactoryBean factoryBean;
	
	@Test
	public void test(){
		logger.info(""+factoryBean);
	}// test()
	
	@Test
	public void sesseionTest(){
		try {
			logger.info(""+factoryBean.getObject().openSession().toString());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}// test()
	
}// class

 

TimeDAOTest.java

package com.mysql.controller;
/*
 * 2016.04.02 테스트 완료
 * by wjheo
 */

import static org.junit.Assert.fail;

import javax.inject.Inject;

import org.junit.Test;
import com.mysql.persistence.TimeDAO;

public class TimeDAOTest extends AbstractTest{

	@Inject
	private TimeDAO dao;
	
	@Test
	public void test() throws Exception {
		logger.info(""+dao.getTime());
		
	}// test()
}// class

 

아래와 같이 파일들이 구성되어야 함

 

이후 MemberDAOImplTest에서 테스트를 하면 db에 값이 저장됨

 

위에 값들은 vo를 참조하여 만들면 된다.

반응형
반응형

jsonTest.zip
0.02MB

 

백단에서 프론트단으로 데이터를 전송해줄 때 많이 쓰이는 방식이 AJAX이다.

 

온라인상에 이미 API가 존재한다면 js에서 바로 $.ajax를 이용하거나 httpRequest를 이용해서 받아오면 되지만

API가 없다면 백단에서 직접 뿌려줘야 한다. 

 

그 방식을 나열해보면 아래와 같다.

1. Json 라이브러리를 이용하여 데이터값을 만들거나, 다른 페이지의 데이터를 가져와 Json형태로 만들어준다.

2. @RequestMapping과 @ResponseBody로 원하는 데이터를 Return 시켜준다.

3. 자바스크립트 ajax로 값을 받아온다.

4. 받아온 값을 html로 띄워 보여준다.

 

특히, 여기서는 우리가 잘아는 아래 처럼 $.ajax명령어가 아닌 jQuery의 DataTable()을 사용하여 데이터를 테이블형태로 바로 받아오겠다.

<script>
    $(function(){
        $.ajax({
            url:'./time.php',
            success:function(data){
                $('#time').append(data);
            }
        })
    })
</script>

 

1. @ResponseBody 작성

단순하게 {}를 만들어서 저장하는 방법도 있겠지만 명령어를 통해서 아래의 데이터를 작성해보겠다.

여기서는 Json 라이브러리만 제대로 알면 90%는 끝이다.

 

{"data":[{"extn":0,"name":0,"position":0,"office":0,"salary":0,"start_date":0},{"extn":1,"name":1,"position":1,"office":1,"salary":1,"start_date":1},{"extn":2,"name":2,"position":2,"office":2,"salary":2,"start_date":2},{"extn":3,"name":3,"position":3,"office":3,"salary":3,"start_date":3},{"extn":4,"name":4,"position":4,"office":4,"salary":4,"start_date":4},{"extn":5,"name":5,"position":5,"office":5,"salary":5,"start_date":5}]}

 

 

※ Json 파일 작성

 

1) Gson 메이븐 저장

pom.xml에 아래와 같이 의존성 주입

<!--Gson과 Json-->
<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20171018</version>
</dependency>
		
<dependency>
     <groupId>com.googlecode.json-simple</groupId>
     <artifactId>json-simple</artifactId>
     <version>1.1.1</version>
</dependency>
	
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.5</version>
</dependency>

참고로 JSONObject 처럼 대문자 JSON은 Json.org에서 제공하는 라이브러리고 JsonObject처럼 소문자 Json은 구글에서 제공하는 Gson이다.

보통 Gson을 많이 쓴다.

 

2) Json 형태 만들기

위의 데이터 형태를 보면 맨 바깥쪽에 {}로 중괄호가 있고 그안에 data:[{배열1},{배열2},{배열3}] 가 있는 형태이다.

 

즉, 맨 상위의 형태는 data와 array로 나눠진다.

따라서 맨위의 json object인 obj1에는 data와 array가 가게끔한다.

 

그 뒤 obj2로 데이터1, 데이터2, 데이터3을 만들어서 이것을 통틀어 jsonArray로 묶어서  맨위의 json object인 obj1에 저장해줄 것이다.

 

아래 코드에 주석으로 설명 써놓았다.

 

Gson 사용

@RequestMapping(value = "/aa", method = RequestMethod.GET)
	@ResponseBody
	public String home3() {
		
		//상위 오브젝트 생성
		JsonObject obj1 = new JsonObject();
		//data: 뒤에 들어갈 값인 jArray 생성
		JsonArray jArray = new JsonArray();
		
		//배열생성, jArray의 0번째 배열에 쭈루룩, 1번째 배열에 쭈루룩~
		for(int i=0; i<6; i++){
		
			JsonObject obj2 = new JsonObject();
			//obj2는 반드시 for문 안에 놓아야 한다. 그래야 중복이 안생긴다.
			
			obj2.addProperty("name",i);
			obj2.addProperty("position",i);
			obj2.addProperty("salary",i);
			obj2.addProperty("start_date",i);
			obj2.addProperty("office",i);
			obj2.addProperty("extn",i);
			
			jArray.add(obj2);

		}
		
		//마지막으로 최상위의 jsonObject에 data와 jArry를 넣어준다.
		
		obj1.add("data", jArray);
		
		String resp = obj1.toString();
		
		return resp;
	}

 

Json.org는 add를 put으로만 바꾸어주면 된다. 둘중 무엇을 쓰던 상관 없다.

 

Json.org 사용

@RequestMapping(value = "/bb", method = RequestMethod.GET)
	@ResponseBody
	public String home5() {
		
		//상위 오브젝트 생성
		JSONObject obj1 = new JSONObject();
		//data: 뒤에 들어갈 값인 jArray 생성
		JSONArray jArray = new JSONArray();
		
		//배열생성, jArray의 0번째 배열에 쭈루룩, 1번째 배열에 쭈루룩~
		for(int i=0; i<6; i++){
		
			JSONObject obj2 = new JSONObject();
			//obj2는 반드시 for문 안에 놓아야 한다. 그래야 중복이 안생긴다.
			
			obj2.put("name",i);
			obj2.put("position",i);
			obj2.put("salary",i);
			obj2.put("start_date",i);
			obj2.put("office",i);
			obj2.put("extn",i);
			
			jArray.put(obj2);

		}
		
		//마지막으로 최상위의 jsonObject에 data와 jArry를 넣어준다.
		
		obj1.put("data", jArray);
		
		String resp = obj1.toString();
		
		return resp;
	}

데이터가 없어서 밸류값을 i로 해놨지만 저 for문 안에서 얼마든지 다른 곳의 데이터를 가져와서 저장할 수 있다.

이때 get(i) 메소드가 많이 쓰인다.

 

이렇게 리턴을 해주고 주소창에 localhost:8080/aa 라고 치면 아래와 같이 나오면 성공이다.

2. JSP와 스크립트 작성

스크립트로 /aa주소에서 데이터를 받아와서 JSP에 띄워준다.

스크립트는 아래에 위치하는 것이 좋다.

 

테이블 id는 example로 해두고 jquery에서  $('#example').DataTable({ })를 사용해서 데이터를 쭈루룩 입력해준다.

 

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<meta charset="utf-8">
      <script src='https://code.jquery.com/jquery-3.3.1.min.js'></script>
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.css">
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.js"></script>
</head>

<body>
<table id="example" class="display" style="width:100%">
        <thead>
            <tr>
                <th>Name</th>
                <th>Position</th>
                <th>Office</th>
                <th>Extn.</th>
                <th>Start date</th>
                <th>Salary</th>
            </tr>
        </thead>

    </table>

<script>
  $(document).ready(function() {
    $('#example').DataTable( {
        "ajax": "/aa",
        "columns": [
            { "data": "name" },
            { "data": "position" },
            { "data": "office" },
            { "data": "extn" },
            { "data": "start_date" },
            { "data": "salary" }
        ]
    } );
} );  
    
</script>
</body>
</html>

 

주소창에 localhosot를 치면 아래와 같이 나오면 성공.

 

 

 

 

반응형

+ Recent posts