web集成mpush开发

服务部署方式参照:https://github.com/mywiki/mpush-doc/blob/master/SUMMARY.md 完成
mpush官方详细开发文档:http://mpush.mydoc.io/?t=134820

redis默认只能本机访问,需要修改配置文件,请参考https://blog.csdn.net/weiyangdong/article/details/79916445进行修改

完整web项目demol连接:https://download.csdn.net/download/qq_16758997/10943141

安装Mpush-Alloc服务时记得修改mpush.config配置文件中的ws-server-port的端口号(端口号为模拟客户端中的端口号)

一、新建一个普通的maven web工程或新建一个web工程再转换为maven工程(文章采用后一种方式,jdk1.8,tomcat 9.0)

二、修改pom.xml文件如下:


  4.0.0
  webmpush
  webmpush
  0.0.1-SNAPSHOT
  war
  
	
		com.github.mpusher
		mpush-client
		0.8.0
	
  
  
    src
    
      
        src
        
          **/*.java
        
      
    
    
      
        maven-compiler-plugin
        3.7.0
        
          1.8
          1.8
        
      
      
        maven-war-plugin
        3.2.1
        
          WebContent
        
      
    
  

新加标签部分,导入mpush相关的jar包


    
        com.github.mpusher
        mpush-client
        0.8.0
    

 

在src目录下新建application.conf文件,文件内容如下

##################################################################################################################
#
# NOTICE:
#
# 系统配置文件,所有列出的项是系统所支持全部配置项
# 如果要覆盖某项的值可以添加到mpush.conf中。
#
# 配置文件格式采用HOCON格式。解析库由https://github.com/typesafehub/config提供。
# 具体可参照说明文档,比如含有特殊字符的字符串必须用双引号包起来。
#
##################################################################################################################

mp {
    #基础配置
    home=${user.dir} //程序工作目录

    #日志配置
    log-level=warn
    log-dir=${mp.home}/logs
    log-conf-path=${mp.home}/conf/logback.xml

    #核心配置
    core {
        max-packet-size=10k //系统允许传输的最大包的大小
        compress-threshold=10k //数据包启用压缩的临界值,超过该值后对数据进行压缩
        min-heartbeat=3m //最小心跳间隔
        max-heartbeat=3m //最大心跳间隔
        max-hb-timeout-times=2 //允许的心跳连续超时的最大次数
        session-expired-time=1d //用于快速重连的session 过期时间默认1天
        epoll-provider=netty //nio:jdk自带,netty:由netty实现
    }

    #安全配置
    security {
        #rsa 私钥、公钥key长度为1024;可以使用脚本bin/rsa.sh生成, @see com.mpush.tools.crypto.RSAUtils#main
        private-key="MIIBNgIBADANBgkqhkiG9w0BAQEFAASCASAwggEcAgEAAoGBAKCE8JYKhsbydMPbiO7BJVq1pbuJWJHFxOR7L8Hv3ZVkSG4eNC8DdwAmDHYu/wadfw0ihKFm2gKDcLHp5yz5UQ8PZ8FyDYvgkrvGV0ak4nc40QDJWws621dm01e/INlGKOIStAAsxOityCLv0zm5Vf3+My/YaBvZcB5mGUsPbx8fAgEAAoGAAy0+WanRqwRHXUzt89OsupPXuNNqBlCEqgTqGAt4Nimq6Ur9u2R1KXKXUotxjp71Ubw6JbuUWvJg+5Rmd9RjT0HOUEQF3rvzEepKtaraPhV5ejEIrB+nJWNfGye4yzLdfEXJBGUQzrG+wNe13izfRNXI4dN/6Q5npzqaqv0E1CkCAQACAQACAQACAQACAQA="
        public-key="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCghPCWCobG8nTD24juwSVataW7iViRxcTkey/B792VZEhuHjQvA3cAJgx2Lv8GnX8NIoShZtoCg3Cx6ecs+VEPD2fBcg2L4JK7xldGpOJ3ONEAyVsLOttXZtNXvyDZRijiErQALMTorcgi79M5uVX9/jMv2Ggb2XAeZhlLD28fHwIDAQAB"
        aes-key-length=16 //AES key 长度
    }

    #网络配置
    net {
        local-ip="127.0.0.1"  //本地ip, 默认取第一个网卡的本地IP
        public-ip="127.0.0.1" //外网ip, 默认取第一个网卡的外网IP

        connect-server-bind-ip=""  //connSrv 绑定的本地ip (默认anyLocalAddress 0.0.0.0 or ::0)
        connect-server-register-ip=${mp.net.public-ip}  //公网ip, 注册到zk中的ip, 默认是public-ip
        connect-server-port=3000 //长链接服务对外端口, 公网端口
        connect-server-register-attr { //注册到zk里的额外属性,比如配置权重,可在alloc里排序
            weight:1
        }

        gateway-server-bind-ip=""  //gatewaySrv 绑定的本地ip (默认anyLocalAddress 0.0.0.0 or ::0)
        gateway-server-register-ip=${mp.net.local-ip}  //本地ip, 注册到zk中的ip, 默认是local-ip
        gateway-server-port=3001 //网关服务端口, 内部端口
        gateway-server-net=tcp //网关服务使用的网络类型tcp/udp/sctp/udt

        gateway-client-port=4000 //UDP 客户端端口
        gateway-server-multicast="239.239.239.88" //239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效
        gateway-client-multicast="239.239.239.99" //239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效
        gateway-client-num=1 //网关客户端连接数

        admin-server-port=3002 //控制台服务端口, 内部端口
        ws-server-port=0 //websocket对外端口, 公网端口, 0表示禁用websocket
        ws-path="/" //websocket path

        public-host-mapping { //本机局域网IP和公网IP的映射关系, 该配置后续会被废弃
            //"10.0.10.156":"111.1.32.137"
            //"10.0.10.166":"111.1.33.138"
        }

        snd_buf { //tcp/udp 发送缓冲区大小
            connect-server=32k
            gateway-server=0
            gateway-client=0 //0表示使用操作系统默认值
        }

        rcv_buf { //tcp/udp 接收缓冲区大小
            connect-server=32k
            gateway-server=0
            gateway-client=0 //0表示使用操作系统默认值
        }

        write-buffer-water-mark { //netty 写保护
            connect-server-low=32k
            connect-server-high=64k
            gateway-server-low=10m
            gateway-server-high=20m
        }

        traffic-shaping { //流量整形配置
            gateway-client {
                enabled:false
                check-interval:100ms
                write-global-limit:30k
                read-global-limit:0
                write-channel-limit:3k
                read-channel-limit:0
            }

            gateway-server {
                enabled:false
                check-interval:100ms
                write-global-limit:0
                read-global-limit:30k
                write-channel-limit:0
                read-channel-limit:3k
            }

            connect-server {
                enabled:false
                check-interval:100ms
                write-global-limit:0
                read-global-limit:100k
                write-channel-limit:3k
                read-channel-limit:3k
            }
        }
    }

    #Zookeeper配置
    zk {
        server-address="127.0.0.1:2181" //多台机器使用","分隔如:"10.0.10.44:2181,10.0.10.49:2181" @see org.apache.zookeeper.ZooKeeper#ZooKeeper()
        namespace=mpush
        digest=mpush //zkCli.sh acl 命令 addauth digest mpush
        watch-path=/
        retry {
            #initial amount of time to wait between retries
            baseSleepTimeMs=3s
            #max number of times to retry
            maxRetries=3
            #max time in ms to sleep on each retry
            maxSleepMs=5s
        }
        connectionTimeoutMs=5s
        sessionTimeoutMs=5s
    }

    #Redis集群配置
    redis {
        cluster-model=single //single,cluster,sentinel
        sentinel-master:"",
        nodes:["127.0.0.1:6379"] //["127.0.0.1:6379"]格式ip:port
        password="" //your password
        config {
            maxTotal:8,
            maxIdle:4,
            minIdle:1,
            lifo:true,
            fairness:false,
            maxWaitMillis:5000,
            minEvictableIdleTimeMillis:300000,
            softMinEvictableIdleTimeMillis:1800000,
            numTestsPerEvictionRun:3,
            testOnCreate:false,
            testOnBorrow:false,
            testOnReturn:false,
            testWhileIdle:false,
            timeBetweenEvictionRunsMillis:60000,
            blockWhenExhausted:true,
            jmxEnabled:false,
            jmxNamePrefix:pool,
            jmxNameBase:pool
        }
    }

    #HTTP代理配置
    http {
        proxy-enabled=true//启用Http代理
        max-conn-per-host=5 //每个域名的最大链接数, 建议web服务nginx超时时间设长一点, 以便保持长链接
        default-read-timeout=10s //请求超时时间
        max-content-length=5m //response body 最大大小
        dns-mapping { //域名映射外网地址转内部IP, 域名部分不包含端口号
            //"mpush.com":["127.0.0.1:8080", "127.0.0.1:8081"]
        }
    }

    #线程池配置
    thread {
        pool {
            conn-work:0 //接入服务线程池大小,0表示线程数根据cpu核数动态调整(2*cpu)
            gateway-server-work:0 //网关服务线程池大小,0表示线程数根据cpu核数动态调整(2*cpu)
            http-work:0 //http proxy netty client work pool size,0表示线程数根据cpu核数动态调整(2*cpu)
            ack-timer:1 //处理ACK消息超时
            push-task:0 //消息推送中心,推送任务线程池大小, 如果为0表示使用Gateway Server的work线程池,tcp下推荐0
            gateway-client-work:0 //网关客户端线程池大小,0表示线程数根据cpu核数动态调整(2*cpu),该线程池在客户端运行
            push-client:2 //消息推送回调处理,该线程池在客户端运行

            event-bus { //用户处理内部事件分发
                min:1
                max:16
                queue-size:10000 //大量的online,offline
            }

            mq { //用户上下线消息, 踢人等
                min:1
                max:4
                queue-size:10000
            }
        }
    }

    #推送消息流控
    push {
       flow-control { //qps = limit/(duration)
            global:{ //针对非广播推送的流控,全局有效
                limit:5000 //qps = 5000
                max:0 //UN limit
                duration:1s //1s
            }

            broadcast:{ //针对广播消息的流控,单次任务有效
                limit:3000 //qps = 3000
                max:100000 //10w
                duration:1s //1s
            }
       }
    }

    #系统监控配置
    monitor {
        dump-dir=${mp.home}/tmp
        dump-stack=false //是否定时dump堆栈
        dump-period=1m  //多久监控一次
        print-log=true //是否打印监控日志
        profile-enabled=false //开启性能监控
        profile-slowly-duration=10ms //耗时超过10ms打印日志
    }

    #SPI扩展配置
    spi {
        thread-pool-factory:"com.mpush.tools.thread.pool.DefaultThreadPoolFactory"
        dns-mapping-manager:"com.mpush.common.net.HttpProxyDnsMappingManager"
    }
}

三、新建一个普通的类,需要实现两个接口 PushSender(mpush启动是需要使用), ServletContextListener(web项目的监听器需要继承的类)

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.FutureTask;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import com.mpush.api.push.PushContext;
import com.mpush.api.push.PushResult;
import com.mpush.api.push.PushSender;
import com.mpush.api.service.Listener;

public class ServiceManager implements PushSender, ServletContextListener {
	public static PushSender pushSender = null;

	// 在tomcat启动是启动消息发送服务
	// 启动一个定时器
	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		// PushClient PushClient=new PushClient();
		if (pushSender == null)
			pushSender = PushSender.create();
		pushSender.start().join();
	}

	public static PushSender getPushSender() {
		if (pushSender == null)
			pushSender = PushSender.create();
		return pushSender;
	}

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		pushSender.stop();
	}

	@Override
	public void start(Listener listener) {
		// TODO Auto-generated method stub

	}

	@Override
	public void stop(Listener listener) {
		// TODO Auto-generated method stub

	}

	@Override
	public CompletableFuture start() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public CompletableFuture stop() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean syncStart() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean syncStop() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void init() {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean isRunning() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public FutureTask send(PushContext context) {
		// TODO Auto-generated method stub
		return null;
	}
}

在tomcat启动是就启动mpush消息发送服务,采用单例模式,增加静态公用get方法获取详细推送服务实例,共其它类调用

// 在tomcat启动是启动消息发送服务
    // 启动一个定时器
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        // PushClient PushClient=new PushClient();
        if (pushSender == null)
            pushSender = PushSender.create();
        pushSender.start().join();
    }

    public static PushSender getPushSender() {
        if (pushSender == null)
            pushSender = PushSender.create();
        return pushSender;
    }

四、增加web项目监听器配置,修改web.xml文件



  webpush
  
    index.html
    index.htm
    index.jsp
    default.html
    default.htm
    default.jsp
  
  
    
    com.webpush.service.ServiceManager
  

新增自定义web项目的监听器(这里的类路径是第三步新建的监听器类路径)


    com.webpush.service.ServiceManager
 

到这里就已经完成mpush继承环境的开发搭建了,以下的内容是增加测试的servlet

五、新建两个servlet类并添加web.xml文件配置:

第一个servlet类:

package com.webpush.pushmessage;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mpush.api.push.AckModel;
import com.mpush.api.push.MsgType;
import com.mpush.api.push.PushCallback;
import com.mpush.api.push.PushContext;
import com.mpush.api.push.PushMsg;
import com.mpush.api.push.PushResult;
import com.mpush.api.push.PushSender;
import com.webpush.service.ServiceManager;//刚才第三步新建servlet监听器的类(修改为自己的类路径)

/**
 * Servlet implementation class Htmlpushmesg
 */
