반응형

  자 여태까지 만들었던 프로젝트를 아마존에 배포할 시간이다.

https://extsdd.tistory.com/113

 

[Spring/eGov ] #8 이클립스에서 마리아DB 데이터 조회하기 / MyBatis / 컨트롤러 Controller / 서비스 / DAO /

https://extsdd.tistory.com/112 [Spring/eGov ] #7 스프링, 전자정부프레임워크 샘플 예제- 마이바티스(MyBatis)로 마리아 DB 연동하기 / https://extsdd.tistory.com/102 [Spring/eGov ] #6 웹 서비스 만들기 2..

extsdd.tistory.com

  여기까지 못따라온 사람은 위 글까지 마치고 오면 될 것 같다.

 

메이븐 프로젝트 / Maven

 

 

  자 지금까지 정자정부프레임워크(스프링)으로 간단한 서비스를 만들었고, 그걸 내 서버에서 돌려봤다. 서버에서 돌리기위해 이클립스상에서 Run을 누르면 JDK환경에서 실행할 수 있는 최소 실행파일만 생성되어 로컬 톰캣에 올라가는 것이지만. 이제 정식으로 내 서비스를 실제 서버에 올리려면 그 서버가 받아 들일 수 있게 만들어야한다.

 

  이게 바로 패키징 과정이라고 하며 Build라고도 부른다. 갤럭시폰을 만들기위해 삼성전자에서 액정 따로 사고, 메인보드사고, 저장장치사고 전선으로 대충 이어서 전원들어오고 작동시켜보면서 테스트는 해보자. 실제로 이런식으로 고객에게 팔지는 않는다. 그걸 다 다듬어서 플라스틱 외관에 담아 우리가 아는 핸드폰의 모양으로 만들어 고객에게 판다. 이거랑 똑같은거다. 소프트웨어도 실제로 완성을 하면 Build 과정을 통해 이걸 다른 JAVA환경에서 실행할 수 있게 만들어 줘야 하는 것이다.

 

 

 

 

 

  메이븐, 많이 들어봤을 것이다. 보통 라이브러리 관리할 메이븐 dependency를 이용해 간단하게 추가하니까 말이다. 맞다 보통 알고있다시피 메이븐이 간단하게 라이브러리 주소만 디펜던시로 걸어주면 알아서 그 라이브러리의 최신본을 따오는 기능을 수행한다. 하지만 더 중요한 기능이 있다.

 

  바로 이 프로젝트를 패키징하여 빌드하고 이 산출물을 통해 배포할 수 있는 배포 툴인건다. 메이븐 프로젝트라는 단어도 들어봤을 것이다. 혹시 그래들이라고도 들어봤나..!? 보통 메이븐과 그래들을 쌍쌍바처럼 같이 다니는걸 들어봤을텐데 이게 다 최종 산출물을 만들어주는 프레임워크의 이름인거다. 자. 결론만 말하자면 이 메이븐이라는 친구가 우리가 EC2서버에서 우리 프로젝트를 돌릴 수있도록 완성품을 만들어주는 역할이라고 생각하면 된다.

 

1. Maven Clean

 

 

 

  자 일단 처음부터 깔끔하게 시작하기 위해 Maven Clean과정을 통해 깔끔하게 없애주자. 본인 프로젝트 오른쪽마우스(1)를 누른뒤 Run As를 누르고(2) Maven clean을 눌러주자(3)

 

 

  여기서 오류나는 사람은 없을꺼고, 보통 다 빌드 성공이 뜰 것이다.

2. Maven Test

 

  자 이제 메이븐을 밀어줬으니 빌드 할 준비가 되었는지 확인하기 위해서 Maven Test를 진행해주자.

 

 

  위 설명대로 이번엔 Maven test를 눌러보자!

 

 

  짜잔~ 빌드 성공

TroubleShooting

 

 

 

  혹시나 저런식으로 JRE, JDK에 관련된 오류가 나타나면 아래 포스팅을 참조해 해결하고오자!

https://extsdd.tistory.com/122

 

[Spring/eGov] 메이븐 빌드 실패 / Failed to execute goal / Perhaps you are running on a JRE rather than a JDK

자 메이븐 빌드를 했는데 위처럼 JRE대신 JDK를 써보라는 오류가 발생했다. 원인은 간단하다. JRE로 빌드를 못한다는거다. JDK로 경로를 다시 잡아주면 된다. 1. Installed JREs 재설정 이클립스 상단 윈�

extsdd.tistory.com

  나도 저 오류가 나타났어 잠시 헤멨었다 ㅎㅎ

 

3. Maven Install

 

  자 다시 본론으로 와서, 이제 진짜 Maven 배포파일을 만들어보자!

 

 

  과정은 똑같고 빌드할 프로젝트를 눌러 Maven Install 버튼을 눌러주자..!

 

 

  그럼 글자들이 쭈루룩 지나가면서 4초만에 완성이 됐다! Build SUCESS!

4. 배포파일 확인

 

 

 

  빌드후 달라진 점이라면 target 폴더에 .war 파일이 생성됐다..! 이게 배포파일이고 이걸 톰캣 폴더에 갔다놓고 재부팅하면! 내가만든 서비스가 시작된다!

 

  저 배포파일의 위치를 잠깐 알아둬야하는데

 

 

  해당 .war 파일을 오른쪽마우스 클릭후 Properties를 눌러주자.

 

 

  저기 로케이션에 나온 경로를 복사해두던지 아님 어디 메모장 같은데 메모를 해놓는다.

5. FileZilla SFTP를 이용한 배포

 

  배포방법에는 수많은 종류가 있다. GIT으로 EC2 인스턴스에 소스를 받아서 Maven Wrapper로 그 자리에서 빌드하는 방법이 있고, 비슷하게 그래들로 하는 방법도 있고, 젠킨스 같은 툴을써서 배포를 더 쉽게하는 방법이 있지만, 나는 소스 수정이 많지 않아 가장 직관적인 방법은 FTP로 직접 배포파일을 쏘기로 했다. ㅎㅎ..

 

https://extsdd.tistory.com/121?category=853192

 

[아마존 AWS EC2] EC2 서버 FileZilla로 FTP 접속하기 / Root 계정 접속 / 파일질라 / SFTP

이제 우리가 만든 EC2 인스턴스에 FTP 접속을 시도해보자. FTP 접속 툴로는 대학교때무터 자주 썼던 파일질라로 정했다. 먼저 알아두자면 FTP란 FIle Transafer Protocol 로써 장비간 파일을 주고받는 프로

extsdd.tistory.com

  자 일단 선행되어야 할 것이 있다면, FIleZilla를 다운 및 설치 후, Root 계정으로 EC2 인스턴스에 붙는 과정을 진행해야한다. 위 포스팅을 보면 나와있으니 따라하고 오면 된다.

 

 

  자 시작해보자.

  1. 먼저 화면의 좌측이 내 실제 컴퓨터다. 저기 1번 박스에 위에서 아까 복붙해놓은 .war파일의 경로를 쳐서 찾아가던지, 디렉토리를 눌러서 찾아가던지 알아서 완성된 .war파일이 있는곳까지 가라.

 

  2. 우측화면은 EC2 인스턴스다. 본인들이 설치한 톰캣폴더의 webapps폴더까지 들어가라, 내 포스팅을 보고한 사람들은 아마 폴더를 server에 만들었을 것이다.

 

  3. 우리 컴퓨터에 있는 .war파일을 오른쪽마우스 눌러주자.

  4. 당연히 업로드 버튼을 눌러준다.

 

 

  오오... 퍼센트가 다 차서 전송이 완료되면 우측 EC2 인스턴스에서도 우리가 만든 .war파일을 볼 수 있다.

6. 톰캣 재부팅

 

  이제 톰캣 재부팅을 하면 저 .war파일을 서버가 돌리기 시작한다.

 

 

  우리 서버로 돌아가서 일단 SU 권한으로 접속후 본인들이 만들어놓은 아파치 톰캣폴더의 bin 폴더까지 이동해보자.

cd /server/apache-tomcat-8.5.55/bin

 

  나 같은 경우에는 위 주소에 톰캣을 설치해놨기 때문에 내 포스팅을 보고 온사람들은 위 명령어를 입력하면 톰캣의 bin까지 올 수 있다.

 

 

 

./shutdown.sh

 

  bin폴더까지 왔으면 위 명령어를 이용해 서버를 꺼주자.

 

 

 

./startup.sh

 

  다시 톰캣 시작명령어를 치고 톰캣이 부팅되면, 아까 넣어놨던 .war파일을 인식해 돌리게 된다.

 

7. 결과 확인

 

http://본인AWS아이피주소:8080/CP_service-1.0.0/reqUrl.do?reqParam=3

 

  위 경로를 찍어보자, 주소중 "본인AWS아이피주소" 이칸에 본인 EC2 IP주소를 넣으면 된다. 그리고 :8080은 톰캣 포트고 뒤에 CP_service-1.0.0 이란게 붙었는데 이건 우리가 만든 배포파일인 .war의 이름이기도 하다. 이거 안보이게 하는법은 나중에하도록하고 우리가 전에 만들었던 변수에따라 url을 리다이렉션 해주는 서비스가 정상적으로 작동하는지 확인하자!

 

 

  아마 위와같은 창이 뜨면 성공인거다!. 엥? 에러가발생했는데 왜 성공이야? 할 수 있지만, 이 에러는 우리가 EC2 서버에 설치한 마리아DB에 테이블이랑 데이터를 넣지 않아서 그런거다. 일단 저 화면이 나오는거 자체만으로 WAS는 문제 없이 돌고있다는 것이다. 왜냐하면 내가 만든 reqUrl.do라는 요청에 어떻게든 반응은 나타내고 있으니까! 오늘은 여기까지하고, 다음에 한번 마리아 DB에 값을 넣고, 테스트해보도록 하자.

 

#AWS #EC2 #스프링 #전자정부프레임워크 #메이븐 #프로젝트 #배포 #파일질라 #Maven #Filezilla #Build #install #빌드 #인스톨

 

반응형
  1. 찰도마도 2021.11.05 06:46

    많은 도움 되었습니다. 정말 감사합니다.

반응형

 

 

 

  자 메이븐 빌드를 했는데 위처럼 JRE대신 JDK를 써보라는 오류가 발생했다.

 

  원인은 간단하다. JRE로 빌드를 못한다는거다. JDK로 경로를 다시 잡아주면 된다.

 

1. Installed JREs 재설정

 

 

 

  이클립스 상단 윈도우 버튼(1)을 누른뒤 Preferences버튼을(2) 눌러주자!

 

 

  1. 자바 탭을 누른다.

  2. Installed JREs 탭을 누른다.

  3. 여기를 보면 지금 Path가 JRE로 잡혀있다.. 분명... 나랑 환경설정하면서 JDK도 설치했는데 왜..! JRE로 잡고 있는거야 ㅡㅡ.... 그래서.. 수동으로 Path를 잡아줘야한다.

  4. Add 버튼을 눌러주자.

 

 

  1. 창이나오면 Standard VM으로 나와있을텐데 그냥 두면된다.

  2. 바로 Next를 눌러 넘어가주자.

 

 

  1. 자 여기서 JDK 경로를 잡아달라고 하는데 메뉴명을보면 JRE home이다. 뭐야 ㅡㅡ JDK를 잡으라는거야 JRE를 잡으란거야 생각이 들 것이다. 왜냐면 나도그랬으니까. 이건 JDK폴더 안에 있는 JRE폴더를 잡아주면 된다. 1번 박스에 나온 경로대로 보통 C드라이브-프로그램파일-JAVA폴더를 가면 JDK폴더가 있을것이다. 그폴더를 열어서 그 폴더 내부에 있는 JRE폴더로 잡아주자.

 

  혹시나 JDK가 없는거 같다!! 하는사람은

https://extsdd.tistory.com/49

 

[스프링/전자정부 프레임워크 입문] #3 개발환경 셋팅 / JDK1.8 / 전자정부 프레임워크 설치

1. JDK 설치 2. 전자정부 프레임워크 설치 1. JDK 설치 1. JDK 설치 비전공자들을 위해 JDK가 무엇인지 간단하게 알아보자. 전편 글들을 읽으면 분명 우리가 사용하려고하는 프레임워크는 JAVA 플랫폼 ��

extsdd.tistory.com

  위 포스팅을 참조해 JDK를 설치하면 되겠다.

 

  2. 다시 본론으로 돌아와서, JDK폴더안에있는 JRE경로를 잡아주면 자동으로 2번 박스에 jar파일들이 잡힌다. 뭐 신경쓸건 없다. 그냥 아~ 제대로 인식하는구나~ 하면된다.

  3. Finish버튼을 눌러주자.

 

 

  1. 뚜둔! 이제야 jdk Path가 생겼다 새로 생긴 jdk경로에 체크박스를 해주고 (체크박스 꼭 해야함!)

  2. Apply를 눌러주자!

  3. 이제 Installed JREs 설정은 끝났다. 저 탭 옆에 있는 화살표를 눌러주자.

2. Execution Envirionment 재설정

 

 

 

  1. 마지막 설정이다 아까 설정했던 Installed JREs 하위에 있는 Execution Envirionment 탭을 눌러주자.

  2. 자기가 설치한 JDK의 버전을 따라가면되는데 난 JDK1.8이니 JavaSE-1.8을 선택!

  3. 그럼 아까 추가한 JDK Path를 체크해주자!

  4. 이제 진짜 끝! APply and Close를 눌러주자!

3. 결과 확인

 

 

 

  자 메이븐 빌드가 제대로 되는지 보기위해 일단 백지부터 시작하기 위해서 Maven Clean을 진행해주자

 

 

  일단 Clean은 완료!

 

 

  이제 우리가 추가한 JDK를 제대로 인식하는지 보기위해서 Maven test를 돌려보자!

 

 

 

  우왕..! 빌드 성공!! 아까 문제가 됐던 JRE, JDK 경로 오류는 나타나지 않는다!

 

#스프링 #전자정부프레임워크 #메이븐 #빌드 #실패 #Maven #Build #Failed

 

반응형
  1. 조동동고 2020.09.24 15:06 신고

    정말 잘보고있습니다 감사합니다 도움이 많이 되었습니다.

  2. 월국토공 2020.11.13 12:15

    전자정부 프레임웤 설명한 자료 중에서는 가장 쉽게 설명해 놓으셨네요.
    기본적인 사항을 이해하는데 도움이 많이 되었습니다.
    감사합니다.

  3. 호야 2021.01.19 22:29

    정말 많은 도움이되었습니다.
    감사합니다^^

반응형

 

https://extsdd.tistory.com/113

 

[Spring/eGov ] #8 이클립스에서 마리아DB 데이터 조회하기 / MyBatis / 컨트롤러 Controller / 서비스 / DAO /

https://extsdd.tistory.com/112 [Spring/eGov ] #7 스프링, 전자정부프레임워크 샘플 예제- 마이바티스(MyBatis)로 마리아 DB 연동하기 / https://extsdd.tistory.com/102 [Spring/eGov ] #6 웹 서비스 만들기 2..

extsdd.tistory.com

  자 저번시간까지 우리가 만든 마리아 DB를 내 스프링 프로젝트와 연동했고, 테스트로 데이터도 넣고, 컨트롤러에서 select까지 해보면서 포스팅을 마쳤다.

 

  오늘 알아볼껀 실제로 어떻게 데이터가 오고가는지 간단하게 디버깅을 해보려고한다. 혹시 아직 디버깅이 뭔지 모르는 분들은 아래 포스팅을 보고오면 될 것 같다. 거기에 간단하게 BreakPoint를 설정하고 진행하는 방법이 있으니 이 포스팅에선 굳이 또 한번 더 설명하진 않겠다.

https://extsdd.tistory.com/102

 

[Spring/eGov ] #6 웹 서비스 만들기 2 / 요청 URL 파라미터 가져오기 / Debug 방법 / 디버깅 하는법 / @Model

 

extsdd.tistory.com

1. 중단점(BreakPoint) 설정

 

 

 

  자 우리 컨트롤러에 저 26번 줄에 커서를 대고 Ctrl+Shift+B 단축키를 눌러 중단점을 걸어주자

