【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【04】跨域_OSS_后端校验

news2024/10/6 2:31:10

持续学习&持续更新中…

学习态度:守破离


【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【04】

  • 跨域
    • 问题
    • 解决
    • 实现
  • 逻辑删除
  • 文件存储
    • 普通上传
    • 云存储
  • 阿里云OSS
    • 简介
    • 术语
    • 简单使用
    • 使用SpringCloudAlibaba—oss
    • 服务端签名后直传
      • 普通上传方式:
      • 服务端签名后直传:
      • 实现:
  • 后端校验—JSR303
  • 统一异常处理
  • 参考

跨域

问题

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS

在这里插入图片描述

在这里插入图片描述

解决

在这里插入图片描述

在这里插入图片描述

实现

gulimall-gateway:

spring:
  cloud:
    gateway:
      routes:
        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
        #需要把精确的路由放到上面【/api/product/**比/api/**更精确】
        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}

## 前端项目,/api
## http://localhost:88/api/captcha.jpg   http://localhost:8080/renren-fast/captcha.jpg
## http://localhost:88/api/product/category/list/tree http://localhost:10000/product/category/list/tree

#        - id: qq_route
#          uri: https://www.qq.com
#          predicates:
#            - Query=url,qq
#        - id: bing
#          uri: https://cn.bing.com/
#          predicates:
#            - Query=url,bing
@Configuration
public class GulimallCorsConfiguration {
    @Bean
    public CorsWebFilter corsWebFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 配置跨域
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*"); // 请求来源
        corsConfiguration.setAllowCredentials(true); // cookie
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);
    }
}

逻辑删除

数据库:

在这里插入图片描述

application.yml:【全局设置】

mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-field: deleted # 全局逻辑删除的实体字段名
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

Model:【局部设置】

@Data
@TableName("pms_category")
public class CategoryEntity implements Serializable {
	// ...
    /**
     * 是否显示[0-不显示,1显示]
     */
    @TableLogic(value = "1", delval = "0")
    private Integer showStatus;
}

Controller:

@RestController
@RequestMapping("product/category")
public class CategoryController {
    /**
     * 删除
     * @RequestBody:获取请求体,必须发送POST请求
     * SpringMVC自动将请求体的数据(json),转为对应的对象
     */
    @RequestMapping("/delete")
    //@RequiresPermissions("product:category:delete")
    public R delete(@RequestBody Long[] catIds){

        //categoryService.removeByIds(Arrays.asList(catIds));

        categoryService.removeMenuByIds(Arrays.asList(catIds));

        return R.ok();
    }
}

ServiceImpl:

@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
    @Override
    public void removeMenuByIds(List<Long> asList) {
        //TODO 检查当前删除的菜单,是否被别的地方引用
        
        //逻辑删除
        baseMapper.deleteBatchIds(asList);
    }
}

文件存储

普通上传

在这里插入图片描述

在这里插入图片描述

云存储

在这里插入图片描述

阿里云OSS

https://www.aliyun.com/product/oss
https://help.aliyun.com/product/31815.html

简介

阿里云对象存储OSS(Object Storage Service)为您提供基于网络的数据存取服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音视频在内的各类数据文件。
OSS视频简介:https://static-aliyun-doc.oss-cn-hangzhou.aliyuncs.com/file-manage-files/zh-CN/20220727/ttob/OSS%E6%96%B0%E7%89%88%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89.mp4

  • 阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,可提供99.9999999999%(12个9)的数据持久性,99.995%的数据可用性。多种存储类型供选择,全面优化存储成本。

  • OSS具有与平台无关的RESTful API接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。

  • 您可以使用阿里云提供的API、SDK接口或者OSS迁移工具轻松地将海量数据移入或移出阿里云OSS。数据存储到阿里云OSS以后,您可以选择标准存储(Standard)作为移动应用、大型网站、图片分享或热点音视频的主要存储方式,也可以选择成本更低、存储期限更长的低频访问存储(Infrequent Access)、归档存储(Archive)、冷归档存储(Cold Archive)作为不经常访问数据的存储方式。

术语

中文英文说明
存储空间Bucket存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。
对象/文件Object对象是 OSS 存储数据的基本单元,也被称为OSS的文件。对象由元信息(Object Meta)、用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。
地域Region地域表示 OSS 的数据中心所在物理位置。您可以根据费用、请求来源等综合选择数据存储的地域。详情请查看OSS已经开通的Region。
访问域名EndpointEndpoint 表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。具体的内容请参见各个Region对应的Endpoint。
访问密钥AccessKeyAccessKey,简称 AK,指的是访问身份验证中用到的AccessKeyId 和AccessKeySecret。OSS通过使用AccessKeyId 和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标识用户,AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,其中AccessKeySecret 必须保密。

