最近用到了前台推送技术,一开始用了comet4j 但是发现偶尔会断开,所以探寻了另一条出路。mina+applet实现推送技术。
分为三步:一.编写mina服务端,客户端代码。(先调试好)
二.将客户端类变成applet类, 进行签章等设置
三.实现applet 和 jsp 通信
上代码,边看代码边将:
1.服务端类MinaServer
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Collection;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
/**
* 服务器启动类
*
* @author JiangBo
*/
public class MinaServer {
/**
* 单例
*/
private static MinaServer instance = new MinaServer();
public static MinaServer getInstance() {
return instance;
}
private MinaServer() {
}
// 端口设置
private static int PORT = 30001;
private SocketAcceptor acceptor;
/**
* 初始化方法
*
* @return
*/
public boolean start() {
// 创建非阻塞的server端的Socket连接
acceptor = new NioSocketAcceptor();
DefaultIoFilterChainBuilder filterChain = acceptor.getFilterChain();
// 添加编码过滤器 处理乱码、编码问题
// filterChain.addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
// 设置核心消息业务处理器
acceptor.setHandler(new ServerMessageHandler());
// 设置session配置,30秒内无操作进入空闲状态
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
try {
// 绑定端口
acceptor.bind(new InetSocketAddress(PORT));
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 向客户端发送(推送)消息
*/
public void sendMessage(String host, String port, String value) {
// 实例化一个向客户端发送的socket对象
Collection<IoSession> sessions = acceptor.getManagedSessions().values();
for (IoSession sess : sessions) {
sess.write(value);
}
}
/**
* main方法
*
* @param args
*/
public static void main(String[] args) {
//
MinaServer server = MinaServer.getInstance();
server.start();
System.out.println("服务器启动成功=================");
}
}
2.ServerMessageHandler类
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.IoFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
/**
* 处理服务器端消息
*
* @author JiangBo
*/
public class ServerMessageHandler implements IoHandler {
/**
* 服务器发生异常
*/
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
System.out.println("服务器发生异常: " + cause.getMessage());
}
/**
* 接收数据
*/
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
System.out.println("服务器接收到数据:" + message);
}
/**
* 发送消息
*/
@Override
public void messageSent(IoSession session, Object message) throws Exception {
System.out.println("服务器发送消息: " + message);
}
/**
* 关闭链接
*/
@Override
public void sessionClosed(IoSession session) throws Exception {
System.out.println("关闭当前session:" + session.getId() + session.getRemoteAddress());
CloseFuture closeFuture = session.close(true);
closeFuture.addListener(new IoFutureListener<IoFuture>() {
public void operationComplete(IoFuture future) {
if (future instanceof CloseFuture) {
((CloseFuture) future).setClosed();
System.out.println("sessionClosed CloseFuture setClosed-->" + future.getSession().getId() + ",");
}
}
});
}
/**
* 创建连接
*/
@Override
public void sessionCreated(IoSession session) throws Exception {
System.out.println("创建一个新连接:" + session.getRemoteAddress());
session.write("session created:" + session.getRemoteAddress());
}
/**
* 空闲
*/
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
System.out.println("当前连接" + session.getRemoteAddress() + "处于空闲状态:" + status);
}
/**
* 打开一个session链接
*/
@Override
public void sessionOpened(IoSession session) throws Exception {
System.out.println("打开一个session:"+ session.getId() + session.getBothIdleCount());
}
}
3.MinaClient客户端类
import java.applet.Applet;
import java.net.InetSocketAddress;
import netscape.javascript.JSObject;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import com.txsoft.ipcc.common.mina.service.CharsetCodecFactory;
/**
* mina客户端
*
* @author JiangBo
*/
public class MinaClient extends Applet {
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
private static String IP = "192.168.1.30";
private static int PORT = 30001;
private SocketConnector connector;
private ConnectFuture future;
private IoSession session;
public void init() {
JSObject window= null;
try {
window=JSObject.getWindow(this);
window.eval("alert('start begin!')");
} catch (Exception e) {
}
// 创建一个socket连接
connector = new NioSocketConnector();
// 设置链接超时时间
connector.setConnectTimeoutMillis(3000);
// 获取过滤器链
DefaultIoFilterChainBuilder filterChain = connector.getFilterChain();
// 添加编码过滤器 处理乱码、编码问题
filterChain.addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
// 消息核心处理器
connector.setHandler(new ClientMessageHandlerAdapter(this));
// 连接服务器,知道端口、地址
future = connector.connect(new InetSocketAddress(IP, PORT));
// 等待连接创建完成
future.awaitUninterruptibly();
// 获取当前session
session = future.getSession();
//
try {
window.eval("alert('end!')");
} catch (Exception e) {
}
}
public void setAttribute(Object key, Object value) {
session.setAttribute(key, value);
}
/**
* 发送
* @param message
*/
public void send(String message) {
session.write(message);
}
/**
* 发送信息到JSP
* @param message
*/
public void sendJsp(String message) {
// 获取JavaScript窗口句柄,引用当前文档窗口
JSObject window = JSObject.getWindow(MinaClient.this);
// 调用页面上的js方法 show(message)
Object obj[] = new Object[1];
obj[0] = message;
window.call("show", obj);// 参数用数组的形势表示。
}
public boolean close() {
CloseFuture future = session.getCloseFuture();
future.awaitUninterruptibly(1000);
connector.dispose();
return true;
}
public SocketConnector getConnector() {
return connector;
}
public IoSession getSession() {
return session;
}
}
4.ClientMessageHandlerAdapter类
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
/**
* 客户端消息处理类
* @author JiangBo
*/
public class ClientMessageHandlerAdapter extends IoHandlerAdapter {
private MinaClient minaClient = null;
public ClientMessageHandlerAdapter(MinaClient minaClient) {
this.minaClient = minaClient;
}
/**
* 接收到消息
*/
public void messageReceived(IoSession session, Object message) throws Exception {
// 接到消息无处理
System.out.println("messageSent服务端发送到客户端的消息:" + message);
if (null != this.minaClient) {
try {
this.minaClient.sendJsp(message.toString());
} catch (Exception e) {
}
}
}
public void messageSent(IoSession session , Object message) throws Exception{
System.out.println("messageSent 客户端发送消息:" + message);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
System.out.println("服务器发生异常: {}" + cause.getMessage());
}
}
5. jsp文件
<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title> test mina push </title>
</head>
<body>
<applet name = "testapplet" code = 'com.txsoft.ipcc.common.mina.client.MinaClient.class'
archive = 'minaClient.jar' width = 100 height = 50 MAYSCRIPT>
</applet>
<script type="text/javascript">
function show(message){
alert(message);
}
</script>
</body>
</html>
注意:例子中要把代码打包放在跟目录下,例子中jar包名叫:minaClient.jar。jar包还需要密码的支持所以打包时候还要把mima的支持包打进去。把下面3个包放在跟minaClient.jar同级目录下。
1.mina-core-2.0.7.jar
2.slf4j-api-1.7.6.jar
3.slf4j-jdk14-1.7.7.jar
打包时候我是通过MANIFEST.MF文件选择了密码支持的3个包
MANIFEST.MF内容:
Manifest-Version: 1.0
Class-Path: mina-core-2.0.7.jar slf4j-api-1.7.6.jar slf4j-jdk14-1.7.7.jar
由于是Applet所以需要生成证书及签名所以在服务端cmd调出命令框 执行授权:
1、keytool -genkey -keystore pepper.store -alias pepper
这个命令用来产生一个密匙库,执行完毕后应该在c:/admin中产生一个pepper.store的文件,这里的pepper是我自己的名字,你可以对它进行修改。另外在执行命令的时候还有提示你输入密匙库的密码,这里你一定要记住,否则后面要用的时候无法输入。
2、keytool -export -keystore pepper.store -alias pepper -file pepper.cert
这个命令用来产生签名时所要用的证书,同样这里的pepper也可以换成你自己需要的名字。这个命令执行完后在c:/admin中产生一个pepper.cert的文件。
3、 jarsigner -keystore pepper.store E:\workspace_IPCC\IPCC\WebRoot\minaClient.jar pepper
这个命令用上面产生的证书将我们的jar文件进行了签名。(可以写绝对路径)
在客户端设置security
C:\Program Files (x86)\Java\jre6\lib\security\java.policy
在最下面添加这句,是允许所有IP 所有端口的权限,让然你可以可以指定IP 和端口
permission java.net.SocketPermission "*:*","accept,connect,resolve";
好了 小伙伴们 快去试试吧~
需要的jar包: