2017年2月5日 星期日

XSLT 1.0

CSS對HTML可以對HTML顯示排版、顏色…等
XSLT是對XML的,但功能更多,雖然CSS也可以對XML做排版,但每個瀏覽器不一定顯示的都一樣,所以用XSLT就不會有這個問題
目前版本有分成 1.0 和 2.0

※xxx.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="ooo.xsl"?>
<root>
    <item1>
        <xxx>x1</xxx>
        <ooo>o3</ooo>
    </item1>
    <item1>
        <xxx>x2</xxx>
        <ooo>o2</ooo>
    </item1>
    <item1>
        <xxx>x3</xxx>
        <ooo>o1</ooo>
    </item1>
    <item2>
        <xxx>x4</xxx>
        <ooo>o6</ooo>
    </item2>
    <item2>
        <xxx>x5</xxx>
        <ooo>o5</ooo>
    </item2>
    <item2>
        <xxx>x6</xxx>
        <ooo>o4</ooo>
    </item2>
</root>

※引用了ooo.xsl


※ooo.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <html>
            <body>
                <h2>OXO</h2>
                <table border="1">
                    <tr bgcolor="red">
                        <th align="left" width="100">O</th>
                        <th align="right" width="100">X</th>
                    </tr>
                    <xsl:for-each select="root/item1">
                        <xsl:sort select="xxx" />
                        <tr>
                            <td bgcolor="lightgreen">
                                <xsl:value-of select="ooo"/>
                            </td>
                            <td bgcolor="lightgreen">
                                <xsl:value-of select="xxx"/>
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

※xsl:stylesheet和xsl:transform是完全一樣的,但大部分的人是用stylesheet,裡面的網址定了可用的標籤,也有語法教學

※template match="/"表示引用此份xsl時,是從根開始有作用,也就是整份文件都有作用

※for-each select 的路徑是從template match之後的路徑,假設將template match="/root",那如果想設成一樣的效果,那就將 for-each select="item1"即可,用的語法是XPath
將想要循環顯示的標籤包起來

※value-of select 是選節點用的,select仍然是XPath

※sort select 當然就是針對排序用的,看要針對哪個標籤,就寫上去
屬性 order 可用正序(ascending)和倒序(descending),正序是預設值


※直接將XML用IE瀏覽器打開是OK的,但用Chrome瀏覽器打開會出「Unsafe attempt to load URL file:///C:/~~~/ooo.xsl from frame with URL file:///C:/~~~/xxx.xml. 'file:' URLs are treated as unique security origins.」
什麼原因目前我不清楚,但看起來Chrome用file:///開頭,且又引用 xsl 都會出這個錯,所以我用Eclipse架Servlet,然後將此兩支丟進去就可以了,因為網址是http開頭的



※if

<xsl:for-each select="root/item1">
    <xsl:sort select="xxx" />
    <xsl:if test="ooo = 'o3' or ooo = 'o2'">
        <tr>
            <td bgcolor="lightgreen">
                <xsl:value-of select="ooo" />
            </td>
            <td bgcolor="lightgreen">
                <xsl:value-of select="xxx" />
            </td>
        </tr>
    </xsl:if>
</xsl:for-each>

※注意等於只有一個

※大小於要用&gt;、&lt;



※choose、when、otherwise

<xsl:for-each select="root/item1">
    <xsl:sort select="xxx" />
    <xsl:choose>
        <xsl:when test="ooo = 'o3'">
            <tr>
                <td bgcolor="lightgreen">
                    <xsl:value-of select="ooo" />
                </td>
                <td bgcolor="lightgreen">
                    <xsl:value-of select="xxx" />
                </td>
            </tr>
        </xsl:when>
    
        <xsl:when test=" ooo = 'o2'">
            <tr>
                <td bgcolor="pink">
                    <xsl:value-of select="ooo" />
                </td>
                <td bgcolor="pink">
                    <xsl:value-of select="xxx" />
                </td>
    
            </tr>
        </xsl:when>
    
        <xsl:otherwise>
            <tr>
                <td bgcolor="yellow">
                    <xsl:value-of select="ooo" />
                </td>
                <td bgcolor="yellow">
                    <xsl:value-of select="xxx" />
                </td>
            </tr>
        </xsl:otherwise>
    </xsl:choose>
</xsl:for-each>

※JSTL也有這個,用choose包起來,裡面放很多個when和一個otherwise,其實就是if、else

※注意以此例 tr 看起來三個都有,所以提出去when的外面,這樣就只要寫一次,但這樣做是不會成功的
應該是 choose 和 when 之間不能加標籤吧!



※apply-templates

是template的子標籤,可以針對xml裡不同的標籤,套用到不同的模版,template 的 match不能重覆,會報錯


<xsl:template match="/root">
    <html>
        <body>
            <h2>OXO</h2>
            <xsl:apply-templates select="item1" />
            <xsl:apply-templates select="item2" />
        </body>
    </html>
</xsl:template>
    
