【Flutter从入门到入坑之三】Flutter 是如何工作的

谷粒商城_01_环境搭建
谷粒商城_02_Nacos、网关
谷粒商城_03_前端基础
谷粒商城_04_商品CRUD
谷粒商城_05_阿里云OSS和前端校验

JSR303校验

问题引入:填写form时应该有前端校验,后端也应该有校验

前端的校验是element-ui表单验证:https://element.eleme.cn/#/zh-CN/component/form

  • Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可。校验规则参见 async-validator

  • 使用自定义校验规则可以解决字母限制、密码不一致、非整数限制等等的问题

  • 基本使用

    // dataForm:表单的数据、dataRule:所有检验的规则
    <el-form :model="dataForm" :rules="dataRule"/>
        
    // 表单的某一项用prop指定校验的目标即可使用
    <el-form-item label="密码" prop="checkPass">
    
    // 
    data() {
          
          
    	return {
          
          
        	dataRule: {
          
          
                // 密码校验的字段checkPass,validator: validatePass指向校验的具体方法,既可以将其替换成方法使用
            	checkPass: [
                {
          
           validator: validatePass, trigger: 'blur' }
            	],
            }
        }
    }
    var validatePass = (rule, value, callback) => {
          
          
        if (value === '') {
          
          
            callback(new Error('请再次输入密码'));
            // dataForm表单的数据
        } else if (value !== this.dataForm.pass) {
          
          
            callback(new Error('两次输入密码不一致!'));
        } else {
          
          
            callback();
        }
    };
    
  • 后端:@NotNull、@NotBank、@URL等等

普通校验

1、使用校验注解

在Java中提供了一系列的校验方式,它这些校验方式在“javax.validation.constraints、org.hibernate.validator.constraints”包中,提供了如@Email、@NotNull、@URL等注解。

  • 主要看注解源码文档来了解其中使用
<!--jsr3参数校验器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.6.1</version>
</dependency>

2、@Valid内置异常

这里内置异常的意思是发生异常时返回的json不是我们的R对象,而是mvc的内置类

在controller类上加:@Validated,方法参数中加校验注解:@Valid,开启校验,

@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand){
    
    
    brandService.save(brand);

    return R.ok();
}

测试: http://localhost:88/api/product/brand/save,在postman种发送上面的请求,发现返回的是json对象,但不是我们的R对象

 // 其中
"defaultMessage": "不能为空",

“defaultMessage”: “不能为空”,这些错误消息定义在“hibernate-validator”的“\org\hibernate\validator\ValidationMessages_zh_CN.properties”文件中。在该文件中定义了很多的错误规则:

javax.validation.constraints.AssertFalse.message     = 只能为false
javax.validation.constraints.AssertTrue.message      = 只能为true
javax.validation.constraints.DecimalMax.message      = 必须小于或等于{
    
    value}
javax.validation.constraints.DecimalMin.message      = 必须大于或等于{
    
    value}
javax.validation.constraints.Digits.message          = 数字的值超出了允许范围(只允许在{
    
    integer}位整数和{
    
    fraction}位小数范围内)
javax.validation.constraints.Email.message           = 不是一个合法的电子邮件地址
javax.validation.constraints.Future.message          = 需要是一个将来的时间
javax.validation.constraints.FutureOrPresent.message = 需要是一个将来或现在的时间
javax.validation.constraints.Max.message             = 最大不能超过{
    
    value}
javax.validation.constraints.Min.message             = 最小不能小于{
    
    value}
javax.validation.constraints.Negative.message        = 必须是负数
javax.validation.constraints.NegativeOrZero.message  = 必须是负数或零
javax.validation.constraints.NotBlank.message        = 不能为空
javax.validation.constraints.NotEmpty.message        = 不能为空
javax.validation.constraints.NotNull.message         = 不能为null
javax.validation.constraints.Null.message            = 必须为null
javax.validation.constraints.Past.message            = 需要是一个过去的时间
javax.validation.constraints.PastOrPresent.message   = 需要是一个过去或现在的时间
javax.validation.constraints.Pattern.message         = 需要匹配正则表达式"{regexp}"
javax.validation.constraints.Positive.message        = 必须是正数
javax.validation.constraints.PositiveOrZero.message  = 必须是正数或零
javax.validation.constraints.Size.message            = 个数必须在{
    
    min}{
    
    max}之间