2. 서버 Debug 모드로 실행

 

 

 

  자 우리가 디버깅을 하려면, 서버도 Debug모드로 켜져있어야 들여다 볼 수 있다. 디버그 모드로 실행하기 위해 서버를 클릭하고 Run(재생버튼)이 아닌 옆에 벌레모양의 Debug 버튼을 눌러서 실행해주자!

3. URL 요청

 

  자 이제 우리가 만든 요청을 어떻게 처리하는지 보기위해 아래 링크를 요청해보자

  http://localhost:8080/reqUrl.do?reqParam=3

  reqUrl.do에 reqParam에 3이라는 값을 담아서 요청했다 엔터를 누르는 순간

 

 

  하단에 이클립스가 주황색으로 변하면서 보라고!! 몸부림 친다. 이클립스를 눌러보자.

 

 

  26번째 줄이 초록색으로 변해있다. 지금 이 서버가 저 요청을 처리하기위해 저 26번째 줄에 멈춰있다는 것이다. 여기서 F8을 누르면 그냥 진행이 되고, F6을 누르면 한줄씩 진행이 되고, F5를 누르면 저 함수 내부로 들어가게 된다. 일단 우리가 확인할 것부터 확인하자.

 

 

  자 우리가 reqUrl.do를 처리할때 1번 박스를 보면 들어오는 데이터를 FwdVO객체에 맵핑해서 가져오는 걸로 되어있다. 그럼 저 26번째줄이 실행되기 직전 값이 제대로 들어왔는지 볼까?

 

  우측 Variable탭의 2번 박스를 보면 현재 searchVO라는 객체에 어떤 값들이 할당되어있는지 보인다. 펼쳐서 보면 reqParam에 3이라는 값을 정상적으로 mapping 해서 가져온걸 볼 수 있다. 이건 ,http://localhost:8080/reqUrl.do?reqParam=3이걸 실행할 때 reqParam=3 이란걸 보고 FwdVO안에 있는 reqParam이라는 변수와 이름을 매칭시켜 가지고 온것이다.

 

  3번 박스를 보면 자바에서 정상적으로 해당 요청값을 받아온 것을 볼 수 있다. 일단 우리가 여기까지 정리할껀, 현재 searchVO에 reqParam이 3의 값으로 요청이 들어왔단거다.

 

 

  자 그럼 다시 중단점이 걸린 26번째 줄을 다시보면 저기 selectTargetUrl()함수가실행되는데 보면 함수안에 저 searchVO 객체를 넣어주는 것을 볼 수 있다. 즉 아까 위에서 봤던 reqParam이 3으로 셋팅된 searchVO객체를 쿼리돌리는 함수에 변수로 넣어준다는 거다.

 

 

  더 구체적으로 보면 1번 번박스에 쿼리를 요청하면서 searchVO라는 객체를 input으로 같이 넣어주는데 그 객체를 살펴보면 2번을 보자, 지금 searchVO에 들어가 있는 값들인데 3번을 보면 객체 타입이 FwdVO로 되어있고 , 해당 쿼리문이 Mapping 되어있는 fwdSql.xml에서 해당 쿼리를 보면 3번 박스처럼 파라미터 형이 FwdVO로 같은 것을 볼 수 있다. 그럼 저 쿼리가 실행될때 자동으로 들어오는 변수들을 FwdVO의 형태로 받아들인 다는 것이다.

 

  자 그럼 이 쿼리가 FwdVO의 형태로 Input이 들어오고 4번 박스를 보면 FwdVO에있는 reqParam이라는 변수를 fwdSql.xml에서 동일하게 쓰는것을 알 수 있다. 이렇게 VO에서 불러온 변수를 쓰려면 #{변수명} 형태로 쓸 수 있게 된다. 현재 searchVO에 reqParam이 3으로 들어있으니 저 fwdSql.xml에 들어있는 쿼리문이 실행될때도 자동으로 mapping 된 값을 가져와 WHERE PM.SEQ_NO = 3으로 마이바티스가 처리할 것이다.

 

  여기까지 알아봤으니 한번 F6을 눌러 저 26번째줄을 실행시켜보자.

 

 

 

 

  자 26번째 줄을 실행하니 커서는 다음 코드인 28번째 줄로 이동했고, 좌측 Variable 탭을보면 방금 26번째 줄을 수행함으로써 변경된 데이터들이 최신화되었다. 한번보자.

 

  1번 박스를 보면 아까 26번째 줄을 실행하면서 쿼리 조회한 결과가 resulstList라는 변수에 들어갔다. 그 resultsList라는 변수를 보기위해 Variable탭에 2번 박스를 눌러보자. 그럼 3번에 어떤 내용을 담고 있는지 나온다. 이 결과는 어디서 온걸까?

 

  우리가 fwdSql.xml 에 쿼리를 작성해놨고 이 4번박스에 있는 쿼리가 실제로 실행된 것이다. #{reqParam}에는 VO에 들어있던 3이 들어갔을꺼고 실제로 DB에서 조회하는 쿼리는 5번과 같이 작성됐을 것이다. 이걸 HeidiSQL에서 실제로 돌려보면 6번과 같은 결과가 조회된다.

 

  다시 3번으로 돌아가서, 아까 6번에서 조회된 DB데이터들을 온전히 불러온 것을 알 수 있다. 결론적으로 지금 1번 박스에있는 resultsList 변수에는 6번 박스에있는 SQL 조회 결과가 들어있는 것이다. 이제 이걸 어떻게 처리할까? 28번째줄도 마저 실행하기위해 F6을 눌러보자!

 

 

  커서는 다음 코드인 30번줄로 이동했고, 다시 데이터들이 최신화 됐다. 자 1번 구문을 통해서 resultsList에서 get(0)을 통해 가장 첫번째 데이터를 가져왔고 그 안에 들어있는 값들은 아까 우리가본 2번 박스다. 저기보면 key=value형태로 되어있는데 1번박스의 .get("urlStr")을보면 저 객체에서 저 urlStr칼럼을 가져오겠다는 뜻이다.

 

 그럼 저 3번 박스에 있는 Key에 해당하는 Value인 www.google.com을 가지고 오게 되는것이고 이 데이터가 1번 박스에 (String)형으로 형변환뒤 URL이라는 변수에 담기는 것이다. 4번박스를 보면 URL이라는 변수에 정상적으로 DB에서 조회한 www.google.com이 담긴 것을 볼 수 있다. 이제 마저 30번째줄인 return구문이후로 쭉 수행시키도록하기위해 F8 버튼을 눌러주자.

 

 

  보면 아까 했던 요청이 google 페이지를 열어준 것을 알 수 있다. redirect로 return했기 때문이다.

 

  앞으로도 이런식으로 값이 변하는 과정을 보면서 코딩을 하면 보다 쉽게, 보다 이해하기 쉽게 만들 수 있을 것이다.

 

  #스프링#전자정부프레임워크 #이클립스 #마리아DB #데이터조회 #Select #디버깅 #방법 #Debug

 

 

 

 

 

반응형
반응형

 

https://extsdd.tistory.com/112

 

[Spring/eGov ] #7 스프링, 전자정부프레임워크 샘플 예제- 마이바티스(MyBatis)로 마리아 DB 연동하기 /

https://extsdd.tistory.com/102 [Spring/eGov ] #6 웹 서비스 만들기 2 / 요청 URL 파라미터 가져오기 / Debug 방법 / 디버깅 하는법 / @Model extsdd.tistory.com 자 우리가 마지막으로 했던게 사용자 요청 URL..

extsdd.tistory.com

  자 저번 시간까지 이클립스와 Maria DB를 MyBatis라는 친구로 연동을 시켰다. 아. 전에 MyBatis가 먼지 설명을 안했는데 간단하게 설명하자면 과거에 JAVA코드로 쿼리로 DB에 있는 데이터를 조회하려고 하면, 소스안에 자바코드도 껴져있고, SQL쿼리문도 껴져있고, 개판처럼 만들어 놓고 썻기때문에 관리도 안됐던 문제가 있었다. 사실 머 문제라기보단 조 불편하고 효율적이지 않았던거지!

MyBatis

 

  하지만 쿼리문과 자바 구문들을 분리해놓으면서, 자바는 자바구문 끼리, 그리고 쿼리는 xml파일에 두고 namespace로 Mapping시켜 사용하게 하는 MyBatis방식이 나왔고 xml에 IF같은 태그가 가능해지면서 쿼리문도 동적으로 변화를 줄 수 있게 됐다. 그러면서 모든 Case의 쿼리를 안짜도 되고 이렇게 Flexible하게 코드를 짤 수 있으니 그야말로 효율을 극대화한 프레임워크라고 할 수 있다. 코드를 보면 머 iBatis도 있고 MyBatis도 있는데 iBatis는 아파치랑 붙어먹을때 쓰던 프레임워크고 구글로 넘어오면서 Mybatis를 쓰게 됐다고만 알고 있으면 될 것 같다.

 

  잔말 그만하고, 일단 MyBatis로 이클립스랑 마리아DB랑 연동이 안 된 사람은 위 포스팅으로 가서 설정을 하고오자. 다 된 사람이라면 이제 본격적으로 시작해보자.

1. 데이터 조회 구조 파악하기.

 

  자. 내가 웹 서비스에대해서 아무것도 모르고 회사에 와서 스프링 하세요! 했을때 완전 No Base인 상태에서 코드들을 따라갔을때 너무 복잡하게 느껴졌었다. 이게 왜 이렇게 되고, 이 코드가 어디랑 연관이 있고.. 거대한 숲에 혼자 떨어져서 내가 어디서 뭘하는지 모르는 그런 기분이었다.

 

  이제 일을 하다보니 스프링 구조에대해서 어느정도 윤곽이 잡혔고, 이제는 하늘에서 숲을 내려다 보듯이 구조와 흐름이 보이기 시작했다. 처음부터 내가 이런 윤곽을 알고 했으면 더 수월했을텐데, 이렇게 초보자들이 볼 수 있게 정리된 글들이 없었다 ㅠㅠ.. 그래서 내가 정리했다.! 초보자 시점에서 전체 윤곽을 그린 모습을!

 

  좀 어려울 수도 있는제 한번 흐름만 파악해보자.

 

 

 

  와..! 엄청 어렵고 복잡하다. 난생 웹서비스를 처음해보는 나는 이런 전체의 모습이 아닌 코드를 한줄한줄 따라가면서 고대 문자 해석하듯이 했을때는 얼마나 어려웠을까 생각해보길 바란다..ㅠㅠ

 

  어렵게 보이지만 스프링 웹 서비스의 구조는 딱 저렇다. 저기서 크게 벗어나지 않는다. 저기서 한개의 기능을 만들면 이제 복붙이고, 저 구조만 지켜지면 뭐든지 할 수 있다. 그러니까 포기하지 말고 따라오길 바란다.

 

  1 . 자 1번 박스는 스프링 프로젝트라고 생각하면 된다. 저기 16번 박스에 있는 DB를 제외하면 다 스프링 프로젝트 내의 소스로 돌리는 것이다. 1번은 별거 없다. 제일 큰 구조부터 접근해보기 위해서 번호를 넣어봤다 ㅎㅎ

Controller / 컨트롤러

 

  2. 아까까진 ice breaking이었고 여기서부터 진짜 시작이다.자 Controller 이름만 봐도 뭔가 파박! 떠오른다. 뭔가 조작하고 제어하고, 뭔가..! 뭔가를 수행하는넘! 맞다 Controller는 business(Biz) 적인 로직을 처리한다. Biz 로직이 머냐구!? 말그대로 사람이 이해할만한 "동작" 정도로 해석하면 될 꺼같은데 이런거다. 컴퓨터는 뭔가 데이터를 삽입, 삭제, 수정, 조회, 머 이런 원초적인 기능밖에 못하는데 컴퓨터가 아닌 우리 사람입장에서 기능이란, 뭔가 고객 데이터를 조회하거나, 게시판의 글 목록들을 불러오거나, 게시글을 클릭했을때 그 글을 보여줘! 처럼 사람이 이해할만한 "기능" 이라고 생각하면 되는 것이다. 좀 감이 왔나? 다시 정리하면 우리 인간들에게 기능다운 기능이란 삽입,삭제 뭐 이런 재미없는 것들을 말하는게 아니라, 그런 조회, 삽입, 삭제등 이런 컴퓨터의 기능들을 이용해 우리 인간세계게에서 통용될 수 있는 그런 기능을 작성하는 것이다. 예를들면 할머니한테 할머니! 제가 DB에서 Select 기능을 수행했어요! 하면 할머니는 뭔 개소리냐? 하고 반문할꺼지만, 할머니! 제가 어떤 예약이 있는지 조회했어요!! 한다면 할머니가 이해할 것이다. 차이점이 느껴지나..! 컴퓨터에는 "예약을 조회한다"는 기능이 없다! 예약정보가 어디있는지, 이걸 조회할지 삭제할지 이런건 다 인간이 정한거고 이 기능을 만들기 위한 로직을 Business 로직이라고 한다.

 

  자 Controller의 결론을 말하자면, 기능을 작성하는 곳이다! 이정도로 이해하면 될 것 같고, 로직은 그냥 짜면 된다 if어쩌고~ 아니면 저쩌고~ 쭈르륵 작성하는데 DB에서 데이터를 가져와야할꺼 아냐? 그 데이터를 가지고 오기 위한 놈이 Service(서비스)라는 놈이다. 예전 포스팅에서도 이 서비스란 놈을 좀 설명했는데, 특정 기능들의 데이터를 서리하는 집합체라고 생각하면 된다. 더 raw하게 써논 설명을 보고 싶다면

https://extsdd.tistory.com/99

 

[Spring/eGov] #3 스프링 기본 구조 / Sample 예제 프로젝트 분석 / 원리 / 전자정부프레임워크 / 컨트롤�

 

extsdd.tistory.com

  위 포스팅 중간쯤에 서비스란 무엇인가 이걸 참조하면 된다. 아무튼 서비스가 실제로 데이터들을 불러오기 위한 객체인데, 우리 Controller에서 필요한 정보들을 조회하기 위한 서비스를 미리 호출해놓고 쓴다.

 

  3. 자 3번 박스를 보면 그 컨트롤러의 실제 예시 코드를 캡쳐해 놓은 것이다. 구조를 보면 컨트롤러 fwdService를 미리 호출해놓고 5번 박스를 보면 그 객체로 8번 박스의 함수를 호출해서 데이터를 조회하는 것을 볼 수 있다. 조회된 데이터들은 17번에 있는 resultList에 담기고 그 밑으로 이 조회된 데이터를 기준으로 Biz 로직을 작성하면 하나의 기능이 되는 것이다.

 

  4. 자 보면 컨트롤러에 fwdService가 선언되었다. 앞으로 이 Controller에선 fedService가 할 수 있는 기능을 이용할 수 있게된다. 필요한 서비스를 이렇게 불러놓으면 되는 것이다.

 

  5. 4번에서 선언한 서비스를 실제로 로직에서 불러와 사용한 것이다.

 

  6. 그 서비스는 service 패키지 경로안에 ~~~~Service.java 형식으로 파일이 있을 것이다. 4번 박스처럼 fwdService라면 FwdService.java 라는 파일로 만들어 놨을 것이다.

 

  7. 이게 이 Service 파일의 구조인데, 보면 함수 이름정도만 선언되어있다.. 즉, 여기서 로직이 작성되진 않는다. 서비스에서 처리하는 로직은 ServiceImpl.java에서 구현된다. Impl 는 Implement정도로 해석하면되고, 말그대로 구현이다.

 

  8. 보면 아까 7번 서비스에서 선언된 기능을 Biz 로직단에서 호출하는 것을 볼 수 있다. 아까 말했듯이 이 구현은 ServiceImple.java에서 구현된다고 했으니까 계속 알아보자.

 

  9. 자 ServiceImpl.java로 오면 크게 구조가 DAO라는 친구가 선언되어 있다. 이건 나중에 알아보도록하고 실제 코드를 보자

 

  10. 자 실제로 serviceImpl.java를 와보자.보면 아까 우리가 7,8번에서 언급한 함수가 여기도 선언되어있다. 맞다 Interface로 선언된 친구다. 그 실제 로직을 보자

 

  11 .바로 이거다 DAO라는 친구를 이용해 selectList를 해오는 것이다. 보면 fwd.selectTargetUrl 이라는 쿼리를 수행하라고 되어있는데, fwd는 xml파일의 namespace를 말하는 것이고, 이 네임스페이스로가면 selectTargetUrl이라는 쿼리문이 있을것이다.