<xsl:template match="item1">
    XXX:
    <span style="color:#ff0000">
        <xsl:value-of select="." />
    </span>
    <br />
</xsl:template>
    
<xsl:template match="item2">
    OOO:
    <span style="color:#00ff00">
        <xsl:value-of select="." />
    </span>
    <br />
</xsl:template>

※select=".",表示此標籤下的標籤

2017年2月3日 星期五

前端呼叫WebService、同源策略 ( WebService 五)

還是使用上一篇 Spring 架好的CXF
再新增一個 動態Web 專案


※使用JS呼叫

可看W3C官網複製

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>Insert title here</title>
        <script type="text/javascript">
            function jsCallWebService() {
                const a = document.getElementById("account").value;
                const p = document.getElementById("password").value;
                const n1 = document.getElementById("num1").value;
                const n2 = document.getElementById("num2").value;
                var data = getData(a, p, n1, n2);
        
                const request = getXmlHttp();
                request.onreadystatechange = function() {
                    if (request.readyState == 4 && request.status == 200) {
                        var result = request.responseXML;
                        var rtn = result.getElementsByTagName("return")[0];
                        var vue = rtn.firstChild.data;
                        document.getElementById("ta").value = vue;
                    }
                };
    
                request.open("POST", "http://localhost:8080/SCXF/aaa/bbb/ccc", true);
                request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                request.send(data);
            }
    
            function getXmlHttp() {
                var xmlhttp;
                if (window.XMLHttpRequest) {
                    // code for modern browsers
                    xmlhttp = new XMLHttpRequest();
                } else {
                    // code for old IE browsers
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                return xmlhttp;
            }
    
            function getData(a, p, n1, n2){
                var d =
                    '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:test="http://test.hello/">' +
                        '<soapenv:Header>' +
                            '<login>' +
                                '<acc>' + a + '</acc>' +
                                '<pass>' + p + '</pass>' +
                            '</login>' +
                        '</soapenv:Header>' +
                        '<soapenv:Body>' +
                            '<test:add>' +
                                '<arg0>' + n1 + '</arg0>' +
                                '<arg1>' + n2 + '</arg1>' +
                            '</test:add>' +
                        '</soapenv:Body>' +
                    '</soapenv:Envelope>';
                return d;
            }
        </script>
    </head>
    
    <body>
        帳號: <input id="account" type="text" value="bruce" /><br />
        密碼: <input id="password" type="password" value="12345" /><br />
        參數1:<input id="num1" type="number" placeholder=0 /><br />
        參數2:<input id="num2" type="number" placeholder=0 /><br />
        <textarea id="ta"></textarea><br />
        <button onclick="jsCallWebService()">javascript AJAX call WebService</button>
    </body>
</html>

※getData方法我本來沒有提出來,run也是ok的,但提出來後出了「org.apache.cxf.binding.soap.SoapFault: Error reading XMLStreamReader: Unexpected character 'u' (code 117) in prolog; expected '<'」的錯
我試著將要傳的參數、帳密都寫死,然後不用「+」串接,也不換行,但還是出一樣的錯
最後我用一個變數來接,最後在return,就沒出錯了



※使用jQuery呼叫

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>Insert title here</title>
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
        <script type="text/javascript">
            function jsCallWebService() {
                const a = document.getElementById("account").value;
                const p = document.getElementById("password").value;
                const n1 = document.getElementById("num1").value;
                const n2 = document.getElementById("num2").value;
                var data = getData(a, p, n1, n2);
                        
                $.post(
                    "http://localhost:8080/SCXF/aaa/bbb/ccc", 
                    data,
                    function(result) {
                        var rtn = result.getElementsByTagName("return")[0];
                        var vue = rtn.firstChild.data;
                        document.getElementById("ta").value = vue;
                    }
                );
    
                //     $.ajax({
                //         type: "POST",
                //         url: "http://localhost:8080/SCXF/aaa/bbb/ccc",
                //         data: data,
                //         success: function(result){
                //             var rtn = result.getElementsByTagName("return")[0];
                //             var vue = rtn.firstChild.data;
                //             document.getElementById("ta").value = vue;
                //         }
                //     });
            }
            
            function getData(a, p, n1, n2){
                var d =
                    '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:test="http://test.hello/">' +
                        '<soapenv:Header>' +
                            '<login>' +
                                '<acc>' + a + '</acc>' +
                                '<pass>' + p + '</pass>' +
                            '</login>' +
                        '</soapenv:Header>' +
                        '<soapenv:Body>' +
                            '<test:add>' +
                                '<arg0>' + n1 + '</arg0>' +
                                '<arg1>' + n2 + '</arg1>' +
                            '</test:add>' +
                        '</soapenv:Body>' +
                    '</soapenv:Envelope>';
                return d;
            }
        </script>
    </head>
    <body>
        帳號: <input id="account" type="text" value="bruce" /><br />
        密碼:<input id="password" type="password" value="12345" /><br />
        參數1:<input id="num1" type="number" placeholder=0 /><br />
        參數2:<input id="num2" type="number" placeholder=0 /><br />
        <textarea id="ta"></textarea><br />
        <button onclick="jsCallWebService()">javascript AJAX call WebService</button>
    </body>
</html>

※註解是比較麻煩的寫法



※同源策略

localhost:8080改成「IP:8080」雖然不會出錯,但回傳就不會將值取出來了,用JS和jQuery都一樣

.什麼是同源策略可參考Mozilla 官網,網址列可將「en-US」改成「zh-TW」或「zh-CN」
總之就是http://www.google.com:80 分成三個部分
1.「http://」是protocol,還有ftp、https…等
2.「www.google.com」 是域名
3.「:80」是port,沒有寫就是:80
只要以上三個部分一樣,就是同源
現在大部分的瀏覽器預設都將 localhost 和轉換過的 IP 認為是不同的

.同源策略又衍生了 JSONP、CORS 技術
也就是同源策略不包括一些特定的標籤、如<script>標籤…等,其他的標籤上一個Mozilla 連結有寫
JSONP只能用在GET請求;CORS沒這個問題,但要較新的瀏覽器才有支援

.瀏覽器可關閉同源策略,可參考這個網址
我改IE 11是有成功的,但Chrome沒成功
使用chrome指令時先切換到chrome安裝資料夾,如我的安裝在「C:\Program Files (x86)\Google\Chrome\Application」,裡面有一支執行檔叫 chrome.exe ,切到這裡下指令即可
不然就要設環境變數了



※用HttpURLConnection可使localhost和IP一樣

package servlet;
    
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
    
@WebServlet("/conn")
public class Connection extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String a = request.getParameter("account");
        String p = request.getParameter("password");
        String n1 = request.getParameter("number1");
        String n2 = request.getParameter("number2");
        System.out.println(a + ":" + p + ":" + n1 + ":" + n2);
    
        String data = 
            "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:test='http://test.hello/'>" +
                "<soapenv:Header>" + 
                    "<login>" + 
                        "<acc>" + a + "</acc>" + 
                        "<pass>" + p + "</pass>" + 
                    "</login>"
                + "</soapenv:Header>" + 
                "<soapenv:Body>" + 
                    "<test:add>" + 
                        "<arg0>" + n1 + "</arg0>" + 
                        "<arg1>" + n2 + "</arg1>" + 
                    "</test:add>" + 
                "</soapenv:Body>" + 
            "</soapenv:Envelope>";
    
        URL url = new URL("http://192.168.0.10:8080/SCXF/aaa/bbb/ccc");
    
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");// 預設是GET
        connection.setDoOutput(true);// 往server端寫資料,預設是false
        connection.setDoInput(true);// 接收server端的資料,預設是true,所以可不寫
        connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
    
        // 向server端寫資料
        OutputStream out = connection.getOutputStream();
        out.write(data.getBytes("UTF-8"));
        out.close();
    
        int responseCode = connection.getResponseCode();
        if (responseCode == 200) {
            // 接收server端回傳的資料
            InputStream in = connection.getInputStream();
            System.out.println("in長度: " + in.available());
    
            // 將server端的資料給瀏覽器
            // 如給text/xml,那jQuery的dataType也必須是xml;給text/text,那jQuery的dataType也必須是text
            response.setContentType("text/xml;charset=UTF-8");
            ServletOutputStream sout = response.getOutputStream();
    
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                sout.write(buffer, 0, len);
            }
            sout.flush();
            in.close();
            sout.close();
        }
    }
}