org.hibernate.validator.constraints.CreditCardNumber.message        = 不合法的信用卡号码
org.hibernate.validator.constraints.Currency.message                = 不合法的货币 (必须是{
    
    value}其中之一)
org.hibernate.validator.constraints.EAN.message                     = 不合法的{
    
    type}条形码
org.hibernate.validator.constraints.Email.message                   = 不是一个合法的电子邮件地址
org.hibernate.validator.constraints.Length.message                  = 长度需要在{
    
    min}{
    
    max}之间
org.hibernate.validator.constraints.CodePointLength.message         = 长度需要在{
    
    min}{
    
    max}之间
org.hibernate.validator.constraints.LuhnCheck.message               = ${
    
    validatedValue}的校验码不合法, Luhn10校验和不匹配
org.hibernate.validator.constraints.Mod10Check.message              = ${
    
    validatedValue}的校验码不合法,10校验和不匹配
org.hibernate.validator.constraints.Mod11Check.message              = ${
    
    validatedValue}的校验码不合法,11校验和不匹配
org.hibernate.validator.constraints.ModCheck.message                = ${
    
    validatedValue}的校验码不合法, ${
    
    modType}校验和不匹配
org.hibernate.validator.constraints.NotBlank.message                = 不能为空
org.hibernate.validator.constraints.NotEmpty.message                = 不能为空
org.hibernate.validator.constraints.ParametersScriptAssert.message  = 执行脚本表达式"{script}"没有返回期望结果
org.hibernate.validator.constraints.Range.message                   = 需要在{
    
    min}{
    
    max}之间
org.hibernate.validator.constraints.SafeHtml.message                = 可能有不安全的HTML内容
org.hibernate.validator.constraints.ScriptAssert.message            = 执行脚本表达式"{script}"没有返回期望结果
org.hibernate.validator.constraints.URL.message                     = 需要是一个合法的URL

org.hibernate.validator.constraints.time.DurationMax.message        = 必须小于${
    
    inclusive == true ? '或等于' : ''}${
    
    days == 0 ? '' : days += '天'}${
    
    hours == 0 ? '' : hours += '小时'}${
    
    minutes == 0 ? '' : minutes += '分钟'}${
    
    seconds == 0 ? '' : seconds += '秒'}${
    
    millis == 0 ? '' : millis += '毫秒'}${
    
    nanos == 0 ? '' : nanos += '纳秒'}
org.hibernate.validator.constraints.time.DurationMin.message        = 必须大于${
    
    inclusive == true ? '或等于' : ''}${
    
    days == 0 ? '' : days += '天'}${
    
    hours == 0 ? '' : hours += '小时'}${
    
    minutes == 0 ? '' : minutes += '分钟'}${
    
    seconds == 0 ? '' : seconds += '秒'}${
    
    millis == 0 ? '' : millis += '毫秒'}${
    
    nanos == 0 ? '' : nanos += '纳秒'}

想要自定义错误消息,可以覆盖默认的错误提示信息,如@NotBlank的默认message是

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

可以在添加注解的时候,修改message:

@NotBlank(message = "品牌名必须非空")
private String name;

当再次发送请求时,得到的错误提示信息:

"defaultMessage": "品牌名必须非空",

但是返回的错误不是R对象,影响接收端的接收,我们可以通过局部异常处理或者统一一次处理解决

局部异常处理BindResult

  • 给校验的Bean后,紧跟一个BindResult,就可以获取到校验的结果。拿到校验的结果,就可以自定义的封装。
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand,
              BindingResult result){
    
     // 手动处理异常

    if( result.hasErrors()){
    
    
        Map<String,String> map=new HashMap<>();
        //1.获取错误的校验结果
        result.getFieldErrors().forEach((item)->{
    
    
            //获取发生错误时的message,提示信息
            String message = item.getDefaultMessage();
            //获取发生错误的属性的名字
            String field = item.getField();
            map.put(field,message);
        });
        return R.error(400,"提交的数据不合法").put("data",map);
    }else {
    
    

    }
    brandService.save(brand);
    return R.ok();
}