DAO (Data Access Object)

 

  먼저 DAO라는 친구를 알고가야한다. 발음은 "다오"라고 부른다. 개귀엽다 ㅎㅎ.. 암튼 이친구가 뭐하는 역할이냐면,DB와 COnnection을 이용해 데이터를 가져와 주는 놈이다. 과거에 코딩을 좀 해본사람이라면 Java 소스안에서 Connection을 맽고 조회하고, Connection을 끝고,, 이런 불필요한 코드들이 아주 많았고, 한번 조회할때마다 이 커넥션을 게속 작성해야해서 너무 불편했다. 하지만 이제 DAO라는 친구에서 조회할꺼면 select, 삽입할꺼면 insert 등.. 함수만 치면 이런 커넥션 알아서 맺고 조회하면 알아서 끝고 다해주는 친구다. 세부 구현은 어떻게됐는지 몰라도 된다. 특급 개발자들이 다 잘 구현해 놓았을테니까 ㅎㅎ 우리는 사용만 하면된다.

 

  12-1. 저 쿼리문을 MyBatis라는 저 fwd.selectTargetUrl이라는 문구를 보고 어디에 있는 파일에서 어떤 구문을 조회할지 Mapping해주는 역할을 해준다.

 

  12-2. 그럼 이 마이바티스를 통해서 fwd네임스페이스니 fwdSql.xml이란 파일을 뒤져서 거기있는 selectTragerUrl이란 쿼리문을 찾아온다.

 

13. 그게바로 이 13번 박스에 있는 id로 매핑시켜 찾아오는것이다.

 

  14. 자 그럼 마이바티스가 어떤 쿼리를 조회할지도 알아낸 것이다.

 

  15. 이제 본젹적으로 아까 말했던 DB랑 Connection을 맺는 DAO라는 친구를 통해, 마이바티스에서 넘겨받은 쿼리 구문들을 본격적으로 조회한다.

 

  16. DAO를 통해 DB에 접속한 단계이다. Connection이 맺어지면 아까 받은 쿼리들을 조회하고 그 결과를 DAO가 다시 가져온다. 그럼 역순으로 다시 11번 박스를 보면 그 조회 결과가 리턴되고, 이 리턴받은 데이터들은 8번 박스에 나온 저 함수에서 리턴되 결국 17번 박스에 있는 변수로 들어가게 되는것이다.

 

  17. 결국 조회된 데이터가 resultList라는 변수에 들어가고 우린 그걸 사용하면 된다.

 

결론 : 기능은 ~Controller.java, ~Service.java, ~ServiceImpl.java, ~VO.java(필요하다면), ~Sql.xml 가 세트로 다닌다고 생각하면 된다. 이렇게 한사이클 돌았는데, 나머지도 보면 다~~똑같다, 이해가 안돼도 되니 느낌만 알고 가도록 하자

2. CommonDAO.java 추가

 

  자 먼저 공통적으로 DB에서 커넥션을 맺어줄 DAO를 만들어보자!

 

 

  자 cmmn 패키지에 오른쪽마우스를 눌러 NEW-Class를 눌러주고 패키지 경로를 하나 만들어주자.

 

 

  자 패키지 경로명에 .dao를 추가해서 만들어주자.

 

 

  만들어진 dao 패키지에 새 클래스를 만들어주자.

 

 

  뚜둔~ 이름은 CommonDAO로 만들어주자!

 

 

  보면 dao 패키지 밑에 CommonDAO.java 파일이 생겼다! 열어보자!

 

 

귀여운 파일이 생겼다. 소스를 넣어 생기를 불어넣어주자.

package cpservice.cmmn.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Repository;

import egovframework.rte.psl.dataaccess.EgovAbstractMapper;

@Repository("CommonDAO")
public class CommonDAO extends EgovAbstractMapper {

	/**
	 * 입력 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId -  입력 처리 SQL mapping 쿼리 ID
	 *
	 * @return DBMS가 지원하는 경우 insert 적용 결과 count
	 */
	public int insert(String queryId) {
		return super.getSqlSession().insert(queryId);
	}

	/**
	 * 입력 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId -  입력 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 입력 처리 SQL mapping 입력 데이터를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 *
	 * @return DBMS가 지원하는 경우 insert 적용 결과 count
	 */
	public int insert(String queryId, Object parameterObject) {
		return super.getSqlSession().insert(queryId, parameterObject);
	}

	/**
	 * 수정 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 수정 처리 SQL mapping 쿼리 ID
	 *
	 * @return DBMS가 지원하는 경우 update 적용 결과 count
	 */
	public int update(String queryId) {
		return super.getSqlSession().update(queryId);
	}

	/**
	 * 수정 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 수정 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 수정 처리 SQL mapping 입력 데이터(key 조건 및 변경 데이터)를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 *
	 * @return DBMS가 지원하는 경우 update 적용 결과 count
	 */
	public int update(String queryId, Object parameterObject) {
		return super.getSqlSession().update(queryId, parameterObject);
	}

	/**
	 * 삭제 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 삭제 처리 SQL mapping 쿼리 ID
	 *
	 * @return DBMS가 지원하는 경우 delete 적용 결과 count
	 */
	public int delete(String queryId) {
		return super.getSqlSession().delete(queryId);
	}

	/**
	 * 삭제 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 삭제 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 삭제 처리 SQL mapping 입력 데이터(일반적으로 key 조건)를  세팅한 파라메터 객체(보통 VO 또는 Map)
	 *
	 * @return DBMS가 지원하는 경우 delete 적용 결과 count
	 */
	public int delete(String queryId, Object parameterObject) {
		return super.getSqlSession().delete(queryId, parameterObject);
	}

	//CHECKSTYLE:OFF
	/**
	 * 명명규칙에 맞춰 selectOne()로 변경한다.
	 * @deprecated select() 메소드로 대체
	 * 
	 * @see EgovAbstractMapper.selectOne()
	 */
	//CHECKSTYLE:ON
	@Deprecated
	public Object selectByPk(String queryId, Object parameterObject) {
		return super.getSqlSession().selectOne(queryId, parameterObject);
	}

	/**
	 * 단건조회 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
	 *
	 * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)
	 */
	public <T> T selectOne(String queryId) {
		return super.getSqlSession().selectOne(queryId);
	}

	/**
	 * 단건조회 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 단건 조회 처리 SQL mapping 입력 데이터(key)를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 *
	 * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)
	 */
	public <T> T selectOne(String queryId, Object parameterObject) {
		return super.getSqlSession().selectOne(queryId, parameterObject);
	}

	/**
	 * 결과 목록을 Map 을 변환한다.
	 * 모든 구문이 파라미터를 필요로 하지는 않기 때문에, 파라미터 객체를 요구하지 않는 형태로 오버로드되었다.
	 *
	 * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
	 * @param mapKey - 결과 객체의 프로퍼티 중 하나를 키로 사용
	 *
	 * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)의 Map
	 */
	public <K, V> Map<K, V> selectMap(String queryId, String mapKey) {
		return super.getSqlSession().selectMap(queryId, mapKey);
	}

	/**
	 * 결과 목록을 Map 을 변환한다.
	 * 모든 구문이 파라미터를 필요로 하지는 않기 때문에, 파라미터 객체를 요구하지 않는 형태로 오버로드되었다.
	 *
	 * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 맵 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 * @param mapKey - 결과 객체의 프로퍼티 중 하나를 키로 사용
	 *
	 * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)의 Map
	 */
	public <K, V> Map<K, V> selectMap(String queryId, Object parameterObject, String mapKey) {
		return super.getSqlSession().selectMap(queryId, parameterObject, mapKey);
	}

	/**
	 * 결과 목록을 Map 을 변환한다.
	 * 모든 구문이 파라미터를 필요로 하지는 않기 때문에, 파라미터 객체를 요구하지 않는 형태로 오버로드되었다.
	 *
	 * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 맵 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 * @param mapKey - 결과 객체의 프로퍼티 중 하나를 키로 사용
	 * @param rowBounds - 특정 개수 만큼의 레코드를 건너띄게 함
	 *
	 * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)의 Map
	 */
	public <K, V> Map<K, V> selectMap(String queryId, Object parameterObject, String mapKey, RowBounds rowBounds) {
		return super.getSqlSession().selectMap(queryId, parameterObject, mapKey, rowBounds);
	}

	//CHECKSTYLE:OFF
	/**
	 * 명명규칙에 맞춰 selectList()로 변경한다.
	 * 
	 * @see EgovAbstractMapper.selectList()
	 * @deprecated List<?> 메소드로 대체
	 */
	//CHECKSTYLE:ON
	@Deprecated
	public List<?> list(String queryId, Object parameterObject) {
		return super.getSqlSession().selectList(queryId, parameterObject);
	}

	/**
	 * 리스트 조회 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
	 *
	 * @return 결과 List 객체 - SQL mapping 파일에서 지정한  resultType/resultMap 에 의한 결과 객체(보통 VO 또는 Map)의 List
	 */
	public <E> List<E> selectList(String queryId) {
		return super.getSqlSession().selectList(queryId);
	}

	/**
	 * 리스트 조회 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 리스트 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 *
	 * @return 결과 List 객체 - SQL mapping 파일에서 지정한  resultType/resultMap 에 의한 결과 객체(보통 VO 또는 Map)의 List
	 */
	public <E> List<E> selectList(String queryId, Object parameterObject) {
		return super.getSqlSession().selectList(queryId, parameterObject);
	}

	/**
	 * 리스트 조회 처리 SQL mapping 을 실행한다.
	 *
	 * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 리스트 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 * @param rowBounds - 특정 개수 만큼의 레코드를 건너띄게 함
	 *
	 * @return 결과 List 객체 - SQL mapping 파일에서 지정한  resultType/resultMap 에 의한 결과 객체(보통 VO 또는 Map)의 List
	 */
	public <E> List<E> selectList(String queryId, Object parameterObject, RowBounds rowBounds) {
		return super.getSqlSession().selectList(queryId, parameterObject, rowBounds);
	}
	
	/**
     * @description   Map 으로 리스트를 조회한다. 단 페이징 로직을 수행한다.
     */
    /*public <E>List<E> selectListWithPaging(String id ,CmMultiVO vo) {
    	MappedStatement ms = super.getSqlSession().getConfiguration().getMappedStatement(id);
    	
    	
		//전체 ROW Counting을 위해 기존 SQLMap 객체를 카피하고 PaginationStatementInterceptor에서 excute하기전에 쿼리를 조작함
		if(!super.getSqlSession().getConfiguration().hasStatement(id+"$$_TOTCNT___$$")){
			MappedStatement.Builder msBuilder = new MappedStatement.Builder(
					ms.getConfiguration(), id+"$$_TOTCNT___$$", ms.getSqlSource(),
					ms.getSqlCommandType());
			
			msBuilder.resource(ms.getResource());
			msBuilder.fetchSize(ms.getFetchSize());
			msBuilder.statementType(ms.getStatementType());
			msBuilder.keyGenerator(ms.getKeyGenerator());
			if (null != ms.getKeyProperties()) {
				for (String keyProperty : ms.getKeyProperties()) {
					msBuilder.keyProperty(keyProperty);
				}
			}
			msBuilder.timeout(ms.getTimeout());
			msBuilder.parameterMap(ms.getParameterMap());
			ResultMap.Builder rmBuilder = new ResultMap.Builder(ms.getConfiguration(), ms.getId()+"$$_TOTCNTMAP___$$", Integer.class, new ArrayList<ResultMapping>());
			ArrayList<ResultMap> rsList = new ArrayList<ResultMap>();
			rsList.add(rmBuilder.build());
			msBuilder.resultMaps(rsList);
			msBuilder.cache(ms.getCache());
			
			synchronized(super.getSqlSession().getConfiguration()) {
				super.getSqlSession().getConfiguration().addMappedStatement(msBuilder.build());
			}

		}
		
		//신규로 생성한 sql을 실행, 실행 시 PaginationStatementInterceptor sql을 조작함
		int totCnt = super.getSqlSession().selectOne(id+"$$_TOTCNT___$$", vo);
		RowBounds rowBounds = null;
		if(vo.getPaginationInfo() != null){
			vo.getPaginationInfo().setTotalRecordCount(totCnt);
			rowBounds = new RowBounds(vo.getPaginationInfo().getFirstRecordIndex(), vo.getPaginationInfo().getRecordCountPerPage());
		}else{
			rowBounds = new RowBounds();
		}


		//실행 시 PaginationStatementInterceptor sql을 조작함
		List<E> resultList = super.getSqlSession().selectList(id, vo, rowBounds);
		
		
		return resultList;
    }*/
    
	/**
	 * 부분 범위 리스트 조회 처리 SQL mapping 을 실행한다.
	 * (부분 범위 - pageIndex 와 pageSize 기반으로 현재 부분 범위 조회를 위한 skipResults, maxResults 를 계산하여 ibatis 호출)
	 *
	 * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
	 * @param parameterObject - 리스트 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
	 * @param pageIndex - 현재 페이지 번호
	 * @param pageSize - 한 페이지 조회 수(pageSize)
	 *
	 * @return 부분 범위 결과 List 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 부분 범위 결과 객체(보통 VO 또는 Map) List
	 */
	public List<?> listWithPaging(String queryId, Object parameterObject, int pageIndex, int pageSize) {
		int skipResults = pageIndex * pageSize;
		//int maxResults = (pageIndex * pageSize) + pageSize;

		RowBounds rowBounds = new RowBounds(skipResults, pageSize);

		return super.getSqlSession().selectList(queryId, parameterObject, rowBounds);
	}

	/**
	 * SQL 조회 결과를 ResultHandler를 이용해서 출력한다.
	 * ResultHandler를 상속해 구현한 커스텀 핸들러의 handleResult() 메서드에 따라 실행된다.
	 *
	 * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
	 * @param handler - 조회 결과를 제어하기 위해 구현한 ResultHandler
	 * @return
	 *
	 * @return 결과 List 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 결과 객체(보통 VO 또는 Map)의 List
	 */
	public void listToOutUsingResultHandler(String queryId, ResultHandler handler) {
		super.getSqlSession().select(queryId, handler);
	}
	
}

저 소스덩어리를 이어서 CommonDAO.java에 넣어주자.

 

 

  넣으면 이런식으로 쭉~ 코드들이 들어갈텐데 저장을 눌러주자. 여기 내용들은 머 이해할 필요까진 없다. 이미 Mapper 역할을 할 EgovAbstractMapper를 상속받아 만들어진 것이기 때문에 그냥 아~ 여기 데이터에 접근해 조회, 삭제, 삽입, 변경 하는 함수들이 들어가는 구나 ~ 정도만 알고있으면 된다.

3. Service 추가

 

 

 

  자 이제 내 DB에서 데이터를 읽어올껀데 그렇게 하기위한 파일들을 작성해보자 먼저 service 부터 선언할껀데 위 service 패키지를 오른쪽마우스 눌러 New버튼 클릭 후 Class를 눌러주자. 그리고 앞으로 파일 생성할 일이 많으니 클래스를 만들라~ 하면 이정도는 외워두길 바란다.

 

 

  자 이름은 FwdService로 정해주고 Finish를 눌러주장!

 

 

  그럼 빈 파일이 생성된다.

아래 코드를 복붙하고 저장해주자.

package cpservice.fwd.service;

import java.util.List;

import egovframework.rte.psl.dataaccess.util.EgovMap;

public interface FwdService {
	/**
	 * URL 조회
	 * @param FwdVO 검색조건
	 * @return List<?> URL 목록
	 */
	List<EgovMap> selectTargetUrl(FwdVO vo);
}

 

 

 

  짜잔 서비스가 생겼다~ 이제 저 서비스에 있는 selectTargetUrl 기능을 구현해보자.

 

4. ServiceImpl 구현

 

 

 

  자 ServiceImpl.java를 만들껀데 다른점이라면 Impl파일은 서비스 패키지가 아니라 impl 패키지에 추가한다는 점이다. 꼭.! 경로 헷살리지 않도록 하자, 만약 service 캐키지 밑에 impl패키지가 없으면 만들어라, 만드는거 New누르고 Package누르면 만들 수 있다. 암트 다시돌아와서 impl 패키지를 오른쪽마우스 누르고 New-Class를 눌러 만들어주자. 이제 파일 만드는 것은 설명안해두 되겠지..!?

 

 

  파일 이름은 FwdServiceImpl로 만들어주자

 

 

 짜잔..! 생겼다..!

 

 

  개 귀여운 파일이 생겼다. 내용을 넣어주자