※前端

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!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>Insert title here</title>
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
        <script type="text/javascript">
            function jsCallWebService() {
                $.post(
                    "conn",
                    {
                        account : $('#account').val(),
                        password : $('#password').val(),
                        number1 : $('#num1').val(),
                        number2 : $('#num2').val()
                    },
                    function(result) {
                        // var vue = $(result).find('return').text();
                        var rtn = result.getElementsByTagName("return")[0];
                        var vue = rtn.firstChild.data;
                        document.getElementById("ta").value = vue;
                    },
                    'xml'
                );
    
                //     $.ajax({
                //         type: "POST",
                //         url: "conn",
                //         data: {
                //             account : $('#account').val(),
                //             password : $('#password').val(),
                //             number1 : $('#num1').val(),
                //             number2 : $('#num2').val()
                //         },
                //         success: function(result){
                //            // var vue = $(result).find('return').text();
                //             var rtn = result.getElementsByTagName("return")[0];
                //             var vue = rtn.firstChild.data;
                //             document.getElementById("ta").value = vue;
                //         },
                //         dataType:'xml'
                //     });
            }
        </script>
    </head>
    
    <body>
        帳號: <input id="account" type="text" value="bruce" /><br />
        密碼: <input id="password" type="password" value="12345" /><br />
        參數1:<input id="num1" type="number" placeholder=0 /><br />
        參數2:<input id="num2" type="number" placeholder=0 /><br />
        <textarea id="ta"></textarea><br />
        <button onclick="jsCallWebService()">javascript AJAX call WebService</button>
    </body>
