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

安能摧眉折腰事权贵,使我不得开心颜


系列文章目录

1. 项目介绍及环境配置
2. 短信验证码登录
3. 用户信息
4. MongoDB


文章目录

  • 系列文章目录
  • 一、通用设置
    • 1. 查询通用设置
      • ⑴. 需求分析
      • ⑵. 数据库表
      • ⑶. 搭建服务提供者
        • ①. 实体类
        • ②. mapper接口
        • ③. api接口
        • ④. api实现类
      • ⑷. 接口文档
      • ⑸. 控制层Controller
        • ①. vo 对象
        • ②. controller
      • ⑹. 调用API,构造 vo 返回对象
        • ①. 逻辑层Service
        • ②. 补充方法
      • ⑺. 测试
    • 2. 设置陌生人问题
      • ⑴. 页面展示
      • ⑵. 接口文档
      • ⑶. 编码实现
        • ①. 控制层
        • ②. 服务层
        • ③. API接口
        • ④. API实现类
      • ⑷. 测试
    • 3. 通知设置
      • ⑴. 页面展示
      • ⑵. 接口文档
      • ⑶. 编码实现
        • ①. 控制层
        • ②. 服务层
        • ③. API接口
        • ④. API实现类
      • ⑷. 测试
    • 4. 查询黑名单
      • ⑴. 页面展示
      • ⑵. 接口文档
      • ⑶. 编码实现
        • ①. vo对象
        • ②. 控制层Controller
        • ③. 业务逻辑层Service
        • ④. API接口
        • ⑤. Mapper接口
        • ⑥. API实现类
        • ⑦. 分页插件支持
      • ⑷. 测试类
      • ⑸. 黑名单测试
    • 5. 移出黑名单
      • ⑴. 接口文档
      • ⑵. 控制层Controller
      • ⑶. 业务层Service
      • ⑷. Api接口
      • ⑸. Api实现类
      • ⑹. 测试
  • 二、MongoDB入门
    • 1. 数据库分析
    • 2. MongoDB简介
    • 3. 体系结构与术语
    • 4. MongoDB安装与连接
    • 5. 基础命令
      • ⑴. 数据库以及表的操作
      • ⑵. 新增数据
      • ⑶. 更新数据
      • ⑷. 删除数据
      • ⑸. 查询数据
    • 6. 索引
  • 三. SpringBoot整合MongoDB
    • 1. 创建工程, 导入依赖
    • 2. 添加 MongoDB 的配置信息
    • 3. 编写启动/引导类
    • 4. 编写实体类, 并通过注解配置映射
    • 5. 编写测试类,进行数据操作
  • 四、今日佳人
    • 1.页面展示
    • 2.搭建服务提供者
      • ⑴. 配置工程环境
      • ⑵. 实体类
      • ⑶. API接口
      • ⑶. API实现类
    • 3. 测试类
    • 4.接口文档
    • 5.控制层
    • 6.服务层
    • 7.vo对象
    • 8.解决MongoDB启动bug
    • 9.Postman测试


一、通用设置

1. 查询通用设置

⑴. 需求分析

通用设置包含:

  • 设置陌生人问题: 当平台其他用户想进行在线交流时需要回答陌生人问题
  • 通用设置: 包含一些APP通知设置
  • 黑名单: 对于不感兴趣的用户设置黑名单屏蔽骚扰

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第1张图片
Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第2张图片


⑵. 数据库表

通用设置:

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

黑名单:

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='黑名单';

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第3张图片


⑶. 搭建服务提供者

①. 实体类

新建 tanhua-model/src/main/java/com/tanhua/model/domain/Settings.java 通用设置 实体类:

/**
 * 通知设置
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Settings extends BasePojo {

    private Long id;
    private Long userId;
    private Boolean likeNotification;
    private Boolean pinglunNotification;
    private Boolean gonggaoNotification;

}

新建 tanhua-model/src/main/java/com/tanhua/model/domain/Question.java 陌生人问题 实体类:

/**
 * 陌生人问题
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Question extends BasePojo {

    private Long id;
    private Long userId;
    //问题内容
    private String txt;

}

新建 tanhua-model/src/main/java/com/tanhua/model/domain/BlackList.java 黑名单 实体类:

/**
 * 黑名单
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BlackList extends BasePojo {

    private Long id;
    private Long userId;
    private Long blackUserId;
}

②. mapper接口

新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/mappers/SettingsMapper.java 通用设置 Mapper接口:

public interface SettingsMapper extends BaseMapper<Settings> {
}

新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/mappers/QuestionMapper.java 陌生人问题 Mapper接口:

public interface QuestionMapper extends BaseMapper<Question> {
}

新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/mappers/BlackListMapper.java 黑名单 Mapper接口:

public interface BlackListMapper extends BaseMapper<BlackList> {
}

③. api接口

新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/SettingsApi.java 通用设置 Api接口:

public interface SettingsApi {
}

新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/QuestionApi.java 陌生人问题 Api接口:

public interface QuestionApi {
}

新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/BlackListApi.java 黑名单 Api接口:

public interface BlackListApi {
}

④. api实现类

新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/SettingsApiImpl.java 通用设置 Api接口实现类:

@DubboService
public class SettingsApiImpl implements SettingsApi{

    @Autowired
    private SettingsMapper settingsMapper;

    // 根据用户id查询
    @Override
    public Settings findByUserId(Long userId) {
        QueryWrapper<Settings> qw = new QueryWrapper<>();
        qw.eq("user_id", userId);
        return settingsMapper.selectOne(qw);
    }
}

新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/QuestionApiImpl.java 陌生人问题 Api接口实现类:

@DubboService
public class QuestionApiImpl implements QuestionApi{

    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public Question findByUserId(Long userId) {
        QueryWrapper<Question> qw = new QueryWrapper<>();
        qw.eq("user_id", userId);
        return questionMapper.selectOne(qw);
    }
}

新建 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/BlackListApiImpl.java 黑名单 Api接口实现类:

@DubboService
public class BlackListApiImpl implements BlackListApi {
}

⑷. 接口文档

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第4张图片


⑸. 控制层Controller

①. vo 对象

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

@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

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

@RestController
@RequestMapping("/users")
public class SettingsController {

    @Autowired
    private SettingsService settingsService;

    /**
     * 查询通用设置
     */
    @GetMapping("/settings")
    public ResponseEntity settings() {
        SettingsVo vo = settingsService.settings();
        return ResponseEntity.ok(vo);
    }
}

⑹. 调用API,构造 vo 返回对象

①. 逻辑层Service

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

@Service
public class SettingsService {

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private SettingsApi settingsApi;

    // 查询用户通用设置
    public SettingsVo settings() {
        SettingsVo vo = new SettingsVo();

        // 1. 查询用户id
        Long userId = UserHolder.getUserId();
        vo.setId(userId);

        // 2. 查询用户手机号
        vo.setPhone(UserHolder.getMobile());

        // 3. 查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);
        // 设置默认问题
        String txt = question == null ? "你喜欢Java吗?" : question.getTxt();
        vo.setStrangerQuestion(txt);

        // 4. APP通知开关数据
        Settings settings = settingsApi.findByUserId(userId);
        if(settings != null) {
            vo.setGonggaoNotification(settings.getGonggaoNotification());
            vo.setLikeNotification(settings.getLikeNotification());
            vo.setPinglunNotification(settings.getPinglunNotification());
        }

        return vo;
    }
}

②. 补充方法

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

public interface QuestionApi {
    // 根据用户查询陌生人问题
    Question findByUserId(Long userId);
}

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

public interface SettingsApi {
    // 根据用户id查询
    Settings findByUserId(Long userId);
}

⑺. 测试

断点测试,查看返回数据
Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第5张图片
关闭断点,可正常查看通知设置、陌生人问题
Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第6张图片


2. 设置陌生人问题

⑴. 页面展示

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第7张图片

⑵. 接口文档

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第8张图片

⑶. 编码实现

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第9张图片

①. 控制层

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

@RestController
@RequestMapping("/users")
public class SettingsController {

    @Autowired
    private SettingsService settingsService;

    /**
     * 查询通用设置
     */
    @GetMapping("/settings")
    public ResponseEntity settings() {
        SettingsVo vo = settingsService.settings();
        return ResponseEntity.ok(vo);
    }

    /**
     * 设置陌生人问题
     */
    @PostMapping("/questions")
    public ResponseEntity questions(@RequestBody Map map) {
        String content = (String) map.get("content");
        settingsService.saveQuestions(content);
        return ResponseEntity.ok(null);
    }
}

②. 服务层

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

@Service
public class SettingsService {

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private SettingsApi settingsApi;

    // 查询用户通用设置
    public SettingsVo settings() {
        SettingsVo vo = new SettingsVo();

        // 1. 查询用户id
        Long userId = UserHolder.getUserId();
        vo.setId(userId);

        // 2. 查询用户手机号
        vo.setPhone(UserHolder.getMobile());

        // 3. 查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);
        // 设置默认问题
        String txt = question == null ? "你喜欢Java吗?" : question.getTxt();
        vo.setStrangerQuestion(txt);

        // 4. APP通知开关数据
        Settings settings = settingsApi.findByUserId(userId);
        if(settings != null) {
            vo.setGonggaoNotification(settings.getGonggaoNotification());
            vo.setLikeNotification(settings.getLikeNotification());
            vo.setPinglunNotification(settings.getPinglunNotification());
        }

        return vo;
    }

    // 设置陌生人问题
    public void saveQuestions(String content) {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);

        // 3. 判断问题是否存在
        if(question == null) {
            // 3.1 如果不存在,保存
            question = new Question();
            question.setUserId(userId);
            question.setTxt(content);
            questionApi.save(question);

        } else {
            // 3.2 如果存在,更新
            question.setTxt(content);
            questionApi.update(question);
        }
    }
}

