블로그 이미지
Peter Note
Web & LLM FullStacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

배너 밑으로는 선전하고 싶은 상품 목록 4개를 열거한다. 이때 반응형 웹 디자인의 그리드(Grid)를 적용해 본다. 




화면 분할


  - WEB-INF/templates/layout/home.html 템플릿의 내용이 많아지면 partial html로 분리하여 include하는 방식을 취한다

  - 우선, Homepage Banner Ad Carousel 부분을 <th:include> 처리하고 Product 목록 부분도 <th:include> 처리해 관리한다. 

  - 기존 화면 

   


  - 변경 화면

    + 박스 테두리 CSS를 적용한다

    + 각 박스 테두리별로 반응형 그리드를 적용한다  

   

  - WEB-INF/templates/layout/home.html 내역중 Carousel에 대한 부분과 product 목록에 대한 부분을 WEB-INF/templates 폴더 밑에 main/partials 폴더를 새롭게 만들고 banner-caruosel.html 과 product-list.html 을 생성하고 기존 내역을 옮긴다. 

  - content의 contentType인 "Homepage Featured Products Title" 인 목록을 뿌려주는 것이다. 

  - layout 폴더에서 main 폴더로 옮기는 이유는 해당 main 폴더 영역에 있는 부분이 계속 변경되기 때문이다. 즉, 다른 페이지로 이동해도 nav와 footer는 고정되어 있다. 

// home.html의 과거 내역 


<blc:content contentType="Homepage Featured Products Title" />    

<div th:if="${contentItem !=null and contentItem['messageText'] !=null}" class="title_bar" th:text="${contentItem['messageText']}"></div>


<ul id="products" class="group">

    <li th:each="product : ${products}" th:object="${product}" th:include="catalog/partials/productListItem" class="product_container"></li>

</ul>



// 신규 layout/home.html 일부 내역 


    <div th:include="main/partials/banner-carousel" />

    

    <div class="section">

        <div th:include="main/partials/featured-products" />

    </div>



// main/partials/featured-products.html


    <div class="container">

   

          <div class="row">

          <blc:content contentType="Homepage Featured Products Title" />  

             <div th:if="${contentItem !=null and contentItem['messageText'] !=null}" 

                  class="col-lg-12 col-md-12 col-sm-12 col-xs-12 featured-title" 

                  th:text="${contentItem['messageText']}"></div>

       

              <div th:each="product : ${products}" 

                   th:object="${product}" 

                   th:include="catalog/partials/productListItem" 

                   class="col-lg-3 col-md-3 col-sm-6 col-xs-6">

              </div>

          </div>

          

    </div>


  - class="col-lg-3 col-md-3 col-sm-6 col-xs-6" 을 적용해서 데스크톱에서는 4개씩 상품이 보이고 테블릿 이하는 2개씩 상품이 보임




Product Item 그리드 구성 


  - th:include="catalog/partials/productListItem" 에서 기존 productListItem.html 의 CSS를 하기와 같이 다시 적용한다 

    + max-width: 320px; 를 주어 박스의 최대 크기를 지정한다. 

// /webapp/css/style.css 일부 내역 


/************************************/

/* featured product list  */

/************************************/

.thumbnail {

max-width: 320px;

display: block;

padding: 5px;

margin-bottom: 10px;

line-height: 1.5;

background-color: #fff;

border: 1px solid #ddd;

border-radius: 4px;

-webkit-transition: border .2s ease-in-out;

-o-transition: border .2s ease-in-out;

transition: border .2s ease-in-out;

}


.thumbnail .content {

padding: 3px;

font: 13px/18px 'BryantLGRegular';

color: #655c5a;

overflow: hidden;

}


.thumbnail .content .title {

font: 15px/18px 'BryantLGMedium';

margin-bottom: 7px;

color: #222222;

height: 36px;

max-height: 36px;

}


.thumbnail .content .desc {

padding: 3px;

font: 13px/18px 'BryantLGLight';

color: #655c5a;

overflow: hidden;

height: 72px;

max-height: 72px;

}


.thumbnail .new_badge {

width: 60px;

height: 60px;

background: url('../img/badge-new.png') no-repeat;

text-indent: -9999px;

position: absolute;

top: -10px;

left: -1px;

z-index: 20;

}


.thumbnail .image {

margin-bottom: 10px;

overflow: hidden;

position: relative;

z-index: 10;

}


.thumbnail .image .price {

position: absolute;

background-color: black;

color: white;

opacity: 0.8;

padding: 10px 20px;

font: 16px/16px 'BryantLGMedium';

font-weight: 600;

bottom: 5px;

right: 5px;

}


  - 적용한 productListItem.html 의 내용은 하기와 같다.

<div class="thumbnail">

<div th:if="*{featuredProduct}" class="new_badge">New!</div>


<div class="image">

<a th:href="@{*{url}}">

    <img th:if="*{media['primary']}" blc:src="@{*{media['primary'].url} + '?browse'}" th:alt="*{name}" />

    <div class="price" th:if="${#object instanceof T(org.broadleafcommerce.core.catalog.domain.ProductBundle)}">

        <div blc:price="*{salePrice}" th:if="*{onSale}" th:classappend="*{defaultSku.onSale}? 'sale'"></div>

        <div blc:price="*{retailPrice}" th:classappend="*{onSale}? 'has-sale'"></div>

    </div>

    <div class="price" th:unless="${#object instanceof T(org.broadleafcommerce.core.catalog.domain.ProductBundle)}">

        <div blc:price="*{defaultSku.salePrice}" th:if="*{defaultSku.onSale}" th:classappend="*{defaultSku.onSale}? 'sale'"></div>

        <div blc:price="*{defaultSku.retailPrice}" th:classappend="*{defaultSku.onSale}? 'has-sale'"></div>

    </div>

    </a>

    </div>

    

<div class="content">

  <div class="title" th:text="*{name}">Product Name</div>

<p class="desc" th:utext="*{longDescription}">description</p>

<p> 

<div th:class="*{'productActions productActions' + id}"

    th:with="checkInventory=*{defaultSku.inventoryType?.type == 'CHECK_QUANTITY'},

              availableInventory=${checkInventory ? #object.defaultSku.quantityAvailable != null and #object.defaultSku.quantityAvailable != 0 : true},

              inCart=${cart.containsSku(#object.defaultSku) and #lists.isEmpty(product.productOptions)}">

    <div th:if="${checkInventory and !availableInventory}" class="out_of_stock">

        <a disabled="disabled" class="inCart">Out of Stock</a>

    </div>

    <div class="btn btn-default" th:classappend="${!inCart}? ' hidden'" th:if="${#lists.isEmpty(product.productOptions)}">

        <a class="modalcart inCart" th:href="@{/cart}"><span th:text="#{product.inCart}">In Cart!</span></a>

    </div>

    <div class="add_to_cart" th:classappend="${inCart or !availableInventory}? ' hidden'">

        <blc:form method="POST" th:action="@{/cart/add}">

            <input type="hidden" name="productId" th:value="*{id}" />

            <input type="hidden" name="quantity" value="1" />

            <input type="hidden" name="hasProductOptions" th:value="*{!#lists.isEmpty(productOptions)}" />

            <input type="submit" class="btn btn-primary" th:value="#{product.buyNow}"/>

        </blc:form>

    </div>

</div>

</p>

    </div>

    

</div>


<div style="display: none;" th:id="*{'productOptions' + id}" class="product-options modal">

    <h3 th:text="*{name}"></h3>

    <div class="product-options" th:substituteby="catalog/partials/productOptions"/>

    <input type="button" class="addToCart" th:value="#{product.buyNow}" />

</div>


화면 구성이 되었다면 다음으로 2단 메뉴 구성을 해보자 

posted by Peter Note

DemoSite에서 제공하는 랜딩 페이지의 중앙에는 마케팅 제품 한개만을 디스플레이한다. 이를 여러개의 마케팅 제품을 Carousel로 변경하는 작업을 해본다. 




Carousel HTML 추가


  - 원래 화면으로 SHIRT SPECIAL 이미지가 고정이다.

    


  - 변경된 화면으로 Carousel을 적용한다. 

    + Twitter Bootstrap의 carousel을 적용

    + 기존 제품을 두번째에 배치

    


  - HTML에서 메인 마케팅 제품의 <blc> 태그 내역음 하기와 같다

    + <blc:content> 태그의 contentType="Homepage Banner Ad"의 값이 키가 되어 content의 데이터를 MySQL에서 찾음

    + 반환값인 contentItem 객체를 통해 Thymeleaf 템플릿엔진은 HTML을 생성해줌

    + Twitter Bootstrap의 carousel을 추가하고 첫번째에 배너를 넣고 다음 아이템(보라색) 두번째에 틀린 배너를 넣음

       contentType인 Homepage Banner Ad2 라는 이름임 

// 원본 소스 

<nav th:substituteby="layout/partials/nav" />

            

<blc:content contentType="Homepage Banner Ad" />   

<div id="banners" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}">

    <a th:href="@{${contentItem['targetUrl']}}"><img blc:src="@{${contentItem['imageUrl']}}" /></a>       

</div>



// 수정 소스 

<div th:include="layout/partials/nav" />

       

<div id="myCarousel" class="carousel slide">

    <!-- Indicators -->

    <ol class="carousel-indicators">

        <li data-target="#myCarousel" data-slide-to="0" class="active"></li>

        <li data-target="#myCarousel" data-slide-to="1"></li>

        <li data-target="#myCarousel" data-slide-to="2"></li>

    </ol>


    <!-- Wrapper for slides -->

    <div class="carousel-inner">

        <div class="item active">

            <blc:content contentType="Homepage Banner Ad" />

            <div class="fill" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}" >

              <a th:href="@{${contentItem['targetUrl']}}"><img style="height:100%; width:100%" blc:src="@{${contentItem['imageUrl']}}" /></a>  

            </div>

            <div class="carousel-caption">

                <h1></h1>

            </div>

        </div>

        <div class="item">

            <blc:content contentType="Homepage Banner Ad2" />

            <div class="fill" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}" >

              <a th:href="@{${contentItem['targetUrl']}}"><img style="height:100%; width:100%" blc:src="@{${contentItem['imageUrl']}}" /></a>  

            </div>

            <div class="carousel-caption">

                <h1>This is Homepage Banner Ad2 Test</h1>

            </div>

        </div>

        <div class="item">

            <div class="fill" style=""></div>

            <div class="carousel-caption">

                <h1>Additional Layout Options at <a href="http://startbootstrap.com">http://startbootstrap.com</a>

                </h1>

            </div>

        </div>

    </div>


    <!-- Controls -->

    <a class="left carousel-control" href="#myCarousel" data-slide="prev">

        <span class="icon-prev"></span>

    </a>

    <a class="right carousel-control" href="#myCarousel" data-slide="next">

        <span class="icon-next"></span>

    </a>

</div>


  - Carousel을 구동하는 자바스크립트를 추가함 

    + WEB-INF/templates/layout/partials/footer.html안에 main.js를 추가함. 메인 페이지 하단에 자바스크립트를 추가해줌 

    + webapp/js 폴더 밑에 main.js 를 추가하고 carousel 자바스크립트를 초기화하고 화면간 이동시간을 설정함

// footer.html 

 <blc:bundle name="heatclinic.js" 

                mapping-prefix="/js/"

                files="main.js,

                       BLC.js,

                       heatClinic.js,

                       cartOperations.js,

                       checkoutOperations.js,

                       globalOnReady.js,

                       manageAccountOperations.js,

                       reviewOperations.js" />



// js/main.js

$('.carousel').carousel({

  interval: 3000

})