</html>

※$(result).find('return').text();使用在dataType是text時

※如果不寫dataType,jQuery預設是智能判斷,會找以下這5種 xml, json, script, text, html

2017年1月30日 星期一

ng-repeat、directive (angularJS 二)

※ng-repeat

迴圈功能

<html ng-app>
    <script type="text/javascript" src="angular.js"></script>
      
    <body>
        <div ng-init="xxx=[1,2,3]">
            <ul>
                <li ng-repeat="x in xxx">
                    {{x}}
                </li>
            </ul>
        </div>
    
        <div ng-init="ooo=[
            {o:'a',x:1},
            {o:'b',x:2},
            {o:'c',x:3}]">
    
            <table border=1>
                <tr>
                    <td ng-repeat="a in ooo">
                        {{a.o + '-' + a.x}}
                    </td>
                </tr>
            </table>
    
            <table border=5>
                <tr ng-repeat="a in ooo">
                    <td>
                        {{a.o + '-' + a.x}}
                    </td>
                </tr>
            </table>
        </div>
    </body>
</html>

※ng-repeat 看要針對哪一個標籤循環,就寫在哪裡,上面的例子有寫在 tr 和 td



※ng-repeat 配合 controller

<html ng-app='xxx'>
    <script type="text/javascript" src="angular.js"></script>
    
    <body>
        <table border=1 ng-controller='ccc'>
            <tr ng-repeat="list in lists">
                <td>
                    {{list.o}} - {{list.x}}
                </td>
            </tr>
        </table>
    </body>
    
    <script>
        var app = angular.module("xxx", []);
        app.controller('ccc', ($scope) => {
            $scope.lists = [
                {
                    o: 'a', x: 1
                }, {
                    o: 'b', x: 2
                }, {
                    o: 'c', x: 3
                }
            ];
        });
    </script>
</html>

※注意 ng-controller 的宣告至少要在ng-repeat的上一層



※directive的Element、Attribute、Class

restrict有以下四種,可以合在一起
E:Element
A:Attribute
C:Class
M:Comment
預設是AE,所以不寫restrict時,可以用在元素和屬性上
要注意取的名字在使用時是用駝峰命名,如smallApple,要使用時,就要用small-apple
以上大小寫都不能錯,如果大小寫錯了不會報錯,只是沒有作用而已


<html ng-app='xxx'>
    <script type="text/javascript" src="angular.js"></script>
    
    <body>
        <div good-boy>div</div>
        <good-boy>defined</good-boy>
        <p class='good-boy'>p</p>
    </body>
    
    <script>
        var app = angular.module("xxx", []);
        app.directive("goodBoy", () => {
            return {
                restrict : "AEC",
                template : '<h1>h</h1>'
            };
        });
    </script>
</html>

※裡面還有一個「replace」的屬性,但不是給這三個值用的,是給下面的comment用的,但如果寫了而且給false不會有作用
但如果給true,有可能會報「Template for directive 'tag name' must have exactly one root element. 」的錯,那是因為template裡面的值至少要有一個頂層標籤,以這個例子就是<h1>
假設我的template只寫h,且replace給true,就會報這個錯

※div、good-boy、p 標籤裡的文字(div、defined、p),只有在angular 讀不到時才會顯示,一讀到一定是覆蓋




※directive 之 comment

<html ng-app='xxx'>
    <script type="text/javascript" src="angular.js"></script>
    
    <body>
        <!-- directive: good-boy -->
        content...
    </body>
    
    <script>
        var app = angular.module("xxx", []);
        app.directive("goodBoy", () => {
            return {
                restrict : "M",
                replace : true,
                template : '<h1>h1</h1>'
            };
        });
    </script>
</html>

※replace是配合restrict為「M」時使用

※在html裡打上<!-- directive: 自定標籤名 -->後,不管replace給什麼,在原始檔裡都會顯示

※這裡的replace是要不要將註解的部分取代成template寫的東東,如給true就會在網頁顯示,但並不會將content...取代掉

2017年1月29日 星期日

ng-app、ng-init、ng-model、ng-bind、module、ng-controller (angularJS 一)

我用的是1.6.1版,之後都用這一版來試


※ng-app、ng-init、ng-model、ng-bind

ng-app:angularJS的啟始點
ng-init:初始值
ng-model:設定變數
ng-bind:挷定變數


<html>
    <script type="text/javascript" src="angular.js"></script>
    
    <body ng-app>
        <p>test1: <input ng-model="xxx1"></p>
        <p ng-bind="xxx1"></p>
    
        <p>test2: <input ng-model="xxx2"></p>
        <p>{{xxx2}}</p>
    
        <div ng-init="ooo1='bruce'">
            <p>test3:<span ng-bind="ooo1"></span></p>
        </div>
    
        <div data-ng-init="ooo2='bruce'">
            <p>test4:<span data-ng-bind="ooo2"></span></p>
        </div>
    
        <div ng-init="xox='00FF00'">
        <input style="color:{{xox}}" ng-model="xox" value='{{xox}}' />
    </body>
    
    <script>
        window.onload = () => {
            console.log(angular.version.full);
        }
    </script>
