陌上花开,可缓缓归矣
1. 项目介绍及环境配置
2. 短信验证码登录
3. 用户信息
4. MongoDB
5. 推荐好友列表/MongoDB集群/动态发布与查看
6. 圈子动态/圈子互动
7. 即时通讯(基于第三方API)
8. 附近的人(百度地图APi)
9. 小视频
10.网关配置
11.后台管理
实时通信(Instant Messaging,简称IM)是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息、文件、语音与视频交流。
对于高并发的即时通讯实现,还是很有挑战的,所需要考虑的点非常多,除了要实现功能,还要考虑并发、流量、负载、服务器、容灾等等。虽然有难度也并不是高不可攀。
官网: https://www.easemob.com/
工作流程:
APP端:
服务端:
注册地址: https://datayi.cn/w/woVL50vR
新增 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest.java
文件:
public class HuanXinTest {
private EMService service;
@Before
public void init() {
EMProperties properties = EMProperties.builder()
.setAppkey("填写上图的 APPKEY")
.setClientId("填写上图的 Client ID")
.setClientSecret("填写上图的 ClientSecret")
.build();
service = new EMService(properties);
}
@Test
public 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();
}
}
编辑 tanhua-app-server/src/main/resources/application.yml
文件:
...
tanhua:
...
huanxin:
appkey: 填写 APPKEY
clientId: 填写 Client ID
clientSecret: 填写 ClientSecret
编辑 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;
}
编辑 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 {
@Bean
public SmsTemplate smsTemplate(SmsProperties properties) {
return new SmsTemplate(properties);
}
@Bean
public OssTemplate ossTemplate(OssProperties properties) {return new OssTemplate(properties);}
@Bean
public AipFaceTemplate aipFaceTemplate() {return new AipFaceTemplate();}
@Bean
public 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 {
@Autowired
private HuanXinTemplate template;
@Test
public void testCreateUser() {
template.createUser("user003", "123456");
}
}
编辑 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;
}
编辑 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;
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java
文件:
public interface UserApi {
// 根据手机号查询用户
User findByMobile(String phone);
// 保存用户, 返回用户ID
Long save(User user);
// 更新环信用户
void update(User user);
}
编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java
文件:
@DubboService
public class UserApiImpl implements UserApi {
@Autowired
private UserMapper userMapper;
// 根据手机号查询用户
public User findByMobile(String mobile) {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("mobile", mobile);
return userMapper.selectOne(qw);
}
// 保存用户,返回用户ID
@Override
public Long save(User user) {
userMapper.insert(user);
return user.getId();
}
// 更新环信用户
@Override
public void update(User user) {
userMapper.updateById(user);
}
}
网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java
网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java
在app中,用户登录后需要根据用户名密码登录环信,由于环信的用户名密码保存在后台,所以需要提供接口进行返回
新增 tanhua-app-server/src/main/java/com/tanhua/server/controller/HuanXinController.java
文件:
@RestController
@RequestMapping("/huanxin")
public class HuanXinController {
@Autowired
private HuanXinService huanXinService;
/**
* 查询环信账号密码
*/
@GetMapping("/user")
public ResponseEntity user() {
HuanXinUserVo vo = huanXinService.findHuanXinUser();
return ResponseEntity.ok(vo);
}
}
新增 tanhua-app-server/src/main/java/com/tanhua/server/service/HuanXinService.java
文件:
@Service
public class HuanXinService {
@DubboReference
private 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());
}
}
新增 tanhua-model/src/main/java/com/tanhua/model/vo/HuanXinUserVo.java
文件:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HuanXinUserVo {
private String username;
private String password;
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java
文件:
public interface UserApi {
// 根据手机号查询用户
User findByMobile(String phone);
// 保存用户, 返回用户ID
Long save(User user);
// 更新环信用户
void update(User user);
// 根据id,查询用户
User findById(Long userId);
}
编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java
文件:
@DubboService
public class UserApiImpl implements UserApi {
@Autowired
private UserMapper userMapper;
// 根据手机号查询用户
public User findByMobile(String mobile) {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("mobile", mobile);
return userMapper.selectOne(qw);
}
// 保存用户,返回用户ID
@Override
public Long save(User user) {
userMapper.insert(user);
return user.getId();
}
// 更新环信用户
@Override
public void update(User user) {
userMapper.updateById(user);
}
// 根据id查询用户
@Override
public User findById(Long userId) {
return userMapper.selectById(userId);
}
}
# userId、huanXinId、nickname需要根据数据库做调整
{"userId":120,"huanXinId":"hx120","nickname":"小宇","strangerQuestion":"你喜欢去看蔚蓝的大海还是去爬巍峨的高山?","reply":"我喜欢秋天的落叶,夏天的泉水,冬天的雪地,只要有你一切皆可~"}
新建 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java
文件:
@RestController
@RequestMapping("/messages")
public class MessagesController {
@Autowired
private MessagesService messagesService;
/**
* 根据环信用户id,查询环信用户详情
*/
@GetMapping("/userinfo")
public ResponseEntity userinfo(String huanxinId) {
UserInfoVo vo = messagesService.findUserInfoByHuanXin(huanxinId);
return ResponseEntity.ok(vo);
}
}
新建 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java
文件:
@Service
public class MessagesService {
@DubboReference
private UserApi userApi;
@DubboReference
private 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;
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java
文件:
public interface UserApi {
// 根据手机号查询用户
User findByMobile(String phone);
// 保存用户, 返回用户ID
Long save(User user);
// 更新环信用户
void update(User user);
// 根据id,查询用户
User findById(Long userId);
// 根据环信id查询用户
User findByHuanXin(String huanxinId);
}
编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java
文件:
@DubboService
public class UserApiImpl implements UserApi {
@Autowired
private UserMapper userMapper;
// 根据手机号查询用户
public User findByMobile(String mobile) {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("mobile", mobile);
return userMapper.selectOne(qw);
}
// 保存用户,返回用户ID
@Override
public Long save(User user) {
userMapper.insert(user);
return user.getId();
}
// 更新环信用户
@Override
public void update(User user) {
userMapper.updateById(user);
}
// 根据id查询用户
@Override
public User findById(Long userId) {
return userMapper.selectById(userId);
}
// 根据环信id查询用户
@Override
public User findByHuanXin(String huanxinId) {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("hx_user", huanxinId);
return userMapper.selectOne(qw);
}
}
编辑 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest2.java
文件:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class HuanXinTest2 {
@Autowired
private HuanXinTemplate template;
@DubboReference
private UserApi userApi;
@Test
public void testCreateUser() {
template.createUser("user003", "123456");
}
// 同步用户账号到环信
@Test
public 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);
}
}
}
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java
文件:
@RestController
@RequestMapping("/tanhua")
public class TanhuaController {
@Autowired
private 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);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java
文件:
@Service
public class TanhuaService {
@DubboReference
private RecommendUserApi recommendUserApi;
@DubboReference
private UserInfoApi userInfoApi;
// 查询今日佳人数据
public TodayBest todayBest() {
// 1. 获取用户id
Long 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. 获取用户id
Long 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 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);
}
}
编辑 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);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/RecommendUserApiImpl.java
文件:
@DubboService
public class RecommendUserApiImpl implements RecommendUserApi{
@Autowired
private MongoTemplate mongoTemplate;
// 查询今日佳人
public RecommendUser queryWithMaxScore(Long toUserId) {
// 根据toUserId查询,根据评分score排序,获取第一条
// 1. 构建Criteria
Criteria criteria = Criteria.where("toUserId").is(toUserId);
// 2. 构建Query
Query 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;
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java
文件:
@RestController
@RequestMapping("/tanhua")
public class TanhuaController {
@Autowired
private 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);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java
文件:
@Service
public class TanhuaService {
@DubboReference
private RecommendUserApi recommendUserApi;
@DubboReference
private UserInfoApi userInfoApi;
@DubboReference
private QuestionApi questionApi;
// 查询今日佳人数据
public TodayBest todayBest() {
// 1. 获取用户id
Long 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. 获取用户id
Long 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 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();
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java
文件:
@RestController
@RequestMapping("/tanhua")
public class TanhuaController {
@Autowired
private 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);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java
文件:
@Service
public class TanhuaService {
@DubboReference
private RecommendUserApi recommendUserApi;
@DubboReference
private UserInfoApi userInfoApi;
@DubboReference
private QuestionApi questionApi;
@Autowired
private HuanXinTemplate huanXinTemplate;
// 查询今日佳人数据
public TodayBest todayBest() {
// 1. 获取用户id
Long 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. 获取用户id
Long 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 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());
}
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java
文件:
@RestController
@RequestMapping("/messages")
public class MessagesController {
@Autowired
private 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);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java
文件:
@Service
public class MessagesService {
@DubboReference
private UserApi userApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private HuanXinTemplate huanXinTemplate;
@DubboReference
private 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. 记录好友关系到MongoDB
friendApi.save(UserHolder.getUserId(), friendId);
}
}
新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/FriendApi.java
文件:
public interface FriendApi {
// 添加好友
void save(Long userId, Long friendId);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/FriendApiImpl.java
文件:
@DubboService
public class FriendApiImpl implements FriendApi {
@Autowired
private MongoTemplate mongoTemplate;
// 添加好友
@Override
public 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);
}
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java
文件:
@RestController
@RequestMapping("/messages")
public class MessagesController {
@Autowired
private 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);
}
}
新建 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;
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java
文件:
@Service
public class MessagesService {
@DubboReference
private UserApi userApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private HuanXinTemplate huanXinTemplate;
@DubboReference
private 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. 记录好友关系到MongoDB
friendApi.save(UserHolder.getUserId(), friendId);
}
// 分页查询联系人列表
public PageResult findFriends(Integer page, Integer pagesize, String keyword) {
// 1. 调用API查询当前用户的好友数据 -- List
List<Friend> list = friendApi.findUserById(UserHolder.getUserId(), page, pagesize);
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 2. 提取数据列表中的好友id
List<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);
}
}
编辑 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);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/FriendApiImpl.java
文件:
@DubboService
public class FriendApiImpl implements FriendApi {
@Autowired
private MongoTemplate mongoTemplate;
// 添加好友
@Override
public 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);
}
}
// 查询好友列表
@Override
public 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{
@Autowired
private UserInfoMapper userInfoMapper;
@Override
public void save(UserInfo userInfo) {
userInfoMapper.insert(userInfo);
}
@Override
public void update(UserInfo userInfo) {
userInfoMapper.updateById(userInfo);
}
@Override
public UserInfo findById(Long id) {
return userInfoMapper.selectById(id);
}
/**
* 批量查询用戶详情
* @param userIds 用户id列表
* @param info 用户详情信息
* @return
*/
@Override
public 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;
}
}