③. API接口

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

public interface QuestionApi {
    // 根据用户查询陌生人问题
    Question findByUserId(Long userId);

    // 保存
    void save(Question question);

    // 更新
    void update(Question question);
}

④. API实现类

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

@DubboService
public class QuestionApiImpl implements QuestionApi{

    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public Question findByUserId(Long userId) {
        QueryWrapper<Question> qw = new QueryWrapper<>();
        qw.eq("user_id", userId);
        return questionMapper.selectOne(qw);
    }

    @Override
    public void save(Question question) {
        questionMapper.insert(question);
    }

    @Override
    public void update(Question question) {
        questionMapper.updateById(question);
    }
}

⑷. 测试

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第10张图片


3. 通知设置

⑴. 页面展示

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第11张图片

⑵. 接口文档

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第12张图片

⑶. 编码实现

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第13张图片

①. 控制层

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

@RestController
@RequestMapping("/users")
public class SettingsController {

    @Autowired
    private SettingsService settingsService;

    /**
     * 查询通用设置
     */
    @GetMapping("/settings")
    public ResponseEntity settings() {
        SettingsVo vo = settingsService.settings();
        return ResponseEntity.ok(vo);
    }

    /**
     * 设置陌生人问题
     */
    @PostMapping("/questions")
    public ResponseEntity questions(@RequestBody Map map) {
        String content = (String) map.get("content");
        settingsService.saveQuestions(content);
        return ResponseEntity.ok(null);
    }

    /**
     * 通知设置
     */
    @PostMapping("notifications/setting")
    public ResponseEntity notifications(@RequestBody Map map) {
        // 获取参数
        settingsService.saveSettings(map);
        return ResponseEntity.ok(null);
    }
}

②. 服务层

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

@Service
public class SettingsService {

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private SettingsApi settingsApi;

    // 查询用户通用设置
    public SettingsVo settings() {
        SettingsVo vo = new SettingsVo();

        // 1. 查询用户id
        Long userId = UserHolder.getUserId();
        vo.setId(userId);

        // 2. 查询用户手机号
        vo.setPhone(UserHolder.getMobile());

        // 3. 查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);
        // 设置默认问题
        String txt = question == null ? "你喜欢Java吗?" : question.getTxt();
        vo.setStrangerQuestion(txt);

        // 4. APP通知开关数据
        Settings settings = settingsApi.findByUserId(userId);
        if(settings != null) {
            vo.setGonggaoNotification(settings.getGonggaoNotification());
            vo.setLikeNotification(settings.getLikeNotification());
            vo.setPinglunNotification(settings.getPinglunNotification());
        }

        return vo;
    }

    // 设置陌生人问题
    public void saveQuestions(String content) {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);

        // 3. 判断问题是否存在
        if(question == null) {
            // 3.1 如果不存在,保存
            question = new Question();
            question.setUserId(userId);
            question.setTxt(content);
            questionApi.save(question);

        } else {
            // 3.2 如果存在,更新
            question.setTxt(content);
            questionApi.update(question);
        }
    }

    // 通知设置
    public void saveSettings(Map map) {
        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. 调用api查询用户通知设置
        Settings settings = settingsApi.findByUserId(userId);

        // 3. 判断通知设置是否存在
        if(settings == null) {
            // 4.1 如果不存在,保存
            settings = new Settings();
            settings.setUserId(userId);
            settings.setLikeNotification(likeNotification);
            settings.setGonggaoNotification(gonggaoNotification);
            settings.setPinglunNotification(pinglunNotification);
            settingsApi.save(settings);

        } else {
            // 4.2 如果存在,更新
            settings.setLikeNotification(likeNotification);
            settings.setGonggaoNotification(gonggaoNotification);
            settings.setPinglunNotification(pinglunNotification);
            settingsApi.update(settings);
        }
    }
}

③. API接口

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

public interface SettingsApi {
    // 根据用户id查询
    Settings findByUserId(Long userId);

    // 保存
    void save(Settings settings);

    // 更新
    void update(Settings settings);
}

④. API实现类

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

@DubboService
public class SettingsApiImpl implements SettingsApi{

    @Autowired
    private SettingsMapper settingsMapper;

    // 根据用户id查询
    @Override
    public Settings findByUserId(Long userId) {
        QueryWrapper<Settings> qw = new QueryWrapper<>();
        qw.eq("user_id", userId);
        return settingsMapper.selectOne(qw);
    }

    // 保存
    @Override
    public void save(Settings settings) {
        settingsMapper.insert(settings);
    }

    // 更新
    @Override
    public void update(Settings settings) {
        settingsMapper.updateById(settings);
    }
}

⑷. 测试

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第14张图片
Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第15张图片


4. 查询黑名单

⑴. 页面展示

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第16张图片

⑵. 接口文档

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第17张图片

⑶. 编码实现

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第18张图片