@WebServlet("/htmlpushmesg")
public class Htmlpushmesg extends HttpServlet {
	private static final long serialVersionUID = 1L;
	PushResult pushResult=null;//消息推送结果
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		int msgType=Integer.valueOf(request.getParameter("msgtype"));
        String pushMsg=request.getParameter("pushMsg");
        String broadcast=request.getParameter("broadcast");
        String[] userIds=request.getParameterValues("userId");
        
        List users=new ArrayList();
        if(userIds!=null)
        	for(int i=0,len=userIds.length;i future = */sender.send(context);
        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(10));
        
        request.setAttribute("pushResult", pushResult);
		request.getRequestDispatcher("/push.jsp").forward(request, response);
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

第二个servlet类:

在新建第二个servlet类之前先建一个redis的配置文件,文件名:redis.properties,放在src目录下

jedis.pool.maxActive=1024
jedis.pool.maxIdle=200
jedis.pool.maxWait=10000
jedis.pool.testOnBorrow=true
jedis.pool.testOnReturn=true
jedis.pool.timeout=10000
# ip地址必须和文件application.conf中的redis的IP地址相同
redisReadURL=127.0.0.1
redisReadPort=6379
# ip地址必须和文件application.conf中的redis的IP地址相同
redisWriteURL=127.0.0.1
redisWritePort=6379
# 你的redis密码,同文件application.conf中的redis中的密码
password=

servlet类

package com.webpush.pushmessage;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mpush.tools.config.CC;
import com.mpush.tools.config.data.RedisNode;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 获取所有在线用户的信息
 */
@WebServlet("/userStutas")
public class UserStutas extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		request.setAttribute("users", getRedisdata());
		request.getRequestDispatcher("/userlist.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
	
	
	/**
	 * redis操作部分
	 */
	// 连接实例的最大连接数
 	private static int MAX_ACTIVE = 1024;
 	// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
 	private static int MAX_IDLE = 200;
 	// 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
 	private static int MAX_WAIT = 10000;
 	// 连接超时的时间
 	private static int TIMEOUT = 10000;
 	// 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
 	private static boolean TEST_ON_BORROW = true;
 	private static JedisPool jedisPool = null;
	
	//加载配置文件
    static void load() {
        Config config = ConfigFactory.load();//扫描加载所有可用的配置文件
        String custom_conf = "mp.conf";//加载自定义配置, 值来自jvm启动参数指定-Dmp.conf
        if (config.hasPath(custom_conf)) {
            File file = new File(config.getString(custom_conf));
            if (file.exists()) {
                Config custom = ConfigFactory.parseFile(file);
                config = custom.withFallback(config);
            }
        }
        Config cfg = CC.cfg.getObject("mp").toConfig().getObject("redis").toConfig();
        try {
			JedisPoolConfig redisconf = new JedisPoolConfig();
			redisconf.setMaxTotal(MAX_ACTIVE);
			redisconf.setMaxIdle(MAX_IDLE);
			redisconf.setMaxWaitMillis(MAX_WAIT);
			redisconf.setTestOnBorrow(TEST_ON_BORROW);
			RedisNode redisnode=cfg.getList("nodes")
					.stream()//第一纬度数组
                    .map(v -> RedisNode.from(v.unwrapped().toString()))
                    .collect(Collectors.toCollection(ArrayList::new)).get(0);
			jedisPool = new JedisPool(redisconf, redisnode.getHost(), redisnode.getPort(), TIMEOUT, cfg.getString("password"));
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
	public Map>> getRedisdata() {
		Jedis jedis = getJedis();
		Map>> map = new HashMap>>();
		for(String key : jedis.keys("mp:ur:*")) {
			//System.err.println(key+"\t");
			Map> maplist=new HashMap>();
			for(String ke : jedis.hkeys(key)) {
				maplist.put(ke, jedis.hmget(key,ke));
				//System.out.print(ke+"\t");
				//System.out.println(jedis.hmget(key,ke));
			}
			map.put(key, maplist);
		}
		returnResource(jedis);
		return map;
	}

	
	/**
	 * 初始化Redis连接池
	 */
	static {
		load();
	}

	/**
	 * 获取Jedis实例
	 */
	public synchronized static Jedis getJedis() {
		try {
			if (jedisPool != null) {
				Jedis resource = jedisPool.getResource();
				return resource;
			} else {
				return null;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/***
	 * 
	 * 释放资源
	 */
	public static void returnResource(final Jedis jedis) {
		if (jedis != null) {
			jedisPool.returnResource(jedis);
		}
	}
}

修改web.xml文件



  webpush
  
    index.html
    index.htm
    index.jsp
    default.html
    default.htm
    default.jsp
  
  
    com.webpush.service.ServiceManager
  
  
    htmlpushmesg
    com.webpush.pushmessage.Htmlpushmesg
  
  
    htmlpushmesg
    /htmlpushmesg.do
  
  
    userStutas
    com.webpush.pushmessage.UserStutas
  
  
    userStutas
    /userStutas.do
  

web Socket客户端,接受消息测试(app请在官网下载,如果Android7.0及以上版本点击绑定退出,请换成Android6.0及以下版本安装测试)




    
    MPush WebSocket Client





消息推送页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="com.webpush.redis.RedisUtils,java.util.*"%>




Insert title here


消息推送

推送结果:<%=request.getAttribute("pushResult")%>
消息类型:
是否广播:广播 指定用户推送
推送用户:<%Map>> users=new RedisUtils().getRedisdata(); for(String user : users.keySet()){%> "><%=user.split("mp:ur:")[1]%> <%}%>
消息内容:

客户端所有用户列表

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*,com.alibaba.fastjson.JSON"%>




Insert title here



	

所有用户列表数据

<% Map>> map = (Map>>) request.getAttribute("users"); Set set = map.keySet(); for (String user : set) { Set se = map.get(user).keySet(); Iterator it = se.iterator(); %> <% String list = map.get(user).get(it.next()).get(0); Map m = JSON.parseObject(list, Map.class); %> <% while (it.hasNext()) { %> <% list = map.get(user).get(it.next()).get(0); m = JSON.parseObject(list, Map.class); %> <% } } %>
用户名 版本号 主机 在线情况 客户端类型
<%=user.split("mp:ur:")[1]%><%=m.get("clientVersion")%> <%=m.get("hostAndPort")%> <%="true".equals(m.get("online").toString()) ? "在线" : "离线"%> <%=m.get("osName")%>
<%=m.get("clientVersion")%> <%=m.get("hostAndPort")%> <%="true".equals(m.get("online").toString()) ? "在线" : "离线"%> <%=m.get("osName")%>

然后运行web项目,查看效果

如果对您有帮助记得点个赞哦

欢迎加群:517413713 讨论

你可能感兴趣的:(web开发)