分布式项目学习

Nacos

Nacos 文档地址: https://nacos.io/zh-cn/docs/quick-start.html

sh startup.sh -m standalone 以非集群的方式启动 127.0.0.1:8848/ 账号: nacos nacos


使用nacos作为注册中心:将微服务注册到 nacos 中

将微服务注册到nacos,各个服务之间的相互调用需要使用注册中心

1. 首先,修改 pom.xml 文件,引入 Nacos Discovery Starter

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacosdiscovery</artifactId>
</dependency>

2. 在应用的 application.properties 中配置 Nacos Server 地址

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=service-provider 为每个服务创建名字是必须的
server.port=8000

3.在主程序中使用@EnableDiscoveryClient 开启服务注册发现功能


使用nacos作为配置中心:

统一管理各微服务配置。在配置中心发布配置,项目在运行阶段可动态读取配置,无需重启项目即可做到修改项目配置

1、pom.xml 引入 NacosConfigStarter。

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>


2、新建一个bootstrap.properties 配置文件中配置 NacosConfig 元数据 该配置文件在springboot中会比applicaion.yml的优先级高主要配置应用名和配置中心地址

spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

3、需要给配置中心默认添加一个叫 数据集(Data Id)gulimall-coupon.properties。默认规则,应用名.properties
4、给应用名.properties 添加任何配置
* 5、动态获取配置。

@RefreshScope:动态获取并刷新配置 加在类上controller
@Value("${配置项的名}"):获取到配置。 在controller上获取配置
//如果配置中心和当前应用的配置文件中都配置了相同的项,优先使用配置中心的配置。

扩展
1)、命名空间:配置隔离;nacos默认:public(保留空间);默认新增的所有配置都在public空间。
开发,测试,生产:利用命名空间来做环境隔离。
注意:在bootstrap.properties;配置上,需要使用哪个命名空间下的配置,

spring.cloud.nacos.config.namespace=9de62e44-cd2a-4a82-bf5c-95878bd5e871 
这个ID是命名空间id


2、每一个微服务之间互相隔离配置,每一个微服务都创建自己的命名空间,只加载自己命名空间下的所有配置
    



项目中的使用:每个微服务创建自己的命名空间,使用配置分组区分环境,dev,test,prod
                    每一类配置分文件放:比如:datasource.yml 、mybatisPuls.yum 、 other.yum
                    加载每一个配置文件:
                        spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
                        spring.cloud.nacos.config.ext-config[0].group=dev
                        spring.cloud.nacos.config.ext-config[0].refresh=true 开启动态刷新,修改配置也会读取到,而不是只在启动时读取
    


 3)、@Value,@ConfigurationProperties ....  以前SpringBoot任何方法从配置文件中获取值,都能使用。配置中心有的优先使用配置中心中的,

 mybatis-plus

文档地址 https://baomidou.com/


    配置全局逻辑删除规则
        logic-delete-value: 1
        logic-not-delete-value: 0
        在实体类中加上逻辑删除注解
        @TableLogic
        private Integer deleted;

使用JSR303规范校验传输中的实体类

使用说明

常用的注解有 @Null、 @NotNull 、@Min等等

下面是一个例子,在实体类中的某个属性上加上校验注解,控制类在接受该实体类时会核对该校验,校验失败则会返回message消息.在实体类后紧跟着一个BindingResult就可以拿到校验结果,自己在返回校验信息。

//控制类代码:save
@RequestMapping("/save")
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand,, BindingResult bandingResult){
  brandService.save(brand);
  return R.ok();
}
//控制类代码:update
@RequestMapping("/update")
public R update(@Validated({UpdateGroup.class})@RequestBody BrandEntity brand){
  brandService.updateById(brand);
  return R.ok();
}

//实体类代码
@Pattern(regexp = "^[a-zA-Z]$",message = "必须为一个a-zA-Z的单个字母",groups = {AddGroup.class, UpdateGroup.class})
@NotBlank(message = "检索首字母不能为空",groups = {AddGroup.class})
private String firstLetter;

对同一个实体类可以对不同场景使用不同检验组。这需要使用@Validated注解指定检验组,检验组中的类是一个纯接口

//纯接口,只是为了给校验分类。添加数据指定该组规则
public interface AddGroup {
}

//纯接口,只是为了给校验分类。更新数据指定该组规则
public interface UpdateGroup {
}