package cpservice.fwd.service.impl;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import cpservice.cmmn.dao.CommonDAO;
import cpservice.fwd.service.FwdService;
import cpservice.fwd.service.FwdVO;
import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
import egovframework.rte.psl.dataaccess.util.EgovMap;

@Service("fwdService")
public class FwdServiceImpl extends EgovAbstractServiceImpl implements FwdService {

	/** CommonDAO */
	// TODO mybatis 사용
	@Resource(name = "CommonDAO")
    private CommonDAO dao;
	
	/**
	 * 요청에 맞는 URL을 조회하는 쿼리
	 */
	@Override
	public List<EgovMap> selectTargetUrl(FwdVO vo) {
		// TODO Auto-generated method stub
		return dao.selectList("fwd.selectTargetUrl", vo);
	}

}

 

  코드 설명을 간단히 해보자면 이 서비스의 selectTargerUrl 함수를 돌리면 selectTargetUrl 쿼리를 조회해서 뱉어주는 역할을한다.

5. fwdSql.xml 작성

 

  자 이제 쿼리문이 작성될 fwdSql.xml을 작성할 것이다.

 

 

  sqlmap 폴더에 폴더를 하나 만들어주자.

 

 

  폴더 이름은 fwd로 정해주자!

 

 

  만들어진 fwd 폴더에 XML파일을 추가해주자. New - Other 클릭!

 

 

  XML을 검색해주고 밑에 XML File을 눌러 NEXT!

 

 

 

  파일명은 fwd.xml로 추가!

 

 

  자 fwd폴더 밑에 fwd.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="fwd">

	<select id="selectTargetUrl" parameterType="cpservice.fwd.service.FwdVO" resultType="egovMap">
		/** selectTagetUrl (fwdSql.xml) 마스터코드 목록 조회*/
		SELECT PM.SEQ_NO
			,PM.URL_STR
			,PM.DISC_STR
			,PM.USE_YN
		FROM prd_mst PM
		WHERE PM.SEQ_NO = #{reqParam}

		 
	</select>
	
</mapper>

 

  통째로 복붙하고 저장하자

 

 

  1. 소스를 좀 살펴보자. 먼저 1번 박스가 네임스페이스다. 자바 소스에서 쿼리를 불러올때 fwd.selectTargetUrl 이라는쿼리를 불러올때 앞에 fwd가 이 네임스페이스다. 긍까 네임스페이스가 Fwd인 파일에있는 selectTargetUrl이란 쿼리를 찾아오겠다~ 이말이다.

 

  2. 2번 박스를 보면 id="selectTargetUrl"로 되어있는데 1번에서 설명과 마찬가지로 해당 쿼리의 고유 ID다, 이 쿼리를 불러오기위해선 저 ID를 호출해야하는 것이다.

 

  3. 이건 파라미터 타입이다. 이 쿼리를 실행하기전에 여기다 객체를 집어 넣을 수 있다. 넣어서 뭐하냐고?!! 아주 중요한 질문인데, 자 만약에 넣을 수 없다면, 저 쿼리를 봤을때 5번 박스가 있는 Where 절에 SEQ_NO를 1일때, 2일때, 3일때 똑같은 쿼리를 여러번 만들어 줘야하는데 #{reqParam} 이란 변수명이 보이는가!?, 저 파라미터로 가져온 FwdVO안에 있는 저 변수명을 가지고 올 수 있는 것이다. 이 쿼리를 요청할때 함수 구문에 VO를 넣어주는 것이 보일텐데, 여기서 그 VO에 넣어져 있는 값을 사용할 수 있는 것이다. 만약에 reqParam에 1이 들어있으면 WHERE PM.SEQ_NO = 1 로 쿼리가 설정되고, reqParam에 2가 들어오면 WHERE PM.SEQ_NO가 2로 셋팅되는식으로, 쿼리문은 하나인데 들어오는 값들에 의해서 쿼리가 동적으로 변화하면서 아주 유연한 쿼링이 가능케하는 것이다. 이게 바로 MyBatis의 강점이라고 할 수 있다.

 

  4. 이건 조회하고나서 어떤 데이터 형으로 뱉어줄지다. 머 String이라고 하면 문자열로 나가는등, 원하는 타입으로 선언하면 된다. 하지만, DB특성사 조회하면 여러 컬럼의 형태로 조회되기 때문에 Map형태로 뽑아줘야한다. 이 전자정부프레임워크에는 egovMap이라는 데이터형이 만들어져 있는데 이 Map을 쓰는게 가장 사용하기 좋다.

 

  5. #{변수명} 이라고 쓰면 3번 박스에서 선언된 VO를 읽어와 그 VO에 들어온 정보들을 쓸 수 있다.

6. Controller.java 수정

 

  자 이제 데이터를 조회할 준비는 다됐고 실제 Biz 로직단에서 반영되도록 소스를 수정해주자!

 

 

  자 저번까지 작성한 컨트롤러의 코드를 보면 그냥 하드코딩이 되어있다. 들어오는 파라미터가 1이면 네이버를, 2면 다음, 3이면 구글 이렇게 값자체가 소스에 박혀있어 나중에 사후 관리측면에서 문제가 되는 소스들이다.

 

  이걸 이제 DB에서 불러오는걸로 바꿔보자 아예 통째로 소스를 부어 넣어주자.

 

package cpservice.fwd.web;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import cpservice.fwd.service.FwdService;
import cpservice.fwd.service.FwdVO;
import egovframework.rte.psl.dataaccess.util.EgovMap;

@Controller
public class FwdController {

	/** 고객관리 서비스 */
	@Resource(name = "fwdService")
	private FwdService fwdService;
	
	@RequestMapping(value = "/reqUrl.do")
	public String selectReqUrl(@ModelAttribute("searchVO") FwdVO searchVO, ModelMap model) throws Exception {
		
		List<EgovMap> resultList = fwdService.selectTargetUrl(searchVO);
		
		String URL = (String) resultList.get(0).get("urlStr");
		
		return "redirect:http://"+URL;
		
	}
	
}

 

  자 이소스로 복붙하고 저장하자.

 

 

  소스를 살펴보자면

 

  1. fwd 관련 쿼리를 사용할 것임으로 fwdService를 호출해주자.

2. 이 호출한 서비스에서 selectTargetUrl 함수를 돌려 쿼리를 실행하주고, 그걸 resultList에 넣어주자. 자 또하나 보자면 함수의 파라미터로 searchVO를 넣어줬는데. 이건 사용자가 이 reqUrl.do를 요청할때 넣어준 데이터들이 들어있는 객체다. 이 VO를 쿼리돌리는 저함수에 넣어주면 분명 저 FwdVO안에 있는 reqParam이라는 사용자가 요청한 값도 받아올 것이다.

 

  3. 자 쿼리를 돌려 조회된 결과가 resultList인데 사실 이 쿼리는 여러행이 나오지 않는다. reqParam에 매칭되는 목적지 URL은 하나이기 때문에 단건 조회인데, 그럼 또 다른 함수를 타야하는데 보통 다건 조회가 많으니 그냥 List형태로 받아오도록했다.. 그래서 resultList.get(0)을 통해서 맨 첫번째 결과를 가져와 get("urlStr")을 통해서 조회한 쿼리에서 urlStr 칼럼을 가져오겠다는 것이다.

 

  4. 마지막으로 redirect://http:// 와 URL을 붙혀 리턴해주면 DB를 기반으로 조회하는 포워딩 시스템이 완성된다!

7. 결과 확인

 

 

  자 이제 서버를 한번 Clean뒤 Run을 해보면 서비스가 동작할텐데 오류없이 실행되면 잘 된거다. 다시 http://localhost:8080/reqUrl.do?reqParam=3이렇게 테스트로 조회를해보고 끝에 reqParam= 뒤에 값을 1,2,3등으로 변경하면서 엔터를 눌러봐라. 만약 각 DB에 넣은 정보에 맞는 페이지를 호출하면 잘 된거다.

 

  혹시 오류가 나는사람들은 다음 포스팅에 할 Debug과정을 통해서 한번 값들이 어떻게 이동하는지 살펴보도록 하자.

 

 

#스프링 #전자정부프레임워크 #마리아DB #이클립스 #마이바티스 #컨트롤러 #DAO #원리 #구조 #MariaDB #ByBatis #Controller

 

 

반응형
  1. HAVY 2021.01.12 15:37

    글 잘보고 있습니다 덕분에 스프링 이해가 잘 됩니다.
    한 가지 부탁이 있습니다.
    우클릭 및 드래그가 되지 않아 긴 코드를 복붙하지 못하고 일일히 타이핑하고 있습니다.
    본문들의 내용을 보니 그걸 일부러 설정하신게 아닌것 같은데 괜찮으시면 혹시 복사 방지를 풀어주실수 있으신가 하고 조심스럽게 여쭤봅니다...

  2. HAVY 2021.01.14 09:48

    중복 댓글 죄송합니다...또한 fwdSql.xml 생성하는 법이 나오지 않은 것 같습니다. 오류가 계속 생겨서 디버깅해보니 프레임워크에서 mariaDB의 정보를 못읽어오는듯 하여 글을 다시보니 fwdSql.xml에서 뭔가 연동을 시키는 것 같아서 댓글 남겨봅니다!

  3. ratta 2021.01.27 11:43

    잘따라가다가 fwdSql.xml 에 관한 사항이 없어 난항을 겪고 있습니다. 해당 부분에 대해 알려주실 수 있을까요? ㅠㅠ

    • ratta 2021.01.27 15:57

      필요없는 난항이였군요 결국 경로를 *.xml 이기에 fwd,xml 이건 fwdSql.xml이건이 문제가 아니였네요 해결했습니다 ㅎㅎ..

    • ratta 2021.01.27 15:57

      필요없는 난항이였군요 결국 경로를 *.xml 이기에 fwd,xml 이건 fwdSql.xml이건이 문제가 아니였네요 해결했습니다 ㅎㅎ..

  4. sss 2021.06.30 16:25

    자바 처음인데 전자정부 하게 되어 혼란스럽다가, 설명 여러번 읽으니 조금 씩 이해가되는 듯 합니다 ㅎㅎ감사합니다 !

반응형

 

https://extsdd.tistory.com/102

 

[Spring/eGov ] #6 웹 서비스 만들기 2 / 요청 URL 파라미터 가져오기 / Debug 방법 / 디버깅 하는법 / @Model

 

extsdd.tistory.com

  자 우리가 마지막으로 했던게 사용자 요청 URL에서 데이터를 가져오는 것을 했다. 가져온 값의 데이터가 1이면 네이버, 2면 다음, 모두 아니면 구글페이지로 넘겨줬다.

 

 

  대략 위와같은 코드로 마무리 했는데, 저렇게 어떤 변수의 값이 대놓고 찍혀있는것을 우리가 하드코딩이라고 한다.

 

하드코딩 hard coding

 

  자 하드코딩의 사전적 의미를 보면 데이터를 코드 내부에 직접 입력하는 것 이라고 한다. 즉.. 저 naver.com, daum.net, google.com 이런 값들이 코드 내부에 대놓고 박혀있는 것이 하드코딩이다.

 

  자 그럼 하드코딩인데 어쩌라고? 한다면은.. 이런 코딩방식은 피해야한다. 왜냐면 저렇게 대놓고 코드안에 데이터를 넣어버리면 당장은 편하다. 직관적으로 저 값에 의해서 실행이 되니까.. 근데 장기적인 입장에서 코드가 수정되거나, 추가되었을때 저부분과 연관된 부분에 영향을 미칠 수 있기 때문이다.

 

 당장 저 변수들이 저 컨트롤러에만 있지만, 나중에 프로젝트가 커짐에따라 저 데이터를 수백개의 자바파일에서 수천번의 참조가 일어날것이다. 그때 만약에 맘이 바껴서 naver.com이 아니라 youtube.com으로 연결하고 싶은데? 라고 맘이 바뀌면 저 수백개의, 수천줄에 참조된 저 www.naver.com이라는 값을 모두 하나도 빠짐없이 바꿔야한다. 위코드는 진짜 단순해서 진짜 바꾸기만 하면 끝이지만, 실제 현업에서 작업을 하다보면 별에별 이상한 오류가 다생긴다. 그래서 하드코딩 방식은 피해야하고, 소프트웨어가 의존성을 갖지 않도록 만들어야한다.

 

  그럼 어떻게할까!? 방법이 있다! 보통 Database를 통해 해당값을 불러온다. 데이터를 Database에서 참조하기 때문에 나중에 다른 값을 불러오고 싶거나 값을 추가하고싶으면 해당 Database에서 수정만 하면 이 스프링 소프트웨어 상에서는 수정이 필요 없는 것이다.

 

  이제 스프링 프로젝트랑 DB를 연결 하는 작업을 해보자. 우리는 취미로 코딩을 하는 개발자이기 때문에 라이센스 비용이 필요없는 무료 RDBMS인 Mara DB를 사용해보자!

 

  #과정중 이미 해버린 과정은 넘어가면 된다.

1. 마리아 DB 설치

 

https://extsdd.tistory.com/103

 

[Maria DB] 마리아 DB 10.5 다운 및 설치 / 서비스 확인 / 스프링 Spring

스프링 프로젝트에 Maria DB를 사용하기 위해서 설치해보자! Maria DB는 MYSQL DB개발자들이 나와서 만든 "무료" 오픈소스 DB라고 생각하면 된다! 성능이 뛰어난 Oracle, MSSQL은 라이센스가 없어 우리가 사

extsdd.tistory.com

  이미 내가 다 정리해놨다 위 링크로 가서 Maria DB를 설치해 주자!

2. 마리아 DB 접속 테스트

 

https://extsdd.tistory.com/104

 

[Maria DB] 마리아 DB 접속 / HeidiSQL 세션 연결

https://extsdd.tistory.com/103 [Maria DB] 마리아 DB 10.5 다운 및 설치 / 서비스 확인 / 스프링 Spring 스프링 프로젝트에 Maria DB를 사용하기 위해서 설치해보자! Maria DB는 MYSQL DB개발자들이 나와서 만든..

extsdd.tistory.com

  DB 설치를 마쳤다면 이제 위 링크의 설명을 보고 자기가 만든 DB에 접속해보자!!

 

  자 여기까지 왔다면 이제 DB설치가 끝났고 접속도 할 수 있게 되었다. 이제 테이블을 만들어 볼껀데. 일단 테이블 설계부터 해보자.

 

 

 

  난 이렇게 짤 것이다 . 자 테이블 2개를 만들껀데 PRD_MST 테이블에는

  SEQ_NO : 요청번호를 담고있음

  URL_STR : 포워딩할 목적지 주소를 가지고 있음

  DISC_STR : 해당 칼럼에 대한 설명

  USE_YN : 사용유무

  이정도로 두고

 

  REQ_MST 테이블은 살짝 Log성 데이터들이다.

  SEQ_NO : PRD_MST테이블에 있는 SEQ_NO칼럼을 참조

  REQ_DATE : 요청한 날짜

 

  이렇게 셋팅할 것이다

 

 

 

  이해가 더 갈 수 있도록. 엑셀로 가상의 데이터들을 집어 넣어 봤다.

PRD_MST테이블을 보면 4가지 URL정보를 가지고 있고 REQ_MST테이블을 보면 SEQ_NO를 요청할 때마다 그 요청한 날짜의 데이터가 들어가 있는 것을 볼 수 있다. 나중에 이 테이블을 이용해, 1번 요청이 몇일에서 몇일까지 몇번 요청 됐는지, 특정날짜에 요청이 몇번 있었는지 이런 레포트성 데이터를 산출 할 수 있다.

 

  자 설명은 끝났고 이제 DB에 해당 테이블을 생성해보자!

3. 마리아 DB 테이블 생성 및 초기화

 

https://extsdd.tistory.com/105

 

[Maria DB] 마리아 / 데이터베이스(스키마) / 테이블 생성 / 데이터 삽입 INSERT / START TRANSACTION / 데이��

