2016年10月2日 星期日

Google Chrome Web Push (客製化訊息 - 需加密)

Google Chrome Web Push是Google的一項服務,可以讓管理者向User主動推播訊息,
跟之前介紹的對Android GCM推播很像(如何向GCM Server傳送資料如何接收GCM Server發送的Registration ID訊息,以php、Java及JSP為例,以php、Java及JSP為例),事實上Google Chrome Web Push目前也是利用GCM服務來實現的。

Google Chrome Web Push可以寫死彈跳訊息的code在client端(註冊時會記錄),也可以動態訊息給client,不過因為安全的問題,必須使用Google規定的方式來加密訊息。

在這邊就來一步步展示如何做一個簡單的Google Chrome Web Push實現:

2016年9月28日 星期三

ByteArrayOutputStream - Java - close 後可取出資料的OutputStream

ByteArrayOutputStream繼承OutputStream,但跟平常看到的例如FileOutputStream、ServletOutputStream等不同,它是可以在資料輸出至OutputStream後、甚至在被close()後,還可以將資料取回的一種OutputStream,例如可用其擁有的方法,toByteArray(),來取得byte[]型別的資料。

例如以之前的文章為例,使用Java製作GIF動畫 - AnimatedGifEncoder,其中
OutputStream o = response.getOutputStream();
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
encoder.start(o);
o.flush();
o.close();

也可寫成:

ByteArrayOutputStream oo = new ByteArrayOutputStream();
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
encoder.start(oo);  //
/* some code */
oo.flush();
oo.close();

byte[] gif_btyeArray = oo.toByteArray();
/* you can do something with gif_byteAray */
OutputStream o = response.getOutputStream();
o.write(gif_btyeArray );
o.flush();
o.close();

可以看到我們先把輸出的資料先送到ByteArrayOutputStream裡,在其close()後,還可以利用ByteArrayOutputStream的toByteArray()取回資料,對資料做想要的處理之後,再送給ServeltOutputSteam

參考資料:
  1. java.ByteArrayInputStream与ByteArrayOutputStream再次理解http://blog.csdn.net/rcoder/article/details/6118313
  2. How can we read or use the contents of outputstream [closed]

2016年9月27日 星期二

使用Java製作GIF動畫 - AnimatedGifEncoder

今天要來介紹一個對於用Java生成動態GIF特別好用的類別, AnimatedGifEncoder,
由Kevin Weiner所撰寫,

下面以一個簡單的例子來演示如何使用。

需求如下:

  1. 寫一個servlet,其接到request後可輸出一個GIF動畫。
  2. 在一個htm內用<img>的src接接看測試

實作的檔案結構如下:

各檔內容如下(AnimatedGifEncoder.java就不介紹了):

  1. index.html
    <!DOCTYPE html>
    <html>
        <head>
            <title>Animated Gif Test</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <style>
                /* 為img加上背景色,測試透明GIF動畫 */
                img {
                    background-color: black;
                }
            </style>
        </head>
        <body>
            <div>Animated Gif Test</div>
            <!-- 測試GIF動畫 -->
            <img src="AnimatedGif.do" />
        </body>
    </html>
  2. AnimatedGif.java
    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    package servlet;
    
    import java.awt.Color;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.io.OutputStream;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import tools.AnimatedGifEncoder;
    
    @WebServlet(name = "AnimatedGif", urlPatterns = {"/AnimatedGif.do"})
    public class AnimatedGif extends HttpServlet {
    
        /**
         * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
         * methods.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            OutputStream o = response.getOutputStream();
            response.setContentType("image/gif"); //設定-- header -- ContentType
            
            Color transparentColor = Color.WHITE;
            
            AnimatedGifEncoder encoder = new AnimatedGifEncoder();
            encoder.setTransparent(transparentColor); //設定透明色
            encoder.setDelay(100);  //設定frame之間的間隔 (毫秒)
            encoder.setRepeat(0);  //設定重覆迴圈次數(不設就是不重覆), 0:無限, 1:重覆一次...
            encoder.start(o);      //綁定OutputStream  
            
            //產生畫布
            BufferedImage generatedImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
            //產生繪圖工具
            Graphics2D graphics2D = generatedImage.createGraphics();
            for (int i = 0; i < 10 ; i++){
                //畫底色
                graphics2D.setColor(transparentColor);
                graphics2D.fillRect(0, 0, generatedImage.getWidth(), generatedImage.getHeight());
                //畫圓圈
                graphics2D.setColor(Color.RED);
                graphics2D.drawOval(i*3, 25, 50, 50);
                //加到GIF動畫frame中
                encoder.addFrame(generatedImage);
            }
            graphics2D.dispose(); //釋放資源
     encoder.finish();  //GIF動畫結束
            //串流輸出
            o.flush();
            o.close();
        }
    
        // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
        /**
         * Handles the HTTP <code>GET</code> method.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }
    
        /**
         * Handles the HTTP <code>POST</code> method.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }
    
        /**
         * Returns a short description of the servlet.
         *
         * @return a String containing servlet description
         */
        @Override
        public String getServletInfo() {
            return "Short description";
        }// </editor-fold>
    
    }
    
    
    
