当前位置: 首页 > news >正文

替换if...else的锦囊妙计

目录

前言

一、又臭又长的if...else

二、消除if...else的锦囊妙计

1、使用注解

2、动态拼接名称

3、模板方法判断

4.策略+工厂模式

5.责任链模式

6、其他的消除if...else的方法

1.根据不同的数字返回不同的字符串

2.集合中的判断

3.简单的判断

4.spring中的判断


原文:9条消除if...else的锦囊妙计,助你写出更优雅的代码

前言

最近在做代码重构,发现了很多代码的烂味道。其他的不多说,今天主要说说那些又臭又长的if...else要如何重构。

在介绍更更优雅的编程之前,让我们一起回顾一下,不好的if...else代码

一、又臭又长的if...else

废话不多说,先看看下面的代码。

public interface IPay {  void pay();  
}  @Service  
public class AliaPay implements IPay {  @Override  public void pay() {  System.out.println("===发起支付宝支付===");  }  
}  @Service  
public class WeixinPay implements IPay {  @Override  public void pay() {  System.out.println("===发起微信支付===");  }  
}  @Service  
public class JingDongPay implements IPay {  @Override  public void pay() {  System.out.println("===发起京东支付===");  }  
}  @Service  
public class PayService {  @Autowired  private AliaPay aliaPay;  @Autowired  private WeixinPay weixinPay;  @Autowired  private JingDongPay jingDongPay;  public void toPay(String code) {  if ("alia".equals(code)) {  aliaPay.pay();  } else if ("weixin".equals(code)) {  weixinPay.pay();  } else if ("jingdong".equals(code)) {  jingDongPay.pay();  } else {  System.out.println("找不到支付方式");  }  }  
}

PayService类的toPay方法主要是为了发起支付,根据不同的code,决定调用用不同的支付类(比如:aliaPay)的pay方法进行支付。

这段代码有什么问题呢?也许有些人就是这么干的。

试想一下,如果支付方式越来越多,比如:又加了百度支付、美团支付、银联支付等等,就需要改toPay方法的代码,增加新的else...if判断,判断多了就会导致逻辑越来越多?

很明显,这里违法了设计模式六大原则的:开闭原则 和 单一职责原则

开闭原则:对扩展开放,对修改关闭。就是说增加新功能要尽量少改动已有代码。

单一职责原则:顾名思义,要求逻辑尽量单一,不要太复杂,便于复用。

那有什么办法可以解决这个问题呢?

二、消除if...else的锦囊妙计

1、使用注解

代码中之所以要用code判断使用哪个支付类,是因为code和支付类没有一个绑定关系,如果绑定关系存在了,就可以不用判断了。

我们先定义一个注解。

@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.TYPE)  
public @interface PayCode {  String value();    String name();  
}

在所有的支付类上都加上该注解

@PayCode(value = "alia", name = "支付宝支付")  
@Service  
public class AliaPay implements IPay {  @Override  public void pay() {  System.out.println("===发起支付宝支付===");  }  
}  @PayCode(value = "weixin", name = "微信支付")  
@Service  
public class WeixinPay implements IPay {  @Override  public void pay() {  System.out.println("===发起微信支付===");  }  
} @PayCode(value = "jingdong", name = "京东支付")  
@Service  
public class JingDongPay implements IPay {  @Override  public void pay() {  System.out.println("===发起京东支付===");  }  
}

然后增加最关键的类:

@Service  
public class PayService2 implements ApplicationListener<ContextRefreshedEvent> {  private static Map<String, IPay> payMap = null;  @Override  public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {  ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();  Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class);  if (beansWithAnnotation != null) {  payMap = new HashMap<>();  beansWithAnnotation.forEach((key, value) ->{  String bizType = value.getClass().getAnnotation(PayCode.class).value();  payMap.put(bizType, (IPay) value);  });  }  }  public void pay(String code) {  payMap.get(code).pay();  }  
}

PayService2类实现了ApplicationListener接口,这样在onApplicationEvent方法中,就可以拿到ApplicationContext的实例。我们再获取打了PayCode注解的类,放到一个map中,map中的key就是PayCode注解中定义的value,跟code参数一致,value是支付类的实例。

这样,每次就可以每次直接通过code获取支付类实例,而不用if...else判断了。如果要加新的支付方法,只需在支付类上面打上PayCode注解定义一个新的code即可。

注意:这种方式的code可以没有业务含义,可以是纯数字,只有不重复就行。

2、动态拼接名称

该方法主要针对code是有业务含义的场景。

@Service  
public class PayService3 implements ApplicationContextAware {   private ApplicationContext applicationContext;  private static final String SUFFIX = "Pay";  @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  this.applicationContext = applicationContext;  }  public void toPay(String payCode) {  ((IPay) applicationContext.getBean(getBeanName(payCode))).pay();  }  public String getBeanName(String payCode) {  return payCode + SUFFIX;  }  
}

我们可以看到,支付类bean的名称是由code和后缀拼接而成,比如:aliaPay、weixinPay和jingDongPay。这就要求支付类取名的时候要特别注意,前面的一段要和code保持一致。调用的支付类的实例是直接从ApplicationContext实例中获取的,默认情况下bean是单例的,放在内存的一个map中,所以不会有性能问题。

特别说明一下,这种方法实现了ApplicationContextAware接口跟上面的ApplicationListener接口不一样,是想告诉大家获取ApplicationContext实例的方法不只一种。

3、模板方法判断

当然除了上面介绍的两种方法之外,spring的源码实现中也告诉我们另外一种思路,解决if...else问题。

我们先一起看看spring AOP的部分源码,看一下DefaultAdvisorAdapterRegistrywrap方法

 public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {  if (adviceObject instanceof Advisor) {  return (Advisor) adviceObject;  }  if (!(adviceObject instanceof Advice)) {  throw new UnknownAdviceTypeException(adviceObject);  }  Advice advice = (Advice) adviceObject;  if (advice instanceof MethodInterceptor) {    return new DefaultPointcutAdvisor(advice);  }  for (AdvisorAdapter adapter : this.adapters) {  if (adapter.supportsAdvice(advice)) {  return new DefaultPointcutAdvisor(advice);  }  }  throw new UnknownAdviceTypeException(advice);  }

重点看看supportAdvice方法,有三个类实现了这个方法。我们随便抽一个类看看

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {  @Override  public boolean supportsAdvice(Advice advice) {  return (advice instanceof AfterReturningAdvice);  }  @Override  public MethodInterceptor getInterceptor(Advisor advisor) {  AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();  return new AfterReturningAdviceInterceptor(advice);  }   
}

该类的supportsAdvice方法非常简单,只是判断了一下advice的类型是不是AfterReturningAdvice

我们看到这里应该有所启发。

其实,我们可以这样做,定义一个接口或者抽象类,里面有个support方法判断参数传的code是否自己可以处理,如果可以处理则走支付逻辑。

public interface IPay {  boolean support(String code);   void pay();  
}  @Service  
public class AliaPay implements IPay {   @Override  public boolean support(String code) {  return "alia".equals(code);  }  @Override  public void pay() {  System.out.println("===发起支付宝支付===");  }  
}  @Service  
public class WeixinPay implements IPay {  @Override  public boolean support(String code) {  return "weixin".equals(code);  }  @Override  public void pay() {  System.out.println("===发起微信支付===");  }  
}  @Service  
public class JingDongPay implements IPay {  @Override  public boolean support(String code) {  return "jingdong".equals(code);  }  @Override  public void pay() {  System.out.println("===发起京东支付===");  }  
}

每个支付类都有一个support方法,判断传过来的code是否和自己定义的相等。

@Service  
public class PayService4 implements ApplicationContextAware, InitializingBean {  private ApplicationContext applicationContext;  private List<IPay> payList = null;  @Override  public void afterPropertiesSet() throws Exception {  if (payList == null) {  payList = new ArrayList<>();  Map<String, IPay> beansOfType = applicationContext.getBeansOfType(IPay.class);  beansOfType.forEach((key, value) -> payList.add(value));  }  }  @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  this.applicationContext = applicationContext;  }  public void toPay(String code) {  for (IPay iPay : payList) {  if (iPay.support(code)) {  iPay.pay();  }  }  }  
}

这段代码中先把实现了IPay接口的支付类实例初始化到一个list集合中,返回在调用支付接口时循环遍历这个list集合,如果code跟自己定义的一样,则调用当前的支付类实例的pay方法。

4.策略+工厂模式

这种方式也是用于code是有业务含义的场景。

  • 策略模式定义了一组算法,把它们一个个封装起来, 并且使它们可相互替换。

  • 工厂模式用于封装和管理对象的创建,是一种创建型模式。

