Day 2 正式coding之基础模块的搭建

Day 2 正式coding之基础模块的搭建

这里会总结构建项目过程中遇到的问题,以及一些个人思考!!

学习方法:

1 github源码 + 文档 + 官网

2 内容复现 ,实际操作

项目源码同步更新到github 欢迎大家star~ 后期会更新并上传前端项目

创建父工程

新建一个jdk17的maven工程,并删掉src目录

image-20240413181927881

导入依赖文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <groupId>com.bootscoder</groupId>
    <artifactId>shopping</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!-- 为表示其为父工程,设置打包方式-->
    <packaging>pom</packaging>


    <!-- 子模块 -->
    <modules>

    </modules>


    <properties>
        <java.version>17</java.version>
        <dubbo.version>3.2.4</dubbo.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.0.2</spring-boot.version>
        <spring-cloud.version>2022.0.0</spring-cloud.version>
        <spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
        <lombok.version>1.18.28</lombok.version>
        <mybatis-plus.version>3.5.4</mybatis-plus.version>
    </properties>


    <!-- 依赖版本声明 -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring Cloud版本-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


            <!-- Spring Cloud Alibaba版本 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


            <!-- SpringBoot版本 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


            <!-- Dubbo版本 -->
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-bom</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


            <!-- lombok版本 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>


            <!-- mybatis-plus版本 -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <!-- 通用依赖 -->
    <dependencies>
        <!-- bootstrap启动器 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    </dependencies>


    <!-- 插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>


    <!-- 依赖仓库路径 -->
    <repositories>
        <repository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>https://maven.aliyun.com/repository/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
    </repositories>


    <!-- 插件仓库路径 -->
    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>https://maven.aliyun.com/repository/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

创建通用模块

使用Nacos时,我们需要使用Dubbo进行服务调用,此时我们需要构建一个通用模块,在通用模块中存放服务接口。除了服务接口,我们还会存放一些实体类、工具类等通用功能,每个模块都会引用通用模块。

Dubbo进行服务调用 有两个身份: 生产者和消费者

通用模块的依赖注入

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
  </dependency>
  <!-- lombok -->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
  <!-- MyBatisPlus -->
  <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
  </dependency>
  <!-- elasticsearch -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

配置父模块

<parent>
        <groupId>com.bootscoder</groupId>
        <artifactId>shopping</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
</parent>

配置子模块

<!-- 子模块  -->
<modules>
  <!-- 通用模块,包含实体类、服务接口、工具类等 -->
  <module>shopping_common</module>
</modules>

流程总结

  1. pom文件改写
  2. 创建pojo文件夹,编写实体类。
  3. 由于通用模块只会被其他模块引用,而不会启动,所以可以删除启动类。
  4. 创建名为shopping的数据库,将数据库脚本导入mysql中。
  5. 在通用模块添加service包存放服务接口,添加utils包存放工具类。

创建商品服务模块

<dependencies>
  <!-- MyBatisPlus -->
  <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
  </dependency>
  <!-- mysql驱动 -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>com.bootscoder</groupId>
    <artifactId>shopping_common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <!-- dubbo -->
  <dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
  </dependency>
  <dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-nacos</artifactId>
  </dependency>
  <!-- nacos -->
  <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  </dependency>
  <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  </dependency>
</dependencies>

# 端口号
server:
  port: 9001


# 日志格式
logging:
  pattern:
   console: '%d{HH:mm:ss.SSS} %clr(%-5level) ---  [%-15thread] %cyan(%-50logger{50}):%msg%n'


spring:
  application:
   name: shopping_goods_service #服务名
  cloud:
   nacos:
    discovery:
     server-addr: 192.168.66.100:8848 # 注册中心地址
 # 数据源
  datasource:
   driver-class-name: com.mysql.cj.jdbc.Driver
   url: jdbc:mysql:///shopping?serverTimezone=UTC
   username: 你的name
   password: 你的密码