①. vo对象

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {

    private Long counts = 0l;//总记录数
    private Integer pagesize;//页大小
    private Long pages = 0l;//总页数
    private Integer page;//当前页码
    private List<?> items = Collections.emptyList(); //列表

    public PageResult(Integer page,Integer pagesize,
                      Long 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

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

@RestController
@RequestMapping("/users")
public class SettingsController {

    @Autowired
    private SettingsService settingsService;

    /**
     * 查询通用设置
     */
    @GetMapping("/settings")
    public ResponseEntity settings() {
        SettingsVo vo = settingsService.settings();
        return ResponseEntity.ok(vo);
    }

    /**
     * 设置陌生人问题
     */
    @PostMapping("/questions")
    public ResponseEntity questions(@RequestBody Map map) {
        String content = (String) map.get("content");
        settingsService.saveQuestions(content);
        return ResponseEntity.ok(null);
    }

    /**
     * 通知设置
     */
    @PostMapping("notifications/setting")
    public ResponseEntity notifications(@RequestBody Map map) {
        // 获取参数
        settingsService.saveSettings(map);
        return ResponseEntity.ok(null);
    }

    /**
     * 分页查询黑名单
     */
    @GetMapping("blacklist")
    public ResponseEntity blacklist(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {

        // 1. 调用Service查询
        PageResult pr = settingsService.blacklist(page, size);

        // 2. 构造返回结果
        return ResponseEntity.ok(pr);
    }
}

③. 业务逻辑层Service

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

@Service
public class SettingsService {

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private SettingsApi settingsApi;

    @DubboReference
    private BlackListApi blackListApi;

    // 查询用户通用设置
    public SettingsVo settings() {
        SettingsVo vo = new SettingsVo();

        // 1. 查询用户id
        Long userId = UserHolder.getUserId();
        vo.setId(userId);

        // 2. 查询用户手机号
        vo.setPhone(UserHolder.getMobile());

        // 3. 查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);
        // 设置默认问题
        String txt = question == null ? "你喜欢Java吗?" : question.getTxt();
        vo.setStrangerQuestion(txt);

        // 4. APP通知开关数据
        Settings settings = settingsApi.findByUserId(userId);
        if(settings != null) {
            vo.setGonggaoNotification(settings.getGonggaoNotification());
            vo.setLikeNotification(settings.getLikeNotification());
            vo.setPinglunNotification(settings.getPinglunNotification());
        }

        return vo;
    }

    // 设置陌生人问题
    public void saveQuestions(String content) {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);

        // 3. 判断问题是否存在
        if(question == null) {
            // 3.1 如果不存在,保存
            question = new Question();
            question.setUserId(userId);
            question.setTxt(content);
            questionApi.save(question);

        } else {
            // 3.2 如果存在,更新
            question.setTxt(content);
            questionApi.update(question);
        }
    }

    // 通知设置
    public void saveSettings(Map map) {
        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. 调用api查询用户通知设置
        Settings settings = settingsApi.findByUserId(userId);

        // 3. 判断通知设置是否存在
        if(settings == null) {
            // 4.1 如果不存在,保存
            settings = new Settings();
            settings.setUserId(userId);
            settings.setLikeNotification(likeNotification);
            settings.setGonggaoNotification(gonggaoNotification);
            settings.setPinglunNotification(pinglunNotification);
            settingsApi.save(settings);

        } else {
            // 4.2 如果存在,更新
            settings.setLikeNotification(likeNotification);
            settings.setGonggaoNotification(gonggaoNotification);
            settings.setPinglunNotification(pinglunNotification);
            settingsApi.update(settings);
        }
    }

    // 分页查询黑名单
    public PageResult blacklist(int page, int size) {
        // 1. 获取当前用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用API查询用户黑名单分页列表  IPage对象
        IPage<UserInfo> iPage = blackListApi.findByUserId(userId, page, size);

        // 3. 对象转化,将查询的IPage对象的内容封装到PageResult中
        PageResult pr = new PageResult(page, size, iPage.getTotal(), iPage.getRecords());

        // 4. 返回
        return pr;
    }
}

④. API接口

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

public interface BlackListApi {
    // 分页查询黑名单列表
    IPage<UserInfo> findByUserId(Long userId, int page, int size);
}

⑤. Mapper接口

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/mappers/BlackListMapper.java 文件:

public interface BlackListMapper extends BaseMapper<BlackList> {
}

⑥. API实现类

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

@DubboService
public class BlackListApiImpl implements BlackListApi {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public IPage<UserInfo> findByUserId(Long userId, int page, int size) {
        // 1. 构建分页参数对象Page
        Page pages = new Page(page, size);

        // 2. 调用方法分页(自定义编写 分页参数Page sql条件参数)
        return userInfoMapper.findBlackList(pages, userId);
    }
}

⑦. 分页插件支持

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/DubboDBApplication.java Dubbo启动类:

@SpringBootApplication
@MapperScan("com.tanhua.dubbo.mappers")
public class DubboDBApplication {
    public static void main(String[] args) {
        SpringApplication.run(DubboDBApplication.class, args);
    }

    // 开启 myBatis-Plus分页插件支持
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

⑷. 测试类

新建 tanhua-app-server/src/test/java/com/tanhua/test/BlackListApiTest.java 测试类:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class BlackListApiTest {

    @DubboReference
    private BlackListApi blackListApi;

    @Test
    public void testFindByMobile() {
        IPage<UserInfo> page = blackListApi.findByUserId(106l, 1, 2);
        for (UserInfo record :page.getRecords()) {
            System.out.println(record);
        }
    }
}

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第19张图片

⑸. 黑名单测试

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第20张图片


5. 移出黑名单

⑴. 接口文档

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第21张图片

⑵. 控制层Controller

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

@RestController
@RequestMapping("/users")
public class SettingsController {

    @Autowired
    private SettingsService settingsService;

    /**
     * 查询通用设置
     */
    @GetMapping("/settings")
    public ResponseEntity settings() {
        SettingsVo vo = settingsService.settings();
        return ResponseEntity.ok(vo);
    }

    /**
     * 设置陌生人问题
     */
    @PostMapping("/questions")
    public ResponseEntity questions(@RequestBody Map map) {
        String content = (String) map.get("content");
        settingsService.saveQuestions(content);
        return ResponseEntity.ok(null);
    }

    /**
     * 通知设置
     */
    @PostMapping("notifications/setting")
    public ResponseEntity notifications(@RequestBody Map map) {
        // 获取参数
        settingsService.saveSettings(map);
        return ResponseEntity.ok(null);
    }

    /**
     * 分页查询黑名单
     */
    @GetMapping("blacklist")
    public ResponseEntity blacklist(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {

        // 1. 调用Service查询
        PageResult pr = settingsService.blacklist(page, size);

        // 2. 构造返回结果
        return ResponseEntity.ok(pr);
    }

    /**
     * 取消黑名单
     */
    @DeleteMapping("/blacklist/{uid}")
    public ResponseEntity deleteBlackList(@PathVariable("uid") Long blackUserId) {
        settingsService.deleteBlackList(blackUserId);
        return ResponseEntity.ok(null);
    }
}

⑶. 业务层Service

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

@Service
public class SettingsService {

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private SettingsApi settingsApi;

    @DubboReference
    private BlackListApi blackListApi;

    // 查询用户通用设置
    public SettingsVo settings() {
        SettingsVo vo = new SettingsVo();

        // 1. 查询用户id
        Long userId = UserHolder.getUserId();
        vo.setId(userId);

        // 2. 查询用户手机号
        vo.setPhone(UserHolder.getMobile());

        // 3. 查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);
        // 设置默认问题
        String txt = question == null ? "你喜欢Java吗?" : question.getTxt();
        vo.setStrangerQuestion(txt);

        // 4. APP通知开关数据
        Settings settings = settingsApi.findByUserId(userId);
        if(settings != null) {
            vo.setGonggaoNotification(settings.getGonggaoNotification());
            vo.setLikeNotification(settings.getLikeNotification());
            vo.setPinglunNotification(settings.getPinglunNotification());
        }

        return vo;
    }

    // 设置陌生人问题
    public void saveQuestions(String content) {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api查询用户陌生人问题
        Question question = questionApi.findByUserId(userId);

        // 3. 判断问题是否存在
        if(question == null) {
            // 3.1 如果不存在,保存
            question = new Question();
            question.setUserId(userId);
            question.setTxt(content);
            questionApi.save(question);

        } else {
            // 3.2 如果存在,更新
            question.setTxt(content);
            questionApi.update(question);
        }
    }

    // 通知设置
    public void saveSettings(Map map) {
        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. 调用api查询用户通知设置
        Settings settings = settingsApi.findByUserId(userId);

        // 3. 判断通知设置是否存在
        if(settings == null) {
            // 4.1 如果不存在,保存
            settings = new Settings();
            settings.setUserId(userId);
            settings.setLikeNotification(likeNotification);
            settings.setGonggaoNotification(gonggaoNotification);
            settings.setPinglunNotification(pinglunNotification);
            settingsApi.save(settings);

        } else {
            // 4.2 如果存在,更新
            settings.setLikeNotification(likeNotification);
            settings.setGonggaoNotification(gonggaoNotification);
            settings.setPinglunNotification(pinglunNotification);
            settingsApi.update(settings);
        }
    }

    // 分页查询黑名单
    public PageResult blacklist(int page, int size) {
        // 1. 获取当前用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用API查询用户黑名单分页列表  IPage对象
        IPage<UserInfo> iPage = blackListApi.findByUserId(userId, page, size);

        // 3. 对象转化,将查询的IPage对象的内容封装到PageResult中
        PageResult pr = new PageResult(page, size, iPage.getTotal(), iPage.getRecords());

        // 4. 返回
        return pr;
    }

    // 取消黑名单
    public void deleteBlackList(Long blackUserId) {
        // 1. 获取当前用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api删除
        blackListApi.delete(userId, blackUserId);
    }
}

⑷. Api接口

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

public interface BlackListApi {
    // 分页查询黑名单列表
    IPage<UserInfo> findByUserId(Long userId, int page, int size);

    // 取消黑名单
    void delete(Long userId, Long blackUserId);
}

⑸. Api实现类

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

@DubboService
public class BlackListApiImpl implements BlackListApi {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private BlackListMapper blackListMapper;

    // 查询黑名单分页列表
    @Override
    public IPage<UserInfo> findByUserId(Long userId, int page, int size) {
        // 1. 构建分页参数对象Page
        Page pages = new Page(page, size);

        // 2. 调用方法分页(自定义编写 分页参数Page sql条件参数)
        return userInfoMapper.findBlackList(pages, userId);
    }

    // 取消黑名单
    @Override
    public void delete(Long userId, Long blackUserId) {
        QueryWrapper<BlackList> qw = new QueryWrapper<>();
        qw.eq("user_id", userId);
        qw.eq("black_user_id", blackUserId);
        blackListMapper.delete(qw);
    }
}

⑹. 测试

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第22张图片
Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第23张图片



二、MongoDB入门

1. 数据库分析

对于社交类软件的功能,它具有以下特点:

  • 数据量会随着用户数增大而增大
  • 读多写少
  • 价值较低
  • 非好友看不到其动态内容
  • 地理位置的查询
  • ……

针对以上特点,结合MySQL、Redis来分析一下:

  • mysql: 关系型数据库(效率低)
  • redis: redis缓存(微博,效率高,数据格式不丰富)
  • MongoDB:
    • 对于数据量大而言,显然不能够使用关系型数据库进行存储
    • 对于读多写少的应用,需要减少读取的成本

探花交友项目的数据库使用:

  • mongodb: 存储业务数据(圈子,推荐的数据,小视频数据,点赞,评论等)
  • redis: 承担的角色是缓存层(提升查询效率)
  • mysql: 存储和核心业务数据,账户

2. MongoDB简介

MongoDB官网:https://www.mongodb.com

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第24张图片

  • MongoDB是一个高效的非关系型数据库(不支持表关系:只能操作单表)
  • MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
  • MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
  • MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

数据存储:
Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第25张图片

MongoDB与Redis和Mysql的对比:

  • 与Redis的对比:
    • Redis纯内存数据库,内存不足触发淘汰策略
    • 结构化存储格式(Bson),方便扩展
  • 与MySQL的对比:
    • MongoDB不支持事务和多表操作
    • MongoDB支持动态字段管理
  • 查询效率对比:
    • Redis > MongoDB > MySQL

Mongodb的适用场景:

  • 游戏装备数据、游戏道具数据:
    • 特征:修改频度较高
  • 物流行业数据:
    • 特征:地理位置信息,海量数据
  • 直播数据、打赏数据、粉丝数据:
    • 特征:数据量大,修改频度极高
  • 日志数据:
    • 特征:数据量巨大,结构多变

3. 体系结构与术语

为了更好的理解,下面与SQL中的概念进行对比:

SQL术语/概念 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 表中的一条数据
column field 数据字段/域
index index 索引
table joins 表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第26张图片

MongoDB中使用Bson存储数据( Binary JSON ),一种类似Json的数据格式。

MongoDB 的逻辑结构是一种层次结构。主要由: 文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面 向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。

  1. MongoDB 的文档(document),相当于关系数据库中的一行记录。
  2. 多个文档组成一个集合(collection),相当于关系数据库的表。
  3. 多个集合(collection),逻辑上组织在一起,就是数据库(database)。
  4. 一个 MongoDB 实例支持多个数据库(database)。 文档(document)、集合(collection)、数据库(database)的层次结构如下图:

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第27张图片


4. MongoDB安装与连接

# 拉取镜像
docker pull mongo

# 创建容器
docker run --name mongo-service -p 27017:27017 -v ~/data/mongodata:/data -d  mongo

在博主的虚拟机中已经提供了MongoDB的镜像和容器,我们只需要使用简单的命令即可启动

# 进入base目录
cd /root/docker-file/base/
# 批量创建启动容器,其中已经包含了redis,zookeeper,mongodb容器
docker-compose up -d
# 查看容器
docker ps -a
# 可以看到mongoDB已经启动,对外暴露了27017的操作端口

使用Navicat15连接 MongoDB:

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

在这里插入图片描述
Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第28张图片


5. 基础命令

⑴. 数据库以及表的操作

#查看所有的数据库
> show dbs

#通过use关键字切换数据库
> use admin

#创建数据库
#说明:在MongoDB中,数据库是自动创建的,通过use切换到新数据库中,进行插入数据即可自动创建数据库
> use testdb

> show dbs #并没有创建数据库

> db.user.insert({id:1,name:'zhangsan'})  #插入数据

> show dbs

#查看表
> show tables

> show collections

#删除集合(表)
> db.user.drop()
true  #如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。

#删除数据库
> use testdb #先切换到要删除的数据中

> db.dropDatabase()  #删除数据库

⑵. 新增数据

在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。

#插入数据
#语法:db.表名.insert(json字符串)

> db.user.insert({id:1,username:'zhangsan',age:20})

> db.user.find()  #查询数据

⑶. 更新数据

update() 方法用于更新已存在的文档。语法格式如下:

db.collection.update(
   <query>,
   <update>,
   [
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   ]
)

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。
  • update : update的对象和一些更新的操作符(如 , , ,inc.$set)等,也可以理解为sql update查询内set后面的
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
  • writeConcern :可选,抛出异常的级别。
#查询全部
> db.user.find()

#更新数据
> 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>
   }
)

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
  • writeConcern :(可选)抛出异常的级别。
#删除数据
> 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])
  • query :可选,使用查询操作符指定查询条件
  • fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。

