前言
代理服务和用户服务搭建完毕后,我们继续搭建剩下的服务:笔记服务和日志服务。
笔记服务 Note
笔记服务负责与笔记本相关的所有业务逻辑处理,也就是本项目中的主要业务功能,在代码上基本不需要做修改,只用配置好 Consul 即可。
代码结构
- controller
- ErrorController.java:全局异常处理
- NoteController.java:笔记接口
- NotesController.java:笔记本接口
- entity
- NoteInfo.java:笔记实体类
- NotesInfo.java:笔记本实体类
- mapper
- NoteMapper.java:笔记持久类
- NotesMapper.java:笔记本持久类
- service
- NoteService.java:笔记业务逻辑类
- NotesService.java:笔记本业务逻辑类
- NoterApplicatiion.java:服务启动类
获取笔记本列表
代码逻辑中唯一需要修改的地方是获取笔记本列表。原来的逻辑是在用户注册成功后,自动创建默认笔记本。当业务分离后,用户注册和创建笔记本是两个互不相干的业务,因此将创建默认笔记本的逻辑放在获取笔记本列表中。当发现用户没有笔记本时,创建一个默认笔记本并返回,这也就进一步做到了业务的解耦,代码如下:
/**
* 获取用户的笔记本列表,如果用户没有笔记本,创建默认笔记本
* @param userId
* @return
*/
public ResultData getListByUser(int userId){
NotesInfo notesInfo = new NotesInfo();
notesInfo.setUserId(userId);
notesInfo.setBaseKyleUseASC(true);
List<NotesInfo> list = mapper.baseSelectList(notesInfo);
if(list == null || list.size() < 1){
notesInfo = insertDefaultNotes(userId);
list.add(notesInfo);
}
return ResultData.success(list);
}
日志服务 Log
日志服务作为独立的一个组件,只负责所有日志的读写操作。通过接收 RabbitMQ 传递过来的数据进行写操作、通过 RESTFul 接口提供读服务。
将原项目中日志相关的操作移过来,没有太大的变化。
代码结构
- controller
- AdminController.java:管理员访问的接口
- EmailLogController.java:邮件发送日志相关
- ErrorController.java:全局异常处理
- handler
- RabbitHandler.java:RabbitMQ 消息处理类
- mapper
- EmailLogMapper.java:邮件发送日志持久类
- ErrorLogMapper.java:错误日志持久类
- LoginLogMapper.java:用户登录日志持久类
- RegisterLogMapper.java:用户注册日志持久类
- service
- EmailLogService.java:邮件发送日志业务逻辑类
- LoginLogService.java: 用户登录日志业务逻辑类
- RegisterLogService.java:用户注册日志业务逻辑类
- LogApplication.java:服务启动类
处理 RabbitMQ 消息
接收 RabbitMQ 传递的消息,通过 JSON 反序列化成实体对象,并记录在数据库中:
@Component
public class RabbitHandler {
@Resource
private EmailLogMapper emailLogMapper;
// 记录邮件发送日志
@RabbitListener(queues = MqConstants.EMAIL_LOG)
public void emailLog(String content){
Console.info("emailLog",content);
EmailLog log = JSON.parseObject(content,EmailLog.class);
emailLogMapper.baseInsertAndReturnKey(log);
}
@Resource
private ErrorLogMapper errorLogMapper;
// 记录异常日志
@RabbitListener(queues = MqConstants.ERROR_LOG)
public void errorLog(String content){
Console.info("errorLog",content);
ErrorLog log = JSON.parseObject(content,ErrorLog.class);
errorLogMapper.baseInsertAndReturnKey(log);
}
@Resource
private LoginLogMapper loginLogMapper;
// 记录用户登录日志
@RabbitListener(queues = MqConstants.LOGON_LOG)
public void loginLog(String content){
Console.info("loginLog",content);
LoginLog log = JSON.parseObject(content,LoginLog.class);
loginLogMapper.baseInsertAndReturnKey(log);
}
@Resource
private RegisterLogMapper registerLogMapper;
// 记录用户注册日志
@RabbitListener(queues = MqConstants.REGISTER_LOG)
public void registerLog(String content){
Console.info("registerLog",content);
RegisterLog log = JSON.parseObject(content,RegisterLog.class);
registerLogMapper.baseInsertAndReturnKey(log);
}
}
管理员接口
AdminController.java 中是原项目中管理员查看日志相关的操作:
@RestController
@RequestMapping(Constants.adminMapping)
public class AdminController {
@Resource
private LoginLogService loginLogService;
@Resource
private RegisterLogService registerLogService;
@GetMapping("/loginLogByDay")
public ResponseEntity getLoginLogByDay(String startDate, String endDate){
if(ObjectUtils.isEmpty(startDate)){
return Response.badRequest();
}
return Response.ok(loginLogService.getCountByDay(startDate,endDate));
}
@GetMapping("/loginLogByMonth")
public ResponseEntity getLoginLogByMonth(String startDate,String endDate){
if(ObjectUtils.isEmpty(startDate)){
return Response.badRequest();
}
return Response.ok(loginLogService.getCountByMonth(startDate,endDate));
}
@GetMapping("/registerLogByDay")
public ResponseEntity getRegisterLogByDay(String startDate, String endDate){
if(ObjectUtils.isEmpty(startDate)){
return Response.badRequest();
}
return Response.ok(registerLogService.getCountByDay(startDate,endDate));
}
@GetMapping("/registerLogByMonth")
public ResponseEntity getRegisterLogByMonth(String startDate,String endDate){
if(ObjectUtils.isEmpty(startDate)){
return Response.badRequest();
}
return Response.ok(registerLogService.getCountByMonth(startDate,endDate));
}
}
邮件发送记录查询
@RestController
@RequestMapping("/emailLog")
public class EmailLogController {
@Resource
private EmailLogService service;
@GetMapping
public ResponseEntity checkCode(String email,String code,Integer type){
if(ObjectUtils.isEmpty(email,code,type)){
return Response.badRequest();
}
return Response.ok(service.checkCode(email, code, type));
}
}
至此,所有服务搭建完毕。
效果测试
注意在配置文件中为不同的服务设置不同的启动端口,所有服务启动完毕后,在 Consul 中能看到如下的记录:
注意:
- 从单体服务到分布式服务,对于客户端来说是无感知的,在客户端只需要配置代理服务的访问地址即可
- 但由于请求的方式发生变化,需要在访问接口中添加 service Header 并指定相应的服务名称,也就是修改 Vue 项目中的 api.js 中各个接口
源码地址
本篇完整的源码地址:
小结
至此,项目的分布式部署完成。如果需要使用缓存,添加对 Redis 的支持即可。这里推荐一个 Redis 的可视化工具,支持 Windows 和 MacOS。
地址:
界面如下: