在探花交友App上,登录的用户可以设置陌生人问题,通知设置,黑名单设置,以及修改手机号码设置。如下图所示:
为了完成上述功能,采用了一下几张表
通用设置:用来保存用户的通知信息,和用户是一对一的关系
CREATE TABLE `tb_settings` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`like_notification` tinyint(4) DEFAULT '1' COMMENT '推送喜欢通知',
`pinglun_notification` tinyint(4) DEFAULT '1' COMMENT '推送评论通知',
`gonggao_notification` tinyint(4) DEFAULT '1' COMMENT '推送公告通知',
`created` datetime DEFAULT NULL,
`updated` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='设置表';
问题表:保存用户的陌生人问题,一个用户只能有一个陌生人问题,和用户表是一对一的关系
CREATE TABLE `tb_question` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
`txt` varchar(200) DEFAULT NULL COMMENT '问题内容',
`created` datetime DEFAULT NULL,
`updated` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
黑名单:和用户表是一对多的关系,黑名单表通过user_id
和black_user_id
唯一确定一条记录
CREATE TABLE `tb_black_list` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`black_user_id` bigint(20) DEFAULT NULL,
`created` datetime DEFAULT NULL,
`updated` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='黑名单';
实体类
Settings
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Settings extends BasePojo {
private Long id;
private Long userId;
private Boolean likeNotification;
private Boolean pinglunNotification;
private Boolean gonggaoNotification;
}
Question
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Question extends BasePojo {
private Long id;
private Long userId;
//问题内容
private String txt;
}
BlackList
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BlackList extends BasePojo {
private Long id;
private Long userId;
private Long blackUserId;
}
Mapper接口
ettingsMapper
public interface SettingsMapper extends BaseMapper<Settings> {}
QuestionMapper
public interface QuestionMapper extends BaseMapper<Question> {}
BlackListMapper
public interface BlackListMapper extends BaseMapper<BlackList> {}
api接口
SettingApi
public interface SettingsApi {
Settings getSettingsByUserId(Long userId);
void save(Settings settings);
void update(Settings settings);
}
QuestionApi
public interface QuestionApi {
Question getQuestionByUserId(Long userId);
void save(Question question);
void update(Question question);
}
BlackListApi
public interface BlackListApi {
IPage<UserInfo> getBlackList(Long userId, int page, int size);
void removeUserFromBlackList(Long userId, Long uid);
}
api服务实现类
SettingServiceImpl
@DubboService
public class SettingsApiImpl implements SettingsApi{
@Resource
private SettingsMapper settingsMapper;
@Override
public Settings getSettingsByUserId(Long userId) {
LambdaQueryWrapper<Settings> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Settings::getUserId, userId);
return this.settingsMapper.selectOne(queryWrapper);
}
@Override
public void save(Settings settings) {
this.settingsMapper.insert(settings);
}
@Override
public void update(Settings settings) {
this.settingsMapper.updateById(settings);
}
}
QuestionServiceImpl
@DubboService
public class QuestionApiImpl implements QuestionApi {
@Resource
private QuestionMapper questionMapper;
@Override
public Question getQuestionByUserId(Long userId) {
LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Question::getUserId, userId);
return this.questionMapper.selectOne(queryWrapper);
}
@Override
public void save(Question question) {
this.questionMapper.insert(question);
}
@Override
public void update(Question question) {
this.questionMapper.updateById(question);
}
}
BlackListServiceImpl
@DubboService
public class BlackListApiImpl implements BlackListApi{
@Resource
private BlackListMapper blackListMapper;
@Override
public IPage<UserInfo> getBlackList(Long userId, int page, int size) {
Page pageInfo = new Page(page, size);
return this.blackListMapper.getBlackList(userId, pageInfo);
}
@Override
public void removeUserFromBlackList(Long userId, Long uid) {
LambdaQueryWrapper<BlackList> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(BlackList::getBlackUserId, uid);
queryWrapper.eq(BlackList::getUserId, userId);
this.blackListMapper.delete(queryWrapper);
}
}
当用户点击通用设置后,我们需要根据用户的id查询到用户的所有设置信息,包括手机号,陌生人问题和通知设置。接口如下
为了封装返回值的数据,我们需要创建一个VO对象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SettingsVo implements Serializable {
private Long id;
private String strangerQuestion = "";
private String phone;
private Boolean likeNotification = true;
private Boolean pinglunNotification = true;
private Boolean gonggaoNotification = true;
}
在Controller中添加一个方法处理查询用户通用设置的请求
@GetMapping("/settings")
public ResponseEntity getSettings() {
// 1. 调用service查询设置信息,返回VO对象
SettingsVo settingsVo = this.settingsService.getSettings();
// 2. 返回结果
return ResponseEntity.ok(settingsVo);
}
在Service中创建方法查询用户通用设置
public SettingsVo getSettings() {
SettingsVo settingsVo = new SettingsVo();
// 1. 获取到用户的id
settingsVo.setId(UserHolder.getUserId());
// 2. 获取到用户的手机号
settingsVo.setPhone(UserHolder.getUserPhone());
// 3. 根据用户id查询陌生人问题
Question question = this.questionApi.getQuestionByUserId(UserHolder.getUserId());
String txt = question == null ? "用户没有设置陌生人问题" : question.getTxt();
settingsVo.setStrangerQuestion(txt);
// 4. 查询设置开关状态
Settings settings = this.settingsApi.getSettingsByUserId(UserHolder.getUserId());
if (settings != null) {
settingsVo.setLikeNotification(settings.getLikeNotification());
settingsVo.setPinglunNotification(settings.getPinglunNotification());
settingsVo.setGonggaoNotification(settings.getGonggaoNotification());
}
return settingsVo;
}
对数据库表进行操作:如果存在数据,更新数据库。如果不存在数据,保存数据库表数据。接口如下:
在Controller中添加方法
@PostMapping("/questions")
public ResponseEntity saveOrUpdateQuestion(@RequestBody Map map) {
// 1. 获取参数
String content = map.get("content").toString();
// 2. 调用service
this.settingsService.saveOrUpdateQuestion(content);
// 3. 返回结果
return ResponseEntity.ok(null);
}
在Service实现业务逻辑
public void saveOrUpdateQuestion(String content) {
// 1. 获取用户ID
Long userId = UserHolder.getUserId();
// 2. 判断用户是否设置过问题 如果设置过 则为更新 否则为新增
Question question = this.questionApi.getQuestionByUserId(userId);
if (question == null) {
// 新增问题
question.setUserId(userId);
question.setTxt(content);
this.questionApi.save(question);
} else {
// 更新问题
question.setTxt(content);
this.questionApi.update(question);
}
}
Controller
/**
* 更改通知设置
*
* @param map
* @return
*/
@PostMapping("notifications/setting")
public ResponseEntity saveOrUpdateSettings(@RequestBody Map map) {
// 1. 调用service
this.settingsService.saveOrUpdateSettings(map);
// 2. 返回数据
return ResponseEntity.ok(null);
}
Service
public void saveOrUpdateSettings(Map map) {
// 0. 解析数据
Boolean likeNotification = (Boolean) map.get("likeNotification");
Boolean pinglunNotification = (Boolean) map.get("pinglunNotification");
Boolean gonggaoNotification = (Boolean) map.get("gonggaoNotification");
// 1. 获取用户id
Long userId = UserHolder.getUserId();
// 2. 查询用户是否有过设置 如果没有 则新增 否则则更新
Settings settings = this.settingsApi.getSettingsByUserId(userId);
if (settings == null) {
settings = new Settings();
settings.setUserId(userId);
settings.setLikeNotification(likeNotification);
settings.setPinglunNotification(pinglunNotification);
settings.setGonggaoNotification(gonggaoNotification);
this.settingsApi.save(settings);
} else {
settings.setLikeNotification(likeNotification);
settings.setPinglunNotification(pinglunNotification);
settings.setGonggaoNotification(gonggaoNotification);
this.settingsApi.update(settings);
}
}
根据用户id在黑名单表中查询用户,需要注意的是,从黑名单表格中查询到的只是userId,我们需要联表查询得到用户信息。此外,在黑名单界面,用户可以点击取消黑名单从而将制定用户从黑名单中移除。接口如下
由于前端对分页数据返回值的要求,这里没有直接使用Mybatis Plus的分页对象,而是自己创建了一个VO类用来封装分页后的相关数据
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {
private Integer counts = 0;//总记录数
private Integer pagesize;//页大小
private Integer pages = 0;//总页数
private Integer page;//当前页码
private List<?> items = Collections.emptyList(); //列表
public PageResult(Integer page,Integer pagesize,
int counts,List list) {
this.page = page;
this.pagesize = pagesize;
this.items = list;
this.counts = counts;
this.pages = counts % pagesize == 0 ? counts / pagesize : counts / pagesize + 1;
}
}
Controller
/**
* 分页查询当前那用户的黑名单
*
* @param page
* @param size
* @return
*/
@GetMapping("/blacklist")
public ResponseEntity getBlackList(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "5") int size) {
// 1. 调用service查询
PageResult pageResult = this.settingsService.getBlackList(page, size);
// 2. 返回结果
return ResponseEntity.ok(pageResult);
}
/**
* 移除黑名单
* @param uid
* @return
*/
@DeleteMapping("/blacklist/{uid}")
public ResponseEntity removeUserFromBlackList(@PathVariable(name = "uid") Long uid) {
// 1.调用service方法移除童虎
this.settingsService.removeUserFromBlackList(uid);
return ResponseEntity.ok(null);
}
Service
public PageResult getBlackList(int page, int size) {
// 1. 获取到用户id
Long userId = UserHolder.getUserId();
// 2. 调用api查询
IPage<UserInfo> iPage = this.blackListApi.getBlackList(userId, page, size);
// 3. 解析page对象成PageResult
return new PageResult(page, size, (int) iPage.getTotal(), iPage.getRecords());
}
public void removeUserFromBlackList(Long uid) {
// 1. 获取当前用户id
Long userId = UserHolder.getUserId();
// 2. 调用api删除
this.blackListApi.removeUserFromBlackList(userId, uid);
}
实现联表查询,我们自己写了一个连表查询的SQL语句
public interface BlackListMapper extends BaseMapper<BlackList> {
@Select("select * from tb_user_info where id in (\n" +
" SELECT black_user_id FROM tb_black_list where user_id=#{userId}\n" +
")")
IPage<UserInfo> getBlackList(@Param("userId") Long userId, @Param("pages") Page pageInfo);
}
此外,为了实现分页功能,还需要开启Mybatis Plus的分页查询功能,因此需要在引导类中添加相关配置
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
探花交友APP允许修改已注册用户的手机号,修改分为以下三个步骤
接口如下
Controller
/**
* 修改手机号发送验证码
* @return
*/
@PostMapping("/phone/sendVerificationCode")
public ResponseEntity sendVerificationCode() {
// 1. 获取登录用户的手机号
String userPhone = UserHolder.getUserPhone();
// 2. 调用Service方法
this.userService.sendMsg(userPhone);
// 3. 返回结果
return ResponseEntity.ok(null);
}
/**
* 判断用户输入的验证码是否正确
* @param map 验证码
* @return 返回布尔类型,true - 正确 false - 错误
*/
@PostMapping("/phone/checkVerificationCode")
public ResponseEntity checkVerificationCode(@RequestBody Map map) {
String code = map.get("verificationCode").toString();
String userPhone = UserHolder.getUserPhone();
boolean verification = this.userService.checkVerificationCode(code, userPhone);
return ResponseEntity.ok(false);
}
/**
* 更改手机号
* @param phone 新手机号
* @return 空
*/
@PostMapping("/phone")
public ResponseEntity updatePhone(String phone) {
Long userId = UserHolder.getUserId();
this.userService.updatePhone(phone, userId);
return ResponseEntity.ok(null);
}
Service
public void sendMsg(String phone) {
// 1. 生成验证码
// String code = RandomStringUtils.randomNumeric(6);
// 2.调用发送验证码的方法
// emailTemplate.sendCode(phone, code);
// 3.将验证码存入redis
String code = "123456"; // 方便测试将验证码写死
redisTemplate.opsForValue().set(VERIFICATION_CODE_PREFIX + phone, code, Duration.ofMinutes(5));
}
public boolean checkVerificationCode(String code, String userPhone) {
// 1.从Redis中获取到验证码
String redisCode = this.redisTemplate.opsForValue().get(VERIFICATION_CODE_PREFIX + userPhone);
// 2.比较验证码
if (StringUtils.isEmpty(redisCode) || !redisCode.equals(code)) {
// 验证码无效或者验证码错误
throw new BusinessException(ErrorResult.loginError());
}
return true;
}
public void updatePhone(String phone, Long userId) {
this.userApi.updatePhone(phone, userId);
}
Api
@Override
public void updatePhone(String phone, Long userId) {
User user = new User();
user.setId(userId);
user.setMobile(phone);
this.userMapper.updateById(user);
}
在探花交友APP中,会涉及很多的数据保存,比如用户的动态,点赞信息,评论信息,位置信息等。这些数据有一下的特点:
针对上述特点,传统的MySQL数据库有些力不从心,因此,我们引入了MongoDB。
MongoDB:是一个高效的非关系型数据库(不支持表关系:只能操作单表)
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
MongoDB采用的是内存和磁盘结合的存储方式,比较常用的数据都保存在内存中,如果内存中找不到数据,再去磁盘中查找,这样就加快了查询的速度。
为了保证数据的安全性,内存中的数据每一分钟都会同步到磁盘中。
此外,为了更加保护数据的安全性,MongoDB在新版本中引入了日志,日志在内存和硬盘中各一份,每10ms同步一次。这样即使断电的时候,内存中的数据没有保存到磁盘,也可以通过日志文件进行恢复,从而保证了数据的安全性。
但是即使这样,也不能MongoDB不能够保证数据100%不丢失。
此外,MongoDB支持数据分页技术,可以将保存的数据进行分页,从而可以非常方便的进行存储容量的扩充
下面是MongoDB和MySQL数据库概念上的对比
MongoDB中存储BSON数据,类似JSON
MongoDB 的逻辑结构是一种层次结构。主要由: 文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面 向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 表中的一条数据 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
MongoDB中常用的数据结构如下:
MongoDB中常见的数据类型有:
在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。
#插入数据
#语法:db.表名.insert(json字符串)
db.user.insert({id:1,name:'zhangsan'}) #插入数据
update() 方法用于更新已存在的文档。语法格式如下:
db.collection.update(
<query>,
<update>,
[
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
]
)
参数说明:
#更新数据
> db.user.update({id:1},{$set:{age:22}})
#注意:如果这样写,会删除掉其他的字段
> db.user.update({id:1},{age:25})
#更新不存在的字段,会新增字段
> db.user.update({id:2},{$set:{sex:1}}) #更新数据
#更新不存在的数据,默认不会新增数据
> db.user.update({id:3},{$set:{sex:1}})
#如果设置第一个参数为true,就是新增数据
> db.user.update({id:3},{$set:{sex:1}},true)
通过remove()方法进行删除数据,语法如下:
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
实例:
#删除数据
> db.user.remove({})
#插入4条测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
> db.user.remove({age:22},true)
#删除所有数据
> db.user.remove({})
MongoDB 查询数据的语法格式如下:
db.user.find([query],[fields])
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | { } |
db.col.find({"by":"Jack"}).pretty() |
where by = 'Jack' |
小于 | { |
db.col.find({"likes":{$lt:50}}).pretty() |
where likes < 50 |
小于或等于 | { |
db.col.find({"likes":{$lte:50}}).pretty() |
where likes <= 50 |
大于 | { |
db.col.find({"likes":{$gt:50}}).pretty() |
where likes > 50 |
大于或等于 | { |
db.col.find({"likes":{$gte:50}}).pretty() |
where likes >= 50 |
不等于 | { |
db.col.find({"likes":{$ne:50}}).pretty() |
where likes != 50 |
实例:
#插入测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
db.user.find() #查询全部数据
db.user.find({},{id:1,username:1}) #只查询id与username字段
db.user.find().count() #查询数据条数
db.user.find({id:1}) #查询id为1的数据
db.user.find({age:{$lte:21}}) #查询小于等于21的数据
db.user.find({$or:[{id:1},{id:2}]}) #查询id=1 or id=2
#分页查询:Skip()跳过几条,limit()查询条数
db.user.find().limit(2).skip(1) #跳过1条数据,查询2条数据
db.user.find().sort({id:-1}) #按照id倒序排序,-1为倒序,1为正序
索引能够极大提高查询的效率。类似于MySQL,MongoDB中叶提供了索引支持。在没有索引的时候,MongoDB需要便利整个集合,查询效率很低。
为MongoDB创建索引的命令如下,为age域设置一个递增的索引
#创建索引
#说明:1表示升序创建索引,-1表示降序创建索引。
> db.user.createIndex({'age':1})
Spring-data对MongoDB做了支持,使用spring-data-mongodb可以简化MongoDB的操作,封装了底层的mongodb-driver。在Springboot中使用MongoDB的步骤如下:
导入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
编写application.yml
spring:
data:
mongodb:
uri: mongodb://192.168.136.160:27017/test
编写集合对应的实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(value="tb_person")
public class Person {
@Id
private ObjectId id;
@Field("myname")
private String name;
private int age;
private String address;
}
- 只要是MongoDB的集合实体类,都需要添加
@Document(value="XXX")
注解,在MongoDB中,集合的名称就为XXX- 在实体类中,需要指定MongoDB的文档的ID,这个ID由MongoDB自动生成,不会重复。在ID字段上使用
@Id
指定。ID的类型应为ObjectId
- 可以通过
@Field("myname")
来指定保存集合的域的名称,如果不指定,默认就以变量面作为域名
引入MongoTemplate
@Resource
private MongoTemplate mongoTemplate;
下面编写了一个测试类,来以Java代码的方式对MongoDB进行CRUD操作
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MongoApplication.class)
public class MongoTest {
@Resource
private MongoTemplate mongoTemplate;
@Test
public void testInsert() {
// 插入一条数据
Person person = new Person();
person.setAddress("上海");
person.setAge(23);
person.setName("Robert");
this.mongoTemplate.save(person);
}
@Test
public void testFindAll() {
// 查询所有数据
List<Person> all = this.mongoTemplate.findAll(Person.class);
all.forEach(System.out::println);
}
@Test
public void testFindByCondition() {
// 根据条件查询
Criteria criteria = Criteria.where("age")
.is(23).and("myname").is("Robert");
Query query = new Query(criteria);
List<Person> people = this.mongoTemplate.find(query, Person.class);
people.forEach(System.out::println);
}
@Test
public void testFindPage() {
int page = 2;
int size = 5;
// 条件分页
Criteria criteria = Criteria.where("age").lt(55);
Query query = new Query(criteria);
query.skip((page - 1) * size).limit(size)
.with(Sort.by(Sort.Order.desc("age")));
List<Person> people = this.mongoTemplate.find(query, Person.class);
people.forEach(System.out::println);
}
@Test
public void testUpdate() {
Query query = new Query(Criteria.where("id").is("63a431e998e6c17444113fc9"));
// updateFirst是更新满足条件的第一个记录
// 设置要更新的内容
Update update = new Update();
update.set("myname", "Jack");
this.mongoTemplate.updateFirst(query, update, Person.class);
}
@Test
public void testDelete() {
// 根据条件删除
Query query = new Query(Criteria.where("myname").is("Jack"));
this.mongoTemplate.remove(query, Person.class);
}
}
学习完MongoDB的使用以后,我们来实现一个功能用来巩固MongoDB的使用。
在用户登录成功后,就会进入首页,首页中有今日佳人、推荐好友、探花、搜附近等功能。
今日佳人,会推荐缘分值最大的用户,进行展现出来。缘分值的计算是由用户的行为进行打分,如:点击、点赞、评论、学历、婚姻状态等信息组合而成的。
实现:我们先不考虑推荐的逻辑,假设现在已经有推荐的结果,我们只需要从结果中查询到缘分值最高的用户就可以了。至于推荐的逻辑以及实现,我们将后面的课程中讲解。
#表结构 recommend_user
{
"userId":1001, #推荐的用户id
"toUserId":1002, #用户id
"score":90, #推荐得分
"date":"2019/1/1" #日期
}
在MongoDB中只存储用户的id数据,其他的数据需要通过接口查询。
其中score
为缘分分数,我们要选择缘分分数最大的。此外,我们是将userId
推荐给toUserId
。
假设userId
=1001,toUserId
=106,那么应该是将1001推荐给106。
今日佳人功能的接口如下:
编写实体类
@AllArgsConstructor
@NoArgsConstructor
@Data
@Document(collection = "recommend_user")
public class RecommendUser implements Serializable {
@Id
private ObjectId id; //主键id
private Long userId; //推荐的用户id
private Long toUserId; //用户id
private Double score =0d; //推荐得分
private String date; //日期
}
编写API
public interface RecommendUserApi {
RecommendUser getTodayBest(Long userId);
}
@DubboService
public class RecommendUserApiImpl implements RecommendUserApi {
@Resource
private MongoTemplate mongoTemplate;
@Override
public RecommendUser getTodayBest(Long userId) {
// 根据toUserId字段查询,然后根据分数排序,取分数最高的一个
Criteria criteria = Criteria.where("toUserId").is(userId);
Query query = new Query().with(Sort.by(Sort.Order.desc("score"))).limit(1);
return mongoTemplate.findOne(query, RecommendUser.class);
}
}
注意:这里我们值选择分数最高的一个可以利用分页查询,pagesize为1,然后获取第一页
Controller
@RestController
@RequestMapping("/tanhua")
public class TanhuaController {
@Resource
private TanhuaService tanhuaService;
/**
* 查询今日佳人
*
* @return
*/
@GetMapping("/todayBest")
public ResponseEntity getTodayBest() {
// 1. 调用service方法查询今日佳人
TodayBest vo = this.tanhuaService.getTodayBest();
// 2. 将结果返回
return ResponseEntity.ok(vo);
}
}
Service
@Service
public class TanhuaService {
@DubboReference
private RecommendUserApi recommendUserApi;
@DubboReference
private UserInfoApi userInfoApi;
public TodayBest getTodayBest() {
// 1. 获取当前用户
Long userId = UserHolder.getUserId();
// 2. 调用api查询
RecommendUser recommendUser = this.recommendUserApi.getTodayBest(userId);
// 如果佳人不存在,则设置一个默认值
if (recommendUser == null) {
recommendUser = new RecommendUser();
recommendUser.setUserId(1L);
recommendUser.setScore(100.0);
}
// 3. 将返回数据封装成vo对象
UserInfo userInfo = this.userInfoApi.getUserInfoById(recommendUser.getUserId());
return TodayBest.init(userInfo, recommendUser);
}
}
注意这里有可能查不到有缘人,因此需要判断一下并设置一个默认值
在项目中,添加了mongo的依赖的话,springboot就会自动去连接本地的mongo,由于他连接不上会导致出错。
解决有2种方案:
排除掉mongo的依赖
springboot中添加排除自动配置的注解
@SpringBootApplication(exclude = {
MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class
}) //排除mongo的自动配置
public class TanhuaServerApplication {
public static void main(String[] args) {
SpringApplication.run(TanhuaServerApplication.class,args);
}
}