条件查询:

操作 格式 范例 RDBMS中的类似语句
等于 {:} db.col.find({"by":"黑马程序员"}).pretty() where by = '黑马程序员'
小于 {:{$lt:}} db.col.find({"likes":{$lt:50}}).pretty() where likes < 50
小于或等于 {:{$lte:}} db.col.find({"likes":{$lte:50}}).pretty() where likes <= 50
大于 {:{$gt:}} db.col.find({"likes":{$gt:50}}).pretty() where likes > 50
大于或等于 {:{$gte:}} db.col.find({"likes":{$gte:50}}).pretty() where likes >= 50
不等于 {:{$ne:}} 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为正序

6. 索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构

#创建索引
> db.user.createIndex({'age':1})

#查看索引
> db.user.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "testdb.user"
	}
]
#说明:1表示升序创建索引,-1表示降序创建索引。

执行计划:
MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。

#插入1000条数据
for(var i=1;i<1000;i++)db.user.insert({id:100+i,username:'name_'+i,age:10+i})

#查看执行计划
> db.user.find({age:{$gt:100},id:{$lt:200}}).explain()

#测试没有使用索引
> db.user.find({username:'zhangsan'}).explain()

#winningPlan:最佳执行计划
#"stage" : "FETCH", #查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询

三. SpringBoot整合MongoDB