成果展示:

原始碼下載:
AnimatedGifEncoderTest.7z

參考資料:

  1. Java – How To Overlay One Image Over Another Using Graphics2D [Tutorial]
  2. 在Java應用程序中創建圖像的方法和技巧
  3. Is there a way to create one Gif image from multiple images in Java? [closed]
  4. 在Java中使用AnimatedGifEncoder生成GIF動畫
  5. [Android] AnimatedGifEncoder
  6. java将gif动态图片分开展示源代码简单示例

2016年9月17日 星期六

typescript + SystemJS + npm + jQuery (Netbeans, Eclipse)

這篇主要紀錄在Netbeans和Eclipse中使用Typescript,並配合SystemJS的範例,再來我們要利用npm來安裝JQuery並用SystemJS引入JQuery模組,學習建立自己的javascript module。

這篇要實現的需求如下:
  1. 在Netbeans和Eclipse中使用typescript外掛編譯我們的ts檔成js檔。
  2. 使用npm安裝JQuery。
  3. 使用SystemJS引入JQuery模組並使用。
  4. 建立一個自製的JS module, Greeter,配製好相應的package.json和export設定,放到node_modules中。
  5. import自制的Greeter,並建立一個myGreeter去entend(繼承)Greeter擴充功能。
以下是我們完成的目錄結構,需注意到的是,藍色框線標示的js及map檔是ts檔被typescript編譯出來的檔案:



接下來講解步驟:

2016年9月10日 星期六

使用raycaster實現Object的選取 - three.js

three.js可以在Scene放置許多的Object3D,但如果我們想要讓User跟那些Obejct做互動,那要如何做呢,例如User在Camera的畫面中看到許多的物件,想用滑鼠去點擊那些物件去做互動。

在three.js中,有一個Raycaster類可以做到上述需求,它的原裡是,想像有一條光束(ray)從Camera畫面中滑鼠指的位置,以垂直於Camera的X-Y平面的方式向Camera的負Z方向射出,並且計算在Scene的children中有哪些物件被這條線射中(ray可以穿過所有Object3D)。 

在這裡,我要來示範一個使用three.js的Raycaster的範例,需求是這樣的:

需求:
  1. 畫面上有許多的Object3D物件,有各自的顏色。
  2. 當滑鼠指到(hover)某一個Object時,將指到的第一個Object變成紅色(即它後面的Object不會變色)。
  3. 滑鼠移開後,剛剛指到但現在沒指的Object變回原來的顏色。
接下來一步步的講解每一個步驟:

2016年8月28日 星期日

Duration的格式化 - DurationFormatUtils - Java

這邊介紹一個Java很好用的類別,DurationFormatUtils,收錄在
Apache Commons Lang中,下載地址在這
package的位置在org.apache.commons.lang.time.DurationFormatUtils,
說明文件在這

DurationFormatUtils可以對代表 " 一段持續時間" 的資料做格式化,在DurationFormatUtils中
這個 "一段持續時間" 是用 millis-second 來的儲存的。