这种是针对于该请求设置了一个内容校验,如果针对于每个请求都单独进行配置,显然不是太合适,实际上可以统一的对于异常进行处理。

统一异常处理

@ExceptionHandler

  • @ ExceptionHandler 需要进行异常处理的方法必须与出错的方法在同一个Controller里面。那么当代码加入了 @ControllerAdvice,则不需要必须在同一个 controller 中了。这也是 Spring 3.2 带来的新特性。 也就是说,@controlleradvice + @ ExceptionHandler 也可以实现全局的异常捕捉。

1、抽取一个异常处理类

  • @ControllerAdvice标注在类上,通过“basePackages”能够说明处理哪些路径下的异常。
  • @ExceptionHandler(value = 异常类型.class)标注在方法上
  • 这里的ConstraintViolationException异常我和项目中不一样,但是可以通过源码定位到里面的属性,然后获取异常信息放入map
/**
 * @author ljy
 * @version 1.0.0
 * @Description 集中处理所有异常
 * @createTime 2021年12月14日 19:22:00
 */
@Slf4j
// @RestControllerAdvice和@ControllerAdvice的关系类似于@RestController
@RestControllerAdvice(basePackages = "com.liu.gulimall.product.controller")// 管理的controller
public class GulimallExceptionControllerAdvice {
    
    

    @ExceptionHandler(value = ConstraintViolationException.class) // 感知精确异常
    // 也可以返回ModelAndView
    // exception是controller中的异常,精确匹配ConstraintViolationException这个异常
    // MethodArgumentNotValidException
    public R handleValidException(ConstraintViolationException exception){
    
    
        Map<String,String> map=new HashMap<>();
        // 获取数据校验的错误结果,和之前一样BindingResult
        exception.getConstraintViolations().forEach(item->{
    
    
            String message = item.getMessage();
            Path propertyPath = item.getPropertyPath();
            map.put(propertyPath.toString(),message);
        });

        log.error("数据校验出现问题{},异常类型{}",exception.getMessage(),exception.getClass());

        return R.error(400,"数据校验出现问题").put("data",map);
    }

    @ExceptionHandler(value = Throwable.class)//异常的范围更大
    public R handleException(Throwable throwable){
    
    
        log.error("未知异常{},异常类型{}",
                throwable.getMessage(),
                throwable.getClass());
        return R.error(BizCodeEnum.UNKNOW_EXEPTION.getCode(),
                BizCodeEnum.UNKNOW_EXEPTION.getMsg());
    }
}

(2)测试: http://localhost:9999/product/brand/save

在这里插入图片描述

(3)默认异常处理

@ExceptionHandler(value = Throwable.class)// 异常的范围更大
public R handleException(Throwable throwable){
    
    
    log.error("未知异常{},异常类型{}",
              throwable.getMessage(),
              throwable.getClass());
    return R.error(BizCodeEnum.UNKNOW_EXEPTION.getCode(),
                   BizCodeEnum.UNKNOW_EXEPTION.getMsg());
}

(4)错误状态码

正规开发过程中,错误状态码有着严格的定义规则,在项目中我们的错误状态码定义

上面的用法主要是通过@Controller+@ExceptionHandler来进行异常拦截处理,单独定义一个枚举类,用来存储这些错误状态码

/***
 * 错误码和错误信息定义类
 * 1. 错误码定义规则为5为数字
 * 2. 前两位表示业务场景,最后三位表示错误码。例如:10001。10:通用 001:系统未知异常
 * 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
 * 错误码列表:
 *  10: 通用
 *      001:参数格式校验
 *  11: 商品
 *  12: 订单
 *  13: 购物车
 *  14: 物流
 */
