第9章 地址位置功能实现

今日内容介绍

63598678289

学习目标

  • 谁看过我的功能实现
  • 我的喜欢的功能实现
  • 上报地理位置功能实现
  • 搜附近的功能实现

1. 谁看过我

【目标】

掌握谁看过我功能实现

【路径】

1:谁看过我功能分析

2:谁看过我功能实现

【讲解】

记录别人来访了我的主页的信息。

  • 保存访问记录
  • 查询访问记录
    • 根据时间判断

1.1. 数据库

image-20201109085126529

userId:被访问人的用户id

visitorUserId:访问者的用户id

1.2. 服务消费者-谁看过我

61459332378

1.2.1. mock接口

地址: https://mock.boxuegu.com/project/164/interface/api/64750

1571493569274

1571493588218

1.2.2. VisitorVo

package com.tanhua.domain.vo;

import lombok.Data;

import java.io.Serializable;

@Data
public class VisitorVo implements Serializable {
    private Long id;
    private String avatar;
    private String nickname;
    private String gender;
    private Integer age;
    private String[] tags;
    private Integer fateValue;
}

1.2.3. Visitor

package com.tanhua.domain.mongo;

import lombok.Data;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.Serializable;

@Data
@Document(collection = "visitors")
public class Visitor implements Serializable {

    private ObjectId id;
    private Long userId; //我的id
    private Long visitorUserId; //来访用户id
    private String from; //来源,如首页、圈子等
    private Long date; //来访时间

    private Double score; //得分
}

1.2.4. MomentController

    /**
     * 谁看过我 /movements/visitors
     */
    @RequestMapping(value = "/visitors",method = RequestMethod.GET)
    public ResponseEntity findListVisitors() {
        List<VisitorVo> list = movementsService.findListVisitors();
        return ResponseEntity.ok(list);
    }

1.2.5. MomentsService

    /**
     * 谁看过我
     */
    public List<VisitorVo> findListVisitors() {
        Long userId = UserHolder.getUserId();
        String key ="visitors_time_"+userId;
        //1 查询redis看当前用户上次访问时间是否存在
        String redisTime = redisTemplate.opsForValue().get(key);
        List<Visitor> visitorList = new ArrayList<>();
        if(!StringUtils.isEmpty(redisTime)) {
            //2 如果时间存在,根据表中date > redis中上次访问时间 + limit 5
            visitorList = visitorsApi.findListVisitorsByTime(userId,Long.parseLong(redisTime));
        }else {
            //3 如果时间不存在, limit 5
            visitorList = visitorsApi.findListVisitors(userId);
        }
        //4 将当前操作时间记录redis
        redisTemplate.opsForValue().set(key,System.currentTimeMillis()+"");
        if(visitorList == null){
            return null;
        }
        //5.visitorList遍历(将 List<Visitor>  转为  List<VisitorVo>)
        List<VisitorVo> visitorVoList = new ArrayList<>();
        for (Visitor visitor : visitorList) {
            VisitorVo visitorVo = new VisitorVo();
            Long visitorUserId = visitor.getVisitorUserId();//访问的用户id
            UserInfo userInfo = userInfoApi.findUserInfoByUserId(visitorUserId);//访客的用户信息
            BeanUtils.copyProperties(userInfo,visitorVo);//avatar  nickname gender   age
            visitorVo.setId(visitorUserId);//访客用户id
            if(!StringUtils.isEmpty(userInfo.getTags())){
                visitorVo.setTags(userInfo.getTags().split(","));//标签
            }
            visitorVo.setFateValue(visitor.getScore().intValue());//缘分值
            visitorVoList.add(visitorVo);
        }
        return visitorVoList;
    }

1.3. 服务提供者-谁看过我

1.3.1. VisitorApi

编写VisitorsApi

package com.tanhua.dubbo.api.mongo;

import com.tanhua.domain.mongo.Visitor;

import java.util.List;

/**
 * 访问服务接口
 */
public interface VisitorsApi {
    /**
     * 根据当前用户id 和 上次登录时间 查询5条记录
     * @param userId
     * @param redisTime
     * @return
     */
    List<Visitor> findListVisitorsByTime(Long userId, Long redisTime);

    /**
     * 根据当前用户id  查询5条记录
     * @param userId
     * @return
     */
    List<Visitor> findListVisitors(Long userId);


