programming/spring_security

[spring security] 페이징 게시판 만들기 1) data 가져와서 뿌리기

labj 2014. 9. 14. 10:26

[spring security] 페이징 게시판 만들기 1) data 가져와서 뿌리기


project-sample2.zip


게시판은 다음과 같은 형태로 만들려고 합니다.

게시판이란 것은 DB상에 있는 Data를 유저가 보기 좋게 브라우저에 보여준다고 생각하면 됩니다.

단순히 DB상의 Table의 Data를 그대로 브라우저의 창으로 옮기는 것입니다.

 

게시판은

 

1) 하나의 페이지에 3개 게시물이 보이고 하나의 그룹에 10개 페이지가 보이는 게시판이고

2) 게시물에서 제목을 클릭하면 아래 상세내용이 보이고

3) 상세내용 입력란에 내용을 넣고 등록 버튼을 클릭하면 게시물이 하나 추가되고

4) 수정버튼을 추가하여 수정버튼을 클릭하면 내용이 수정되고

5) 삭제버튼을 클릭하면 게시물이 삭제되는

 

형태로 만들려고 합니다.

 

페이징에 대한 방법은 여러가지가 있습니다. 소스상에 이는 페이징 방법도 그중에 하나입니다.

게시판 화면이 처음 열리면 그 다음부터는 ajax으로 data를 가지고와서 화면에 뿌려줍니다.

등록, 수정, 삭제도 ajax으로 처리합니다.



1. Table 만들기 (/project-sample2/src/main/java/sql/Dump20140914.sql)

SQL 명령어 중에 CREATE 문을 알면 쉽게 만듭니다. 하지만 처음 DB 테이블을 만들려고 보면 어떻게 해야 할지를 모르는 경우가 많습니다.

이 경우에 가장 좋은 방법은 이미 만들어져 있는 테이블의 스키마 정보를 보고 똑같이 만드는 것입니다.

다른 방법은 DB Tool에서 제공하는 메뉴를 이용하는 것입니다.

MySQL Workbench에서 sampleDb의 Table을 선택하고 오른쪽 마우스를 클릭하면 





Create Table 메뉴가 나옵니다. 여기에 테이블 정보를 입력하고 Apply를 누르면 테이블이 하나 생성됩니다.

각 메뉴에 대한 항목은 Database를 공부하면서 하나 하나 알아가야 할 것입니다.




이미 생성되어 있는 테이블의 스키마 정보를 보는 방법은 테이블을 선택하고 마우스 오른쪽 버튼을 클릭하여 Send to SQL Editor > Create Statement 메뉴를 누르면

 



SQL 창에 board 테이블의 create table문이 생성되어 보입니다.

 



이걸 복사하여 그대로 사용하거나 원하는 형태로 변경하여 새롭게 board 테이블을 만듭니다.

 

2. 테이블에 Data 넣기

테이블에 하나의 data를 넣으려면 insert 문을 사용합니다.

테이블을 만들고 테스트를 하려고 보면 data가 1개 가지고는 아무것도 할 수 없습니다.

보통은 100만건 1000만건 정도의 data를 테이블에 넣고서 쿼리 속도가 잘 나오는지 봅니다.

지금은 간단한 테스트를 위해서 몇십건 정도의 data만 넣어봅니다.

이것도 쿼리문을 만들자니 쉽지 않네요

이미 등록되어 있는 data에서 뽑아내거나 MySql Workbench를 이용하여 Data를 입력합니다

먼저 select 쿼리를 합니다.




select 쿼리가 실행되어 쿼리결과가 보이면 중간에 디스켓 모양의 메뉴를 클릭합니다.




여러가지 파일 형식중에서 SQL INSERT statements(*.sql)을 선택합니다.




저장 버튼을 누르고 원하는 테이블명을 Export 합니다.


 

aaa.sql 파일을 텍스트 편집기로 열어보면 원하는 쿼리문이 생성되어 있습니다.

/*

-- Query: SELECT * FROM sampledb.board

LIMIT 0, 1000

 

-- Date: 2014-09-11 00:16

*/

INSERT INTO `board` (`IDX`,`HD_CODE`,`DT_CODE`,`QNA_DSC`,`TITLE`,`CONTENT`,`WRITER_ID`,`NOTIFY_CELLPHONE`,`NOTIFY_SMS_YN`,`ATCH_FILE_NAME`,`ATCH_SVR_FILE_NAME`,`ATCH_FILE_SIZE`,`REG_DAY`,`REPLY_YN`,`REPLY_DAY`,`REPLY_FOR_IDX`,`HITCNT`,`USE_FLAG`) VALUES (1,'BOARD','QNA','Q','제목1','내용1','admin','010-3333-4444','N','a.jpg','a.jpg_20140900112222',1024,'2014-09-08 13:47:42','N',NULL,NULL,0,'Y');

