SpringCloud 微服务拆分小Demo(上)

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

前言

由于时间关系,这次期末作孽只能做一个非常简单的玩意,由于期末作业可以在阶段作品的基础上进行优化,于是我有个大胆的想法,为什么我不阔以直接把SpringBoot 构建的单体项目拆分为微服务架构,这个也是一个升级嘛,顺便复习一下微服务。

本次微服务拆分的案例是:嘿从零开始基于SpringBoot 打造在线聊天室(4.4W字最长博文)

(PS:主要是为了对付期末作业,如果没事的话,别这样乱拆)

这个是基于vue + springBoot 整合mybatis websocket 做的在线聊天室(这里直接使用Map来代替redis,所以直需要mysql做存储)

由于我们只是对后端进行技术升级,所以,我们前端基本上不用动,甚至连接口都不用换。这充分体现了前后端分离的第一个好处呀。那第二个好处咧?当然是基于vue更加方便去嫖组件呀!

所以页面还是这个样子: 在这里插入图片描述 这个样子 在这里插入图片描述 and this: 在这里插入图片描述

项目创建

废话不多说,我们重新创建我们的项目。这部分内容可以参考这两篇博客,我这里就不复述了。

SpringCloud微服务项目搭建流程

SpringCloud基本微服务构建(Eureka+GateWay)

我们这里先创建出四个module, 分别是登录,注册,Eureka,GateWay。

在这里插入图片描述

这里呢,我把登录和注册拆分为两个模块了,也就是这样。

在这里插入图片描述

之所以这样拆呢其实也很简单,如果后面有微信登录,注册,qq邮箱等等第三方验证登录的时候,业务肯定很复杂,所以这两个模块还是需要拆分的。

但是在这里的话,又有个问题,因为登录和注册在很多方面又是相互耦合的,例如User。你登录的时候需要User实体,同样注册也需要呀,如果拆分,那么可能就需要每一个模块都需要User,例如在这里: 在这里插入图片描述

那么这里的话如果不优化,那么就会出现代码重复。

那么如何优化呢,其实也很简单,我们单独把User服务再拆分出来,也就是这样:

在这里插入图片描述

不过,这里为了省事,我就不拆了,毕竟这玩意我就是闹着玩,没办法交个期末作业,而且我这样做压根就不算优化。

登录/注册拆分

这里忘了说了,我这里拆的话还是每一个服务在共用同一个数据库,懒得再拆表了。

注册模块

注册模块的话比较好拆分 因为用到的东西很少。

在这里插入图片描述

就是做一个简单的插入

Controller代码


@Controller
@ResponseBody
public class Register {

    @Autowired
    RegisterMessage registerMessage;
    @Autowired
    UserService userService;

    @PostMapping("/register")
    public RegisterMessage Register(@RequestBody Map<String, Object> userMap) throws Exception {
        String account = (String) userMap.get("account");
        String username = (String)userMap.get("username");
        String password = (String) userMap.get("password");
        if(account!=null && password!=null){
            userService.addUser(account,username,password);
            registerMessage.setFlag(1);
        }else {
            registerMessage.setFlag(-1);
        }
        return registerMessage;
    }
}

复制代码

Server代码

@Service
public class UserService {

    @Autowired
    UserMapper userMapper;
    public User selectUserById(Integer id){return userMapper.selectUserById(id);}
    public User selectUserByAccount(String account){
        return userMapper.selectUserByAccount(account);
    }
    public User selectUserByAccountAndPassword(String account,String password){
        return userMapper.selectUserByAccountAndPassword(account,password);
    }
    @Transactional(rollbackFor = Exception.class)
    public int addUser(String account,String username,String password) throws Exception {
//        发生异常回滚
        int flag = 1;

        try {
            userMapper.AddUser(account, username, password);
        }catch (Exception e){
            flag = -1;
            throw new Exception("用户添加异常");
        }
        return flag;
    }
}

复制代码

就这两个核心的。

登录模块

这个登录模块就稍微复杂了一点,因为还有个token生成,并且登录后进入聊天室也是在这里做的,所以,功能复杂一点。 在这里插入图片描述

对比原来的项目,就少了个聊天模块 在这里插入图片描述

然后这里保留的话,也是保留了比较多的东西的

拦截器保留

在这里插入图片描述

持久层保留

这部分的话也是,其实就是保留User和Friend,看过原来的单体项目的应该知道,这个friend其实室没事用的,本来要做的,但是没去做,以后再说吧。

在这里插入图片描述

服务层

之后的话,服务层和注册的不太一样,不过也是原来单体架构里面的服务层一样的


@Service
public class UserService {

    @Autowired
    UserMapper userMapper;
    public User selectUserById(Integer id){return userMapper.selectUserById(id);}
    public User selectUserByAccount(String account){
        return userMapper.selectUserByAccount(account);
    }
    public User selectUserByAccountAndPassword(String account,String password){
        return userMapper.selectUserByAccountAndPassword(account,password);
    }
    @Transactional(rollbackFor = Exception.class)
    public int addUser(String account,String username,String password) throws Exception {
//        发生异常回滚
        int flag = 1;

        try {
            userMapper.AddUser(account, username, password);
        }catch (Exception e){
            flag = -1;
            throw new Exception("用户添加异常");
        }
        return flag;
    }
}

复制代码

至于工具类,这个就保留了两个 在这里插入图片描述

网关GateWay配置

做完这些之后的话,还需要再配置一下网关,主要是为了做跨域。 两个方案。

一个是配置文件: 在这里插入图片描述


      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期
复制代码

还有一个,自然就是配置类

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");//允许所有请求头
        config.addAllowedOrigin("*");//允许所有请求方法,例如get,post等
        config.addAllowedHeader("*");//允许所有的请求来源
        config.setMaxAge(360000L);
        config.setAllowCredentials(true);//允许携带cookie

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);//对所有经过网关的请求都生效

        return new CorsWebFilter(source);
    }
}

复制代码

前端设置

这里做了之后我们前端还要再设置一下,让请求走网关。

我的网关的完整配置如下:

server:
  port: 8000


spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true

      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

      routes:
        - id: loginclient
          uri: lb://loginclient
          predicates:
            - Path=/loginClient/**
          filters:
            - StripPrefix=1

        - id: registerclient
          uri: lb://registerclient
          predicates:
            - Path=/registerClient/**
          filters:
            - StripPrefix=1




eureka:
  client:
    service-url:  # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

复制代码

然后再我的前端的话也是原来做了跨域处理的,但是GateWay的话需要重新设置一下,主要是让GateWay通过一下Axios请求 在这里插入图片描述

然后在我的登录,注册模块就是这样的: 在这里插入图片描述

在这里插入图片描述

到这里的话我们的登录注册功能其实就改造完成了。接下来是聊天改造。

聊天拆分

这部分也是分两个部分,一个是聊天的信息加载,还有一个是,websocket 网络聊天。

聊天拆分的话,这里我们将引入RabbitMQ,用来做聊天信息的持久化,原来是,你发了我就存,这样做可以,但是qps多了就炸了,所以引入消息队列。当然这里的话我们还是使用mysql来做存储,实际上我们应该使用mangodb的,但是作业要求是mysql,而且mysql也可以勉强完成工作,大不了SpringBoot 那里再开启缓存嘛,降低一下查询压力(只要没有发送新消息) 而且这里还能再拆分,那就是在线聊天人员统计,管理这一块,不过不能再搞了,因为容易被锤~

当然最重要的原因是:

在这里插入图片描述

一个SpringBoot 起来就烧掉我起码100MB 的内存。技术除了牛逼之外,我觉得省钱也是很重要的。 (这也是为什么要搞个好点的电脑搞开发,不然你连idea可能都养不起)

ok,天也不早了,这个咱们下回分解。(端午都不去玩,我还是人嘛!!!)

猜你喜欢

转载自juejin.im/post/7105026213218877470