Homepage Banner Ad2 추가하기


  - Homepage Banner Ad가 추가된 위치를 Admin에서 화인할 수 있다.

    + DemoSite에 보면 admin sub-module이 있고 Ant를 통해서 실행할 수 있다. 

    + http://localhost:8081/admin 으로 접속해서 id:admin, pwd:admin으로 접속한다.

    + 관리페이지의 Content -> Content Items를 보면 아이템 목록이 나오고 "Content Type"이 Homepage Banner Ad가 언어별로 등록됨

    + 즉, <blc:content> 태그의 contentType이 데이터 조회를 위한 파라미터 키이고 Homepage Banner Ad가 값임.

    


  - 최초에 DemoSite를 수행할 때 src/main/resources/runtime-properties/development.properties는 하기와 같다 

    + create-drop 설정은 DemoSite 서버(jetty)를 기동할 때 기존 테이블을 전부 drop 하고 새롭게 생성하고 데이터를 넣어줌 

    + 한번 생성된 이후 다시 drop하지 않고 DemoSite를 기동하고 싶으면 update로 변경함 

// 기존 설정 

blPU.hibernate.hbm2ddl.auto=create-drop


// 변경 설정

blPU.hibernate.hbm2ddl.auto=update


  - 결국 DemoSite 기동할 때 insert 구문을 통해 Homepage Banner Ad를 넣고 있으므로 Homepage Banner Ad2 값을 넣을 수 있음

    + sql 파일은 core sub-module의 src/main/resrouces/sql밑에 존재함 

    + 관련 sql은 load_content_structure.sql 과 load_content_data.sql 이다 

    + content_structure는 원화 기준, 언어 기준, 화면 템플릿의 논리적 그룹핑 명칭 등록 및 4단계를 거쳐 structure를 만들어준다 

// load_content_structure.sql 안에 보라색 내역 Homepage Banner Ad2를 추가함


---------------------------------------------------------------------------------------------------------------------------

-- Structured Content Step 4:   Create Types (These represent areas on a page or general types:  e.g 'Homepage Banner Ad')

---------------------------------------------------------------------------------------------------------------------------

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (1, 'Homepage Banner Ad', NULL, 1);

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (2, 'Homepage Middle Promo Snippet', NULL, 2);

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (3, 'Homepage Featured Products Title', NULL, 3);

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (4, 'Right Hand Side Banner Ad', NULL, 1);


-- by ysyun

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (5, 'Homepage Banner Ad2', NULL, 1);


    + content_data는 컨텐트의 url, image 등의 세부 내역이 담겨져 있다. 

    + 원본은 3개의 Banner가 우선순위가 있게 등록되어 있는데 Homepage Banner Ad2를 새로운 배너 우선순위 1로 해서 등록한다.

    + 기존 베너에 있던 Buy One Get One을 Homepage Banner Ad2에 배정한다. 

    + 세번째 Carousel을 등록하고 싶다면 Homepage Banner Ad3를 structure에 등록해서 하기 과정에 sql을 추가하면 끝! 

    + 이미지는 webapp/img/banners 폴더에 존재함 

// load_content_data.sql 에서 보라색 부분을 추가한다.


---------------------------------------------------

-- HOME PAGE BANNER

---------------------------------------------------