/**
 * @author ljy
 * @version 1.0.0
 * @Description TODO
 * @createTime 2021年12月14日 19:23:00
 */
public enum BizCodeEnum {
    
    

    UNKNOW_EXEPTION(10000,"系统未知异常"),

    VALID_EXCEPTION( 10001,"参数格式校验失败");

    private int code;
    private String msg;

    BizCodeEnum(int code, String msg) {
    
    
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
    
    
        return code;
    }

    public String getMsg() {
    
    
        return msg;
    }
}

分组校验功能(多场景校验)

前面解决了统一异常处理,但是同一实体比如id,修改的时候不能为空,添加的时候为空,那怎么来校验呢?

我们采取分组的方式

1、定义分组接口,A(添加分组)、B(删除分组),接口只是标识

2、在controller方法中添加的方法中使用 @Validated(A.class)

// 表示添加的时候采用A分组策略
public R save(@Validated({
    
    A.class}) @RequestBody BrandEntity brand){
    
    

3、在实体属性上,比如id,@NotNull(message = “修改id不为空”,groups = {B.class})、@Null(message = “新增id必须为空”,groups = {A.class})

@NotNull(message = "修改必须定制品牌id", groups = {
    
    UpdateGroup.class})
@Null(message = "新增不能指定id", groups = {
    
    AddGroup.class})
@TableId
private Long brandId;

在这种情况下,没有指定分组的校验注解,默认是不起作用的。想要起作用就必须要加groups。

  • controller接收到之后,根据@Validated表明的分组信息,然后确定品牌对应的校验注解。

总结:

package com.liu.common.valid;

/**
 * @author ljy
 * @version 1.0.0
 * @Description TODO
 * @createTime 2021年12月14日 20:49:00
 */
public interface addGroup {
    
    
}
========================
/**
 * 保存
 */
@RequestMapping("/save")
public R save(@Validated({
    
    addGroup.class}) @RequestBody BrandEntity brand, BindingResult result){
    
    
    brandService.save(brand);
    return R.ok();
}
========================
/**
 * 品牌名
 */
@NotBlank(message = "品牌名不能为空", groups  = {
    
    addGroup.class})
private String name;
========================
{
    
    
    "msg": "提交的数据不合法",
    "code": 400,
    "data": {
    
    
        "name": "品牌名不能为空"
    }
}

自定义校验注解

Hibernate Validator提供了一系列内置的校验注解,可以满足大部分的校验需求。但是,仍然有一部分校验需要特殊定制

比如:要校验showStatus的0/1状态,只能是0,1两个值

1、添加依赖

<!--校验-->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.1.0.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.1.Final</version>
</dependency>
<!--高版本需要javax.el-->
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.el</artifactId>
    <version>3.0.1-b08</version>
</dependency>

2、自定义注解

/**
 * @author ljy
 * @version 1.0.0
 * @Description 自定义注解,模仿其他的检验注解即可
 * @createTime 2021年12月14日 20:57:00
 */
@Documented
@Constraint(validatedBy = {
    
     ListValueConstraintValidator.class}) // 校验器,指定校验器,需要我们自己定义
@Target({
    
     METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) // 在哪可以标注此注解
@Retention(RUNTIME)
public @interface ListValue {
    
    
    // 必须有3个属性
    // 使用该属性去Validation.properties中取
    String message() default "{com.liu.common.valid.ListValue.message}"; // 错误信息

    Class<?>[] groups() default {
    
     }; // 分组校验

    Class<? extends Payload>[] payload() default {
    
     }; // 自定义负载信息

    // 数组,需要用户自己指定
    int[] value() default {
    
    };
}

因为上面的message值对应的最终字符串需要去ValidationMessages.properties中获得,所以我们在common中新建文件ValidationMessages.properties

3、ValidationMessages.properties

com.liu.common.valid.ListValue.message=必须提交指定的值 [0,1]

4、自定义校验器

  • 通过源码:@Constraint注解的validatedBy是一个ConstraintValidator类型,并且里面包含了注解和校验类型,所以我们自定义实现ConstraintValidator,放入我们的注解和类型
/**
 * @author ljy
 * @version 1.0.0
 * @Description TODO
 * @createTime 2021年12月14日 21:06:00
 */
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    
    
    // 存储所有可能的值
    private Set<Integer> set=new HashSet<Integer>();

    // 初始化,你可以获取注解上的内容并进行处理
    public void initialize(ListValue constraintAnnotation) {
    
    
        // 获取后端写好的限制 // 这个value就是ListValue里的value,我们写的注解是@ListValue(value={0,1})
        int[] value = constraintAnnotation.value();
        for (int i : value) {
    
    
            set.add(i);
        }
    }

    /**
     * 覆写验证逻辑
     * @param value 需要校验的值
     * @param context
     * @return
     */
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
    
    
        // 看是否在限制的值里,是返回true
        return  set.contains(value);
    }
}

