SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)
陌上花开,可缓缓归矣
系列文章目录
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)相关推荐
- SpringBoot交友APP项目实战(详细介绍+案例源码) - 9.小视频(SpringCache缓存)
有人相爱,有人跳海 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 ...
- SpringBoot交友APP项目实战(详细介绍+案例源码) - 10.网关配置
系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 7. 即时通讯(基 ...
- Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB
安能摧眉折腰事权贵,使我不得开心颜 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4.MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子 ...
- Dobbo微服务项目实战(详细介绍+案例源码) - 3.用户信息
想出去旅游,想出去玩,想大吃大喝 0_o 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6 ...
- Dobbo微服务项目实战(详细介绍+案例源码) - 5.推荐好友列表/MongoDB集群/动态发布与查看
You are a wizard, Harry! 系列文章目录 1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5.推荐好友列表/MongoDB集群/动态发布与查 ...
- SpringBoot+SpringCloud+Mybatis+Vue 电商项目实战,附视频+源码+文档,包含所有主流技术栈。...
大家好,我是树哥. 今天给大家分享一个电商项目--- 畅购商城.项目采用前后端分离的技术架构. 采用SpringBoot+SpringCloud+Mybatis+Vue为主要技术栈,包括了大型商城的主 ...
- SpringBoot+SpringCloud+Mybatis+Vue电商项目实战,附视频+源码+文档,包含所有主流技术栈...
今天给大家分享一个电商项目--- 畅购商城.项目采用前后端分离的技术架构. 采用SpringBoot+SpringCloud+Mybatis+Vue为主要技术栈,包括了大型商城的主要功能.难点功能以及 ...
- android从入门到精通-项目实战(心得及源码)
个人心得 这个周的时间,我用了三天的时间跟着书籍上面的内容实现了,家庭理财通这个小的app,算是用来练手的开始.首先开始实现的时候,我是先从项目的架构开始,首先你的先理解者这个APP具体是干什么的,有 ...
- 仿小米运动的蓝牙开源项目(附详细实现说明+源码)
托瓦兹 莱纳斯 是一个天才. 这个项目主要以蓝牙和自己diy的手环连接,可以记录测试数据,绘制成折线坐标图之类的功能. 项目结构很简单 6个类,其中AcceptThread,ConnectedThre ...
最新文章
- html怎么把图片作为背景_抖音背景图片怎么弄,抖音背景图片引导关注
- 今天诞生了智能车竞赛华南赛区三项最好成绩
- c++ 哈希_详解Python中的可哈希对象与不可哈希对象(二)
- c++ 头文件 .h 理解与实践
- 电脑手机wifi互传文件_手机之间怎么互传文件?几则小技巧了解下
- wxWidgets:wxLayoutAlgorithm类用法
- pytorch学习入门 (二) Variable(变量)
- 中老铁路国内段首座四线特大桥顺利合龙
- 大数据技术及大数据架构
- 除了Google还有什么搜索引擎?
- 正态分布是离散分布还是连续分布_正态分布,谁与争峰
- 关于C语言数组的输入与输出
- 什么是嵌入式操作系统 常见的嵌入式系统有哪些
- 【百度大脑新品体验】行驶证识别
- Tensor.shape[0]的理解
- t3计算机名带特殊符号,带特殊符号的网名,带特殊符号的网名
- Day18 洛谷P1321 单词覆盖还原
- MacTeX的使用心得
- 5和6 objbc oracle_《Oracle Database 12c完全参考手册(第7版)(试读版)》
- (三)模仿学习-Action数据的模仿
热门文章
- matlab模块连接,模块
- MATLAB Simulink
- MathWorks 中国
- 深入理解JDK动态代理原理,使用javassist动手写一个动态代理框架
- 计算机自带的超级锁怎么设置,MIUI自带机密解锁+超顺畅设置小窍门
- 网线(UTP双绞线)的安装
- 170527 逆向-CrackMe(4)
- j2me(javame)开发找不到MIDlet类。请检查jad文件或用—MIDLET参数指定解决方案
- 微生物基础实验操作参考手册,微生物科研人必看!干货满满
- oracle定时任务报“并非所有变量都已经绑定”以及创建,删除等
- 使用 Scikit-Learn 的人工数据集
- 一些图书和出版社的网址