这几天在学习dwr,学习了推送后,当然想再实现以下多人聊天。于是在网上查找了一些例子,其中http://www.cnblogs.com/hoojo/archive/2011/06/08/2075201.html,这篇博文写的是最详细的,然后在他的基础上,我进行了代码的编写,但是在整合过程中,用idea没有实现,最后又换成myEclipse搭建maven web项目,成功实现了。,下面开始我的项目。
首先,先把项目目录给大家看下
下面就开始创建项目了:
准备工作:要把dwr.jar架包下下来,下载地址:https://java.net/downloads/dwr/Development%20Builds/Build%20116/dwr.jar
然后把这个架包添加到WEB-INIF的lib目录下,需要注意的是:如果只是单纯的添加进去,然后再build Path,虽然可以看到jar里面的文件,但是并没有读取成功,因为咱们的本地jar在maven厂库里找不到,所以在配置pom.xml时,需要添加build,下面请看pom.xml的配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dwrDemo</groupId>
<artifactId>dwrSpringDemo</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>dwrSpringDemo Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- spring相关架包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.aop</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.asm</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.aspects</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.beans</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.context</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.context.support</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.core</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.expression</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.jdbc</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.jms</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.orm</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.oxm</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.transaction</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.web</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.web.servlet</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.web.portlet</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aopalliance</groupId>
<artifactId>com.springsource.org.aopalliance</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<extdirs>${basedir}/WebRoot/WEB-INF/lib</extdirs>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置中build 的一定要写,不然还会报:classnotfound的错误。
第一步:先创建一个实体类 message
把用户的信息保存进去,以便提取的时候好用。
/**
*
*/
package com.item.pojo;
import java.util.Date;
/**
* @Description:信息实体类
*
* @author ZZK
* @ date 2017年6月26日
* title Message
*/
public class Message {
private int id;
private String msg;
private Date time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
}
第二步:创建聊天信息事件
/**
*
*/
package com.item.chat;
import org.springframework.context.ApplicationEvent;
/**
* @Description:发送聊天信息事件
* 继承ApplicationEvent,构造参数用于传递发送过来的消息。
* 这个事件需要一个监听器监听,一旦触发了这个事件,我们就可以向客户端发送消息。
*
* @author ZZK
* @ date 2017年6月26日
* title ChatMessageEvent
*/
public class ChatMessageEvent extends ApplicationEvent{
/**
* @param source
*/
public ChatMessageEvent(Object source) {
super(source);
}
}
第三步:创建发送信息的服务类
/**
*
*/
package com.item.chat;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import com.item.pojo.Message;
/**
* @Description:发送信息的服务类
* 用户客户端发送消息。dwr需要暴露这个类里面的发送消息的方法
* @author ZZK
* @ date 2017年6月26日
* title ChatService
*/
public class ChatService implements ApplicationContextAware{
private ApplicationContext ctx;
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
this.ctx=ctx;
}
/**
* 向服务器发送信息,服务器端监听ChatMessageEvent事件,当有事件触发就向所有客户端发送信息
* @param message 消息
* sendMessage方法需要浏览器客户端调用此方法完成消息的发布,
* 传递一个Message对象,并且是触发ChatMessageEvent事件。
*/
public void sendMessage(Message message){
//发布事件
ctx.publishEvent(new ChatMessageEvent(message));
}
}
第四步: 编写监听器监听客户端是否触发ChatMessageEvent
/**
*
*/
package com.item.chat;
import java.util.Collection;
import java.util.Date;
import javax.servlet.ServletContext;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContext;
import org.directwebremoting.ServerContextFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.web.context.ServletContextAware;
import com.item.pojo.Message;
/**
* @Description: 编写监听器监听客户端是否触发ChatMessageEvent
* MessageEvent事件的监听类
* 需要spring的支持 利用spring的消息驱动机制
* @author ZZK
* @ date 2017年6月26日
* title ChatMessageClient
*/
@SuppressWarnings("rawtypes")
public class ChatMessageClient implements ApplicationListener, ServletContextAware{
private ServletContext ctx;
public void setServletContext(ServletContext servletContext) {
this.ctx = servletContext;
}
public void onApplicationEvent(ApplicationEvent event) {
//如果事件类型是ChatMessageEvent就执行下面操作
if (event instanceof ChatMessageEvent){
Message msg = (Message) event.getSource();
ServerContext context = ServerContextFactory.get();//获取服务的上下文
//获得客户端所有chat页面script session连接数
Collection<ScriptSession> scriptSessions =context.getScriptSessionsByPage(ctx.getContextPath() + "/chat.jsp");
for (ScriptSession session : scriptSessions) {
ScriptBuffer sb = new ScriptBuffer();
Date time = msg.getTime();
//获取具体事件
String s = time.getYear() + "-" + (time.getMonth() + 1) + "-" + time.getDate() + " "
+ time.getHours() + ":" + time.getMinutes() + ":" + time.getSeconds();
//执行setMessage方法
sb.appendScript("showMessage({msg: '")
.appendScript(msg.getMsg())
.appendScript("', time: '")
.appendScript(s)
.appendScript("'})");
System.out.println(sb.toString());
//执行客户端script session方法,相当于浏览器执行JavaScript代码
//上面就会执行客户端浏览器中的showMessage方法,并且传递一个对象过去
session.addScript(sb);
}
}
}
}
上面的代码主要是监听客户端的事件,一旦客户端有触发ApplicationEvent事件或是其子类,就会执行onApplicationEvent方法。代码中通过instanceof判断对象实例,然后再执行。如果有触发ChatMessageEvent事件,就获取所有连接chat.jsp这个页面的ScriptSession。然后像所有的ScriptSession中添加script。这样被添加的ScriptSession就会在有连接chat.jsp的页面中执行。
所以这就是客户端为什么会执行服务器端的JavaScript代码。但前提是需要在web.xml中添加dwrComet配置以及在chat页面添加ajax反转。
这些都弄好后,就要在我们的web。xml配置一下了:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_1498458481457">
<!-- 加载Spring容器配置 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 设置Spring容器加载配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext-*.xml</param-value>
</context-param>
<!-- dwr监听器 -->
<listener>
<listener-class>org.directwebremoting.servlet.DwrListener</listener-class>
</listener>
<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>
<!-- dwr的comet控制 -->
<init-param>
<param-name>pollAndCometEnabled</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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
然后是dwr.xml的配置,要注意的是,dwr.xml和web.xml 是在同一目录下
<?xml version="1.0" encoding= "UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN"
"http://directwebremoting.org/dwr/dwr30.dtd">
<dwr>
<allow>
<convert match="com.item.pojo.Message" converter="bean">
<param name="include" value="msg,time" />
</convert>
<!-- charService的sendMessage方法传递的是Message对象,所以要配置Message对象的convert配置。
create的creator是spring,表示在spring容器中拿chatService对象。
里面的参数的beanName表示在spring容器中找name等于charService的bean对象。
-->
<create creator="spring" javascript="ChatService">
<param name="beanName" value="chatService" />
</create>
</allow>
</dwr>
接下来就是配置spring的bean了,因为maven项目里有resource,所以直接在src里的resource里写applicationContext-beans.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="chatService" class="com.item.chat.ChatService"/>
<bean id="chatMessageClient" class="com.item.chat.ChatMessageClient"/>
</beans>
这些都配置完成,下面就开始配置页面了,因为指定好了chat.jsp,所以咱们要新建一个chat.jsp,然后在里面写代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>多人聊天室</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript" src="dwr/engine.js"></script>
<script type="text/javascript" src="dwr/util.js"></script>
<script type="text/javascript" src="dwr/interface/ChatService.js"></script>
<script type="text/javascript">
function send() {
var time = new Date();
var content = dwr.util.getValue("content");//获取消息内容
var name = dwr.util.getValue("userName"); //获取名字
var info = encodeURI(encodeURI(name + " say:\n" + content));
var msg = {"msg": info, "time": time};
dwr.util.setValue("content", "");
if (!!content) {
ChatService.sendMessage(msg);
} else {
alert("发送的内容不能为空!");
}
}
function showMessage(data) {
var message = decodeURI(decodeURI(data.msg));
var text = dwr.util.getValue("info");
if (!!text) {
dwr.util.setValue("info", text + "\n" + data.time + " " + message);
} else {
dwr.util.setValue("info", data.time + " " + message);
}
}
</script>
</head>
<body οnlοad="dwr.engine.setActiveReverseAjax(true);">
<textarea rows="20" cols="60" id="info" readonly="readonly"></textarea>
<hr/>
昵称:<input type="text" id="userName"/><br/>
消息:<textarea rows="5" cols="30" id="content"></textarea>
<input type="button" value=" Send " οnclick="send()" style="height: 85px; width: 85px;"/>
</body>
</html>
这些都配置好了,就可以开始咱们的tomcat启动了,最后显示的结果是同步实现的,
这是用的两个浏览器进行同一页面聊天的,功能实现了。在这里感谢文章开头提到的博主,是他的研究成果,才有了结果的实现。