dubbo:
  application:
   name: shopping_goods_service #服务名
   serialize-check-status: DISABLE
   check-serializable: false
  protocol:
   name: dubbo # 通讯协议
   port: -1 # 端口号,-1表示自动扫描可用端口。
  registry:
   address: nacos://192.168.66.100:8848 # 注册中心


# 配置Mybatis-plus
mybatis-plus:
  global-config:
   db-config:
   # 表名前缀
    table-prefix: boots_
   # 主键生成策略为自增
    id-type: auto
  configuration:
  # 关闭列名自动驼峰命名映射规则
   map-underscore-to-camel-case: false
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启sql日志

spring:
  profiles:
    active: dev #环境
  cloud:
    nacos:
      config:
        server-addr: 192.168.66.100:8848
        namespace: 44d5da8b-b356-4aa8-b4be-49a54cb8b8ee
        file-extension: yaml
        prefix: shopping_goods_service


  1. 构建springboot
  2. pom文件依赖+父子模块指定
  3. 修改yaml
在nacos 中编写配置文件

将配置文件放到nacos中, 在项目中进行读取

image-20240414172936180

配置文件发布

在本地代码中配置 bootstrap.yml 连接nacos 配置中心

woc 这个idea 版本(2019)已经落后了???

更新后 依然起不来

马勒戈壁 说老子没配置database 傻逼

md 配置中心和本地文件命名指向不匹配,操了

更新idea后成功

image-20240414192903798

编写根据id查询品牌功能(放到goods里面)
  1. 在启动类中添加注解@EnableDiscoveryClient // 向注册中心注册该服务
    @EnableDubbo // 开启Dubbo
    @RefreshScope // 配置动态刷新
  2. 编写服务实现类
    1. 记得加dubbo 的service注解
    2. 加事务注解
  3. 编写mapper
  4. 启动类扫描mapper

image-20240414195432921

nacos 使用

提问-通用模块的细节:

  1. 这里提一个小的问题哈,为什么这里的GoodsService 可以调用common呢?
  2. 做分布式搭建后,是否仍然可以进行调用?

maven依赖引入;

需要整体打包,或者将common注册到maven的中心仓库

做完整体的流程我想模拟一下分布式调用

创建管理员端API模块

这里使用postman进行测试;没有使用过的……那你可能要Google一下了

image-20220725114012728

商城分为管理员端和用户端,用户端是用户访问的,可以查询商品、购买商品;管理员端是商家访问的,可以维护商品。由于管理员端的访问量有限,我们将管理员端的所有控制器都放入管理员端的API模块。

前端项目访问该模块的控制器,控制器返回json数据给前端。管理员端API模块并不能查询数据,它只是服务的消费者,需要连接服务的生产者才能查询到数据。

image-20240416212357763

  1. 创建名为shopping_manager_api的SpringBoot工程,添加相关依赖。

  2. 设置该工程的父工程为shopping

  3. 编写根据id 查询的controller

/**
 * 品牌控制器
 *
 * @author bootsCoder
 * @date created on 2024/4/15
 */
@RestController
@RequestMapping(("/brand"))
public class BrandController {
    @DubboReference
    private BrandService brandService;
    @GetMapping("/findById")
    public Brand findById(Long id){
        return brandService.findById(id);
    }
}

image-20240415181355208

API接口设置统一数据返回格式


/**
 * 全局统一结果配置
 *
 * @author bootsCoder
 * @date created on 2024/4/15
 */
@Data
@AllArgsConstructor
public class BaseResult<T> {
    // 状态码(成功:200 失败:其他)
    private Integer code;
    // 提示消息
    private String message;
    // 返回数据
    private T data;


    // 构建成功结果
    public static <T> BaseResult<T> ok() {
        return new BaseResult(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), null);
    }


    // 构建带有数据的成功结果
    public static <T> BaseResult<T> ok(T data) {
        return new BaseResult(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
    }
}


/**
 * 状态码
 *
 * @author bootsCoder
 * @date created on 2024/4/15
 */