    /**
     * 保存访客记录
     */
    void saveVisitor(Visitor visitor);
}

1.3.2. VisitorApiImpl

编写VisitorsApiImpl

package com.tanhua.dubbo.api.mongo;

import com.tanhua.domain.mongo.Visitor;
import org.apache.dubbo.config.annotation.Service;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.List;

/**
 * 访客服务接口实现类
 */
@Service
public class VisitorsApiImpl implements VisitorsApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 根据当前用户id 和 上次登录时间 查询5条记录
     * @param userId
     * @param redisTime
     * @return
     */
    @Override
    public List<Visitor> findListVisitorsByTime(Long userId, Long redisTime) {
        Query query = new Query();
        query.addCriteria(
                Criteria.where("userId").is(userId)
                .and("date").gt(redisTime)
        );
        query.limit(5);
        query.with(Sort.by(Sort.Direction.DESC,"date"));
        return mongoTemplate.find(query,Visitor.class);
    }

    /**
     * 根据当前用户id  查询5条记录
     * @param userId
     * @return
     */
    @Override
    public List<Visitor> findListVisitors(Long userId) {
        Query query = new Query();
        query.addCriteria(
                Criteria.where("userId").is(userId)
        );
        query.limit(5);
        query.with(Sort.by(Sort.Direction.DESC,"date"));
        return mongoTemplate.find(query,Visitor.class);
    }


    /**
     * 保存访客记录
     */
    @Override
    public void saveVisitor(Visitor visitor) {
        visitor.setId(ObjectId.get());
        visitor.setDate(System.currentTimeMillis());
        mongoTemplate.save(visitor);
    }
}

1.3.3. 构造测试数据

package com.tanhua.dubbo.test;

import com.tanhua.domain.mongo.Visitor;
import com.tanhua.dubbo.api.mongo.VisitorsApi;
import org.apache.commons.lang3.RandomUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class TestVisitors {

    @Autowired
    private VisitorsApi visitorApi;

    @Test
    public void testSave(){
        for (int i = 0; i < 100; i++) {
            Visitor visitor = new Visitor();
            visitor.setFrom("首页");
            visitor.setUserId(130l);//用户id
            visitor.setScore(77d);
            visitor.setVisitorUserId(RandomUtils.nextLong(11,50));
            this.visitorApi.saveVisitor(visitor);
        }
        System.out.println("ok");
    }
}

1.3.4. 测试

postman测试:

61348943836

app测试:

61348951556

【小结】

掌握谁看过我功能实现

2. 我的喜欢

【目标】

掌握互相喜欢、喜欢、粉丝功能实现

【路径】

1: 互相喜欢、喜欢、粉丝统计

2: 查询相互喜欢、我喜欢、粉丝列表分页查询

3:粉丝-喜欢

【讲解】

在我的模块中,将详细展现“喜欢”相关的数据,如下:

1572445671626

1572445655283

2.1. 我的喜欢介绍

  • 喜欢
    • 我喜欢别人,如:张三喜欢李四,就是喜欢的数据,并不代表李四也喜欢张三。
  • 粉丝
    • 对于李四而言,张三就是他的粉丝。
  • 相互关注(喜欢)
    • 如果李四也喜欢张三,那么,张三和李四就是相互喜欢。两个人添加好友关系!

2.2. 服务消费者-互相喜欢、喜欢、粉丝统计

61458155807

2.2.1. mock接口

1572446825205

1572446837503

2.2.2. CountsVo


package com.tanhua.domain.vo;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;

@Data
@AllArgsConstructor
public class CountsVo implements Serializable {
    private Long eachLoveCount; //互相喜欢
    private Long loveCount; //喜欢
    private Long fanCount; //粉丝
}

2.2.3. UserInfoController

    /**
     *  互相喜欢、喜欢、粉丝统计
     */
    @RequestMapping(value = "/counts",method = RequestMethod.GET)
    public ResponseEntity findCounts(){
        CountsVo countsVo = userInfoService.findCounts();
        return ResponseEntity.ok(countsVo);
    }

