陌上花开,可缓缓归矣

系列文章目录

1. 项目介绍及环境配置
2. 短信验证码登录
3. 用户信息
4. MongoDB
5. 推荐好友列表/MongoDB集群/动态发布与查看
6. 圈子动态/圈子互动
7. 即时通讯(基于第三方API)
8. 附近的人(百度地图APi)
9. 小视频
10.网关配置
11.后台管理


文章目录

  • 系列文章目录
  • 一、环信
    • 1. 即使通信
      • ⑴. 功能需求
      • ⑵. 技术方案
    • 2. 环信
      • ⑴. 概述
      • ⑵. 概述API文档
      • ⑶. 工作流程
      • ⑷. 创建探花应用
        • ①. 注册账号
        • ②. 创建应用
    • 3. 基础API
      • ⑴. 测试类
      • ⑵. 后台数据
    • 4. 抽取工具
      • ⑴. 添加相关配置信息
      • ⑵. 编写properties对象,添加配置属性
      • ⑶. 编写template对象,配置组件方法
      • ⑷. 定义自动装配类型
      • ⑸. 编写测试类
  • 二、用户体系集成
    • 1. 环信用户注册
      • ⑴. 需求分析
      • ⑵. 编码实现
        • ①. 实体类 - 添加环信用户信息字段
        • ②. Service - 工具类完成用户信息注册
        • ③. API接口
        • ④. API接口实现类 - 调用工具类注册到环信
      • ⑶. 雷电模拟器测试
        • ①. 安装雷电模拟器
        • ②. 安装新探花交友APP
        • ③. 注册新用户
        • ④. 测试结果
    • 2. 查询环信用户信息
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. Service
        • ③. vo对象
        • ④. API接口
        • ⑤. API实现类
      • ⑶. 雷电模拟器测试
    • 3. 环信后台发送消息测试
      • ⑴. 后台
      • ⑵. APP(雷电模拟器)
    • 4. 根据id查询用户信息
      • ⑴. 编码实现
        • ①. Controller
        • ②. Service
        • ③. Api接口
        • ④. Api实现类
      • ⑵. Postman测试
    • 5. 同步用户账号到环信
      • ⑴. 整理数据库
      • ⑵. 编写测试类
      • ⑶. 同步结果
  • 三、联系人管理
    • 1. 发送好友申请
      • ⑴. 查看佳人详情
        • ①. 接口文档
        • ②. 编码实现
          • Ⅰ. Controller
          • Ⅱ. Service
          • Ⅲ. API
          • Ⅳ. ApiImpl
        • ③. 测试
      • ⑵. 查看陌生人问题
        • ①. 接口文档
        • ②. 编码实现
          • Ⅰ. Controller
          • Ⅱ. Service
        • ③. 页面效果
      • ⑶. 回复陌生人问题
        • ①. 接口文档
        • ②. 编码实现
          • Ⅰ. Controller
          • Ⅱ. Service
        • ③. 页面效果
    • 2. 添加好友
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. Service
        • ③. API
        • ④. API实现类
      • ⑶. 页面效果
    • 3. 联系人列表
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. vo对象
        • ③. Service
        • ④. API接口
        • ⑤. API实现类
        • ⑥. 添加昵称检索功能
      • ⑶. 页面效果

一、环信

1. 即使通信

实时通信(Instant Messaging,简称IM)是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息、文件、语音与视频交流。

⑴. 功能需求

  • 探花交友项目中也提供了类似微信的聊天功能,用户可以和好友或陌生人聊天
  • 如果是陌生人,通过【聊一下】功能进行打招呼,如果对方同意后,就成为了好友,可以进行聊天了
  • 陌生人之间如果相互喜欢,那么就会成为好友,也就可以聊天了
  • 在消息界面中也可以查看:点赞、评论、喜欢、公告等消息信息

⑵. 技术方案

对于高并发的即时通讯实现,还是很有挑战的,所需要考虑的点非常多,除了要实现功能,还要考虑并发、流量、负载、服务器、容灾等等。虽然有难度也并不是高不可攀。

  • 方案一:

    • 自主实现,从设计到架构,再到实现。
    • 技术方面可以采用:Netty + WebSocket + RocketMQ + MongoDB + Redis + ZooKeeper + MySQL

  • 方案二:

    • 对接第三方服务完成。
    • 这种方式简单,只需要按照第三方的api进行对接就可以了。
    • 如:环信、网易、容联云通讯等。

2. 环信

⑴. 概述

官网: https://www.easemob.com/

平台架构:

集成:

⑵. 概述API文档

  • 探花前端使用AndroidSDK进行集成 - 文档:http://docs-im.easemob.com/im/android/sdk/import
  • 后端集成用户体系 - 文档:http://docs-im.easemob.com/im/server/ready/user
  • 集成文档: https://docs-im-beta.easemob.com/document/android/quickstart.html

⑶. 工作流程

工作流程:

  • 客户端用户注册

  • 注册用户好友关系(联系人)

  • 客户端获取环信身份信息

  • 手机端在线聊天

APP端:

  • 在APP端与服务端,都需要完成与环信的集成。
  • 在APP端,通过服务端查询用户在环信的账号密码。
  • APP端,登录环信,进行好友聊天

服务端:

  • 将用户信息同步注册到环信
  • 将用户好友信息同步到环信

⑷. 创建探花应用

①. 注册账号

注册地址: https://datayi.cn/w/woVL50vR

②. 创建应用

3. 基础API

⑴. 测试类

新增 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest.java 文件:

public class HuanXinTest {private EMService service;@Beforepublic void init() {EMProperties properties = EMProperties.builder().setAppkey("填写上图的 APPKEY").setClientId("填写上图的 Client ID").setClientSecret("填写上图的 ClientSecret").build();service = new EMService(properties);}@Testpublic void test() {// 注册用户// service.user().create("user001", "123456").block();// service.user().create("user002", "123456").block();// 添加联系人// service.contact().add("user001", "user002").block();// 发送消息Set<String> set = CollUtil.newHashSet("user002");service.message().send("user001","users", set,new EMTextMessage().text("吃了吗?"),null).block();}
}

⑵. 后台数据



4. 抽取工具

⑴. 添加相关配置信息

编辑 tanhua-app-server/src/main/resources/application.yml 文件:

...
tanhua:
...huanxin:appkey: 填写 APPKEYclientId: 填写 Client IDclientSecret: 填写 ClientSecret

⑵. 编写properties对象,添加配置属性

编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/properties/HuanXinProperties.java 文件:

@Configuration
@ConfigurationProperties(prefix = "tanhua.huanxin")
@Data
public class HuanXinProperties {private String appkey;private String clientId;private String clientSecret;}

⑶. 编写template对象,配置组件方法

编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/template/HuanXinTemplate.java 文件:

@Slf4j
public class HuanXinTemplate {private EMService service;public HuanXinTemplate(HuanXinProperties properties) {EMProperties emProperties = EMProperties.builder().setAppkey(properties.getAppkey()).setClientId(properties.getClientId()).setClientSecret(properties.getClientSecret()).build();service = new EMService(emProperties);}//创建环信用户public Boolean createUser(String username,String password) {try {//创建环信用户service.user().create(username.toLowerCase(), password).block();return true;}catch (Exception e) {e.printStackTrace();log.error("创建环信用户失败~");}return false;}//添加联系人public Boolean addContact(String username1,String username2) {try {//创建环信用户service.contact().add(username1,username2).block();return true;}catch (Exception e) {log.error("添加联系人失败~");}return false;}//删除联系人public Boolean deleteContact(String username1,String username2) {try {//创建环信用户service.contact().remove(username1,username2).block();return true;}catch (Exception e) {log.error("删除联系人失败~");}return false;}//发送消息public Boolean sendMsg(String username,String content) {try {//接收人用户列表Set<String> set = CollUtil.newHashSet(username);//文本消息EMTextMessage message = new EMTextMessage().text(content);//发送消息  from:admin是管理员发送service.message().send("admin","users",set,message,null).block();return true;}catch (Exception e) {log.error("删除联系人失败~");}return false;}
}

⑷. 定义自动装配类型

编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/TanhuaAutoConfiguration.java 文件:

@EnableConfigurationProperties({SmsProperties.class,OssProperties.class,AipFaceProperties.class,HuanXinProperties.class
})
public class TanhuaAutoConfiguration {@Beanpublic SmsTemplate smsTemplate(SmsProperties properties) {return new SmsTemplate(properties);}@Beanpublic OssTemplate ossTemplate(OssProperties properties) {return new OssTemplate(properties);}@Beanpublic AipFaceTemplate aipFaceTemplate() {return new AipFaceTemplate();}@Beanpublic HuanXinTemplate huanXinTemplate(HuanXinProperties properties) {return new HuanXinTemplate(properties);}
}

⑸. 编写测试类

编辑 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest2.java 文件:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class HuanXinTest2 {@Autowiredprivate HuanXinTemplate template;@Testpublic void testCreateUser() {template.createUser("user003", "123456");}
}

二、用户体系集成

1. 环信用户注册

⑴. 需求分析

  • 探花用户注册时需要将用户信息注册到环信系统中

