Open Source

Open Source

SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.2) “Nuxt Directory Structure”

หลังจากที่ได้ทำการ create nuxt project เป็นที่เรียบร้อยแล้ว (ถ้ายังไม่รู้ว่า setup Nuxt อย่างไรเข้าไปติดตามได้ที่บทความนี้ ” SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project” “ ) สังเกตุว่าภายใต้ project จะเจอ folders และ files ต่าง ๆ  แต่ละส่วนแบ่งการทำงานและมีหน้าที่ต่างกัน

  • assets
    • คือ folder เก็บไฟล์ resources อย่างเช่น image ,javascript ,stylesheet หรือเป็นไฟล์อื่น ๆ ที่ต้องการทำเป็น static resource
    • การเรียกใช้งาน <img src=“~/assets/image.png”>
    • <template>
        <img src="~/assets/image.png">
      </template>
  • components
    • คือ folder เก็บ File components (.vue)
  • layouts
    • ใช้เก็บไฟล์ layout ของ project ภายในจะมีไฟล์ default.vue เป็น template layout  สามารถกำหนด error page กรณีที่มี error status ที่ไม่ใช้ 200 และยังสามารถสร้าง custom layout ในแบบที่เราต้องการได้อีกด้วย
    • <template>
        <div>
          <nuxt/>
        </div>
      </template>
  • middleware
    • เก็บไฟล์ที่เป็น intercepter ของ project ตัวอย่างไฟล์ authentication กรณีทำระบบ login (auth.js) ก็จะสร้างเก็บไว้ที่ folder นี้
    • export default function (context) {
        context.userAgent = context.isServer ? context.req.headers['user-agent'] : navigator.userAgent
      }
  • pages
    • เก็บไฟล์ views (route mapping) ของ project
    •  
    • <template>
        <div class="container">
          <h1 v-if="error.statusCode === 404">Page not found</h1>
          <h1 v-else>An error occurred</h1>
          <nuxt-link to="/">Home page</nuxt-link>
        </div>
      </template>
      
      <script>
      export default {
        props: ['error'],
        layout: 'blog' // you can set a custom layout for the error page
      }
      </script>
  •  plugins
    • เก็บไฟล์ config plugin เพื่อเรียกใช้ plugin ร่วมกับ project เรา เช่น axios เป็นต้น
  • static
    • เก็บไฟล์ static content ที่สามารถเรียกเข้าถึงได้ผ่าน route url ของ project ได้
    • <!-- Static image from static directory -->
      <img src="/my-image.png"/>
      
      <!-- webpacked image from assets directory -->
      <img src="~/assets/my-image-2.png"/>
  • store
    • เก็บไฟล์ data store Vuex Store store เก็บ data ทำ passing data ภายใน project โดยจะมี main file index.js และเรียก import  modules ต่าง ๆ ได้
    • import Vuex from 'vuex'
      
      const createStore = () => {
        return new Vuex.Store({
          state: () => ({
            counter: 0
          }),
          mutations: {
            increment (state) {
              state.counter++
            }
          }
        })
      }
      
      export default createStore
  • nuxt.config.js
    • file config หลักของ Project ใช้ config เรื่อง build ,css ,js ,plugin ,dev ,env ,generate ,head ฯลฯ เป็นต้น
    • const pkg = require('./package')
      
      module.exports = {
        mode: 'universal',
      
        /*
        ** Headers of the page
        */
        head: {
          title: pkg.name,
          meta: [
            { charset: 'utf-8' },
            { name: 'viewport', content: 'width=device-width, initial-scale=1' },
            { hid: 'description', name: 'description', content: pkg.description }
          ],
          link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
        },
      
        /*
        ** Customize the progress-bar color
        */
        loading: { color: '#fff' },
      
        /*
        ** Global CSS
        */
        css: [],
      
        /*
        ** Plugins to load before mounting the App
        */
        plugins: [],
      
        /*
        ** Nuxt.js modules
        */
        modules: [
          // Doc: https://github.com/nuxt-community/axios-module#usage
          '@nuxtjs/axios',
          // Doc:https://github.com/nuxt-community/modules/tree/master/packages/bulma
          '@nuxtjs/bulma'
        ],
        /*
        ** Axios module configuration
        */
        axios: {
          // See https://github.com/nuxt-community/axios-module#options
        },
      
        /*
        ** Build configuration
        */
        build: {
          postcss: {
            preset: {
              features: {
                customProperties: false
              }
            }
          }
          /*
          ** You can extend webpack config here
          */
          // extend(config, ctx) {
          //   // Run ESLint on save
          //   if (ctx.isDev && ctx.isClient) {
          //     config.module.rules.push({
          //       enforce: 'pre',
          //       test: /\.(js|vue)$/,
          //       loader: 'eslint-loader',
          //       exclude: /(node_modules)/
          //     })
          //   }
          // }
        }
      }
      
  • package.json
    • lib dependencies ของ Nuxt Project
    • {
        "name": "poolsawat",
        "version": "1.0.0",
        "description": "My shining Nuxt.js project",
        "author": "pool13433",
        "private": true,
        "scripts": {
          "dev": "nuxt",
          "build": "nuxt build",
          "start": "nuxt start",
          "generate": "nuxt generate",
          "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
          "precommit": "npm run lint"
        },
        "dependencies": {
          "cross-env": "^5.2.0",
          "nuxt": "^2.0.0",
          "@nuxtjs/bulma": "^1.2.0",
          "@nuxtjs/axios": "^5.0.0"
        },
        "devDependencies": {
          "nodemon": "^1.11.0",
          "babel-eslint": "^8.2.1",
          "eslint": "^5.0.1",
          "eslint-loader": "^2.0.0",
          "eslint-plugin-vue": "^4.0.0",
          "eslint-config-prettier": "^3.1.0",
          "eslint-plugin-prettier": "2.6.2",
          "prettier": "1.14.3"
        }
      }

บทความนี้เป็นเพียงรายละเอียดคร่าว ๆ ของแต่ละส่วนของ Project Nuxt ศึกษาเพิ่มเติมได้จากลิ้งนี้ Nuxt Doc

SPA สร้าง Web Site Universal ด้วย Nuxt.js (EP.1) “Setup Nuxt Project”

