DWR的宣传语是 “ Easy Ajax For Java”。
需求是这样的--后端定时接受服务器发送过来的信息。并把信息每隔五秒推送一次到前端实现页面局部刷新功能!
AJAX可是实现前端异步发送请求到后端,拿取数据,并实现页面局部刷新的功能!
Ajax有一个很大的缺陷就是“无法满足传统桌面系统的需求——服务器端需要向客户端主动发送消息”。服务端推送技术的应用场景有很多!
DWR框架技术可以实现即时推送后端数据到客户端。
因为这个功能。我是帮别人做的。他用的框就是springmvc.也没用maven做管理。所以步骤如下:
1:引入jar包
dwr.jar commons-logging-1.1.3.jar quartz-2.3.0.jar quartz-jobs-2.2.3.jar spring-context-support-4.0.0.RELEASE.jar
2:配置文件配置相关DWR框架支持
web.xml配置。配置类似DispatchServlet的配置
<!-- dwr配置信息start -->
<servlet>
<!-- 指定DWR核心Servlet的名字 -->
<servlet-name>dwr</servlet-name>
<!-- 指定DWR核心Servlet的实现类 -->
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<!-- 指定DWR核心Servlet处于调试状态 -->
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<!-- 设置使用反向Ajax技术 -->
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>initApplicationScopeCreatorsAtStartup</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<!--长连接只保持时间 -->
<param-name>maxWaitAfterWrite</param-name>
<param-value>60</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 指定核心Servlet的URL映射 -->
<servlet-mapping>
<servlet-name>dwr</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<!-- dwr配置信息end -->
<!--对静态文件和页面不拦截-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
dwr.xml文件配置。放在和web.xml同目录。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
"http://getahead.org/dwr/dwr20.dtd">
<dwr>
<!-- DWR可以创建和转换的类 -->
<allow>
<!-- 指定用哪种创造器 -->
<create javascript="Message" creator="new" scope="application"><!-- application -->
<include method="addMessage"/> <!--只对前端开房addMessage方法-->
<param name="class" value="com.zukai.test.Message"></param>
</create>
</allow>
</dwr>
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
<!-- <bean id="udpClient" class="com.zukai.connection.udp.UDPClient" init-method="recv"/> -->
<!-- 业务实体 -->
<bean name="quartzTest" class="com.zukai.test.QuartzTest" init-method="recv"/>
<!-- 定义定时任务 -->
<bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="quartzTest"></property><!-- 目标对象 -->
<property name="targetMethod" value="pushRefresh"></property><!-- 目标方法 -->
<property name="concurrent" value="false"></property><!-- 多job并发设置 -->
</bean>
<!-- 定义触发器 -->
<bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="quartzTestJob"/>
<!--延时多少秒后执行,这里不延时 0秒后运行 -->
<property name="startDelay" value="0" />
<!-- 每隔5秒重复运行 -->
<property name="repeatInterval" value="5000" />
</bean>
<!-- 定义定时调度 -->
<bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="quartzTestTrigger" />
</list>
</property>
</bean>
</beans>
上面是引入定时任务的配置信息。每5秒执行一次冲服务器获取数据信息。代码如下:
package com.zukai.test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
*author:liyy
*date:2018年10月9日
*描述信息:
*/
@Component
public class QuartzTest {
public static Logger logger = LoggerFactory.getLogger(QuartzTest.class);
public static Map<String,Object> mapCache = new ConcurrentHashMap<>();
public static DatagramSocket ds = null;
//每隔五秒調用一次,获取数据推送到页面
public void pushRefresh() throws IOException, InterruptedException {
Message mg = new Message();
String message = null;
if(mapCache.containsKey("message")){
message = (String)mapCache.get("message");
mg.addMessage("admin", message+"瓦"+","+message+"度");
}
}
//获取UDP服务器发送的数据,并存储到mapCache里面。
public void recv(){
new Thread(new ReceiveThread()).start();
}
public void schedule(){
//注意这里就是可以进行数据库的查询操作,可以将查询需要推送的信息放到第二个参数,第一个参数自然是我们要指定推送的表示用户
Message mg = new Message();
for(int i=0;i<100;i++){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mg.addMessage("admin", i+1000+"瓦"+","+i+30+"度");
}
}
private String bytesToHex(byte[] bytes, int begin, int end) {
StringBuilder hexBuilder = new StringBuilder(2 * (end - begin));
for (int i = begin; i < end; i++) {
hexBuilder.append(Character.forDigit((bytes[i] & 0xF0) >> 4, 16)); // 转化高四位
hexBuilder.append(Character.forDigit((bytes[i] & 0x0F), 16)); // 转化低四位
}
return hexBuilder.toString().toUpperCase();
}
public static Long HexToDecimalism(String hexNum){
Long decNum = Long.parseLong(hexNum,16);
return decNum;
}
class ReceiveThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
logger.info("接受数据开始......");
//DatagramSocket ds = null;
try {
if(ds==null){
ds = new DatagramSocket(2000);// UDP通信类 2000为端口号
}
} catch (SocketException e1) {
// prompt("本地接收端口已被使用");
logger.error("本地接收端口已被使用");
System.exit(0);
}
while (true) {
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length); // 接收数据
try {
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();// ip地址
int port = dp.getPort();// 返回接收或发送该数据报文的远程主机端口号。
String text = bytesToHex(dp.getData(),0,dp.getLength());
//String text = new String(dp.getData(), 0, dp.getLength());
// 获取的串口数据
if (text.equals("exit")) {
System.out.println(ip + "退出会话......");
break;
}
System.out.println(ip + ":" + port + "===>me " + text);
mapCache.put("message", text);
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//ds.close();
}
}
}
}
}
前端页面定时获取数据。刷新
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/engine.js"></script>
<script type="text/javascript" src="js/util.js"></script>
<script type="text/javascript" src="js/Message.js"></script>
<script type="text/javascript" src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
var chatlog = "";
//发送信息
/* function sendMessage() {
var message = $("#message").val();
var user = $("#user").val();
Message.addMessage(user, message);
} */
//接收信息
function receiveMessages(messages) {
var lastMessage = messages;
/* chatlog = "<div>" + lastMessage + "</div>" + chatlog; */
electricity = lastMessage.split(",")[0];
temperature = lastMessage.split(",")[1];
dwr.util.setValue("showElectricity",electricity, {
escapeHtml : false
});
dwr.util.setValue("showTemperature", temperature, {
escapeHtml : false
});
}
//读取name值作为推送的唯一标示
function onPageLoad(){
var userId = getQueryString("name");
/* $("#myName").html(userId); */
Message.onPageLoad(userId);
}
//获取url中的参数
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
//一上来就加载onPageLoad()方法,将读取的name作为唯一标识,这里不一定要从url中取出name作为标识符,只要是该页面唯一的数据都可以是标识符
$(document).ready(function(){
dwr.engine.setActiveReverseAjax(true);//使用ajax反向代理
dwr.engine.setNotifyServerOnPageUnload(true);//服务启动直接加载
onPageLoad();
});
</script>
</head>
<body>
<!-- 我是<span id="myName" style="color:red"></span><br/>
推送给下面这位user<br/>
user:<br/>
<input id="user" type="text" /><br/>
推送信息为:<br/>
<input id="message" type="text" value="hey" />
<input type="button" value="send" onclick="sendMessage()" />
<br> -->
<!-- <div id="list"></div> -->
<div style="height: 760px;width: 100%;">
<div style="height: 180px;width: 100%;text-align:center;">
电流:<input id="showElectricity" type="text" value="" style="width: 440px;height: 60px;">
</div>
<div style="height: 180px;width: 100%;text-align: center;">
温度:<input id="showTemperature" type="text" value="" style="width: 440px;height: 60px;">
</div>
</div>
</body>
</html>
package com.zukai.test;
/**
*author:liyy
*date:2018年10月9日
*描述信息:
*/
import java.util.Collection;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpSession;
import org.directwebremoting.Browser;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ScriptSessionFilter;
import org.directwebremoting.WebContextFactory;
public class Message{
public void addMessage(String userid, String message) {
final String userId = userid;
final String autoMessage = message;
System.out.println("To:" + userid + ",Msg:" + message);
Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
public boolean match(ScriptSession session) {
if (session.getAttribute("name") == null)
return false;
else
return (session.getAttribute("name")).equals(userId);
}
}, new Runnable() {
private ScriptBuffer script = new ScriptBuffer();
public void run() {
script.appendCall("receiveMessages", autoMessage);
Collection<ScriptSession> sessions = Browser
.getTargetSessions();
for (ScriptSession scriptSession : sessions) {
if(scriptSession.getAttribute("name").equals(userId)){
scriptSession.addScript(script);
break;
}
}
}
});
}
//页面加载直接执行该方法
public void onPageLoad(String name) {
HttpSession session = WebContextFactory.get()
.getSession();
session.setAttribute("name", name);
WebContextFactory.get().getScriptSession().setAttribute("name", name);
}
}