建议:一个项目创建一个Bucket

简单使用

  • 创建一个AccessKey,只用于“OpenAPI 调用访问”,并分配“AliyunOSSFullAccess”权限

  • 创建一个Bucket,存储类型为“低频访问存储”,读写权限为“公共读”

  • 简单的文件上传:

            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>3.5.0</version>
            </dependency>
    
        @Test
        public void testUpload() throws Exception {
            // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
            String endpoint = "xxx";
            // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
            String accessKeyId = "xxx";
            String accessKeySecret = "xxx";
            // 填写Bucket名称,例如examplebucket。
            String bucketName = "xxx";
            // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
            String objectName = "mengwa.jpg";
            // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
            // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
            String filePath = "C:\\Users\\lpruoyu\\Pictures\\Saved Pictures\\mengwa.jpg";
    
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    
            try {
                InputStream inputStream = new FileInputStream(filePath);
                // 创建PutObject请求。
                ossClient.putObject(bucketName, objectName, inputStream);
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
        }
    

使用SpringCloudAlibaba—oss

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
        </dependency>
spring:
  cloud:
    alicloud:
      access-key: xxx
      secret-key: xxx
      oss:
        endpoint: xxx
    @Autowired
    OSSClient ossClient;

    @Test
    public void testUpload() throws Exception {
        String bucketName = "xxx";
        String objectName = "chumen.png";
        String filePath = "C:\\Users\\lpruoyu\\Pictures\\Saved Pictures\\chumen.png";
        try {
            InputStream inputStream = new FileInputStream(filePath);
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, inputStream);
        } catch (Exception e) {
            System.out.println("Exception:" + e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

服务端签名后直传

普通上传方式:

在这里插入图片描述

服务端签名后直传:

在这里插入图片描述

在这里插入图片描述

实现:

创建跨域规则:

在这里插入图片描述

@RestController
public class OssController {
    @Autowired
    OSS ossClient;

    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endpoint;
    @Value("${spring.cloud.alicloud.oss.bucket}")
    private String bucket;
    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;

    @RequestMapping("/oss/policy")
    public R policy() {

        //https://gulimall-hellolp.oss-cn-hangzhou.aliyuncs.com/chumen.png

        String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
        // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
//        String callbackUrl = "http://88.88.88.88:8888";
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format + "/"; // 用户上传文件时指定的前缀。

        Map<String, String> respMap = null;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));
        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        }

        return R.ok().put("data", respMap);
    }
}

后端校验—JSR303

前后端都需要校验

// 是接口就行(用于分组校验)
public interface AddGroup {
}
public interface UpdateGroup {
}
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 品牌id
	 */
	@NotNull(message = "修改必须指定品牌id",groups = {UpdateGroup.class})
	@Null(message = "新增不能指定id",groups = {AddGroup.class})
	@TableId
	private Long brandId;
	/**
	 * 品牌名
	 */
	@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
	private String name;
	/**
	 * 品牌logo地址
	 */
	@NotBlank(groups = {AddGroup.class})
	@URL(message = "logo必须是一个合法的url地址",groups={AddGroup.class,UpdateGroup.class})
	private String logo;
	
	/**
	 * 介绍
	 */
	private String descript;
	
	/**
	 * 显示状态[0-不显示;1-显示]
	 */
//	@Pattern()
	@NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})
  	@ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class})
	private Integer showStatus;
	
	/**
	 * 检索首字母
	 */
	@NotEmpty(groups={AddGroup.class})
	@Pattern(regexp="^[a-zA-Z]$",message = "检索首字母必须是一个字母",groups={AddGroup.class,UpdateGroup.class})
	private String firstLetter;
	
	/**
	 * 排序
	 */
	@NotNull(groups={AddGroup.class})
	@Min(value = 0,message = "排序必须大于等于0",groups={AddGroup.class,UpdateGroup.class})
	private Integer sort;

}
    @RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    // 给校验的bean后紧跟一个BindingResult,就可以获取到校验的结果
    public R save(/*@Valid*/ @Validated({AddGroup.class}) @RequestBody BrandEntity brand/*,BindingResult result*/){
//        if(result.hasErrors()){
//            Map<String,String> map = new HashMap<>();
//            //1、获取校验的错误结果
//            result.getFieldErrors().forEach((item)->{
//                //FieldError (item)
                  // 获取到错误提示
//                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();
    }
    
    /**
     * 修改
     */
    @RequestMapping("/update")
    //@RequiresPermissions("product:brand:update")
    public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand){
        brandService.updateDetail(brand);
        return R.ok();
    }

自定义校验:

        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