https://extsdd.tistory.com/104 [Maria DB] 마리아 DB 접속 / HeidiSQL 세션 연결 https://extsdd.tistory.com/103 [Maria DB] 마리아 DB 10.5 다운 및 설치 / 서비스 확인 / 스프링 Spring 스프링 프로젝트에 Ma..

extsdd.tistory.com

  위 포스팅으로 가서 DB를 만들어주면 된다.

4. Pom.xml 수정

 

  자. 우리가 프로젝트를 Run했을때, 게시판이 뜨고 간단한 정보들이 들어있는것을 봤을 것이다. 그때 나도 든 생각이 어? 기본 예제인데 머 DB가 구성되어 있나보네? 라고 생각했었는데 맞다. 프로젝트 내부에 hsqlDB가 내장되어있다. 우리는 MariaDB를 사용할 것이기 때문에 hsqlDB를 뜯어내고 마리아DB로 대체해주는 작업을 실시해주자!

 

파일찾기 : Ctrl+Shift+R (Resource)

 

  자 프로젝트에서 컨트롤+쉬프트+R 버튼을 눌러주자.

 

 

 

  검색창에 "pom.xml"을 입력하고 Open 해주자! 그럼 우측과 같은 파일이 열리게 된다!

pom.xml

 

  일단 이 pom.xml은 우리 프로젝트에서 어떤 라이브러리를 사용할지 명시해놓는 장소이다. 예전에 우리가 라이브러리를 사용하려면 무슨..라이브러리 Import하고.. 파일도 따로 관리해주고.. 공홈하고 버전도 다르고.. 완전 개판이었다.. 내 프로젝트 다른사람이 열려고하면 뭐..라이브러리가 없네..파일이 없네...경로가 이상하네...버전이 안맞네.. 이버전과 저번과 충돌이 나네.... 후.. 한마디로 패버릴 만큼 머리가 아팠는데 그간 라이브러리 관리하는 기술이 꽤나 발전했다.

 

  이 pom.xml에 자기가 사용할 라이브러리의 dependency만 걸어놓으면은 알아서 해당 라이브러리의 최신본은 가져와서 적용시켜주고, 라이브러리 잠시 사용안할때는 주석처리로 없앨수도 있다.

 

 

  자 111번줄 언저리로 가보면 hsqldb에서부터 오라클까지 어느정도 dependency가 설정되어있다. 프레임워크 답게, 저기서 자기가 사용하고싶은걸 골라 주석 해제후 뷔페마냥 알아서 쓰란말이다.

 

  자 먼저 1번 hsqldb는 아까 말했듯이, 프로젝트에가 실행되면 그 메모리 위에 올라가는 DB이기 때문에 사용안할 것임으로 주석처리를 하자

 

  2번은 Log4jdbc라고해서 쿼링이 수행되면 그 행동과 결과를 톰캣 콘솔 Log에 찌어주는 아주 고마운 놈이다. 그래서 우린 이친구를 사용할꺼고 이친구는 주석을 풀어준다!

 

  3번 DBCP는 커넥션풀을 관리해주는 친구인데 우리 실습에는 아직 사용안할 것이기 때문에 주석상태로 둔다.

 

  4번 MYSQL 설정은 MARIA DB 설정에서 사용하기 때문에 주석을 풀어줄 것이다.

 

  5번은 ORACLE DB를 쓸꺼냐는말하고 같은데 우린 무료 RDBMS인 MARIA DB를 사용할 것이기 때문에 그냥 주석으로 둔다!! 그럼 코드를 함 수정해보자!

 

 

  그럼 이런모습이 된다. 간단하게 보면 다주석하고 저 log4jdbc와 mysql 이 dependency만 가져가겠다는 것이다.

<!-- Maria DB -->
<dependency>
	<groupId>org.mariadb.jdbc</groupId>
    	<artifactId>mariadb-java-client</artifactId>
    	<version>2.4.1</version>
</dependency>

<!-- Apache Baics Data Source -->
<dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.3</version>
</dependency>

  그리고 마리아 DB를 사용하기 위해서 마리아 DB Dependency 와 아파치 BasicDataSource를 사용하기위한 라이브러리도 필요하다. 위 두 소스를 추가해주자.

 

 

 

 

  짜잔 맨 아래에 두개 추가해줬당! 혹시 오타나 헷갈리는 사람이 있을수도 있으니 111번~164번줄 까지 코드를 첨부해 주겠다! 아 그리고 코드를 추가하면 꼭 저장을 해주자!

 

        <!-- <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>2.3.2</version>
        </dependency> -->
        
        <!-- mysql이나 oracle DB 사용시 아래 설정 추가 -->  
        <dependency>
            <groupId>com.googlecode.log4jdbc</groupId>
            <artifactId>log4jdbc</artifactId>
            <version>1.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <!-- <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency> -->
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.31</version>
        </dependency>

        <!-- <dependency>
            <groupId>ojdbc</groupId>
            <artifactId>ojdbc</artifactId>
            <version>14</version>
            <scope>system</scope>
            <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/ojdbc-14.jar</systemPath>
        </dependency> -->
       
       <!-- Maria DB -->
		<dependency>
			<groupId>org.mariadb.jdbc</groupId>
		    	<artifactId>mariadb-java-client</artifactId>
		    	<version>2.4.1</version>
		</dependency>
		
		<!-- Apache Baisc Data Source -->
		<dependency>
		        <groupId>commons-dbcp</groupId>
		        <artifactId>commons-dbcp</artifactId>
		        <version>1.3</version>
		</dependency>
		
	</dependencies>

 

5. context-datasource.xml 수정

 

 

 

  자 그럼 다시 파일찾기(Ctrl + R)를 눌러 context-datasource.xml 을 검색해주자.

 

 

 

  자 이런화면이 나올텐데 7번 부터 10번줄은 주석처리를 해준다. 그리고 한 12번줄정도에 저 코뭉텅이 하나를 추가해준다. 추가하는 곳에 담기는 내용은 내 로컬 서버의 접속 데이터베이스 명과 접속 계정에 대한 정보가 담긴다.

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://127.0.0.1:3306/cp_service_db" />
        <property name="username" value="root"/>
        <property name="password" value="비밀번호"/>
    </bean>

 

  소스는 여가다 첨부했당 ㅎㅎ. property별로 보자면 일단 url은 접속주소인데 우린 로컬 DB(내컴퓨터)에 접속할꺼니 127.0.0.1(=localhost)는 가만히 두고 :3306이 붙은건 포트이름이다. 바뀔 부분이라면 3306/ 뒤에 접속할 데이터베이스의 테이블 명을 써주면된다. 나는 로컬DB에 저 cp_service_db라는 테이블이 있기 때문에 저렇게 썻다. username은 보통 관리자니까 root을 입력하면 되고 비밀번호는 자기가 지정했던 관리자 비번을 입력하면 끝~ 그리고 저장을 눌러주자.

6. 필요없는 기존 소스파일 삭제

 

 

 

 

  이제 사용하지 않는 기존 소스파일들은 삭제할 것이다. 삭제할게 더 있을텐데 일단 안전빵으로 저 셋트만 삭제하자. 보통 스프링에선 Controller, Service, SeriviceImpl 파일이 세트로 같이 다닌다는 것을 알고 있음 될 것 같다.

 

- EgovSampleServiceImpl.java

- SampleDAO.java

- SampleMapper.java

- EgovSampleService.java

- SampleDefaultVO.java

- SampleVO.java

- EgovSampleController.java

- context-sqlMap.xml

- excample 폴더

 

  위 10개의 파일들은 다 지워주자 필요없다. 삭제는 간단하다 해당 파일명을 클릭하고 Delete버튼을 눌러주면 된다.

 

 

  이런 화면이 뜨는데 그냥 OK를 눌러주자.

7. sql-mapper-config.xml 생성

 

 

 

 

  자 6번 과정에서 보면 example 폴더 밑에 sql-mapper-config.xml 이라는 친구가 있는데 아까 지웠기 때문에 날아갔다 ㅎㅎ 그래서 새로 추가해줘야한당 ㅎㅎ

 

 

  자 sqlmap에서 오른쪽 마우스를 눌러주고 New - Other 버튼을 클릭한다.

 

 

  자 검색창에 XML을 입력하고 나오는 결과중에 XML File 이라는 친구를 누르고 NEXT!

 

 

  파일명을 "sql-mapper-config.xml"으로 설정하고 Finish 버튼을 눌러주자.

 

 

  자.. ㅎㅎ 아무것도 없는 파일이 생겼다..귀찮으니까 소스를 떄려박아주자.

<?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>
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<setting name="jdbcTypeForNull" value="NULL" />
		<setting name="callSettersOnNulls" value="true" />
	</settings>
    <typeAliases>
		<typeAlias alias="egovMap" type="egovframework.rte.psl.dataaccess.util.EgovMap"/>
    </typeAliases>
</configuration>

 

  추가 하는게아니고 저 파일 내용 전체지우고 걍 저거 전체 복붙하면 된다. 여기 sql-mapper-config 파일의 역할은 머 쉽게 말하면 DB에서 데이터들을 이쪽 JAVA를 사용하는 전자정부프레임워크(스프링)에서 알아먹게 하려면 어떤 설정들이 필요할 것이다.

 

  왜냐면 엄연히 다른 시스템이니까, 데이터 베이스와 여기 JAVA 프로젝트는 완전다르다. 그 알아먹게 하는 과정을 Mapping 이라고 하는거라고 생각하면 된다. 매핑이라고 하면 좀 어려운가? 그니까 이런거다, 데이터베이스가 데이터 들을 어떻게 잘 추출은 했다. 그래서 뭐 DB에서 이해할 수 있는 데이터 뭉탱이들이 나왔는데.. 이거 JAVA 너네 어떻게 이해할래..? 이런 의문을 가지다가 JAVA가 음..그럼 너가 나한테 데이터를 ~이렇게 주면 내가 이해해먹을 수 있어!! 하고 서로 이해할 수 있게 맞춰주는것이고, 뭐 매핑보다는 매칭이 더 이해가 잘 될것이다.

 

  아무튼 DB와 JAVA사이에 이렇게 서로 정보들을 이해시키는 과정인 Mapping 과정이 있는데 이걸 어떤식으로 할지 설정을 하는 파일이 이파일이라고 생각하면 된다.

 

  자 셋팅부터 함 보자, 보니까 Camel표현식을 쓰기로 되어있다. 아주 예전에 Camel 표현식을 한번 설명한 적이 있는데 그걸 쓴다는거고, Null 처리는 어떻게할껀지 정도가 나와있다. 그리고 자료형으로 뭘 쓸껀지 머 이런것도 있다. 전자정부 프레임워크에서 사용하는 egovMap 이라는 자료형을 사용한다는 것이다.

 

  머 여기는 이해못해도 되기 때문에 이해하기 싫으면 걍 복붙하고 저장 ㄱㄱ

8. context-mapper.xml 수정

 

 

 

  자 그럼 다시 파일찾기(Ctrl + R)를 눌러 context-mapper.xml 을 검색해 열어주자.

 

 

  보면 이렇게 생겼을텐데 저기 configLocation, mapperLocations 프로퍼티를 주석처리해준다. 잘 보면 어느 경로에서 Config, Mapper 파일들을 읽어올꺼냐는데 저기 example폴더는 우리가 날려버러렸기 때문에 새로 지정해줘야한다.

		<property name="configLocation" value="classpath:/egovframework/sqlmap/sql-mapper-config.xml" />
		<property name="mapperLocations">
			<list>
				<value>classpath:/egovframework/sqlmap/***/*.xml</value>
			</list>
		</property>

 

  경로를 새로 지정하는 코드는 위와 같다. 한 11번째줄 쯤 적절한 곳에 넣어주자. 물론 bean 태그 안에 있어야한다.

 

 

  자 1번 박스를 보면 아까 위에서 말한데로 주석처리 해줘서 지워줬고, 2번 박스를 보자, 11번줄을 먼저보면 classpath가 우리가 아까 7번에서 만들었던 경로로 바뀐걸 볼 수 있다.

 

  12번째 줄 mapprtLocations 프로퍼티를 보면 한줄로 작성된게 아니라 List로 쪼개놨다. 이유는 확장성을 위한건데 경로가 sqlmap/***/*.xml 이런식으로 잡혀있다. 여기서 ***은 "어떤 폴더" 정도로 해석하는 특정되지 않은 폴더이다. 즉, 어떤 폴더 아래있는 모든 xml파일을 보겠다는 것이다.

 

  이렇게 ***(어떤 폴더) 단위를 만든이유가, 나중에 쿼리들을 작성할때 기능에 맞는 쿼리들을 모아놓는게 좋기때문에 저기에 fwd 폴더를 만들어 포워딩에 필요한 쿼리들을 보관하고, 머 예약이면 rsm폴더를 만들어 그밑에 쿼리들을 보관하면 각 기능별로 쿼리 관리가 유용해지니 이렇게 했다. 어려우면 그냥 넘어가도 된다. 크게 중요한 것은 아니다. 결론만 말하자면 sqlmap 폴더밑에 모든 폴더에 있는 모든 xml파일을 mapper파일로 불러오도록 설정했다 ㅎㅎ.

9. 프로젝트 Clean (완전 새로 빌드)

 

  자 이제 마리아 DB연동이 된건고, 서버를 새로 돌려야하는데 변경된 파일들이 많기 때문에 안전빵으로 프로젝트 Clean을 진행해주자.

 

  Project Clean 기능은 이미 만들어진 target 파일 등 이미 만들어진 잡파일들을 다 삭제해줌으로써 프로젝트 빌드시 예전자료 대충 가져와서 만드는게 아닌, 진짜 내가 가진 파일들로 처음부터 빌드 할 수 있게된다.

 

 

  자 Clean 하려는 프로젝트를 선택하고(1) 상단에 Project(2) 메뉴를 누른 뒤 Clean(3) 버튼을 눌러주자

 

 

  저기 Clean all Projects 가 체크되어 있기 때문에 모든 프로젝트가 정리된다. 머 풀고 밑에서 하나씩 골라줘도 되는데 플젝이 몇개없고 가벼운 플젝이니 그냥 Clean을 해준다.

 

 

  5시 방향 구석을 보면 Clean이 진행되는게 보인다. 저기에 뭐 뜨는게 다 없어지면 Clean이 완료된 것이다.

 

10. Server Run / 중간 점검

 

  자 이정도까지만 해도 내 소스파일에 많은 변화가 있었으니, 오류없이 잘 됐는지 보기위해 한번 서버를 Run해보고 http://localhost:8080/reqUrl.do해당 요청을 보냈을때 다른 페이지로 정상적으로 포워딩 하는지 보자.

 

  잘 작동한다면 지금까지 문제가 없는 것이다.기존 Sample파일은 암세포 도려내듯이 살짝잘라서 버려줬고 내 파일들만 정상적으로 남아있는 것이다. 프로젝트 파일내에 자꾸 sample 머시기 파일들이랑 기본 예제 관련 파일들이 많아서 내 프로젝트인데도.. 중고차를 산 느낌처럼 없애고 싶었는데 자 도려낸 것 같다.

 

  만약 여기서 서버 Run이 안돼거나 우리가 만든 reqUrl.do가 실행되지 않는다면 MariaDB에 접속을 못했거나 Sample예제 파일을 도려내면서 먼가 충돌이 일어난것이다. 내가 아는선에서 도와줄테니 댓글에 남겨주길 바란다.

 

  일단 글이 너무 길어져서 데이터 조회 테스트는 못썻는데 다음 포스팅에서 알아보자!

 

#스프링 #전자정부프레임워크 #샘플예제 #Sample #기본예제 #마리아DB #mariaDB #연동 #완전히 #암수술 #마이바티스 #MyBatis

 