2.2.4. UserService

    /**
     *  互相喜欢、喜欢、粉丝统计
     */
    public CountsVo findCounts() {
        Long userId = UserHolder.getUserId();
        //1. 根据当前用户id查询好友表 互相喜欢数量
        Long eachLoveCount = friendApi.findEachLoveCount(userId);
        //2  根据当前用户id查询喜欢表 喜欢数量
        Long loveCount = userLikeApi.findLoveCount(userId);
        //3 根据当前用户id查询喜欢表 粉丝数量
        Long fanCount = userLikeApi.findFanCount(userId);
        return new CountsVo(eachLoveCount,loveCount,fanCount);
    }

2.3. 服务提供者-互相喜欢、喜欢、粉丝统计

2.3.1. UserLike

package com.tanhua.domain.mongo;

import lombok.Data;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.Serializable;
 
@Data
@Document(collection = "user_like")
public class UserLike implements Serializable {

    private ObjectId id;
    @Indexed
    private Long userId; //用户id,自己
    @Indexed
    private Long likeUserId; //喜欢的用户id,对方

    private Long created; //创建时间
}

2.3.2. UserLikeApi

package com.tanhua.dubbo.api.mongo;

/**
 * 喜欢服务接口
 */
public interface UserLikeApi {
    /**
     *喜欢数量
     * @param userId
     * @return
     */
    Long findLoveCount(Long userId);

    /**
     * 粉丝数量
     * @param userId
     * @return
     */
    Long findFanCount(Long userId);
}

2.2.3. UserLikeApiImpl

package com.tanhua.dubbo.api.mongo;

import com.tanhua.domain.mongo.UserLike;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

/**
 * 喜欢服务接口
 */
@Service
public class UserLikeApiImpl implements UserLikeApi{
    @Autowired
    private MongoTemplate mongoTemplate;
    /**
     *喜欢数量
     * @param userId
     * @return
     */
    @Override
    public Long findLoveCount(Long userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        return mongoTemplate.count(query, UserLike.class);
    }
    /**
     * 粉丝数量
     * @param userId
     * @return
     */
    @Override
    public Long findFanCount(Long userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("likeUserId").is(userId));
        return mongoTemplate.count(query, UserLike.class);
    }
}

2.3.4 FriendApi

/**
 *互相喜欢数量
 * @param userId
 * @return
 */
Long findEachLoveCount(Long userId);

2.3.5 FriendApiImpl

    /**
     *互相喜欢数量
     * @param userId
     * @return
     */
    @Override
    public Long findEachLoveCount(Long userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        return mongoTemplate.count(query,Friend.class);
    }

2.3.6. 测试

postman测试

61349498705

app测试

61349504238

2.4. 服务消费者-查询相互喜欢、我喜欢、粉丝列表

谁看过我 分页查询

61460191112

2.4.1. 接口说明

该接口集成了4个接口,用type做了区分,如下:

1 互相关注 2 我关注 3 粉丝 4 谁看过我

1572509882278

2.4.2. FriendVo

package com.tanhua.domain.vo;

import lombok.Data;

import java.io.Serializable;

@Data
public class FriendVo implements Serializable {

    private Long id;
    private String avatar;
    private String nickname;
    private String gender;
    private Integer age;
    private String city;
    private String education;
    private Integer marriage; //婚姻状态(0未婚,1已婚)
    private Integer matchRate; //匹配度
}

2.4.3. UserInfoController

    /**
     *  互相喜欢、喜欢、粉丝、谁看过我 - 翻页列表
     * 1 互相关注
     * 2 我关注
     * 3 粉丝
     * 4 谁看过我
     */
    @RequestMapping(value = "/friends/{type}",method = RequestMethod.GET)
    public ResponseEntity findPageFriend(@PathVariable("type") int type,@RequestParam(defaultValue = "1") int page,
    @RequestParam(defaultValue = "10") int pagesize){
        PageResult<FriendVo> friendVoPageResult = userInfoService.findPageFriend(type,page,pagesize);
        return ResponseEntity.ok(friendVoPageResult);
    }