5、使用

/**
 * 显示状态[0-不显示;1-显示]
 */
@ListValue(value = {
    
    0,1},groups ={
    
    addGroup.class})
private Integer showStatus;

6、测试

{
    
    
    "msg": "提交的数据不合法",
    "code": 400,
    "data": {
    
    
        "showStatus": "必须提交指定的值 [0,1]"
    }
}

在这里插入图片描述

Elasticsearch

初步检索

1、检索es信息

(1)GET /_cat/nodes:查看所有节点 :http://localhost:9200/_cat/nodes

(2)GET /_cat/health:查看es健康状况:green表示健康值正常

(3)GET /_cat/master:查看主节点

(4)GET/_cat/indicies:查看所有索引 ,等价于mysql数据库的show databases;

2、新增文档

保存一个数据,保存在哪个索引的哪个类型下(哪张数据库哪张表下),保存时用唯一标识指定

# 在customer索引下的external类型下保存1号数据
PUT customer/external/1

{
    
    
 "name":"John Doe"
}

PUT和POST区别

  • POST新增。如果不指定id,会自动生成id,指定id就会修改这个数据,并新增版本号;
    • 可以不指定id,不指定id时永远为创建
    • 指定不存在的id为创建
    • 指定存在的id为更新,而版本号会根据内容变没变而觉得版本号递增与否
  • PUT可以新增也可以修改。PUT必须指定id;由于PUT需要指定id,我们一般用来做修改操作,不指定id会报错。
    • 必须指定id
    • 版本号总会增加

seq_no和version的区别:

  • 每个文档的版本号"_version" 起始值都为1 每次对当前文档成功操作后都加1
  • 而序列号"_seq_no"则可以看做是索引的信息 在第一次为索引插入数据时为0,每对索引内数据操作成功一次sqlNO加1, 并且文档会记录是第几次操作使它成为现在的情况的

下面是在postman中选用POST方式的测试数据:

创建数据成功后,显示201 created表示插入记录成功。

返回数据:
带有下划线开头的,称为元数据,反映了当前的基本信息。  
{
    
    
    "_index": "customer", 表明该数据在哪个数据库下;
    "_type": "external", 表明该数据在哪个类型下;
    "_id": "1",  表明被保存数据的id;
    "_version": 1,  被保存数据的版本
    "result": "created", 这里是创建了一条数据,如果重新put一条数据,则该状态会变为updated,并且版本号也会发生变化。
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}
12345678910111213141516

下面选用POST方式:

添加数据的时候,不指定ID,会自动的生成id,并且类型是新增:

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "5MIjvncBKdY1wAQm-wNZ",
    "_version": 1,
    "result": "created",
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 11,
    "_primary_term": 6
}
1234567891011121314

再次使用POST插入数据,不指定ID,仍然是新增的:

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "5cIkvncBKdY1wAQmcQNk",
    "_version": 1,
    "result": "created",
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 12,
    "_primary_term": 6
}

添加数据的时候,指定ID,会使用该id,并且类型是新增:

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 1,
    "result": "created",
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 13,
    "_primary_term": 6
}

再次使用POST插入数据,指定同样的ID,类型为updated

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 2,
    "result": "updated",
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 14,
    "_primary_term": 6
}