반응형
  1. 오류 ㅠㅠ... 2021.04.08 15:44

    심각: Context initialized 이벤트를 [org.springframework.web.context.ContextLoaderListener] 클래스의 인스턴스인 리스너에 전송하는 동안 예외 발생
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSession' defined in file [C:\egov\eGovFrameDev-3.10.0-64bit\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\egovBoardProject\WEB-INF\classes\egovframework\spring\context-mapper.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [C:\egov\eGovFrameDev-3.10.0-64bit\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\egovBoardProject\WEB-INF\classes\egovframework\sqlmap\example\sql-map-config.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 124; 외부 DTD: accessExternalDTD 속성으로 설정된 제한으로 인해 'http' 액세스가 허용되지 않으므로 외부 DTD 'sql-map-config-2.dtd' 읽기를 실패했습니다.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1630)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:737)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4705)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5171)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1412)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1402)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    Caused by: org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [C:\egov\eGovFrameDev-3.10.0-64bit\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\egovBoardProject\WEB-INF\classes\egovframework\sqlmap\example\sql-map-config.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 124; 외부 DTD: accessExternalDTD 속성으로 설정된 제한으로 인해 'http' 액세스가 허용되지 않으므로 외부 DTD 'sql-map-config-2.dtd' 읽기를 실패했습니다.
    at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:595)
    at org.mybatis.spring.SqlSessionFactoryBean.afterPropertiesSet(SqlSessionFactoryBean.java:475)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1688)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1626)
    ... 21 more
    Caused by: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 124; 외부 DTD: accessExternalDTD 속성으로 설정된 제한으로 인해 'http' 액세스가 허용되지 않으므로 외부 DTD 'sql-map-config-2.dtd' 읽기를 실패했습니다.
    at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:263)
    at org.apache.ibatis.parsing.XPathParser.<init>(XPathParser.java:127)
    at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:80)
    at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:592)
    ... 24 more
    Caused by: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 124; 외부 DTD: accessExternalDTD 속성으로 설정된 제한으로 인해 'http' 액세스가 허용되지 않으므로 외부 DTD 'sql-map-config-2.dtd' 읽기를 실패했습니다.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:261)
    ... 27 more
    라고 에러가발생하는데 구글에 검색해보니 DTD 관련 오류인것 같은데... 원래 egov의 sql-mapper-config.xml이랑 같은 내용으로 DOCTYPE을 입력했는데 왜 이 프로젝트에서만 이런 오류가 발생하는거죠?

    • 김진호 2021.11.24 14:31

      저도 동일한 오류네요 ㅎㅎ 내용대로 두번 다시 해 봤는데 동일한 상황이라... 뭔가 아직 맞게 안된 상태인 거 같아요... 이후에 해결됐습니다. mybatis ibatis 설정변경했나... 그런데 암튼 여기 내용들 따라하면서 해결되네요

    • 저는 2021.12.24 15:25

      example 폴더 삭제하고 해보세요
      sql-mapper-config.xml 파일 경로문제일꺼에요

  2. 강카 2021.05.11 17:03

    server run돌리면 하얀 웹화면과 함께 아래와 같은 콘솔이 나오는데 무슨 문제인 건가요?

    2021-05-11 16:49:07,733 WARN [org.springframework.web.servlet.PageNotFound] No mapping found for HTTP request with URI [/Blog/egovSampleList.do] in DispatcherServlet with name 'action'

    • 으엄으엄 2021.05.31 10:33

      저도 같은 에러입니다...해결하셨나요
      -> 해결
      알고보니 index.jsp 에서 egovSampleList.do를 참고하더라고요. 이걸 reqUrl.do로 변경해줬습니다.

  3. 찰스 2021.07.29 08:43

    '-. DB 연동 에러 문의

    [ 작성 코드 ]
    <?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="fwd">
    <select id="selectTargetUrl" parameterType="cpservice.fwd.service.FwdVO" result Type="egovMap">
    /** selectTagetUrl (fwdSql.xml) 마스터코드 목록 조회**/
    SELECT PM.SEQ_NO
    ,PM.URL_STR
    ,PM.DISC_STR
    ,PM.USE_YN
    FROM prd_mst PM
    WHERE PM.SEQ_NO = #{reqParam}
    </select>
    </mapper>

    여기 중에서 "<select id="selectTargetUrl" parameterType="cpservice.fwd.service.FwdVO" result Type="egovMap">" 구문에서 에러가 나는데 알수가 없네요.

    Attribute name "result" associated with an element type "select" must be followed by the ' = ' character.

    이러한 에러가 나면서 원인을 모르겠네요.
    시간 되실 때 답변 부탁드립니다.

  4. asdf 2021.09.06 12:47

    sql-map-config.xml 파일에서 ibatis 주소가 이제는 접속되지 않는 주소입니다. "http://ibatis.apache.org/dtd/sql-map-config-2.dtd" 로 수정해주셔야 하고
    context-mapper.xml파일에서 mapperlocations 부분의 주소가 classpath:/egovframework/sqlmap/example/sample/***/*.xml처럼 기존 샘플 xml파일을 못찾게 해줘야 정상작동 합니다. 다음 강의에서 mapper xml file을 만들어야 하니 저는 그 파일이 들어갈 경로를 지정해놓았습니다
    mapper xml file의 정의를 확인해보시기바랍니다.

  5. 2022.06.30 18:37

    감사합니다...........진짜 한 5~6시간 헤매고 있었는데 이대로 따라하니까 바로 성공했어요 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

반응형

 

https://extsdd.tistory.com/101

 

[Spring/eGov ] #5 웹 서비스 만들기 1 / 컨트롤러 생성 / VO 생성 / Controller / 다른 URL 페이지 포워딩 하�

https://extsdd.tistory.com/100 [Spring/eGov] #4 스프링 Sample 기본 예제 프로젝트, 패키지 이름 바꾸기 / 파일 찾기 extsdd.tistory.com 저번 시간에 드디어 예제 프로젝트의 정체성을 완전히 내걸로 만들어놨..

extsdd.tistory.com

 

 

  저번시간에 사용자가 URL요청을 하면, 서버가 다른 페이지로 넘겨주는 기능을 구현했다. 그런데 만약 여러 주소중 알맞은 주소로 포워딩 시켜준다고 하면 reqUrlNaver.do , reqUrlDaue.do, reqUrlGoogle.do 이런식으로 모든 .do 요청을 다 만들어야 할까?.! 아니다.

 

  페이지를 포워딩 시켜주는 reqUrl.do는 그대로 유지하고, 서버가 판단해주고 알맞은 서버로 포워딩 해주면 될 것같다. 그럴려면 사용자가 reqUrl.do를 호출할때 어떤 주소로 포워딩할 정보를 담아줄지 정보를 같이 넘겨줘야하는데, 이번시간에는 그 정보를 어떻게 넘겨주는지 알아보자! 많이 할껀 없고 저번에 VO를 만들어놨기때문에 좀 수월할 것이다.

 

@ModelAttribute

 

  자 사용자 화면에서 우리 서버로 요청을보낼때 데이터를 실어보내는 방법에는 여러가지가 있다.

  1. URL param (PathVariable)

  2. HttpServletRequest param

  3. RequestParam

  4. 기타 등등..

  꽤 여러가지가 있는데 우린 RequestParam 방식과 비슷하지만, 자동적으로 우리 VO와 매핑시켜주는 @ModelAttribute 방식을 이용해서 구현 할 예정이다.

 

  먼저 RequestParam방식은 @RequestParam("variable1") String variable1 이런식으로 사용자가 variable1로 데이터를 실어서 주면 스프링에선 String 자료형으로 variable1의 변수로 이용할 수 있다인데, 이게 불편한점이 머냐면, 가끔 변수 한, 두개 저렇게 해주면 쓸만한데 예를들어 사용자 페이지에서 변수 데이터 100개를 가져 와야한다고 치면

 

  @RequestParam("variable1") String variable1

  @RequestParam("variable2") String variable2

  @RequestParam("variable3") String variable3

  ...

  @RequestParam("variable100") String variable100

 

  이걸 다달아줘야한다.. 그렇지 않으려면 방법이 멀까!? 바로 VO를 이용하면 된다. 저번시간에 VO라는 친구들 배워봤다. 다시 리마인드 해보자면

 

 

  이런식이다. VariableVO에 변수 1부터 100까지 다 선언해놓고 그 100가지 변수를 담고있는 데이터 주머니를 VariableVO라고 부르는 것이다. 그건 알겠고 이제 그 VO랑 어떻게 하겠다는 건데?

 

 

  히힣.. 놀랍게도 벌써 그 구분은 저번에 코드에 넣어놨다. 저 1번 박스에 있는 부분만 한번 보자. 가장 핵심은 @ModelAttribute 어노테이션인데이 어노테이션은 사용자 페이지에서 넘어온 정보들을 서버에서 있는 스프링 프로젝트(java)단에서 쓸 수 있게 해주는 역할을 한다.

 

  자 그럼 저 어노테이션이 뭔 역할을 하는지 이제 알았고 searchVO라는것은 멀까 search..! 말그대로 찾는다..! 뭐를? VO를..!! VO를 찾는다..! 라는 뜻이다. 이걸 박아놓으면 사용자 요청에 어떤 데이터들이 들어올텐데 이걸 우리가 담을 데이터 바구니(VO)에 알아서 맵핑을 해주겠다는 것이고, searchVO로 불러온 데이터들은 보통 주로 쓰이는 메인 VO이기 때문에 자동으로 .do인 자바 요청이 끝난뒤 다시 사용자 페이지에 결과를 줄때 자동으로 모델에 추가해주는 기능을 한다. model.addAttribute("searchVO"); 이 한줄을 안써도 자동으로 된다는 뜻이다.!

 

  자 이제 개념은 알겠고, 혹여나 몰라도 상관없다. 이제 실습을 통해서 데이터를 어떻게 가지고 오는지 확인해 보자!

 

 

  자 저번에 우리가 만든 VO를 보면 reqParam 이라는 변수를 만들어 놨다. 이제 우리가 페이지 요청을 할때 저 데이터에 담아서 보내볼 껀데, 그 과정을 확인하려면, Debug를 해야한다!

 

Debug (디버그)

 

  오.. 오랫만에 그럴듯한 단어가 나왔다. 시스템에 문제가 생겼을때 개발자들이 말하곤한다. "디버깅해봐!", "디버깅 태워봐!!" 이런식으로 Debug + ing = Debugging 표현하는 것을 어꺠너머로 들어본 사람도 있을 것이다.

 

  TMI이긴 하지만, 근본적인거를 간단히라도 알고 하는게 좋으니까 한번 알아보자 ^_^. 자 Bug는 멀까!? 이거 게임많이 해본 사람이라면 아주 많이 들어봤을것이다. "아ㅡㅡ 버그 생겼어", "이거 버그 아냐!?" 뭔가 시스템적으로 오류가 생기면 버그가 발생했다고들 한다. 버그의 어원은 1940년대 하버드에서 컴퓨터 실험을하다 오작동이 발생해 확인해보니 컴퓨터 하드웨어에 모기가 껴있어서 발생해서 "Bug"라고 불리게 되었다.

 

  자 버그=오작동! 정도로 해석하면 되니 debug는 더 쉬울 것이다. de-라는 접두사는 반대의미를 가지고 있다. debug니 버그가 발생하지 않도록한다는 의미라고 해석하면된다.

 

  그럼 debug의미는 알겠는데 구체적으로 우리 프로그래머 단에서 하는건 먼데? 라고한다면, 코드를 한줄씩 돌려보고, 그 순간에 컴퓨터가 처리하고 있는 객체의 정보를 들여다 볼 수 있다. 즉, 우리가 어떤 요청을 했을때 우리가 보는 화면엔 "페이지를 표시할 수 없습니다" 이런 화면만 뜨면, 문제가 발생한 것은 알 수 있지만, 이 복잡한 컴퓨터 시스템에서 구체적으로 어떤 부분떄문에 문제가 발생했는지는 힘들 것이다. 실행->결과 이렇게만 나오니까.

 

  하지만 Debug과정을통해서 실행->과정->결과의 단계로 우리가 과정을 들여다보면서 원하는 코드구문에 BreakPoint를 걸어 한줄한줄 코드를 들여다보면서 어디서 어떤 부분에 어떤 데이터때문에 문제가 발생하는지 찾아볼 수 있는 분석 툴이라고 보면 된다!

Debug 모드로 프로젝트 실행

 

 

 

  자 우리가 원래 서버를 실행시킬때 보통 재생버튼을 눌러 실행해 보았으나, 이번에는 서버탭(1)을 클릭하고 원하는 서버를 클릭한뒤(2) 벌레모양의 버튼(3)을 눌러보자! 이쯤되면 이제 저 버튼이 왜 벌레오먕인지도 알 것이다. 저 버튼은 Debug 버튼인거다! 벌레잡는 버튼! = 버그 잡는 버튼!!

 

  http://localhost:8080/

 

  자 디버그 모드로 실행되면 뭐..그냥 Run(재생버튼) 했을때와 크게 다른점은 바로 안느껴진다. 일단 서버가 실행되면 정상적으로 실행됐는지 확인해보기 위해서 위 주소로 접속해서 페이지를 정상적으로 띄어주는지 확인해주자. 문제가 없다면 우리가 전에 만들었던 주소도 호출해보자!

 

  http://localhost:8080/reqUrl.do

 

  자 저번에 우리가 네이버로 넘어가는 코드를 작성했으니 네이버로 넘어갈 것이다. 자 이제 전에 만들었던 소스들이 문제가 없다는걸 확인했으니 본격적으로 진행해보자.

Perspective Java EE로 변경

 

  디버그모드를 원할히 이용하려면 Perspective를 변경해줘야한다. 한국말로 관점 정도로 해석하면 되는데,

 

 

  우측 상단 1시방향 구석을 보면 저기에 Perspective를 설정 할 수 있다. 지금 현재 우리는 저 빨간박스 우측에 G머시기가 써져있는 아이콘인 EgovFrame 관점으로 되어있을텐데, 이 Perspective로 하면 브레이크 포인트를 걸 수가 없다. 그러니 우리는 저 자바 콩 아이콘이 그려져있는 저 빨간박스에 있는 버튼을 눌러 Perspective를 변경해주자.

Breakpoints 탭 추가 "Alt + Shift + Q" + "B"

 

  자 디버그 모드로 들어왔는데 머 딱히 달라진게 없어서 별거 없다고 생각한 사람도 있겠지만, 이제부터 시작이다. 일단 Breakpoints 라는 것이 있는데 한국말로 "중단점"이다. 풀어말하자면 멈출 부분이란 뜻이다. 이 서버가 돌아가기 위해선 우리가 작성한 소스코드 일부분을 포함해서 수천, 수만 줄의 소스코드들이 있는데, 이중 우리가 멈춰서 보고싶은 부분에 중단점을 걸어 프로그램을 잠시 그 순간에 잡아두도록 설정할 수 있는 부분이다.

 

  일단 "ALT + SHIFT + Q" 버튼을 눌러보자, 3개의 키를 동시에 눌러주면 된다. 그리고 1초..?2초..?정도 기다려주자. 바로는 안뜨더라..ㅋㅋ

 

 

 

  그럼 화면 우측 하단 구석에 저런 화면이 뜰텐데 우린 Breakpoint를 열어줄꺼니 "B"버튼을 한번 더 눌러주자! 그럼 2번 화면처럼 Breakpoints 탭이 생긴 것을 볼 수 있다. 이 창이 바로 BreakPoints 를 관리하는 화면이다. 사실 단축키 말고 마우스로도 설정에 들어가 이탭을 불러 올 수는 있는데, 너무 과정이 많아서 그냥 단축키를 외우도록하자! "Alt + Shift + Q" + "B"!!

 

Breakpoints 선언 (Ctrl+Shift+B)

 

  자 이제 본격적으로 프로그램을 멈춰줄 중단점을 선언할건데 우린 요청한 데이터가 서버로 들어와 VO에 자동으로 Mapping 되는지를 확인할 것이기 때문에 우리가 만든 요청부분에 Breakpoints를 만들어주자.

 

 

  자 우리가 만든파일 16번 줄에 있는 return "redirect:http://www.naver.com";줄에 마우스를 눌러 입력커서를 저 위치로 이동시키고 Ctrl+Shift+B 단축키를 눌러보자! (1번 박스) 그럼 2번 박스위치에 파란색 점이 하나 찍힐 것이고 3번 박스인 Breakpoints 박스에 해당 중단점이 하나 추가될 것이다! (Brekapoints 박스가 하단에 있을테지만 난 우측이 편해서 우측으로 옮겼당 ㅎㅎ)

 

  1번 위치에서 Ctrl+Shift+B버튼을 눌렀을때 중단점이 추가되지 않은 사람들은 아직 Perspective가 egovFrame일 확률이 높다. 본문 위를 살펴보면 Perspective를 Java EE로 바꾸는 과정이 있는데 따라해주면 해결된다.

 