2.4.4. UserService

    /**
     *  互相喜欢、喜欢、粉丝、谁看过我 - 翻页列表
     * 1 互相关注
     * 2 我关注
     * 3 粉丝
     * 4 谁看过我
     */
    public PageResult<FriendVo> findPageFriend(int type, int page, int pagesize) {
        Long userId = UserHolder.getUserId();
        //1 调用服务 分页查询 互相喜欢、喜欢、粉丝、谁看过我(PageResult<RecommendUser)
        PageResult<RecommendUser> pageResult = new PageResult<>();
        switch (type){
            case 1:
                pageResult = userLikeApi.findPageLikeEachOther(userId,page,pagesize);
                break;
            case 2:
                pageResult = userLikeApi.findPageOneSideLike(userId,page,pagesize);
                break;
            case 3:
                pageResult = userLikeApi.findPageFens(userId,page,pagesize);
                break;
            case 4:
                pageResult = userLikeApi.findPageMyVisitors(userId,page,pagesize);
                break;
            default: break;
        }
        if(pageResult == null || CollectionUtils.isEmpty(pageResult.getItems())){
            return new PageResult<>(10l,10l,1l,1l,null);
        }
        //2 循环遍历List<RecommendUser> 查询tb_user_info
        List<FriendVo> friendVoList = new ArrayList<>();
        for (RecommendUser recommendUser : pageResult.getItems()) {
            FriendVo friendVo = new FriendVo();
            Long friendUserId = recommendUser.getUserId();///展示的用户id
            UserInfo userInfo = userInfoApi.findUserInfoByUserId(friendUserId);
            BeanUtils.copyProperties(userInfo,friendVo);//除了缘分值 都有
            friendVo.setMatchRate(recommendUser.getScore().intValue());//缘分值
            friendVo.setId(friendUserId);//展示的用户id(互相喜欢 喜欢 粉丝 谁看过我的用户id)
            friendVoList.add(friendVo);
        }
        //3 构造vo返回
        PageResult<FriendVo> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(pageResult,voPageResult); //copy counts pagesize pages page
        voPageResult.setItems(friendVoList);//设置返回集合Vo
        return voPageResult;
    }

2.5. 服务提供者-查询相互喜欢、我喜欢、粉丝列表 谁看过我 分页查询

2.5.1. UserLikeApi

   /**
     * 互相喜欢分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    PageResult<RecommendUser> findPageLikeEachOther(Long userId, int page, int pagesize);

    /**
     * 我喜欢分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    PageResult<RecommendUser> findPageOneSideLike(Long userId, int page, int pagesize);

    /**
     *粉丝分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    PageResult<RecommendUser> findPageFens(Long userId, int page, int pagesize);

    /**
     * 谁看过我分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    PageResult<RecommendUser> findPageMyVisitors(Long userId, int page, int pagesize);

2.5.2. UserLikeApiImpl

    /**
     * 互相喜欢分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    @Override
    public PageResult<RecommendUser> findPageLikeEachOther(Long userId, int page, int pagesize) {
        //1.查询好友表总记录数
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.limit(pagesize);
        query.skip((page-1)*pagesize);
        long counts = mongoTemplate.count(query, Friend.class);
        //2 分页查询当前页面需要展示的数据
        List<Friend> friendList = mongoTemplate.find(query, Friend.class);
        if(CollectionUtils.isEmpty(friendList)){
            return null;
        }
        //3.根据好友表中查询好友id再查询推荐用户表 得到缘分值
        List<RecommendUser> recommendUserList = new ArrayList<>();
        for (Friend friend : friendList) {
            Long currentUserId = friend.getUserId(); //当前用户id
            Long friendId = friend.getFriendId();//好友用户id
            recommendUserList.add(getRecommendUser(currentUserId, friendId));
        }
        //4.构造PageResult<RecommendUser>分页对象返回
        long pages =  counts/pagesize + (counts%pagesize > 0 ?1:0);
        return new PageResult<>(counts,(long)pagesize,pages,(long)page,recommendUserList);
    }

    /**
     * 我喜欢分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    @Override
    public PageResult<RecommendUser> findPageOneSideLike(Long userId, int page, int pagesize) {
        //1.查询好友表总记录数
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.limit(pagesize);
        query.skip((page-1)*pagesize);
        long counts = mongoTemplate.count(query, UserLike.class);
        //2 分页查询当前页面需要展示的数据
        List<UserLike> userLikeList = mongoTemplate.find(query, UserLike.class);
        if(CollectionUtils.isEmpty(userLikeList)){
            return null;
        }
        //3.根据好友表中查询好友id再查询推荐用户表 得到缘分值
        List<RecommendUser> recommendUserList = new ArrayList<>();
        for (UserLike userLike : userLikeList) {
            Long currentUserId = userLike.getUserId(); //当前用户id
            Long friendId = userLike.getLikeUserId();//好友用户id
            recommendUserList.add(getRecommendUser(currentUserId, friendId));
        }
        //4.构造PageResult<RecommendUser>分页对象返回
        long pages =  counts/pagesize + (counts%pagesize > 0 ?1:0);
        return new PageResult<>(counts,(long)pagesize,pages,(long)page,recommendUserList);
    }

    /**
     * 互相喜欢等分页公共方法
     * @param currentUserId
     * @param friendId
     * @return
     */
    private RecommendUser getRecommendUser(Long currentUserId, Long friendId) {
        Query recommendQuery = new Query();
        recommendQuery.addCriteria(Criteria.where("userId").is(friendId).and("toUserId").is(currentUserId));
        RecommendUser recommendUser = mongoTemplate.findOne(recommendQuery, RecommendUser.class);
        if (recommendUser == null || recommendUser.getScore() == null) {
            //设置默认值
            recommendUser = new RecommendUser();
            recommendUser.setScore(66.6);//默认缘分值
            recommendUser.setToUserId(currentUserId);//当前登录用户id
            recommendUser.setUserId(friendId);//好友id
        }
        return recommendUser;
    }

    /**
     *粉丝分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    @Override
    public PageResult<RecommendUser> findPageFens(Long userId, int page, int pagesize) {
        //1.查询好友表总记录数
        Query query = new Query();
        query.addCriteria(Criteria.where("likeUserId").is(userId));
        query.limit(pagesize);
        query.skip((page-1)*pagesize);
        long counts = mongoTemplate.count(query, UserLike.class);
        //2 分页查询当前页面需要展示的数据
        List<UserLike> userLikeList = mongoTemplate.find(query, UserLike.class);
        if(CollectionUtils.isEmpty(userLikeList)){
            return null;
        }
        //3.根据好友表中查询好友id再查询推荐用户表 得到缘分值
        List<RecommendUser> recommendUserList = new ArrayList<>();
        for (UserLike userLike : userLikeList) {
            Long currentUserId = userLike.getLikeUserId(); //当前用户id
            Long friendId = userLike.getUserId();//好友用户id
            recommendUserList.add(getRecommendUser(currentUserId, friendId));
        }
        //4.构造PageResult<RecommendUser>分页对象返回
        long pages =  counts/pagesize + (counts%pagesize > 0 ?1:0);
        return new PageResult<>(counts,(long)pagesize,pages,(long)page,recommendUserList);
    }

    /**
     * 谁看过我分页查询
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    @Override
    public PageResult<RecommendUser> findPageMyVisitors(Long userId, int page, int pagesize) {
        //1.查询好友表总记录数
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        query.limit(pagesize);
        query.skip((page-1)*pagesize);
        long counts = mongoTemplate.count(query, Visitor.class);
        //2 分页查询当前页面需要展示的数据
        List<Visitor> visitorList = mongoTemplate.find(query, Visitor.class);
        if(CollectionUtils.isEmpty(visitorList)){
            return null;
        }
        //3.根据好友表中查询好友id再查询推荐用户表 得到缘分值
        List<RecommendUser> recommendUserList = new ArrayList<>();
        for (Visitor visitor : visitorList) {
            Long currentUserId = visitor.getUserId(); //当前用户id
            Long friendId = visitor.getVisitorUserId();//好友用户id
            recommendUserList.add(getRecommendUser(currentUserId, friendId));
        }
        //4.构造PageResult<RecommendUser>分页对象返回
        long pages =  counts/pagesize + (counts%pagesize > 0 ?1:0);
        return new PageResult<>(counts,(long)pagesize,pages,(long)page,recommendUserList);
    }

2.5.3. 测试

postman测试

61349854095

app测试

61349858223

61349861390

61349863233

61349865028

61349867833

2.6. 服务消费者-喜欢

61458366968

2.6.1. UserInfoController

   /**
     * 粉丝-喜欢
     * 请求连接:POST  /fans/:uid
     */
    @PostMapping("/fans/{id}")
    public ResponseEntity fansLike(@PathVariable("id") Long likeUserId) {
        return userService.fansLike(likeUserId);
    }