พวกเรามาถึงยุคที่ต้องมีเว็บไซต์ที่เข้าใช้งานแล้วรู้สึกว่ารวดเร็วทันใจเพราะเมื่อมีอะไรมาขัดจังหวะคนใช้งานจะรู้สึกไม่อยากรอ หรือ อาจจะเลิกสนใจ website ของคุณไปเลย แล้วถ้าอยากจะสร้าง website ลักษณะที่ตอบโจทย์ที่กล่าวมาละ เครื่องมืออะไรจะตอบโจทย์นี้ได้
SPA หรือ single page application คือการที่มี application ที่มีการทำงานในหน้าเดียวกล่าวคือจะไม่มีการ refresh หน้า ถ้าในสมัยเก่าก่อนวิธีการที่นิยมที่สุดก็คงเป็นการใช้ AJAX ในการ รับ-ส่งค่าข้อมูลระหว่างกันโดยเมื่อมีข้อมูลหน้าเว็บเปลี่ยนก็สั่งให้ DOM เปลี่ยนแปลงโดยใช้งานร่วมกับ jQuery พระเอกตลอดการของเรานั้นเอง ฟังดูยากสำหรับเมื่อก่อน
SPA ก็มี framework ในการพัฒนา 3 ค่ายดัง ๆ อย่าง React(Facebook) ,Angular(Google), Vue(ทีมพัฒนาอิสระ) ซึ่ง 3 framework ก็ล้วนเป็น open source แล้วทั้งสิน ถ้าเมื่อจะเลือกเครื่องมืออะไรสักอย่างก็ต้องเข้าไปใช้งาน หรือต้องได้ลองเล่น และเมื่อเกิดปัญหา หรือรู้สึกว่าติดขัดก็จะเลิกและเปลี่ยนไปใช้งานตัวถัดไป และเมื่อถ้าได้ลองจะครบทั้ง 3 framework แล้วตัวเราเองก็จะเลือกได้เองว่าจะเลือก framework ตัวใด
Vue คือ framework ระดับแรก ๆ ที่นักพัฒนามือใหม่เลือกใช้งาน ด้วยเหตุผลเรื่องความง่ายในการติดตั้งไม่จำเป็นต้องติดตั้ง build tool ก็สามารถเริ่มต้นใช้งานได้
Nuxt.js เป็น framework ที่พัฒนาต่อยอดจาก VueJS เพื่อช่วยแก้ปัญหาสำหรับ website ที่ต้องการทำเรื่อง SEO(Search Engine Optimization) เพื่อในพบการค้นหาใน google ได้ง่ายยิ่งขึ้น
เริ่มต้นใช้งาน
เริ่มแรกติดตั้ง Nuxt.js

  1. ติดตั้ง npx (ไม่ขอกล่าวถึงสำหรับขั้นตอนการติดตั้งส่วนนี้) หรือจะใช้ yarn ก็ได้ตามความถนัด
  2. npx: create nuxt project
    npx create-nuxt-app <project-name>
  3. yarn: create nuxt project
    yarn create nuxt-app <project-name>
  4. ใส่ชื่อ project? Project name (poolsawat)
  5. ใส่คำอธิบาย? Project description (My shining Nuxt.js project)
  6. เลือก integrate ร่วมกับ framework อื่น เลือก None (Nuxt default server)
    > none
    express
    koa
    adonis
    hapi
    feathers
    micro
  7. เลือก ui framework
    > none
    bootstrap
    vuetify
    bulma
    tailwind
    element-ui
    buefy
  8. Single Page App เลือก mode website SEO เลือก Universal
    > Universal
    SPA
  9. website ที่มีการต่อเรียก api ก็ให้ติดตั้ง axios ด้วย
    no
    > yes
  10. เพิ่มการตรวจสอบ source code ด้วย ESLint
    no
    > yes
  11. เพิ่มให้มีการจัด format code หลัง save
    no
    > yes
  12. รอ…
  13. ทำตาม stepcd poolsawat
    npm run dev

ติดตั้งเรียบร้อยลอง start application ดู

d:\Blogger\nuxt\poolsawat>npm run dev

> [email protected] dev d:\Blogger\nuxt\poolsawat
> nuxt

INFO Building project

√ success Builder initialized
√ success Nuxt files generated

READY Listening on http://localhost:3000

เสร็จสิ้นเป็นที่เรียบร้อย ตอนหน้าจะพาไปแนะนำโครงสร้างภายใน Nuxt.js กันว่าแต่ละส่วนใช้ทำงานอะไรบ้าง และถ้าจะสร้าง page ใหม่จะต้องทำอย่างไร

สร้าง Project JSF Primeface ด้วย Maven พร้อมกับสอนทำระบบ Template Layout

Java Server Faces (JSF) เป็นเว็บแอ็พพลิเคชันที่ใช้ Java ซึ่งมีจุดมุ่งหมายเพื่อลดความซับซ้อนในการพัฒนาอินเทอร์เฟซสำหรับผู้ใช้บนเว็บ JavaServer Faces เป็นเทคโนโลยีการแสดงผลแบบมาตรฐานซึ่งได้รับการประกาศไว้ในข้อกำหนดผ่านกระบวนการ Java Community Process

JSF ถูกนำไปพัฒนาต่อยอดความสามารถโดยบริษัทขนาดใหญ่ หลายบริษัท

  • Apache MyFaces – The Apache Foundation JSF implementation with Ajax components
  • Backbase Enterprise Ajax – JSF Edition – Ajax framework
  • BootsFaces Open source JSF Framework based on Bootstrap
  • IBM Notes – XPages
  • ICEfaces – open-source, Java JSF extension framework and rich components, Ajax without JavaScript
  • JBoss RichFaces (derived from and replaces Ajax4jsf) – Ajax-enabled JSF components for layout, file upload,
  • forms, inputs and many other features. It reached its end-of-life in June 2016.
  • OmniFaces – open-source JSF utility library
  • Open Faces – Ajax framework with JSF components
  • Oracle ADF Faces Rich Client – Oracle Application Development Framework
  • PrimeFaces – Ajax framework with JSF components
  • Sun Java BluePrints AJAX components
  • ZK – Ajax framework with JSF components





Primeface เป็น Framework ที่ไม่หยุดพัฒนาและมี UI Component มากมายและสวยงาม

ด้วยความสม่ำเสมอในการพัฒนาและมีการปรับปรุง framework อยู่ตลอดเวลา ออกผลิตภัณฑ์ตัวใหม่ออกมา เช่น PrimeNG ,PrimeReact ,PrimeUI เป็นต้น ทำให้เลือก Primeface เป็นตัวเลือกในการพัฒนา Project Webapp นี้

มาเริ่มสร้าง Project กัน

  1. Build Maven Project (maven-archetype-webapp) ขึ้นมา
  2. เพิ่ม Dependencies
  3. สร้างไฟล์ webapp/WEB-INF/faces-config.xml
  4. เพิ่ม Configure Faces Servlet in webapp/WEB-INF/web.xml
  5. สร้างไฟล์ webapp/templates/layout.xhtml
  6. สร้างไฟล์ webapp/templates/themeMenu.xhtml เพื่อทำเป็น navigator Menu ลิ้งไปที่หน้าอื่น ๆ
  7. สร้าง page webapp/pages/page1.xhtml ,page2.xhtml ,page3.xhtml ,page4.xhtml

    1. จุดที่สำคัญคือเพิ่ม template=”../templates/layout.xhtml” เข้าไปเพิ่มที่ ui:composition ทำให้อ้างถึง template layout ได้
  8. การเปลี่ยน Primeface Theme ของ website

  9. ตัวอย่างหน้า web site

