2016年6月24日 星期五

annotation (DWR 六)

官網連結
也就是不寫dwr.xml,用annotation的方式一樣可以
前端取資料庫的 method為例,改成annotation

※web.xml

<servlet>
    <servlet-name>dwr-invoker</servlet-name>
    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>true</param-value>
    </init-param>
    
    <init-param>
        <param-name>classes</param-name>
        <param-value>
            dao.impl.DaoImpl,
            vo.Chess
        </param-value>
    </init-param>
</servlet>
    
<servlet-mapping>
    <servlet-name>dwr-invoker</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

※只有增加classes的init-param部分

※這裡增加impl和java bean,如果不寫會在執行時出「DefaultConverterManager convertOutbound」的錯



※impl

@RemoteProxy(name="dao")
public class DaoImpl implements Idao {
    @Override
    @RemoteMethod
    public boolean save(Chess chess) {
        System.out.println("新增成功!");
        return true;
    }
    
    @Override
    @RemoteMethod
    public Chess getChess(Long id) {
        Chess chess = new Chess();
        chess.setId(id);
        chess.setName("象棋");
        chess.setDate(new Date());
        return chess;
    }
    
    @Override
    @RemoteMethod
    public List<Chess> getAllChess() {
        List<Chess> chList = new ArrayList<>();
        for (long i = 1; i < 4; i++) {
            Chess chess = new Chess();
            chess.setId(i);
            if (i == 1) {
                chess.setName("象棋");
            } else if (i == 2) {
                chess.setName("跳棋");
            } else if (i == 3) {
                chess.setName("五子棋");
            }
            try {
                chess.setDate(new SimpleDateFormat("yyyyMMdd").parse("2010061" + i));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            chList.add(chess);
        }
        return chList;
    }
}

※class上多個@RemoteProxy,其他方法上面都是@RemoteMethod



※vo

@DataTransferObject
public class Chess{
    @RemoteProperty
    private Long id;
    
    @RemoteProperty
    private String name;
    
    @RemoteProperty
    private Date date;
    
    // setter/getter...
}

※java bean要轉換要使用@DataTransferObject,而欄位用@RemoteProperty

DWR3 整合 Spring3.x

官網連結

前端取資料庫的method為例



※pom.xml

<dependency>
    <groupId>org.directwebremoting</groupId>
    <artifactId>dwr</artifactId>
    <version>3.0.1-RELEASE</version>
</dependency>
    
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
    
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.2</version>
</dependency>
    
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>3.2.15.RELEASE</version>
</dependency>
    
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>3.2.15.RELEASE</version>
</dependency>
    
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>3.2.13.RELEASE</version>
</dependency>

※springMVC也要,因為listener是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>dwr</servlet-name>
    <servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>
    
<servlet-mapping>
    <servlet-name>dwr</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

※注意官方寫的順序有錯

※context-param裡的param-value要記得改



※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:dwr="http://www.directwebremoting.org/schema/spring-dwr"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
    
    <dwr:url-mapping />
    <bean class="dao.impl.DaoImpl">
        <dwr:remote javascript="dao">
            <!-- <dwr:exclude method="add" /> -->
            <dwr:include method="getChess" />
        </dwr:remote>
        <aop:scoped-proxy proxy-target-class="false" />
    </bean>
    
    <dwr:controller id="dwrController" debug="true">
        <dwr:config-param name="activeReverseAjaxEnabled" value="true" />
    </dwr:controller>
    
    <dwr:configuration>
        <dwr:convert type="bean" class="vo.Chess" javascript="ch" />
    </dwr:configuration>
    