我們可以利用DurationFormatUtils來對持續時間用我們提供的自訂格式來格式化,例如181800000毫秒可以用 "dd'天'HH'時'mm'分'ss'秒'" 來表示成 "02天02時30分00秒"

下面就來紀錄一下DurationFormatUtils的使用方法:
import java.time.Duration;
import java.time.Instant;
import org.apache.commons.lang3.time.DurationFormatUtils;

public class DurationFormatUtilsTest {

    public static void main(String[] args) {
        Instant startInstant = Instant.parse("2015-05-01T00:00:00Z");  //ISO 8601 表示法
        Instant endInstant = Instant.parse("2015-05-03T02:30:00Z");        
        Duration duration = Duration.between(startInstant, endInstant); //得到兩個Instant差的Duration
        
        String resultDurationString1 = DurationFormatUtils.formatDuration(duration.toMillis(), "dd'天'HH'時'mm'分'ss'秒'");
        System.out.println(resultDurationString1); //輸出: 02天02時30分00秒
        
        String resultDurationString2 = DurationFormatUtils.formatDuration(duration.toMillis(), "dd'天'HH'時'mm'分'ss'秒'", false);
        System.out.println(resultDurationString2); //輸出: 2天2時30分0秒  //(10以下的數字不補0)
        
        String resultDurationString3 = DurationFormatUtils.formatDuration(duration.toMillis(), "HH'時'mm'分'ss'秒'");
        System.out.println(resultDurationString3); //輸出: 50時30分00秒  //(沒有設定小時以上的單位,小時以上全部由小時表示:50小時)
        
        String resultDurationString4 = DurationFormatUtils.formatDurationISO(duration.toMillis());
        System.out.println(resultDurationString4); //輸出: P0Y0M2DT2H30M0.000S //ISO 8601標準格式
        
    }
}

參考資料:

  1. Class DurationFormatUtils
  2. 常用jar包之commons-lang使用
  3. Java 8的日期與時間(Date-Time)API

2016年8月20日 星期六

使用Ajax上傳檔案 - (Javascript, JQuery or AngularJS) + FormData

在以前我們要在網頁中傳送檔案資料時,通常會需要設計一個html Form,並設定Form的encype=multipart/form-data和準備一個input type="file",在User按下submit按鈕後,跟據Form
所設定的action="URL",將整個頁面request移動到action所指定的地方,例如Servlet,
等處理完後在將User導至其他網頁頁面。

但有沒有可能不要讓User被導到其他頁面,留在原頁面就完成檔案資訊的傳送呢?
答案是可以的,這邊就要利用新的javascript類別FormData和Ajax的技術來達到Ajax傳
送檔案(也可順便傳遞其他input資料)資料。


在這邊我們要利用Netbeans、Servlet3.0、Tomcat 8來實做我們的範例,
實現了三個版本的檔案上傳:Javascript、JQuery、AngularJS
首頁是專案檔案結構,如下圖:

所用的版本JQuery為v2.0.3、AngularJS為v1.5.8,
主要的重要檔案有:

  1. fileUploadAjaxExample.html
    給User上傳檔案的html網頁。
  2. FileUploadAjax.js
    處理檔案資料上傳的Javascript File.
    包含Javascript、JQuery、AngularJS三個版本。
  3. FileUploadAction.java
    用來接收檔案資料的servlet,這裡設定URL patter為/fileUpload.do
  4. web.xml
    設定檔,其中必須在要接收檔案的servlet中設定的tag,
    tag裡可以有以下的子tag設定:
    <location>         檔案存放位置 (使用Part.write(fileName)可以在寫入檔案,但如果fileName
                               為絕對路徑則以絕對路徑為準)
    <max-file-size>  最大檔案size
    <max-request-size>   最大request size  (例如POST的request size)
    <file-size-threshold>
       超過file-size-threshold的檔案request將會以臨時暫存的方式存到硬                                       碟中,預設為0
接下來我以來各別看下每個實作檔案的內容: