用redis实现类似微信摇一摇
- - 数据库 - ITeye博客1, 客户端上传用户id和经纬度. 客户端在等待n秒后, 将用户id和上次服务器返回的字符串(wkw69y)一起上传至服务器端, 服务器端只需用redis的 keys wkw69y* 就能获取所有的key, 通过截取key中的userid就可以得到附近的人的用户id. 3, 如果客户端要显示相距xx米,按距离排序怎么搞.
@RequestMapping(value = "/xx") @ResponseBody public String yaoYiYao(Integer userid, String pwd, Double longitude, Double latitude) { String hashval = GeoHash.encode(latitude, longitude); //密码-hash值-用户id, 拼接起来作为redis的key String key = (StringUtils.isNotBlank(pwd) ? "" : (pwd.trim() + "-")) + hashval + "-" + userid; redisCache.setWithExpire(key, "", 10); return (StringUtils.isNotBlank(pwd) ? "" : (pwd.trim() + "-")) + hashval.substring(0, 6); }
@RequestMapping(value = "/xx") @ResponseBody public String yaoYiYaoList(Integer userid, String hashval) { //从redis中取出所有以hashval开头的key Set<String> set = redisCache.keys(hashval + "*"); if (CollectionUtils.isEmpty(set)) { return null; } Set<Integer> useridSet = new HashSet<>(); //遍历key, 从key中截取出用户id for (String key : set) { String keyArr[] = key.split("-"); useridSet.add(Integer.valueOf(keyArr[keyArr.length - 1]));//取最后一个 } useridSet.remove(userid);//排除自己 // TODO 已经拿到用户id集合, 接下来就是查询数据了 }
import java.util.BitSet; import java.util.HashMap; public class GeoHash { private static int numbits = 6 * 5; //经纬度单独编码长度 //32位编码对应字符 final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; //定义编码映射关系 final static HashMap<Character, Integer> lookup = new HashMap<Character, Integer>(); //初始化编码映射内容 static { int i = 0; for (char c : digits) lookup.put(c, i++); } //对编码后的字符串解码 public double[] decode(String geohash) { StringBuilder buffer = new StringBuilder(); for (char c : geohash.toCharArray()) { int i = lookup.get(c) + 32; buffer.append(Integer.toString(i, 2).substring(1)); } BitSet lonset = new BitSet(); BitSet latset = new BitSet(); //偶数位,经度 int j = 0; for (int i = 0; i < numbits * 2; i += 2) { boolean isSet = false; if (i < buffer.length()) isSet = buffer.charAt(i) == '1'; lonset.set(j++, isSet); } //奇数位,纬度 j = 0; for (int i = 1; i < numbits * 2; i += 2) { boolean isSet = false; if (i < buffer.length()) isSet = buffer.charAt(i) == '1'; latset.set(j++, isSet); } double lon = decode(lonset, -180, 180); double lat = decode(latset, -90, 90); return new double[] { lat, lon }; } //根据二进制和范围解码 private double decode(BitSet bs, double floor, double ceiling) { double mid = 0; for (int i = 0; i < bs.length(); i++) { mid = (floor + ceiling) / 2; if (bs.get(i)) floor = mid; else ceiling = mid; } return mid; } //对经纬度进行编码 public static String encode(double lat, double lon) { BitSet latbits = getBits(lat, -90, 90); BitSet lonbits = getBits(lon, -180, 180); StringBuilder buffer = new StringBuilder(); for (int i = 0; i < numbits; i++) { buffer.append((lonbits.get(i)) ? '1' : '0'); buffer.append((latbits.get(i)) ? '1' : '0'); } return base32(Long.parseLong(buffer.toString(), 2)); } //根据经纬度和范围,获取对应二进制 private static BitSet getBits(double lat, double floor, double ceiling) { BitSet buffer = new BitSet(numbits); for (int i = 0; i < numbits; i++) { double mid = (floor + ceiling) / 2; if (lat >= mid) { buffer.set(i); floor = mid; } else { ceiling = mid; } } return buffer; } //将经纬度合并后的二进制进行指定的32位编码 private static String base32(long i) { char[] buf = new char[65]; int charPos = 64; boolean negative = (i < 0); if (!negative) i = -i; while (i <= -32) { buf[charPos--] = digits[(int) (-(i % 32))]; i /= 32; } buf[charPos] = digits[(int) (-i)]; if (negative) buf[--charPos] = '-'; return new String(buf, charPos, (65 - charPos)); } public static void main(String[] args) throws Exception { GeoHash geohash = new GeoHash(); String s = geohash.encode(25.770000, 110.125555); System.out.println(s); double[] geo = geohash.decode(s); System.out.println(geo[0] + " " + geo[1]); } }