    • 对于老数据:编写单元测试方法批量的注册到环信
    • 对于新用户:改造代码(用户注册的时候,自动注册到环信
  • APP从服务端获取当前用户的环信用户密码,自动登入环信系统
    • 编写一个接口,获取当前用户在环信的用户名密码
    • APP自动获取环信服务器发送的信息数据

⑵. 编码实现

①. 实体类 - 添加环信用户信息字段

编辑 tanhua-model/src/main/java/com/tanhua/model/domain/User.java 文件:

@Data
@AllArgsConstructor  //满参构造方法
@NoArgsConstructor   //无参构造方法
public class User extends BasePojo {private Long id;private String mobile;private String password;// 环信用户信息private String hxUser;private String hxPassword;
}

②. Service - 工具类完成用户信息注册

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserService.java 文件:

.../*** 验证登录* @param phone* @param code*/public Map loginVerification(String phone, String code) {// 1. 从redis中获取验证码String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone);// 2. 对验证码进行校验if(StringUtils.isEmpty(redisCode) || !redisCode.equals(code)) {// throw new RuntimeException("验证码错误");throw new BusinessException(ErrorResult.loginError());}// 3. 删除redis中的验证码redisTemplate.delete("CHECK_CODE_" + phone);// 4. 通过手机号查询用户User user = userApi.findByMobile(phone);boolean isNew = false;// 5. 如果用户不存在,创建用户保存到数据库if(user == null) {user = new User();user.setMobile(phone);// user.setCreated(new Date());// user.setUpdated(new Date());user.setPassword(DigestUtils.md5Hex("123456"));Long userId = userApi.save(user);user.setId(userId);isNew = true;// 注册环信用户String hxUser = "hx" + user.getId();Boolean create = huanXinTemplate.createUser(hxUser, Constants.INIT_PASSWORD);if(create) {user.setHxUser(hxUser);user.setHxPassword(Constants.INIT_PASSWORD);userApi.update(user);}}// 6. 通过JWT生成token(存入手机号和用户ID)Map tokenMap = new HashMap();tokenMap.put("id", user.getId());tokenMap.put("mobile", phone);String token = JwtUtils.getToken(tokenMap);// 7. 构造返回值Map retMap = new HashMap();retMap.put("token", token);retMap.put("isNew", isNew);return retMap;}
}

③. API接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java 文件:

public interface UserApi {// 根据手机号查询用户User findByMobile(String phone);// 保存用户, 返回用户IDLong save(User user);// 更新环信用户void update(User user);
}

④. API接口实现类 - 调用工具类注册到环信

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java 文件:

@DubboService
public class UserApiImpl implements UserApi {@Autowiredprivate UserMapper userMapper;// 根据手机号查询用户public User findByMobile(String mobile) {QueryWrapper<User> qw = new QueryWrapper<>();qw.eq("mobile", mobile);return userMapper.selectOne(qw);}// 保存用户,返回用户ID@Overridepublic Long save(User user) {userMapper.insert(user);return user.getId();}// 更新环信用户@Overridepublic void update(User user) {userMapper.updateById(user);}
}

⑶. 雷电模拟器测试

①. 安装雷电模拟器

网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java

②. 安装新探花交友APP

网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java

③. 注册新用户


④. 测试结果


2. 查询环信用户信息

在app中,用户登录后需要根据用户名密码登录环信,由于环信的用户名密码保存在后台,所以需要提供接口进行返回

⑴. 接口文档

⑵. 编码实现

①. Controller

新增 tanhua-app-server/src/main/java/com/tanhua/server/controller/HuanXinController.java 文件:

@RestController
@RequestMapping("/huanxin")
public class HuanXinController {@Autowiredprivate HuanXinService huanXinService;/*** 查询环信账号密码*/@GetMapping("/user")public ResponseEntity user() {HuanXinUserVo vo = huanXinService.findHuanXinUser();return ResponseEntity.ok(vo);}
}

②. Service

新增 tanhua-app-server/src/main/java/com/tanhua/server/service/HuanXinService.java 文件:

@Service
public class HuanXinService {@DubboReferenceprivate UserApi userApi;/*** 查询当前用户的环信账号密码*/public HuanXinUserVo findHuanXinUser() {// 1. 获取当前用户id, 根据规则拼接Long userId = UserHolder.getUserId();// 2. 根据当前用户id,查询用户User user = userApi.findById(userId);if(user == null) {return null;}return new HuanXinUserVo(user.getHxUser(), user.getHxPassword());}
}

③. vo对象

新增 tanhua-model/src/main/java/com/tanhua/model/vo/HuanXinUserVo.java 文件:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class HuanXinUserVo {private String username;private String password;
}

④. API接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java 文件:

public interface UserApi {// 根据手机号查询用户User findByMobile(String phone);// 保存用户, 返回用户IDLong save(User user);// 更新环信用户void update(User user);// 根据id,查询用户User findById(Long userId);
}

⑤. API实现类

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java 文件:

@DubboService
public class UserApiImpl implements UserApi {@Autowiredprivate UserMapper userMapper;// 根据手机号查询用户public User findByMobile(String mobile) {QueryWrapper<User> qw = new QueryWrapper<>();qw.eq("mobile", mobile);return userMapper.selectOne(qw);}// 保存用户,返回用户ID@Overridepublic Long save(User user) {userMapper.insert(user);return user.getId();}// 更新环信用户@Overridepublic void update(User user) {userMapper.updateById(user);}// 根据id查询用户@Overridepublic User findById(Long userId) {return userMapper.selectById(userId);}
}

⑶. 雷电模拟器测试

3. 环信后台发送消息测试

⑴. 后台

# userId、huanXinId、nickname需要根据数据库做调整
{"userId":120,"huanXinId":"hx120","nickname":"小宇","strangerQuestion":"你喜欢去看蔚蓝的大海还是去爬巍峨的高山?","reply":"我喜欢秋天的落叶,夏天的泉水,冬天的雪地,只要有你一切皆可~"}

⑵. APP(雷电模拟器)

4. 根据id查询用户信息

⑴. 编码实现

①. Controller

新建 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java 文件:

@RestController
@RequestMapping("/messages")
public class MessagesController {@Autowiredprivate MessagesService messagesService;/*** 根据环信用户id,查询环信用户详情*/@GetMapping("/userinfo")public ResponseEntity userinfo(String huanxinId) {UserInfoVo vo = messagesService.findUserInfoByHuanXin(huanxinId);return ResponseEntity.ok(vo);}
}

②. Service

新建 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java 文件:

@Service
public class MessagesService {@DubboReferenceprivate UserApi userApi;@DubboReferenceprivate UserInfoApi userInfoApi;// 根据环信用户id,查询用户详情public UserInfoVo findUserInfoByHuanXin(String huanxinId) {// 1. 根据环信id查询用户User user = userApi.findByHuanXin(huanxinId);// 2. 根据用户id,查询用户详情UserInfo userInfo = userInfoApi.findById(user.getId());// 3. 构建vo返回值UserInfoVo vo = new UserInfoVo();BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性if(userInfo.getAge() != null) {vo.setAge(userInfo.getAge().toString());}return vo;}
}

③. Api接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java 文件:

public interface UserApi {// 根据手机号查询用户User findByMobile(String phone);// 保存用户, 返回用户IDLong save(User user);// 更新环信用户void update(User user);// 根据id,查询用户User findById(Long userId);// 根据环信id查询用户User findByHuanXin(String huanxinId);
}

④. Api实现类

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java 文件:

@DubboService
public class UserApiImpl implements UserApi {@Autowiredprivate UserMapper userMapper;// 根据手机号查询用户public User findByMobile(String mobile) {QueryWrapper<User> qw = new QueryWrapper<>();qw.eq("mobile", mobile);return userMapper.selectOne(qw);}// 保存用户,返回用户ID@Overridepublic Long save(User user) {userMapper.insert(user);return user.getId();}// 更新环信用户@Overridepublic void update(User user) {userMapper.updateById(user);}// 根据id查询用户@Overridepublic User findById(Long userId) {return userMapper.selectById(userId);}// 根据环信id查询用户@Overridepublic User findByHuanXin(String huanxinId) {QueryWrapper<User> qw = new QueryWrapper<>();qw.eq("hx_user", huanxinId);return userMapper.selectOne(qw);}
}

⑵. Postman测试

5. 同步用户账号到环信

⑴. 整理数据库

⑵. 编写测试类

编辑 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest2.java 文件:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class HuanXinTest2 {@Autowiredprivate HuanXinTemplate template;@DubboReferenceprivate UserApi userApi;@Testpublic void testCreateUser() {template.createUser("user003", "123456");}// 同步用户账号到环信@Testpublic void register() {for (int i = 1; i < 106; i++) {User user = userApi.findById(Long.valueOf(i));if(user != null) {Boolean create = template.createUser("hx" + user.getId(), Constants.INIT_PASSWORD);if (create){user.setHxUser("hx" + user.getId());user.setHxPassword(Constants.INIT_PASSWORD);userApi.update(user);}}}}
}

⑶. 同步结果



三、联系人管理

1. 发送好友申请

⑴. 查看佳人详情

①. 接口文档

②. 编码实现

Ⅰ. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java 文件:

@RestController
@RequestMapping("/tanhua")
public class TanhuaController {@Autowiredprivate TanhuaService tanhuaService;/*** 今日佳人*/@GetMapping("/todayBest")public ResponseEntity todayBest() {TodayBest vo = tanhuaService.todayBest();return ResponseEntity.ok(vo);}/*** 查询分页推荐好友列表*/@GetMapping("recommendation")public ResponseEntity recommendation(RecommendUserDto dto) {PageResult pr = tanhuaService.recommendation(dto);return ResponseEntity.ok(pr);}/*** 查看佳人详情*/@GetMapping("/{id}/personalInfo")public ResponseEntity personalInfo(@PathVariable("id") Long userId) {TodayBest best = tanhuaService.personalInfo(userId);return ResponseEntity.ok(best);}
}
Ⅱ. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java 文件:

@Service
public class TanhuaService {@DubboReferenceprivate RecommendUserApi recommendUserApi;@DubboReferenceprivate UserInfoApi userInfoApi;// 查询今日佳人数据public TodayBest todayBest() {// 1. 获取用户idLong userId = UserHolder.getUserId();// 2. 调用api查询RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);// 3. 设置默认值if(recommendUser == null) {recommendUser = new RecommendUser();recommendUser.setUserId(1l);recommendUser.setScore(99d);}// 4. 将recommendUser 转化成 todayBest对象UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());TodayBest vo = TodayBest.init(userInfo, recommendUser);// 5. 返回return vo;}// 查询分页推荐好友列表public PageResult recommendation(RecommendUserDto dto) {// 1. 获取用户idLong userId = UserHolder.getUserId();// 2. 调用RecommendUserApi查询数据列表(PageResult -- RecommendUser)PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);// 3. 获取分页中的RecommendUser数据列表List<RecommendUser> items = (List<RecommendUser>) pr.getItems();// 4. 判断列表数据是否为空if (items == null) {return pr;}//        // 5. 循环RecommendUser推荐列表,根据推荐的用户id查询用户详情
//        List<TodayBest> list = new ArrayList<>();
//        for (RecommendUser item : items) {//            Long recommendUserId = item.getUserId();
//            UserInfo userInfo = userInfoApi.findById(recommendUserId);
//            if(userInfo != null) {//                // 条件判断
//                if(!StringUtils.isEmpty(dto.getGender()) && !dto.getGender().equals(userInfo.getGender())) {//                    continue;
//                }
//                if (dto.getAge() != null && dto.getAge() < userInfo.getAge()) {//                    continue;
//                }
//                TodayBest vo = TodayBest.init(userInfo, item);
//                list.add(vo);
//            }
//        }
//// 5. 提取所有推荐的用户id列表List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);UserInfo userInfo = new UserInfo();userInfo.setAge(dto.getAge());userInfo.setGender(dto.getGender());// 6. 构建查询条件,批量查询所有的用户详情Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);// 7. 循环推荐的数据列表,构建vo对象List<TodayBest> list = new ArrayList<>();for (RecommendUser item : items) {UserInfo info = map.get(item.getUserId());if(info != null) {TodayBest vo = TodayBest.init(info, item);list.add(vo);}}// 6. 构造返回值pr.setItems(list);return pr;}// 查看佳人详情public TodayBest personalInfo(Long userId) {// 1. 根据用户id,查询用户详情UserInfo userInfo = userInfoApi.findById(userId);// 2. 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());// 3. 构造返回值return TodayBest.init(userInfo, user);}
}
Ⅲ. API

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/RecommendUserApi.java 文件:

public interface RecommendUserApi {// 查询今日佳人RecommendUser queryWithMaxScore(Long toUserId);// 分页查询推荐好友列表PageResult queryRecommendUserList(Integer page, Integer pagesize, Long toUserId);// 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)RecommendUser queryByUserId(Long userId, Long toUserId);
}
Ⅳ. ApiImpl

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/RecommendUserApiImpl.java 文件:

@DubboService
public class RecommendUserApiImpl implements RecommendUserApi{@Autowiredprivate MongoTemplate mongoTemplate;// 查询今日佳人public RecommendUser queryWithMaxScore(Long toUserId) {// 根据toUserId查询,根据评分score排序,获取第一条// 1. 构建CriteriaCriteria criteria = Criteria.where("toUserId").is(toUserId);// 2. 构建QueryQuery query = Query.query(criteria).with(Sort.by(Sort.Order.desc("score"))).limit(1); // 查询第一条(第一页第一条)// 3. 调用mongoTemplate查询return mongoTemplate.findOne(query, RecommendUser.class);}// 分页查询推荐好友列表public PageResult queryRecommendUserList(Integer page, Integer pagesize, Long toUserId) {// 1. 构建Criteria对象Criteria criteria = Criteria.where("toUserId").is(toUserId);// 2. 构造query对象Query query = Query.query(criteria);// 3. 查询总数long count = mongoTemplate.count(query, RecommendUser.class);// 4. 查询数据列表query.with(Sort.by(Sort.Order.desc("score"))).limit(pagesize).skip((page - 1) * pagesize);List<RecommendUser> list = mongoTemplate.find(query, RecommendUser.class);// 5. 构造返回值return new PageResult(page, pagesize, count, list);}// 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)public RecommendUser queryByUserId(Long userId, Long toUserId) {Criteria criteria = Criteria.where("toUserId").is(toUserId).and("userId").is(userId);Query query = Query.query(criteria);RecommendUser user = mongoTemplate.findOne(query, RecommendUser.class);if(user == null) {user = new RecommendUser();user.setUserId(userId);user.setToUserId(toUserId);// 构建缘分值user.setScore(95d);}return user;}
}

③. 测试

⑵. 查看陌生人问题

①. 接口文档

②. 编码实现

Ⅰ. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java 文件:

@RestController
@RequestMapping("/tanhua")
public class TanhuaController {@Autowiredprivate TanhuaService tanhuaService;/*** 今日佳人*/@GetMapping("/todayBest")public ResponseEntity todayBest() {TodayBest vo = tanhuaService.todayBest();return ResponseEntity.ok(vo);}/*** 查询分页推荐好友列表*/@GetMapping("recommendation")public ResponseEntity recommendation(RecommendUserDto dto) {PageResult pr = tanhuaService.recommendation(dto);return ResponseEntity.ok(pr);}/*** 查看佳人详情*/@GetMapping("/{id}/personalInfo")public ResponseEntity personalInfo(@PathVariable("id") Long userId) {TodayBest best = tanhuaService.personalInfo(userId);return ResponseEntity.ok(best);}/*** 查看陌生人问题*/@GetMapping("/strangerQuestions")public ResponseEntity strangerQuestions(Long userId) {String questions = tanhuaService.strangerQuestions(userId);return ResponseEntity.ok(questions);}
}
Ⅱ. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java 文件:

@Service
public class TanhuaService {@DubboReferenceprivate RecommendUserApi recommendUserApi;@DubboReferenceprivate UserInfoApi userInfoApi;@DubboReferenceprivate QuestionApi questionApi;// 查询今日佳人数据public TodayBest todayBest() {// 1. 获取用户idLong userId = UserHolder.getUserId();// 2. 调用api查询RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);// 3. 设置默认值if(recommendUser == null) {recommendUser = new RecommendUser();recommendUser.setUserId(1l);recommendUser.setScore(99d);}// 4. 将recommendUser 转化成 todayBest对象UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());TodayBest vo = TodayBest.init(userInfo, recommendUser);// 5. 返回return vo;}// 查询分页推荐好友列表public PageResult recommendation(RecommendUserDto dto) {// 1. 获取用户idLong userId = UserHolder.getUserId();// 2. 调用RecommendUserApi查询数据列表(PageResult -- RecommendUser)PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);// 3. 获取分页中的RecommendUser数据列表List<RecommendUser> items = (List<RecommendUser>) pr.getItems();// 4. 判断列表数据是否为空if (items == null) {return pr;}//        // 5. 循环RecommendUser推荐列表,根据推荐的用户id查询用户详情
//        List<TodayBest> list = new ArrayList<>();
//        for (RecommendUser item : items) {//            Long recommendUserId = item.getUserId();
//            UserInfo userInfo = userInfoApi.findById(recommendUserId);
//            if(userInfo != null) {//                // 条件判断
//                if(!StringUtils.isEmpty(dto.getGender()) && !dto.getGender().equals(userInfo.getGender())) {//                    continue;
//                }
//                if (dto.getAge() != null && dto.getAge() < userInfo.getAge()) {//                    continue;
//                }
//                TodayBest vo = TodayBest.init(userInfo, item);
//                list.add(vo);
//            }
//        }
//// 5. 提取所有推荐的用户id列表List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);UserInfo userInfo = new UserInfo();userInfo.setAge(dto.getAge());userInfo.setGender(dto.getGender());// 6. 构建查询条件,批量查询所有的用户详情Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);// 7. 循环推荐的数据列表,构建vo对象List<TodayBest> list = new ArrayList<>();for (RecommendUser item : items) {UserInfo info = map.get(item.getUserId());if(info != null) {TodayBest vo = TodayBest.init(info, item);list.add(vo);}}// 6. 构造返回值pr.setItems(list);return pr;}// 查看佳人详情public TodayBest personalInfo(Long userId) {// 1. 根据用户id,查询用户详情UserInfo userInfo = userInfoApi.findById(userId);// 2. 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());// 3. 构造返回值return TodayBest.init(userInfo, user);}// 查看陌生人问题public String strangerQuestions(Long userId) {Question question = questionApi.findByUserId(userId);return question == null ? "你喜欢吃青椒吗?" : question.getTxt();}
}

③. 页面效果

⑶. 回复陌生人问题

①. 接口文档

②. 编码实现

Ⅰ. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java 文件:

@RestController
@RequestMapping("/tanhua")
public class TanhuaController {@Autowiredprivate TanhuaService tanhuaService;/*** 今日佳人*/@GetMapping("/todayBest")public ResponseEntity todayBest() {TodayBest vo = tanhuaService.todayBest();return ResponseEntity.ok(vo);}/*** 查询分页推荐好友列表*/@GetMapping("recommendation")public ResponseEntity recommendation(RecommendUserDto dto) {PageResult pr = tanhuaService.recommendation(dto);return ResponseEntity.ok(pr);}/*** 查看佳人详情*/@GetMapping("/{id}/personalInfo")public ResponseEntity personalInfo(@PathVariable("id") Long userId) {TodayBest best = tanhuaService.personalInfo(userId);return ResponseEntity.ok(best);}/*** 查看陌生人问题*/@GetMapping("/strangerQuestions")public ResponseEntity strangerQuestions(Long userId) {String questions = tanhuaService.strangerQuestions(userId);return ResponseEntity.ok(questions);}/*** 回复陌生人问题*/@PostMapping("/strangerQuestions")public ResponseEntity replyQuestions(@RequestBody Map map) {// 前端传递的userId是 Integer类型String obj = map.get("userId").toString();Long userId = Long.valueOf(obj);String reply = map.get("reply").toString();tanhuaService.replyQuestions(userId, reply);return ResponseEntity.ok(null);}
}
Ⅱ. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java 文件:

@Service
public class TanhuaService {@DubboReferenceprivate RecommendUserApi recommendUserApi;@DubboReferenceprivate UserInfoApi userInfoApi;@DubboReferenceprivate QuestionApi questionApi;@Autowiredprivate HuanXinTemplate huanXinTemplate;// 查询今日佳人数据public TodayBest todayBest() {// 1. 获取用户idLong userId = UserHolder.getUserId();// 2. 调用api查询RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);// 3. 设置默认值if(recommendUser == null) {recommendUser = new RecommendUser();recommendUser.setUserId(1l);recommendUser.setScore(99d);}// 4. 将recommendUser 转化成 todayBest对象UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());TodayBest vo = TodayBest.init(userInfo, recommendUser);// 5. 返回return vo;}// 查询分页推荐好友列表public PageResult recommendation(RecommendUserDto dto) {// 1. 获取用户idLong userId = UserHolder.getUserId();// 2. 调用RecommendUserApi查询数据列表(PageResult -- RecommendUser)PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);// 3. 获取分页中的RecommendUser数据列表List<RecommendUser> items = (List<RecommendUser>) pr.getItems();// 4. 判断列表数据是否为空if (items == null) {return pr;}//        // 5. 循环RecommendUser推荐列表,根据推荐的用户id查询用户详情
//        List<TodayBest> list = new ArrayList<>();
//        for (RecommendUser item : items) {//            Long recommendUserId = item.getUserId();
//            UserInfo userInfo = userInfoApi.findById(recommendUserId);
//            if(userInfo != null) {//                // 条件判断
//                if(!StringUtils.isEmpty(dto.getGender()) && !dto.getGender().equals(userInfo.getGender())) {//                    continue;
//                }
//                if (dto.getAge() != null && dto.getAge() < userInfo.getAge()) {//                    continue;
//                }
//                TodayBest vo = TodayBest.init(userInfo, item);
//                list.add(vo);
//            }
//        }
//// 5. 提取所有推荐的用户id列表List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);UserInfo userInfo = new UserInfo();userInfo.setAge(dto.getAge());userInfo.setGender(dto.getGender());// 6. 构建查询条件,批量查询所有的用户详情Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);// 7. 循环推荐的数据列表,构建vo对象List<TodayBest> list = new ArrayList<>();for (RecommendUser item : items) {UserInfo info = map.get(item.getUserId());if(info != null) {TodayBest vo = TodayBest.init(info, item);list.add(vo);}}// 6. 构造返回值pr.setItems(list);return pr;}// 查看佳人详情public TodayBest personalInfo(Long userId) {// 1. 根据用户id,查询用户详情UserInfo userInfo = userInfoApi.findById(userId);// 2. 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());// 3. 构造返回值return TodayBest.init(userInfo, user);}// 查看陌生人问题public String strangerQuestions(Long userId) {Question question = questionApi.findByUserId(userId);return question == null ? "你喜欢吃青椒吗?" : question.getTxt();}// 回复陌生人问题public void replyQuestions(Long userId, String reply) {// 1. 构造消息数据Long currentUserId = UserHolder.getUserId();UserInfo userInfo = userInfoApi.findById(currentUserId);Map map = new HashMap<>();map.put("userId", currentUserId);map.put("huanXinId", Constants.HX_USER_PREFIX + currentUserId);map.put("nickname", userInfo.getNickname());map.put("strangerQuestion", strangerQuestions(userId));map.put("reply", reply);String message = JSON.toJSONString(map);// 2. 调用template对象,发送消息Boolean aBoolean = huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + userId, message);// 3. 异常处理if (!aBoolean) {throw new BusinessException(ErrorResult.error());}}
}

③. 页面效果

使用雷电模拟器进行多开,一个用户向另一个用户在线发送消息

2. 添加好友

⑴. 接口文档

⑵. 编码实现

①. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java 文件:

@RestController
@RequestMapping("/messages")
public class MessagesController {@Autowiredprivate MessagesService messagesService;/*** 根据环信用户id,查询环信用户详情*/@GetMapping("/userinfo")public ResponseEntity userinfo(String huanxinId) {UserInfoVo vo = messagesService.findUserInfoByHuanXin(huanxinId);return ResponseEntity.ok(vo);}/*** 添加好友*/@PostMapping("/contacts")public ResponseEntity contacts(@RequestBody Map map) {Long friendId = Long.valueOf(map.get("userId").toString());messagesService.contacts(friendId);return ResponseEntity.ok(null);}
}

②. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java 文件:

@Service
public class MessagesService {@DubboReferenceprivate UserApi userApi;@DubboReferenceprivate UserInfoApi userInfoApi;@Autowiredprivate HuanXinTemplate huanXinTemplate;@DubboReferenceprivate FriendApi friendApi;// 根据环信用户id,查询用户详情public UserInfoVo findUserInfoByHuanXin(String huanxinId) {// 1. 根据环信id查询用户User user = userApi.findByHuanXin(huanxinId);// 2. 根据用户id,查询用户详情UserInfo userInfo = userInfoApi.findById(user.getId());// 3. 构建vo返回值UserInfoVo vo = new UserInfoVo();BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性if(userInfo.getAge() != null) {vo.setAge(userInfo.getAge().toString());}return vo;}// 添加好友public void contacts(Long friendId) {// 1. 好友关系记录到环信Boolean aBoolean = huanXinTemplate.addContact(Constants.HX_USER_PREFIX + UserHolder.getUserId(),Constants.HX_USER_PREFIX + friendId);if(!aBoolean) {throw new BusinessException(ErrorResult.error());}// 2. 记录好友关系到MongoDBfriendApi.save(UserHolder.getUserId(), friendId);}
}

③. API

新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/FriendApi.java 文件:

public interface FriendApi {// 添加好友void save(Long userId, Long friendId);
}

④. API实现类

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/FriendApiImpl.java 文件:

@DubboService
public class FriendApiImpl implements FriendApi {@Autowiredprivate MongoTemplate mongoTemplate;// 添加好友@Overridepublic void save(Long userId, Long friendId) {// 1. 保存自己的好友数据Query query1 = Query.query(Criteria.where("userId").is(userId).and("friendId").is(friendId));// 1.1 判断好友关系是否存在if(!mongoTemplate.exists(query1, Friend.class)) {// 1.2 如果不存在,保存Friend friend1 = new Friend();friend1.setUserId(userId);friend1.setFriendId(friendId);friend1.setCreated(System.currentTimeMillis());mongoTemplate.save(friend1);}// 2. 保存好友的数据Query query2 = Query.query(Criteria.where("userId").is(friendId).and("friendId").is(userId));// 2.1 判断好友关系是否存在if(!mongoTemplate.exists(query2, Friend.class)) {// 2.2 如果不存在,保存Friend friend1 = new Friend();friend1.setUserId(friendId);friend1.setFriendId(userId);friend1.setCreated(System.currentTimeMillis());mongoTemplate.save(friend1);}}
}

⑶. 页面效果

3. 联系人列表

⑴. 接口文档

⑵. 编码实现

①. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java 文件:

@RestController
@RequestMapping("/messages")
public class MessagesController {@Autowiredprivate MessagesService messagesService;/*** 根据环信用户id,查询环信用户详情*/@GetMapping("/userinfo")public ResponseEntity userinfo(String huanxinId) {UserInfoVo vo = messagesService.findUserInfoByHuanXin(huanxinId);return ResponseEntity.ok(vo);}/*** 添加好友*/@PostMapping("/contacts")public ResponseEntity contacts(@RequestBody Map map) {Long friendId = Long.valueOf(map.get("userId").toString());messagesService.contacts(friendId);return ResponseEntity.ok(null);}/*** 分页查询联系人列表*/@GetMapping("/contacts")public ResponseEntity contacts(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pagesize,String keyword) {PageResult pr = messagesService.findFriends(page, pagesize, keyword);return ResponseEntity.ok(pr);}
}

②. vo对象

新建 tanhua-model/src/main/java/com/tanhua/model/vo/ContactVo.java 文件:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ContactVo implements Serializable {private Long id;private String userId;private String avatar;private String nickname;private String gender;private Integer age;private String city;public static ContactVo init(UserInfo userInfo) {ContactVo vo = new ContactVo();if(userInfo != null) {BeanUtils.copyProperties(userInfo,vo);vo.setUserId("hx"+userInfo.getId().toString());}return vo;}
}

③. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java 文件:

@Service
public class MessagesService {@DubboReferenceprivate UserApi userApi;@DubboReferenceprivate UserInfoApi userInfoApi;@Autowiredprivate HuanXinTemplate huanXinTemplate;@DubboReferenceprivate FriendApi friendApi;// 根据环信用户id,查询用户详情public UserInfoVo findUserInfoByHuanXin(String huanxinId) {// 1. 根据环信id查询用户User user = userApi.findByHuanXin(huanxinId);// 2. 根据用户id,查询用户详情UserInfo userInfo = userInfoApi.findById(user.getId());// 3. 构建vo返回值UserInfoVo vo = new UserInfoVo();BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性if(userInfo.getAge() != null) {vo.setAge(userInfo.getAge().toString());}return vo;}// 添加好友public void contacts(Long friendId) {// 1. 好友关系记录到环信Boolean aBoolean = huanXinTemplate.addContact(Constants.HX_USER_PREFIX + UserHolder.getUserId(),Constants.HX_USER_PREFIX + friendId);if(!aBoolean) {throw new BusinessException(ErrorResult.error());}// 2. 记录好友关系到MongoDBfriendApi.save(UserHolder.getUserId(), friendId);}// 分页查询联系人列表public PageResult findFriends(Integer page, Integer pagesize, String keyword) {// 1. 调用API查询当前用户的好友数据 -- List<Friend>List<Friend> list = friendApi.findUserById(UserHolder.getUserId(), page, pagesize);if(CollUtil.isEmpty(list)) {return new PageResult();}// 2. 提取数据列表中的好友idList<Long> friendIds = CollUtil.getFieldValues(list, "friendId", Long.class);// 3. 调用UserInfoApi查询用户好友的详情UserInfo userInfo = new UserInfo();userInfo.setNickname(keyword);Map<Long, UserInfo> map = userInfoApi.findByIds(friendIds, userInfo);// 4. 构造vo对象List<ContactVo> vos = new ArrayList<>();for (Friend friend : list) {UserInfo info = map.get(friend.getFriendId());if(info != null) {ContactVo vo = ContactVo.init(info);vos.add(vo);}}return new PageResult(page, pagesize, 0l, vos);}
}

④. API接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/FriendApi.java 文件:

public interface FriendApi {// 添加好友void save(Long userId, Long friendId);// 查询好友列表List<Friend> findUserById(Long userId, Integer page, Integer pagesize);
}

⑤. API实现类

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/FriendApiImpl.java 文件:

@DubboService
public class FriendApiImpl implements FriendApi {@Autowiredprivate MongoTemplate mongoTemplate;// 添加好友@Overridepublic void save(Long userId, Long friendId) {// 1. 保存自己的好友数据Query query1 = Query.query(Criteria.where("userId").is(userId).and("friendId").is(friendId));// 1.1 判断好友关系是否存在if(!mongoTemplate.exists(query1, Friend.class)) {// 1.2 如果不存在,保存Friend friend1 = new Friend();friend1.setUserId(userId);friend1.setFriendId(friendId);friend1.setCreated(System.currentTimeMillis());mongoTemplate.save(friend1);}// 2. 保存好友的数据Query query2 = Query.query(Criteria.where("userId").is(friendId).and("friendId").is(userId));// 2.1 判断好友关系是否存在if(!mongoTemplate.exists(query2, Friend.class)) {// 2.2 如果不存在,保存Friend friend1 = new Friend();friend1.setUserId(friendId);friend1.setFriendId(userId);friend1.setCreated(System.currentTimeMillis());mongoTemplate.save(friend1);}}// 查询好友列表@Overridepublic List<Friend> findUserById(Long userId, Integer page, Integer pagesize) {Query query = Query.query(Criteria.where("userId").is(userId)).skip((page - 1) * pagesize).limit(pagesize).with(Sort.by(Sort.Order.desc("created")));return mongoTemplate.find(query, Friend.class);}
}

⑥. 添加昵称检索功能

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserInfoApiImpl.java 文件:

@DubboService
public class UserInfoApiImpl implements UserInfoApi{@Autowiredprivate UserInfoMapper userInfoMapper;@Overridepublic void save(UserInfo userInfo) {userInfoMapper.insert(userInfo);}@Overridepublic void update(UserInfo userInfo) {userInfoMapper.updateById(userInfo);}@Overridepublic UserInfo findById(Long id) {return userInfoMapper.selectById(id);}/*** 批量查询用戶详情* @param userIds 用户id列表* @param info 用户详情信息* @return*/@Overridepublic Map<Long, UserInfo> findByIds(List<Long> userIds, UserInfo info) {// 1. 用户id列表QueryWrapper qw = new QueryWrapper<>();qw.in("id", userIds);// 2. 添加筛选条件if(info != null) {if(info.getAge() != null) {qw.lt("age", info.getAge());}if(!StringUtils.isEmpty(info.getGender())) {qw.eq("gender", info.getGender());}if(!StringUtils.isEmpty(info.getNickname())) {qw.like("nickname", info.getNickname());}}// 3. 获取用户详情列表 转换成map集合List<UserInfo> list = userInfoMapper.selectList(qw);Map<Long, UserInfo> map = CollUtil.fieldValueMap(list, "id");// 4. 返回return map;}
}

⑶. 页面效果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)相关推荐

  1. SpringBoot交友APP项目实战(详细介绍+案例源码) - 9.小视频(SpringCache缓存)

    有人相爱,有人跳海 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 ...

  2. SpringBoot交友APP项目实战(详细介绍+案例源码) - 10.网关配置

    系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 7. 即时通讯(基 ...

  3. Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB

    安能摧眉折腰事权贵,使我不得开心颜 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4.MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子 ...

  4. Dobbo微服务项目实战(详细介绍+案例源码) - 3.用户信息

    想出去旅游,想出去玩,想大吃大喝 0_o 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6 ...

  5. Dobbo微服务项目实战(详细介绍+案例源码) - 5.推荐好友列表/MongoDB集群/动态发布与查看

    You are a wizard, Harry! 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5.推荐好友列表/MongoDB集群/动态发布与查 ...

  6. SpringBoot+SpringCloud+Mybatis+Vue 电商项目实战,附视频+源码+文档,包含所有主流技术栈。...

    大家好,我是树哥. 今天给大家分享一个电商项目--- 畅购商城.项目采用前后端分离的技术架构. 采用SpringBoot+SpringCloud+Mybatis+Vue为主要技术栈,包括了大型商城的主 ...

  7. SpringBoot+SpringCloud+Mybatis+Vue电商项目实战,附视频+源码+文档,包含所有主流技术栈...

    今天给大家分享一个电商项目--- 畅购商城.项目采用前后端分离的技术架构. 采用SpringBoot+SpringCloud+Mybatis+Vue为主要技术栈,包括了大型商城的主要功能.难点功能以及 ...

  8. android从入门到精通-项目实战(心得及源码)

    个人心得 这个周的时间,我用了三天的时间跟着书籍上面的内容实现了,家庭理财通这个小的app,算是用来练手的开始.首先开始实现的时候,我是先从项目的架构开始,首先你的先理解者这个APP具体是干什么的,有 ...

  9. 仿小米运动的蓝牙开源项目(附详细实现说明+源码)

    托瓦兹 莱纳斯 是一个天才. 这个项目主要以蓝牙和自己diy的手环连接,可以记录测试数据,绘制成折线坐标图之类的功能. 项目结构很简单 6个类,其中AcceptThread,ConnectedThre ...

最新文章

  1. html怎么把图片作为背景_抖音背景图片怎么弄,抖音背景图片引导关注
  2. 今天诞生了智能车竞赛华南赛区三项最好成绩
  3. c++ 哈希_详解Python中的可哈希对象与不可哈希对象(二)
  4. c++ 头文件 .h 理解与实践
  5. 电脑手机wifi互传文件_手机之间怎么互传文件?几则小技巧了解下
  6. wxWidgets:wxLayoutAlgorithm类用法
  7. pytorch学习入门 (二) Variable(变量)
  8. 中老铁路国内段首座四线特大桥顺利合龙
  9. 大数据技术及大数据架构
  10. 除了Google还有什么搜索引擎?
  11. 正态分布是离散分布还是连续分布_正态分布,谁与争峰
  12. 关于C语言数组的输入与输出
  13. 什么是嵌入式操作系统 常见的嵌入式系统有哪些
  14. 【百度大脑新品体验】行驶证识别
  15. Tensor.shape[0]的理解
  16. t3计算机名带特殊符号,带特殊符号的网名,带特殊符号的网名
  17. Day18 洛谷P1321 单词覆盖还原
  18. MacTeX的使用心得
  19. 5和6 objbc oracle_《Oracle Database 12c完全参考手册(第7版)(试读版)》
  20. (三)模仿学习-Action数据的模仿

热门文章

  1. matlab模块连接,模块 - MATLAB Simulink - MathWorks 中国
  2. 深入理解JDK动态代理原理,使用javassist动手写一个动态代理框架
  3. 计算机自带的超级锁怎么设置,MIUI自带机密解锁+超顺畅设置小窍门
  4. 网线(UTP双绞线)的安装
  5. 170527 逆向-CrackMe(4)
  6. j2me(javame)开发找不到MIDlet类。请检查jad文件或用—MIDLET参数指定解决方案
  7. 微生物基础实验操作参考手册,微生物科研人必看!干货满满
  8. oracle定时任务报“并非所有变量都已经绑定”以及创建,删除等
  9. 使用 Scikit-Learn 的人工数据集
  10. 一些图书和出版社的网址