테스트 요청

 

  localhost:8080/reqUrl.do?reqParam=999

 

  자 이제 저 주소를 한번 들어가보자. 달라진 점이라면 기존 localhost:8080/reqUrl.do 뒤에 ?가 붙었다. ?가 붙으면 뒤쪽은 서버로 전달할 Data를 보내겠다는 의미정도로 해석하면 되겠다. ?뒤쪽을 보면 우리가 VO에서 선언한 변수명인 reqParam이 있다. reqParam=999 의 의미는 저 변수에 999라는 변수를 담아서 보내겠다는 뜻이다 엔터를 쳐보자!

 

 

 

  자 이클립스로 돌아와보면 이런 화면이 떠있을텐데, 중단점을 인식했고, 디버그가 걸렸으니, Perspective를 debug관점으로 바꿀꺼냐는 것인데, 뭐 우린 Debug 관점의 고급기능을 이용할 일은 없으니 1번을 체크해주고 2번을 눌러 관점을 바꾸지 않겠다고 하고 진행한다.

 

 

  소스 코드를 보면 우리가 중단점을 건 부분이 초록색으로 표시되며 현재 저부분에서 프로그램이 멈춰있다! 라고 생각하면 된다. 그럼 저 당시의 변수들을 어떻게 보는지 알아보장!

 

 

  자 1번 위치에 마우스를 올려 한 1초정도를 기다리면 노란색 박스가 뜨는데 거기 보면 지금 FwdVO형태로 이름이 맞는것끼리 자동으로 매핑된 reqParam이 들어온 것을 볼 수 있다. 값도 보면 999로 들어온 것을 볼 수 있다.

 

  현재 우리 VO에는 reqParam으로 한개 변수 밖에 없지만, 만약 여러개의 변수를 전달한다고 하면

 

  http://localhost:8080/reqUrl.do?reqParam=999&reqName=꺄하하

 

  이런식으로 변수뒤에 "&" 기호를 붙혀 추가로 전달이 가능하다. 아마 저 주소를 그대로 입력하면 오류가 나지는 않는다. 매핑할 수 있는것만 매핑하는 것이기 때문에 FwdVO에 선언되지 않은 reqName이란 변수는 매핑되지 않고 그냥 무시 되는 것이다!

 

  그리고 http://localhost:8080/reqUrl.do?reqParam=꺄하하

이 주소를 호출하면 역시 에러가 발생할 것이다 왜냐하면 FwdVO에 reqParam이 정수형인 Int로 선언되어 있는데 데이터로 "꺄하하"라는 String 형의 변수가 들어오니 형이 맞지않아 매핑에 실패하는 것이당 ㅎㅎ

 

 

  마지막으로 이런 URL 파라미터 전달방식으로 100개의 변수를 전달한다고 하면, 주소가 엄청나게 길어질 것이다. 이렇게 하지 않기위해 나중에는 form에 있는 정보를 그대로 보내는 방식이 있는데 그건 나중에 배워보도록하고 일단은 한두개 전달하는건 이방식이 좋으니 이렇게 진행해보자.

 

 

  자 다시 이상황으로 돌아와서 보면, 지금 저 16번째줄에 프로그램이 걸려있고 저 페이지를 요청한 인터넷 창을보면 아직도 모래시계가 뜨면서 멈춰 있는 것을 볼 수 있다. 이떄 한줄 씩 진행하고 싶을때는 F8을 진행시켜 진행해보자.

 

  - F5 : 함수 안으로 들어가본다

  - F6 : 코드를 한줄씩 실행시킨다

  - F7 : 이 함수를 나온다.

  - F8 : 걍 진행한다.

 

  이렇게 4가지 단축키로 프로그램 실행을 분석할 수 있다. 보통 F5는 잘 안누른다. 해당 함수안까지 봐야하는 세부분석이 필요할 때 보통 누르고, 보통은 F6을 눌러 한줄씩 실행한다. F7도 보통 많이 쓰진 않았다. F8은 중단점을 풀어 진행한다. 하지만 계쏙 진행하다 내가 만들어놨던 중단점을 또 만나면 그때 다시 중단점이 걸린다.

 

  자 저상태에서 F8을 눌렀다면 중단점에서 빠져나와 프로그램이 계속 실행되고 최초 해당 URL을 요청했던 인터넷 페이지는 정상적으로 Naver를 띄우고 있을 것이다.

 

사용자 요청에 따른 분기처리

 

  자 그럼 우리가 사용자가 reqParam에 1을 담아서 주면 네이버로 연결시켜주고, 2를 담아서 주면 다음에 연결시켜주는 소스를 작성해보자.

 

 

  자 기존 return 머시기 한줄 있던 코드대신 저 빨간 박스에 있는 코드들로 변경해주자. 그리고 Breakpoint도 ㄷ저 if문 처음 시작할때로 지정해주자.

package cpservice.fwd.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import cpservice.fwd.service.FwdVO;

@Controller
public class FwdController {

	@RequestMapping(value = "/reqUrl.do")
	public String selectReqUrl(@ModelAttribute("searchVO") FwdVO searchVO, ModelMap model) throws Exception {
		
		if (searchVO.getReqParam() == 1){
			return "redirect:http://www.naver.com";
		}else if(searchVO.getReqParam() ==2){
			return "redirect:http://www.daum.net";
		}
		
		return "redirect:http://www.google.com";
		
	}
	
}

 

귀찮은 사람을 위해서 코드도 첨부했당. ㅎㅎ

 

 

  코드 분석을 해보자.

 

  16번 줄을 보면 searchVO에서 reqParam의 값이 1이면

  17번 줄처럼 네이버로 연결시켜준다.

  18번 줄처럼 만약 reqParam의 값이 2면

  19번 줄처럼 다음으로 연결시켜준다.

 

  만약 reqParam의 값이 1도 2도 아니고 없거나 다른 숫자가 들어오면 그냥 구글로 넘겨준다!

 

  이정도 코드로 보면된다. 여기서 물어볼만한건, searchVO에서 값을 쓰고, 꺼내오는건 저번 시간에 VO를 선언할때 안에 같이 따라오는 get, set 함수를 지정했기 떄문에 이걸로 꺼내오느라고 searchVO.getReqParam() 함수를 사용하는 것이고 22번줄에 구글로 포워딩시켜주는 return을 넣어놓은 이유는 사용자가 요청을 줄때 꼭 reqParam을 안넘겨 줄 수도 있고, 혹은 넘겨준다 하더라고 1이나 2가 아닌 999를 넘겨줄 때는 처리할 로직이 없기때문에 그 아무것도 아닌경우는 구글롤 넘겨주겠다~ 해주는 로직이다.

 

  자 16번 if문줄에 브레이크 포인트를 걸었다면 진짜 값들을 보면서 어떻게 처리되는지 확인해보자. 코드가 수정됐으니 다시 Debug버튼을 눌러 서버를 재부팅 시켜주고 주소를 요청해보자!

 

http://localhost:8080/reqUrl.do

 

  자 우리가 처음 작성했던 기본 구문이다 어떻게 되는지 보기위해 인터넷창에 한번 쳐보자!

Variables 탭 추가 "Alt + Shift + Q" + "V"

 

  일단 우리가 들어온 값들을 계속 마우스 올려 보면 귀찮으니 이걸 보여주는 탭을 추가해보자, BreakPoints창을 연것과 단축키가 비슷하다, 알트+쉬프트+Q를 누르면 한 1~2초뒤 우측 하단에 머 창이뜨는데 거기서 V를 눌러주자.

 

 

  그럼 이렇게 현재 값들을 볼 수 이쓴ㄴ Variables 탭이 추가된다. 이제 코드를 한줄한줄 돌리면서 값들이 바뀌면 실시간으로 저 Variable들이 변화를 하게 된다. 위 사진처럼 searchVO를 펼쳐보면 reqParam이 보이게되고, 변수를 담아서 보내지 않으면 0을 보내주는 것을 알 수 있다.

 

 

  자 다시 돌아와서 현재 16번 줄에 멈춰있고 지금 이순간 searchVO에 reqParam은 0의 값이 들어온 것을 볼 수 있다. 이제 F6을 눌러 한줄 진행하면 16번 줄의 if문을 실행한 결과로 넘어간다. F6을 한번 눌러보자.

 

 

  자 1번 위치에서 2번 위치로 이동했다. 이유가 멀까. 간단하다 reqParam의 값이 0이니까 저 if문에 reqParam이 1이 아니기때문에 통과한 것이다. 한번더 F6을 눌러보자.

 

 

  자 2번 박스의 if문에도 해당하지 않으니 당연히 3번 박스로 커서가 이동할꺼고 이때 F8을 눌러 진행을 시키면 페이지가 google로 이동한 것을 볼 수 있다.

 

 

  이제 URL에 값을 넣어서 한번 테스트해보자.

 

  http://localhost:8080/reqUrl.do?reqParam=1

 

  다시 디버그가 걸릴텐대 한번 확인해보장

 

 

 

  자 우측 Variable화면을 보면 reqParam이 1로 들어온 것을 볼 수 있고 일단 16번줄에 브포를 걸었으니 멈춰있는데 F6을 한번 눌러보자!

 

 

  자 reqParam에 1이 들어왔으니 당연히 if문 내부로 통과할 것이고 커서가 2번 박스로 들어올꺼다. 여기서 F8을 눌러 진행하면 naver로 포워딩이 되고, 다시 reqParam을 2로 요청하고 다시 디버그 결과를 보면 daum으로 포워딩 되는 것을 볼 수 있다!

 

요청에 따른 분기처리는 여기까지~

 

 

#스프링 #Spring #전자정부프레임워크 #웹서비스 #만들기 #URL파라미터 #디버깅 #Debug #방법

 

 

반응형
  1. 김진호 2021.11.23 16:59

    정말 친절하게도 아주 자세하게 설명해 주셨네요.
    수고 많으셨습니다.
    감사합니다 ^^

반응형

 

https://extsdd.tistory.com/100

 

[Spring/eGov] #4 스프링 Sample 기본 예제 프로젝트, 패키지 이름 바꾸기 / 파일 찾기

 

extsdd.tistory.com

 

  저번 시간에 드디어 예제 프로젝트의 정체성을 완전히 내걸로 만들어놨다 ㅎㅎ이제 진짜 내프로젝트다. 이제 진짜 간단한 웹서비스를 만들어 볼껀데, 만드려는 서비스는 웹페이지를 포워딩 시켜주는 서비스 이다. 포워딩이란 다른곳으로 안내해준다는 건데, 사용자가 특정 URL로 접근하면 사용자가 가진 데이터를 확인해서 어디로 보내줘야할지 서버가 판단해주는 역할을 수행할 예정이다. 잔말 말고 컨트롤러를 추가해보자!!

 

1. Controller 추가

 

 

 

  일단 저번에 우리가 이 포워딩 기능을 담당하는 패키지가 fwd(fowarding)라고 정해놓았고 전 글들을 읽으면 알겠지만 컨트롤러 파일은 web에 위치해 있다. 따라서 1번에 있는 cpservice.fwd.web 디렉토리에 2번 New를 눌러 3번 Class를 생성해주자.

 

 

 

  별거 없다. 1번에 기능+Controller의 이름을 설정한다. 나는 forwading 기능을 수행하는 Controller이기 때문에 FwdController로 명명했다. 완료되면 딴거 손델 필요 없이 Finish를 눌러주자.

 

 

  ㅡㅡ... 찐따같은 파일이 하나 생겼다...음.. 지금까지 보던것고 다르게 간지가 하나도 안난다..기본적인 컨트롤러의 꼴을 잡아보자.

 

  먼저 이 FwdController 자바 파일은 컨트롤러의 역할을 수행할 것이기 때문에 서버가 서블릿한테 내가 컨트롤러라는 것을 알려야한다. 그러기 위해선 저번시간에 말했던 @ 모양의 어노테이션을 이용해 알린다고 했다. 한번 추가해보자

 

 

  망해따 벌써 오류가 뜬다.. 하지만 아니다. 저 빨간 줄이뜬 Controller라는 글자위에 마우스를 올려두고 한 1~2초를 기다려보자.

 

 

  이런 창이 나타난다. 그렇다 이클립스는 오류가 발생했을때 자기가 해결 할 수 있는만한것은 여려가지 방법으로 저렇게 추천을 해준다. 위 오류는 그거다. 그냥 @Controller만 써놓으면 컴퓨터가 모른다는 것이다. 그럼 저기 빨간 네모친 해결방안을 눌러보자.

 

 

  그럼 저 컨트롤러에 대한 정보들이 Import되는 것을 볼 수 있다. 그렇다. 컴퓨터가 알아먹을 수 있게 쟤에 대한 정보를 우리 컨트롤러에서 사용할 수 있도록 불러오자는 뜻이다. 저 org.springframework.stereotype.Controller 파일을 여기서도 사용하겠단 뜻이다. 그럼 저 @Controller가 뭔지 어떤놈이지 알아먹을 수 있단 소리로 이해하면 된다.

 

  저렇게 @Controller를 컨트롤러 클래스에 붙여놓음으로써 이제 서블릿은 사용자의 요청이 들어왔을때 여기서도 뒤지게 된다 ㅎㅎ 자. 이제 컨트롤러는 만들었고 이제 기능을 진짜로 만들어보자!!

 

  위에서 말했든 만들어볼 기능은 어떤 데이터를 사용자가 주면 그거에 따라서 서버가 알맞은 페이지를 띄어주는 기능이다. 자 그럼.. 일단 먼저 선행되어야 하는게. 사용자가 데이터를 줄때 이 데이터를 어떻게 넘겨주고, 서버에서 그걸 어떻게 받느냐는 것이다.

VO = Value Object (데이터 주머니)

 

  자 스프링에서 자료를 주고받고하는 대표적인 개념이다 브이오!! 한국말로 값을 가진 객체다!! 이게 머냐면은, 음.........구식 방식부터 생각해보자. 고객 검색 기능을 수행한다고 할때 최초에 사용자가 고객을 검색하면 이름, 연락처, 주소 등 3가지의 정보를 조회했다고 해보자. 과거에는 이 값들을 다 코드에 쳐서 달고 다녔다.

 

  통신기술이 발달함에 따라, 더 많은 정보들을 처리하게 되고, 예전시스템으로 어떤 기능을 처리하는데 200개의 변수를 담고 있다면.. 생각만해도 개 노가다일꺼 같다는 생각이 든다.. 그리고 이 고객정보 데이터를 한번만 가지고 가는것도 아니고 연계기능들을 수행하면서 계속 달고다니는데 그럴수록 문제는 더 심해진다.

 

  그래서 나온게 바로 VO다! 값들을 가진 객체!! 근데 이게 모든 데이터를 VO라는 데이터 주머니에 다 때려 박는게 아니고, 그 컨트롤러가 취급하는 정보들끼리 나눠놓는 것이다. 자 봐라, 고객정보를 처리하는 컨트롤러가 있고, 예약정보를 처리하는 컨트롤러가 있다고하면 여기서 VO는 몇개 일까? 2개다! (죽어도 2개여야하는 것은 아니다. 같이 쓸 수도 있고, 공통VO도 있고 하니까..)

 

 

  위 사진처럼 각 컨트롤러마다 필요한 공통정보들이 들어가 있을것이다. 저렇게 기능단위로 다 묶어놓으면 예약을 처리할때 저 VO만 가지고 댕기면 예약처리하는곳 어디서든 저 VO객체 하나만 넘기면 되는것이다. ㅎㅎ 쉽게 말하면 각 컨트롤러에서 사용하는 데이터들을 각각 모아놓은게 VO라고 보면 된다.

 

  나는 FwdController에서 취급할 데이터로는 고객이 요청할때 숫자 데이터를 넣어줄껀데 그데이터를 담고있는 VO를 지금 만들어보자.

 

 

  내가 FwdController에서 사용 할 VO다.... 기능이 너무 간단해서 사용자가 요청하는 데이터 한개만 담고 있을 VO다 .. 간지는 안나지만 따라하기엔 쉬울것이다. 이제 진짜 VO를 만들어보자.

 

 

  우리가 컨트롤러.java 파일을 생성했던 것 처럼 cpservice.fwd.service 패키지에 FwdVO.java를 추가해준다. 그리고 더블클릭하여 코드를보자!... 역시 간지가 안난다 빨리 채워보자.