自定义校验注解

虽然上面的场景已经满足大多数要求了,但是你一定有自己的规则,想定义自己的规则也很简单,我们先来点一个注解的源码进去看看它是怎么写的

@Documented
@Constraint(validatedBy = { })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
public @interface NotBlank {

	String message() default "{javax.validation.constraints.NotBlank.message}";

	Class<?>[] groups() default { };

	Class<? extends Payload>[] payload() default { };

	/**
	 * Defines several {@code @NotBlank} constraints on the same element.
	 *
	 * @see NotBlank
	 */
	@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
	@Retention(RUNTIME)
	@Documented
	public @interface List {
		NotBlank[] value();
	}
}

 可以看到自定义校验注解也要有上面的元注解信息,其中

@Constraint(validatedBy = { })用来指定该检验注解使用什么校验器,这里用空的是源码在初始化中去定义了。

message用于指定校验出错返回的信息去哪里取,我们可以在resources下创建一个ValidationMessages.properties文件用来存放该信息

groups用来指定该注解用在哪个分组

payload用来定义写负载信息

我们安照上面的源码照葫芦画瓢,自己定义一个用来校验该值是否是我们自己指定的整数


@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class }) //指定使用的自定义校验器
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.myself.common.valid.ListValue.message}"; // 指定错误提示的消息

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    int[] vals() default { };//用来存放指定的整数
}

创建注解时我们发现这个的一些包没有导入,我们要在项目的Pom文件中导入javax校验相关的包

<dependency>
	<groupId>javax.validation</groupId>
	<artifactId>validation-api</artifactId>
	<version>2.0.1.Final</version>
</dependency>

在resources下创建一个ValidationMessages.properties文件用来存放该信息,也可以不创建,我们直接在message中写校验出错的信息

com.atguigu.common.valid.ListValue.message="值必须为0或1"

最后我们还差一个校验器。检验器需要事项ConstraintValidator接口,第一个泛型是我们的校验注解,第二个是校验的类型


public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    private Set<Integer> set = new HashSet<>();
    //初始化方法
    @Override
    public void initialize(ListValue constraintAnnotation) {
        //初始化时我们把规则传入的数值放入自己定义的set集合中
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }

    }

    /**
     *判断是否校验成功
     * @param value 需要校验的值
     * @param context
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        //这里去判断需要校验的值是不是在我们的规则中
        return set.contains(value);
    }
}

最后我们使用这个自定义的校验注解

	/**
	 * 显示状态[0-不显示;1-显示] 添加和修改时都必须校验该值是否为0或1
	 */
	@ListValue(vals = {0,1},groups = {AddGroup.class, UpdateGroup.class})
	private Integer showStatus;

使用JsonInclud注解

1.在类上加入@JsonInclude(value = JsonInclude.Include.NON_NULL),表明该类为NULL的字段不参加序列化!

2.将该标记放在属性上,如果该属性为NULL则不参与序列化 !

3.如果放在类上边,那对这个类的全部属性起作用 !

使用场景:如果数据库中查出的数据为空,正常会返回一个null,或者默认值如[] 0,想要数据为空则不返回该字段就可使用

//属性为null时不序列化
@JsonInclude(value = JsonInclude.Include.NON_NULL)
private List<CategoryEntity> child;

Include.Include.ALWAYS -------------->默认,总是序列化
Include.NON_DEFAULT ------------->属性为默认值不序列化
Include.NON_EMPTY ---------------->属性为 空(“”) 或者为 NULL 都不序列化
Include.NON_NULL ------------------>属性为NULL 不序列化

统一异常返回

@Slf4j
@RestControllerAdvice
public class GuliMaillExceptionControllerAdvice {
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handlerVaildException(MethodArgumentNotValidException e){
        log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
        // 拿到数据校验异常信息类
        BindingResult bindingResult = e.getBindingResult();
        Map<String,String> errorMap = new HashMap<>();
        // 将所有校验出错的字段全部放到map中。
        bindingResult.getFieldErrors().forEach(fieldError -> errorMap.put(fieldError.getField(),fieldError.getDefaultMessage()));
        // 统一返回所有出错的字段和提示信息。异常码,和异常类型定义在BizCodeEnume枚举类中
        return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap);
    }
    @ExceptionHandler(value = Throwable.class)
    public R handlerException(Throwable t){
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}

  • 41
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code小鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值