개발에 있어서 가장 중요한 문서는

프로세스 명세서, 화면 설계서, 데이터 베이스 구조(ERD)라고 생각한다.

최소한 이 3가지는 있어야 개발 할 수 있다고 생각하고

이 3가지를 정리하면 웬만한 프로그램도 이해할 수 있다고 생각한다.

화면 설계서는 웹에서 실행시켜보는 것으로 대체하고

나머지 2가지에 대해서 정리했다.


JPetStore는 다음 그림에서 보는 것 같이

일반적인 쇼핑몰과 동일한 기능을 제공하고 있다.


먼저, 쇼핑몰에서 동물에 대한 분류(개, 고양이 등)를 선택하고,

세부 설정에 따라 원하는 동물을 찾아들어 간다.

(검색을 이용 할 수도 있다.)

맘에 드는 동물에 대한 정보를 본 후 ,

카트에 담기(Add to Cart)를 눌러 장바구니(cart)에 담는다.

(화면과 다음 흐름을 맞춰서 보면 이해 하기 쉽다.)


장바구니에서 주문을 하면(Proceed to Checkout)

로그인 창이 나타난다.

로그인 정보는 ID와 비밀번호를 j2ee와 j2ee로 동일하게 입력하면 된다.

(또는 ACID / ACID)

로그인을 하고 결제(주문) 정보를 입력하면

완료 메시지와 구매 리스트를 볼 수 있는 구조로 개발 되었다.

이 흐름은 다음 그림과 같은 URL로 되어 있다.

위 그림과 같이 클릭해 보면

웹 브라우저의 주소 입력창에 나타나는

URL (파마메터 포함)이 다음 그림과 같은 것을 알수 있다.

이 구조로 소스를 찾아보면

개발 흐름을 쉽게 파악할 수 있을 것이다.


다음으로 사용된 데이터 베이스 구조를 살펴 보면(ERD)

다음 그림과 같다.

resource/database/jpetstore-hsqldb-schema.sql파일의 내용을

AmaterasERD로 정리했다.

왼쪽에는 동물 분류와 세부 정보, 오른쪽에는 구매자 정보, 중앙에 주문 정보를 배치했다.

위 그림은 논리모드(Logical Mode),

아래 그림은 물리 모드(Physical Mode)를 갈무리 한 것이다.

주문 테이블(order)에서 ship(ship addr, shipcity...)은

직역으로 선적자로 적었지만 의미상 수신자,