public interface IPay {void pay();
}@Service
public class AliaPay implements IPay {@PostConstructpublic void init() {PayStrategyFactory.register("aliaPay", this);}@Overridepublic void pay() {System.out.println("===发起支付宝支付===");}}@Service
public class WeixinPay implements IPay {@PostConstructpublic void init() {PayStrategyFactory.register("weixinPay", this);}@Overridepublic void pay() {System.out.println("===发起微信支付===");}
}@Service
public class JingDongPay implements IPay {@PostConstructpublic void init() {PayStrategyFactory.register("jingDongPay", this);}@Overridepublic void pay() {System.out.println("===发起京东支付===");}
}public class PayStrategyFactory {private static Map<String, IPay> PAY_REGISTERS = new HashMap<>();public static void register(String code, IPay iPay) {if (null != code && !"".equals(code)) {PAY_REGISTERS.put(code, iPay);}}public static IPay get(String code) {return PAY_REGISTERS.get(code);}
}@Service
public class PayService3 {public void toPay(String code) {PayStrategyFactory.get(code).pay();}
}

这段代码的关键是PayStrategyFactory类,它是一个策略工厂,里面定义了一个全局的map,在所有IPay的实现类中注册当前实例到map中,然后在调用的地方通过PayStrategyFactory类根据code从map获取支付类实例即可。

5.责任链模式

这种方式在代码重构时用来消除if...else非常有效。

  • 责任链模式:将请求的处理对象像一条长链一般组合起来,形成一条对象链。请求并不知道具体执行请求的对象是哪一个,这样就实现了请求与处理对象之间的解耦。

常用的filterspring aop就是使用了责任链模式,这里我稍微改良了一下,具体代码如下:

public abstract class PayHandler {@Getter@Setterprotected PayHandler next;public abstract void pay(String pay);}@Service
public class AliaPayHandler extends PayHandler {@Overridepublic void pay(String code) {if ("alia".equals(code)) {System.out.println("===发起支付宝支付===");} else {getNext().pay(code);}}}@Service
public class WeixinPayHandler extends PayHandler {@Overridepublic void pay(String code) {if ("weixin".equals(code)) {System.out.println("===发起微信支付===");} else {getNext().pay(code);}}
}@Service
public class JingDongPayHandler extends PayHandler {@Overridepublic void pay(String code) {if ("jingdong".equals(code)) {System.out.println("===发起京东支付===");} else {getNext().pay(code);}}
}@Service
public class PayHandlerChain implements ApplicationContextAware, InitializingBean {private ApplicationContext applicationContext;private PayHandler header;public void handlePay(String code) {header.pay(code);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic void afterPropertiesSet() throws Exception {Map<String, PayHandler> beansOfTypeMap = applicationContext.getBeansOfType(PayHandler.class);if (beansOfTypeMap == null || beansOfTypeMap.size() == 0) {return;}List<PayHandler> handlers = beansOfTypeMap.values().stream().collect(Collectors.toList());for (int i = 0; i < handlers.size(); i++) {PayHandler payHandler = handlers.get(i);if (i != handlers.size() - 1) {payHandler.setNext(handlers.get(i + 1));}}header = handlers.get(0);}
}

这段代码的关键是每个PayHandler的子类,都定义了下一个需要执行的PayHandler子类,构成一个链式调用,通过PayHandlerChain把这种链式结构组装起来。

6、其他的消除if...else的方法

当然实际项目开发中使用if...else判断的场景非常多,上面只是其中几种场景。下面再列举一下,其他常见的场景。

1.根据不同的数字返回不同的字符串
public String getMessage(int code) {  if (code == 1) {  return "成功";  } else if (code == -1) {  return "失败";  } else if (code == -2) {  return "网络超时";  } else if (code == -3) {  return "参数错误";  }  throw new RuntimeException("code错误");  
}

其实,这种判断没有必要,用一个枚举就可以搞定。

public enum MessageEnum {  SUCCESS(1, "成功"),  FAIL(-1, "失败"),  TIME_OUT(-2, "网络超时"),  PARAM_ERROR(-3, "参数错误");  private int code;  private String message;  MessageEnum(int code, String message) {  this.code = code;  this.message = message;  }  public int getCode() {  return this.code;  }  public String getMessage() {  return this.message;  }  public static MessageEnum getMessageEnum(int code) {  return Arrays.stream(MessageEnum.values()).filter(x -> x.code == code).findFirst().orElse(null);  }  
}

再把调用方法稍微调整一下

public String getMessage(int code) {  MessageEnum messageEnum = MessageEnum.getMessageEnum(code);  return messageEnum.getMessage();  
}

完美。

2.集合中的判断

上面的枚举MessageEnum中的getMessageEnum方法,如果不用java8的语法的话,可能要这样写

public static MessageEnum getMessageEnum(int code) {  for (MessageEnum messageEnum : MessageEnum.values()) {  if (code == messageEnum.code) {  return messageEnum;  }  }  return null;  
}

对于集合中过滤数据,或者查找方法,java8有更简单的方法消除if...else判断。

public static MessageEnum getMessageEnum(int code) {  return Arrays.stream(MessageEnum.values()).filter(x -> x.code == code).findFirst().orElse(null);  
}
3.简单的判断

其实有些简单的if...else完全没有必要写,可以用三目运算符代替,比如这种情况:

public String getMessage2(int code) {  if(code == 1) {  return  "成功";  }  return "失败";  
}

改成三目运算符:

public String getMessage2(int code) {  return code == 1 ? "成功" : "失败";  
}

修改之后代码更简洁一些。

4.spring中的判断

对于参数的异常,越早被发现越好,在spring中提供了Assert用来帮助我们检测参数是否有效。