DynamicReport Engine สร้างครั้งเดียวออก Report ได้ทุกแบบ (Hybrid Report)

โปรเจคเกือบจะทุกระบบที่พัฒนาขึ้นมาจำเป็นต้องมองหาระบบออกรายงาน เพื่อดูรูปแบบมิติของข้อมูลในมุมมองต่าง ๆ และรูปแบบชนิดของไฟล์หลากหลายชนิด เช่น PDF , XLS ,HTML , DOCX ,PPTX , CSV , TEXT , XML เป็นต้น ถ้าความต้องการของลูกค้าอยากจะได้ทุกชนิดละคงต้องประเมินเวลาไปอย่างน้อย 1 เดือนสำหรับการที่ทำ Report ให้ออกมาตามประเภทไฟล์ข้างต้นนี้ทั้งหมด แต่ลูกค้าที่น่ารักใจร้อนอยากจะได้เร็ว ๆ ให้เวลาช้าที่สุด 1 สัปดาห์ได้ไหม บทความนี้ช่วยคุณแก้ปัญหานี้ได้แน่นอน

สำหรับบทความนี้ก็เหมาะสำหรับนักพัฒนาที่มีพื้นฐาน Java สักหน่อย เริ่มกันเลย

    1. สร้าง Maven Project ขึ้นมา (จะเป็น Java Web หรือ Java Application ก็แล้วแต่ลักษณะงานของคุณ)
    2. เพิ่ม .pom ตามนี้
      <?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.poolsawat</groupId>
          <artifactId>MyDynamicReport</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>jar</packaging>
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <maven.compiler.source>1.7</maven.compiler.source>
              <maven.compiler.target>1.7</maven.compiler.target>
              
              <slf4j.version>1.7.7</slf4j.version>
              
              <jasperreports.version>6.3.1</jasperreports.version>
              <dynamicreport.version>5.0.0</dynamicreport.version>
              <groovy.version>1.8.6</groovy.version>
              <poi.version>3.10.1</poi.version>
              
          </properties>
          <dependencies>        
      
              <dependency>
                  <groupId>org.codehaus.groovy</groupId>
                  <artifactId>groovy-all</artifactId>
                  <version>${groovy.version}</version>
              </dependency>        
              <dependency>
                  <groupId>net.sourceforge.dynamicreports</groupId>
                  <artifactId>dynamicreports-core</artifactId>
                  <version>${dynamicreport.version}</version>
              </dependency>        
              <dependency>
                  <groupId>net.sf.jasperreports</groupId>
                  <artifactId>jasperreports</artifactId>
                  <version>${jasperreports.version}</version>
                  <exclusions>
                      <exclusion>
                          <groupId>commons-logging</groupId>
                          <artifactId>commons-logging</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
              
              <!--Poi-->
              <dependency>
                  <groupId>org.apache.poi</groupId>
                  <artifactId>poi</artifactId>
                  <version>${poi.version}</version>
              </dependency>
              
              
              <!-- Logging -->
              <dependency>
                  <groupId>org.slf4j</groupId>
                  <artifactId>slf4j-api</artifactId>
                  <version>${slf4j.version}</version>
                  <scope>compile</scope>
              </dependency>
              <dependency>
                  <groupId>org.slf4j</groupId>
                  <artifactId>slf4j-log4j12</artifactId>
                  <version>${slf4j.version}</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
              <dependency>
                  <groupId>commons-logging</groupId>
                  <artifactId>commons-logging</artifactId>
                  <version>1.2</version>
              </dependency>
      
          </dependencies>
      </project>




  1. สร้าง GenarateReport.java
    package com.poolsawat.dynamic;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.util.Date;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import static net.sf.dynamicreports.report.builder.DynamicReports.*;
    import net.sf.dynamicreports.report.builder.style.StyleBuilder;
    import net.sf.dynamicreports.report.constant.HorizontalTextAlignment;
    import net.sf.dynamicreports.report.datasource.DRDataSource;
    import net.sf.dynamicreports.report.exception.DRException;
    import net.sf.jasperreports.engine.JRDataSource;
    
    /**
     *
     * @author poola410
     */
    public class GenarateReport {
    
        public GenarateReport() {
            build();
        }
    
        private void build() {
            try {
                report()//create new report design
                        //.setDefaultFont(stl.font().setFontName("TH SarabunPSK").setFontSize(16))                    
                        .columns(
                                col.column("PostId", "id", type.integerType())
                                        .setStyle(getTableStyle())
                                        .setTitleStyle(getTableStyle()),
                                col.column("PostTitle", "title", type.stringType())
                                        .setStyle(getTableStyle())
                                        .setTitleStyle(getTableStyle()),
                                col.column("PostAuthor", "author", type.stringType())
                                        .setStyle(getTableStyle())
                                        .setTitleStyle(getTableStyle()),
                                col.column("PostPublicDate", "public_date", type.dateType())
                                        .setStyle(getTableStyle())
                                        .setTitleStyle(getTableStyle()))
                        .title(cmp.text("PoolsawatBlogs"))//shows report title
                        .pageFooter(cmp.pageXofY())//shows number of page at page footer
                        .setDataSource(createDataSource())//set datasource
                        //.show();//create and show report
                        .toPdf(new FileOutputStream(new File("./src/main/resources/output/poolsawat.pdf")))
                        .toXls(new FileOutputStream(new File("./src/main/resources/output/poolsawat.xls")))
                        .toCsv(new FileOutputStream(new File("./src/main/resources/output/poolsawat.csv")))
                        .toXlsx(new FileOutputStream(new File("./src/main/resources/output/poolsawat.xlsx")))
                        .toHtml(new FileOutputStream(new File("./src/main/resources/output/poolsawat.html")))
                        .toPptx(new FileOutputStream(new File("./src/main/resources/output/poolsawat.pptx")))
                        .toText(new FileOutputStream(new File("./src/main/resources/output/poolsawat.text")))
                        .toXml(new FileOutputStream(new File("./src/main/resources/output/poolsawat.xml")));
                        
            } catch (DRException e) {
                e.printStackTrace();
            } catch (FileNotFoundException ex) {
                Logger.getLogger(GenarateReport.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        private StyleBuilder getTableStyle(){
            return stl.style().setBorder(stl.border(stl.pen1Point()))
                    .setHorizontalTextAlignment(HorizontalTextAlignment.LEFT);
        }
    
        private JRDataSource createDataSource() {
            DRDataSource dataSource = new DRDataSource("id", "title","author","public_date");
            dataSource.add(1215,"Quartz Scheduler มันคืออะไร การใช้งานเบื้องต้น", "admin", new Date());
            dataSource.add(1150,"Gson Open Source Library สำหรับจัดการ JSON Formatter", "admin", new Date());
            dataSource.add(1132,"สร้าง Spring MVC 4 ร่วมกับ Apache Tiles 3", "admin", new Date());
            dataSource.add(1099,"[ES6] Promise คืออะไร", "admin", new Date());
            dataSource.add(1072,"ประสบการณ์ทำเว็บไซต์ให้ปลอดภัยด้วย HTTPS ไม่ยากอย่างที่คิด", "admin", new Date());
            dataSource.add(1025,"เล่าประสบการณ์แข่งขัน Hackathon ครั้งแรกให้ชีวิต", "admin", new Date());
            dataSource.add(1002,"สรุปสิ่งที่ได้รับจากงาน Cloud Functions for Firebase and Next Generation of Web", "admin", new Date());
            return dataSource;
        }
    
        public static void main(String[] args) {
            new GenarateReport();
        }
    }
    
  2. สั่ง RUN File GenarateReport.java
  3. ดู output ตาม Path

 DynamicReport สามารถทำ Report ที่แสดงในรูปแบบของกราฟได้ด้วย ศึกษาเพิ่มเติมจากลิ้งนี้

Github source ZIP , Github Source Repository

Gson Open Source Library สำหรับจัดการ JSON Formatter

“JSON” ไม่ใช่เรื่องใหม่อะไร เพราะปัจจุบันมีการใช้งานกันอย่างแพร่หลาย สำหรับเอาไว้ใช้จัดการข้อมูลรับส่งระหว่าง frontend และ backend เพราะด้วยความง่ายและดูเป็นมาตฐาน มีรูปแบบที่ตายตัว ที่ใคร ๆ ก็สามารถเข้าใจได้เพราะเป็นการเก็บข้อมูลแบบ Key และ value

Java Library ที่ใช้สำหรับจัดการ JSON Data ก็มีมากมายให้ได้เลือกใช้งาน เช่น Google-Gson Library ,Flexjson ,Json-io ,Genson ,JSONiJ ,Jackson ,JSON-lib เป็นต้น ผมเองเป็นคนนึงที่นิยมใช้งาน Library ที่เป็น Open Source และต้องมีกลุ่ม Community ที่ใหญ่ และ Gson เองก็ได้รับความนิยมมาก เพราะด้วยความง่ายในการใช้งาน

การเริ่มใช้งาน Gson

เพิ่ม dependency

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.6.2</version>
</dependency>




การใช้งานเบื้องต้นของ Gson จะมีด้วยกัน 2 รูปแบบ ด้วยกัน คือ Serialization ,Deserialization

Serialization การแปลงข้อมูลที่อยู่ในรูปแบบ Object ไปเป็น Json String Format

Gson gson = new Gson();
gson.toJson(1);            // ==> 1
gson.toJson("abcd");       // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values);       // ==> [1]

Deserialization  การแปลงข้อมูลในรูปแบบ Json String Format ไปเป็น Object

int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean false = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"abc\"", String.class);
String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);

ตัวอย่างการใช้งานง่าย ๆ

สร้าง POJO Class

public class EasyObject {
    private String valueString;
    private int valueInteger;
    private Date valueDate;
    private boolean valueBoolean;
    // getter , setter

    @[email protected] public String toString() { return "EasyObject [valueString=" + valueString + ", valueInteger=" + valueInteger + ", valueDate=" + valueDate + ", valueBoolean=" + valueBoolean + "]"; }
}

ตัวอย่าง Method Serialization

private void exampleSerialization(){
  EasyObject easy = new EasyObject();
  easy.setValueBoolean(true);
  easy.setValueDate(new Date());
  easy.setValueInteger(999);
  easy.setValueString("poolsawat.com");
  //Serialization 
  System.out.println("serialization :: "+new Gson().toJson(easy));  
}
/*
serialization :: {"valueString":"poolsawat.com","valueInteger":999,"valueDate":"Oct 4, 2017 9:35:34 PM","valueBoolean":true} 
*/

ตัวอย่าง Method Deserialization

private void exampleDeserialization(){
  String json = "{\"valueString\":\"poolsawat.com\",\"valueInteger\":999,\"valueDate\":\"Oct 4, 2017 9:30:08 PM\",\"valueBoolean\":true}";
  EasyObject easy = new Gson().fromJson(json, EasyObject.class);
  System.out.println("deserialization :: "+easy.toString());  
}
/* 
deserialization :: EasyObject [valueString=poolsawat.com, valueInteger=999, valueDate=Wed Oct 04 21:30:08 ICT 2017, valueBoolean=true] 
*/

เมื่อใช้งาน Gson ไปสักระยะก็จะพบปัญหา หรือ สิ่งที่อยากปรับแต่งกับข้อมูลผลลัพธ์ให้เป็นไปตามความต้องการ Gson เองก็มี  GsonBuilder Class สำหรับให้เอาไว้ Custom Serialization and Deserialization

ตัวอย่างการแสดงผลลัพธ์ทาง Console ให้อยู่ในรูปแบบที่สวยงานโดยการ กำหนด PrettyPrinting

private void examplePrettyPrinting(){
  EasyObject easy = new EasyObject();
  easy.setValueBoolean(true);
  easy.setValueDate(new Date());
  easy.setValueInteger(999);
  easy.setValueString("poolsawat.com");
  //Serialization 
  Gson gson = new GsonBuilder().setPrettyPrinting().create();		
  System.out.println("serialization :: "+gson.toJson(easy));
}

/*
serialization :: {
  "valueString": "poolsawat.com",
  "valueInteger": 999,
  "valueDate": "Oct 4, 2017 9:54:58 PM",
  "valueBoolean": true
}*/

ตัวอย่างต้องการ custom field ที่มี value เป็น null อยากที่จะให้แสดงผลลัพธ์ field ที่เป็น null นั้นออกมาด้วยจำเป็นต้องกำหนด ให้  .serializeNulls()

private void exampleSerializeNulls(){
  EasyObject easy = new EasyObject();
  easy.setValueBoolean(true);
  //easy.setValueDate(new Date());
  easy.setValueInteger(999);
  easy.setValueString("poolsawat.com");
  
  //Serialization exclude null
  Gson gson = new GsonBuilder().setPrettyPrinting()				
      .create();		
  System.out.println("serialization exlude null:: "+gson.toJson(easy));
  
  //Serialization exclude null
  gson = new GsonBuilder().setPrettyPrinting()				
      .serializeNulls()
      .create();		
  System.out.println("serialization want null :: "+gson.toJson(easy));
}
/*
serialization exlude null:: {
  "valueString": "poolsawat.com",
  "valueInteger": 999,
  "valueBoolean": true
}
serialization want null :: {
  "valueString": "poolsawat.com",
  "valueInteger": 999,
  "valueDate": null,
  "valueBoolean": true
}*/




หากต้องการที่จะกำหนดชื่อใหม่ให้กับ key name ก็สามารถทำได้ โดยไม่ด้วยกัน 2 วิธี คือการกำหนดผ่าน annotation @SerializedName และ anonymous inner type การ setFieldNamingStrategy

@SerializedName("rename_valueBoolean") // เพิ่มเข้า
private boolean valueBoolean;

private void exampleRenameFieldKeyWithAnnotation(){
  EasyObject easy = new EasyObject();
  easy.setValueBoolean(true);
  //easy.setValueDate(new Date());
  easy.setValueInteger(999);
  easy.setValueString("poolsawat.com");
  
  Gson gson = new GsonBuilder().setPrettyPrinting()					
      .create();		
  System.out.println("serialization :: "+gson.toJson(easy));
}
/*
serialization :: {
  "valueString": "poolsawat.com",
  "valueInteger": 999,
  "rename_valueBoolean": true
}
*/

private boolean valueBoolean; // ไม่ต้องมี annotation แล้ว

private void exampleRenameFieldKeyWithAnonymous(){
  EasyObject easy = new EasyObject();
  easy.setValueBoolean(true);
  //easy.setValueDate(new Date());
  easy.setValueInteger(999);
  easy.setValueString("poolsawat.com");
  
  Gson gson = new GsonBuilder().setPrettyPrinting()		
      .setFieldNamingStrategy(new FieldNamingStrategy() {
        
        public String translateName(Field f) {
          if (f.getName().equals("valueBoolean"))
            return "rename_valueBoolean";
          else
            return f.getName();
        }
      })
      .create();		
  System.out.println("serialization :: "+gson.toJson(easy));
}

/*
serialization :: {
  "valueString": "poolsawat.com",
  "valueInteger": 999,
  "rename_valueBoolean": true
}
*/

สำหรับการกำหนดรุปแบบ format ให้ field ที่เป็น type date ก็สามารถกำหนดให้ได้ด้วยการกำหนด setDateFormat ตาม format ที่เรากำหนดเองได้เลย

private void exampleDateFormat(){
  EasyObject easy = new EasyObject();
  easy.setValueBoolean(true);
  easy.setValueDate(new Date());
  easy.setValueInteger(999);
  easy.setValueString("poolsawat.com");
  
  Gson gson = new GsonBuilder().setPrettyPrinting()		
      .setDateFormat("dd/MM/yyyy HH:mm:ss")
      .create();
  System.out.println("serialization dd/MM/yyyy HH:mm:ss :: "+gson.toJson(easy));		
  
  gson = new GsonBuilder().setPrettyPrinting()		
      .setDateFormat("yyyy/MM/dd")
      .create();
  System.out.println("serialization yyyy/MM/dd :: "+gson.toJson(easy));		
}
/*
serialization dd/MM/yyyy HH:mm:ss :: {
  "valueString": "poolsawat.com",
  "valueInteger": 999,
  "valueDate": "04/10/2017 22:29:53",
  "rename_valueBoolean": true
}
serialization yyyy/MM/dd :: {
  "valueString": "poolsawat.com",
  "valueInteger": 999,
  "valueDate": "2017/10/04",
  "rename_valueBoolean": true
}
*/

ในบางครั้งเราก็ไม่ต้องการสร้าง POJO สำหรับการเก็บ Data ชุดใหม่ Gson ก็มี Class สำหรับสร้าง Json Object เองได้สำหรับคนที่อยากกำหนด key ที่หลากหลาย

private void exampleJsonObject(){
  JsonObject object = new JsonObject();
  object.addProperty("blog_title", "Gson Open Source Library สำหรับจัดการ JSON Formatter");
  object.addProperty("blog_content", "“JSON” ไม่ใช่เรื่องใหม่อะไร เพราะปัจจุบันมีการ...");
  object.addProperty("blog_date", "04/10/2017");
  object.addProperty("blog_author", "poolsawat apin");
  Gson gson = new GsonBuilder().setPrettyPrinting().create();		
  System.out.println("serialization JsonObject :: "+gson.toJson(object));		
}
/*
serialization JsonObject :: {
  "blog_title": "Gson Open Source Library สำหรับจัดการ JSON Formatter",
  "blog_content": "“JSON” ไม่ใช่เรื่องใหม่อะไร เพราะปัจจุบันมีการ...",
  "blog_date": "04/10/2017",
  "blog_author": "poolsawat apin"
}
*/

อยากสร้างในรูปแบบของ Json Array ก็สามารถทำได้

private void exampleJsonArray(){
  JsonArray array = new JsonArray();
  
  JsonObject object1 = new JsonObject();
  object1.addProperty("blog_title", "Gson Open Source Library สำหรับจัดการ JSON Formatter");
  object1.addProperty("blog_content", "“JSON” ไม่ใช่เรื่องใหม่อะไร เพราะปัจจุบันมีการ...");
  object1.addProperty("blog_date", "04/10/2017");
  object1.addProperty("blog_author", "poolsawat apin");
  array.add(object1);
  
  JsonObject object2 = new JsonObject();
  object2.addProperty("blog_title", "สร้าง Spring MVC 4 ร่วมกับ Apache Tiles 3");
  object2.addProperty("blog_content", "สำหรับงานพัฒนาเว็บไซต์ด้วยภาษา Java มี Frameworks ให้เลือกอย่างมากมาย ...");
  object2.addProperty("blog_date", "15/09/2017");
  object2.addProperty("blog_author", "poolsawat apin");
  array.add(object2);
  
  Gson gson = new GsonBuilder().setPrettyPrinting().create();		
  System.out.println("serialization JsonArray :: "+gson.toJson(array));					
}
/*
serialization JsonArray :: [
  {
    "blog_title": "Gson Open Source Library สำหรับจัดการ JSON Formatter",
    "blog_content": "“JSON” ไม่ใช่เรื่องใหม่อะไร เพราะปัจจุบันมีการ...",
    "blog_date": "04/10/2017",
    "blog_author": "poolsawat apin"
  },
  {
    "blog_title": "สร้าง Spring MVC 4 ร่วมกับ Apache Tiles 3",
    "blog_content": "สำหรับงานพัฒนาเว็บไซต์ด้วยภาษา Java มี Frameworks ให้เลือกอย่างมากมาย ...",
    "blog_date": "15/09/2017",
    "blog_author": "poolsawat apin"
  }
]
*/

เหล่านี้เป็นตัวอย่างการใช้งานเบื้องต้นส่วนหนึ่งเท่านั้น มี UserGuide ให้ได้เข้าไปดูวิธีการใช้งานเพิ่มเติมได้

สร้าง Spring MVC 4 ร่วมกับ Apache Tiles 3

สำหรับงานพัฒนาเว็บไซต์ด้วยภาษา Java มี Frameworks ให้เลือกอย่างมากมาย เช่น JSF ,Vaadin ,GWT เป็นต้น และอีก 1 Framework ที่ได้รับความนิยมไม่แพ้ตัวอื่น ๆ เลยก็เป็น Spring MVC

ปัญหาที่ต้องเจอสำหรับงานพัฒนาเว็บคือการเรียกใช้งาน js,css ที่เป็น plugins มากมายก่ายกอง และเว็บไซต์ 1 เว็บก็ไม่ได้มีแค่หน้าเดียวซะเมื่อไหร่ละ เกิดความซ้ำซ้อนในการเรียก import js,css เข้ามาในแต่ละ page ดีหน่อยก็ทำไฟล์ include_js_css.jsp สำหรับทำหน้าที่ import js,css และเมื่อต้องการเรียก plugins js,css ก็ import include_js_css.js เข้ามา ก็พอจะแก้ปัญหานี้ให้ผ่านไปได้แต่ก็ยังไม่ถือว่าเป็นมือโปรสักเหล่าไหร่ และก็ทำให้การเขียนโค๊ดดูไม่สะอาดตาเอาซะเลย

เพราะว่า Spring MVC ปัจจุบันเวอชั่น 5 เข้าไปแล้ว ปัญหาเรื่องที่กล่าวมานี้ก็ย่อมได้รับการแก้ไขแล้ว วันนี้ก็เลยอยากจะนำพามาให้รู้จัก Apache Tiles ทำให้การจัดการไฟล์ view ทั้งหลายในเว็บของเราดูเป็นระเบียบเรียบร้อยยิ่งขึ้น เริ่มกันเลย

ก่อนอื่นสร้าง Maven Project ขึ้นมา ทำการเพิ่มใน pom.xml

<properties>
    <tiles.version>3.0.7</tiles.version>
    <spring.version>4.0.1.RELEASE</spring.version>
</properties>
<dependencies>
  <!-- Apache Tiles -->
  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-core</artifactId>
    <version>${tiles.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-core</artifactId>
    <version>${tiles.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-api</artifactId>
    <version>${tiles.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-servlet</artifactId>
    <version>${tiles.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-jsp</artifactId>
    <version>${tiles.version}</version>
  </dependency>


  <!-- -->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
  </dependency>
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
  </dependency>
  <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.1</version>
  </dependency>

  <!-- Spring dependencies -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>

</dependencies>

เพิ่ม code ใน web.xml

<servlet>
  <servlet-name>dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</context-param>

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

สร้างไฟล์ dispatcher-servlet.xml ใน WEB-INF/

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-package="com.poolsawat" />


  <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
    <property name="definitions">
      <list>
        <value>/WEB-INF/tiles/tiles-template.xml</value>
        <value>/WEB-INF/views/tiles-views.xml</value>
      </list>
    </property>
  </bean>

  <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
  </bean>

</beans>




สร้างชุดไฟล์ tiles สำหรับทำ template

/WEB-INF/tiles/layouts/defaultLayout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><tiles:getAsString name="title" /></title>
</head>
<body>
  <table border="1'" style="width:93%;margin: 30px 50px 30px 50px;">
    <tbody>
      <tr>
        <td colspan="2" style="background-color: orange;"><tiles:insertAttribute name="header" /></td>
      </tr>
      <tr>
        <td style="width:20%;background-color: yellow;"><tiles:insertAttribute name="menu" /></td>
        <td style="width:80%;background-color: blue;"><tiles:insertAttribute name="body" /></td>
      </tr>
      <tr>
        <td colspan="2" style="background-color: pink;"><tiles:insertAttribute name="footer" /></td>
      </tr>
    </tbody>
  </table>
</body>
</html>

/WEB-INF/tiles/template/defaultFooter.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div style="width:100%;hight:300px;">
  <h1>Footer</h1>
</div>

/WEB-INF/tiles/template/defaultHeader.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div style="width:100%;hight:300px;">
  <h1>Header</h1>
</div>

/WEB-INF/tiles/template/defaultMenu.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="context" value="${pageContext.request.contextPath}" />
<div style="hight:300px;">
  <ul>
    <li><a href="${context }/hello">Hello</a></li>
    <li><a href="${context }/home">Home</a></li>
    <li><a href="${context }/welcome">Welcome</a></li>
  </ul>
</div>

/WEB-INF/tiles/tiles-template.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
  <definition name="default" template="/WEB-INF/tiles/layouts/defaultLayout.jsp">
    <put-attribute name="header" value="/WEB-INF/tiles/template/defaultHeader.jsp" />
    <put-attribute name="menu" value="/WEB-INF/tiles/template/defaultMenu.jsp" />  
    <put-attribute name="title" value="" />		
    <put-attribute name="body" value="" />
    <put-attribute name="footer" value="/WEB-INF/tiles/template/defaultFooter.jsp" />		
  </definition>	
</tiles-definitions>

ต่อไปสร้าง view สำหรับเป็นหน้า page ของเว็บเรา

/WEB-INF/views/hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<h1>Hello Page</h1>

/WEB-INF/views/home.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<h1>Home Page</h1>

/WEB-INF/views/welcome.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<h1>Welcome Page</h1>

/WEB-INF/views/tiles-views.xml

<?xml version="1.0"?>
  <!DOCTYPE tiles-definitions PUBLIC
    "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
    "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
  <definition name="hello" extends="default">
    <put-attribute name="title" value="hello" />
    <put-attribute name="body" value="/WEB-INF/views/hello.jsp" />
  </definition>
  
  <definition name="welcome" extends="default">
    <put-attribute name="title" value="welcome" />
    <put-attribute name="body" value="/WEB-INF/views/welcome.jsp" />
  </definition>
  
  <definition name="home" extends="default">
    <put-attribute name="title" value="home" />
    <put-attribute name="body" value="/WEB-INF/views/home.jsp" />
  </definition>
  
</tiles-definitions>

ไฟล์ tiles-template.xml จะเป็นไฟล์สำหรับ config tiles ว่าจะให้ไปเรียก layouts แต่ละส่วน ในตัวอย่างจะมีการแบ่งหน้าเว็บเป็น 4 ส่วน คือ header , menu , body ,footer

ไฟล์ tiles-views.xml จะถูกใช้งานเป็นตัวกำหนด view ของแต่ละ page จะเรียกนำไฟล์อะไรมาใช้บ้างจะถูกกำหนดที่ไฟล์นี้ definition name จะถูกไปเรียกในการ Mapping กับ Controller

ขั้นตอนต่อไปก็ทำในส่วนของการ mapping controller กับ view

package : com/poolsawat/controller/IndexController.java

package com.poolsawat.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {

  @RequestMapping("/hello")
  public String hello() {
    return "hello";
  }
  
  @RequestMapping("/welcome")
  public String welcome() {
    return "welcome";
  }
  
  @RequestMapping("/home")
  public String home() {
    return "home";
  }
}

ทดสอบโปรแกรม

โครงสร้างเว็บ

Github Source Code ตัวอย่างนี้

Electron Framework เริ่มต้นการสร้างโปรเจค Hello World

บทความนี้จะพามาทำ Desktop App ด้วย Javascript , HTML คุณฟังไม่ผิดหรอก Javascript สามารถใช้พัฒนาได้จริง ๆ

การที่เราจะพัฒนา App ที่ Run ได้บน Desktop นั้นคงจะจินตณาการไปว่าต้องเขียนด้วย C/C++, VB, .NET, Java หรือ Objective-C/Swift ได้เท่านั้น แต่สำหรับยุคปัจจุบันเทคโนโลยีบนโลกเปลี่ยนไปไวมาก Web Application ที่ถือว่าได้รับความนิยมมากในปัจจุบันก็ยังคงหนีไม่พ้นการนำ Javascript เข้ามาช่วยเพิ่มขีดความสามารถของ Application นั้นให้ทำงานได้อย่างมีประสิทธิภาพ Javascript ที่ต้องบอกว่าความสามารถครอบจักรวาลจริง ๆ จึงมีคนคิดค้นให้ Javascript Language นี้สามารถนำมาใช้พัฒนา Desktop Application ได้อย่างไม่น่าเชื่อ




เครื่องมือยอดฮิตในปัจจุบันอย่าง Atom Editor ,VSCode Editor นั้นก็ถูกพัฒนามาจาก Electron Framework ด้วยกันทั้งนั้น

เริ่มต้นการเขียนโปรแกรมเพื่อให้แสดง Hello World

เพราะด้วยว่า การติดตั้ง Electron นั้นจำต้องทำผ่านทาง npm ของ NodeJS จึงอยากให้ติดตั้ง NodeJS ที่เครื่องคอมพิวเตอร์กันก่อนให้เรียบร้อย

หลังจากที่ได้ติดตั้ง NodeJS เป็นที่เรียบร้อยแล้วให้ทำการ install Package Electron แบบ Global ในเครื่องของเราด้วยคำสั่ง

npm install -g electron -prebuilt

รอจนกว่าจะติดตั้งเสร็จ (อาจจะใช้เวลานานสักหน่อย)

หลังจากติดตั้งสำเร็จให้ตรวจสอบ Electron Version เพื่อเช็คว่าติดตั้งเรียบร้อยดี ไม่มีปัญหา

electron --version

ต่อไปจะมาทำการสร้าง App Hello World กัน

สร้าง Directory ชื่อ App มาก่อนเพื่อเก็บโค๊ดของเราจากนั้นสร้างไฟล์ index.html ,main.js ขึ้นมา พร้อมใส่โค๊ดไปตามนี้

ไฟล์ index.html

<!DOCTYPE>
<html>

<head>
    <meta charset="utf-8">
    <title>App Electron By Poolsawat</title>
</head>

<body>
    <h1>Hello World</h1>
</body>

</html>




ไฟล์ main.js

const { app, BrowserWindow } = require('electron')
const url = require('url')
const path = require('path')

let win

app.on('ready', function() {
    win = new BrowserWindow({ width: 800, height: 600 })
    win.loadURL(url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file',
        slashes: true
    }))
})

ต่อไปทำการสั่งให้ Application Hello World ทำงานได้โดยการ Run ผ่าน Electron Command

electron main.js

Docker ฉบับผู้เริ่มต้น (Setup On Window)

Docker คืออะไร

Docker คือ Platform สำหรับการ Developing, Shipping and Running Application ที่สร้างสภาพแวดล้อมเสมือนจริง

Docker Platform มีส่วนประกอบด้วยสิ่งเหล่านี้

Docker Engine คือ  เป็นเหมือนตัว Runtime สำหรับ Build และ Run Docker Container ช่วยให้คุณสามารถจัดการ Dependencies ต่าง ๆ

Docker Hub คือ แหล่งที่จัดเก็บ Docker Image ต่าง ๆ (มองว่าคล้ายกับ github)

Docker Machine คือ สำหรับการ Deploy Docker ไปที่ Production

Docker Swarm คือ เครื่องมือที่จัดการเครื่องที่ Run Docker หลาย ๆ เครื่องให้อยู่ในสภาพแวดล้อมเดียว สามารถ scale ระบบบน Docker Swarm ได้มีประสิทธิภาพมากกว่าการสั่งงาน Docker ทีละเครื่อง

Docker Compose คือ การร่วมเอา Docker Container หลายๆ Container มาสั่งให้ทำงานพร้อมกัน

Kitematic คือ เครื่องมือ GUI ที่รวบรวมคำสั่งของ Docker Command ต่าง ๆ ในรูปแบบ UI ให้สามารถใช้งานได้ง่าย ๆ ยิ่งขึ้น

ปัญหาที่เหล่า Developer พบเจอในการ Development Application

  • เสียเวลาติดตั้ง Application ใหม่ทุกครั้ง
  • Run Application บน Production ไม่ได้แต่ Run บนเครื่อง Dev ได้ (เป็นแบบนี้บ่อยมาก)
  • มี Dev เข้ามาเพิ่มในทีมต้องเสียเวลาในการจัดเตรียม Environment ใหม่ (ซึ่งเตรียมแล้วอาจจะเกิดปัญหา Environment ไม่ตรงกับเครื่องเพื่อนในเรื่องของ Version ต่างๆ)

Install Docker On Window Side

  1. ตรวจสอบสภาพความพร้อมของเครื่องที่จะทำการ install
    1. ตรวจสอบ OS Version ของเครื่องที่จะ Install
    2. ตรวจสอบ Virtualization ว่า enabled อยู่หรือไม่ ให้ทำการ enabled Virtualization ก่อน
  2. Install Tools
    1. Install Docker Toolbox  (Click next, next, …)
    2. Install VirtualBox
  3.  ตรวจสอบ Icon Tools บนหน้า Desktop ของเครื่อง Computer คุณ

docker-icon

เริ่มการเข้าใช้งาน Docker

  1. Click Icon Docker Quickstart ขึ้นมา
  2. ตรวจสอบ Docker-machine IP
  3. ตรวจสอบ Version
    docker --version
    
    docker-compose --version
    
    docker-machine --version

ทำความเข้าใจ Docker Containers และ Docker Images

  • Images
    • เมื่อเป็น Image แล้วจะอ่านได้อย่างเดี่ยวแก้ไขอะไรไม่ได้
    • ถูกสร้างขึ้นจากผู้ใช้งาน Docker
    • ถูกจัดเก็บไว้ที่ Docker Hub หรือ Local Registry
  • Containers
    • แยกการทำงานออกจากกัน
    • Containers ต่าง ๆ จำเป็นต้อง Run บน Application ของคุณ
    • 1 Container จำเป็นต้องมี Image 1 อันเป็นอย่างน้อย




Create Hello World Container

#Syntax
docker run [options] [image] [command] [args]

#examples
docker run ubuntu:14.04 echo "Hello World"

#*image is specified with repository:tag

Docker Command อื่น ๆ ที่ใช้งานบ่อย ๆ

#Find Images
docker images

#Find Container is Running
docker ps
# Find Container all
docker ps -a

#Find Logs is Container
docker logs <container id>

#Container with Terminal
# -i flag tells docker to connect to STDIN on the container
# -t flag specifies to get a pseudo-terminal
docker run -i -t ubuntu:latest /bin/bash

#Running in Detached Mode (Run Background Process)
docker run -d <image id>

#More Practical Container
# -P flag to map container ports to host ports
docker run -d -P tomcat:7


#start container
docker start <container id>

#stop container 
docker stop <container id>

#delete conatiner
docker rm <container id>

#delete image
docker rmi <image id>
#or
docker rmi <repo:tag>

#mapped to a host directory
docker run -i -t -v /data/src:/test/src nginx:1.7

#mapping ports
docker run -d -p 8080:80 nginx:1.7

#automaping ports
docker run -d -P nginx:1.7

#creating a Link
docker run -d -P --name website --link database:db nginx

สรุปสิ่งที่ได้รับจากงาน OpenStack Thailand Chapter – User and Contributor MeetUp #1

OpenStack Thailand Chapter – User and Contributor MeetUp #1 30 พฤศจิกายน 2016 เวลา 18:00 – 21:00

Agenda :

18:00 – 18:30 น.  ลงทะเบียน
18:30 – 19:00 น.  กล่าวต้อนรับ และ วัตถุประสงค์ในการจัดตั้งกลุ่ม OpenStack Thailand Chapter – User and Contributor
19:00 – 19:30 น.  Why you need to attend Openstack Summit and how to attend at very affordable budget? โดย Dr. Abhisak Chulya, CEO and Founder, NIPA.cloud
19:30 – 19:45 น.  พักการบรรยาย
19:45 – 20:30 น. How to be OpenStack Contributor โดย คุณจิรายุส นิ่มแสง, CEO and Founder, Opsta
20:30 – 21:00 น. Open Discussion

OpenStack คืออะไร

OpenStack การรวมกันของ Projects Open Source เพื่อให้เกิดเป็น Project Openstack นี้ขึ้นมา สำหรับใช้เพื่อการสร้าง Private หรือ Public Clounds

openstack-software-diagram

โดย OpenStack Project นี้เองก็จะมี Project ที่เป็น Core Services หลักอยู่ ประกอบด้วยกันอยู่ 6 Services

  • NOVA คือ เป็นตัวแทนของ Service ที่จัดการ Compute
  • NEUTRON คือ Service จัดการระบบ Networking
  • SWIFT คือ Service ที่เอาไว้จัดการ Object Storage สำหรับจัดเก็บข้อมูลแบบ cloud storage จัดเก็บข้อมูลและเรียกใช้งาน แบบ API
  • CINDER คือ  Block Storage
  • KEYSTONE คือ Service ตรวจสอบและอนุมัติการให้บริการสำหรับบริการ OpenStack ทั้งหมดในระบบ
  • GLANCE คือ Service จัดการเกี่ยวกับการให้บริการเกี่ยวกับ Media ต่าง ๆ

 

openstack-core-service

และ Optional Service โดยให้พิจรณาจาก Maturity ว่ายิ่งเยอะ ยิ่งดูเสถียรเหมาะแก่การจะทำไปใช้งาน

openstack-optional-serviceOpenstack ประกอบด้วย 4 “Open” เข้าด้วยกัน

  • Open Source
  • Open Design
  • Open Development
  • Open Community

OpenStack จะถูกเรียกแต่ละ version release ตามครั้งการจัดรวม Community

  • Barcelona (OCATA) Fall 2016
  • Austin(NEWTON) Spring 2016
  • Tokyo(MIKATA) Fall 2015
  • Vancouver(LIBERTY) Spring 2015
  • Paris(KILO) Fall 2014
  • Atlanta(JUNO) Spring 2014
  • Hong Kong(ICEHOUSE) Fall 2013

ซึ่ง Release Mitaka (2016-04-07) ถูกบันทึกสถิติไว้

  • ผู้เข้าร่วมงาน 40,497 คน
  • บริษัทที่คอยสนับสนุนกว่า 596 บริษัท
  • 179 ประเทศ
  • 35,000 K Line of Code




OpenStack Summit Sponsorship

openstack-sponsorship

Release Series

openstack-release-series

OpenStack Superuser Award Nominees เรียกได้ว่าบริษัทที่มีชื่อเสียงทั่วโลกที่ได้ทำเทคโนโลยี OpenStack ไปใช้งานแล้ว

  • China Mobile
  • City Network
  • Cloundwatt
  • DataCentered
  • Internap
  • MercadoLibre
  • ฯลฯ

OpenStack Foundation Structure

  • OpenStack Foundation คือ องค์กรไม่แสวงหาผลกำไร
    • Board Of Directors
    • Technical Committee (TC) ทำหน้าทีคอยดูภาพรวมทั้งหมดของ OpenStack
    • User Committee จะเป็นตำแหน่งที่ถูกเลือกโดยเหล่า Members ทั้งหลาย
    • Members ผู้ใช้งานทั่วไปที่ join เข้าเป็น member ของ OpenStack
  • OpenStack Project Teams
    • Projects Team Leads (PLTs) หน้าที่เป็นผู้นำสูงสุดของ Project นั้น ๆ ได้รับเงินเดือนจากบริษัทที่เป็น Sponsor
    • Active Project Contributor (APC) ทำหน้าที่ดูหลาย ๆ Project ไปพร้อมๆ กัน
    • Active Technical Contributor (ATC) การที่เรา Contribute Openstack อยู่เรื่อยๆ และจะถูกเลือกให้เป็นตำแหน่งนี้เอง

ติดตาม OpenStack Release State ได้แบบละเอียด ที่ลิ้งนี่

ตบท้ายได้แนะนำเทคนิคการไป Openstack Summit ในครั้งต่อ ๆ ไปแบบประหยัดจะต้องทำอย่างไร

ขอบคุณที่ติดตามครับผม