常量表
Constants.java
/**
* 项目中的全局常量定义
*/
public interface Constants {
String WEBSOCKET_STR = "websocket";
String UPGRADE_STR = "Upgrade";
int OK_CODE = 200;
String HTTP_CODEC = "http-codec";
String AGGREGATOR = "aggregator";
String HTTP_CHUNKED = "http-chunked";
String HANDLER = "handler";
int MAX_CONTENT_LENGTH = 65536;
int PORT = 8989;
String WEB_SOCKET_URL = "ws://localhost:"+PORT+"/ws";
//订阅者列表
String IM_QUEUE_CHANNLID = "im-queue-channlid";
}
配置类:
NettyConfig.java
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @program: Netty-WebSocket
* @description: 工程的全局配置类
**/
public class NettyConfig {
/**
* 存储每一个客户端接入进来时的channel对象
*/
public final static ChannelGroup GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 本地存储一份map
*/
public final static Map LOCALCHANNELMAP = new ConcurrentHashMap<>();
/**
* 本地存储一份map 送达到key,channel
*/
public final static Map> LOCALCHANNELLISTMAP = new ConcurrentHashMap<>();
}
收发消息 handler
MyWebsocketHandler.java
import com.xx.im.api.WebsocketServer;
import com.xx.im.api.config.Constants;
import com.xx.im.api.config.NettyConfig;
import com.xx.im.api.redis.JedisUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
/**
* @program: Netty-WebSocket
* @description: 接收处理并响应客户端WebSocket请求的核心业务处理类
**/
@ChannelHandler.Sharable
public class MyWebsocketHandler extends SimpleChannelInboundHandler
初始化通道
MyWebsocketInitializer.java
import com.xx.im.api.config.Constants;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;
public class MyWebsocketInitializer extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(Constants.HTTP_CODEC, new HttpServerCodec());
ch.pipeline().addLast(Constants.AGGREGATOR, new HttpObjectAggregator(Constants.MAX_CONTENT_LENGTH));
ch.pipeline().addLast(Constants.HTTP_CHUNKED, new ChunkedWriteHandler());
ch.pipeline().addLast(Constants.HANDLER, new MyWebsocketHandler());
}
}
redis 工具类
JedisUtil.java
import com.alibaba.fastjson.JSON;
import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.xx.im.api.config.Constants;
import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.params.geo.GeoRadiusParam;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JedisUtil {
private static final int DEFAULT_SETEX_TIMEOUT = 60 * 60;// setex的默认时间
public static Jedis jedis ;
public static Jedis jedisSub ;
public static void init(){
try {
new Thread(JedisUtil::run).start();
System.out.println("im init ");
}catch (Exception e){
e.printStackTrace();
}
}
private static void run() {
jedis = new Jedis("192.168.9.135");
jedis.auth("xxxx");// 设置密码
jedis.connect();
jedisSub = new Jedis("192.168.9.135");
jedisSub.auth("xxxx");// 设置密码
RedisMsgPubSubListener listener = new RedisMsgPubSubListener();
jedisSub.subscribe(listener, Constants.IM_QUEUE_CHANNLID);
}
public static void pushMsg(String msg){
jedis.publish(Constants.IM_QUEUE_CHANNLID, msg);
}
/**
* 添加一个字符串值,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
public static int set(String key, String value) {
if (isValueNull(key, value)) {
return 0;
}
try {
if (jedis.set(key, value).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个字符串值,成功返回1,失败返回0,默认缓存时间为1小时,以本类的常量DEFAULT_SETEX_TIMEOUT为准
*
* @param key
* @param value
* @return
*/
public static int setEx(String key, String value) {
if (isValueNull(key, value)) {
return 0;
}
try {
if (jedis.setex(key, DEFAULT_SETEX_TIMEOUT, value).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个字符串值,成功返回1,失败返回0,缓存时间以timeout为准,单位秒
*
* @param key
* @param value
* @param timeout
* @return
*/
public static int setEx(String key, String value, int timeout) {
if (isValueNull(key, value)) {
return 0;
}
try {
if (jedis.setex(key, timeout, value).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个指定类型的对象,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
public static int set(String key, T value) {
if (isValueNull(key, value)) {
return 0;
}
try {
byte[] data = enSeri(value);
if (jedis.set(key.getBytes(), data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个指定类型的对象,成功返回1,失败返回0,默认缓存时间为1小时,以本类的常量DEFAULT_SETEX_TIMEOUT为准
*
* @param key
* @param value
* @return
*/
public static int setEx(String key, T value) {
if (isValueNull(key, value)) {
return 0;
}
try {
byte[] data = enSeri(value);
if (jedis.setex(key.getBytes(), DEFAULT_SETEX_TIMEOUT, data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个指定类型的对象,成功返回1,失败返回0,缓存时间以timeout为准,单位秒
*
* @param key
* @param value
* @param timeout
* @return
*/
public static int setEx(String key, T value, int timeout) {
if (isValueNull(key, value)) {
return 0;
}
try {
byte[] data = enSeri(value);
if (jedis.setex(key.getBytes(), timeout, data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 将一个数值+1,成功返回+后的结果,失败返回null
*
* @param key
* @return
* @throws JedisDataException
*/
public static Long incr(String key) throws JedisDataException {
if (isValueNull(key)) {
return null;
}
try {
return jedis.incr(key);
} finally {
}
}
/**
* 将一个数值+n,成功返回+后的结果,失败返回null
*
* @param key
* @return
* @throws JedisDataException
*/
public static Long incrBy(String key, long integer) throws JedisDataException {
if (isValueNull(key)) {
return null;
}
try {
return jedis.incrBy(key,integer);
} finally {
}
}
/**
* 将一个数值-1,成功返回-后的结果,失败返回null
*
* @param key
* @return
* @throws JedisDataException
*/
public static Long decr(String key) throws JedisDataException {
if (isValueNull(key)) {
return null;
}
try {
return jedis.decr(key);
} finally {
}
}
/**
* 将一个数值-n,成功返回-后的结果,失败返回null
*
* @param key
* @return
* @throws JedisDataException
*/
public static Long decrBy(String key,long integer) throws JedisDataException {
if (isValueNull(key)) {
return null;
}
try {
return jedis.decrBy(key, integer);
} finally {
}
}
/**
* 添加一个字符串值到list中,,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
public static int setList(String key, String... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
Long result = jedis.rpush(key, value);
if (result != null && result != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个字符串值到list中,全部list的key默认缓存时间为1小时,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
public static int setExList(String key, String... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
Long result = jedis.rpush(key, value);
jedis.expire(key, DEFAULT_SETEX_TIMEOUT);
if (result != null && result != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个字符串值到list中,全部list的key缓存时间为timeOut,单位为秒,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
public static int setExList(String key, int timeOut, String... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
Long result = jedis.rpush(key, value);
jedis.expire(key, timeOut);
if (result != null && result != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个类型对象值到list中,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
@SafeVarargs
public static int setList(String key, T... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
int res = 0;
for (T t : value) {
byte[] data = enSeri(t);
Long result = jedis.rpush(key.getBytes(), data);
if (result != null && result != 0) {
res++;
}
}
if (res != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个类型对象值到list中,全部list的key默认缓存时间为1小时,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
@SafeVarargs
public static int setExList(String key, T... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
int res = 0;
for (T t : value) {
byte[] data = enSeri(t);
Long result = jedis.rpush(key.getBytes(), data);
if (result != null && result != 0) {
res++;
}
}
jedis.expire(key, DEFAULT_SETEX_TIMEOUT);
if (res != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个类型对象值到list中,全部list的key缓存时间为timeOut,单位秒,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
@SafeVarargs
public static int setExList(String key, int timeOut, T... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
int res = 0;
for (T t : value) {
byte[] data = enSeri(t);
Long result = jedis.rpush(key.getBytes(), data);
if (result != null && result != 0) {
res++;
}
}
jedis.expire(key, timeOut);
if (res != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个List集合成功返回1,失败返回0
*
* @param key
* @param value
* @return
* @throws IOException
* @throws RuntimeException
*/
public static int setList(String key, List value) throws RuntimeException, IOException {
if (isValueNull(key, value)) {
return 0;
}
try {
byte[] data = enSeriList(value);
if (jedis.set(key.getBytes(), data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个List集合,成功返回1,失败返回0,默认缓存时间为1小时,以本类的常量DEFAULT_SETEX_TIMEOUT为准
*
* @param key
* @param value
* @return
* @throws IOException
* @throws RuntimeException
*/
public static int setExList(String key, List value) throws RuntimeException, IOException {
if (isValueNull(key, value)) {
return 0;
}
try {
byte[] data = enSeriList(value);
if (jedis.setex(key.getBytes(), DEFAULT_SETEX_TIMEOUT, data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个List集合,成功返回1,失败返回0,缓存时间以timeout为准,单位秒
*
* @param key
* @param value
* @param timeout
* @return
* @throws IOException
* @throws RuntimeException
*/
public static int setExList(String key, List value, int timeout) throws RuntimeException, IOException {
if (isValueNull(key, value)) {
return 0;
}
try {
byte[] data = enSeriList(value);
if (jedis.setex(key.getBytes(), timeout, data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个字符串到set,如果key存在就在就最追加,如果key不存在就创建,成功返回1,失败或者没有受影响返回0
*
* @param key
* @param value
* @return
*/
public static int setSet(String key, String... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
Long result = jedis.sadd(key, value);
if (result != null && result != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个字符串set,如果key存在就在就最追加,整个set的key默认一小时后过期,如果key存在就在可以种继续添加,如果key不存在就创建,成功返回1,失败或者没有受影响返回0
*
* @param key
* @param value
* @return
*/
public static int setExSet(String key, String... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
Long result = jedis.sadd(key, value);
jedis.expire(key, DEFAULT_SETEX_TIMEOUT);
if (result != null && result != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个字符串set,如果key存在就在就最追加,整个set的key有效时间为timeOut时间,单位秒,如果key存在就在可以种继续添加,如果key不存在就创建,,成功返回1,失败或者没有受影响返回0
*
* @param key
* @param value
* @return
*/
public static int setExSet(String key, int timeOut, String... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
Long result = jedis.sadd(key, value);
jedis.expire(key, timeOut);
if (result != null && result != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个类型到set集合,如果key存在就在就最追加,成功返回1,失败或者没有受影响返回0
*
* @param key
* @param value
* @return
*/
@SafeVarargs
public static int setSet(String key, T... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
int res = 0;
for (T t : value) {
byte[] data = enSeri(t);
Long result = jedis.sadd(key.getBytes(), data);
if (result != null && result != 0) {
res++;
}
}
if (res != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个类型到set集合,如果key存在就在就最追加,整个set的key默认有效时间为1小时,成功返回1,失败或者没有受影响返回0
*
* @param key
* @param value
* @return
*/
@SafeVarargs
public static int setExSet(String key, T... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
int res = 0;
for (T t : value) {
byte[] data = enSeri(t);
Long result = jedis.sadd(key.getBytes(), data);
if (result != null && result != 0) {
res++;
}
}
jedis.expire(key, DEFAULT_SETEX_TIMEOUT);
if (res != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个类型到set集合,如果key存在就在就最追加,整个set的key有效时间为timeOut,单位秒,成功返回1,失败或者没有受影响返回0
*
* @param key
* @param value
* @return
*/
@SafeVarargs
public static int setExSet(String key, int timeOut, T... value) {
if (isValueNull(key, value)) {
return 0;
}
try {
int res = 0;
for (T t : value) {
byte[] data = enSeri(t);
Long result = jedis.sadd(key.getBytes(), data);
if (result != null && result != 0) {
res++;
}
}
jedis.expire(key, timeOut);
if (res != 0) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 添加一个Map集合,成功返回1,失败返回0
*
* @param key
* @param value
* @return
*/
public static int setMap(String key, Map value) {
if (value == null || key == null || "".equals(key)) {
return 0;
}
try {
String data = JSON.toJSONString(value);
if (jedis.set(key, data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个Map集合,成功返回1,失败返回0,默认缓存时间为1小时,以本类的常量DEFAULT_SETEX_TIMEOUT为准
*
* @param key
* @param value
* @return
*/
public static int setExMap(String key, Map value) {
if (value == null || key == null || "".equals(key)) {
return 0;
}
try {
String data = JSON.toJSONString(value);
if (jedis.setex(key, DEFAULT_SETEX_TIMEOUT, data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 缓存一个Map集合,成功返回1,失败返回0,缓存时间以timeout为准,单位秒
*
* @param key
* @param value
* @param timeout
* @return
*/
public static int setExMap(String key, Map value, int timeout) {
if (value == null || key == null || "".equals(key)) {
return 0;
}
try {
String data = JSON.toJSONString(value);
if (jedis.setex(key, timeout, data).equalsIgnoreCase("ok")) {
return 1;
} else {
return 0;
}
} finally {
}
}
/**
* 获取一个字符串值
*
* @param key
* @return
*/
public static String get(String key) {
if (isValueNull(key)) {
return null;
}
try {
return jedis.get(key);
} finally {
}
}
/**
* 获得一个指定类型的对象
*
* @param key
* @param clazz
* @return
*/
public static T get(String key, Class clazz) {
if (isValueNull(key)) {
return null;
}
try {
byte[] data = jedis.get(key.getBytes());
T result = deSeri(data, clazz);
return result;
} finally {
}
}
/**
* 获得一个字符串集合,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1
* 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
*
* @param key
* @param start
* @param end
* @return
*/
public static List getList(String key, long start, long end) {
if (isValueNull(key)) {
return null;
}
try {
List result = jedis.lrange(key, start, end);
return result;
} finally {
}
}
/**
* 获得一个类型的对象集合,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。
* 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
*
* @param key
* @param start
* @param end
* @return
*/
public static List getList(String key, long start, long end, Class clazz) {
if (isValueNull(key)) {
return null;
}
try {
List lrange = jedis.lrange(key.getBytes(), start, end);
List result = null;
if (lrange != null) {
for (byte[] data : lrange) {
if (result == null) {
result = new ArrayList<>();
}
result.add(deSeri(data, clazz));
}
}
return result;
} finally {
}
}
/**
* 获得list中存了多少个值
*
* @return
*/
public static long getListCount(String key) {
if (isValueNull(key)) {
return 0;
}
try {
return jedis.llen(key);
} finally {
}
}
/**
* 获得一个List的集合,
*
* @param key 键
* @param clazz 返回集合的类型
* @return
* @throws IOException
*/
public static List getList(String key, Class clazz) throws IOException {
if (isValueNull(key)) {
return null;
}
try {
byte[] data = jedis.get(key.getBytes());
List result = deSeriList(data, clazz);
return result;
} finally {
}
}
/**
* 获得一个字符串set集合
*
* @param key
* @return
*/
public static Set getSet(String key) {
if (isValueNull(key)) {
return null;
}
try {
Set result = jedis.smembers(key);
return result;
} finally {
}
}
/**
* 获得一个字符串set集合
*
* @param key
* @return
*/
public static Set getSet(String key, Class clazz) {
if (isValueNull(key)) {
return null;
}
try {
Set smembers = jedis.smembers(key.getBytes());
Set result = null;
if (smembers != null) {
for (byte[] data : smembers) {
if (result == null) {
result = new HashSet<>();
}
result.add(deSeri(data, clazz));
}
}
return result;
} finally {
}
}
/**
* 获得集合中存在多少个值
*
* @param key
* @return
*/
public static long getSetCount(String key) {
if (isValueNull(key)) {
return 0;
}
try {
return jedis.scard(key);
} finally {
}
}
/**
* 获得一个Map的集合
*
* @param key
* @param v
* @param k
* @return
*/
public static Map getMap(String key, Class k, Class v) {
if (key == null || "".equals(key)) {
return null;
}
try {
String data = jedis.get(key);
@SuppressWarnings("unchecked")
Map result = (Map) JSON.parseObject(data);
return result;
} finally {
}
}
/**
* 判斷key是否存在
* @param key
* @return
*/
public static boolean exists(String key){
try {
return jedis.exists(key);
} finally {
}
}
/**
* 判斷key是否存在
* @param keys
* @return
*/
public static Long exists(String... keys){
try {
return jedis.exists(keys);
} finally {
}
}
/**
* 删除一个值
*
* @param key
*/
public static void del(String... key) {
try {
for (int i = 0; i < key.length; i++) {
jedis.del(key);
}
} finally {
}
}
// --------------------------公用方法区------------------------------------
/**
* 检查值是否为null,如果为null返回true,不为null返回false
*
* @param obj
* @return
*/
private static boolean isValueNull(Object... obj) {
for (int i = 0; i < obj.length; i++) {
if (obj[i] == null || "".equals(obj[i])) {
return true;
}
}
return false;
}
/**
* 序列化一个对象
*
* @param value
* @return
*/
private static byte[] enSeri(T value) {
@SuppressWarnings("unchecked")
RuntimeSchema schema = (RuntimeSchema) RuntimeSchema.createFrom(value.getClass());
byte[] data = ProtostuffIOUtil.toByteArray(value, schema,
LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
return data;
}
/**
* 反序列化一个对象
*
* @param data
* @param clazz
* @return
*/
private static T deSeri(byte[] data, Class clazz) {
if (data == null || data.length == 0) {
return null;
}
RuntimeSchema schema = RuntimeSchema.createFrom(clazz);
T result = schema.newMessage();
ProtostuffIOUtil.mergeFrom(data, result, schema);
return result;
}
/**
* 序列化List集合
*
* @param list
* @return
* @throws IOException
*/
private static byte[] enSeriList(List list) throws RuntimeException, IOException {
if (list == null || list.size() == 0) {
throw new RuntimeException("集合不能为空!");
}
@SuppressWarnings("unchecked")
RuntimeSchema schema = (RuntimeSchema) RuntimeSchema.getSchema(list.get(0).getClass());
ByteArrayOutputStream out = new ByteArrayOutputStream();
ProtostuffIOUtil.writeListTo(out, list, schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
byte[] byteArray = out.toByteArray();
return byteArray;
}
/**
* 反序列化List集合
*
* @param data
* @param clazz
* @return
* @throws IOException
*/
private static List deSeriList(byte[] data, Class clazz) throws IOException {
if (data == null || data.length == 0) {
return null;
}
RuntimeSchema schema = RuntimeSchema.createFrom(clazz);
List result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(data), schema);
return result;
}
//----------------------geo start------------------------------------------
/**
* 增加地理位置的坐标
*
* @param key
* @param coordinate
* @param member
* @return Long
*/
public static Long geoadd(String key, GeoCoordinate coordinate, String member) {
try {
return jedis.geoadd(key, coordinate.getLongitude(), coordinate.getLatitude(), member);
} finally {
}
}
/**
* 批量添加地理位置
*
* @param key
* @param memberCoordinateMap
* @return Long
*/
public static Long geoadd(String key, Map memberCoordinateMap) {
try {
return jedis.geoadd(key, memberCoordinateMap);
} finally {
}
}
/**
* 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序,)
*
* @param key
* @param coordinate
* @param radius
* @return List
*/
public static List geoRadius(String key, GeoCoordinate coordinate, double radius) {
try {
return jedis.georadius(key, coordinate.getLongitude(), coordinate.getLatitude(), radius, GeoUnit.KM, GeoRadiusParam.geoRadiusParam().withDist().withCoord().sortAscending());
} finally {
}
}
/**
* 根据给定地理位置获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序,)
*
* @param key
* @param member
* @param radius
* @return List
*/
public List georadiusByMember(String key, String member, double radius) {
try {
return jedis.georadiusByMember(key, member, radius, GeoUnit.KM, GeoRadiusParam.geoRadiusParam().withDist().withCoord().sortAscending());
} finally {
}
}
/**
* 查询2位置距离
*
* @param key
* @param member1
* @param member2
* @param unit
* @return Double
*/
public static Double geoDist(String key, String member1, String member2, GeoUnit unit) {
try {
Double dist = jedis.geodist(key, member1, member2, unit);
return dist;
} finally {
}
}
/**
* 查询位置的geohash
*
* @param key
* @param members
* @return List
*/
public static List geoHash(String key, String... members) {
try {
List resultList = jedis.geohash(key, members);
return resultList;
} finally {
}
}
/**
* 获取地理位置的坐标
*
* @param key
* @param member
* @return List
*/
public static List geopos(String key, String... member) {
try {
List result = jedis.geopos(key, member);
return result;
} finally {
}
}
}
redis 订阅监听
RedisMsgPubSubListener.java
import com.xx.im.api.config.NettyConfig;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.DefaultChannelId;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPubSub;
import java.util.Date;
/**
*/
public class RedisMsgPubSubListener extends JedisPubSub {
private static Logger log = LoggerFactory.getLogger(RedisMsgPubSubListener.class);
@Override
public void onMessage(String msgChannel, String iMChannelId) {
if (StringUtil.isNullOrEmpty(iMChannelId)){
return;
}
// 避免 如果不是在本机,则丢弃 避免 压力透彻到 redis
String isExists = NettyConfig.LOCALCHANNELMAP.get(iMChannelId);
if (StringUtil.isNullOrEmpty(isExists)){
// 离线则丢弃,不推送
return;
}
String msg = JedisUtil.get(iMChannelId);
if (StringUtil.isNullOrEmpty(msg)){
return;
}
ChannelId id = JedisUtil.get(iMChannelId+"Id", DefaultChannelId.class);
if (id == null){
return;
}
log.info("iMChannelId:"+iMChannelId+" msg:"+msg);
Channel channel = NettyConfig.GROUP.find(id);
if (channel != null){
String responseStr = new Date().toString() + channel.id() + " ===>>> " + msg;
TextWebSocketFrame tws = new TextWebSocketFrame(responseStr);
channel.writeAndFlush(tws);
//如果推送完成,在清理到 redis中的 消息
JedisUtil.del(iMChannelId);
}
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
log.info("channel:" + channel + "is been subscribed:" + subscribedChannels);
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
log.info("channel:" + channel + "is been unsubscribed:" + subscribedChannels);
}
}
启动类
WebsocketServer.java
import com.xx.im.api.config.Constants;
import com.xx.im.api.handler.MyWebsocketInitializer;
import com.xx.im.api.redis.JedisUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebsocketServer {
private static Logger log = LoggerFactory.getLogger(WebsocketServer.class);
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
//启动订阅
JedisUtil.init();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new MyWebsocketInitializer());
log.info("服务端开启等待客户端连接...");
Channel channel = bootstrap.bind(Constants.PORT).sync().channel();
channel.closeFuture().sync();
} catch (Exception e) {
log.error("服务端启动失败", e);
} finally {
// 退出程序
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
log.info("服务端已关闭");
}
}
}
测试客户端
ws123.html
WebSocket客户端