bill(billaddr, billcidy...는 계산자로 번역했지만

주문자로 이해하는 것이 맞다.

전체적인 테이블 구조는 일반적이라

관계(Relation) 중심으로 기억해 두면 될 것 같다.

jpetstore.erd

 

다만, 로그인 관리(signon) 테이블을

계정(account)테이블과 별도로 구성하고

사용자 아이디를

로그인 테이블에서는 username,

계정 테이블에서는 userid로 다르게 명명하고

길이(length)도 25와 80으로 다르게 부여한 것은 이상하다.

같게 기능을 하고 같은 값을 사용하는 것을

왜 다르게 구현했는지...







'Java > JPetStore' 카테고리의 다른 글

1. JPetStore  (2) 2016.11.06
2. JPetStore 설치  (2) 2016.11.06
4. JPetStore - 코드 둘러보기  (1) 2016.11.06

먼저, 기본적인 설명은 http://www.mybatis.org/jpetstore-6/ko/에 잘 정리되어 있다.

여기서는 jpetstore와 spring-jpetstore의 차이를

두 가지로 정리하면서 코드를 둘러봤다.


먼저, JPetStore 예제들은 기본적으로

다음 그림과 같이 MVC(Model–View–Controller)를 지키고 있다.


사용자에 의해 Action(Control)이 호출되고,

데이터 가공이 필요하면 서비스를 통해 DBMS를 제어하고

적절한 가공을 해서 JSP(HTML)로 변환해서

클라이언트(웹브라우저)에게 전송하는 구조를 가지고 있다.


이상의 그림은 MVC에 맞춰서 그렸다기 보다는

jpetstore의 구성 클래스가 존재하는 디렉토리 명 중심으로 작성하였다.


예로, 위 그림에 맞추어

jpetstore의 동물에 대한 분류 화면을 대상으로 함수들을 정리했다.

분류의 첫 화면(http://localhost:8080/jpetstore/actions/Catalog.action)은

HTML로 구성되어 서비스와 매퍼가 사용되지 않아서 넘어가고

상세 분류(Catalog.action?viewCategory=&categoryId=FISH)화면을 대상으로 한다.


Stripes로 인해 URL이 다소 특이하지만

Stripes에 대해서는 찾아보길 바라고 여기서는 간단하게 정리한다.

Spring MVC에서는 viewCategory.action으로 호출하게 되는데

viewCategory 컨트롤이 작성된 클래스의 파라메터처럼 호출한다.

쇼핑몰 구조에서 정리한 동물분류와 관련된 모든 기능은

CatalogActionBean.java에 각각의 함수로 구현되고,

상세 분류(viewCategory)처럼 파라메터로 호출된다.

위 그림에 맞추어 실제 코드를 확인해 보길 바라고,

사용자가 동물 분류중 하나를 선택하면

CatalogActionBean.java에 있는 viewCategory Action이 실행된다.

viewCategory Action에서는 파라메터로

사용자가 선택한 동물 분류(categoryId)가 넘어 오고,

이 분류를 파라메터로 분류별 동물 리스트(getProductListByCategory)를

데이터 베이스에서 찾아온다(CatalogService).

(코드에서는 제품-product-로 사용했는데 동물을 제품으로 부르기...)


spring-jpetstore도 위 그림에 맞추어

다음과 같이 정리했다.

spring-jpetstore는 Spring MVC에 맞추어 개발되어

Action이 아닌 Controller란 말을 사용한다.

viewCategory에 흔히 보는 @RequestMapping도 사용되었다.

웹사이트에서 접속된 URL을 확인하면

다음과 같이 직접 호출된다.

http://localhost:8080/spring-jpetstore/catalog/viewCategory?categoryId=FISH


jpetstore와 spring-jpetstore의 두번째 차이는 로그인 처리이다.


jpetstore에서 원하는 동물을 카트에 넣고

결제를 하려고 하면 다음과 같은 로그인 창이 나타난다.

로그인을 하고 결제를 한뒤,

페이지 상단에 있는 Sign Out 버튼을 이용하여 로그아웃한다.

즉, 로그인 되지 않은 상태에서

자신의 정보를 수정하거나(http://localhost:8080/jpetstore/actions/Account.action?editAccountForm=)

주문 내역을(http://localhost:8080/jpetstore/actions/Order.action?listOrders=)

직접 접속할 경우 빈 값이나 오류 페이지를 보게 된다.

jpetstore는로그인 체크를 하지 않은 것이다.

이처럼 사용자가 로그인을 하지 않은 경우 로그인 페이지로 이동하도록 해야 한다.

다음 코드와 같이 결제를 하려고 할때(newOrderForm)에만

로그인 체크를 하고 있다.

  public Resolution newOrderForm() {
    HttpSession session = context.getRequest().getSession();
    AccountActionBean accountBean = (AccountActionBean) session.getAttribute("/actions/Account.action");
    CartActionBean cartBean = (CartActionBean) session.getAttribute("/actions/Cart.action");

    clear();
    if (accountBean == null || !accountBean.isAuthenticated()) {
      setMessage("You must sign on before attempting to check out.  Please sign on and try checking out again.");
      return new ForwardResolution(AccountActionBean.class);

    } else if (cartBean != null) {
      order.initOrder(accountBean.getAccount(), cartBean.getCart());
      return new ForwardResolution(NEW_ORDER);
    } else {
      setMessage("An order could not be created because a cart could not be found.");
      return new ForwardResolution(ERROR);
    }
  }


반면, spring-jpetstore는 다음 코드에 나타난 것과 같이

로그인 체크를 하고 있지 않다.

    @RequestMapping("newOrderForm")
    public String newOrderForm(OrderForm orderForm, Model model) {
        UserDetails userDetails = (UserDetails) SecurityContextHolder
                .getContext().getAuthentication().getPrincipal();
        Account account = userDetails.getAccount();

        Order order = new Order();
        order.initOrder(account, cart);
        beanMapper.map(order, orderForm);
        model.addAttribute(order);

        return "order/NewOrderForm";
    }

spring-jpetstore는 Spring Security를 적용하여

spring-security.xml에 로그인이 필요한 페이지를 지정하고 있다.

    <sec:http auto-config="true" use-expressions="true">
        <sec:form-login login-page="/account/signonForm"
            login-processing-url="/account/signon"
            authentication-failure-url="/account/signonForm?error=true" />
        <sec:logout delete-cookies="JSESSIONID" logout-url="/account/signoff"
            logout-success-url="/" />
        <sec:intercept-url pattern="/account/editAccount*"
            access="isAuthenticated()" />
        <sec:intercept-url pattern="/order/**" access="isAuthenticated()" />
    </sec:http>

따라서 계정정보 수정(editAccount)이나 주문(order) 등의 페이지를 실행할 때,

로그인을 하지 않은 경우 로그인 창이 실행된다.


이외에 jpetstore에는 JUnit을 이용하여

데이터를 가지고 오는 서비스와 관련된 부분에

단위 테스트가 적용되어 있다.

그림과 같이 테스트할 파일을 선택하고

Run As > JUnit Test로 간단하게 실행해서

정상 실행 되는지 확인해 보자 (그림 중앙 하단).

'Java > JPetStore' 카테고리의 다른 글

1. JPetStore  (2) 2016.11.06
2. JPetStore 설치  (2) 2016.11.06
3. JPetStore - 쇼핑몰 구조  (0) 2016.11.06

Project9은 Spring 4 + MyBatis 3 + MariaDB (Maven) 기반으로 제작한 웹 프로젝트 템플릿이다.

소스는 Github에서 받을 수 있다.

데모는 여기에서 확인할 수 있다.

데모는 AWS 무료를 사용하는 관계로  1년(2017-09-17) 이후에는 접속이 안될 수 있고

작성한 데이터는 통보없이 삭제될 수 있다.

웹 개발시 많이 사용되는 다양한 기능들 미리 구현해 두고

복사해서 사용하기 위해 제작하였다.

많이 사용되는 회원관리(로그인, 로그아웃 포함), 부서관리 (조직도), 게시판 (설정), 무한 댓글 등의 기능을 미리 구현해 두었고,

프로젝트에 따라 필수적인 기능을 샘플로 구현해서

같이 작업하는 개발자들이 일관되고 빠르게 작업할 수 있게 하였다.

그리고, 유사 기능은 복사/붙여넣기를 하여 쉬운 개발을 하려고 준비하였다.

(만들고 보니 전자정부프레임과 비슷한 느낌이…)


주요 구현 기능은 다음과 같다.

  • 멀티 게시판 (무한 댓글, 좋아요 등)
  • 회원 기능: 모든 페이지는 회원만 접속 가능. 로그인/로그 아웃 기능. 회원관리 등
  • 보안 기능: 일반사용자(U)와 관리자(A)로 구분하여 일반 사용자는 관리자 페이지에 접근 불가.
  • 다국어 처리
  • 디자인: 부트스트랩기반 반응형 웹 적용 (SB-Admin)
  • 공통 에러 페이지 처리(404, 500)
  • 로그 처리(logback, log4jdbc)


준비된 샘플

  • 사용자 선택: 부서, 사용자 선택 기능 (팝업)
  • 날짜(DatePicker) 선택 및 챠트(morris) 사용법 샘플
  • 엑셀 다운로드(jXLS) 샘플


사용된 라이브러리와 구성은 다음 그림과 같다.


디렉토리 구조는 다음과 같다.

java 패키지는 gu 하위에 있으며

동일한 디렉토리 구조로 JSP 파일이 WEB-INF 하위의 jsp에 있다.

admin 디렉토리는 관리자 기능으로

게시판 생성과 부서(조직도), 사용자 관리 등을 가지고 있다.

board 디렉토리는 게시판 기능을 가지고 있다.

main 디렉토리는 메인 화면(index)과 샘플을 가지고 있다.

member 디렉토리는 로그인/아웃, 개인정보 수정등을 가지고 있다.

common 디렉토리는 공통 기능을 가진 디렉토리로

파일 업로드/다운로드(엑셀), 권한 관리등을 기능만 가지고 있다.

jsp의 common 디렉토리는 페이징 화면, 오류 페이지등

공통으로 사용되는 화면을 가지고 있다.

마지막으로 etc 디렉토리는 공통으로 사용되는 화면과 기능을 가진 디렉토리로

부서나 사용자 선택등을 가지고 있다.


resources의 message는 다국어 처리 파일을 가지고 있고

sql 디렉토리는 프로그램에서 사용되는 모든 Mybatis SQL문을 가지고 있다.


마지막으로 테이블 구성(ERD)는 다음과 같다.

AmaterasERD로 작성되었고

파일명이 project9.erd로 github에서 같이 배포되고 있다.

Logical mode

Physical mode

'Java > 기타' 카테고리의 다른 글

그룹웨어 (Java) - 설치  (27) 2018.04.15
과제 관리 시스템 (PMS9)  (8) 2016.12.01
Project9 설치  (5) 2016.09.18
데이터를 Excel 파일로 다운로드  (2) 2016.09.18

먼저 Eclipse를 이용하여 github에서 소스를 다운로드 받는다.

Eclipse를 이용하여 github에서 소스를 다운 받는 방법은 여기를 참고하면 된다.

github 소스 주소만 바꾸어서 사용하면 된다.


MariaDB에 데이터 베이스(project9)를 생성하고

소스와 같이 제공되는 tables.sql(테이블 정보), tableData.sql (샘플 데이터)를 실행하여 테이블과 데이터를 생성한다.

MariaDB 데이터 베이스 생성법


applicationContext.xml에 적절한 접속 정보를 입력한다.

톰캣이나 이클립스에서 project9를 실행

http://localhost:8080/project9/로 접속



관리자(admin/admin)로 로그인 하거나

일반 사용자로(user1/user1, user2/user2 ...) 로그인 하면 된다.


PC에서 보는 일반적인 화면


PC에서 보는 작은 화면 or 모바일에서 보는 화면




'Java > 기타' 카테고리의 다른 글

그룹웨어 (Java) - 설치  (27) 2018.04.15
과제 관리 시스템 (PMS9)  (8) 2016.12.01
Project9  (8) 2016.09.18
데이터를 Excel 파일로 다운로드  (2) 2016.09.18

Java에서 데이터를 엑셀로 다운로드 하는 방법은 몇 가지 방법이 있다.

http://greatkim91.tistory.com/72

개인적으로 jXLS를 방법을 선호하는데

jXLS은 템플릿 방식으로 Java의 MVC를 그대로 활용할 수 있기 때문이다.

다만, 엑셀 2003(XLS) 파일만 지원되다 엑셀 2007(XLSX) 파일 지원은 뒤늦게 지원되어

관련 문서가 많지 않아 (못 찾은 것일 수도),

여기에 문서로 정리한다.

http://jxls.sourceforge.net/getting_started.html

https://github.com/svn2github/jxls-105/blob/master/jxls-examples/src/main/java/net/sf/jxls/sample/StressXlsxTest.java

http://senni.tistory.com/27

http://blog.naver.com/PostView.nhn?blogId=likerkawk&logNo=220260084312

이상의 문서를 참조해서 다음의 예제를 만들었다.

기본 개념들은 위 자료를 참고하길 바란다.


개인적으로 오랫동안 jXLS를 사용해 왔고 선호하는 이유는

Java의 MVC 개념을 적용하여 사용할 수 있기 때문이다.

Java의 MVC에서 V (view)는 JSP를 의미하는데

처리된 데이터를 적절하게 디자인하여 화면에 출력하게 된다.

jXLS를 사용하면 기존 코드(M과 C)를 그대로 활용하고

JSP 대신 엑셀 파일을 사용하여 처리한다.

JSP로 보여주나 Excel로 보여주나(다운로드)

같은 개념으로 보고 그림과 같이 View만 바꿔서 사용하는 것이다. 

예를 들어, 게시판 리스트를 작성한다고 하면

다음과 같이 컨트롤을 작성한다. (게시판 예제 참조)

@RequestMapping(value = "/boardList")
public String boardList(HttpServletRequest request, BoardSearchVO searchVO, ModelMap modelMap) {

        searchVO.pageCalculate( boardSvc.selectBoardCount(searchVO) );
        List<?> listview  = boardSvc.selectBoardList(searchVO);
       
        modelMap.addAttribute("searchVO", searchVO);
        modelMap.addAttribute("listview", listview);

        return "board/BoardList";
}


jXLS를 사용하여 다음과 같이 사용할 수 있다.

@RequestMapping(value = "/boardListExcel")
public void boardListExcel(HttpServletRequest request, HttpServletResponse response, BoardSearchVO searchVO) {

        List<?> listview  = boardSvc.selectBoardList(searchVO);
        Map<String , Object> beans = new HashMap<String , Object>();
        beans.put("listview" , listview );

        MakeExcel me = new MakeExcel();
        me.download(request, response, beans, me.get_Filename("project9"), "board.xlsx");
}

ModelMap으로 값을 JSP로 전달하는 대신

Map을 사용하고

board/BoardList(.jsp)파일을 반환하는 대신

board.xlsx라는 엑셀 템플릿을 지정한다.

이외에 엑셀은 모든 데이터를 받기 때문에

페이징 처리를 위한 개수(selectBoardCount) 계산을 하지 않는 차이가 있다.

JSP와 엑셀 모두 같은 서비스와 SQL을 사용하기 때문에

복잡한 별도 처리 없이 코드 재사용성을 높일 수 있다.

MakeExcel 클래스의 주요 코드는 다음과 같고

jXLS를 메소드 호출(download)만으로 사용하기 위해

미리 jXLS 사용 코드를 함수화 한 코드일 뿐이다.

download 메소드를 호출해서 사용하는 것만 알면 되므로

클래스에 대한 자세한 설명을 하지 않는다.

public void download(HttpServletRequest request, HttpServletResponse response, Map<String , Object> beans, String filename, String templateFile) {
        String tempPath = request.getSession().getServletContext().getRealPath("/WEB-INF/templete") ;
       
        try {
            InputStream is = new BufferedInputStream(new FileInputStream(tempPath + "\\" + templateFile));
            XLSTransformer transformer = new XLSTransformer();
            Workbook resultWorkbook = transformer.transformXLS(is, beans);
            response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + ".xlsx\"");
            OutputStream os = response.getOutputStream();
            resultWorkbook.write(os);
           
        } catch (ParsePropertyException | InvalidFormatException | IOException ex) {
            LOGGER.error("MakeExcel"); // System.out.println(ex);
        }
}

MakeExcel.java


마지막으로 view에서 처리가 있다.

JSP에서 다양한 디자인과 함께 데이터를 출력하게 된다.

엑셀에서는 그림과 같이 적절한 디자인을 하고

${} 안에 Map으로 넘긴 변수명을 넣어 사용하면 된다.

Map으로 넘긴 변수명이 listview이니 ${listview} 이고

listview는 글제목(brdtitle), 작성자(brdwriter), 작성일자(brddate) 등을 가지는

VO 클래스들을 가지고 있기 때문에 그림과 같이

${listview.brdtitle}, ${listview.brdwriter} 등으로 사용하게 된다.

listview는 LIST 형으로 JSP에서는 반복문을 사용해야 하지만

jXLS에서는 알아서 처리해주기 때문에

그림과 같이 작성만 하면 된다.

board.xlsx


자세한 코드는 project9에 샘플로 작성되어 있다.

https://github.com/gujc71/project9


jXLS을 사용하면

엑셀의 챠트 등 엑셀에서 제공하는 대부분의 기능을 사용할 수 있는 장점도 있다.



추가해야 할 라이브러리는 다음과 같다.

        <dependency>
            <groupId>net.sf.jxls</groupId>
            <artifactId>jxls-core</artifactId>
            <version>1.0.6</version>
        </dependency>
      
        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls</artifactId>
            <version>2.3.0</version>
        </dependency>
      
        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls-poi</artifactId>
            <version>1.0.9</version>
        </dependency>
      
        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls-jexcel</artifactId>
            <version>1.0.6</version>
        </dependency>
              
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.14</version>
        </dependency>
      
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.14</version>
        </dependency>




'Java > 기타' 카테고리의 다른 글

그룹웨어 (Java) - 설치  (27) 2018.04.15
과제 관리 시스템 (PMS9)  (8) 2016.12.01
Project9  (8) 2016.09.18
Project9 설치  (5) 2016.09.18

앞서 만든 멀티 게시판은 게시판 그룹에 대한 관리 기능이 없기 때문에

1. 없는 그룹(게시판)에 대한 오류 처리가 되지 않는다. 즉, 그룹번호(bgno)를 무작위로 넣고 글쓰기를 해도 문제 없이 작동한다.

- 관리자에 의해 생성된 게시판만 사용하도록 해야 한다.

2. 각 게시판은 공지사항, 커뮤니케이션, Q&A 등 다양한 이름으로 제공되어야 하지만 하나의 이름(board)로 고정되어 있다.

3. 배경 이미지 변경, 댓글 기능 가능 여부 등 게시판별 다양한 옵션이 제공되어야 한다.

제대로 멀티 게시판을 사용하기 위해서는 이상의 기능들이 있어야 한다.

권한 관리 기능을 구현하지 않았기 때문에

이러한 기능을 관리자 페이지에서 지정할 순 없지만

별도의 페이지에서 설정하도록 구현하였다.


요약하면

하나의 게시판에 대한 정보를 가지고 있어야 한다는 것이다.

따라서, 게시판 그룹 정보를 저장하는 테이블을 생성하고

게시판 그룹 테이블에 정보(bgno)가 없으면 사용하지 못하도록 한다 ①.

게시판 그룹 테이블에 해당 게시판의 이름(BGNAME)을 저장하게 한다②.

이외에 게시판 사용여부(BGUSED, 삭제(BGDELETEFLAG)는

리스트에서 보이지 않지만 사용여부는 중지/사용을 반복할 수 있음),

댓글 기능 사용여부(BGREPLY),

공지사항을 위해 글쓰기 금지(BGREADONLY) 등의 옵션을 저장할 필드를 추가한다 ③.

따라서 다음과 같은 테이블 구조를 가지게 된다.

CREATE TABLE TBL_BOARDGROUP (
  BGNO INT(11) NOT NULL AUTO_INCREMENT,        -- 게시판 그룹번호
  BGNAME VARCHAR(50),                                    -- 게시판 그룹명
  BGPARENT INT(11),                                          -- 게시판 그룹 부모
  BGDELETEFLAG CHAR(1),                                 -- 삭제 여부
  BGUSED CHAR(1),                                           -- 사용 여부
  BGREPLY CHAR(1),                                          -- 댓글 사용여부
  BGREADONLY CHAR(1),                                    -- 글쓰기 가능 여부
  BGDATE DATETIME,                                          -- 생성일자
  PRIMARY KEY (BGNO)
);

추가적으로 게시판 그룹은 게시판 폴더라고도 부르는데

윈도우 폴더처럼 계층 구조를 가지기 때문이다.

부서별(부서 그룹)로 공지사항, 토론방 등의 게시판을 생성할 수 있고

동아리(그룹) 하위에 기타, 축구 등의 동아리를 하위로 생성하고

기타 동아리 하위에 공지사항, 토론방 등의 게시판을 생성할 수 있다.

따라서 계층 구조를 가지게 된다.

다만, 앞서 계층형 댓글(무한댓글) 에서 다른 것과 개념은 같지만 구현이 다르다.

계층형 댓글은 트리 형태의 웹 구현을 직접 구현했지만

게시판 그룹은 트리 라이브러리(dynatree)를 사용해서 구현할 것이고

부모만 표현하면 라이브러리에서 처리하기 때문에 다른 필드는 사용하지 않았다.


테이블(TBL_BOARDGROUP)을 생성했으면,

다음과 같이 BoardGroupVO를 작성한다.

public class BoardGroupVO {

    private String bgno, bgname, bglevel, bgparent, bgdeleteflag, bgused, bgreply, bgreadonly, bgdate;

    public String getBgno() {
        return bgno;
    }

    public void setBgno(String bgno) {
        this.bgno = bgno;
    }

    public String getBgname() {
    ~~ 생략 ~~

BoardGroupVO.java

모든 데이터 입출력은 게시판 응용이라는 것을 강조하기 위해

전혀 다를 것 같은 게시판 그룹 관리도 유사한 방식(함수명)으로 개발했다.

일단, BoardGroupCtr.java, BoardGroupSvc.java 두 개의 파일이 필요한데

소스 코드를 보면 컨트롤 명은 다르지만 실제 함수 명은 게시판과 동일하게 처리했다.

예로, 컨트롤 명 boardGroupList는 게시판 그룹 리스트를 처리하는 컨트롤이지만

함수는 boardList이다.

즉, 게시판 boardList를 수정해서 사용했다는 것으로

코드가 유사하다는 의미이다.

게시판만 만들 줄 알면 데이터 베이스를 기반으로 하는

대부분의 프로그램은 만들 수 있다는 말을 하기 위해서 이렇게 명명했다.


이외에 board8 컨트롤과 jsp도 복사해서 board9로 바꾸어 사용한다.

SQL은 그대로 사용한다.

게시판의 기능은 멀티 게시판(board8)에서 구현된 것을 그대로 사용하고

앞서 언급한 게시판 그룹의 3가지 핵심 기능을 간단하게 추가할 것이기 때문이다.













'Java > 게시판 9: 멀티 & 관리' 카테고리의 다른 글

2. 게시판 그룹 리스트  (2) 2016.08.14
3. 게시판 그룹 읽기 / 삭제  (0) 2016.08.14
4. 게시판 그룹 쓰기와 수정  (0) 2016.08.14
5. 게시판 적용  (0) 2016.08.14

게시판 그룹 리스트의 핵심은 데이터를 트리 구조로 표현하는 것이다.

즉, 리스트 기능을 표 형태가 아닌 트리 구조의 계층형으로 구현한다.

부서별 게시판들(공지사항, 토론방, QNA 등)로 구성하거나

하위 토론방을 주제별로 구분해서 사용할 수 있기 때문이다.

리스트를 트리로 구현하면서 신규, 읽기, 수정, 삭제를 하나의 페이지로 구현하고

신규, 읽기, 수정, 삭제가 발생할때 마다 트리를 매번 다시 생성하는 것은

비효율적이고 복잡해서

신규, 읽기, 수정, 삭제를 Ajax로 구현한다.


따라서 멀티 게시판 관리자 기능의 핵심은 트리 사용과 Ajax 활용이 된다.


개인적으로 사용해본 트리 라이브러리 중

dynatree가 무료(MIT) 중에서 가장 무난하다고 생각해서 사용한다.

자세한 사용법은 찾아보길 바라고 여기서는 관련된 내용만 다룬다.

http://wwwendt.de/tech/dynatree/doc/sample-select.html
http://jwgye.tistory.com/13

이외에 jstree나 bootstrap-treeview도 좋다고 생각한다.

    https://www.jstree.com/demo/
    https://github.com/jonmiles/bootstrap-treeview


다음 그림과 같이 트리 구조로 게시판 그룹이 있다고 하면

dynatree는 다음과 같이 JSON을 이용하여 트리 구조를 표현해서 넘겨만 주면 된다.

    {“key”: “1”, “title”: “공지사항”},
    {"key": "2", "title": "동아리", "isFolder": true,
        "children": [
            {"key": "3", "title": "기타"},
            {"key": "4", "title": "축구"}
            ]
        },
    {"key": "5", "title": "토론방"} 

Key는 그룹번호(bgno), title는 그룹 명(bgname)을 의미하고

2번 동아리는 자식(children)으로 기타(3)와 축구(4)를 가지는 트리 구조이다.

1과 5는 출력만 하면 된다.

이상과 같이 JSON 데이터를 생성하는 것이 트리 표현의 핵심인데

Java의 ObjectMapper를 이용하면 쉽게 처리할 수 있다.

ObjectMapper는 리스트(List)등의 구조체를 문자열로 변환하는 클래스인데

리스트의 항목이 클래스(VO)로 되어 있기 때문에

변환을 하면 JSON형태가 되게 된다.

클래스의 변수(메소드) 명이 JSON의 키로 생성되는 것이다.

변수의 값은 JSON의 키 값으로 생성된다.


따라서, 다음과 같이 TreeVO를 생성하면 쉽게 해결 된다.

dynatree에서 사용하는 key, title, isFolder, children로 클래스 멤버를 구성하고

데이터베이스에서 데이터를 가지고 올 때에도 이와 같이 가지고 오는 것이다.

public class TreeVO {
    private String key, title, parent;
    private boolean isFolder;
    private List children;
   
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    ~~ 생략 ~~

TreeVO.java

List로 지정된 children이 트리 변환의 핵심인데

ObjectMapper에 의해

List는 하위 JSON 집합으로 변환된다.


데이터 베이스에서 danatree의 JSON 키 생성구조(TreeVO)로 데이터 리스트를 조회하고

이 리스트를 계층 구조로 정리하고(children에 넣어주고)

ObjectMapper를 이용해서 JSON으로 변환하는 것이

게시판 그룹 리스트의 핵심 사항이다.


이 개념을 가지고 하나씩 구현해 본다.

먼저, 메인 페이지이자 게시판 그룹 리스트를 구현한다.

하나의 게시판 그룹이 추가될 때 마다

게시판 그룹 리스트 페이지를 새로 실행하고

게시판 그룹 트리를 다시 생성하는 것은 비효율적이고 직관성이 떨어져

이상의 그림과 같이

왼쪽에 리스트(트리), 오른쪽에는 입력/수정 화면이 하나로 묶어서 구현한다.

왼쪽의 트리에서 게시판을 선택하면

오른쪽에 해당 정보가 나오고 수정/삭제 할 수 있는 방식이다.

게시판에서는 각각의 화면이 다른 페이지로 있었지만

여기서는 모든 페이지가 하나에 구현된다.

따라서 Ajax가 많이 사용된다.


먼저, 게시판 그룹 리스트를 가지고 오는(selectBoardGroupList) 컨트롤을 작성한다.

@RequestMapping(value = "/boardGroupList")
public String boardList(ModelMap modelMap){
    List<?> listview   = boardSvc.selectBoardGroupList();

    TreeMaker tm = new TreeMaker();
    String treeStr = tm.makeTreeByHierarchy(listview);
   
    modelMap.addAttribute("treeStr", treeStr);
   
    return "board9/BoardGroupList";

BoardGroupCtr.java

public List<?> selectBoardGroupList(){
    return sqlSession.selectList("selectBoardGroupList");
}

BoardGroupSvc.java

<select id="selectBoardGroupList" resultType="gu.common.TreeVO" >
    SELECT BGNO 'KEY', BGNAME TITLE, BGPARENT PARENT
      FROM TBL_BOARDGROUP
     WHERE BGDELETEFLAG='N'
     ORDER BY BGNO 
</select> 

board9.xml

selectBoardGroupList를 이용해 가지고 온 데이터는

dynatree에 필요한 데이터 구조(KEY, TITLE)로 맞춘 TreeVO에 담겨 있다.

게시판 그룹의 부모(BGPARENT) 정보를 이용하여 계층 구조를 생성하게 된다.


Listview의 개수만큼(size) 하나씩(item=TreeVO) 반복하며

새로운 리스트(rootlist)에 하나씩 추가한다.

이때, 하나의 데이터(TreeVO)의 부모 정보(bgparent)가 NULL이 아니면

부모가 있다는 의미로

부모 데이터를 찾아서 (for ~~~ mtDO.getParent().equals(ptDO.getKey()))

children(List)에 내가 너의 자식이라고 추가(add)해 주는 방식으로 계층을 형성한다.

부모가 없는 경우는 최상위 노드(Root)를 의미하며

새로운 리스트(rootlist)에 추가하고 다음으로 넘어간다.

public class TreeMaker {
    public String makeTreeByHierarchy(List<?> listview){
        List<TreeVO> rootlist= new ArrayList<TreeVO>();
       
        for (Integer i=0; i<listview.size(); i++) {           
            TreeVO mtDO = (TreeVO)listview.get(i);           
           
            if (mtDO.getParent()==null) {
                rootlist.add(mtDO);
                continue;
            }   
             for (Integer j=0; j<listview.size(); j++) {
                 TreeVO ptDO = (TreeVO) listview.get(j);
                 if (mtDO.getParent().equals(ptDO.getKey())) {
                     if (ptDO.getChildren()==null) ptDO.setChildren(new ArrayList<Object>() );
                     List<TreeVO> a = ptDO.getChildren();
                     a.add(mtDO);
                     ptDO.setIsFolder(true);
                     break;
                 }
             }     
         }

        ObjectMapper mapper = new ObjectMapper();
        String str="";
        try {
            str = mapper.writeValueAsString(rootlist);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }

TreeMaker.java

계층 구조로 데이터가 정리되면

ObjectMapper로 JSON형태의 문자열로 변환하면 된다.

일반 리스트 데이터를 위와 같은 방식으로 변환하는 것은

자주 사용하는 것이라 common폴더에 생성하였다.

설명이 어려워서 이해되지 않는 경우

boardGroupList 컨트롤에서 사용하는 것처럼

makeTreeByHierarchy를 호출하는 것만 기억해도 된다.


이렇게 생성한 정보는 modelMap을 이용하여 JSP로 보낸다.

JSP 파일에서는 넘겨 받은 treeStr의 값을

다음과 같이 dynatree의 문법에 맞춰 넣어주면 트리가 생성된다.

#tree는 트리를 만들 대상 DIV의 ID이다.

$(function(){
    $("#tree").dynatree({
        children: <c:out value="${treeStr}" escapeXml="false"/>,
        onActivate: TreenodeActivate
    });
            fn_groupNew();
});
~~ 생략 ~~
<div id="tree"></div> 

BoardGroupList.jsp

Dynatree를 사용하기 위해서는

다음과 같이 CSS와 JS 파일을 포함해야 한다.

<link rel="stylesheet" href="js/dynatree/ui.dynatree.css" id="skinSheet"/>
<script src="js/jquery-2.2.3.min.js"></script>
<script src="js/jquery-ui.js"></script>
<script src="js/dynatree/jquery.dynatree.js"></script> 

BoardGroupList.jsp

Dynatree는 JQuery와 JQueryUI를 기반으로 제작되었기 때문에

위와 같이 JQuery도 지정해야 한다.


웹 페이지를 실행해 보면 이상의 그림과 같이 트리가 생성된 것을 볼 수 있다.

(데이터가 없어서 못 볼 수도 있다.)

onActivate는 트리의 노드가 선택되면 발생하는 이벤트로 

TreenodeActivate를 아직 구현하지 않아서 노드를 클릭하면 오류가 발생한다.











'Java > 게시판 9: 멀티 & 관리' 카테고리의 다른 글

1. 멀티게시판 관리자(그룹) 준비  (2) 2016.08.14
3. 게시판 그룹 읽기 / 삭제  (0) 2016.08.14
4. 게시판 그룹 쓰기와 수정  (0) 2016.08.14
5. 게시판 적용  (0) 2016.08.14

사용자가 트리의 노드를 선택하면

onActivate 이벤트에 지정된 TreenodeActivate함수가 실행된다.

파라메터로 사용자가 선택한 노드(node)가 넘어오고

전역변수(selectedNode)에 넣어서 다른 함수에서 사용할 수 있게 했다.

selectedNode(node).data.key는 TreeVO 구성시 key를 의미하고

그룹번호(bgno)가 저장되어 있다.

이 값(key== bgno)을 파라메터로

게시판 그룹 정보 읽기 컨트롤(boardGroupRead)을 호출한다.

콜백 함수는 receiveData로 반환에 성공하면

지정된 그룹번호(bgno)에 해당하는 데이터가 JSON 형태로 반환된다(receiveData).

Function TreenodeActivate(node) {
    selectedNode = node;
   
    if (selectedNode==null || selectedNode.data.key==0) return;
    $.ajax({
        url: "boardGroupRead",
        cache: false,
        data: { bgno : selectedNode.data.key }       
    }).done(receiveData);
}

function receiveData(data){
    $("#bgno").val(data.bgno);
    $("#bgname").val(data.bgname);
    $('input:radio[name="bgused"][value="' + data.bgused + '"]').prop('checked', true);
    $('input:radio[name="bgreadonly"][value="' + data.bgreadonly + '"]').prop('checked', true);
    $('input:radio[name="bgreply"][value="' + data.bgreply + '"]').prop('checked', true);
}

BoardGroupList.jsp

수신된 데이터(receiveData)는 JQuery 적당하게 값을 설정하면 된다.

코드가 복잡하게 보이는 것은

Radio를 ID가 아닌 Name으로 접근해서 그렇다.

게시판 사용여부(BGUSED), 댓글 기능 사용여부(BGREPLY), 글쓰기 금지(BGREADONLY) 는 Y/N로 저장되고

Radio의 선택여부에 따라서 Y/N으로 설정하면 된다.


사용된 HTML 코드를 보면

사용여부의 경우 name은 bgused이고 ID는 bgusedY와 bgusedN인 두 개의 radio가 있다.

각각은 Label이 사용/사용중지로 되어 있으며

Label의 for 속성이 bgusedY와 bgusedN를 가리킨다.

이것은 작은 radio를 선택할 수도 있고

글자를 표현한 Label를 선택해도 해당(for) radio를 선택하게 하기 위한 것이다.

따라서 radio의 ID가 달라야 한다.

댓글 기능 사용여부(BGREPLY), 글쓰기 금지(BGREADONLY)도 동일한 방식으로 구현하였다.

 <tr>
    <th>사용여부</th>
    <td>
        <input name="bgused" id="bgusedY" type="radio" checked="checked" value="Y"><label for="bgusedY">사용</label>
        <input name="bgused" id="bgusedN" type="radio" value="N"><label for="bgusedN">사용중지</label>
    </td>
</tr>
<tr>
    <th>등록가능</th>
    <td>
        <input name="bgreadonly" id="bgreadonlyN" type="radio" checked="checked" value="N"><label for="bgreadonlyN">사용</label>
        <input name="bgreadonly" id="bgreadonlyY" type="radio" value="Y"><label for="bgreadonlyY">사용안함</label>
    </td>
</tr>
<tr>
    <th>댓글</th>
    <td>
        <input name="bgreply" id="bgreplyY" type="radio" checked="checked" value="Y"><label for="bgreplyY">사용</label>
        <input name="bgreply" id="bgreplyN" type="radio" value="N"><label for="bgreplyN">사용안함</label>
    </td>
</tr>

BoardGroupList.jsp

JQuery는 ID를 이용하여 쉽게 사용할 수 있는데 ($(“bgused"]))

이상의 내용 때문에 다음과 같이 Name을 사용해야 한다.

$('input:radio[name="bgused"])


receiveData에서 다소 복잡해 보이는 다음의 코드는

이름(name)이 그룹번호(bgused)인 태그 중에서

값(value)이 Y/N인 태그의 체크(checked) 속성(prop)을 true로 설정하여

선택된 모습으로 출력해 주는 것이다.

    $('input:radio[name="bgused"][value="' + data.bgused + '"]').prop('checked', true);
    $('input:radio[name="bgreadonly"][value="' + data.bgreadonly + '"]').prop('checked', true);
    $('input:radio[name="bgreply"][value="' + data.bgreply + '"]').prop('checked', true);

JQuery가 복잡해 보일 뿐

컨트롤과 서비스, SQL문은 게시판과 동일하다.

컨트롤에서 BoardGroupVO로 받아온 그룹 정보(bgInfo)를

ObjectMapper를 이용하여 JSON으로 변환하여 전송하는 것이 다르다.

       @RequestMapping(value = "/boardGroupRead")
       public void boardRead(HttpServletRequest request, HttpServletResponse response){
       
        String bgno = request.getParameter("bgno");
       
        BoardGroupVO bgInfo = boardSvc.selectBoardGroupOne(bgno);
       
        ObjectMapper mapper = new ObjectMapper();
        response.setContentType("application/json;charset=UTF-8");
       
        try {
            response.getWriter().print( mapper.writeValueAsString(bgInfo));
        } catch (IOException ex) {
             System.out.println("오류: 게시판 그룹에 문제가 발생했습니다.");
        }
    } 

BoardGroupCtr.java

public BoardGroupVO selectBoardGroupOne(String param){
        return sqlSession.selectOne("selectBoardGroupOne", param);

BoardGroupSvc.java

<select id="selectBoardGroupOne" parameterType="String" resultType="gu.board9.BoardGroupVO">
        SELECT BGNO, BGNAME, BGUSED, BGREPLY, BGREADONLY
          FROM TBL_BOARDGROUP
         WHERE BGDELETEFLAG='N' AND BGNO=#{bgno}
 </select>

board9.xml

삭제(fn_groupDelete)는 지정된 트리 노드의 값(key, bgno)을

Ajax로 서버로 보내(boardGroupDelete)서 삭제하고

적절한 메시지를 출력해 주면 된다.

그리고, 트리에서 현재 선택된 노드를 제거하고(remove)

선택되면서 출력된 값들을 지워준다.

유사한 코드로 구성되어 상세한 설명을 생략한다.



'Java > 게시판 9: 멀티 & 관리' 카테고리의 다른 글

1. 멀티게시판 관리자(그룹) 준비  (2) 2016.08.14
2. 게시판 그룹 리스트  (2) 2016.08.14
4. 게시판 그룹 쓰기와 수정  (0) 2016.08.14
5. 게시판 적용  (0) 2016.08.14

게시판 그룹 쓰기/수정은 게시판 새 글 쓰기/수정과 동일하다.

사용자가 입력한 값을 받아서

새 번호(그룹 - bgno)를 부여하고 INSERT 문을 실행하거나

그룹 번호가 있으면 UPDATE문으로 수정하면 된다.

다만, 댓글처럼 Ajax로 처리하기 때문에

JavaScript가 많이 사용된다.

더욱이 HTML Radio를 사용하면서

작성해야 하는 코드가 조금 더 많아져 복잡해 보인다.


다음 코드를 보면 일반적인 Ajax 사용과 같다.

function fn_groupSave(){
    if($("#bgname").val() == ""){
        alert("게시판 이름을 입력해주세요.");
        return;
    }
    var bgno =null;
    if (selectedNode!=null) bgno =selectedNode.data.key;

    if (!confirm("저장하시겠습니까?")) return;

    $.ajax({
        url: "boardGroupSave",
        cache: false,
        type: "POST",
        data: { bgno:$("#bgno").val(), bgname:$("#bgname").val(), bgparent: bgno,
                bgused : $("input:radio[name=bgused]:checked").val(),
                bgreadonly : $("input:radio[name=bgreadonly]:checked").val(),
                bgreply : $("input:radio[name=bgreply]:checked").val()}       
    }).done(receiveData4Save);

BoardGroupList.jsp

selectedNode는 트리의 노드가 선택되면 발생하는 이벤트(onActivate)에서

선택된 노드를 가지고 있도록 한 전역변수이다.

따라서, selectedNode에 값이 있으면

게시판 그룹 수정이고(bgno 값 존재), 없으면 신규가 된다.

사용자가 노드를 선택하면

선택한 노드가 selectedNode에 지정되고

입력상자(input)의 ID가 bgno에도 값이 저장된다.

저장할 데이터를 구성하여 boardGroupSave를 호출하면

게시판과 유사한 다음 SQL문으로 저장하게 된다.


<insert id="insertBoardGroup" parameterType="gu.board9.BoardGroupVO" >
    <selectKey resultType="String" keyProperty="bgno" order="BEFORE">
        SELECT IFNULL(MAX(BGNO),0)+1 FROM TBL_BOARDGROUP
    </selectKey>   
    INSERT INTO TBL_BOARDGROUP(BGNO, BGNAME, BGUSED, BGREPLY, BGREADONLY, BGPARENT, BGDELETEFLAG, BGDATE)
    VALUES (#{bgno}, #{bgname}, #{bgused}, #{bgreply}, #{bgreadonly}, #{bgparent}, 'N', NOW() )
</insert>


<update id="updateBoardGroup" parameterType="gu.board9.BoardGroupVO">
    UPDATE TBL_BOARDGROUP
       SET BGNAME=#{bgname}, BGUSED=#{bgused}, BGREPLY=#{bgreply}, BGREADONLY=#{bgreadonly}
     WHERE BGNO=#{bgno}
</update>  

board9.xml

SQL문은 별도의 이름을 부여했지만

서비스(DTO)의 이름은 게시판 글쓰기/수정과 이름이 같다(insertBoard).

insertBoard에서는 게시판과 같이 그룹번호(bgno) 값이

없으면 신규 등록 (INSERT)

있으면 수정(UPDATE)을 실행한다.

    public void insertBoard(BoardGroupVO param){
        if ("".equals(param.getBgparent())) param.setBgparent(null);
           
        if (param.getBgno()==null || "".equals(param.getBgno()))
             sqlSession.insert("insertBoardGroup", param);
        else sqlSession.insert("updateBoardGroup", param);
    } 

BoardGroupSvc.java

이렇게 처리한 뒤 컨드롤(boardGroupSave)에서는

Json 형태(ObjectMapper)로 저장한 그룹 정보를 반환한다(bgInfo).

신규일경우는 MyBatis가 글번호를 반환 받아서 bgInfo에 저장해서 반환한다(selectKey).

     @RequestMapping(value = "/boardGroupSave")
       public void boardSave(HttpServletResponse response, BoardGroupVO bgInfo){
        
        boardSvc.insertBoard(bgInfo);
        
        ObjectMapper mapper = new ObjectMapper();
        response.setContentType("application/json;charset=UTF-8");
        
        try {
            response.getWriter().print( mapper.writeValueAsString(bgInfo));
        } catch (IOException ex) {
             System.out.println("오류: 게시판 그룹에 문제가 발생했습니다.");
        }
    }

BoardGroupCtr.java

컨트롤이 반환한 정보(bgInfo)는

클라이언트에서 Ajax 호출시 지정된 receiveData4Save 함수에 파라메타(data)로 넘겨 진다.

선택된 노드(selectedNode)가 있거나(!==null),

선택된 노드의 수정이면(선택된 노드와 반환된 데이터의 키 값이 같으면)

선택된 노드의 제목이 수정될수 있어서 무조건 수정해준다.

IF문 처리를 해도 되지만 간단한 데이터 변경이라 무조건 하도록 했다.

function receiveData4Save(data){
    if (selectedNode!==null && selectedNode.data.key===data.bgno) {
        selectedNode.data.title=data.bgname;
        selectedNode.render();
    } else {
        addNode(data.bgno, data.bgname);
    }
   
    alert("저장되었습니다.");

BoardGroupList.jsp

수정이 아닌 경우

즉, 최상위 노드에 추가(선택 노드 없음, selectedNode===null)하거나

선택노드의 자식 노드를 추가할 경우

(선택노드와 반환된 데이터 키 값이 다르면, selectedNode.data.key!==data.bgno)

새로운 노드를 생성해서 추가해 준다 (addNode).


addNode함수의 내용은 다음과 같다.

dynatree의 사용법으로 별도의 설명을 하지 않으니 찾아보길 바라고

선탠된 노드($("#tree").dynatree("getActiveNode"))가 있으면

자식으로 추가하고

없으면 최상위($("#tree").dynatree("getRoot"))에 추가한다.

function addNode(nodeNo, nodeTitle){
    var node = $("#tree").dynatree("getActiveNode");
    if (!node) node = $("#tree").dynatree("getRoot");
    var childNode = node.addChild({key: nodeNo, title: nodeTitle});
    node.expand() ;
    node.data.isFolder=true;
    node.tree.redraw();

BoardGroupList.jsp










'Java > 게시판 9: 멀티 & 관리' 카테고리의 다른 글

1. 멀티게시판 관리자(그룹) 준비  (2) 2016.08.14
2. 게시판 그룹 리스트  (2) 2016.08.14
3. 게시판 그룹 읽기 / 삭제  (0) 2016.08.14
5. 게시판 적용  (0) 2016.08.14

웹 페이지(JSP파일)가 존재하는

리스트(board9List), 글쓰기(board9Form), 글읽기(board9Read) 컨트롤(Board9Ctr.java)에

다음 코드를 각각 넣어줘야 한다.

        BoardGroupVO bgInfo = boardGroupSvc.selectBoardGroupOne4Used(boardInfo.getBgno());
        if (bgInfo==null) return "board9/BoardGroupFail";
        
        ~~ 생략 ~~
        modelMap.addAttribute("bgInfo", bgInfo);

Board9Ctr.java

게시판 그룹 번호(getBgno)에 대한 정보를 찾아보고(selectBoardGroupOne4Used)

관리자에서 등록된 정보가 없으면(bgInfo==null)

오류 페이지(BoardGroupFail)를 보여주고 종료한다.

정보가 있는 경우  modelMap에 넣어서 적절한 웹 페이지로 넘겨준다.


그룹 번호에 해당하는 정보를 찾는 SQL문은 다음과 같고

삭제(BGDELETEFLAG)되지 않고, 사용가능(BGREPLY)으로 지정된 데이터를 

조회하게 구성한다.

    <select id="selectBoardGroupOne4Used" parameterType="String" resultType="gu.board9.BoardGroupVO">
        SELECT BGNO, BGNAME, BGUSED, BGREPLY, BGREADONLY
          FROM TBL_BOARDGROUP
         WHERE BGDELETEFLAG='N' AND BGNO=#{bgno} AND BGUSED='Y'
    </select>  

board9.xml

모든 게시판 페이지(JSP)에는 게시판 이름(bgname)을 보여주는 다음 코드를 넣어줘야 한다.

    <h1><c:out value="${bgInfo.bgname}"/></h1>

마지막으로

게시판 그룹 관리자에서 지정된 설정(등록가능, 댓글)에 따라

게시판이 운영되도록 해야 한다.


리스트에는 기존의 글쓰기 버튼에 다음 코드를 추가해 준다.


    <c:if test="${bgInfo.bgreadonly=='N'}">
        <a href="board9Form?bgno=<c:out value="${searchVO.bgno}"/>">글쓰기</a>
    </c:if> 

BoardList.jsp

관리 기능에서 [등록가능 (bgreadonly)]이 설정되면(Y)

글쓰기 링크가 활성화 되는 코드를 넣어준다.

기존 코드에 IF문을 넣어서 구현하였다.

제대로 구현하기 위해서는 board9Save 컨트롤에서도 구현할 것이 있지만

이정도 수준에서 처리하고 넘어간다.


[댓글 (bgreply)] 기능 사용여부도 기존 코드에 IF문을 넣어서 처리한다.

<c:if test="${bgInfo.bgreply=='Y'}">
    <div style="border: 1px solid; width: 600px; padding: 5px">
        <form id="form1" name="form1">
            <input type="hidden" id="brdno1" name="brdno" value="<c:out value="${boardInfo.brdno}"/>">
            작성자: <input type="text" id="rewriter1" name="rewriter" size="20" maxlength="20"> <br/>
            <textarea id="rememo1" name="rememo" rows="3" cols="60" maxlength="500" placeholder="댓글을 달아주세요."></textarea>
            <a href="#" onclick="fn_formSubmit()">저장</a>
        </form>
    </div>
</c:if> 

BoardList.jsp

댓글 모든 기능에 IF문을 넣는게 아니고

게시물에 대한 첫 댓글 작성 부문을 보이지 않게 해서 댓글을 작성할 수 없도록했다.

좀더 제대로 구현하려면 컨트롤 처리도 필요하고

댓글 리스트(replyList)도 보이지 않게 하면 된다.


그림과 같이 웹 브라우저에서 접속해 보면 

http://localhost:8080/board/board9List?bgno=2로 접속하면

공지사항이란 게시판 제목이 출력되고

http://localhost:8080/board/board9List?bgno=3으로 접속하면

일반게시판이라는 제목이 출력된다.

또, 공지사항은 글쓰기 버튼이 보이지 않고

일반 게시판은 글쓰기 버튼이 보인다.


글쓰기, 글읽기에서도 적용된 내용을 확인해 보길 바란다.


+ Recent posts