 public void save(Integer code,String name) {  if(code == null) {throw Exception("code不能为空");     } else {if(name == null) {throw Exception("name不能为空");     } else {System.out.println("doSave");}}}

如果参数非常多的话,if...else语句会很长,这时如果改成使用Assert类判断,代码会简化很多:

 public String save2(Integer code,String name) {      Assert.notNull(code,"code不能为空"); Assert.notNull(name,"name不能为空"); System.out.println("doSave");}

当然,还有很多其他的场景可以优化if...else,我再这里就不一一介绍了,感兴趣的朋友可以给我留言,一起探讨和研究一下

相关文章:

替换if...else的锦囊妙计

目录 前言 一、又臭又长的if...else 二、消除if...else的锦囊妙计 1、使用注解 2、动态拼接名称 3、模板方法判断 4.策略工厂模式 5.责任链模式 6、其他的消除if...else的方法 1.根据不同的数字返回不同的字符串 2.集合中的判断 3.简单的判断 4.spring中的判断 原文…...

新建一个flask项目

在Flask中创建一个新的项目&#xff0c;您可以遵循以下步骤&#xff1a; 确保您已经安装了Python环境。如果还未安装Flask&#xff0c;可以通过pip来安装&#xff1a; pip install flask创建一个新的文件夹作为您的项目文件夹&#xff0c;例如myflaskapp&#xff1a; mkdir …...

【Linux 内核源码分析】物理内存组织结构

多处理器系统两种体系结构&#xff1a; 非一致内存访问&#xff08;Non-Uniform Memory Access&#xff0c;NUMA&#xff09;&#xff1a;这种体系结构下&#xff0c;内存被划分成多个内存节点&#xff0c;每个节点由不同的处理器访问。访问一个内存节点所需的时间取决于处理器…...

力扣日记2.21-【回溯算法篇】46. 全排列

力扣日记&#xff1a;【回溯算法篇】46. 全排列 日期&#xff1a;2023.2.21 参考&#xff1a;代码随想录、力扣 46. 全排列 题目描述 难度&#xff1a;中等 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&…...

[AIGC] Kafka 消费者的实现原理

在 Kafka 中&#xff0c;消费者通过订阅主题来消费数据。每个消费者都属于一个消费者组&#xff0c;消费者组中的多个消费者可以共同消费一个主题&#xff0c;实现分布式消费。每个消费者都会维护自己的偏移量&#xff0c;用于记录已经读取到的消息位置。消费者可以选择手动提交…...

Dubbo框架admin搭建

Dubbo服务监控平台&#xff0c;dubbo-admin是图形化的服务管理界面&#xff0c;从服务注册中心获取所有的提供者和消费者的配置。 dubbo-admin是前后端分离的项目&#xff0c;前端使用Vue&#xff0c;后端使用springboot。因此&#xff0c;前端需要nodejs环境&#xff0c;后端需…...

Linux 内存top命令详解

通过top命令可以监控当前机器的内存实时使用情况&#xff0c;该命令的参数解释如下&#xff1a; 第一行 15:30:14 —— 当前系统时间 up 1167 days, 5:02 —— 系统已经运行的时长&#xff0c;格式为时:分 1 users ——当前有1个用户登录系统 load average: 0.00, 0.01, 0.05…...

OCP使用CLI创建和构建应用

文章目录 环境登录创建project赋予查看权限部署第一个image创建route检查pod扩展应用 部署一个Python应用连接数据库创建secret加载数据并显示国家公园地图 清理参考 环境 RHEL 9.3Red Hat OpenShift Local 2.32 登录 通过 crc console --credentials 可以查看登录信息&…...

Chrome关闭时出现弹窗runtime error c++R6052,且无法关闭

环境&#xff1a; Chrome 版本121 Win10专业版 问题描述&#xff1a; Chrome关闭时出现弹窗runtime error cR6052&#xff0c;且无法关闭 解决方案&#xff1a; 1.任务管理器打开&#xff0c;强制结束进程 2.再次打开谷歌浏览器&#xff0c;打开设置关于Chrome&#xff0…...

【动态规划专栏】专题二:路径问题--------6.地下城游戏

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…...

flink operator 1.7 更换日志框架log4j 到logback

更换日志框架 flink 1.18 1 消除基础flink框架log4j 添加logback jar 1-1 log4j log4j-1.2-api-2.17.1.jar log4j-api-2.17.1.jar log4j-core-2.17.1.jar log4j-slf4j-impl-2.17.1.jar 1-2 logback logback-core-1.2.3.jar logback-classic-1.2.3.jar slf4j-api-1.7.25.jar2 …...

算法项目(1)—— LSTM+CNN+四种注意力对比的股票预测

本文包含什么? 项目运行的方式(包教会)项目代码(在线运行免环境配置)不通注意力的模型指标对比一些效果图运行有问题? csdn上后台随时售后.项目说明 本项目实现了基于CNN+LSTM构建模型,然后对比不同的注意力机制预测股票走势的效果。首先看一下模型结果的对比: 模型MS…...

Qt C++春晚刘谦魔术约瑟夫环问题的模拟程序

什么是约瑟夫环问题&#xff1f; 约瑟夫问题是个有名的问题&#xff1a;N个人围成一圈&#xff0c;从第一个开始报数&#xff0c;第M个将被杀掉&#xff0c;最后剩下一个&#xff0c;其余人都将被杀掉。例如N6&#xff0c;M5&#xff0c;被杀掉的顺序是&#xff1a;5&#xff…...

Typora+PicGO+腾讯云COS做图床

文章目录 Typora&#xff0b;PicGO&#xff0b;腾讯云COS做图床一、为什么使用图床二、Typora、PicGO和腾讯云COS介绍三、下载Typora和PicGOTyporaPicGO 四、配置Typora、PicGO和腾讯云COS腾讯云COS配置PicGO配置Typora配置 Typora&#xff0b;PicGO&#xff0b;腾讯云COS做图床…...

WebStorm | 如何修改webstorm中新建html文件默认生成模板中title的初始值

在近期的JS的学习中&#xff0c;使用webstorm&#xff0c;总是要先新建一个html文件&#xff0c;然后再到里面书写<script>标签&#xff0c;真是麻烦&#xff0c;而且标题也是默认的title&#xff0c;想改成文件名还总是需要手动去改 经过小小的研究&#xff0c;找到了修…...

大厂的数据质量中心系统设计

日常工作中&#xff0c;数据开发上线完一个任务后并不是就可以高枕无忧&#xff0c;时常因上游链路数据异常或者自身处理逻辑的 BUG 导致产出的数据结果不可信。而问题发现可经历较长周期&#xff08;尤其离线场景&#xff09;&#xff0c;往往是业务方通过上层数据报表发现数据…...

docker (一)-简介

1.什么是docker Docker 是一个开源的应用容器引擎&#xff0c;由于docker影响巨大&#xff0c;今天也用"Docker" 指代容器化技术。 2.docker的优势 一键部署&#xff0c;开箱即用 容器使用基于image镜像的部署模式&#xff0c;image中包含了运行应用程序所需的一…...

全国乙卷高考理科数学近年真题的选择题练一练和解析

虽然很多中小学才陆陆续续开学&#xff0c;但是高三的学子们一定是过年的时候也在抓紧备考&#xff0c;毕竟&#xff0c;距离2024年高考只剩下不到四个月了。 如何在最后四个月的时间提高成绩&#xff1f;以高考真题为抓手是一个不错的方法&#xff0c;因为真题都是严格遵循考试…...

uniapp运动课程健身打卡系统微信小程序

考虑到实际生活中在我来运动管理方面的需要以及对该系统认真的分析,将系统分为小程序端模块和后台管理员模块&#xff0c;权限按管理员和用户这两类涉及用户划分。 (a) 管理员&#xff1b;管理员使用本系统涉到的功能主要有&#xff1a;首页、个人中心、用户管理、课程类别管理…...

IP详细地理位置查询:技术原理与应用实践

IP地址是互联网上设备的唯一标识&#xff0c;在网络安全、个性化服务等领域具有重要意义。通过IP详细地理位置查询&#xff0c;可以获取到IP地址所在地的具体信息&#xff0c;为网络管理、定位服务等提供支持。IP数据云将深入探讨IP详细地理位置查询的技术原理、应用实践以及相…...

SpringBoot2整合支付宝进行沙箱支付

目录 1. 进入支付宝的开放平台 2. 导入Maven依赖 3. 配置application.yml文件 NATAPP.cn(内网穿透工具) 注册登录 下载 4. 后端配置 5. 测试 1. 进入支付宝的开放平台 开发平台: 支付宝开放平台 登录后,点击控制台 点击最下面的沙箱 2. 导入Maven依赖 <dependency…...

世界顶级名校计算机专业,都在用哪些书当教材?

清华、北大、MIT、CMU、斯坦福的学霸们在新学期里要学什么&#xff1f;今天我们来盘点一下那些世界名校计算机专业采用的教材。 欢迎来到英杰社区&#xff1a; https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区&#xff1a; https://bbs.csdn.net/topics/617897397 &…...

Linux内核解读

来自鹅厂架构师 作者&#xff1a;aurelianliu 工作过程中遇到的调度、内存、文件、网络等可以参考。 1.os运行态 X86架构&#xff0c;用户态运行在ring3&#xff0c;内核态运行在ring0&#xff0c;两个特权等级。 &#xff08;1&#xff09;内核、一些特权指令&#xff0c;例…...

在VS里使用C#制作窗口应用

新建项目 创建项目的时候搜索net&#xff0c;选择这个。 打开应该是这样 第一个控件 选择公共控件 - PictureBox - 拖入Form 在Image处选择上传本地资源&#xff0c;建议上传一个小一点的图片。 修改一下尺寸。 ctrls 保存 从“属性”切换到“事件” 双击Click事件…...

Nginx的流式响应配置

Nginx的流式响应配置 使用ChatGPT的能力在聊天时来实现打字机效果&#xff0c;因此需要服务端接口进行流式响应&#xff0c;碰到了几个问题&#xff1a; 1、服务端明明配置了响应头的Content-Type为&#xff1a;text/event-stream&#xff0c;但前端仍然不是流式接收内容。 2、…...

Excel练习:双层图表

Excel练习&#xff1a;双层图表 学习视频Excel制作双层图表&#xff0c;很多人都不会&#xff0c;其实只需1步操作就够了&#xff01;_哔哩哔哩_bilibili ​​ 通过调整两个图形的显示范围实现 增加折现图的负数显示范围&#xff0c;使折现图仅出现在整体图形的上方增加柱形…...

2024展望龙年,索蝶音乐成立

近日,北京索蝶文化传媒有限公司在北京成立,引起了业内众多公司的关注。作为翰扬影视的兄弟公司,索蝶音乐致力于音乐、练习生两大市场的深耕及探索,立志三年内成为国内市场的主流厂牌。 公司负责人刘孝林先生表示,索蝶音乐以艺人经纪、艺人包装、音乐制作与发行、练习生选拔与培…...

什么是 Wake-on-LAN?如何使用 Splashtop 远程喊醒电脑

在当今数字互联的世界里&#xff0c;远程访问电脑已不仅仅是一种便利&#xff0c;而是许多人的需要。无论是远程工作、IT 支持&#xff0c;还是管理整个网络中的计算机群&#xff0c;我们都必须掌握正确的工具和技术。 其中一项在远程访问中发挥关键作用的技术是 Wake-on-LAN …...

正则表达式的一些高级用法

不允许出现某个单词&#xff0c;使用?! (?!Pattern).\.matches 表示.matches之前的不能是Pattern非贪婪匹配&#xff0c;在匹配项后加? matches\((.*?)\) 这里在.*后加问号&#xff0c;表示尽可能少的匹配。\w表示字母、数字和下划线防范redos攻击&#xff0c;可使用Cyber-…...

第3.1章:StarRocks数据导入——Insert into 同步模式

一、概述 在StarRocks中&#xff0c;insert的语法和mysql等数据库的语法类似&#xff0c;并且每次insert into操作都是一次完整的导入事务。 主要的 insertInto 命令包含以下两种&#xff1a; insert into tbl select ...insert into tbl (col1, col2, ...) values (1, 2, ...…...