1. 创建工程, 导入依赖

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第29张图片
编辑 pom.xml 文件:

...

    <!--导入MongoDB依赖-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

2. 添加 MongoDB 的配置信息

新建 application.yml 文件:

# 配置MongoDB连接地址
spring:
  data:
    mongodb:
      uri: mongodb://192.168.136.160:27017/testdb

3. 编写启动/引导类

新建 com/tanhua/mongo/MonGoApplication.java 文件:

@SpringBootApplication
public class MonGoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplication.class, args);
    }
}

4. 编写实体类, 并通过注解配置映射

新建 com/tanhua/mongo/domain/Person.java 文件:

// 指定实体类和MongoDB的映射关系
@Document("tb_person") // 如果为空默认monGoDB同名集合
@Data
public class Person {

    @Id
    private ObjectId id; // MongoDB推荐用法

    @Field("myname") // 如果不写,默认属性名为字段名
    private String name;

    private Integer age;

    private String address;
}

5. 编写测试类,进行数据操作

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第30张图片

新建 com/tanhua/mongo/test/MongoTest.java 文件:

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

    // 1. 注入MongoTemplate对象
    @Autowired
    private MongoTemplate mongoTemplate;

    // 2. 调用其方法完成数据的CRUD

    // 3.1 保存
    @Test
    public void testSave() {
        Person person = new Person();
        person.setName("zoe");
        person.setAge(18);
        person.setAddress("北京海淀区");
        mongoTemplate.save(person);
    }

    // 3.2 插入测试数据
    @Test
    public void testInsert() {
        for (int i = 0; i < 10; i++) {
            Person person = new Person();
            person.setName("zoe" + i);
            person.setAge(18 + i);
            person.setAddress("北京海淀区" + i);
            mongoTemplate.save(person);
        }
    }

    // 3.3 查询所有
    @Test
    public void testFIndAll() {
        List<Person> list = mongoTemplate.findAll(Person.class);
        for (Person person : list) {
            System.out.println(person);
        }
    }

    // 3.4 条件查询
    @Test
    public void testFind() {
        // 1. 创建Criteria对象,并设置查询条件
        Criteria criteria = Criteria.where("myname").is("zoe"); // is 相当于 SQL中的 =

        // 2. 根据Critical创建Query对象
        Query query = Query.query(criteria);

        // 3. 查询
        List<Person> list = mongoTemplate.find(query, Person.class);// Query对象, 实体类对象
        for (Person person : list) {
            System.out.println(person);
        }
    }

    // 3.5 多个条件查询
    @Test
    public void testFind2() {
        // 1. 创建Criteria对象,并设置查询条件
        Criteria criteria = Criteria.where("myname").is("zoe")
                .and("age").is(18);

        // 2. 根据Critical创建Query对象
        Query query = Query.query(criteria);

        // 3. 查询
        List<Person> list = mongoTemplate.find(query, Person.class);// Query对象, 实体类对象
        for (Person person : list) {
            System.out.println(person);
        }
    }

    // 分页查询
    @Test
    public void testFindPage() {
        int page = 1;
        int size = 2;

        // 1. 创建Criteria对象,并设置查询条件
        Criteria criteria = Criteria.where("age").lt(50); // 年龄小于50

        // 2. 根据Critical创建Query对象
        Query query = Query.query(criteria)
                .skip((page - 1) * size) // 查询页数
                .limit(size) // 每页条数
                .with(Sort.by(Sort.Order.desc("age"))); // 排序,按年龄降序排列

        // 3. 查询
        List<Person> list = mongoTemplate.find(query, Person.class);// Query对象, 实体类对象
        for (Person person : list) {
            System.out.println(person);
        }
    }

    // 更新
    @Test
    public void testUpdate() {
        // 1. 构建query对象
        Query query = Query.query(Criteria.where("id").is("63428ba254fedd7eb5a9b066"));

        // 2. 设置需要更新的数据内容
        Update update = new Update();
        update.set("age", 10);
        update.set("myname", "tom");

        // 3. 调用方法
        mongoTemplate.updateFirst(query, update, Person.class);
    }

    // 删除
    @Test
    public void testDelete() {
        // 1. 构建query对象
        Query query = Query.query(Criteria.where("id").is("63428ba254fedd7eb5a9b066"));

        // 2. 调用方法
        mongoTemplate.remove(query, Person.class);
    }
}


四、今日佳人

1.页面展示

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第31张图片


2.搭建服务提供者

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第32张图片

⑴. 配置工程环境

新建 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/DubboMongoApplication.java 启动类:

@SpringBootApplication
public class DubboMongoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DubboMongoApplication.class,args);
    }
}

新建 tanhua-dubbo/tanhua-dubbo-mongo/src/main/resources/application.yml yml文件:

server:
  port: 18082
spring:
  application:
    name: tanhua-dubbo-mongo
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.136.160:8848
  data:
    mongodb:
      uri: mongodb://192.168.136.160:27017/tanhua
dubbo:
  protocol:
    name: dubbo
    port: 20882
  registry:
    address: spring-cloud://localhost
  scan:
    base-packages: com.tanhua.dubbo.api  #dubbo中包扫描

⑵. 实体类

新建 tanhua-model/src/main/java/com/tanhua/model/mongo/RecommendUser.java 文件:

@AllArgsConstructor
@NoArgsConstructor
@Data
@Document(collection = "recommend_user")
public class RecommendUser implements java.io.Serializable {
    private ObjectId id; //主键id
    private Long userId; //推荐的用户id
    private Long toUserId; //用户id
    private Double score =0d; //推荐得分
    private String date; //日期
}

⑶. API接口

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

public interface RecommendUserApi {

    // 查询今日佳人
    RecommendUser queryWithMaxScore(Long toUserId);
}

⑶. API实现类

新建 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);
    }
}

3. 测试类

新建 tanhua-app-server/src/test/java/com/tanhua/test/RecommendUserApiTest.java 文件:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class RecommendUserApiTest {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @Test
    public void testFindByMobile() {
        RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(106L);
        System.out.println(recommendUser);
    }
}

查看打印结果,返回的用户(今日佳人)数据


4.接口文档

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第33张图片


5.控制层

新建 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);
    }
}

6.服务层

新建 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;
    }
}

7.vo对象

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

/**
 * 今日佳人
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TodayBest {

    private Long id; //用户id
    private String avatar;
    private String nickname;
    private String gender; //性别 man woman
    private Integer age;
    private String[] tags;
    private Long fateValue; //缘分值

    /**
     * 在vo对象中,补充一个工具方法,封装转化过程
     */
    public static TodayBest init(UserInfo userInfo, RecommendUser recommendUser) {
        TodayBest vo = new TodayBest();
        BeanUtils.copyProperties(userInfo,vo);
        if(userInfo.getTags() != null) {
            vo.setTags(userInfo.getTags().split(","));
        }
        vo.setFateValue(recommendUser.getScore().longValue());
        return vo;
    }
}

8.解决MongoDB启动bug

在项目中,添加了mongo的依赖,springboot就会自动去连接本地的mongo,由于连接不上会导致出错。

解决有2种方案:

  • 排除掉mongo的依赖
  • springboot中添加排除自动配置的注解

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

//启动类
// @SpringBootApplication
@SpringBootApplication(exclude = {
        MongoAutoConfiguration.class,
        MongoDataAutoConfiguration.class
}) //排除mongo的自动配置
public class AppServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppServerApplication.class,args);
    }
}

9.Postman测试

Dobbo微服务项目实战(详细介绍+案例源码) - 4.MongoDB_第34张图片


你可能感兴趣的:(Java,mongodb,微服务,数据库)