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標籤,且要用「(」「)」將想顯示的字包起來

FreeMaker Hello World

官網連結


<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.25-incubating</version>
</dependency>
--------------------
public class Clazz {
    private Integer cid;
    private String cname;
    private Set<Student> setStudent = new HashSet<>();
    private Map<String, String> map = new HashMap<>();
    
    // setter/getter...
}
--------------------
public class Student {
    private Integer sid;
    private String sname;
    
    // setter/getter...
}

※new一個簡單的project就可以了,因為我想測試List,所以寫個一對多的java Bean



Configuration cfg = new Configuration(Configuration.VERSION_2_3_25);
cfg.setDirectoryForTemplateLoading(new File("src/main/java/resources"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
    
// 單一
Map<String, Object> root = new HashMap<>();
root.put("xxx", "bruce");
root.put("ifElse", 2);
    
// 一對多
Clazz clazz = new Clazz();
clazz.setCid(1);
clazz.setCname("a");
    
Set<Student> set = new HashSet<>();
Student stu1 = new Student();
stu1.setSid(101);
stu1.setSname("aaa");
    
Student stu2 = new Student();
stu2.setSid(102);
stu2.setSname("bbb");
    
Student stu3 = new Student();
stu3.setSid(103);
stu3.setSname("ccc");
    
set.add(stu1);
set.add(stu2);
set.add(stu3);
    
clazz.setSetStudent(set);
    
// Map
Map<String, String> map = new HashMap<>();
map.put("I", "1");
map.put("II", "2");
map.put("III", "3");
clazz.setMap(map);
    
root.put("ooo", clazz);
Template temp = cfg.getTemplate("xxx.ftl");
Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);

※Configuration一些有的沒的,可到官網複製

※這裡要注意setDirectoryForTemplateLoading("")和Template temp = cfg.getTemplate("xxx.ftl")
一個設定資料夾,一個設定檔案,ftl就是下面的HTML格式,不一定要要HTML格式,副檔名也不一定要叫ftl,只要裡面是純文本即可


<html>
    <head>
        <title>This is a Test!</title>
    </head>
    <body>
        xxx = ${xxx}
    
        <#if ifElse == 1>
            是1
        <#elseif ifElse == 2>
            是2
        <#else>
            不是1,也不是2
        </#if>
    
        cid = ${ooo.cid}
        Clazz = ${ooo}
        cname = ${ooo.cname}
    
        <#-- 我是註解 -->
        <#-- ${ooo.setStudent.sid} list不能這樣用-->
    
        <#list ooo.setStudent as item>
            ${item.sid}
        </#list>
    
        <#-- Map 2.3.25(含) 以上才能用 -->
        <#list ooo.map as k, v>
            ${k} - ${v}
        </#list>
    
    </body>
</html>

※if else 好像不能判斷字串,一執行都會錯,但我是直接點if else的超連結,沒有每一篇都看

※此次專案的圖如下:


2017年1月15日 星期日

架設CXF、WSDL格式、SOAP格式 ( WebService 二)

※架設CXF

apache官網下載CXF框架,下載ZIP的
然後將lib裡面的jar檔通通複製到專案裡
啟動server的程式碼和上一篇一樣,但Console不太一樣了

本來只有黑色的字,現在會發現有jetty和cxf的字

啟動server的Endpoint.publish的回傳值,用JDK是「com.sun.xml.internal.ws.transport.http.server.EndpointImpl」,但用了CXF後會變成「org.apache.cxf.jaxws.EndpointImpl」

JDK是不能回傳Map的,我用java8都還是不行;在啟動伺服器端的程式時,會報「GetXXXResponse do not have a property of the name return」,但用CXF是可以的,但此時用wsimport生成的程式碼,回傳的不是Map,寫test時用法如下:

HelloWSService hws = new HelloWSService();
IHelloWS hw = hws.getHelloWSPort();
    
Return map = hw.getMap();
List<Entry> entry = map.getEntry(); // map.entry
for (Entry e : entry) {
    System.out.println(e.getKey());
    System.out.println(e.getValue());
}

※map.entry和map.getEntry()都可以,但map.entry是protected;map.getEntry()是public,


在下載下來的資料夾裡,有個bin資料夾,裡面都是一些轉換的工具,這裡使用wsdl2java,當然要先在環境變數裡設定,用法和JDK的差不多,雖然用法可以用wsdl2java -h,但還可以看官網的表格比較清楚

此時下wsdl2java -d D:\xxx http://localhost:8888/aaa/bbb/ccc?wsdl,不用加-keep就有java檔了,其他測試方法和上一篇一樣,如果不想加-d就先切換到想生成的路徑

但此時還有一個地方不太一樣,就是wsdl的格式稍有不同
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://test.hello/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloWSService" targetNamespace="http://test.hello/">
    <wsdl:types>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://test.hello/" elementFormDefault="unqualified" targetNamespace="http://test.hello/" version="1.0">
            <xs:element name="add" type="tns:add"/>
            <xs:element name="addResponse" type="tns:addResponse"/>
            <xs:element name="hello" type="tns:hello"/>
            <xs:element name="helloResponse" type="tns:helloResponse"/>
            <xs:complexType name="hello">
                <xs:sequence/>
            </xs:complexType>
            <xs:complexType name="helloResponse">
                <xs:sequence/>
            </xs:complexType>
            <xs:complexType name="add">
                <xs:sequence>
                    <xs:element minOccurs="0" name="arg0" type="xs:int"/>
                    <xs:element name="arg1" type="xs:int"/>
                </xs:sequence>
            </xs:complexType>
            <xs:complexType name="addResponse">
                <xs:sequence>
                    <xs:element minOccurs="0" name="return" type="xs:string"/>
                </xs:sequence>
            </xs:complexType>
        </xs:schema>
    </wsdl:types>
    <wsdl:message name="hello">
        <wsdl:part element="tns:hello" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="helloResponse">
        <wsdl:part element="tns:helloResponse" name="parameters"></wsdl:part>
    </wsdl:message>
        <wsdl:message name="addResponse">
        <wsdl:part element="tns:addResponse" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="add">
        <wsdl:part element="tns:add" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:portType name="IHelloWS">
        <wsdl:operation name="hello">
            <wsdl:input message="tns:hello" name="hello"></wsdl:input>
            <wsdl:output message="tns:helloResponse" name="helloResponse"></wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="add">
            <wsdl:input message="tns:add" name="add"></wsdl:input>
            <wsdl:output message="tns:addResponse" name="addResponse"></wsdl:output>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="HelloWSServiceSoapBinding" type="tns:IHelloWS">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="hello">
            <soap:operation soapAction="" style="document"/>
            <wsdl:input name="hello">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="helloResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="add">
            <soap:operation soapAction="" style="document"/>
            <wsdl:input name="add">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="addResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="HelloWSService">
        <wsdl:port binding="tns:HelloWSServiceSoapBinding" name="HelloWSPort">
            <soap:address location="http://localhost:8888/aaa/bbb/ccc"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

※types下的schema本來是import的,現在直接寫出來了



※WSDL格式

<definitions>
    <types>
        <xsd:schema>
            <xsd:import />(裡面是<element>)
        </xsd:schema>
    </types>
    <message>
        <part />
    </message>
    <message>
        <part />
    </message>
    <portType>
        <operation>
            <input />
            <output />
        </operation>
    </portType>
    <binding>
        <soap:binding />
        <operation>
            <soap:operation />
            <input>
                <soap:body />
            </input>
            <output>
                <soap:body />
            </output>
        </operation>
    </binding>
    <service>
        <port>
            <soap:address />
        </port>
    </service>
</definitions>

※必須有XML schema 基礎

※types:定義XML約束,方法的名稱、參數、回傳值
message:一個方法會有兩個,會對應到types裡的約束
portType:介面類型
binding:綁定介面的實作
service:一組服務

※從service開始由下往上,一層一層解析

※types > schema > element
message > part          part連到element
portType > operation > input/ouput          input/output連到message
binding > operation > input/output          bingding連到portType
service > port > addrress          port連到binding
由service的name屬性開始解析



※SOAP格式

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:test="http://test.hello/">
    <soapenv:Header/>
    <soapenv:Body>
        <test:add>
            <arg0></arg0>
            <arg1></arg1>
        </test:add>
    </soapenv:Body>
</soapenv:Envelope>
--------------------
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ns2:addResponse xmlns:ns2="http://test.hello/">
            <return>Answer is 100</return>
        </ns2:addResponse>
    </soap:Body>
</soap:Envelope>

※從WSDL解析出來的XML,可以讓java做轉換

※上面是Request;下面是Response

※基本上很像HTML,HTML下有HEAD和BODY;SOAP是ENVELOPE下有HEADER和BODY,BODY裡有請求的方法或回傳值


2017年1月13日 星期五

form屬性、input屬性、base、input type (HTML5 二)

※form屬性、input屬性

HTML5的form的屬性目前新增兩個autocomplete、novalidate,這兩個input屬性也可使用,且會覆蓋form的屬性

※form

<form id=twoForm action=xxx.action></form>
<form id=oneForm action=ooo.action></form>
    
<input name=a value=aaa form=oneForm />
<input name=b value=bbb form=oneForm />
<input type=submit value=登入 form=oneForm />
<br />
<input name=c value=ccc form=twoForm />
<input name=d value=ddd form=twoForm />
<input type=submit value=登入 form=twoForm />

※之前要提交的內容都要寫在form裡面,現在可以不用
要提交的內容有一個屬性form,對到form的id名稱即可,用name不行

※form不要寫成<form action=xxx.action />


※formaction

<form id=xxx action=xxx.action></form>
    
<input type=submit value=增 form=xxx formaction=add.action />
<input type=submit value=刪 form=xxx formaction=del.action />
<input type=submit value=改 form=xxx formaction=upd.action />
<input type=submit value=查 form=xxx formaction=que.action />

※之前一個form要提交,想做多件事,都要取個name屬性名稱,然後在後端判斷這個字再做不同的事

※利用formaction屬性可以提交到不同的地方,當然同一個地方又有不同的事,還是要判斷

※formaction屬性會覆蓋屬性form連到的form id,所以這個例子的form id=xxx是沒有作用的

※input、button才有此屬性


※formmethod

input、button 才有此屬性,可以指定post、get方法,會覆蓋form的method屬性


※placeholder

input 和 textarea 才有此屬性,功能是給預設值


※autofocus

頁面一載入,就會將游標停在指定的地方,但如果裡面有值,假設是abc,那游標會停在a的左邊

如果有多個autofocus,只會抓取第一個


※autocomplete

輸入過後,要不要顯示之前打過的功能
屬性值是on和off,只有form和input才有此屬性

如果是form的autocomplete給on,那就代表屬於此form的資料通通都有此功能


※list


<input list=ooo />
    
<datalist id="ooo">
    <option value="param1">
    <option value="param2">
    <option value="param3">
</datalist>


※只有input有此屬性

※和autocomplete一樣的地方是,以此例而言,可以打pa後再選
和autocomplete不一樣的地方是,只會出現datalist裡的內容

※如果和autocomplete連用,除了datalist一定會有外,設定on還會加上曾經打過的值


※required、novalidate、formnovalidate

<form id=xxx action=xxx.action novalidate></form>
    
<input name=a required form=xxx />
<input type=submit form=xxx />

※只要加上required就表示欄必輸,按提交鈕時會驗證
但如果在form加上novalidate或者在input type=submit加上formnovalidate就不會驗證
驗證時有基本的訊息,但並不是很清楚是哪個欄位,可設定title屬性,這樣驗證時也會包括title裡的字串


※formenctype

form有個屬性enctype,之前就有了,有以下三個值
application/x-www-form-urlencoded:預設值,會對文字編碼
multipart/form-data:不會對文字編碼,上傳時必用
text/plain:空格轉成「+」,不會編碼

現在因為form的內容可以不在裡面寫,也就是可以有多個input type=submit
所以多了個formenctype


※formtarget

form有個屬性target,之前就有了,有以下四個值
_blank:在新視窗打開
_self:預設值,在目前框架打開
_parent:在父框架打開
_top:在整個窗口打開

現在因為form的內容可以不在裡面寫,也就是可以有多個input type=submit
所以多了個formtarget


※step

input type=number時使用,假設step=5,那就只能是5的倍數
要注意number不能打小數點,但負的可以


※min、max

<form id=xxx action=xxx.action></form>
    
<input type=date name=a max=1855-07-31 form=xxx required /><br />
<input type=date name=b min=2010-01-10 form=xxx required /><br />
<input type=number name=c min=1 max=5 form=xxx required /><br />
<input type=submit form=xxx />

※只能使用在input type=number和date



※base


<base href="http://localhost:8080/xox/" target="_blank">
    
<img src=ooo.jpg >
<a href=http://www.google.com>Google</a>
<a href=xxx>xxx</a>

※功能是可以在網址加上前綴

※就只有兩個屬性,target和上面介紹的一樣

※因為base為http://localhost…,所以ooo.jpg和xxx的前面自動會加上前綴

※Google的超連結因為網址打齊了,所以不會在前面加前綴



※input type

HTML5的type,新增了14個,color、date、datetime、datetime-local、email 、image、month 、number 、range 、search、tel、time 、url、week
並不是每個它都有範例的,有些我也沒悟出來,且我只用Chrome試而已


<form id=xxx action=xxx.action></form>
date:年月日<input type="date" form=xxx name=date /><br />
time:時分秒<input type="time" form=xxx name=time /><br />
datetime:沒試出來<input type="datetime" form=xxx name=datetime /><br />
datetime-local:年月日時分秒<input type="datetime-local" form=xxx name=datetime-local /><br />
month:年月<input type="month" form=xxx name=month /><br />
week:年星期<input type="week" form=xxx name=week /><br />
<br />
number:只能打出[正|負]整數<input type="number" form=xxx name=number /><br />
email:x@x<input type="email" form=xxx name=email /><br />
tel:須配合pattern<input type="tel" form=xxx pattern=\d{4}-\d{3}-\d{3} name=tel /><br />
url:http://x<input type="url" form=xxx name=url /><br />
<br />
color:選顏色,提交後是「%23+6個16進制」,但預設值的「%23」要打「#」<input type="color" form=xxx name=color value=#800080 /><br />
image:有submit的功能,提交後是name.x和name.y,自己寫的submit並不會包括這一個,所以它有自己的submit<input type="image" form=xxx name=image /><br />
range:拖曳範圍<input type="range" form=xxx min=-500 max=1000 name=range /><br />
search:沒試出來<input type="search" form=xxx name=search /><br />
<input type=submit form=xxx />

※畫面如下


※送出後的網址列
date=2017-01-02
time=22%3A04  -->22:04
datetime=xxx
datetime-local=2017-01-04T00%3A00  2017/01/04 00:00
month=2017-01
week=2017-W01  -->2017年,第01週
number=2
email=xxx.ooo%40gmail.com  -->xxx.ooo@gmail.com
tel=0800-222-333
url=http%3A%2F%2Fwww.google.com  -->http://www.google.com
color=%23800080
range=1000
search=sdf

※可得知
:=%3A
日期時間之間用T
@=%40
/=%2F
#=%23

※在javascript可以使用encodeURIComponent(':@/#');轉成%xxx
使用decodeURIComponent('%3A%40%2F%23');轉成符號

※但通常都是傳到後端的,所以js只能測試用,以下是java的轉換

try {
    String encode = URLEncoder.encode(":@/#", "UTF-8");
    System.out.println(encode); // %3A%40%2F%23
    
    String decode = URLDecoder.decode(encode, "UTF-8");
    System.out.println(decode); // :@/#
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

※java.net包下的工具

※range看不到數字目前是多少,可以搭配其他標籤顯示出來,例如HTML5還有一個output標籤,不能修改內容的,也沒有框框,如下配合使用


<input type="range" form=xxx min=-500 max=1000 name=range value=300 onchange=out.value=value />
<output id=out>300</output>

※預設值兩個都給300,然後拖曳後放開滑鼠就會改變,onchange裡面可以寫js,以前就有了,所以如果無效可以用
document.getElementById(out).value = this.value

※type=file在以前就有了,但屬性有變多
<input type=file accept=image/* multiple />
※ 可以利用accept上傳指定的文件;multiple可上傳多個

2017年1月12日 星期四

多種div、自定標籤、IE9以下支援、屬性值 (HTML5一)

W3C官網連結


※多種div

div可以化成8種標籤:header、section、footer、aside、nav、main、article、figure
因為以前只要不知道用什麼標籤,就用div或span,所以整個畫面看起來看混亂,所以現在還可以用這8種,當然你要亂用也行,反正就是div,只是畫面會好看一些,如下:
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    
    <body>
        <header>開頭</header>
        <main>主要內容</main>
        <footer>結尾</footer>
    </body>
</html>
--------------------
<header>開頭</header>
<main>
    主要內容
</main>
<footer>結尾</footer>

※虛線下是更簡變的寫法,可以把html head body,甚至是doctype都可以省略



※自定標籤


<style>
    xxx {
        display: block;
        background-color: #FF0000;
        font-size: 30px;
    } 
</style> 
<xxx>123456</xxx>

※自定一個叫xxx的標籤,和以前的css一模一樣,只是自己定一個標籤名而已



※IE9以下的支援

<head>
    <!--[if lt IE 9]>
        <script src="官網提供的js路徑"></script>
    <![endif]-->
</head>

※HTML5只有支援IE9(含)以上版本

※中間的js要到官網下載,或者直接打上http的路徑

※除了這一段打在head裡外,還必須把doctype html head body都顯式的打出來才行



※屬性值


<input value=xxx>
<input value="xxx ooo">
<input value='xxx ooo'>
    
<input value="a" disabled="disabled">
<input value="b" disabled="true">
<input value="c" disabled="">
<input value="d" disabled>

※屬性值可以不打「'」和「"」,但有空格或一些特殊符號還是要加

※boolean如上的四種寫法都是true(當然「'」「"」或不加也OK),其他都是false

2017年1月10日 星期二

Debug PL SQL

以 PL/SQL Developer為例
1.用Command Window叫出想debug的procedure或function,然後在行數按右鍵有一些功能可以用,如下:

紅x才是debug,按Set Breakpoint就會出現,或按行數的數字也會出現
綠0是書籤,按Set Bookmark就會出現,或按行數的左邊空白的地方也會出現
Goto Bookmark會出現有設定的點


2.在procedure或function的名稱按右鍵test會出現如下的畫面

先在下面的紅框打上要測的資料,如果是procedure,out的部分不用打,然後按左上角的鑰匙就會到debug處


到debug處後,左下角有如下的圖
可以在Variable打上這個procedure或function的變數名,如果有找到,右邊的Value會自動出現內容,Variable也可以打Record的變數,例如:rec.xxx