</html>

※ng-app會針對設定的範圍啟作用,如上是在body設置,所以整個body都會啟作用,假設設定在第一個p標籤,那只有第一個標籤會啟作用

※可以用「data-ng-」開頭取代「ng-」開頭,也可以一起使用

※ng-init、ng-model 就沒有範圍了,例如test2的{{xxx2}}改成{{xxx1}}是抓的到的

※angular.version是取版本用的

※xxx1和xxx2是有差別的,xxx2在網路較慢時,或按F5不放,有時會看到{{xxx2}}出現;xxx1不會



※ng-init 多個變數

<html>
    <script type="text/javascript" src="angular.js"></script>
    
    <body ng-app>
        <div ng-init="xxx='x';ooo='o'">
            <p>test1: <span ng-bind="xxx + ' ' + ooo"></span></p>
        </div>
    
        <div ng-init="init={xxx:'x',ooo:'o'}">
            <p>test2: <span ng-bind="init.ooo"></span></p>
        </div>
    
        <div ng-init="zzz=[0,1,2,3]">
            <p>test3: {{zzz[2]}}</p>
        </div>
    
        <div>
            <p>test4: <span ng-bind="zzz[2]"></span></p>
        </div>
    </body>
</html>

※ng-init可設定多個變數;但ng-model不行



※module、ng-controller

module:設定模組
ng-controller:設定控制器的範圍


<html>
    <script type="text/javascript" src="angular.js"></script>
    
    <body ng-app='xxx'>
        <div ng-controller='ooo'>
            p1: <input type='number' ng-model='p1'><br />
            p2: <input type='number' ng-model='p2'><br />
            <span>number:{{p1 + p2}}</span>
        </div>
    </body>
</html>
    
<script>
    var app = angular.module('xxx', []);
    app.controller('ooo', ($scope) => {
        $scope.p1= 1;
        $scope.p2= 2;
    });
</script>

※設定完p1和p2變數,可以重覆用很多次,如上但直接寫{{p1}}和ng-model="p1"都抓的到

※<script>那一段也可以寫在一支(或兩支)js,然後用<script src>加載進來

※var app可寫成一行

※angular.module 第一個參數為 module 名稱,第二個參數為依賴哪一些module,這個例子為沒有依賴

※ng-app取得設定的module

※設定好ng-controller的範圍後,就可以在裡面取得設定的變數,其中「$scope」是不能改的

※{{}}裡面是可以四則運算的,所以寫死的數字也是可以運行的

※angulars也有MVC:
M:scope,可在V和C使用
V:HTML
C:Javascript



※module 的依賴

<html>
    <script type="text/javascript" src="angular.min.js"></script>
    
    <body ng-app='xxx'>
        <div ng-controller='ooo'>
            p1: <input type='number' ng-model='p1'><br />
            p2: <input type='number' ng-model='p2'><br />
            <span>number:{{p1 + p2}}</span><br /><br />
    
            p3: <input type='number' ng-model='p3'><br />
            p4: <input type='number' ng-model='p4'><br />
            <span>number:{{p3 + p4}}</span><br /><br />
    
            p5: <input type='number' ng-model='p5'><br />
            p6: <input type='number' ng-model='p6'><br />
            <span>number:{{p5 + p6}}</span>
        </div>
    </body>
</html>
    
<script>
    var app = angular.module('xxx', ['xxx2', 'xxx3']);
    app.controller('ooo', ($scope, zzz, yyy) => {
        $scope.p1= 1;
        $scope.p2= 2;
        $scope.p3 = zzz.zzzMultiply2(20);
        $scope.p4 = zzz.zzzMultiply2(100);
        $scope.p5 = yyy.yyyAdd2(20);
        $scope.p6 = yyy.yyyAdd2(100);
    });
    
    angular.module('xxx2', []).service('zzz', function() {
        this.zzzMultiply2 = (x) => {
            return x + x;
        }
    });
    
    angular.module('xxx3', []).service('yyy', function() {
        this.yyyAdd2 = (x) => {
            return x + 2;
        }
    });
</script>

※sevice的功能是定義的字串可以在controller裡用,並且使用裡面的方法

※此例還可寫成xxx只依賴 xxx2 ,xxx2 又依賴 xxx3 ,此時的 xxx 還是能抓的到 yyy



※scope範圍


<html>
    <script type="text/javascript" src="angular.min.js"></script>
    
    <body ng-app='xxx'>
        <div ng-controller='ooo1'>
            <p>p1+p2:{{p1 + p2}}</p>
            <p>p3:{{p3}}</p>
            <p>number:{{p4 + p5}}</p>
            <p>p6:{{p6}}</p>
        </div>
        ------------------------------
        <div ng-controller='ooo2'>
            <p>p1+p2:{{p1 + p2}}</p>
            <p>p3:{{p3}}</p>
            <p>number:{{p4 + p5}}</p>
            <p>p6:{{p6}}</p>
        </div>
    </body>