@Getter
@AllArgsConstructor
public enum ResultCode {
    // 正常
    SUCCESS(200, "OK")
    ;

    private final Integer code;
    private final String message;
}
 @GetMapping("/findById")
    public BaseResult<Brand> findById(Long id){
        Brand brand = brandService.findById(id);
        return BaseResult.ok(brand);
    }


image-20240415182915192

统一异常处理

  • 异常信息从服务端传入消费端时,Dubbo会默认封装异常,绕过我们的全局异常处理器,所以在通用模块禁用Dubbo异常封装,

  • 由于新版Dubbo默认关闭对象序列化,使得异常信息不能从服务端传入消费端(会发生什么呢?),所以在通用模块开启Dubbo序列化:

# 禁用Dubbo异常封装,使用自定义异常处理
dubbo.provider.filter=-exception
# 开启Dubbo序列化
dubbo.application.serialize-check-status=DISABLE

为了让所有项目都可以加载全局异常处理类,可以在通用模块的resources目录下建立META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,添加如下内容:

com.bootscoder.shopping_common.result.GlobalExceptionHandler

在Dubbo这样的分布式服务框架中,如果默认关闭了对象序列化,就会影响异常信息从服务端传到消费端的能力。具体表现为:

  1. 异常信息丢失:当服务端发生异常时,这些异常信息需要通过网络传输到消费端。对象序列化是这一过程中的关键,它允许复杂的对象数据转换为字节流,以便可以通过网络传输。如果序列化被关闭,异常对象不能被有效地转换和传输,导致消费端无法接收到完整的异常信息。
  2. 通用异常代替:在没有获取到具体异常信息的情况下,消费端可能只能接收到一些非常通用的异常,例如java.rmi.RemoteException。这意味着消费端得到的错误信息不具体,无法准确反映服务端发生的实际问题。
  3. 错误处理困难:缺乏具体的异常信息会使得消费端难以进行针对性的错误处理或调试。这可能会增加问题诊断和解决的时间和复杂性,影响服务的整体可靠性和用户体验。
  4. 服务降级处理:在一些情况下,如果异常信息不能正确传递,系统可能需要依赖预定义的服务降级策略。这些策略虽然能保持系统运行,但可能不是最优解决方案。

image-20240416212345908


/**
 * 自定义异常
 *
 * @author bootsCoder
 * @date created on 2024/4/15
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class MyException extends RuntimeException {
    // 状态码
    private Integer code;
    // 错误消息
    private String msg;

    public MyException(ResultCode resultCode){
        this.code = resultCode.getCode();
        this.msg = resultCode.getMessage();
    }
}   
package com.bootscoder.shopping_common.result;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 统一异常处理
 *
 * @author bootsCoder
 * @date created on 2024/4/15
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    // 处理业务异常
    @ExceptionHandler(MyException.class)
    public BaseResult defaultExceptionHandler(MyException e){
        BaseResult baseResult = new BaseResult(e.getCode(),e.getMsg(),null);
        return baseResult;
    }
    // 处理系统异常
    @ExceptionHandler(Exception.class)
    public BaseResult defaultExceptionHandler(HttpServletRequest req, HttpServletResponse resp, Exception e) {
        e.printStackTrace();
        BaseResult baseResult = new BaseResult(ResultCode.SYSTEM_ERROR.getCode(),ResultCode.SYSTEM_ERROR.getMessage(),null);
        return baseResult;
    }
}

@GetMapping("/findById")
    public BaseResult<Brand> findById(Long id){

        /**
         * 测试异常处理器
         */
        if (id == 0){
            long i = 1/id;
        } else if (id == -1 ) {
            throw new MyException(ResultCode.PARAMETER_ERROR);
        }
        Brand brand = brandService.findById(id);
        return BaseResult.ok(brand);
    }
{
    "code": 500,
    "message": "系统异常",
    "data": null
}
{
    "code": 601,
    "message": "参数异常",
    "data": null
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值