2.6.2. UserService

   @Reference
   private FriendApi friendApi;

   /**
     * 对关注我的粉丝,进行喜欢操作
     *  likeUserId : 粉丝的用户id
     */
    public ResponseEntity fansLike(Long likeUserId) {
        //1、删除粉丝的关注数据
        userLikeApi.delete(likeUserId,UserHolder.getUserId());
        //2、记录双向的好友关系
        friendApi.add(UserHolder.getUserId(),likeUserId);
        //3、注册好友关系到环信
        huanXinTemplate.makeFriends(UserHolder.getUserId(),likeUserId);
        return ResponseEntity.ok(null);
    }

2.7. 服务提供者-喜欢

2.7.1. UserLikeApi

//喜欢
void delete(Long userId, Long likeUserId);

2.7.2. UserLikeApiImpl

@Override
public void delete(Long userId, Long likeUserId) {
    Query query = new Query(
        Criteria.where("userId").is(userId)
        .and("likeUserId").is(likeUserId)
    );
    mongoTemplate.remove(query, UserLike.class);
}

2.7.3. 测试

61350146063

【小结】

掌握互相喜欢、喜欢、粉丝功能实现

3. 地理位置(重点)

【目标】

掌握地址位置功能实现

【路径】

1: 地址位置功能分析

2: 地址位置功能实现

【讲解】

客户端检测用户的地理位置,当变化大于500米时或每隔5分钟,向服务端发送地理位置。

3.1. 服务消费者-地址位置

61460702991

3.1.1. 接口说明

image-20201108182903957

3.1.2. UserLocationController

package com.tanhua.server.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * 搜附近-控制层
 */
@RestController
@RequestMapping("/baidu")
public class UserLocationController {

    @Autowired
    private UserLocationService userLocationService;

    /**
     * 上报地理位置
     */
    @RequestMapping(value = "/location",method = RequestMethod.POST)
    public ResponseEntity saveUserLocation(@RequestBody Map params){
        Double latitude =(Double) params.get("latitude");///纬度
        Double longitude =(Double) params.get("longitude");//经度
        String addrStr = (String)params.get("addrStr");//位置描述
        userLocationService.saveUserLocation(latitude,longitude,addrStr);
        return ResponseEntity.ok(null);
    }
}

3.1.3. UserLocationService

package com.tanhua.server.service;

import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 搜附近业务逻辑处理层
 */
@Service
@Transactional
public class UserLocationService {

    @Reference
    private UserLocationApi userLocationApi;


    /**
     * 上报地理位置
     */
    public void saveUserLocation(Double latitude, Double longitude, String addrStr) {
        //调用服务 上报地理位置(保存地址 或 更新地址)
        userLocationApi.saveUserLocation(latitude, longitude, addrStr, UserHolder.getUserId());
    }
}

3.2. 服务提供者-地址位置

3.2.1. UserLocation

package com.tanhua.domain.mongo;

import lombok.Data;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.Serializable;
 
@Data
@Document(collection = "user_location")
@CompoundIndex(name = "location_index", def = "{'location': '2dsphere'}")
public class UserLocation implements Serializable {

    @Id
    private ObjectId id;
    @Indexed
    private Long userId; //用户id
    private GeoJsonPoint location; //x:经度 y:纬度
    private String address; //位置描述
    private Long created; //创建时间
    private Long updated; //更新时间
    private Long lastUpdated; //上次更新时间
}

3.2.2. UserLocationApi

package com.tanhua.dubbo.api.mongo;

import com.tanhua.domain.vo.UserLocationVo;

import java.util.List;

/**
 * 搜附近服务接口
 */
public interface UserLocationApi {
    /**
     * 上报地理位置
     */
    void saveUserLocation(Double latitude, Double longitude, String addrStr, Long userId);
}

3.2.3. UserLocationApiImpl

package com.tanhua.dubbo.api.mongo;

import com.tanhua.domain.mongo.UserLocation;
import com.tanhua.domain.vo.UserLocationVo;
import org.apache.dubbo.config.annotation.Service;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.List;

/**
 * 搜附近服务接口实现类
 */