@Documented
@Constraint(validatedBy = { l.p.common.valid.ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{l.p.common.valid.ListValue.message}";

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

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

    int[] vals() default { };
}
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {

    private Set<Integer> set = new HashSet<>();
    //初始化方法
    @Override
    public void initialize(ListValue constraintAnnotation) {

        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);
    }
}

ValidationMessages.properties:

l.p.common.valid.ListValue.message=必须提交指定的值

使用:

    @NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})
    @ListValue(vals = {0, 1}, groups = {AddGroup.class, UpdateStatusGroup.class})
    private Integer showStatus;
    @RequestMapping("/xx")
    public R xx(@Validated(AddGroup.class) @RequestBody BrandEntity brand){
		// xxxx 
        return R.ok();
    }

统一异常处理

/***
 * 错误码和错误信息定义类
 * 1. 错误码定义规则为5为数字
 * 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
 * 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
 * 错误码列表:
 *  10: 通用
 *      001:参数格式校验
 *  11: 商品
 *  12: 订单
 *  13: 购物车
 *  14: 物流
 */
public enum BizCodeEnume {
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VAILD_EXCEPTION(10001,"参数格式校验失败");

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

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}
/**
 * 集中处理所有异常
 */
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
    @ExceptionHandler(value= MethodArgumentNotValidException.class)
    public R handleVaildException(MethodArgumentNotValidException e){
        log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();

        Map<String,String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError)->{
            errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
        });
        return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap);
    }

    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        log.error("错误:",throwable);
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}

参考

雷丰阳: Java项目《谷粒商城》Java架构师 | 微服务 | 大型电商项目).


本文完,感谢您的关注支持!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Win10安装ElasticSearch笔记

1、安装前准备条件因为ElasticSearch7.17需要JDK1.8的支持&#xff0c;首先确保你的win10已经提前安装好了jdk8的版本ElasticSearch支持的JDK最低版本是1.8.0。ElasticSearch7.17及以下的版本最低版本是JDK1.8.0ElasticSearch8.0及以上的版本最低版本是JDK162、官网下载ES安装包…

Java开发环境配置 “IntelliJ IDEA”(超详细整理,适合新手入门)

前言 &#x1f4dc; “ 作者 久绊A ” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴 目录 前言 一、IDEA的介绍 1、大概介绍 2、详细介绍 二、Intelli…

Python中的logging模块

软件开发中通过日志记录程序的运行情况是一个开发的好习惯&#xff0c;对于错误排查和系统运维都有很大帮助。Python标准库自带日志模块&#xff0c;程序的日志功能直接调用标准库的日志模块即可通过日志&#xff0c;开发者可以清楚的了解发生了哪些事件&#xff0c;包括出现了…

Linux随记(五)

一、已用statefulset创了两个nginx副本 web-0 和 web-1 &#xff0c;目的将各自容器的hostname重定向到index.html。但显示的是master节点的hostname。 怎么写才是搞成 pod里面的主机名&#xff1f;#最终解决方法&#xff1a; 在sh -c 双引号里$符号前面加上\转义。 或者 sh -…

Redis原理篇(二)网络模型

一、用户空间和内核空间 应用需要通过Linux内核与硬件交互。 内核本质也是应用&#xff0c;运行的时候也需要CPU资源、内存资源。用户应用也在消耗这些资源。 为了避免用户应用导致冲突甚至内核崩溃&#xff0c;用户应用与内核是分离的&#xff1a; 进程的寻址空间会划分为两…

《安富莱嵌入式周报》第301期:ThreadX老大离开微软推出PX5 RTOS第5代系统,支持回流焊的自焊接PCB板设计,单色屏实现多级灰度播放视频效果

往期周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 祝大家开工大吉 视频版&#xff1a; https://www.bilibili.com/video/BV1GT411o7zr 1、ThreadX老大离开微软&…

又一个开源工具搞完了,工作效率直接翻倍

&#x1f3e1; 博客首页&#xff1a;派 大 星 ⛳️ 欢迎关注 &#x1f433; 点赞 &#x1f392; 收藏 ✏️ 留言 &#x1f3a2; 本文由派大星原创编撰 &#x1f6a7; 系列专栏&#xff1a;《开源专栏》 &#x1f388; 本系列主要输出作者自创的开源项目 &#x1f517; 作品&…

JavaScript switch 语句

JavaScript switch 语句 switch 语句评估一个表达式&#xff0c;将表达式的值与case子句匹配&#xff0c;并执行与该情况相关联的语句。 举例说明 const expr Papayas; switch (expr) {case Oranges:console.log(Oranges are $0.59 a pound.);break;case Mangoes:case Papa…