package cpservice.fwd.service;

import java.io.Serializable;
import org.apache.commons.lang3.builder.ToStringBuilder;

public class FwdVO implements Serializable{


	/** reqParam */
	private int reqParam;

	public int getReqParam() {
		return reqParam;
	}

	public void setReqParam(int reqParam) {
		this.reqParam = reqParam;
	}


	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this);
	}
	
}

 

  해당 내용을 복붙해준다. 만약 프로젝트 이름이 다르다면 그것만 수정해주면 된다.

 

 

  소스를 복붙하고, 저기 FwdVO에 마우스를 올리면 Add generated serial version ID 버튼이 있자. 버튼을 눌러 UID를 할당시키자. serialVersionUID란 같은 클래스인지 판별할때 쓰이는데 나중에 프로그램이 변하거나 할때 프로젝트가 안깨질 확률이 높아진다. 눌러서 추가하자.

 

 

  자 UID를 추가해서 serialVersionUID가 생성된 것을 볼 수 있다. 근데 저건 사실 필요없고 이제 VO에 담길 실제 데이터를 보자. 나는 진짜 딱 한 변수만 VO에 담았다. 혹시 다른사람 더 추가하고 싶은게 있으면 1번꼴로 계속 밑에 써내려가면 된다. 2번 박스는 VO에 한번만 작성되면 되는거라서 신경이 크게 안쓰인다. 머냐면은 VO.toString() 함수를 돌리면 VO내부에 있는 key 와 Value들이 쭈르륵 나와주게 하는 함수이다. 보통 로그데이터를 뽑거나할때 많이 쓰인다.

 

  다시 1번 박스를 보면 VO의 한 데이터는 3가지 구성으로 되어 있다 먼저 자료 선언이 있다. 나는 private int reqParam으로 선언해놨고 그 밑에 get, set이 붙은 함수들이 있다. 이건 약속이다 VO는 데이터 주머니기 때문에 데이터를 set하고 다시 가져갈 수 있도록 get이 있어야한다. 한변수당 이 두개 함수는 무조건 와야하는 것이다. 만약 없으면 오류가 난다.

 

자 여기까지 했으면 ReqParam이라는 하나의 데이터를 가지고 있는 주머니인 FwdVO를 생성했다. 이제 데이터 주고받을 주머니도 만들어 놨으니 진짜!! 컨트롤러에서 기능을 구현해보자!

 

@Request Mapping

 

package cpservice.fwd.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import cpservice.fwd.service.FwdVO;

@Controller
public class FwdController {

	@RequestMapping(value = "/reqUrl.do")
	public String selectSampleList(@ModelAttribute("searchVO") FwdVO searchVO, ModelMap model) throws Exception {

		return "redirect:http://www.naver.com";
		
	}
	
}

  자 다시 FwdController.java로 돌아와서 위 코드를 넣어주자! 그리고 코드를 분석해보자.

 

 

  새로 생긴거 위주로 보면 1번은 뭐 이제 살짝 느꼇을꺼다..크게 뭐 중요한건 아니라는걸... 어차피 소스 추가하면 이클립스가 다 자동으로 추가하기도 해주고, 없으면 넣으라고 알려도 주니까. 암튼 저 임포트 파일들은 아래 소스코드를 돌리는데 필요한 객체들을 다 가져와 놓은 것이라고 볼 수 있다.

 

  2번 박스를 보면 핵심이다. @RequestMapping 어노테이션이 붙으면 이건 서버에서 Servlet이 받아들일 URL주소를 정의할 수 있다! 나는 reqUrl.do 라고 정의해놨는데 기존에는 localhost:8080/reqUrl.do 주소를 쳐도 서버는 저게 뭔지 알 수 없었지만 이걸 추가하는 순간 서버는 localhost:8080/reqUrl.do를 요청하면 아래 구문들을 수행하게 된다!! 이런식으로 서버에 요청들을 여기 등록해놓을 수 있는것이다. 물론 경로형태로도 등록할 수 있다. localhost:8080/tm/rs/rm/reqUrl.do 이런식으로 세분화 시킬수도 있다는 말이당 ㅎㅎ 요기다 자기가 원하는 URL을 정의하면 된다. 나는 URL을 요청하는 작업을 구현할 것이기 때문에 reqUrl.do 로 지었당.

 

  3번 박스를 보면 함수이름은 selectReqUrl이고 그뒤가 살짝 어려울 수 있을텐데 설명을 들으면 그나마 이해가 갈 것이다. 자 처음부터 @modelAttribute("searchVO" FwdVO searchVO, ModelMap model) 이 구분부터 보면 이 요청이 오면 FwdVO라는 데이터주머니에 담아서 searchVO라는 이름으로 이 함수 내부에서 사용할 것이다. 그리고 model이라는 것을 만들어놨다가. 로직을 처하면서 여기다가 사용자가 볼 화면으로 보내줄 데이터들을 모아놓을 것이다~ 이정도 의미로 해석하면 되고, throws Exception 구문은 만약 에러가 발생할시 작동하는 함수인데 보통 서버 Log에 해당 사항을 기록한다.

 

  마지막 4번 보면 함수 내부에 별다른 로직은 없고 바로 return이 되는데, 기능을 해석해보면 사용자가 localhost:8080/reqUrl.do 이 URL로 접속하면 다시 naver로 포워딩 시켜주는 기능을 수행하게 되는 것이다. ㅎㅎㅎ

 

테스트

 

  자 이제 잘 작동하는지 모두 저장하고 서버를 작동시키자! 여러번 해봤으니 이제 따로 설명은 Pass..!

localhost:8080/reqUrl.do를 인터넷창에 입력해보자!

 

 

  뚜둔..! 분명 localhost 머시기 주소를 치고 들어갔지만 네이버 화면이 떳다!! 내가 만든 서버가 작동한 순간이다 .. 감동 짝짝짝.. 일단 오늘 여기까지하고.. 너무 졸려서 자러가야겠다..

 

#스프링 #Spring #전자정부프레임워크 #웹서비스 #만들기 #컨트롤러 #VO #생성 #다른 #URL #포워딩 #Controller

 

반응형
  1. 익명 2021.01.04 14:57

    비밀댓글입니다

  2. 익명 2021.01.28 13:21

    비밀댓글입니다

반응형

 

https://extsdd.tistory.com/99

 

[Spring/eGov] #3 스프링 기본 구조 / Sample 예제 프로젝트 분석 / 원리 / 전자정부프레임워크 / 컨트롤�

 

extsdd.tistory.com

 

  저번시간에 기본적인 스프링 프로젝트가 어떤식으로 돌아가는지 알아보았다. 막판에 카페 닫을시간이 되서 급히 마무리한 감이있는데, 오늘도 열심히 진도를 빼보자!

 

  오늘 해볼일은 바로 전자정부 예제로 들어있는 Sample 예제 프로젝트를 내 프로젝트로 바꿔보려고 한다. 이게 무슨말이냐고!? 자 우리가 셈플 프로젝트를 생성하면 패키지 디렉토리의 이름들이 egovframework.example 로 되어있고, 이름들이 sample 머시기로 되어있으니까 아무리 생각해도 간지가 안난다. 내 프로젝트는 따로 이름이 있다고!!

 

  그럼 아예 너껄로 새로 만들면 되잖아 ㅡㅡ! 라고 생각할 수 있지만... 그건 ..싫다.. 왜냐하면.. 기본예제에 셋팅이 너무 잘되어 있기 때문이다... DB를 읽어오는 MYBATIS, IBATIS등.. 이미 유용한 라이브러리들도 연동이 되어있기 떄문에 아예 깡통에서 시작해서 이것들을 추가하느니 그냥 샘플 예제의 이름만 내껄로 바꾸는게 이득이라고 판단했기 때문이다. 그럼 시작해보자

 

1. 패키지 디렉토리 수정

 

 

 

 

  자 먼저 패키지 익스플로어에서 1번 화살표를누르고 2번 package Presentation 버튼을 눌러준다. 나는 보통 하이어라키 타입을 쓰는데 디렉토리 수정을 위해서 Flat으로 바꿔주자!

 

 

 

  자 우리가 바꿀 패키지들은 1번 박스에 있는 총 5개를 바꿔야 한다. 보면 알겠지만 egovframework.example 이부분이 기본 예제이름으로 박힌 것 같고 나머지 cmmn 은 공통기능이니까 놔두고 sample은 샘플 기능으로 넣은것이니 저 패키지 명도 바꿔주도록 하자!

 

  - egoveframework.example → cpservice (자기 프로젝트 이름)

  - egoveframework.example.sample → fwd (기능 집합 이름) (fwd = forwarding 기능들의 집합)

 

  나는 저렇게 바꾸려고 한다. 내가 시험으로 만들 서비스 이름은 내 서버로 요청이 들어오면 그걸 다른 인터넷 URL로 포워딩 해주는 기능이기 때문이다. 바꿀 명칭은 3번 박스에 넣고 4번 OK를 눌러 명칭들을 바꿔주자 5개 다 바꿔주면 된다.

 

 

  짜잔~ 바꾸면 이렇게 될 것이다 ㅎㅎ

 

2. base-package 명 변경

 

  자. 이제 두번째로 할 것은 바로 base package명을 바꿔주는 것이다. 이게머냐면, 어떤 패키지 디렉토리들에서 컨트롤러 파일들을 읽어올 것이냐는 것이다 ! 이해가 됐으려나..!? 어려운건 없어보이는데..? 말로만 하면 모르니 파일을 보면서 다시보자

 

  먼저 알아야할게 있다. 앞으로 가장 많이 쓸 단축키인데 우리 프로젝트 소스상 특정 텍스트를 검색하는 기능이다.

파일 검색 : Ctrl+ H

 

 

 

  자 컨트롤키와 H를 눌러보자. 위 창이 뜨는데 1번에 파일 서치 탭에 들어가보자. 아마 처음 하시는 분들은 여러가지 탭이 뜰텐데 나는 나머지 탭은 많이 안써서 다 꺼놓은 상태이다. 아무튼 File Search탭에 들어가고 2번에는 검색할 스트링을 입력하는 공간이다. 그리고 3번은 확장자인데 *이 입력되어있으면 전체라는 뜻이다. 머 화면단에서만 찾고싶으면 *.js, *.jsp, *.html 등으로 검색하는 확장자를 제한할 수 있다. 우린 소스 규모가 크지 않으니 걍 *로 둬도된다. 나중에 검색 시간이 너무오래걸리면 줄여주도록하고, 마지막 4번을 누르면 검색된당. 검색해보자!

<context:component

  위 텍스트를 복사해서 2번 항목에 넣고 검색을 돌려보자

 

 

  뚜둔! 하단을 보면 검색 결과가 나왔다! 1번 박스를 보니 프로젝트 내에서 모두 2건이 검색됐당!! 2번 박스를 눌러 다 펼쳐보자. 그럼 context-common.xml과 dispatcher-servlet.xml 두파일에서 해당 텍스트가 발견됐다. 두 파일 모두 바꿔줘야하는데 먼저 3-1을 더블 클릭 해보자.

 

 

  처음 열어보면 base-package가 egovframework만 있을텐데 그 앞에 아까 자기가 정했던 패키지 이름을 추가해주고 쉼표를 찍어준다. 나는 패키지 이름의 맨 앞을 cpservice라고 변경했기때문에 cpservice, 을 삽입했다. 그리고 컨트롤+S를 눌러 저장해준다.

 

  이 문서에는 프로젝트에서 공통으로 사용하는 기능들을 객체로 만들어 놓는 곳인데, 그중에 컨트롤러를 긁어오는 친구도 저 우리가 바꾼 beans 에 설정을 해놓기 때문에 바꾸는 것이다. beans이란 일단 간단하게 객체정도로 알고 있으면 된다.

 

 

  자 다시 나머지 하나 3-2번 박스를 더블클릭 눌러 dispatcher-servlet.xml을 열어준다. 수정하는 방법은 똑같아. 자신 패키지, 을 추가해준다.

 

  이 dispatcher-servlet.xml은 사용자의 요청이 들어왔을때 이걸 어떤놈한테 떤져줄지에대한 정보를 정의해 놓는곳이라, 여기에도 우리의 새로운 패키지를 인식시켜놔야 그 패키지의 컨트롤러를 인식한다.

3. 참조 패키지 디렉토리명 일괄 변경

 

자. 큰 설정은 끝났는데, 이미 소스코드상에서 기존에 있던 패키지명을 참조하는 부분도 있을것 아닌가? 그부분을 한방에 바꿔주기 위해서 서치기능인 컨트롤+H버튼을 눌러보자!

egovframework.example.sample

 

  자 위에 검색어를 입력하고 2번 박스에 있는 Replace를 눌러보자! 그럼 창이 또 뜨는데 With칸에 아까 우리가 위에서 변경했던 패키지 명을 참조해 자신 프로젝트명.기능명으로 바꿔보자!

 

 

egovframework.example

 

  이번엔 이거를 바꾸자 이건 프로젝트명으로만 바꾸면된다. 참고로 위에 바꾼거하고 순서가 바뀌면 안된다!

4.확인

 

 

 

  자 서버를 실행시켜야 하는데, 뭐 저번에 잘 따라왔다면 잘 알겠지만 까먹었을 분들을 위해서 새로 캡쳐해왔다. 하단에 서버탭에 들어가 실행하려는 서버를 클릭하고 재생버튼을 누르면 된다.

 

 

  그럼 Console들이 이렇게 쭉 찍히고 다 완료되면 하단에 빨간줄이 몇줄 찍힌다. 그리고 서버탭에 톰캣의 상태가 Started상태로 변하기도한다. 서버 부팅을 완료했으면 자기 로컬 서버에 들어가보자.

 

http://localhost:8080

 

접속!

 

 

 

  이상 없이 빌드된 것을 볼 수 있다. ㅎㅎ다음시간엔 진짜 기능을 만들어보도록 하자!

 

#스프링 #Spring #전자정부프레임워크 #기본예제 #Sample #프로젝트 #이름 #패키지 #바꾸기 #파일 찾기 #샘플

 

 

 

반응형
  1. 쿠거 2020.12.02 09:16

    안녕하세요. 선생님의 포스팅을 보고 웹프로젝트를 실습하고 있는데요.

    [Spring/eGov] #4 스프링 Sample 기본 예제 프로젝트, 패키지 이름 바꾸기 / 파일 찾기
    3. 참조 패키지 디렉토리명 일괄 변경 부분이 그림/내용 등 뭔가 빠진듯 합니다.
    포스팅과 똑같이 cpservice로 그대로 따라 했습니다.
    컨트롤+H 로 egovframework.example 서치시 8개정도가 나오는데 포스팅 자료는 1개 나오고
    그리고
    egovframework.example.sample => 프로젝트명.기능명
    egovframework.example => 프로젝트명
    위의 두가지도 우측 replace 할 값을 cpservice 기준으로 명시 부탁 드립니다.
    상단의 5개 패키지명 수정시 처럼...
    암튼 감사히 잘 공부하고 있습니다만 수정 부탁 드립니다.
    수정후 가능하시면 LNIJHOR@hanmail.net 으로 회신한번 주시면 감사하겠습니다.
    금번 실습 프로젝트를 기본으로 ajax, jquery 등등 살을 붙여가면서 실습 예정입니다.

    • 동글 2020.12.30 16:38

      저도 맨처음에 그대로 했다가 안되서 서치된 8개 항목들 하나하나 고쳤는데 패키지명 똑같이 하셨으면 egovfreamework.sample까지 지우시고cpservice.fwd 붙여넣으면 되더라구여

    • WJ.Lee 2021.11.23 16:18 신고

      저 부분을 보면서 실수할 수 있겠구나... 라고 생각했습니다.
      위에서 수정한 것 처럼
      egovframework.example.sample
      => cpservice.fwd

      egovframework.example
      => cpservice

      로 replace 하시면 됩니다.

  2. 저는 2021.12.24 12:12

    저는 cpservice.sample 이런식으로 되어있어서 cpservice.fwd로 바꿔주니깐 되네요

+ Recent posts