@Service
public class UserLocationApiImpl implements UserLocationApi{

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 上报地理位置
     *
     * latitude  //纬度
     * longitude //经度
     * “x表示当地的纬度,y表示当地的经度
     */
    @Override
    public void saveUserLocation(Double latitude, Double longitude, String addrStr, Long userId) {
        //1.根据当前登录用户id 查询用户地理位置数据是否存在
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        long nowTime = System.currentTimeMillis();
        if(!mongoTemplate.exists(query, UserLocation.class)) {
            //2 如果不存在,则直接保存当前用户地理位置
            UserLocation userLocation = new UserLocation();
            userLocation.setId(ObjectId.get());//主键id
            userLocation.setUserId(userId);//当前用户id
            //double x, double y
            userLocation.setLocation(new GeoJsonPoint(latitude,longitude));
            userLocation.setAddress(addrStr);//地理位置中文
            userLocation.setCreated(nowTime);
            userLocation.setUpdated(nowTime);
            userLocation.setLastUpdated(nowTime);
            mongoTemplate.insert(userLocation);
        }else {
            //3 如果存在,则直接更新当前用户地理位置
            Query updateQuery = new Query();
            query.addCriteria(Criteria.where("userId").is(userId));
            Update update = new Update();
            update.set("location",new GeoJsonPoint(latitude,longitude));
            update.set("address",addrStr);
            update.set("updated",nowTime);
            update.set("lastUpdated",nowTime);
            mongoTemplate.updateFirst(updateQuery,update,UserLocation.class);
        }
    }
 
}

3.2.4. 测试

坐标拾取系统:http://api.map.baidu.com/lbsapi/getpoint/index.html

61350344232

造测试数据

tanhua-dubbo-service模块test包下

package com.tanhua.dubbo.test;

import com.tanhua.dubbo.api.mongo.UserLocationApi;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserLocationTest {

    @Autowired
    private UserLocationApi userLocationApi;

    /**
     * latitude  //纬度
     * longitude //经度
     * “x表示当地的纬度  >  y表示当地的经度
     */
    @Test
    public void saveUserLocation(){
        userLocationApi.saveUserLocation(22.582111,113.929778,"深圳黑马程序员",1l);
        userLocationApi.saveUserLocation(113.929778,22.582111,"深圳黑马程序员",1l);
        userLocationApi.saveUserLocation(113.925528,22.587995,"红荔村肠粉",2l);
        userLocationApi.saveUserLocation(113.93814,22.562578,"深圳南头直升机场",3l);
        userLocationApi.saveUserLocation(114.064478,22.549528,"深圳市政府",4l);
        userLocationApi.saveUserLocation(113.986074,22.547726,"欢乐谷",5l);
        userLocationApi.saveUserLocation(113.979399,22.540746,"世界之窗",6l);
        userLocationApi.saveUserLocation(114.294924,22.632275,"东部华侨城",7l);
        userLocationApi.saveUserLocation(114.314011,22.598196,"大梅沙海滨公园",8l);
        userLocationApi.saveUserLocation(113.821705,22.638172,"深圳宝安国际机场",9l);
        userLocationApi.saveUserLocation(113.912386,22.566223,"海雅缤纷城(宝安店)",10l);
    }
}

【小结】

掌握地址位置功能实现

4、搜附近(重点)

【目标】

掌握搜附近功能实现

【路径】

1: 搜附近功能分析

2: 搜附近功能实现

【讲解】

在首页中点击“搜附近”可以搜索附近的好友,效果如下:

1571966080530

4.1. 服务消费者-搜附近

61459202064

4.1.1. 接口说明

1571993019268

1571993038155

4.1.2. NearUserVo

package com.tanhua.server.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class NearUserVo {
    private Long userId;
    private String avatar;
    private String nickname;
}

4.1.3. UserLocationVo

由于UserLocation不能序列化,所以要再定义UserLocationVo进行返回数据。

package com.tanhua.domain.vo;

import com.tanhua.domain.mongo.UserLocation;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Data
public class UserLocationVo implements Serializable {
    private String id;
    private Long userId; //用户id
    private Double longitude; //经度
    private Double latitude; //维度
    private String address; //位置描述
    private Long created; //创建时间
    private Long updated; //更新时间
    private Long lastUpdated; //上次更新时间