3、查看文档

GET /customer/external/1

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 10,
    "_seq_no": 18,//并发控制字段,每次更新都会+1,用来做乐观锁
    "_primary_term": 6,//同上,主分片重新分配,如重启,就会变化
    "found": true,
    "_source": {
    
    
        "name": "John Doe"
    }
}
123456789101112

乐观锁用法:通过“if_seq_no=1&if_primary_term=1”,当序列号匹配的时候,才进行修改,否则不修改。

实例:将id=1的数据更新为name=1,然后再次更新为name=2,起始1_seq_no=18,_primary_term=6

(1)将name更新为1

PUT http://localhost:9200/customer/external/1?if_seq_no=18&if_primary_term=6

(2)将name更新为2,更新过程中使用seq_no=18

PUT http://localhost:9200/customer/external/1?if_seq_no=18&if_primary_term=6

结果为:出现更新错误。

(3)查询新的数据

GET http://localhost:9200/customer/external/1

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 11,
    "_seq_no": 19,
    "_primary_term": 6,
    "found": true,
    "_source": {
    
    
        "name": "1"
    }
}

能够看到_seq_no变为19

(4)再次更新,更新成功

4、更新文档_update

POST customer/externel/1/_update
{
    
    
    "doc":{
    
    
        "name":"111"
    }
}
或者
POST customer/externel/1
{
    
    
    "doc":{
    
    
        "name":"222"
    }
}
或者
PUT customer/externel/1
{
    
    
    "doc":{
    
    
        "name":"222"
    }
}

不同:带有update情况下

  • POST操作会对比源文档数据,如果相同不会有什么操作,文档version不增加。
  • PUT操作总会重新保存并增加version版本

POST时带_update对比元数据如果一样就不进行任何操作。

看场景:

  • 对于大并发更新,不带update
  • 对于大并发查询偶尔更新,带update;对比更新,重新计算分配规则

(1)POST更新文档,带有_update

如果再次执行更新,则不执行任何操作,序列号也不发生变化

返回
{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 12,
    "result": "noop", // 无操作
    "_shards": {
    
    
        "total": 0,
        "successful": 0,
        "failed": 0
    },
    "_seq_no": 20,
    "_primary_term": 6
}

POST更新方式,会对比原来的数据,和原来的相同,则不执行任何操作(version和_seq_no)都不变。

(2)POST更新文档,不带_update,和put一样

在更新过程中,重复执行更新操作,数据也能够更新成功,不会和原来的数据进行对比。

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 13,
    "result": "updated",
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 21,
    "_primary_term": 6
}

5、删除文档或索引

DELETE customer/external/1
DELETE customer // 删除索引

注:elasticsearch并没有提供删除类型的操作,只提供了删除索引和文档的操作。

实例:删除id=1的数据,删除后继续查询

DELETE http://localhost:9200/customer/external/1

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 14,
    "result": "deleted",
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 22,
    "_primary_term": 6
}

再次执行DELETE http://localhost:9200/customer/external/1

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 15,
    "result": "not_found",
    "_shards": {
    
    
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 23,
    "_primary_term": 6
}

GET http://localhost:9200/customer/external/1

{
    
    
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "found": false
}
123456

删除索引

实例:删除整个costomer索引数据

删除前,所有的索引http://localhost:9200/_cat/indices

green  open .kibana_task_manager_1   DhtDmKrsRDOUHPJm1EFVqQ 1 0 2 0 31.3kb 31.3kb
green  open .apm-agent-configuration vxzRbo9sQ1SvMtGkx6aAHQ 1 0 0 0   283b   283b
green  open .kibana_1                rdJ5pejQSKWjKxRtx-EIkQ 1 0 8 3 28.8kb 28.8kb
yellow open customer                 mG9XiCQISPmfBAmL1BPqIw 1 1 9 1  8.6kb  8.6kb

删除“ customer ”索引

DELTE http://localhost:9200/customer

响应
{
    
    
    "acknowledged": true
}