</html>
    
<script>
    var app = angular.module('xxx', []);
    
    app.controller('ooo1', ($scope, $rootScope) => {
        $scope.p1= 1;
        $scope.p2= 2;
        $rootScope.p3=3;
    });
    
    app.controller('ooo2', ($scope, $rootScope) => {
        $scope.p4= 4;
        $scope.p5= 5;
        $rootScope.p6=6;
    });
</script>

※定了兩個controller,ooo1和ooo2,第一個div使用ooo1;第二個div使用ooo2,個別使用不同的範圍

※$scope 只能使用在 ng-controller 設定的範圍;而 $rootScope 沒有這種限制,哪裡都能使用

※如果$scope 和 $rootScope 都設一樣的變數,會以 $scope 為主

2017年1月26日 星期四

CXF 與 Spring 整合 ( WebService 四)

官網的maven 設定連結
官網的spring 設定連結

※pom.xml

<properties>
    <cxf.version>3.1.9</cxf.version>
    <spring.version>3.2.15.RELEASE</spring.version>
</properties>
    
<dependencies>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>${cxf.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

※Spring基本要兩個包,core和context,但因為要run server,所以還要加web包



※伺服器端

要整合Spring,伺服器端要Web專案才可以


※web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/applicationContext.xml</param-value>
</context-param>
    
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
    
<servlet>
    <servlet-name>cxf</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
    
<servlet-mapping>
    <servlet-name>cxf</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

※<servlet-class>的路徑在Servlet Transport能找到

※<servlet-class>的CXFServlet在cxf-rt-transports-http-x.x.x.jar裡面



※applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://cxf.apache.org/jaxws 
    http://cxf.apache.org/schemas/jaxws.xsd">
    
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    
    <!-- <bean id="hs" class="hello.test.HelloWS" /> -->
    <!-- <jaxws:endpoint implementor="#hs" address="/aaa/bbb/ccc" /> -->
    
    <jaxws:endpoint implementor="hello.test.HelloWS" address="/aaa/bbb/ccc" />
</beans>

※註解的部分是第二種方法

※address是要接在IP後的

※SEI和之前一樣

※cxf.xml在cxf-core-x.x.xjar裡面的「META-INF\cxf」

※cxf-servlet.xml在cxf-rt-transports-http-x.x.x.jar裡面的「META-INF\cxf」

※如果有cxf-extension-soap.xml,可在cxf-rt-bindings-soap-2.2.3.jar 裡面的「META-INF\cxf」找到

※執行後會自動run出如下的畫面

※所以整合後,原本的網址會變成:IP加上專案名稱

※wsdl如下:

※aaa/bbb/ccc 是在 applicationContext.xml 裡設定的

※完成後就可用類似 SoapUI的軟體測試



※用戶端

用一般的專案即可,不用用到web專案,當然要用也行
用wsimport 或 wsdl2java 產生用戶端程式碼後,裡面只有一隻interface


※applicationContext.xml

    
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:jaxws="http://cxf.apache.org/jaxws"
        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.xsd
        http://cxf.apache.org/jaxws 
        http://cxf.apache.org/schemas/jaxws.xsd">    
    
    <jaxws:client id="hws" 
        serviceClass="hello.test.IHelloWS"
        address="http://localhost:8080/SCXF/aaa/bbb/ccc" />
        
    <!--
        <bean id="hws" factory-bean="clientFactory" factory-method="create"/>
        <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
            <property name="serviceClass" value="hello.test.IHelloWS"/>
            <property name="address" value="http://localhost:8080/SCXF/aaa/bbb/ccc"/>
        </bean>
    -->
</beans>

※註解的部分是另外一種方法,看來CXF已幫我們寫好了,所以不一定要用jaxws的命名空間


※測試類

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
IHelloWS client = (IHelloWS) context.getBean("hws");
System.out.println(client.add(50, 20));
context.close();



※攔截器


伺服器端和用戶端的java檔和上一篇一樣


※用戶端的applicationContext.xml

<jaxws:client id="hws" 
    serviceClass="hello.test.IHelloWS"
    address="http://localhost:8080/SCXF/aaa/bbb/ccc">
    
    <jaxws:outInterceptors>
        <bean class="AddLoginInfo">
            <constructor-arg name="account" value="bruce" />
            <constructor-arg name="password" value="12345" />
        </bean>
    </jaxws:outInterceptors>
</jaxws:client>

※


※伺服器端的applicationContext.xml

<jaxws:endpoint implementor="hello.test.HelloWS" address="/aaa/bbb/ccc">
    <jaxws:inInterceptors>
        <bean class="hello.test.CheckLoginInfo" />
    </jaxws:inInterceptors>
</jaxws:endpoint>

※


2017年1月22日 星期日

CXF 攔截器 ( WebService 三)

JDK沒有攔截器的功能,但CXF有



※內鍵攔截器

以logging為例,如下:


※伺服器端

import java.util.List;
import javax.xml.ws.Endpoint;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.message.Message;
    
String url = "http://localhost:8888/aaa/bbb/ccc";
EndpointImpl publish = (EndpointImpl) Endpoint.publish(url, new HelloWS());
    
System.out.println("增加server in log");
List<Interceptor<? extends Message>> in = publish.getInInterceptors();
in.add(new LoggingInInterceptor());
    
System.out.println("增加server out log");
List<Interceptor<? extends Message>> out = publish.getOutInterceptors();
out.add(new LoggingOutInterceptor());
    
System.out.println("server is start!");

※注意import的包,CXF有很多同名的class,但package不同

※在網址打上xxx.wsdl就會執行伺服器端in的部分,在console會顯示

※out的部分可用第一篇的JavaClientCallWebService.java


※用戶端

import java.util.List;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.message.Message;
    
HelloWSService hws = new HelloWSService();
IHelloWS hw = hws.getHelloWSPort();
    
Client client = ClientProxy.getClient(hw);
System.out.println("增加client out log");
List<Interceptor<? extends Message>> out = client.getOutInterceptors();
out.add(new LoggingOutInterceptor());
    
System.out.println("增加client in log");
List<Interceptor<? extends Message>> in = client.getInInterceptors();
in.add(new LoggingInInterceptor());
    
System.out.println(hw.add(1, 2));

※使用wsimport或wsdl2java產生程式碼後,使用如上的程式碼,這前幾篇也有做過,只是多個中間攔截器的部分

※首先先向server端丟出訊息,因為現在寫的是用戶端,所以對用戶端來說是out,然後伺服器端的in會接收,在來是伺服器端的out,最後再丟回給用戶端的out,攔截器完成後,再印出程式碼



※自定攔截器


※用戶端

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ns2:add xmlns:ns2="http://test.hello/">
            <arg0>1</arg0>
            <arg1>2</arg1>
        </ns2:add>
    </soap:Body>
</soap:Envelope>

※內鍵攔截器的伺服器端的console有Inbound Message,裡面的Payload就是長這個樣子


※AddLoginInfo.java 

import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
    
public class AddLoginInfo extends AbstractPhaseInterceptor<SoapMessage> {
    private String account;
    private String password;
    
    public AddLoginInfo(String account, String password) {
        super(Phase.PRE_PROTOCOL); // 表示在轉換成SOAP之前
        this.account = account;
        this.password = password;
    }
    
    @Override
    public void handleMessage(SoapMessage msg) throws Fault {
        /**
         * <login> <acc></acc> <pass></pass> </login>
         */
        Document doc = DOMUtils.createDocument();
        Element loginEle = doc.createElement("login");
    
        Element accEle = doc.createElement("acc");
        accEle.setTextContent(account);
    
        Element passEle = doc.createElement("pass");
        passEle.setTextContent(password);
    
        loginEle.appendChild(accEle);
        loginEle.appendChild(passEle);
    
        List<Header> headers = msg.getHeaders();
        headers.add(new Header(new QName("login"), loginEle));
    
        System.out.println("客戶端的 handleMessage執行成功!");
    }
}

※繼承 AbstractPhaseInterceptor 並增加 SOAP 的 head

※QName裡的字串必需與createElement裡的字串一樣,表示要攔截login標籤,否則攔截不到


※測試

HelloWSService hws = new HelloWSService();
IHelloWS hw = hws.getHelloWSPort();
    
Client client = ClientProxy.getClient(hw);
System.out.println("增加client out log");
List<Interceptor<? extends Message>> out = client.getOutInterceptors();
out.add(new AddLoginInfo("bruce", "12345"));
    
System.out.println(hw.add(1, 2));

※將out的攔截器指向新增的AddLoginInfo


※伺服器端的console

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <login>
            <acc>bruce</acc>
            <pass>12345</pass>
        </login>
    </soap:Header>
    <soap:Body>
        <ns2:add xmlns:ns2="http://test.hello/">
            <arg0>1</arg0>
            <arg1>2</arg1>
        </ns2:add>
    </soap:Body>
</soap:Envelope>

※一樣是 Inbound Message 的 Payload,此時會印出新增的login


※伺服器端

import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
    
public class CheckLoginInfo extends AbstractPhaseInterceptor<SoapMessage> {
    public CheckLoginInfo() {
        super(Phase.PRE_PROTOCOL);
    }
    
    @Override
    public void handleMessage(SoapMessage msg) throws Fault {
        Header header = msg.getHeader(new QName("login"));
        if (header != null) {
            Element ele = (Element) header.getObject();
    
            NodeList acc = ele.getElementsByTagName("acc");
            String account = acc.item(0).getTextContent();
    
            NodeList pass = ele.getElementsByTagName("pass");
            String password = pass.item(0).getTextContent();
    
            if ("bruce".equals(account) && "12345".equals(password)) {
                System.out.println("驗證通過!");
                return;
            }
        }
    
        System.out.println("驗證未通過!");
        throw new Fault(new RuntimeException("帳號和密碼不正確"));
    }
}

※同樣繼承 AbstractPhaseInterceptor 並從head取出帳號和密碼


※server.java

String url = "http://localhost:8888/aaa/bbb/ccc";
EndpointImpl publish = (EndpointImpl) Endpoint.publish(url, new HelloWS());
    
List<Interceptor<? extends Message>> in = publish.getInInterceptors();
in.add(new CheckLoginInfo());
    
System.out.println("server is start!");

※因為客戶端丟過來,所以當然是用in去接

※此時輸入正確的帳密才會印出「call add method!」,否則就會被攔截器攔截並拋出例外

2017年1月19日 星期四

audio和video、progress和meter、details、mark、abbr、ruby (HTML5 三)

※audio、video

<audio controls autoplay muted loop preload=auto src=d:\01.ogg />
    
<audio controls autoplay muted loop preload=auto>
    <source src=d:\01.ogg type=audio/ogg />
    <source src=d:\20.mp3 type=audio/mp3 />
</audio>
    
<video width="320" height="240" controls poster=D:\images.jpg >
    <source src="movie.mp4" type="video/mp4">
    <source src="movie.ogg" type="video/ogg">
</video>

※
controls:是否要出現控制面版
autoplay:一進入頁面是否要自動播放
controls不設定,autoplay有設定,就是背景的功能

muted:是否要一開始是靜音
loop:播放完是否要重覆播放
preload:一進入頁面,加載檔案的方式,有三個合法值auto、metadata、none
.auto表示全部加載
.metadata表示加載一部分
.none表示都不加載
src:指定要播放的內容,如果不寫可以在audio新增子標籤source,如上的範例
source可以指定很多,並不是第一個播放完就播放第二個
它的功能是要給不同瀏覽器的相容問題使用的,因為每個瀏覽器支援的格式不同,在這裡指定多個,它會以第一個開始抓,可以播的就播了,以下就不管了

video標籤才有的屬性
除了width和height外,還有個poster,就是視頻格式都不支援時,顯示的圖片



※progress、meter

<progress></progress>
<progress max=1000></progress>
<progress value=60 max=100></progress>
<progress id=pro value=0 max=100></progress>
<br />
<meter></meter>
<meter min=0 max=1000></meter>
<meter value=60 max=100></meter>
<meter id=met value=0 min=-1000 max=1000 low=100 high=500 optimum=800></meter>
<script>
    var pro = document.getElementById('pro');
    var flag = true;
    setInterval(
        () => {
            if(pro.value >= 100) flag = false;
            if(pro.value <= 0) flag = true;
            
            if(flag && pro.value < 100){
                pro.value = pro.value + 20;
            }
    
            if(!flag && pro.value > 0){
                pro.value = pro.value - 20;
            }
        }
    , 100);
    
    var met = document.getElementById('met');
    var f = true;
    setInterval(
        () => {
            if(met.value >= met.max) f = false;
            if(met.value <= met.min) f = true;
    
            if(f && met.value < met.max){
                met.value = met.value + 20;
            }
    
            if(!f && met.value > met.min){
                met.value = met.value - 20;
            }
        }
    , 100);
</script>

※progress目前只有max和value兩個屬性

※meter除了max和value,還有min、low、high、optimum、form
其中low、high、optimum是跑的時候能顯示不同的顏色,有紅黃綠
optimum是指定最好的那一端



※details、mark、abbr


<details>
    I'm a <mark>mark</mark><br />
    You are a pig.
</details>
<br />
<details open>
    default <mark>open</mark>
</details>
<br />
<details open>
    <summary>Title</summary>
    I'm a <mark>mark</mark><br />
    <abbr title='World Wide Web Consortium'>W3C</abbr>
</details>

※
※mark會將字反黃

※details會多個倒三角形,可以點開,預設點開用open;標題用summary

※abbr專門為縮寫使用,可搭配title屬性讓滑鼠放上去時顯示,當然裡面不打縮寫也行,只是就失去了定義這個標籤的意義



※ruby


北京話:<br />
<ruby>
    柳 <rt> ㄌㄧㄡˇ </rt>
    邊 <rt> ㄅㄧㄢ </rt>
    求 <rt> ㄑㄧㄡˊ </rt>
    去 <rt> ㄑㄩˋ </rt>
    地 <rt> ㄉㄧˋ </rt>
</ruby>
<br />
<br />
閔南語:<br />
<ruby>
    柳 <rt> 丩二柳 </rt>
    邊 <rt> 堅一邊 </rt>
    求 <rt> 丩五求 </rt>
    去 <rt> 居三去 </rt>
    地 <rt> 雞七地 </rt>
</ruby>
<br />
<br />
Browser不支援時:
<ruby>
    柳 <rt><rp>(</rp>ㄌㄧㄡˇ<rp>)</rp></rt>
</ruby>

※亞洲用的,結果如下:
※不支援又想顯示要用rp標籤,且要用「(」「)」將想顯示的字包起來