    public static final UserLocationVo format(UserLocation userLocation) {
        UserLocationVo userLocationVo = new UserLocationVo();
        userLocationVo.setAddress(userLocation.getAddress());
        userLocationVo.setCreated(userLocation.getCreated());
        userLocationVo.setId(userLocation.getId().toHexString());
        userLocationVo.setLastUpdated(userLocation.getLastUpdated());
        userLocationVo.setUpdated(userLocation.getUpdated());
        userLocationVo.setUserId(userLocation.getUserId());
        userLocationVo.setLongitude(userLocation.getLocation().getX());
        userLocationVo.setLatitude(userLocation.getLocation().getY());
        return userLocationVo;
    }

    public static final List<UserLocationVo> formatToList(List<UserLocation> userLocations) {
        List<UserLocationVo> list = new ArrayList<>();
        for (UserLocation userLocation : userLocations) {
            list.add(format(userLocation));
        }
        return list;
    }
}

4.1.3. UserLocationController

    /**
     * 搜附近
     */
    @RequestMapping(value = "/tanhua/search",method = RequestMethod.GET)
    public ResponseEntity searchNearUser(@RequestParam(required=false) String gender, @RequestParam(defaultValue = "2000") String distance){
        List<NearUserVo> nearUserVoList = userLocationService.searchNearUser(gender,distance);
        return ResponseEntity.ok(nearUserVoList);
    }

4.1.4. UserLocationService

    /**
     * 搜附近
     */
    public List<NearUserVo> searchNearUser(String gender, String distance) {
        Long userId = UserHolder.getUserId();
        //1.调用服务获取附近用户列表数据
        List<UserLocationVo> userLocationVoList = userLocationApi.searchNearUser(distance,userId);
        if(CollectionUtils.isEmpty(userLocationVoList)){
            return null;
        }
        //2.将当前用户id过滤
        List<NearUserVo> nearUserVoList = new ArrayList<>();
        for (UserLocationVo userLocationVo : userLocationVoList) {
            NearUserVo nearUserVo = new NearUserVo();
            if(userLocationVo.getUserId().equals(userId)){
                //跳过当条记录,继续循环
                continue;
            }
            //3.查询附近用户信息
            UserInfo userInfo = userInfoApi.findUserInfoByUserId(userLocationVo.getUserId());
            //4.将附近用户的性别不符合要求的数据过滤
            if(!StringUtils.isEmpty(gender)){
                if(!gender.equals(userInfo.getGender())){
                    //跳过用户选择的性别 跟userInfo中 性别不一样
                    continue;
                }
            }
            BeanUtils.copyProperties(userInfo,nearUserVo);//头像 昵称
            nearUserVo.setUserId(userInfo.getId());//附近用户的id
            nearUserVoList.add(nearUserVo);
        }
        return nearUserVoList;
    }

4.2. 服务提供者-搜附近

4.2.1. UserLocationApi

    /**
     * 搜附近
     */
    List<UserLocationVo> searchNearUser(String distance, Long userId);

4.2.3. UserLocationApiImpl

   /**
     * 搜附近
     *
     * distance:单位 米m ==> 千米 km
     */
    @Override
    public List<UserLocationVo> searchNearUser(String distance, Long userId) {
        //1 根据当前用户id获取当前用户的位置
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        UserLocation userLocation = mongoTemplate.findOne(query, UserLocation.class);
        GeoJsonPoint location = userLocation.getLocation();
        //2 根据当前用户位置 和 距离 搜索附近的用户
        Circle circle = new Circle(location,new Distance(Double.parseDouble(distance)/1000, Metrics.KILOMETERS));
        Query nearQuery = new Query();
        nearQuery.addCriteria(Criteria.where("location").withinSphere(circle));
        List<UserLocation> userLocationList = mongoTemplate.find(nearQuery, UserLocation.class);
        //3.将List<UserLocation> 转换为 List<UserLocationVo>
        return UserLocationVo.formatToList(userLocationList);
    }

4.2.4. 测试

postman测试

61350613944

app测试

61350543363

61350539766

【小结】

掌握搜附近功能实现

作业

1.谁看过我-保存记录到访客表

2.喜欢-功能实现

总结

1.谁看过我

2.搜附近


3.互相喜欢、喜欢、粉丝统计

4.互相喜欢、喜欢、粉丝统计、谁看过我分页列表查询

5.粉丝-喜欢

posted on 2022-04-23 15:26  ofanimon  阅读(120)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css