力扣刷题|104.二叉树的最大深度、559.n 叉树的最大深度、111.二叉树的最小深度、222.完全二叉树的节点个数

文章目录LeetCode 104.二叉树的最大深度题目链接&#x1f517;思路LeetCode 111.二叉树的最小深度题目链接&#x1f517;思路LeetCode 222.完全二叉树的节点个数题目链接&#x1f517;普通二叉树求法针对完全二叉树解法LeetCode 104.二叉树的最大深度 题目链接&#x1f517; …

WebAssembly 助力 桌面端运行web

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.WebAssembly 是基…

缺陷分析测试人员绕不开的知识点

缺陷分析也是测试工程师需要掌握的一个能力&#xff0c;但是很多时候大家只记得要提交缺陷、统计缺陷情况&#xff0c;而忽视了缺陷分析。 其实每个项目的缺陷记录都是有很大价值的。在测试阶段分析当前缺陷情况&#xff0c;及时发现存在的问题并调整测试策略&#xff0c;才能…

区间一维dp史上最细总结(绝对干货,还不会的一定要进来)

那年初夏&#xff08;三&#xff09; 注&#xff1a;此部分仅为娱乐和引入用&#xff0c;与本文没有太大关联&#xff0c;可以跳过&#xff0c;阅读下面的正文部分。 上篇出现于&#xff1a;DFS&#xff08;深度优先搜索&#xff09;详解&#xff08;概念讲解&#xff0c;图片…

HashSet源码分析

一、HashSet继承关系 1、继承 public boolean equals(Object o) {if (o this)return true;// o没有实现Set接口&#xff0c;返回falseif (!(o instanceof Set))return false;// 向下转换Collection<?> c (Collection<?>) o;// 元素个数不相等&#xff0c;返回f…

4.组件通讯

默认情况下组件只能使用自己的状态&#xff0c;但当组件拆分的比较小的时候&#xff0c;就不可避免的使用到其他组件的状态&#xff0c;比如之前做的例子&#xff0c;当我们的发表评论区域与显示评论区域拆分为两个组件时&#xff0c;这两个组件之间一定要进行通讯以达成某些功…

π122M30代替Si8621AB-B-IS 低功耗,高能效、抗干扰能力好的 双通道数字隔离器解决方案

π122M30代替Si8621AB-B-IS 低功耗&#xff0c;高能效、抗干扰能力好的解决方案电路简单、稳定性更高 &#xff0c;具有出色的性能特征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器产品。 产品传输通道间彼此独立&#xff0c;可实现多种传输方向的配置&…

Day11 C++STL入门基础知识八——stack、queue容器 基本概念-常用接口 【全面深度剖析+例题代码展示】

&#x1f483;&#x1f3fc; 本人简介&#xff1a;男 &#x1f476;&#x1f3fc; 年龄&#xff1a;18 &#x1f6a9; 今日留言&#xff1a;亮亮被迫去练科目二啦&#xff0c;定时发布的文章&#xff0c;回来统一给大家三连回复嗷~&#x1f609; 文章目录1. stack容器——栈1.…

CSDN常见问题汇总

1.怎么申请退款&#xff1f; 通过CSDN平台购买的“VIP会员、余额”&#xff0c;在刚购买后未使用的情况可支持退款&#xff1b; “付费资源、付费专栏、盲盒、魔盒、课程、C认证”等虚拟商品一经购买后&#xff0c;除了特殊原因外&#xff0c;概不支持退款&#xff1b; 特殊原…

美团8年测试经验,一文手把手教你抒写接口测试框架集成测试报告

在接口自动化测试完成后&#xff0c;通常我们都需要一个测试报告来进行结果展示&#xff0c;而测试报告的美观程度直接决定了你在同事和领导眼中的技术形象&#xff0c;本文将介绍rest-assured接口测试框架集成ExtentReports测试报告&#xff0c;让你的框架更加完美。 ExtentR…

【大唐杯备考】——5G网元功能与接口(学习笔记)

&#x1f4d6; 前言&#xff1a;本期介绍5G网元功能与接口。 目录&#x1f552; 1. 5G移动通信系统整体网络架构&#x1f558; 1.1 5G核心网架构&#x1f558; 1.2 5G接入网架构&#x1f552; 2. 5G主要网元功能&#x1f558; 2.1 UPF&#xff08;用户面功能&#xff09;&#…

使用code-server为Docker容器搭建在线开发环境

Code-server是一个基于服务端的开源VSCode。只要服务器端配置好code-server&#xff0c;就可以在任何浏览器上使用VScode访问服务器的代码进行编程。&#xff08;GitHub地址&#xff1a;https://github.com/cdr/code-server&#xff09; Docker是一个开源的Linux容器引擎。我们…