删除后,所有的索引 http://localhost:9200/_cat/indices

green open .kibana_task_manager_1   DhtDmKrsRDOUHPJm1EFVqQ 1 0 2 0 31.3kb 31.3kb
green open .apm-agent-configuration vxzRbo9sQ1SvMtGkx6aAHQ 1 0 0 0   283b   283b
green open .kibana_1                rdJ5pejQSKWjKxRtx-EIkQ 1 0 8 3 28.8kb 28.8kb

6、ES的批量操作——bulk

匹配导入数据

POST http://localhost:9200/customer/external/_bulk

两行为一个整体
{
    
    "index":{
    
    "_id":"1"}}
{
    
    "name":"a"}
{
    
    "index":{
    
    "_id":"2"}}
{
    
    "name":"b"}
注意格式json和text均不可,要去kibana里Dev Tools

语法格式:

{
    
    action:{
    
    metadata}}\n
{
    
    request body  }\n

{
    
    action:{
    
    metadata}}\n
{
    
    request body  }\n

这里的批量操作,当发生某一条执行发生失败时,其他的数据仍然能够接着执行,也就是说彼此之间是独立的。

bulk api以此按顺序执行所有的action(动作)。如果一个单个的动作因任何原因失败,它将继续处理它后面剩余的动作。当bulk api返回时,它将提供每个动作的状态(与发送的顺序相同),所以您可以检查是否一个指定的动作是否失败了。

实例1: 执行多条数据

POST /customer/external/_bulk
{
    
    "index":{
    
    "_id":"1"}}
{
    
    "name":"John Doe"}
{
    
    "index":{
    
    "_id":"2"}}
{
    
    "name":"John Doe"}
12345

执行结果

#! Deprecation: [types removal] Specifying types in bulk requests is deprecated.
{
    
    
  "took" : 318,  花费了多少ms
  "errors" : false, 没有发生任何错误
  "items" : [ 每个数据的结果
    {
    
    
      "index" : {
    
     保存
        "_index" : "customer", 索引
        "_type" : "external", 类型
        "_id" : "1", 文档
        "_version" : 1, 版本
        "result" : "created", 创建
        "_shards" : {
    
    
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 0,
        "_primary_term" : 1,
        "status" : 201 新建完成
      }
    },
    {
    
    
      "index" : {
    
     第二条记录
        "_index" : "customer",
        "_type" : "external",
        "_id" : "2",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
    
    
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 1,
        "_primary_term" : 1,
        "status" : 201
      }
    }
  ]
}

实例2:对于整个索引执行批量操作

POST /_bulk
{
    
    "delete":{
    
    "_index":"website","_type":"blog","_id":"123"}}
{
    
    "create":{
    
    "_index":"website","_type":"blog","_id":"123"}}
{
    
    "title":"my first blog post"}
{
    
    "index":{
    
    "_index":"website","_type":"blog"}}
{
    
    "title":"my second blog post"}
{
    
    "update":{
    
    "_index":"website","_type":"blog","_id":"123"}}
{
    
    "doc":{
    
    "title":"my updated blog post"}}

7、样本测试数据

准备了一份顾客银行账户信息的虚构的JSON文档样本。每个文档都有下列的schema(模式)。

{
    
    
	"account_number": 1,
	"balance": 39225,
	"firstname": "Amber",
	"lastname": "Duke",
	"age": 32,
	"gender": "M",
	"address": "880 Holmes Lane",
	"employer": "Pyrami",
	"email": "[email protected]",
	"city": "Brogan",
	"state": "IL"
}

https://github.com/elastic/elasticsearch/blob/master/docs/src/test/resources/normalized-T1117-AtomicRed-regsvr32.json ,导入测试数据,

POST bank/account/_bulk
上面的数据
http://localhost:9200/_cat/indices
刚导入了1000条
yellow open bank                     99m64ElxRuiH46wV7RjXZA 1 1 1000 0 427.8kb 427.8kb

猜你喜欢

转载自blog.csdn.net/XH_jing/article/details/129437448
今日推荐