INSERT INTO `board` (`IDX`,`HD_CODE`,`DT_CODE`,`QNA_DSC`,`TITLE`,`CONTENT`,`WRITER_ID`,`NOTIFY_CELLPHONE`,`NOTIFY_SMS_YN`,`ATCH_FILE_NAME`,`ATCH_SVR_FILE_NAME`,`ATCH_FILE_SIZE`,`REG_DAY`,`REPLY_YN`,`REPLY_DAY`,`REPLY_FOR_IDX`,`HITCNT`,`USE_FLAG`) VALUES (2,'BOARD','QNA','Q','제목2','내용2','admin','010-4333-4444','N','a.jpg','a.jpg_20140900112222',1024,'2014-09-08 13:47:58','N',NULL,NULL,0,'Y');

....

 

쿼리문에서 ` 문자는 전부 replace해서 없애 버리고 

 

INSERT INTO board (IDX,HD_CODE,DT_CODE,QNA_DSC,TITLE,CONTENT,WRITER_ID,NOTIFY_CELLPHONE,NOTIFY_SMS_YN,ATCH_FILE_NAME,ATCH_SVR_FILE_NAME,ATCH_FILE_SIZE,REG_DAY,REPLY_YN,REPLY_DAY,REPLY_FOR_IDX,HITCNT,USE_FLAG) VALUES (1,'BOARD','QNA','Q','제목1','내용1','admin','010-3333-4444','N','a.jpg','a.jpg_20140900112222',1024,'2014-09-08 13:47:42','N',NULL,NULL,0,'Y');

 

남은 쿼리문을 가지고  원하는 만큼의 data를 만들어서 insert 합니다.

CREATE TABLE 문을 보면 key 컬럼을 위해서 idx 컬럼에 다음처럼

 

    IDX int(11) NOT NULL AUTO_INCREMENT,

 

AUTO_INCREMENT 문을 사용했습니다. data가 insert 될 때마다 1씩 증가값을 자동으로 넣으라는 명령입니다.

그러므로 아까 INSERT문에서 IDX를 삭제하고 실행해야 합니다.

 

INSERT INTO board (HD_CODE,DT_CODE,QNA_DSC,TITLE,CONTENT,WRITER_ID,NOTIFY_CELLPHONE,NOTIFY_SMS_YN,ATCH_FILE_NAME,ATCH_SVR_FILE_NAME,ATCH_FILE_SIZE,REG_DAY,REPLY_YN,REPLY_DAY,REPLY_FOR_IDX,HITCNT,USE_FLAG) VALUES ('BOARD','QNA','Q','제목1','내용1','admin','010-3333-4444','N','a.jpg','a.jpg_20140900112222',1024,'2014-09-08 13:47:42','N',NULL,NULL,0,'Y');

 


3. MyBatis SQL XML로 data 가져오기

- 조회, 등록, 수정, 삭제하기 흐름

1) 게시판의 조회, 등록, 수정, 삭제를 위해서는 다음 SQL문에 대해서 알아야 합니다.

[기본 SQL]

 - 조회 : SELECT TITLE, CONTENT FROM BOARD;

 - 등록 : INSERT INTO BOARD (TITLE, CONTENT) VALUE ('제목', '내용');

 - 수정 : UPDATE BOARD SET TITLE='제목1', CONTENT='내용1' WHERE IDX=1;

 - 삭제 : DELETE BOARD WHERE IDX=1;

 

여기서는 MyBatis를 조금더 쉽게 사용하기 이 프로젝트에서는 CRUDMapper.java 란 것을 사용합니다.

CRUDMapper.java를 사용하기 전에 미리 MyBatis에 대해서 기본 샘플을 사용하여 테스트를 해 보아야 합니다.

 

 

[MyBatis 테스트 샘플]

 

그래야 어떤 흐름으로 MyBatis가 동작하는지를 알 수 있습니다. 그리고 좀더 응용을 하여 개발을 할 수 있습니다.

CRUDMapper는 MyBatis에서 사용되는 ID값을 미리 등록하고 Mapper를 선언하여 Service단에서 상속받아 사용하는 것입니다.

각 기능별로 Mapper 명만 다르고 ID값은 동일하게 사용하는 것입니다. 이렇게 사용하면 개발속도가 조금더 빨라집니다.

 

2) mapper xml 파일

 

기본 구조는 다음과 같습니다.

 

- BoardMapper.xml

<mapper namespace=... >

           <resultMap id="selectOne" ...>

                     ...

           </resultMap>

 

           <select id=...>              

                     ...

           </select>

          

           <insert id=...>

                     ...

           </insert>         

 

           <update id=...>

                     ...

           </update>

 

           <delete id=...>

                     ...

           </delete>

</mapper>

 

CRUD Mapper에서 정의한 메소드명으로

 

           int selectMapInt1(Map<String, Object> data)  throws DataAccessException;

 

mapper XML 파일에서 id값을 지정하면

 

           <!-- select count -->

           <select id="selectMapInt1" parameterType="java.util.Map" resultType="int">

                     SELECT COUNT(1) FROM BOARD

                     <where>

                                <if test="idx != null and idx != '' ">AND IDX = #{idx }</if>

                                ...

                     </where>

           </select>

 

service단에서 해당하는 메소드를 호출하여

           int total = 0;

           ...

           // total count

           if (chk.equals("0") || chk.equals("")) {

           } else {

                     total = this.selectMapInt1(list);

           }

 

mapper XML 파일에서 SQL문이 생성되어

 

           SELECT COUNT(1) FROM BOARD

           WHERE IDX = 1

           ...

 

Database에서 실행되어 결과가 resultType에 선언된 것처럼 int로 리턴됩니다.

 

           <select id="selectMapInt1" parameterType="java.util.Map" resultType="int">

 

servcie단에서 int totlal 변수에

          

           total = this.selectMapInt1(list);

 

SQL 쿼리 결과값이 담깁니다.

 

 

 

3) mapper xml 에서 쿼리해서 Service단으로 값 전달하기

 

mapper xml에서 사용되는 문법은 JSTL 문법과 비슷합니다.

엘리먼트에 select, insert, update, delete 가 있고

엘리먼트에 따라서 쿼리문을 사용합니다.

어트리뷰트에는  id, parameterType, resultMap, resultType 이 있습니다.

id는 CRUD Mapper에 정의된 메소드명과 동일하게 사용하면 됩니다.

하나의 xml 파일내에서 id는 유니크하게 사용되어야 합니다.

 

parameterType은 쿼리를 위한 조건을 담아서 service단에서 호출할 때 전해주는 값입니다.

 

           - java.lang.String

           - java.util.Map

           - int

           - Domain ( get, set 메소드가 있는 자바 파일)

 

type에 맞는 값을 받으면 해당 엘리먼트 안에서

 

           - parameterType="java.lang.String" :

           #{id}로 값이 들어갑니다. 'id' 라는 변수명은 다른것으로 바뀌어도 됩니다. 엘리먼트 안에서 #{}은 하나만 있어야 합니다.

           SELECT * FROM TBNAME WHERE ID=#{id}

 

           - parameterType="java.util.Map" : 

           map은 service단에서 다음처럼 선언되고 값이 저장되었다면

 

                     Map<String, Object> list = new HashMap<String, Object>();

                     list.put("title", "제목");                

                     list.put("contents", "내용");

 

           mapper xml에서 map의 키값이 변수명이 됩니다.

          

                     SELECT * FROM TBNAME WHERE title=#{title} AND contents=#{contents}

          

MyBatis에서는 parameterType 으로 값을 전달 받으면 쿼리문을 생성합니다.

 

           SELECT * FROM TBNAME WHERE title='제목' AND contents='내용'

 

생성된 쿼리문은 /src/main/resources/properties/jdbc.properties 에 선언된 DB에 접속하여

          

jdbc.driverClassName=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://127.0.0.1:3306/sampledb?characterEncoding=UTF-8

jdbc.username=dbuser

jdbc.password=!password

 

결과값을 가져옵니다.

결과값은 resultMap, resultType 에 선언된 값에 담겨서 service단으로 넘겨집니다.

 

resultMap은 mapper XML문에 보면 상단에 resultMap이라고 선언된 엘리먼트의 id값으로 설정하면 됩니다.

결과값은 resultMap에 선언된 result에 맵핑됩니다.

resultType은  java.lang.String, java.util.Map, int, Domain 으로 설정되고

결과값이 맵핑됩니다.

 

쿼리문의 컬럼이 하나라면 resultType은 java.lang.String, int와 같이 하나가 리턴되는 Type일 것입니다.

 

           SELECT COL1 FROM TBNAME WHERE title=#{title} AND contents=#{contents}

 

 

쿼리문의 컬럼이 여러개라면 resultType은 java.util.Map, Domain와 같이 여러개가 리턴되는 Type일 것입니다.

 

           SELECT COL1, COL2, COL3 FROM TBNAME WHERE title=#{title} AND contents=#{contents}

          

 

쿼리결과가 한개라면 service단에서 java.util.Map, Domain으로 리턴 받습니다.

쿼리결과가 여러개라면 service단에서

 

           List<Board> listData = this.selDomainMap1(list);    

           List<Map<String, Object>> listData = this.selDomainMap1(list);

 

List로 받으면 됩니다.

 

 

4) Controller 단에서 브라우저에서는 처음에 게시판 화면을 보여주기 위해서 /board/main 이란 url을 호출합니다.

브라우저에서는 ajax을 통해서 /board/listAjax 이란 url을 호출합니다.

 

 

 

 

 

 

5) 브라우저에서 게시판에 게시물을 보여주려고 ajax을 통해서 /board/listAjax 이란 url을 호출합니다.

브라우저와 Controller 간에 전달하고 받는 정보는 Firefox에서 Firebug로 확인해 볼 수 있습니다.



 - 브라우저에서 Controller로 전달



 - Controller에서 브라우저로 응답



 - Controller에서 브라우저로 응답을 좀더 보기 좋게 JSON으로


6) 응답받은 json 포맷의 data를 자바스크립트에서 파싱하여 유저가 보기 좋은 형태로 만들어서 Browser로 보여주는 것입니다.

 

htmlTemp = htmlTemp + "<div class=\"tb_tr\">"

+"         <div class=\"tb_td1\">"+rows[i].idx+"</div>"

+"         <div class=\"tb_td2\"><span class=\"btnTitle\" value=\""+i+"\" >"+rows[i].title+"</span></div>"

+"         <div class=\"tb_td3\">"+rows[i].writer_id+"</div>"

+"         <div class=\"tb_td4\">"+rows[i].reg_day+"</div>"

+"</div>";

 

           $("#itemList").html(htmlTemp);

 

게시물의 상세보기를 위해서 응답받은 data를 json 포맷으로 array변수(boardArrayList)에 담아

 

boardArrayList.push({

idx                 :rows[i].idx

,hd_code             :rows[i].hd_code

,dt_code             :rows[i].dt_code

,qna_dsc             :rows[i].qna_dsc

,title               :rows[i].title

,content             :rows[i].content

,writer_id           :rows[i].writer_id

,notify_cellphone    :rows[i].notify_cellphone

,notify_sms_yn       :rows[i].notify_sms_yn

,atch_file_name      :rows[i].atch_file_name

,atch_svr_file_name  :rows[i].atch_svr_file_name

,atch_file_size      :rows[i].atch_file_size

,reg_day             :rows[i].reg_day

,reply_yn            :rows[i].reply_yn

,reply_day           :rows[i].reply_day

,reply_for_idx       :rows[i].reply_for_idx

,hitcnt              :rows[i].hitcnt

,use_flag            :rows[i].use_flag

});

 

게시물을 클릭했을 때 화면에 뿌려줍니다.

 

           $("#itemfrm input[name='idx']").val(boardArrayList[value1].idx

 

 

Database에 있는 data Browser로 온 것 뿐입니다. data Database에서 바로 Browser로 올 수 있도록 한다면 가장 좋은 방법일 것입니다.

 

 

7) 지금까지 쿼리문을 담은 mybatis xml부터 jsp 파일까지 data가 전달되는 것을 보았습니다.

 

- CRUDMapper.java

- CRUDService.java

- CRUDServiceImpl.java

- Board.java

- BoardMapper.xml

- BoardMapper.java

- BoardService.java

- BoardServiceImpl.java

- BoardController.java

- /board/main.jsp

 

9개 파일에 대해서 코딩을 하고 controller에 url을 주면 외부에서 웹프로젝트로 접근 할 수 있습니다.

SpringSecurity에서 하나 더 작업을 할게 있는데 url에 대한 권한 설정입니다.

권한설정은 applicationContext-security.xml 에서 하는데 controller에 선언한 url에 맞추어서 http 엘리먼트 안에

 

           <intercept-url pattern="/board/**"       access="permitAll()" />

 

한줄만 추가하면 됩니다. 그러면 외부에서 url을 통해서 웹서버로 data를 전달하고 받을 수 있게 됩니다.

 



[spring security] 페이징 게시판 만들기 1) data 가져와서 뿌리기