    <dwr:annotation-scan base-package="dao.impl.DaoImpl, vo.Chess"
        scanDataTransferObject="true" scanRemoteProxy="true" />
</beans>

※<dwr:url-mapping />有時候會報錯,但不影響執行

※這些設定可以參考上面的「前端取資料庫的method」連結裡面的設定,只是寫法不同而已

※bean class還是不能寫interface

※<dwr:remote>裡面全部不寫就是全部方法都可以用,可以用debug看,dwr會有紅字提示

※include和exclude是加方法和排除方法的意思,兩者只能選其一

※include和exclude可以寫沒有定義的方法
寫在include裡,又沒寫其他的方法,那就表示沒有方法可以用
寫在exclude裡,又沒寫其他的方法,那就表示所有方法都可以用,也就是等於不寫

※dwr.xml可以整個刪除了

※更詳細的要看官網,我只寫其中一個方法而已

※annotation的部分用最下面的即可,寫法和第六篇的annotation一樣

2016年6月23日 星期四

上傳 (DWR 五)

※pom.xml

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.2</version>
</dependency>

※上傳功能要用到這個jar,也可以到官方提供的demo檔copy

※如果沒給jar還是可以起,但要用到時,會報「java.lang.UnsupportedOperationException: File uploads not supported」錯誤



※.java

@Override
public String dealWith(FileTransfer ft) {
    if (ft.getSize() != 0) {
        System.out.println("filename=" + ft.getFilename());
        System.out.println("mimeType=" + ft.getMimeType());

        WebContext ctx = WebContextFactory.get();
        System.out.println("contextPath=" + ctx.getContextPath());
        System.out.println("realPath=" + ctx.getServletContext().getRealPath("/"));
        try {
            ft.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "success!";
    }
    return "fail!";
}

※可以利用getMimeType()控制上傳的型態

※WebContext可以取得ContextPath和ServletContext



※.jsp

function fileUpload(){
    dao.dealWith(dwr.util.getValue('f'), {
        callback : function(rtn){
            dwr.util.setValue('sp', rtn);
        }
    });
}
----------
<input type="file" id="f" />
<input type="button" id="b" value="click me" onclick="fileUpload()" />
<span id="sp"></span>



※有進度條的上傳

要用到上一篇的activeReverseAjaxEnabled為true,所以web.xml要設定



※.java

public String dealWith(FileTransfer ft) {
    long size = ft.getSize();
    if (size != 0) {
        // 原始檔名
        String oFileName = ft.getFilename();
    
        // 隨機亂數 + 原始檔名
        String fileName = UUID.randomUUID() + "-" + oFileName.substring(oFileName.lastIndexOf("\\") + 1);
    
        // 檔案路徑
        String filePath = WebContextFactory.get().getServletContext().getRealPath("/") + "upload_file"
                + File.separator + fileName;
    
        // 建立檔案類別,順便產生必要的路徑
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
    
        Browser.withCurrentPage(new Runnable() {
            @Override
            public void run() {
                try (
                    InputStream input = ft.getInputStream();
                    OutputStream output = new FileOutputStream(file)
                ) {
                    byte bArray[] = new byte[1024];
                    int len = 0;
                    // 目前長度
                    int currentLen = 0;
                    while ((len = input.read(bArray)) != -1) {
                        // 為了方便看進度條有在動,所以用sleep
                        Thread.sleep(50);
    
                        output.write(bArray, 0, len);
                        currentLen += len;
                        // 百分比
                        double precent = Math.ceil(currentLen / (double) size * 100);
                        ScriptSessions.addFunctionCall("xxx", size, currentLen, precent);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        return "success!";
    }
    return "fail!";
}

※addFunctionCall的xxx要對應到前端的function



※.jsp

dwr.engine.setActiveReverseAjax(true) ;
dwr.engine.setNotifyServerOnPageUnload(true) ;
    
function fileUpload(){
    dao.dealWith(dwr.util.getValue('f'), {
        callback : function(rtn){
            dwr.util.setValue('sp', rtn);
        }
    });
}
    
function xxx(size , currlen , percent) {
    document.getElementById("bar").style.width = percent + "%";
    document.getElementById("bar").innerHTML = percent + "%";
    
    // HTML5
    // document.getElementById("progress").value = percent;
    // document.getElementById("person").innerHTML = percent + "%";
    
    document.getElementById("allLeng").innerHTML = currlen + " | " + size;
}
----------
<input type="file" id="f" />
<input type="button" id="b" value="click me" onclick="fileUpload()" />
<span id="sp"></span>
    
<div style="width: 352px; border: 1px solid black; height: 30px;">
    <i id="bar" style="background: pink; float: left; height: 100%;"></i>
</div>
    
<!--     HTML5 -->
<!--     <div> -->
<!--         <progress max="100" value="0" id="progress"></progress> -->
<!--         <i id="person"></i> -->
<!--     </div> -->
<span id="allLeng"></span>

※註解的部分為HTML5才有的進度條標籤

反向AJAX (DWR 四)

※web.xml

<servlet>
    <servlet-name>dwr-invoker</servlet-name>
    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>activeReverseAjaxEnabled</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>dwr-invoker</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

官網連結

※DaoImpl.java

public class DaoImpl implements Idao {
    @Override
    public void send(String msg, int c) {
        for (int i = 0; i < c; i++) {
            Browser.withAllSessions(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    DateFormat df = new SimpleDateFormat("ss");
                    ScriptSessions.addFunctionCall("xxx", msg + df.format(new Date()));
                }
            });
        }
    }
}

官網連結

※dwr.xml

<dwr>
    <allow>
        <create creator="new" javascript="dao">
            <param name="class" value="dao.impl.DaoImpl" />
        </create>
    </allow>
</dwr>


※index.jsp

<script type='text/javascript' src='/dwrTest/dwr/engine.js'></script>
<script type='text/javascript' src='/dwrTest/dwr/interface/dao.js'></script>
<script type='text/javascript' src='/dwrTest/dwr/util.js'></script>
----------
dwr.engine.setActiveReverseAjax(true);
dwr.engine.setNotifyServerOnPageUnload(true);
    
function xxx(m){
    var p = document.createElement('p');
    p.appendChild(document.createTextNode(m));
    $('sp').appendChild(p);
}
window.onload = dao.send("bruce is me ", 5);
----------
<span id="sp"></span>


2016年6月22日 星期三

開新視窗與回傳值

此篇介紹open、opener 和 showModalDialog

※open、opener


使用open、opener,主流的瀏覽器都有支援

※dad.html

function openWindow(){  
    window.open('son.html','_blank','height=400,width=400');  
}
----------
<form name="dadForm">
    <table>
        <tr>
            <td>
                <input type="button" value="開新視窗" onclick="openWindow()">
                <input name="ooo" value="999" />
                <input name="rtn" disabled="disabled" />
            </td>
        </tr>
    </table>
</form>

W3C文件有寫open有四個參數,第三個參數有很多,我只寫兩個,可以參考看看


※son.html

function closeWindow(){
    alert(document.sonForm.xxx.value);
    alert(window.opener.document.dadForm.ooo.value);
    // 將xxx的value給父視窗的rtn
    window.opener.document.dadForm.rtn.value = document.sonForm.xxx.value;
    window.close();
}
----------
<form name="sonForm">
    <table>
        <tr>
            <td><input name="xxx" value="20" /></td>
        </tr>
        <tr>
            <td>
                <input type="button" value="確認" onclick="closeWindow()">
            </td>
        </tr>
    </table>
</form>

※使用window.opener開頭可以呼叫父視窗的資料

※通常還有兩個事件比較常用
onunload:按右上角的X鈕會觸發
onbeforeunload:離開頁面就會觸發
注意呼叫window.close()會關閉視窗,關閉前會呼叫onbeforeunload方法,但onunload沒有呼叫到
按右上角的X兩個都會呼叫到

window.onunload = function(){
    // ...
}
    
window.onbeforeunload = function(){
    // ...
}

※內容還是可以用window.opener開頭呼叫爸爸的一些有的沒的

※其他事件可參考mozilla官網的WindowEventHandlers教學



※showModalDialog

IE有支援
參考資源

※和open、opener的差別主要有兩個

1.使用showModalDialog不能按右鍵
2.使用showModalDialog會將父視窗凍結起來

※dad.html

function modalDialog(){
    var rtn = window.showModalDialog('son.html', document.dadForm.ooo.value,'dialogHeight=400,dialogWidth=400');
    alert('return=' + rtn);
}
----------
<form name="dadForm">
    <table>
        <tr>
            <td>
                <input type="button" value="開新視窗" onclick="modalDialog()">
                <input name="ooo" value="999" />
                <input name="rtn" disabled="disabled" />
            </td>
        </tr>
    </table>
</form>

※第一個參數是必填,其他都是選填

※變數可以接收子視窗的回傳值

※第二個參數可以傳陣列,這樣就可以傳多個值了


※son.html

window.onload = function(){
    alert(window.dialogArguments);
}
    
function closeWindow(){
    alert(document.sonForm.xxx.value);
    // 將xxx的value給父視窗的rtn
    window.returnValue = document.sonForm.xxx.value;
    window.close();
}
----------
<form name="sonForm">
    <table>
        <tr>
            <td><input name="xxx" value="20" /></td>
        </tr>
        <tr>
            <td>
                <input type="button" value="確認" onclick="closeWindow()">
            </td>
        </tr>
    </table>
</form>

※window.dialogArguments可以接受父視窗的參數

※window.returnValue可以將值回傳給父視窗

※類似像showModalDialog的,我提供的超連結還有兩個showModelessDialog、show,這我沒研究,因為主流瀏覽器不是全部支援,應該是大同小異吧!

Util (DWR 三)

第一篇其實還有一個util,一樣把它複製到前端
官網連結

※id

document.getElementById('sp1').innerHTML = rtn;
$('sp1').innerHTML = rtn;
dwr.util.byId('sp1').innerHTML = rtn;

※上一篇的getElementById因為太長了,所以官方幫我們封裝起來了,有兩種方式,都是一樣的

※這兩種方式後面是用javascript的方法,還可以用util的setValue,後面會介紹



※getText和getValue

function test(id){
    alert('text=' + dwr.util.getText(id));
    alert('value=' + dwr.util.getValue(id));
    // alert('text=' + DWRUtil.getText('sp6'));
    // alert('value=' + DWRUtil.getValue('sp6'));
}
----------
<h1 id="sp1" onclick="test(this.id)">1</h1>
<input id="sp2" value="2222222222" onclick="test(this.id)" />
<span id="sp3" onclick="test(this.id)">3</span>
<div id="sp4" onclick="test(this.id)">4</div>
<textarea rows="30" cols="5" id="sp5" onclick="test(this.id)">5</textarea>
<select id="sp6" onchange="test(this.id)">
    <option value="oo">o1</option>
    <option value="xx">o2</option>
    <option value="zz">o3</option>
</select>
<input type="button" onclick="test(sp2)" />

※getText官網有說只能使用在下拉,我試的結果確實是這樣

※只要有屬性value,getValue都可以用,但記得要先將上面的getText註解掉,否則網頁出錯,就不會執行getValue了

※官網寫DWRUtil.getText,我試的結果不行(註解的部分),不管是getText和getValue,用dwr.util才是可以的(可能舊版本可以吧!)



※setValue

function test(id){
    // dwr.util.setValue(id, '<h1>xxx</h1>');
    dwr.util.setValue(id, '<h1>xxx</h1>', { escapeHtml:false });
}

※最後一個參數可以視情況加,功能是要不要忽略HTML



※addOptions和removeAllOptions

function addOption(id){
    // 方法一(value和text一樣)
    dwr.util.addOptions(id, ["aa", "bb", "cc"]);
    
    // 方法二(value和text一樣,但只抓xxx)
    var data = [{xxx:"aa"}, {xxx:"bb"}, {ooo:"cc"}];
    dwr.util.addOptions(id, data, "xxx");
    
    // 方法三(value和text可以不一樣,其中之一抓不到會是undefined,都抓不到不顯示)
    dwr.util.addOptions(
        id, 
        [{ooo:'a', xxx:'aa'},
         {yyy:'b', zzz:'bb'},
         {ooo:'c', xxx:'cc'}],
        'ooo', 'xxx');
    
    // 方法四(結果和方法一一樣)
    function opt(o) { 
        return o; 
    }
    dwr.util.addOptions(id, ["aa", "bb", "cc"], opt);
}
    
function removeAll(id){
    dwr.util.removeAllOptions(id);
}
----------
<select id="sp">
    <option value="oo">o1</option>
    <option value="xx">o2</option>
    <option value="zz">o3</option>
</select>
<input type="button" value="remove" onclick="removeAll('sp')" />
<input type="button" value="add" onclick="addOption('sp')" />

※不只有這些方法,以後有用到再研究



※從資料庫抓值後,顯示在前端的下拉

var oao;
dao.getAllChess({
    callback : function getAllChessCallback(rtnList){
        oao = rtnList;
        // dwr.util.addOptions('sp', rtnList, 'id', 'name');
    }
});
    
function getOptions(){
    dwr.util.addOptions('sp', oao, 'id', 'name');
}
----------
<input type="button" value="add" onclick="getOptions()" />

※按下按鈕就會顯示,如果要一進頁面就顯示,就不需要oao變數了



※addRows和removeAllRows

var i = 0;
function testAddRow(){
    var xxx = [
        function(d){return ++i},
        function(d){return d},
        function(d){
            return '<input type="button" value="click me" onclick="alert(\'hey\')" />';
        }
    ];
    dwr.util.setEscapeHtml(false);
    dwr.util.addRows('sp', ['aaa', 'bbb'], xxx);
    // dwr.util.addRows('sp', ['aaa', 'bbb'], xxx, {escapeHtml:false});
}
    
function testRemoveRow(){
    i=0;
    dwr.util.removeAllRows('sp');
}
----------
<input type="button" value="remove" onclick="testRemoveRow()" />
<input type="button" value="load" onclick="testAddRow()" />
<table id="sp">
    <tr>
        <th>A</th>
        <th>B</th>
        <th>C</th>
    </tr>
</table>

※第二個參數表示幾筆資料,裡面的值會傳到function的d,不一定要return這個值,但又不能不寫



※selectRange

function test(){
    dwr.util.selectRange("xxx", 4, 8);
}
----------
<input id="xxx" value="012345678911" onclick="test()" />

※從0開始,所以一按下會幫我們反白4567(最後的8不算),不知道這個功能要做什麼?



※onReturn

<form onsubmit="after()">
    <input onkeypress="dwr.util.onReturn(event, submitFunction)"/>
    <input type="submit" />
</form>
----------
function submitFunction(){
    alert('submit');
}
    
function after(){        
    alert('after');
}

※按下submit時,會執行after方法;而如果在text裡面按下enter時,會執行submitFuntion方法後,再執行after方法,也就是可以攔截submit的資料

2016年6月20日 星期一

前端取資料庫的 method (DWR 二)

※vo

public class Chess {
    private Long id;
    private String name;
    private Date date;
    // setter/getter...
}


※interface和Impl

public boolean save(Chess chess);
public Chess getChess(Long id);
public List<Chess> getAllChess();
    
    
    
@Override
public boolean save(Chess chess) {
    System.out.println("新增成功!");
    return true;
}
    
@Override
public Chess getChess(Long id) {
    Chess chess = new Chess();
    chess.setId(id);
    chess.setName("象棋");
    chess.setDate(new Date());
    return chess;
}
    
@Override
public List<Chess> getAllChess() {
    List<Chess> chList = new ArrayList<>();
    for (long i = 1; i < 4; i++) {
        Chess chess = new Chess();
        chess.setId(i);
        if (i == 1) {
            chess.setName("象棋");
        } else if (i == 2) {
            chess.setName("跳棋");
        } else if (i == 3) {
            chess.setName("五子棋");
        }
        try {
            chess.setDate(new SimpleDateFormat("yyyyMMdd").parse("2010061" + i));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        chList.add(chess);
    }
    return chList;
}

※模擬資料庫


※dwr.xml

<dwr>
    <allow>
        <create creator="new" javascript="dao">
            <param name="class" value="dao.impl.DaoImpl" />
        </create>
        <convert match="vo.Chess" converter="bean" javascript="ch" />
    </allow>
</dwr>

※bean不能亂打,這裡可參考官網



※index.html

var bean = {
    id : 100,
    name : "象棋",
    date : new Date()
};
    
//     dao.save(bean, saveCallback);
//     function saveCallback(rtn){
//         document.getElementById('sp1').innerHTML = rtn;
//     }
    
dao.save(bean, {
    callback : function saveCallback(rtn){
        document.getElementById('sp1').innerHTML = rtn;
    }
});
    
dao.getChess(100, {
    callback : function getChessCallback(rtn){
        document.getElementById('sp2').innerHTML = 
            rtn.id + "<br />" + 
            rtn.name + "<br />" + 
            rtn.date;
    }
});
    
dao.getAllChess({
    callback : function getgetAllChessCallback(rtnList){
        var sp3 = document.getElementById('sp3');
        for(var i=0; i<rtnList.length; i++){
            var temp = document.createElement('temp');
            temp.appendChild(document.createTextNode(
                rtnList[i].id + ", " + 
                rtnList[i].name + ", " + 
                rtnList[i].date
            ));
            sp3.appendChild(temp);
            sp3.appendChild(document.createElement("br"));
        }
    }
});
----------
<h1 id="sp1"></h1>
<h2 id="sp2"></h2>
<h3 id="sp3"></h3>



上一篇的xxx,這裡已經改dao了,要注意,先設定dwr.xml,然後debug=true確定有看到再寫



這次的專案圖:

2016年6月16日 星期四

Hello DWR (DWR 一)

※下載

DWR首頁


下載jar包,而demo要不要下看個人喜好,裡面是範例
也可以用下面maven的方式,但其實啟動伺服器時,還會報缺common jar包的錯,還得再下載(也可以複製官網WAR裡的jar)
我將我沒出錯的pom貼在下面

<dependency>
    <groupId>org.directwebremoting</groupId>
    <artifactId>dwr</artifactId>
    <version>3.0.1-RELEASE</version>
</dependency>
    
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>




選擇左邊的Documentation-->Index
下面一點會看到web.xml和dwr.xml,還有dwr內容的教學



※設定

將上面的web.xml和dwr.xml複製到專案裡,dwr主要是要上面的DTD
然後寫一支interface和實作
我將程式碼貼在下面

※Idao和DaoImpl

package dao;
public interface Idao {
    public String helloDWR(String name);
}
    
    
    
package dao.impl;
import dao.Idao;
public class DaoImpl implements Idao {
    public String helloDWR(String name) {
        return new StringBuffer().append("Hello ").append(name).toString();
    }
}



※web.xml

<servlet>
    <servlet-name>dwr-invoker</servlet-name>
    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>dwr-invoker</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>



※dwr.xml

<dwr>
    <allow>
        <create creator="new" javascript="xxx">
            <param name="class" value="dao.impl.DaoImpl" />
        </create>
    </allow>
</dwr>

※new和class不能亂打

※雖然有定interface,但是只能打impl,否則會報錯



※啟動伺服器

web.xml有設定debug是true
所以啟動伺服器後
網址如下http://localhost:8080/dwrTest/
dwrTest是我的專案名稱(你不一定是取這個名稱)
再後面加個dwr,會自動變成http://localhost:8080/dwrTest/dwr/index.html
就會出現如下的畫面,debug一定要true,不然會404


dwr.xml裡的javascript="xxx"會出現,點進去後




我標紅色的地方會出現剛剛寫的方法名稱,裡面就是要寫的參數,右邊還有Execute按鈕可看結果


※使用dwr.xml裡的xxx

※index.jsp

<%
    String path = new StringBuffer()
        .append(request.getScheme())
        .append("://")
        .append(request.getServerName())
        .append(":")
        .append(request.getServerPort())
        .append(request.getContextPath())
        .toString();
%>
    
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type='text/javascript' src='<%=path%>/dwr/engine.js'></script>
    <script type='text/javascript' src='<%=path%>/dwr/interface/xxx.js'></script>
    <script type="text/javascript">
        xxx.helloDWR("DWR", helloDWRCallBack);
        function helloDWRCallBack(rtn){
            document.getElementById('sp').innerHTML = rtn;
        }
    </script>
</head>
<body>
    <h1 id="sp"></h1>
</body>

※<script>那兩行是從debug=true裡面複製的,但我給它絕對路徑(第二張圖的getting started裡面有寫)
p.s 也可以完全不改,直接貼上也是可以run,此時就可以不用最上面的scriptlet了

※在javascript裡可以直接使用xxx,因為已經在dwr.xml裡已經new過了,第二個參數是回傳值,回傳值要寫一個function,名稱可以隨便取,對應好即可

這兩個誰在上面或下面都可以,但也可以合在一起,如下:
xxx.helloDWR("DWR", {
    callback : function helloDWRCallBack(rtn){
        document.getElementById('sp').innerHTML = rtn;
    }
});

※也就是第二個參數變成「{callback : function}」

※因為helloDWRCallBack沒有被其他地方使用,還可以不取名,也就是變成匿名函數

※除了callback外,還有很多,請參考官網