-- Content Item

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (100, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Buy One Get One - Twice the Burn', FALSE, 5, 'en', 1);

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (101, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Shirt Special - 20% off all shirts', FALSE, 1, 'en', 1);

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (102, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Member Special - $10 off next order over $50', FALSE, 5, 'en', 1);


-- by ysyun

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (103, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Buy One Get One - Twice the Burn', FALSE, 1, 'en', 5);


-- Fields

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (1, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/buy-one-get-one-home-banner.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (2, CURRENT_TIMESTAMP, 'targetUrl', 1, '/hot-sauces');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (3, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/shirt-special.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (4, CURRENT_TIMESTAMP, 'targetUrl', 1, '/merchandise');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (5, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/member-special.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (6, CURRENT_TIMESTAMP, 'targetUrl', 1, '/register');


-- by ysyun

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (7, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/buy-one-get-one-home-banner.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (8, CURRENT_TIMESTAMP, 'targetUrl', 1, '/hot-sauces');


-- Field XREF

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (100, 1, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (100, 2, 'targetUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (101, 3, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (101, 4, 'targetUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (102, 5, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (102, 6, 'targetUrl');


-- by ysyun

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (103, 7, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (103, 8, 'targetUrl');


  - sql 추가하고 create-drop으로 놓은 다음 DemoSite를 제구동하면 Admin에서 하기와 같이 나온다. 

  


베너를 Carousel로 변환하여 볼 수 있을 것이다. 다음은 2 level Menu로 변경하는 과정을 살펴보자. 



참조 


  - Broadleaf DemoSite 소스

posted by Peter Note

BroadleafThymeleaf이라는 서버 템플릿 엔진을 사용하고 있다. Broadleaf은 Tymeleaf을 상속받아 확장한 <blc:XXX> 태그를 xxxProcessor 클래스에 정의하고 있다. 따라서 템플릿에는 Tymeleaf 태그와 Broadleaf이 정의한 <blc:XXX> 태그가 함께 사용된다. 이에 대해 간략히 알아보고 Twitter Bootstrap을 템플릿에 적용해 보자 




Broadleaf에서 Thymeleaf 역할 


  - Thymeleaf은 레이아웃 템플릿 보다 텍스트 템플릿에 가깝고 객체값을 받아서 화면에 표현해 주는 제어구문들을 가지고 있다.

  - AngularJS의 Directive와 서버 템플릿의 Taglib로 사용자 정의한 태그와 백앤드/프론트앤드만 틀리고 유사하다고 하겠다. 

  - 그럼 데이터는 어떻게 주고 받아서 표현할까?

     + Thymeleaf은 HTML을 해석하고 맵핑된 객체를 통해 Value가 설정된 HTML을 최종 클라이언트에 전송한다. 

     + 이때 객체 정보는 Broadlead의 <blc:XXX> 태그에서 Broadleaf core소스에서 정의한 XXXProcessor 가 YYYService를 통해서 Thymleaf에 사용할 객체를 조회/설정/전달한다. 


  - core/broadlleaf-framework : Hibernate와 연결된 DAO와 업무 도메인 Service가 존재한다. 

  - core/broadleaf-framework-web : web이므로 프론트단에 필요한 폼, 필터, 태그처리 프로세스(Processor)등이 존재한다. 

    + DemoSite의 메인 페이지 템플릿은 /site/src/main/webapp/WEB-INF/templates/layout/home.html 해당 파일이다. 

    + home.html을 열어보면 맨위에 하기와 같이 <head>가 설정되어 있다. 

    + <head> 태그를 core/broadleaf-framework-web의 org.broadleafcommerce.core.web.processor.HeadProcessor 가 처리한다.

    + HeadProcessor는 pageTitle 값을 처리하는 클래스이다. 

    + 즉, XxxYyyZzzProcessor 가 있고 태그로 <xxx-yyy-zzz> 태그를 사용하면 XxxYyyZzzProcessor 가 동작하는 것이다. 

// home.html 일부 내역


<head th:include="/layout/partials/head (pageTitle='Broadleaf Demo - Heat Clinic')"></head>

<body>

    <div id="notification_bar"></div>

    <header th:substituteby="layout/partials/header" />

    

    <div id="content" class="width_setter group" role="main">

        <nav th:substituteby="layout/partials/nav" />

        <blc:content contentType="Homepage Banner Ad" />       

        <div id="banners" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}">

            <a th:href="@{${contentItem['targetUrl']}}"><img blc:src="@{${contentItem['imageUrl']}}" /></a>       

        </div>

  ... 중략 ...

</body>



// HeadProcessor.java 일부 내역


import org.thymeleaf.processor.element.AbstractFragmentHandlingElementProcessor;

public class HeadProcessor extends AbstractFragmentHandlingElementProcessor {

    @Resource(name = "blHeadProcessorExtensionManager")

    protected HeadProcessorExtensionListener extensionManager;

    public static final String FRAGMENT_ATTR_NAME = StandardFragmentAttrProcessor.ATTR_NAME;

    protected String HEAD_PARTIAL_PATH = "layout/partials/head";


    public HeadProcessor() {

        super("head");

    }


    @Override

    public int getPrecedence() {

        return 10000;

    }


    @Override

    protected boolean getRemoveHostNode(final Arguments arguments, final Element element) {

        return true;

    }


    @Override

    @SuppressWarnings("unchecked")

    protected List<Node> computeFragment(final Arguments arguments, final Element element) {

        String pageTitle = element.getAttributeValue("pageTitle");

        try {

            Expression expression = (Expression) StandardExpressions.getExpressionParser(arguments.getConfiguration())

                    .parseExpression(arguments.getConfiguration(), arguments, pageTitle);

            pageTitle = (String) expression.execute(arguments.getConfiguration(), arguments);

        } catch (TemplateProcessingException e) {}


        ((Map<String, Object>) arguments.getExpressionEvaluationRoot()).put("pageTitle", pageTitle);

      ((Map<String, Object>) arguments.getExpressionEvaluationRoot()).put("additionalCss", element.getAttributeValue("additionalCss"));


        extensionManager.processAttributeValues(arguments, element);

        return new ArrayList<Node>();

    }

}


  - <blc:content> 는 특별히 admin/broadleaf-conentmanagement-modul 에서 org.broadleafcommerce.cms.web.processor.ContentProcessor 로 존재한다.

  - <blc.content> 태그는 내부적으로 서비스를 호출해서 contentItem을 값을 설정해 준다. 이때 contentType="Homepage Banner Ad"는 admin 페이지에서 설정해주는 것이다. 즉, 관리 도구를 통해 Content Mangement를 할 수 있고 이를 간단히 <blc:xxx> 태그를 사용한다.

1) admin 프로젝트에서 ant task중 jetty-demo 실행

2) http://localhost:8081/admin (id:admin, password: admin)

3) Content 메뉴의 content items 목록이 나온다. 여기서 "Content Type"으로 찾으면 됨 



  - Thymeleaf의 특정 인터페이스를 상속받으면 자신만의 태그를 쉽게 만들수 있고 Broadleaf에서는 XXXProcessor로 만들고 있는 것이다. 그리고 <blc:xxx> 태그를 만들어 xxxProcessor내부에서 Service를 통해 Hibernate를 호출해 업무적인 부분을 처리하고 있다.


  얼핏 보면 AngularJS의 Directive를 만들고 내부에서 AngularJS 서비스를 DI(Dependency Injection) 받아 호출하고 서비스내에서 서버로 AJAX 호출하는 계층을 두는 것과 유사하다. 따라서 Broadleaf에서 정의한 xxxProcessor들을 AngularJS Directive로 전환하면 AngularJS기반의 SPA(Single Page Application)으로의 전환이 가능하다. 




Twitter Bootstrap 적용하기 


  - 트위터 부트스트랩은 UI Framework으로 RWD (Responsible Web Design)을 적용할 수 있는 CSS를 제공하고 많이 사용하는 jQuery 플러그인도 함께 제공된다. 

  - 우선 트위터 부트스트랩 v3.3.1을 다운로드하고 압축을 풀면 css, fonts, js 폴더가 있다 

  - site/src/main/webapp 밑에 css, fonts, js를 복사한다. 

  - site/src/main/webapp/WEB-INF/templates/layout 폴더가 상/하/메인에 대한 레이아웃을 설정하는 템플릿 HTML이 존재한다

  - 상단 head.html에 bootstrap.css를 추가하고 하단 footer.html에 bootstrap.js를 하기와 같이 추가한다 

// layout/partials/head.html 


    <blc:bundle name="style.css" 

                mapping-prefix="/css/"

                files="bootstrap.css,

                       style.css,

                       jquery.rating.css" />



// layout/partials/footer.html


    <blc:bundle name="lib.js" 

                mapping-prefix="/js/"

                files="plugins.js,

                       libs/jquery.MetaData.js,

                       libs/jquery.rating.pack.js,

                       libs/jquery.dotdotdot-1.5.1.js,

                       bootstrap.js" />


  - 기존의 CSS는 전부 무시하고 트위터 부트스트랩을 재적용하는 단계이다. 따라서 DemoSite에 적용한 css/style.css 의 내용을 전부 제거 한다.

  - 제거한 내용에 몇가지 CSS를 하기와 같이 적용한다.

/************************************/

/* Header Customizing               */

/************************************/

.navbar .navbar-top {

height: 30px;

padding-top: 5px;

background-color: #F5F5F5;

transition: all 0.1s ease-out 0s;

-webkit-transition: all 0.1s ease-out 0s;

-moz-transition: all 0.1s ease-out 0s;

-ms-transition: all 0.1s ease-out 0s;

-o-transition: all 0.1s ease-out 0s;

font-size: 11px;

line-height: 11px;

text-transform: uppercase;

}


.navbar .container-fluid {

background-color:#525252;

}


.navbar-inverse .navbar-nav > li > a, .navbar-inverse .navbar-brand {

color: #FEFEFE;

}


html, body {

height: 100%;

}


  - site의 WEB-INF/templates/layout/home.html 의 내역에서 필요없는 부분을 주석처리 하고 partials/nav.html 를 사용한다. 

    + <blc:xxx> 로 사용하는 부분을 전부 제거했다. 나중에 필요한 부분에 넣을 것이다. 

    + partails/nav.html 에서 메뉴역할을 하도록 partails/header.html을 nav.html에 통합할 것이다. 

    + <blc:form> 을 통해 제품 검색을 수행한다. 

<head th:include="/layout/partials/head (pageTitle='Broadleaf And Twitter Bootstrap')"></head>


<body>

    <div id="notification_bar"></div>

    

    <nav th:substituteby="layout/partials/nav" />

    

    <footer th:substituteby="layout/partials/footer" />

    

</body>

</html>


  - 다음으로 메뉴를 nav.html에 적용한다. 

    + 트위터 부트스트랩에 맞게 RWD를 적용하고 카테고리(Categories)에 대해 Thymeleaf의 <li th:each> 구문을 적용한다.

    + Admin 화면 (http://localhost:8081/admin) 에서 Category에 해당하는 내용이 메뉴에 적용되는 것으로 broadleaf-framework-web 프로젝트의 org.broadleafcommerce.core.web.processor.CategoriesProcessor가 처리한다. 

<nav>   

    <div th:remove="all">

        <!--

             This template displays the navigation of the site by looking up the category named "Nav"

             and building a list of the categories sub-categories.                          

        -->

    </div>

    

    <blc:categories resultVar="navCategories" parentCategory="Primary Nav" maxResults="6" />

    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">

    

      <!-- TOP Header  -->

      <div class="navbar-top">

      <div class="container">

      <div class="pull-right">

   

    <div th:if="${customer.anonymous}"  th:remove="tag">

            <a th:href="@{/login}">

                <span th:text="#{home.login}">Login</span>

            </a>

            &nbsp;|&nbsp; 

            <a th:href="@{/register}">

                <span th:text="#{home.register}">Register</span>

            </a>

            &nbsp;|&nbsp; 

        </div>

        <div th:unless="${customer.anonymous}" th:remove="tag">

            <span><span th:text="#{home.welcome}">Welcome</span>, <a th:href="@{/account}" th:text="${customer.firstName}"></a></span>

            &nbsp;|&nbsp; 

            <a th:href="@{/logout}">

                <span th:text="#{home.logout}">Logout</span>

            </a>

            &nbsp;|&nbsp; 

        </div>

        <img blc:src="@{/img/icon-cart.jpg}" alt="Shopping Cart Icon" />&nbsp; 

        <a id="cartLink" th:href="@{/cart}">

            <span id="headerCartItemWordSingular_i18n" style="display: none;" th:text="#{home.item}" />

            <span id="headerCartItemWordPlural_i18n" style="display: none;" th:text="#{home.items}" />

            <span class="headerCartItemsCount" th:text="${cart.itemCount}" />

            <span class="headerCartItemsCountWord" th:text="${cart.itemCount == 1} ? #{home.item} :  #{home.items}" />

        </a>

   

    </div>   

    </div>

      </div>

      

      <!-- Responsible Menu -->

      <div class="container-fluid">

        <div class="navbar-header">

          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">

            <span class="sr-only">Toggle navigation</span>

            <span class="icon-bar"></span>

            <span class="icon-bar"></span>

            <span class="icon-bar"></span>

          </button>

          <a class="navbar-brand" href="/">eCommerce</a>

        </div>

        

        <div id="navbar" class="navbar-collapse collapse">

          <!-- Categories -->

          <ul class="nav navbar-nav navbar-right">

       

        <blc:form class="navbar-form navbar-right" style="margin-left:5px; margin-right:5px" th:action="@{/search}" method="GET">

            <input type="search" class="form-control" placeholder="SEARCH PROD" name="q" th:value="${originalQuery}" />

            <input type="submit" class="btn btn-default" value="go" />

    </blc:form>

   

            <li th:each="category : ${navCategories}" th:unless="${#strings.isEmpty(category.url)}">

            <a class="home" th:href="@{${category.url}}" th:class="${categoryStat.first}? 'home'" th:text="${category.name}"></a>

        </li>

          </ul>

        </div>

      </div>

      

    </nav>

    

</nav>


결과 화면은 다음과 같이 정상적인 화면과 RWD 메뉴가 적용된 화면이다. 



* 소스는 제공되지 않습니다. 관심있으신 분은 별도로 문의해 주세요. 



참조 


  - http://www.broadleafcommerce.org

  - Broadleaf core 깃헙 소스

  - http://www.thymeleaf.org

  - 트위터 부트스트랩

posted by Peter Note

BroadLeaf eCommerce 솔루션은 서버는 자바 Spring Framework와 Hibernate를 사용하고 상품에 대한 검색은 Solr를 사용한다. 그리고 클라이언트는 ThymeLeaf 템플릿 엔진을 사용해서 BroadLeaf과 강하게 결합해서 사용된다. BroadLeaf 데모 사이트를 실제 사용할 수 있는 eCommerce 사이트로 전환하는 과정을 살펴본다. 또한 Frontend 쪽에 Twitter BootstrapAngularJS를 적용해 Tymeleaf과 상호 운용될 수 있도록 설정해 본다.






Broadleaf DemoSite 설치 


  - BroadleafCommerce 는 코어 소스이고 Community 버전으로 오픈소스를 제공한다. 

  - BroadleafCommerce 코어 소스를 사용한 DemoSite를 제공한다. 

  - DemoSite를 깃헙에서 받아 사용해도 되고 eclipse workspace 파일을 별도로 이곳에서 받아도 된다. (다운로드 버전은 3.1.8 버전)

    + 만일 3.1.9 버전을 사용하고 싶다면 깃헙의 DemoSite 릴리즈에서 3.1.9-GA를 다운로드하면 된다.


  - DemoSite를 maven project로 eclipse에 import하는 과정은 BroadLeaf Starting 가이드를 참조한다.

    + eclipse는 luna를 사용하면 eclipse용 maven 플러그인이 기본 설치되어 있다. 

    + 단, Apache Maven 은 다운로드해서 설치하고 path를 잡아준다.

    + 최초 DemoSite/build.xml 을 Ant view에서 열고 "change-identifier"를 수행하고

       maven의 grouId를 com.xxxx 식으로 넣고  "y"를 선택하면 자바 패키지와 maven groupId등을 설정한 값으로 자동 변경한다. 


  - 최초에 메이븐 빌드를 한번 해준다. 먼저 DemoSite로 이동해서 하기 명령을 한번 수행한다

$ cd DemoSite

$ mvn clean install


  - Broadleaf은 Site와 Admin으로 구분되어 Site는 쇼핑사이트를 Admin은 카랄로그와 컨텐츠를 관리하고 각각 8080, 8081를 사용한다.

    + site/build.xml 과 admin/build.xml 을 ant view에서 열고 "jetty-demo"를 수행하면 된다. 

    + 데이터베이스는 기본으로 메모리DB인 HSQLDB를 사용한다.

Site

http://localhost:8080


Admin (id: admin, password: admin)

http://localhost:8081/admin/




MySQL전환하기 


  - MySQL 전환작업은 가이드를 참조한다. 

  - mysql로 전환하기 위해 데이터베이스와 계정을 broadleaf 로 지정하고 계정 암호는 abc1234 로 생성한다.

-- %> mysql --user=root -p mysql

-- Enter password: ******


-- mysql> grant all on broadleaf.* to broadleaf@localhost identified by 'abc1234' with grant option;

-- mysql> create database broadleaf;

-- mysql> flush privileges;


-- %> mysql -u broadleaf -p broadleaf

-- Enter password: ******


-- mysql> show grants for broadleaf@localhost;

-- mysql> select current_user;


  - admin과 site가 mysql을 사용하도록 DemoSite/pom.xml과 admin/pom.xml과 site/pom.xml에 다음을 설정한다 

// DemoSite/pom.xml  안에 설정 

<dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <version>5.1.34</version>

    <type>jar</type>

    <scope>compile</scope>

</dependency> 


// admin, site/pom.xml 안에 설정 

<dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

</dependency> 


  - jetty를 통해 기동될 때 데이터베이스 커넥션 유형을 3가지를 사용하는데 HSQLDB에서 MySQL로 환경값을 바꾸어 주어야 한다. 

    + /site/src/main/webapp/WEB-INF/jetty-env.xml

    + /admin/src/main/webapp/WEB-INF/jetty-env.xml

<New id="webDS" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>jdbc/web</Arg>

    <Arg>

        <New class="org.apache.commons.dbcp.BasicDataSource">

            <Set name="driverClassName">com.mysql.jdbc.Driver</Set>

            <Set name="url">jdbc:mysql://localhost:3306/broadleaf?useUnicode=true&amp;characterEncoding=utf8</Set>

            <Set name="username">broadleaf</Set>

            <Set name="password">abc1234</Set>

        </New>

    </Arg>

</New>

<New id="webSecureDS" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>jdbc/secure</Arg>

    <Arg>

        <New class="org.apache.commons.dbcp.BasicDataSource">

            <Set name="driverClassName">com.mysql.jdbc.Driver</Set>

            <Set name="url">jdbc:mysql://localhost:3306/broadleaf?useUnicode=true&amp;characterEncoding=utf8</Set>

            <Set name="username">broadleaf</Set>

            <Set name="password">abc1234</Set>

        </New>

    </Arg>

</New>

<New id="webStorageDS" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>jdbc/storage</Arg>

    <Arg>

        <New class="org.apache.commons.dbcp.BasicDataSource">

            <Set name="driverClassName">com.mysql.jdbc.Driver</Set>

            <Set name="url">jdbc:mysql://localhost:3306/broadleaf?useUnicode=true&amp;characterEncoding=utf8</Set>

            <Set name="username">broadleaf</Set>

            <Set name="password">abc1234</Set>

        </New>

    </Arg>

</New>


  - 하이버네이트의 Dialect를 HSQLDB에서 MySQL로 바꾼다. 

     + /core/src/main/resources/runtime-properties/common-shared.properties  의 맨 하단에 다음을 넣는다. 

# overriding dialect 

blPU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blSecurePU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blCMSStorage.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect


  - DemoSite의 build.properties의 기본 환경값을 HSQLDB에서 MySQL로 바꾼다. 

    + /DemoSite/build.properties 의 맨 하단에 다음을 넣는다. 

# new overriding 

ant.hibernate.sql.ddl.dialect=org.hibernate.dialect.MySQL5InnoDBDialect


ant.blPU.url=jdbc:mysql://localhost:3306/broadleaf

ant.blPU.userName=broadleaf

ant.blPU.password=abc1234

ant.blPU.driverClassName=com.mysql.jdbc.Driver


ant.blSecurePU.url=jdbc:mysql://localhost:3306/broadleaf

ant.blSecurePU.userName=broadleaf

ant.blSecurePU.password=abc1234

ant.blSecurePU.driverClassName=com.mysql.jdbc.Driver


ant.blCMSStorage.url=jdbc:mysql://localhost:3306/broadleaf

ant.blCMSStorage.userName=broadleaf

ant.blCMSStorage.password=abc1234


  - 그리고 가장 중요한 설정은 site와 admin 의 common.properties에 맨 하단에 다음 사항을 필히 넣어 주어야 BLC_SKU 테이블이 생성됨

    + /site/src/main/resources/runtime-properties/common.properties

    + /admin/src/main/resources/runtime-properties/common.properties

# overriding dialect 

blPU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blSecurePU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blCMSStorage.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect


  - 전환 후에는 ant task에서 "build-app"를 해주고 "jetty-run-no-db"를 선택하면 build한 target 디렉토리의 소스가 적용된다. 


     




참조 

  

  - Broadleaf v3.1 Guide

posted by Peter Note
2014. 5. 27. 09:24 Study Frameworks/Liferay Portal

Template을 공유하는 방법에 대해 알아보자 



Resource Importer App 설치 

  - 템플릿 적용을 위해서는 Template Importer를 사용하는데 이는 Resources Importer App의 일부 기능이다. 

  - Liferay Makketplace 에서 Resources Importer App 다운로드 설치한다. (v2.0.1 CE 버전)

    + 오른쪽의 [Free] 버튼 클릭

    + 가입하고 로그인후 개인적 용도로 사용 선택

    + 구매내역으로 이동하면 [Download] 버튼을 클릭

    + 최종파일 : Resources Importer CE.lpkg

    + 최종파일을 $LIFERAY_PORTAL/deploy 폴더에 넣고 start 하면 tomcat webapps로 자동 배포된다

      

    또는 Control Panel로 이동하여 선택해서 설치할 수도 있다 

     


  - Resource Importer App 개념 

The Resources Importer app allows front-end developers to package web content, portlet configurations, and layouts together in a theme without saving it as a compiled .LAR file thereby allowing for greater flexibility in its usage between Liferay Portal versions. This app will automatically create associated content when other plugins are deployed that are configured to make use of the Resource Importer app.



Sample Template 적용하기

  - mobiconsoft_template 라는 portlet을 eclipse에서 생성한다

    

  - maven 기반이므로 pom.xml을 이전 블로그를 참조하여 수정한다

    

  - liferay-plugin-package.properties 안에 다음을 첨부한다. 또한 기존에 설정된 name 값을 삭제한다  

name=

module-group-id=liferay

module-incremental-version=1

tags=

short-description=

change-log=

page-url=http://www.liferay.com

author=Liferay, Inc.

licenses=LGPL


required-deployment-contexts=resources-importer-web

resources-importer-developer-mode-enabled=true

module-incremental-version=1

  - portlet.xml에서 <display-name> 태그도 삭제한다 

  - WEB-INF/src 밑으로 templates-importer를 만든다. 그러나 지금은 maven 기반이므로 src/main/resources 밑에 templates-importer 폴더를 생성한다 

   


  - samples-template-importer-content.zip 파일을 다운로드 받아 templates-importer 폴더 안에 푼다.  

    


  - 폴더의 구조

  • templates-importer/
    • journal/
      • structures/ - contains structures (XML) and folders of child structures. Each folder name must match the file name of the corresponding parent structure. For example, to include a child structure of parent structure Parent 1.xml, create a folder named Parent 1/ at the same level as the Parent 1.xml file, for holding a child structures.
      • templates/ - groups templates (FTL or VM) into folders by structure. Each folder name must match the file name of the corresponding structure. For example, create folder Structure 1/ to hold a template for structure file Structure 1.xml.
    • templates/
      • application_display/ - contains application display template (ADT) script files written in either the FreeMarker Template Language (.ftl) or Velocity (.vm). The extension of the files, .ftl for FreeMarker or .vm for Velocity must reflect the language that the templates are written in.
        • asset_category/ - contains categories navigation templates
        • asset_entry/ - contains asset publisher templates
        • asset_tag/ - contains tags navigation templates
        • blogs_entry/ - contains blogs templates
        • document_library/ - contains documents and media templates
        • site_map/ - contains site map templates
        • wiki_page/ - contains wiki templates
      • dynamic_data_list/ - contains dynamic data list templates and structures
        • display_template/ - groups templates (FTL or VM) into folders by structure. Each folder name must match the file name of the corresponding structure. For example, create folderStructure 1/ to hold a template for structure file Structure 1.xml.
        • form_template/ - groups templates (FTL or VM) into folders by structure. Each folder name must match the file name of the corresponding structure. For example, create folder Structure 1/ to hold a template for structure file Structure 1.xml.
        • structure/ - contains structures (XML)
      • page/ - contains page templates (JSON)


  - 이제 프로젝트를 선택하고 contentx menu를 통해 mobiconsoft_template 포틀릿을 배포한다. 

   

   배포가 성공하면 deploy 폴더로 자동 복사된다. 

[INFO] --- liferay-maven-plugin:6.2.1:deploy (default-cli) @ mobiconsoft_template ---

[INFO] Deploying mobiconsoft_template-1.0.0-SNAPSHOT.war to /liferay_portal/portal-6.2-ce-ga2/deploy

     [null] Copying 1 file to /liferay_portal/portal-6.2-ce-ga2/deploy

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 10.980s

[INFO] Finished at: Tue May 27 08:51:31 KST 2014

[INFO] Final Memory: 34M/525M

[INFO] ------------------------------------------------------------------------

 

   - 로그인후 Admin의 Control Panel을 선택하고 "Site"에서 Global을 선택한다 

   

  - Configuration의 "Application Display Templates"을 선택한다  

   

  - 리스트에 보면 첨부한 내역을 볼 수 있다. 이후 처리에 대한 부분은 to be continue... (문서에 정확히 안나와 있음)

  - template의 layout은 templates/page/*.json 으로 정의한다 

{

"layoutTemplate": {

"columns": [

[

{

"portletId": "58"

}

],

[

{

"portletId": "47"

}

]

],

"friendlyURL": "/page-1",

"name": "Page 1",

"title": "Page 1"

},

"layoutTemplateId": "2_columns_ii"

}


  * ant 기반 해당 포틀릿 소스



<참조>

  - Creating plugin to share template

  - Theme 정의하기

  - Liferay Dev Guide in GitHub

posted by Peter Note
2014. 5. 27. 00:15 Study Frameworks/Liferay Portal

Liferay에서 제공하는 포틀릿을 확장하는 방법에 대해 알아본다. 



기존 플러그인 확장 순서 

  - 포틀릿 하나를 만든다 

$ cd ~/liferay_portal/plugins-sdk-6.2/portlets

$ create.sh mobiconsoft_hi "modify portlet"

Buildfile: /liferay_portal/plugins-sdk-6.2/portlets/build.xml


create:

     [copy] Copying 9 files to /liferay_portal/plugins-sdk-6.2/portlets/mobiconsoft_hi-portlet

    [mkdir] Created dir: /liferay_portal/plugins-sdk-6.2/portlets/mobiconsoft_hi-portlet/docroot/WEB-INF/tld

     [copy] Copying 7 files to /liferay_portal/plugins-sdk-6.2/portlets/mobiconsoft_hi-portlet/docroot/WEB-INF/tld


BUILD SUCCESSFUL

Total time: 3 seconds


$ cd mobiconsoft_hi-portlet/

  - portlet 소스 하나를 mobiconsoft_hi-portlet/docroot/ 밑으로 복사

    + https://github.com/liferay/liferay-plugins 에는 CE 관련 소스들이 있다. 로컬로 clone한다

    + portlet 소스는 liferay-plugins/portlet/ 밑에 존재한다

  - ant를 통해서 war파일을 만든다

$ ant war 

수행이 정상적으로 완료되면 

/plugins-sdk-6.2/dist/ 폴더에 mobiconsoft_hi-portlet-6.2.0.2.war 파일이 생성된다 



Eclipse Import 한 후 Mavenization

  - git clone한 소스를 import 하게 되면 ant 기반으로 되어 있다. build.xml을 통하여 ant deploy를 할 수 있다. 

    

  - maven 기반으로 만드는 것은 다음과 같이 해보자

    + 먼저 eclipse에서 liferay plugin을 maven 기반으로 생성한다

    + WEB-INF 소스를 그대로 복사한다. 

    + 단, WEB-INF/**/*.java 소스들은 maven의 src/main/java 로 리소스는 src/main/resources로 패키지 구조에 맞게 복사한다 

  - 다음 pom.xml 에서 다음 부분을 첨부한다 

        <properties>

   <liferay.app.server.deploy.dir>/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps</liferay.app.server.deploy.dir>

   <liferay.app.server.lib.global.dir>/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/lib/ext</liferay.app.server.lib.global.dir>

   <liferay.app.server.portal.dir>/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT</liferay.app.server.portal.dir>

   <liferay.auto.deploy.dir>/liferay_portal/portal-6.2-ce-ga2/deploy</liferay.auto.deploy.dir>

   <liferay.maven.plugin.version>6.2.1</liferay.maven.plugin.version>

   <liferay.version>6.2.1</liferay.version>

    </properties>

   

    <repositories>

   <repository>

       <id>liferay-ce</id>

       <name>Liferay CE</name>

       <url>https://repository.liferay.com/nexus/content/groups/liferay-ce</url>

       <releases><enabled>true</enabled></releases>

       <snapshots><enabled>true</enabled></snapshots>

   </repository>

</repositories>

<pluginRepositories>

   <pluginRepository>

       <id>liferay-ce</id>

       <url>https://repository.liferay.com/nexus/content/groups/liferay-ce/</url>

       <releases><enabled>true</enabled></releases>

       <snapshots><enabled>true</enabled></snapshots>

   </pluginRepository>

</pluginRepositories>

<build>

<plugins>

<plugin>

<groupId>com.liferay.maven.plugins</groupId>

<artifactId>liferay-maven-plugin</artifactId>

<version>${liferay.maven.plugin.version}</version>

<executions>

<execution>

<phase>generate-sources</phase>

<goals>

<goal>build-css</goal>

</goals>

</execution>

</executions>

<configuration>

<autoDeployDir>${liferay.auto.deploy.dir}</autoDeployDir>

<appServerDeployDir>${liferay.app.server.deploy.dir}</appServerDeployDir>

<appServerLibGlobalDir>${liferay.app.server.lib.global.dir}</appServerLibGlobalDir>

<appServerPortalDir>${liferay.app.server.portal.dir}</appServerPortalDir>

<liferayVersion>${liferay.version}</liferayVersion>

<pluginType>portlet</pluginType>

</configuration>

</plugin>

<plugin>

<artifactId>maven-compiler-plugin</artifactId>

<version>2.5</version>

<configuration>

<encoding>UTF-8</encoding>

<source>1.6</source>

<target>1.6</target>

</configuration>

</plugin>

<plugin>

<artifactId>maven-resources-plugin</artifactId>

<version>2.5</version>

<configuration>

<encoding>UTF-8</encoding>

</configuration>

</plugin>

</plugins>

</build>


<dependencies> ... 여기는 기존 설정을 그대로 사용함  </dependencies>


pom.xml 파일은 글로벌 settings.xml에 repository에 설정해도 된다. 또한 Nexus가 설치 되어 있다면 설정한다. 계속해서 포틀릿을 만들고 배포를 위해서는 Nexus를 설치하여 운영하는게 좋겠다. 



<참조> 

  - 기존 플러그인 확장하기 

posted by Peter Note
2014. 5. 26. 09:44 Study Frameworks/Liferay Portal

포틀릿에서 Action Phase 수행후 Render Phase로 정보들 어떻게 전달 될 수 있는지 알아보자 



Action 에서 Render Phase로 정보전달 방식

  - render parameters를 통한 정보 전달 : REQUEST SCOPE

> Action Phase

  processAction 안에서 actionResponse.setRenderParameter("parameter-name", "value");  값을 설정


> Render Phase

  renderRequest.getParameter("parameter-name"); 호출하여 값을 얻어옴 


> 단, action phase에서는 only read 이므로 set이 가능하려면 portlet.xml 에 다음 설정을 한다. 해당 설정을 하게되면 action phase parameters 가 render phase parameters로 복사된다. 

<init-param>

    <name>copy-request-parameters</name>

    <value>true</value>

</init-param>


> action parameter를 render parameter로 전달하게 되면 action phase이후 모든 포틀릿의 render phase가 호출되는 것임을 유의 


  - 세션 방식의 전달 : SESSION SCOPE

> actionRequest에 설정하고 JSP가 읽는다. 해당 설정값은 JSP에 딱 한번 사용되고 자동으로 삭제한다 

//SessionMessages 사용 경우 

package com.liferay.samples;


import java.io.IOException;

import javax.portlet.ActionRequest;

import javax.portlet.ActionResponse;

import javax.portlet.PortletException;

import javax.portlet.PortletPreferences;

import com.liferay.portal.kernel.servlet.SessionMessages;

import com.liferay.util.bridges.mvc.MVCPortlet;


public class MyGreetingPortlet extends MVCPortlet {

    public void setGreeting(

            ActionRequest actionRequest, ActionResponse actionResponse)

    throws IOException, PortletException {

        PortletPreferences prefs = actionRequest.getPreferences();

        String greeting = actionRequest.getParameter("greeting");


        if (greeting != null) {

            try {

                prefs.setValue("greeting", greeting);

                prefs.store();

                SessionMessages.add(actionRequest, "success");

            }

            catch(Exception e) {

                SessionErrors.add(actionRequest, "error");

            }

        }

    }

}


// view.jsp 에서 sucess / error 사용 

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>

<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<liferay-ui:success key="success" message="Greeting saved successfully!"/>

<liferay-ui:error key="error" message="Sorry, an error prevented savingyour greeting" />


<% PortletPreferences prefs = renderRequest.getPreferences(); String

greeting = (String)prefs.getValue(

    "greeting", "Hello! Welcome to our portal."); %>


<p><%= greeting %></p>


<portlet:renderURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:renderURL>


<p><a href="<%= editGreetingURL %>">Edit greeting</a></p>


  - Liferay Portal 은 multi parameters들을 포틀릿에 전달하므로 namespace 구분을 하는게 중요하다 

<portlet:namespace />  를 사용하면 포틀릿별 유니크한 네임스페이스를 가질 수 있다 

예) submitForm(document.<portlet:namespace />fm);  form에 대한 것


Liferay는 namespaced 파라미터만 포틀릿에 접근할 수 있다. 그러나 third-part 에서 unamespaced parameter가 존재하면

 liferay-portal.xml 에서 기능을 꺼주어야 한다. 

<requires-namespaced-parameters>false</requires-namespaced-parameters>



Multi Action 추가

  - 포틀릿에 원하는 Action만큼 추가할 수 있다

1) 메소드 명칭은 사용자 정의 & 두개의 파라미터 받음 

    public void setGreeting(ActionRequest actionRequest, ActionResponse actionResponse) 

         throws IOException, PortletException {...

    }


    public void sendEmail(ActionRequest actionRequest, ActionResponse actionResponse) 

        throws IOException, PortletException {

        // Add code here to send an email

    }


2) setGreeting 명칭은 JSP에서 actionURL의 name과 일치해야 한다 

<portlet:actionURL var="editGreetingURL" name="setGreeting">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:actionURL>



포틀릿 URL Mapping을 친숙한 방법으로 전환

  - v6 부터 human readable 하게 url을 만들 수 있다. 

 > 원래 보이는 형태 

http://localhost:8080/web/guest/home?p_p_id=mygreeting_WAR_mygreetingportlet

    &p_p_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=column-1

    &p_p_col_count=2&_mygreeting_WAR_mygreetingportlet_mvcPath=%2Fedit.jsp


 > friendly url 변환 

http://localhost:8080/web/guest/home/-/my-greeting/edit

  - liferay-portlet.xml 에서 </icon> 이후 <instanceable> 바로 전에 하기 설정을 넣음 

1) liferay-portlet.xml 설정 내역 

<liferay-portlet-app>

<portlet>

<portlet-name>mobiconsoft_greeting</portlet-name>

<icon>/icon.png</icon>

<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>

<friendly-url-mapping>mobiconsoft_greeting</friendly-url-mapping>

<friendly-url-routes>mobiconsoft/greeting/mobiconsoft-greeting-friendly-url-routes.xml</friendly-url-routes>

<instanceable>false</instanceable>

<header-portlet-css>/css/main.css</header-portlet-css>

<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>

</portlet>


2) src/main/resources/폴더 밑의 monbiconsoft/greeting/ 폴더 밑으로 mobiconsoft-greeting-friendly-url-routes.xml 생성 및 입력


<?xml version="1.0"?>

<!DOCTYPE routes PUBLIC "-//Liferay//DTD Friendly URL Routes 6.2.0//EN"

"http://www.liferay.com/dtd/liferay-friendly-url-routes_6_2_0.dtd">


<routes>

    <route>

        <pattern>/{mvcPathName}</pattern>

        <generated-parameter name="mvcPath">/{mvcPathName}.jsp</generated-parameter>

    </route>

</routes>


3) eclipse의 context menu에서 "Liferay" -> "Maven" -> "deploy"를 선택하면 war파일 생성됨 


4) eclipse에서 테스트 서버 수행하면 deploy 폴더의 war 파일들이 자동배포된다. test@liferay.com (패스워드 : test) 로그인

    로그인후 우측 상단의 "+" 를 클릭하고 Sample 메뉴에서 mobiconsoft_greeting을 추가하면 하기 무한루프 오류가 발생함

    (추후 오류현상 추적필요)


시도하고 시도해 보고 실패에서 배워보자. 다음엔 포틀릿를 좀 더 고도화 해보자 



<참조> 

  - Action -> Render Phase 정보전달

  - Multi Action 추가하는 방법

posted by Peter Note

포틀릿을 생성하고 세부사항에 대하여 알아보고, 포틀릿의 두가지 Phase를 이해하자. 이를 위해 Maven 기반으로 포틀릿을 생성하고 Java와 JSP를 생성/수정해 보도록 한다. 

완성된 포틀릿의 edit 모습

 


포틀릿 생성

  - 이클립스 IDE를 통한 생성

  - CLI 명령으로 통한 생성

// CLI 생성

// 이름의 뒤에 자동으로 "-portlet"이 붙는다 

$ cd ~/development/liferay_portal/plugins-sdk-6.2/portlets

$ create.sh mobiconsoft-greeting "hi youngsik"

Buildfile: /Users/xxx/development/liferay_portal/plugins-sdk-6.2/portlets/build.xml

.. 중략 ..

BUILD SUCCESSFUL

Total time: 1 second


// 배포

$ ant deploy 

Buildfile: /Users/xxx/development/liferay_portal/plugins-sdk-6.2/portlets/build.xml

deploy:

    .. 중략 ..

     [copy] Copying 1 file to /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/deploy

BUILD SUCCESSFUL

Total time: 9 seconds


* 만일 tomcat ROOT를 변경하였다면 deploy/*.war는 기본 폴더인 {TOMCAT_HOME}/webapps/ 밑으로 들어간다. 

tomcat을 수행하기전에 deploy/*.war 파일을 변경된 폴더 밑으로 copy한 후 시작한다. (변경된 폴더로 deploy하는 설정을 못 찾겠음)



Portlet 구조이해

  - 톰켓에 배포된 디렉토리 구조

> 자바 소스, 웹 리소스, 환경 설정 3가지로 구성되어있다.

  톰켓의 단일 Context로 운영된다. 즉, J2EE Context 폴더 구조임 


> xml 환경파일들

 portlet.xml : JSR-286 Portlet 스펙에 대한 환경파일

 liferay-display.xml : 화면구성 위저드에서 카테고리 지정 

 liferay-plugin-package.properties : hot deploy 설정

 liferay-portlet.xml : liferay portal server와 특화된 portlet 설정들

 

> 리소스들

 html : 클라이언트에 표현되는 것으로 <html>, <head> 태그는 없어야 함

 css, js : 다른 css와 충돌하지 않도록 namespace를 준다 


  - portlet.xml

    + MVCPortlet : 포틀릿 전체 기능이 내장된 놈. 우리가 만드는 포틀릿은 실제 요것을 상속받아서 구현된다. 

    + portlet-info : 카테고리되었을 때 이름 지정 

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0">

<portlet>

<portlet-name>mobiconsoft-greeting</portlet-name>

<display-name>hi youngsik</display-name>

<portlet-class>com.liferay.util.bridges.mvc.MVCPortlet</portlet-class>

<init-param>

<name>view-template</name>

<value>/view.jsp</value>

</init-param>

<expiration-cache>0</expiration-cache>

<supports>

<mime-type>text/html</mime-type>

</supports>

<portlet-info>

<title>hi youngsik</title>

<short-title>hi youngsik</short-title>

<keywords>hi youngsik</keywords>

</portlet-info>

<security-role-ref>

<role-name>administrator</role-name>

</security-role-ref>

<security-role-ref>

<role-name>guest</role-name>

</security-role-ref>

<security-role-ref>

<role-name>power-user</role-name>

</security-role-ref>

<security-role-ref>

<role-name>user</role-name>

</security-role-ref>

</portlet>

</portlet-app>


  - liferay-portlet.xml 

    + header-portlet-css : <header> 태그에 들어갈 css 

    + footer-portlet-javascripit : </body> 끝에 들어갈 javascript 

    + instanceable : 해당 포틀릿이 한페이지 멀티로 나오는 인스턴스들인지 true / false 설정

<?xml version="1.0"?>

<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_2_0.dtd">


<liferay-portlet-app>

<portlet>

<portlet-name>mobiconsoft-greeting</portlet-name>

<icon>/icon.png</icon>

<header-portlet-css>/css/main.css</header-portlet-css>

<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>

<css-class-wrapper>mobiconsoft-greeting-portlet</css-class-wrapper>

</portlet>

<role-mapper>

<role-name>administrator</role-name>

<role-link>Administrator</role-link>

</role-mapper>

<role-mapper>

<role-name>guest</role-name>

<role-link>Guest</role-link>

</role-mapper>

<role-mapper>

<role-name>power-user</role-name>

<role-link>Power User</role-link>

</role-mapper>

<role-mapper>

<role-name>user</role-name>

<role-link>User</role-link>

</role-mapper>

</liferay-portlet-app>



포틀릿을 수정해 보기 

  - liferay-portal.xml 에서 instanceable=false 추가 

<instanceable>false</instanceable>

  - view.jsp 파일 수정 

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<%

PortletPreferences prefs = renderRequest.getPreferences();

String greeting = (String)prefs.getValue("greeting", "Hello! Welcome to our portal.");

%>


<p><%= greeting %></p>


<portlet:renderURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:renderURL>


<p><a href="<%= editGreetingURL %>">Edit greeting</a></p>

  - edit.jsp 파일 신규 추가

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>


<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<%

PortletPreferences prefs = renderRequest.getPreferences();

String greeting = renderRequest.getParameter("greeting");

if (greeting != null) {

    prefs.setValue("greeting", greeting);

    prefs.store();

%>

    <p>Greeting saved successfully!</p>

<%

}

%>


<%

greeting = (String)prefs.getValue("greeting", "Hello! Welcome to our portal.");

%>


<portlet:renderURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:renderURL>


<aui:form action="<%= editGreetingURL %>" method="post">

    <aui:input label="greeting" name="greeting" type="text" value="<%=greeting %>" />

    <aui:button type="submit" />

</aui:form>


<portlet:renderURL var="viewGreetingURL">

    <portlet:param name="mvcPath" value="/view.jsp" />

</portlet:renderURL>


<p><a href="<%= viewGreetingURL %>">&larr; Back</a></p>

  - {SDK}/portlets 밑에서 수정했으면 다시 deploy를 이미 www 폴더에서 수정했다면 tomcat 다시 restart 한다.

// 수정한 view.jsp 


// 신규 추가한 edit.jsp 



  - *.jsp 에서 중요한 사항

    +  http://java.sun.com/portlet_2_0 에서 정의한 <portlet:renderURL> 태그(taglib)를 사용한다  

    +  edit.jsp에서 aui(AlloyUI == YUI3)를 이용하여 form을 만들고 있다 

    + <portlet:defineObjects/> 를 넣으면 renderRequest, portletConfig, portletPreferences 를 jsp에서 사용할 수 있다. 이것은 jsp에서만 유효하고 여러가지 오브젝트를 사용토록 해준다 

RenderRequest renderRequest: represents the request sent to the portlet to handle a render. renderRequest is only available to a JSP if the JSP was included during the render request phase.


ResourceRequest resourceRequest: represents the request sent to the portlet for rendering resources. resourceRequest is only available to a JSP if the JSP was included during the resource-serving phase.


ActionRequest actionRequest: represents the request sent to the portlet to handle an action. actionRequest is only available to a JSP if the JSP was included during the action-processing phase.


EventRequest eventRequest: represents the request sent to the portlet to handle an event. eventRequest is only available to a JSP if the JSP was included during the event-processing phase.


RenderResponse renderResponse: represents an object that assists the portlet in sending a response to the portal. renderResponse is only available to a JSP if the JSP was included during the render request phase.


ResourceResponse resourceResponse: represents an object that assists the portlet in rendering a resource. resourceResponse is only available to a JSP if the JSP was included in the resource-serving phase.


ActionResponse actionResponse: represents the portlet response to an action request. actionResponse is only available to a JSP if the JSP was included in the action-processing phase.


EventResponse eventResponse: represents the portlet response to an event request. eventResponse is only available to a JSP if the JSP was included in the event-processing phase.


PortletConfig portletConfig: represents the portlet’s configuration including, the portlet’s name, initialization parameters, resource bundle, and application context. portletConfig is always available to a portlet JSP, regardless of the request-processing phase in which it was included.


PortletSession portletSession: provides a way to identify a user across more than one request and to store transient information about a user. A portletSession is created for each user client. portletSession is always available to a portlet JSP, regardless of the request-processing phase in which it was included. portletSession is null if no session exists.


Map<String, Object> portletSessionScope: provides a Map equivalent to the PortletSession.getAtrributeMap() call or an empty Map if no session attributes exist.


PortletPreferences portletPreferences: provides access to a portlet’s preferences. portletPreferences is always available to a portlet JSP, regardless of the request-processing phase in which it was included.


Map<String, String[]> portletPreferencesValues: provides a Map equivalent to the portletPreferences.getMap() call or an empty Map if no portlet preferences exist.



Liferay IDE를 통한 개발 (주의사항)

  - 기본 {TOMCAT_HOME}/webapps/ROOT 를 사용한다. 

  - 기존 ~/liferay_portal/www 에서 다시 원위치로 설정한다.

1) {TOMCAT_HOME}/conf.xml 에서 위치 변경

<Host appBase="/Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps" autoDeploy="true" name="localhost" unpackWARs="true">


2) {PLUGIN_SDK}/build.<username>.properties

app.server.tomcat.lib.global.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/lib/ext

app.server.tomcat.deploy.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps

app.server.parent.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2

app.server.tomcat.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42

app.server.type = tomcat

app.server.tomcat.portal.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT

  - 또한 Maven으로 생성시 pom.xml에서 <version> 은 "1.0.0-SNAPSHOT"이 아니라 "portlet" 이라고 준다 



포틀릿의 2 Phase Execution 이해 

  - Action Phase와 Render Phase로 구성된다

  - Action Phase

    + 하나의 포틀릿에서만 유저 인터렉션이 일어날 수있다. 

    + 사용자의 prefereneces는 한번만 변경되고 재변경되지 않는다 

  - Render Phase

    + action phase가 있은 후 모든 포틀릿의 render phase를 호출한다.

1) action phase를 만들기위해서 기존에 Eclipse에서 생성한 "mobiconsoft-sample"에서 자바소스를 추가한다 

    (CLI 방식일 경우 : {SDK}/porlets/mobiconsoft-sample-portlet/WEB-INF/src 밑에 둔다)

     MVCPorlet을 상속받는다 

package com.mobiconsoft.sample;


import java.io.IOException;

import javax.portlet.ActionRequest;

import javax.portlet.ActionResponse;

import javax.portlet.PortletException;

import javax.portlet.PortletPreferences;

import com.liferay.util.bridges.mvc.MVCPortlet;


public class YoungSikGreetingPortlet extends MVCPortlet {

    @Override

    public void processAction(ActionRequest actionRequest, ActionResponse actionResponse)

        throws IOException, PortletException {

        PortletPreferences prefs = actionRequest.getPreferences();

        String greeting = actionRequest.getParameter("greeting");


        if (greeting != null) {

            prefs.setValue("greeting", greeting);

            prefs.store();

        }


        super.processAction(actionRequest, actionResponse);

    }

}


2) portlet.xml 파일의 내용에서 MVCPortlet을 바꾼다 

<portlet-class>com.mobiconsoft.sample.YoungSikGreetingPortlet</portlet-class>


3) edit.jsp 안에 action을 넣어보자 

   - renderURL : render phase에서만 호출 된다 

   - actionURL : 페이지안의 모든 포틀릿을 rendering 하기전에 action phase를 수행한다

   - resourceURL : xml, images, json, AJAX 요청등

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>


<%@ page import="com.liferay.portal.kernel.util.ParamUtil" %>

<%@ page import="com.liferay.portal.kernel.util.Validator" %>

<%@ page import="javax.portlet.PortletPreferences" %>


<portlet:defineObjects />


<%

    PortletPreferences prefs = renderRequest.getPreferences();

    String greeting = (String)prefs.getValue("greeting", "Hello! Welcome to our portal.");

%>


<portlet:actionURL var="editGreetingURL">

    <portlet:param name="mvcPath" value="/edit.jsp" />

</portlet:actionURL>


<aui:form action="<%= editGreetingURL %>" method="post">

        <aui:input label="greeting" name="greeting" type="text" value="<%=

    greeting %>" />

        <aui:button type="submit" />

</aui:form>


<portlet:renderURL var="viewGreetingURL">

        <portlet:param name="mvcPath" value="/view.jsp" />

</portlet:renderURL>


<p><a href="<%= viewGreetingURL %>">&larr; Back</a></p>


4) deploy 해서 확인해 볼 수 있다. 



<참조>

  - 포틀릿 해부하기 

  - 포틀릿 수정하기 

  - 포틀릿 2 Phase Execution

  - pom.xml 파일 샘플 

pom-userxxx-liferay.xml

posted by Peter Note

Liferay는 기본 Ant 기반으로 되어 있고, Maven 기반으로 변경할 수 있다. 



Maven 및 Nexus OSS 설치

  - Ant는 build.xml에 설정하고 Maven은 pom.xml (Project Object Model)에 설정한다 

  - 예전 Spring+Maven 설정 블로깅을 참조한다.

  - 메이븐은 로컬에 Nexus 서버를 설치하여 프로젝트/사내 시스템 단위로 라이브러리를 관리할 수 있다

   + http://www.sonatype.org/nexus/

   + Nexus 설치 가이드

   + 접속 : http://localhost:8081/nexus  (admin / admin123)

   + Optional Install 사항이다. 굳이 설치하지 않아도 됨

  - Liferay Nexus Repository : https://repository.liferay.com/nexus/index.html



Liferay Maven 설정

  - 다운로드 liferay maven 라이브러리 (liferay-portal-maven-[version]-[date].zip) : CE버전만 해당됨

  - 해당 파일에는 Maven artifact에 대한 파일 뿐만 아니라 스크립트 도구도 포함되어 있다. 적절한 위치에 압축을 해제한다 

1) maven은 liferay-portals 소스를 참조하여 빌드되므로 소스를 다운로드 한다 

$ cd ~/development/liferay_portal/sources

$ git clone https://github.com/liferay/liferay-portal.git 


2) app.server.[user name].properties 파일을 liferay-portal 폴더 밑에 생성한다

$ cd ~/development/liferay_portal/sources/liferay-portal

$ vi app.server.[username].properties

app.server.type=tomcat

app.server.parent.dir=/Users/nulpulum/development/liferay_portal/portal-6.2-ce-ga2

app.server.tomcat.dir=${app.server.parent.dir}/tomcat-7.0.42


3) Local Repository 가 아닌 Liferay Central Repository에서 Artifacts 를 설치할 경우 pom.xml에 들어갈 내용

<repositories>

    <repository>

        <id>liferay-ce</id>

        <name>Liferay CE</name>

        <url>https://repository.liferay.com/nexus/content/groups/liferay-ce</url>

        <releases><enabled>true</enabled></releases>

        <snapshots><enabled>true</enabled></snapshots>

    </repository>

</repositories>


<pluginRepositories>

    <pluginRepository>

        <id>liferay-ce</id>

        <url>https://repository.liferay.com/nexus/content/groups/liferay-ce/</url>

        <releases><enabled>true</enabled></releases>

        <snapshots><enabled>true</enabled></snapshots>

    </pluginRepository>

</pluginRepositories>


  > Central Repository in Nexus


 > CLI 명령을 통해 접근 할 수도 있다

mvn archetype:generate -DarchetypeCatalog=https://repository.liferay.com/nexus/content/groups/liferay-ce

   


Liferay Eclipse IDE에 Maven 설정

  - Liferay IDE 2.0 에서는 Maven project configurator (m2e-liferay) 제공

1) 만일 Meven Integration for Eclipse 1.4가 설치되어 있다면 1.5 버전으로 먼저 업데이트한다. 


2) "Help" -> "Install New Software ..." 에서  Liferay SDK와 m2e-liferay 를 삭제하고-already installed 링크 클릭하여 삭제가능- Liferay IDE의 m2e-liferay 두개를 다시 설치한다.  (mobile SDK는 미선택)

Liferay IDE repository - http://releases.liferay.com/tools/ide/latest/stable/.

 


으악 Liferay Perspective가 동작하질 않는다!!!

3) Liferay Eclipse 4.3 - Kepler로 이동하기 

  - 멘붕이 시작되었다. m2e-liferay를 설치한 후 Liferay perspective가 제대로 동작하질 않아서 SDK, m2e 모두 삭제하고 다양한 방법으로 여러번 reinstall 시도를 하여도 Liferay Perspective가 제대로 동작하지 않아서 Eclipse Kepler(4.3) 최신버전으로 Liferay를 재구성 하였다.

  - 다운로드 Eclipse Kepler 설치 

  - JDK v1.7 기반


  - pom.xm 배포위치 & 저장소 위치 & 의존성 관계 라이브러리 환경 설정

    + Global settings, User settings, Parent Project pom.xml, Project pom.xml 4군데 중 하나에 설정한다. 

    + 다른 프로젝트충돌을 방지할려면 자신의 프로젝트 pom.xml에 설정하는게 좋겠다.

    + Global/User settings 에는 profile에 설정하여 pom.xml에서 profile을 불러와서 사용하면 된다. (pom.xml 마다 설정이 필요없음)

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

<project xmlns="http://maven.apache.org/POM/4.0.0"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>


    <groupId>com.liferay.sample</groupId>

    <artifactId>sample-parent-project</artifactId>

    <version>1.0-SNAPSHOT</version>

    <packaging>pom</packaging>


    <name>sample-parent-project</name>

    <url>http://www.liferay.com</url>


    <!-- START : Maven 방식 Liferay plugin 생성시 추가해야할 내역 --> 

    <properties>

    <liferay.app.server.deploy.dir>/Users/xxx/development/liferay_portal/www</liferay.app.server.deploy.dir>

    <liferay.app.server.lib.global.dir>

/Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42\lib\ext

    </liferay.app.server.lib.global.dir>

    <liferay.app.server.portal.dir>/Users/xxx/development/liferay_portal/www/ROOT</liferay.app.server.portal.dir>

    <liferay.auto.deploy.dir> /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/deploy</liferay.auto.deploy.dir>

    <liferay.maven.plugin.version>6.2.1</liferay.maven.plugin.version>

    <liferay.version>6.2.1</liferay.version>

    </properties>


    <repositories>

    <repository>

        <id>liferay-ce</id>

        <name>Liferay CE</name>

        <url>https://repository.liferay.com/nexus/content/groups/liferay-ce</url>

        <releases><enabled>true</enabled></releases>

        <snapshots><enabled>true</enabled></snapshots>

    </repository>

</repositories>


<pluginRepositories>

    <pluginRepository>

        <id>liferay-ce</id>

        <url>https://repository.liferay.com/nexus/content/groups/liferay-ce/</url>

        <releases><enabled>true</enabled></releases>

        <snapshots><enabled>true</enabled></snapshots>

    </pluginRepository>

</pluginRepositories>

     <!-- END : Maven 방식 Liferay plugin 생성시 추가해야할 내역 --> 


   <!-- 이하 자동 생성되는 내역 일부임 --> 

    <dependencies>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>portal-client</artifactId>

         <version>${liferay.version}</version>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>portal-impl</artifactId>

         <version>${liferay.version}</version>

         <scope>provided</scope>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>portal-pacl</artifactId>

         <version>${liferay.version}</version>

         <scope>provided</scope>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>portal-service</artifactId>

         <version>${liferay.version}</version>

         <scope>provided</scope>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>portal-web</artifactId>

         <version>${liferay.version}</version>

         <type>war</type>

         <scope>provided</scope>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>util-bridges</artifactId>

         <version>${liferay.version}</version>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>util-java</artifactId>

         <version>${liferay.version}</version>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>util-slf4j</artifactId>

         <version>${liferay.version}</version>

       </dependency>

       <dependency>

         <groupId>com.liferay.portal</groupId>

         <artifactId>util-taglib</artifactId>

         <version>${liferay.version}</version>

       </dependency>

    </dependencies>

</project>



Maven 방식 Liferay Plugin 생성

  - Liferay는 플로그인 6가지 방식에 대한 Maven의 archetype을 제공하고 있다 

  - Archetype is Maven’s project templating toolkit

1) Eclipse Liferay IDE에서 "New Liferay Plugin Project" 선택

2) Build type을 Maven으로 선택

다음에서 MVCPortlet 선택


* CLI 명령 생성하기 

- 생성

mvn archetype:generate -DarchetypeCatalog=https://repository.liferay.com/nexus/content/groups/liferay-ce


- 배포 

mvn liferay:deploy


3) IDE로 생성된 pom.xml 에는 오류가 있다. 위의 pom.xml에서 추가해야 할 것들을 추가한다

  - properties : 배포 위치 및 버전 정보

  - repositories : Liferay remote repository 위치 (Nexus OSS로 local proxy server 사용하지 않을 경우)

  - pluginRepositores 


4) Eclipse에서 "mobiconsoft-sample"을 선택하고 컨텍스트메뉴 "Liferay" -> "Maven" -> "liferay:deploy" 를 선택하여 war파일을 만들어 본다 

[INFO] --- liferay-maven-plugin:6.2.1:deploy (default-cli) @ mobiconsoft-sample ---

[INFO] Deploying mobiconsoft-sample-1.0.0-SNAPSHOT.war to /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/deploy

     [null] Copying 1 file to /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/deploy

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------


deploy 디렉토리에 생성된 모습


5) Eclipse에서 해당 war를 tomcat 컨텍스트로 추가하고 시작하면 Liferay 화면에서 확인을 할 수 있다


Liferay v6.2 CE Server를 시작하면 Liferay 화면이 뜬다 


  - 그외 Maven 아키타입들 

liferay:portlet, liferay:hook, liferay:ext, liferay:theme, liferay:layout


그외 ...

Liferay ServiceBuilder portlets

Liferay webs

Liferay Ext

JSF Portlet Archetype

ICEFaces Portlet Archetype

PrimeFaces Portlet Archetype

Liferay Faces Alloy Portlet Archetype

Liferay Rich Faces Portlet Archetype

DBBuilder - The build-db goal lets you execute the DBBuilder to generate SQL files.

SassToCSSBuilder - The build-css goal precompiles SASS in your css; this goal has been added to theme archetype.



지금까지 환경설정을 하고 어떻게 Maven으로 빌드하는 과정을 보았다. 다음 블로깅에서는 플로그인 개발 실무를 보도록 한다. 



<참조>

  - Liferay Maven 빌드 환경 구성하기

  - 샘플 pom.xml 파일 

pom-userxxx-liferay.xml

posted by Peter Note

Liferay의 Service Builder 도구는 비즈니스 업무를 만들어내는 도구이다. 그리고 Plugins SDK에 대해서 알아보도록 한다. 



Service Builder 개념  

  - Service Builder 도구는 Model-Driven code generator이다. 

  - WEB-INF/service.xml 안에 entity로 정의되고 이를 참조하여 model, persistence, service 파일이 자동 생성되는 구조이다. 

  - 자동 생성된 내역은 여러다른 포틀릿에서도 공유할 수 있게 구성된다 

 > service.xml 에서 Entity를 추가하고 필드를 정의 할 수 있다


> 각 Entity에 대해서 Column을 정의한다 



> Event와 Location을 추가했는데 두 entity간의 relation을 Diagram에서 맺어 줄 수 있다


  - event-listing 프로젝트를 선택하고 컨텍스트메뉴를 보면 "Liferay" -> "Build Services" 를 선택하여 파일을 자동 생성한다

> WEB-INF/src , sql 밑으로 소스가 자동 생성되었다 



기존에 있는 프로젝트 Import하여 분석하기 

  - "New" -> "New Liferay Project form Existing Source" 로 기존의 플러그인을 Eclipse에 불러서 사용할 수 있다 

  - Plugins SDK 안에 존재하는 플러그인을 불러오고 싶다면 "Import..." -> "Liferay Projects from Plugins SDK"를 선택한다 

> Liferay에서 선택


> SDK를 선택하면 Plugins SDK에 포함된 플러그인을 자동 열거하여 준다. 원하는 것을 선택하고 Runtime을 선택한다 



Plugins SDK 이해하기

  - Plugin SDK 설치는 지난 블로그에서 다루었다. 이제 Plugins SDK의 환경설정은 build.properties에서 한다

> 환경설정 주의

 ~/development/liferay_portal/plugins-sdk-6.2/build.properties 는 절대로 변경하지 말자

 대시 build.<username>.properties 파일을 변경한다. 

  - SDK 디렉토리 구조

clients/ - client applications directory.

dist/ - archived plugins for distribution and deployment.

ext/ - Ext plugins directory. See Advanced Customization with Ext Plugins.

hooks/ - hook plugins directory. See Customizing and Extending Functionality with Hooks.

layouttpl/ - layout templates directory. See Creating Liferay Layout Templates.

lib/ - commonly referenced libraries.

misc/ - development configuration files. Example, a source code formatting specification file.

portlets/ - portlet plugins directory. See Developing Portlet Applications.

themes/ - themes plugins directory. See Creating Liferay Themes and Layout Templates.

tools/ - plugin templates and utilities.

webs/ - web plugins directory.

build.properties - default SDK properties.

build.<username>.properties - (optional) override SDK properties.

build.xml - contains targets to invoke in the SDK.

build-common.xml - contains common targets and properties referenced throughout the SDK.

build-common-plugin.xml - contains common targets and properties referenced by each plugin.

build-common-plugins.xml - contains common targets and properties referenced by each plugin type.



Ant 기반 빌드하기 

  - build.xml은 Ant 빌드 파일이다 

build-service - builds the service layer for a plugin, using Liferay Service Builder.

clean - cleans the residual files created by the invocations of the compilation, archiving, and deployment targets.

compile - compiles the plugin source code.

deploy - builds and deploys the plugin to your application server.

format-source - formats the source code per Liferay’s source code guidelines, informing you of violations that must be addressed. See the Development Sytle community wiki page for details.

format-javadoc - formats the Javadoc per Liferay’s Javadoc guidelines. See the Javadoc Guidelines community wiki page for details.

  - CLI (Command Line Interface) 기반으로 포틀릿 만들기 

> SDK/portlets/ 안에 보면 create.bat/create.sh 파일이 존재한다 

$ cd ~/development/liferay_portal/plugins-sdk-6.2/portlets

$ ./create.sh test-listing "test listing"


> 해당 디렉토리에서 배포하기 

$ ant deploy 


> 배포에 성공하게 되면 하기 디렉토리에 war파일 두개(event-listing-portlet, test-listing-portlet)이 생성된다 

  $PORTAL_HOME/deploy/*.war 파일은 tomcat에 배포된다 


다음 블로그에서는 Maven 기반 빌드를 보도록 하자. 



<참조>

  - Plugins SDK 이해

posted by Peter Note
2014. 4. 30. 17:28 Study Frameworks/Liferay Portal

Liferay 포털의 개발은 결국 기존 플러그인들의 확장 및 신규 개발 관건이다. 툴에 대한 이해를 하고 설치 사용해 보자 



Liferay IDE

  - Eclipse 플러그인으로 Eclipse Market에서 검색하여 설치가능 : "liferay ide"

  - Plugin SDK 또는 Maven과 Liferay runtime 환경과 결합하여 개발한 것을 배포 테스트 가능케 해준다  

  - Eclipse Indigo(3.7.x), Juno(4.2.x), Kepler(4.3.x) 에서 설치가능 

  - Plugin SDK와 Runtime 환경 설정 블로깅 참조 



Liferay Project 생성 

  - Eclipse의 Liferay IDE Perspective를 띄운다 

  - "New" -> "Liferay Plugin Project"를 선택한 후 하기와 같이 입력하고 "Service Builder"를 선택하고 생성한다 

    

  - 프로젝트 생성 내역

> docroot : 실제로 서비스하는 영역이다 

> view.jsp : 포틀릿으로 보여지는 웹 화면

> *xml : 포틀릿 설정 화면 


- liferay-display.xml 

  포틀릿 카테고리로 sample에 해당 포틀릿이 들어간다 

<display>

  <category name="category.sample">

    <portlet id="event-listing" />

  </category>

</display> 


  - 포틀릿 배포하기 

> 포틀릿을 생성하면 위치는 sdk/portlets 폴더밑으로 생성된다 


> Eclipse에서 Tomcat Server를 등록하여 기동한 상태라면 "And and New.." 컨텍스 메뉴를 선택하여 event-listing-porlet을 Add 하면 자동으로 Hot Deploy이 되어 반영된다 


- 포탈 화면에서 확인해 보자 

Sample 밑의 카테고리에 "Event Listing" 포틀릿이 존재하여 드래그앤드롭하여 원하는 위치에 놓을 수 있다


  - 프로젝트를 만든 후 기본 제공하는 항목을 제거하고 플러그인을 만들것이다. 기본 제공 설정내역을 삭제해 보자

1) WEB-INF/liferay-display.xml  에서 <portlet>..</portlet> 부분 제거 

2) WEB-INF/liferay-portlet.xml 에서  <portlet>..</portlet> 부분 제거 

3) WEB-INF/portlet.xml 에서  <portlet>..</portlet> 부분 제거  

4) view.jsp 파일 제거 


삭제까지 진행되었으면 이제 해당 프로젝트에 새로운 플러그인을 만들 준비가 되었다. 



Liferay Plugin 개발 

  - 프로젝트에는 여러개의 플러그인이 포함될 수 있다. 위에 만들어 놓은 "Event Listing" 프로젝트안에 여러개의 플러그인을 넣어본다 

  - Location Listing과 Event Listing 포틀릿 플러그인을 만들어 보자 

  - Location Listing Portlet 생성

1) 프로젝트명을 선택하고 context menu -> New -> "Liferay Portlet"을 선택하고 LocationListing 포틀릿을 입력


2) Next로 이동하여 포틀릿 정보를 입력


3) 카테고리 정보를 입력한다 "MobiconSoft"


  - event-listing 포틀릿을 생성한다 

> location-listing 과 같은 방식으로 생성

  MVCPortlet을 상속 받으면서 같은 java package에 속한다 


> 최종 생성된 Eclipse Project 모습

   + com.mobiconsoft.event의 클래스들은 MVCPortlet을 상속받아서 자동 생성된다 

   + liferay-display.xml, liferay-portlet.xml, portlet.xml 안에 위저드로 설정한 내용이 반영된다 


  - 프로젝트의 컨텍스트가 이미 Server에 반영되어서 위저드로 생성시에 Hot Deploy가 된다. 다음으로 "Mobiconsoft" 카테고리에 EventListing과 LocationListing이 반영되었는지 확인한다. 




다음 블로그에서는 "Service Builder" 도구를 사용하여 어떻게 Model, Persistence, Service Layer를 만들 수 있는지 살펴보도록 한다 


posted by Peter Note
2014. 4. 30. 17:20 Study Frameworks/Liferay Portal

기본 설치할 때 기본데이터를 체크하였다면 "Joe Bloggs" 가 나오고 몇가지 직관적인 메뉴를 통해서 포털의 화면을 구성할 수 있다. 가장 기본적인 것이라서 개발자 입장에서 기존에 제공하는 것의 변경 및 필요한 기능의 개발은 어떻게 하는지 Liferay Developer Guide (v6.2 기준) 를 통해 보도록 하자. 



가이드 내역 

  - Developing Application for Liferay

  - Extending and Customizing Liferay

  - 개발툴 선택하기 



Liferay를 위해 어플리케이션 개발 

  - liferay에서 어플리케이션을 연동하는 두가지 방법

    + Portlets 

    + OpenSocial gadget : 

  - Portlets

    + 자바로 쓰여진 어플리케이션 모듈로 포틀릿 컨테이너안에서 구동됨 

    + liferay 서버에 hot deploy가 가능하여 서버 재기동이 필요없음

    + 하나의 플러그인에 여러개의 포틀릿을 두어서 화면을 구성할 수 있다 

    + Liferay에서 정의한 프레임워크 : MVC 포틀릿, Alloy 포틀릿으로 구현된다 

  - OpenSocial gadget

    + 여러 언어로 개발가능

    + remote / local gadget 으로 구분

  - AlloyUI

    + v6 부터 클라이언트에서 사용

    + YUI3 이용

    + 다른 자바스크립 라이브러리 추가 가능



Liferay 기능 확장 및 커스터마이징

  - 여러 프러그인을 하나로 묶은 WAR로 배포하여 사용할 수 있다

  - Theme 사용자 정의 

    + Look and Feel에 대한 제어가 가능

    + Velocity 또는 FreeMarker와 CSS를 혼용하여 사용

    + 업무로직과 별개의 RWD(Responsive Web Desgin)이 가능

    + AlloyUI를 사용

  - Layout Templates

    + theme과 유사하지만 look and feel이 아니라 화면 페이지에 포틀릿 배치 정의에 대한 것이다 

    + Velocity를 사용하여 hot deploy 된다 

  - Hook Plugin

    + Liferay의 core function에 대하여 hooking 처리 할 수 있는 기능

    + 로그인, 세션관리, 코어 서비스들

  - Ext Plugin

    + Liferay core를 큰규모의 변경을 가하고자 할 때 사용

    + 친숙하고 정말 필요할 때만 사용. 서버 재기동 필요

 


개발 툴 선택 

  - CLI 방식 : ANT + Plugin SDK 

  - GUI 방식 : Eclipse 기반 Liferay IDE + Plugin SDK

  - Maven을 사용할 수 있다 

 

다음 단락에서는 3가지를 통해 개발하는 방법을 알아본다 

 > Developing Apps with Eclipse Liferay IDE

 > Leveraging the Plugins SDK

 > Developing Plugins Using Maven



<참조>

  - Liferay Developer Guide

  - Ext Plugin 개발 가이드

posted by Peter Note
2014. 4. 30. 12:33 Study Frameworks/Liferay Portal

Liferay CE v6.2 GA2 버전을 다운로드 받고 설치하는 과정과 Eclispse ID와 Liferay Plugins SDK도 설치해 보자. 



Liferay 다운로드 

  - JDK : v7.* 버전을 권장하고 없다면 V6.* 도 가능하다

  - 다운로드 파일 :  the liferay + tomcat bundle

  - 다운로드후 적당한 위치에 zip 압축을 푼다. (linux 기준)

// 압축을 풀었을 때 폴더명칭을 portal-6.2-ce-ga2 로 변경하였다 (사용자 정의함)

~/development/liferay_portal/portal-6.2-ce-ga2


  - data : lucene 데이터 파일

  - deploy : 플러그인 배포 .war 파일 놓는곳

  - tomact : 톰캣 위치 


// portal-ide.properties

auto.deploy.tomcat.conf.dir=/Users/xxxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/conf/Catalina/localhost


// portal-setup-wizard.properties 및 liferay와 mysql 연결 정보 (username : liferay, database : liferaydb)

liferay.home=/Users/xxxx/development/liferay_portal/portal-6.2-ce-ga2
admin.email.from.address=test@liferay.com
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.username=liferay
jdbc.default.url=jdbc:mysql://localhost:3306/liferaydb?autoReconnect=true



Liferay Tomcat 설정

  - tomcat 위치

~/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42

  - 디폴트 웹 어플리케이션 위치

~/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT

  - 웹 어플리케이션 위치를 옮길 경우 tomcat의 환경설정

// 변경위치를 www 로 할 경우

~/development/liferay_portal/portal-6.2-ce-ga2/www


// ~/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/conf/server.xml 수정

<Host appBase="/Users/xxxx/development/liferay_portal/www" autoDeploy="true" name="localhost" unpackWARs="true">

    <Context docBase="ROOT" path="" reloadable="true"/>

    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log." suffix=".txt"/>

</Host>

  - tomcat 시작

~/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/bin/startup.sh


몇분을 기다리면 브라우져가 자동 시작하여 http://localhost:8080/ 을 호출하고 초기 셋업페이지가 나온다. 

이때 mysql 연결로 바꾸자 (portal-setup-wizard.properties 참조)



Liferay Plugins SDK 설치 

  - 플러그인 소스 다운로드받자 : 나중에 eclipse ide에서 debugging 하거나 수정할 때 사용

$ cd  ~/development/liferay_portal/

$ mkdir sources && cd sources


// 플러그인 소스 다운로드 

$ git clone https://github.com/liferay/liferay-plugins.git

  - 다운로드 Liferay CE v6.2 ga2 Plugins SDK   

// ~/development/liferay_portal/ 위치에 sdk 압축을 푼다 

~/development/liferay_portal/plugins-sdk-6.2


// 최종 디렉토리 구조

  - ~/development/liferay_portal/plugins-sdk-6.2/build.<사용자명>.properties 내용 수정

app.server.tomcat.lib.global.dir = /Users/nulpulum/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/lib/ext

#app.server.tomcat.deploy.dir = /Users/nulpulum/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps

app.server.tomcat.deploy.dir = /Users/nulpulum/development/liferay_portal/www

app.server.parent.dir = /Users/nulpulum/development/liferay_portal/portal-6.2-ce-ga2

app.server.tomcat.dir = /Users/nulpulum/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42

app.server.type = tomcat

#app.server.tomcat.portal.dir = /Users/nulpulum/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT

app.server.tomcat.portal.dir = /Users/nulpulum/development/liferay_portal/www/ROOT



Eclipse IDE 설치

  - Eclipse Juno 버전 이상에서 "Eclipse Marketplace..." 에 들어가서 "liferay" 검색하면 "liferay IDE" 이클립스 플러그인이 나오면 Install

    


  - Liferay perpective를 띄웠을 때 화면 

    툴바에서 파란색 아이콘 3가지가 Liferay 기능이다. 

    


  - Liferay의 tomcat 서버를 등록한다 

    


  - 다음으로 Plugins SDK를 등록한다 

    



*** Liferay IDE를 통한 개발 (주의사항)

  - 기본 {TOMCAT_HOME}/webapps/ROOT 를 사용한다. 

  - 기존 ~/liferay_portal/www 에서 다시 원위치로 설정한다.

   (단, ant CLI 방식은 괜찮다)

  - 사용자가 xxx 일 경우

1) {TOMCAT_HOME}/conf.xml 에서 위치 변경

<Host appBase="/Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps" autoDeploy="true" name="localhost" unpackWARs="true">


2) {PLUGIN_SDK}/build.<username>.properties

app.server.tomcat.lib.global.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/lib/ext

app.server.tomcat.deploy.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps

app.server.parent.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2

app.server.tomcat.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42

app.server.type = tomcat

app.server.tomcat.portal.dir = /Users/xxx/development/liferay_portal/portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT



<참조>

  - Liferay 환경 구성 - 한글

  - Liferay 초기 환경 설정

  - Liferay 개발환경 구성

  - Liferay tomcat 시작하기

  - A to Z Liferay 개발환경 설정하기 (필독)

posted by Peter Note
2014. 4. 30. 12:32 Study Frameworks/Liferay Portal

Liferay는 Enterprise Portal을 만들기 위한 솔루션이다. 커뮤니티 버전(CE)과 엔터프라이즈 버전(EE)이 존재하고, 오픈소스버전은 CE버전을 사용하면 된다. Liferay를 들어가기전에 Portal에 대한 올바른 이해와 설치 및 개발환경 설정 그리고 플로그인 개발을 보고 요즘 가장 핫한 Angular.js와 Node.js를 접목하여 클라이언트단 포틀랫(Portlet) 개발생산성 향상과 Node.js의 Socket.io를 이용한 실시간(Realtime) 구현에 대해서도 연재를 통하여 알아보자.





엔터프라이즈 포탈(EP)이란 무엇인가?

기업이 전술상 또는 전략상으로 필요로 하는 업무용 어플리케이션을 적은 비용으로 빠르게 구현하여 비즈니스 유저들에게 제공함으로써 IT는 업무 어플리케이션 구축 비용 및 시간을 절약하고 비즈니스 유저들은 자신의 업무에 필요한 어플리케이션을 신속히 제공받음으로써 사업의 기회비용을 줄일 수 있도록 지원하는 시스템. -인용-


  - 보다 자세한 이해는 엔터프라이즈 포탈이란 무엇인가? 연재글을 참조한다 

  - EP를 위하여 통합적으로 운영되어야 할 부분

    + 통합 검색 : 문서 검색 뿐만아니라 서비스/애플리케이션 단위의 검색도 가능

    + 콘텐츠 관리 : 디지털 컨텐츠/미디어의 Publish/Delivery 가능

    + 협업 기능 : SNS, 메신저, 게시판과 같은 온라인 소셜활동 가능 

    + 기타 : 다양한 어플리케이션/시스템 통합 프레임워크 제공 (SSO, KMS, BPM, ESB, SNS 등의 연동)



Liferay Portal이 제공하는 기능

  - 메일 : SMS Text Messenger

  - 블로그 : Blog, Asset Publisher (파일공유), RSS, Twitter

  - 위키 : Wiki

  - 문서 관리 : Document Library 문서공유 

  - 일정 관리 : Calendar

  - 게시판 : Message Boards (게시판) 

  - 투표 : Polls

  - 이미지 관리 : Image Gallery

  - 기사 : Journal, News

  - 공지 : Announcements, Alerts



Liferay 기술 스택

  - 서버 : Java(JDK v7 권장), Spring, Hibernate, EJB(optional)

  - 클라이언트 : AlloyUI (YUI3 + Twitter Bootstrap)



Liferay 버전 및 파일 다운로드

  - CE v6.2 GA2 (2014.4월 현재)

  - Portal 과 Plugins 파일로 구성됨

    + Portal은 메인 어플리케이션

    + Plugin은 확장 모듈이며 6가지(theme, portlet, EXT, layout template, hooks, web modules) 타입이 존재

  - GitHub : https://github.com/liferay/



다음글에서는 Liferay를 설치하고 설정하는 방법에 대해 알아보자 



참조

  - 엔터프라이즈 포탈이란 무엇인가?

  - Liferay GitHub Repository

posted by Peter Note
prev 1 next