Spring Boot 经典九设计模式全览

在Spring Boot中,设计模式的应用广泛且重要,它们有助于提高代码的可维护性、可扩展性和复用性。以下是Spring Boot中经典的9种设计模式及其代码案例:

1. 单例模式(Singleton Pattern)

在Spring中,bean默认就是单例模式。Spring通过单例注册表的方式来实现单例,即维护一个Map来存储单例类的实例。

   // 单例模式示例public class SingletonService {private static SingletonService instance;private SingletonService() {}public static SingletonService getInstance() {if (instance == null) {instance = new SingletonService();}return instance;}}

2. 工厂模式(Factory Pattern)

工厂模式用于创建对象,而无需指定创建对象的具体类。Spring Boot中可以通过@Bean注解在配置类中实现工厂方法。

1. 定义接口或抽象类
// 用户接口  
public interface ReturnUser {  List<String> getUserByType();  
} 
2. 实现接口或继承抽象类

然后,创建实现该接口或继承该抽象类的具体类。

// 机构用户实现类  
@Component  
public class OrgUserImpl implements ReturnUser {  @Override  public List<String> getUserByType() {  // 业务逻辑  return Arrays.asList("org1", "org2", "org3");  }  
} // 角色用户实现类  
@Component  
public class RoleUserImpl implements ReturnUser {  @Override  public List<String> getUserByType() {  // 业务逻辑  return Arrays.asList("role1", "role2", "role3");  }  
} 
3. 创建工厂类

接下来,创建一个工厂类,用于生成具体类的实例。

// 用户工厂类  
@Component  
public class ReturnUserFactory {  @Autowired  private OrgUserImpl orgUser;  @Autowired  private RoleUserImpl roleUser;  public ReturnUser getUserList(String module) {  switch (module) {  case "org":  return orgUser;  case "role":  return roleUser;  default:  return null;  }  }  
} 
4. 在Spring Boot中使用工厂类

你可以在你的Spring Boot应用程序中的任何地方使用工厂类来创建对象。例如,在一个控制器中:

import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RequestParam;  
import org.springframework.web.bind.annotation.RestController;  @RestController  
public class ReturnUserController {  @GetMapping("/returnUser")  public String getAnimalSound(@RequestParam String type) {  ReturnUser returnUser  = AnimalFactory.getUserList(type);  if (returnUser != null) {  returnUser.makeSound();  return "The returnUser makes the sound: " + returnUser.makeSound();  } else {  return "Unknown returnUser type";  }  }  
}

3. 代理模式(Proxy Pattern)

1. 定义接口

首先,定义一个接口,这是被代理对象必须实现的。

public interface Service {  void performTask();  
}
2. 实现接口

然后,创建一个实现该接口的具体类。

public class RealService implements Service {  @Override  public void performTask() {  System.out.println("Performing real service task.");  }  
}
3. 创建代理类

接下来,创建一个代理类,它实现了相同的接口,并在调用实际对象的方法之前或之后添加额外的行为。

public class ServiceProxy implements Service {  private final Service realService;  public ServiceProxy(Service realService) {  this.realService = realService;  }  @Override  public void performTask() {  System.out.println("Performing proxy task before real service.");  realService.performTask();  System.out.println("Performing proxy task after real service.");  }  
}
4. 在Spring Boot中使用代理

你可以在你的Spring Boot应用程序中的任何地方使用代理类。例如,在一个控制器中:

import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RestController;  @RestController  
public class ServiceController {  private final Service service;  // 你可以通过构造函数注入来传递代理对象,或者你可以直接在控制器中创建代理对象  public ServiceController(Service realService) {  this.service = new ServiceProxy(realService);  }  @GetMapping("/service")  public String getService() {  service.performTask();  return "Service task performed with proxy.";  }  
}

但是,请注意,在上面的例子中,我们并没有真正利用Spring的依赖注入来管理代理的创建。在实际应用中,你可能会希望Spring来管理这些代理对象。这可以通过使用Spring AOP(面向切面编程)来实现,它允许你在不修改源代码的情况下向现有对象添加行为。


代理模式为其他对象提供一种代理以控制对这个对象的访问。Spring AOP(面向切面编程)就是代理模式的一个应用。

// 切面类  
@Aspect  
@Component  
public class MyAspect {  @Around("execution(* com.example.service.*.*(..))")  public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {  long start = System.currentTimeMillis();  Object proceed = joinPoint.proceed();  long executionTime = System.currentTimeMillis() - start;  System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");  return proceed;  }  
}

4. 观察者模式(Observer Pattern)

在Spring Boot中使用观察者模式(Observer Pattern)可以让你构建一个能够自动通知和更新依赖对象(观察者)的系统,当某个对象(主题)的状态发生变化时。Spring Boot中的事件监听机制就是观察者模式的一个应用。

1. 定义主题接口

首先,你需要定义一个主题接口,它包含添加、移除和通知观察者的方法。

// Subject.java  
public interface Subject {  void registerObserver(Observer observer);  void removeObserver(Observer observer);  void notifyObservers();  
}
2. 实现具体的主题

接下来,实现一个具体的主题类,该类将维护一个观察者列表,并在状态变化时通知它们。

// ConcreteSubject.java  
import java.util.ArrayList;  
import java.util.List;  public class ConcreteSubject implements Subject {  private List<Observer> observers = new ArrayList<>();  private String state;  @Override  public void registerObserver(Observer observer) {  observers.add(observer);  }  @Override  public void removeObserver(Observer observer) {  observers.remove(observer);  }  @Override  public void notifyObservers() {  for (Observer observer : observers) {  observer.update(this);  }  }  public void setState(String state) {  this.state = state;  notifyObservers();  }  public String getState() {  return state;  }  
}
3. 定义观察者接口

然后,定义一个观察者接口,它包含一个更新方法,当主题状态变化时被调用。

// Observer.java  
public interface Observer {  void update(Subject subject);  
}
4. 实现具体的观察者

实现具体的观察者类,这些类将响应主题的状态变化。

// ConcreteObserver.java  
public class ConcreteObserver implements Observer {  private String name;  public ConcreteObserver(String name) {  this.name = name;  }  @Override  public void update(Subject subject) {  ConcreteSubject concreteSubject = (ConcreteSubject) subject;  System.out.println(name + " received state update: " + concreteSubject.getState());  }  
}
5. 在Spring Boot应用中使用

最后,在Spring Boot应用中使用这些类。你可以通过配置类或直接在控制器、服务等组件中实例化它们。

// ObserverPatternApplication.java  
import org.springframework.boot.CommandLineRunner;  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  @SpringBootApplication  
public class ObserverPatternApplication implements CommandLineRunner {  public static void main(String[] args) {  SpringApplication.run(ObserverPatternApplication.class, args);  }  @Override  public void run(String... args) throws Exception {  ConcreteSubject subject = new ConcreteSubject();  Observer observer1 = new ConcreteObserver("Observer 1");  Observer observer2 = new ConcreteObserver("Observer 2");  subject.registerObserver(observer1);  subject.registerObserver(observer2);  subject.setState("New State");  }  
}

在这个示例中,ObserverPatternApplication是我们的Spring Boot应用主类。它创建了一个ConcreteSubject对象,并注册了两个ConcreteObserver对象。然后,它更改主题的状态,这将触发对观察者的通知。

5. 策略模式(Strategy Pattern)

策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互换。Spring Boot中可以通过接口和不同的实现类来实现策略模式。

// 策略接口  
public interface PaymentStrategy {  void pay(double amount);  
}  // 具体策略实现类:信用卡支付  
@Component  
public class CreditCardPayment implements PaymentStrategy {  @Override  public void pay(double amount) {  System.out.println("Paid " + amount + " using Credit Card");  }  
}  // 具体策略实现类:现金支付  
@Component  
public class CashPayment implements PaymentStrategy {  @Override  public void pay(double amount) {  System.out.println("Paid " + amount + " using Cash");  }  
}  // 上下文类  
@Component  
public class PaymentContext {  @Autowired  private List<PaymentStrategy> paymentStrategies;  public void setPaymentMethod(String method) {  this.paymentMethod = method;  }  public void pay(double amount) {  for (PaymentStrategy strategy : paymentStrategies) {  if (strategy.getClass().getSimpleName().equalsIgnoreCase(this.paymentMethod)) {  strategy.pay(amount);  break;  }  }  }  private String paymentMethod;  
}

6. 模板方法模式(Template Method Pattern)

在Spring Boot中使用模板方法模式(Template Method Pattern)通常涉及创建一个抽象基类,该类定义了一个算法的框架,但将某些步骤的实现留给子类。这样,你可以在不改变算法结构的情况下,通过定义新的子类来改变算法中的某些步骤。

1. 定义抽象基类

首先,你需要创建一个抽象基类,其中包含一个模板方法(通常是final的,以防止子类覆盖它)和一些抽象方法(或钩子方法,这些可以是具体实现,但允许子类根据需要覆盖它们)。

// AbstractClass.java  
public abstract class AbstractClass {  // 模板方法,定义了算法的框架  public final void templateMethod() {  step1();  step2();  hookMethod(); // 钩子方法,允许子类在必要时提供自己的实现  step3();  }  // 抽象方法,由子类实现  protected abstract void step1();  protected abstract void step3();  // 钩子方法,有默认实现,但允许子类覆盖  protected void hookMethod() {  // 默认实现为空,或者提供一些通用的行为  }  // 具体方法,可以包含一些算法的通用步骤  private void step2() {  // 这里是算法的一个具体步骤,通常不需要子类覆盖  }  
}
2. 实现具体子类

然后,你需要创建具体子类,这些子类将提供模板方法中抽象方法和钩子方法的具体实现。

// ConcreteClassA.java  
public class ConcreteClassA extends AbstractClass {  @Override  protected void step1() {  System.out.println("ConcreteClassA implementation of step1");  }  @Override  protected void step3() {  System.out.println("ConcreteClassA implementation of step3");  }  // 可以选择覆盖钩子方法以提供额外的行为  // @Override  // protected void hookMethod() {  //     System.out.println("ConcreteClassA implementation of hookMethod");  // }  
}  // ConcreteClassB.java  
public class ConcreteClassB extends AbstractClass {  @Override  protected void step1() {  System.out.println("ConcreteClassB implementation of step1");  }  @Override  protected void step3() {  System.out.println("ConcreteClassB implementation of step3");  }  // 覆盖钩子方法以提供不同的行为  @Override  protected void hookMethod() {  System.out.println("ConcreteClassB implementation of hookMethod");  }  
}
3. 在Spring Boot应用中使用

最后,在你的Spring Boot应用中,你可以像使用任何其他Spring Bean一样使用这些具体子类。你可以通过配置类、@Component注解或直接在控制器、服务等组件中实例化它们。

// TemplateMethodPatternApplication.java  
import org.springframework.boot.CommandLineRunner;  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  @SpringBootApplication  
public class TemplateMethodPatternApplication implements CommandLineRunner {  public static void main(String[] args) {  SpringApplication.run(TemplateMethodPatternApplication.class, args);  }  @Override  public void run(String... args) throws Exception {  AbstractClass concreteClassA = new ConcreteClassA();  AbstractClass concreteClassB = new ConcreteClassB();  // 调用模板方法  concreteClassA.templateMethod();  concreteClassB.templateMethod();  }  
}

在这个示例中,TemplateMethodPatternApplication是我们的Spring Boot应用主类。它创建了两个具体子类的实例,并调用了它们的模板方法。这将按照算法框架执行,并使用子类提供的具体实现。

请注意,虽然在这个例子中我们没有将AbstractClass及其子类作为Spring Bean来管理,但在实际的应用中,你可能会希望这样做以便利用Spring的依赖注入功能。你可以通过添加@Component注解并使用@Autowired@Bean注解来将这些类集成到Spring的上下文中。

7. 适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的类一起工作。在Spring Boot应用中,你可以使用适配器模式来适配不同接口或类的实现,以便它们可以无缝地协同工作。

下面是一个如何在Spring Boot中使用适配器模式的示例。

假设我们有一个旧的支付服务(LegacyPaymentService),它的接口和新支付服务(NewPaymentService)的接口不兼容。我们需要一个适配器来使它们可以一起工作。

1. 定义旧的支付服务接口和实现

首先,我们定义一个旧的支付服务接口及其实现:

// LegacyPaymentService.java  
public interface LegacyPaymentService {  void makeLegacyPayment(double amount);  
}  // LegacyPaymentServiceImpl.java  
public class LegacyPaymentServiceImpl implements LegacyPaymentService {  @Override  public void makeLegacyPayment(double amount) {  System.out.println("Making legacy payment of: " + amount);  }  
}
2. 定义新的支付服务接口和实现

接下来,我们定义一个新的支付服务接口及其实现:

// NewPaymentService.java  
public interface NewPaymentService {  void makePayment(double amount);  
}  // NewPaymentServiceImpl.java  
public class NewPaymentServiceImpl implements NewPaymentService {  @Override  public void makePayment(double amount) {  System.out.println("Making new payment of: " + amount);  }  
}
3. 创建适配器类

现在,我们需要创建一个适配器类,它将旧的支付服务适配为新的支付服务:

// LegacyPaymentServiceAdapter.java  
public class LegacyPaymentServiceAdapter implements NewPaymentService {  private LegacyPaymentService legacyPaymentService;  public LegacyPaymentServiceAdapter(LegacyPaymentService legacyPaymentService) {  this.legacyPaymentService = legacyPaymentService;  }  @Override  public void makePayment(double amount) {  legacyPaymentService.makeLegacyPayment(amount);  }  
}
4. 使用Spring Boot配置和测试

最后,我们在Spring Boot应用中配置这些类并进行测试。


import org.springframework.boot.CommandLineRunner;  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
import org.springframework.context.annotation.Bean;  @SpringBootApplication  
public class PaymentServiceApplication implements CommandLineRunner {  public static void main(String[] args) {  SpringApplication.run(PaymentServiceApplication.class, args);  }  @Bean  public LegacyPaymentService legacyPaymentService() {  return new LegacyPaymentServiceImpl();  }  @Bean  public NewPaymentService newPaymentService(LegacyPaymentService legacyPaymentService) {  return new LegacyPaymentServiceAdapter(legacyPaymentService);  }  @Override  public void run(String... args) throws Exception {  NewPaymentService paymentService = newPaymentService();  paymentService.makePayment(100.0);  }  
}

在这个示例中,PaymentServiceApplication类是我们的Spring Boot应用主类。它定义了两个Bean:legacyPaymentServicenewPaymentServicenewPaymentService是通过LegacyPaymentServiceAdapter适配的legacyPaymentService

当运行Spring Boot应用时,run方法会被调用,并且适配器会将新的支付请求转换为旧的支付请求,并输出相应的日志。

8. 装饰者模式(Decorator Pattern)

装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你动态地将责任附加到对象上,而无需修改其现有的代码。在Spring Boot应用中,你可以使用装饰者模式来增强或修改对象的行为,而无需使用继承或创建大量的子类。

1. 定义组件接口

首先,我们定义一个接口,该接口将作为要装饰的对象的基类或接口。

// PaymentComponent.java  
public interface PaymentComponent {  void pay(double amount);  
}
2. 实现基础组件

接下来,我们实现这个接口的基础版本,即不添加任何装饰的组件。

// SimplePayment.java  
public class SimplePayment implements PaymentComponent {  @Override  public void pay(double amount) {  System.out.println("Paid: " + amount);  }  
}
3. 创建装饰者基类

现在,我们创建一个装饰者基类,它实现了相同的接口,并持有一个被装饰对象的引用。

// PaymentDecorator.java  
public abstract class PaymentDecorator implements PaymentComponent {  protected PaymentComponent paymentComponent;  public PaymentDecorator(PaymentComponent paymentComponent) {  this.paymentComponent = paymentComponent;  }  @Override  public abstract void pay(double amount);  
}
4. 实现具体的装饰者

然后,我们实现具体的装饰者,这些装饰者将添加额外的行为或修改现有行为。

// LoggingPaymentDecorator.java  
public class LoggingPaymentDecorator extends PaymentDecorator {  public LoggingPaymentDecorator(PaymentComponent paymentComponent) {  super(paymentComponent);  }  @Override  public void pay(double amount) {  System.out.println("Logging payment of: " + amount);  paymentComponent.pay(amount);  }  
}  // TaxPaymentDecorator.java  
public class TaxPaymentDecorator extends PaymentDecorator {  private double taxRate;  public TaxPaymentDecorator(PaymentComponent paymentComponent, double taxRate) {  super(paymentComponent);  this.taxRate = taxRate;  }  @Override  public void pay(double amount) {  double totalAmount = amount * (1 + taxRate);  System.out.println("Applying tax rate of " + (taxRate * 100) + "%");  paymentComponent.pay(totalAmount);  }  
}
5. 使用Spring Boot配置和测试

最后,我们在Spring Boot应用中配置这些类并进行测试。

// PaymentServiceApplication.java  
import org.springframework.boot.CommandLineRunner;  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
import org.springframework.context.annotation.Bean;  @SpringBootApplication  
public class PaymentServiceApplication implements CommandLineRunner {  public static void main(String[] args) {  SpringApplication.run(PaymentServiceApplication.class, args);  }  @Bean  public PaymentComponent simplePayment() {  return new SimplePayment();  }  @Bean  public PaymentComponent decoratedPayment(PaymentComponent simplePayment, double taxRate) {  PaymentComponent loggingPayment = new LoggingPaymentDecorator(simplePayment);  return new TaxPaymentDecorator(loggingPayment, taxRate);  }  @Override  public void run(String... args) throws Exception {  PaymentComponent paymentComponent = decoratedPayment(simplePayment(), 0.10); // 10% tax rate  paymentComponent.pay(100.0);  }  
}

在这个示例中,PaymentServiceApplication类是我们的Spring Boot应用主类。它定义了两个Bean:simplePaymentdecoratedPaymentdecoratedPayment是通过组合LoggingPaymentDecoratorTaxPaymentDecorator来装饰simplePayment的。

然而,需要注意的是,在Spring容器中直接这样配置decoratedPaymentBean可能会有些复杂,因为我们需要传递一个double类型的taxRate参数。在实际应用中,你可能会使用配置属性、环境变量或其他方式来传递这个参数。

为了简化示例,这里直接在run方法中创建了装饰后的对象。但在实际生产环境中,你应该通过配置或注入的方式来管理这些Bean的依赖关系。

9. 原型模式(Prototype Pattern)

原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。在Spring中,可以通过实现PrototypeBeanFactory来创建原型Bean。

// 原型Bean类  
public class PrototypeBean implements Cloneable {  private String name;  public void setName(String name) {  this.name = name;  }  public String getName() {  return name;  }  @Override  protected Object clone() throws CloneNotSupportedException {  return super.clone();  }  
}  // 配置类  
@Configuration  
public class AppConfig {  @Bean  @Scope("prototype")  public PrototypeBean prototypeBean() {  return new PrototypeBean();  }  
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无人机避障——使用三维PCD点云生成的2D栅格地图PGM做路径规划

着重介绍通过对三维 PCD 点云进行处理生成 2D 栅格地图 PGM&#xff0c;而后将该 PGM 地图充分运用到无人系统路径规划之中&#xff0c;使得无人机能够依据此规划合理避开飞行路线上可能出现的障碍物。&#xff08;解决如何使用PGM的问题&#xff09; Hybrid A*算法 参考博客…

线性代数(1)——线性方程组的几何意义

线性代数的基本问题是求解个未知数的个线性方程&#xff1b; 例如&#xff1a;&#xff08;方程1&#xff09;。 在线性代数的第一讲中&#xff0c;我们从Row Picture、Column Picture、Matrix Picture三个角度来看这个问题。 上面的系统是二维的。通过添加第三个变量&#…

浮动+flex布局

一.浮动 1.介绍 2.效果 <style> .one{ width: 100px; height: 100px; background-color: red; float: left; } .two{ width: 200px; height: 200px; background-color: blue; float: right; } </style> </head> <body> <div class"one&quo…

没有对象来和我手撕红黑树吧

1. 红黑树的介绍 红黑树也是一种自平衡的二叉搜索树&#xff0c;在每一个节点增加了一个存储位来表示节点的颜色&#xff0c;可以是红色也可以是黑色&#xff0c;通过约束颜色来维持树的平衡&#xff0c;具有以下的性质&#xff1a; 每个节点不是红色就是黑色根节点为黑色如果…

深入理解gPTP时间同步过程

泛化精确时间协议(gPTP)是一个用于实现精确时间同步的协议,特别适用于分布式系统中需要高度协调的操作,比如汽车电子、工业自动化等。 gPTP通过同步主节点(Time Master)和从节点(Time Slave)的时钟,实现全局一致的时间参考。 以下是gPTP实现主从时间同步的详细过程:…

rom定制系列------红米note8_miui14安卓13定制修改固件 带面具root权限 刷写以及界面预览

&#x1f49d;&#x1f49d;&#x1f49d;红米note8机型代码&#xff1a;ginkgo。高通芯片。此固件官方最终版为稳定版12.5.5安卓11的版本。目前很多工作室需要高安卓版本的固件来适应他们的软件。并且需要root权限。根据客户要求。修改固件为完全root。并且修改为可批量刷写的…

MicroServer Gen8再玩 OCP万兆光口+IT直通之二

这个接上一篇&#xff0c;来个简单测试。 一、测试环境 PC端&#xff1a;Win10&#xff0c;网卡&#xff1a;万兆光纤&#xff08;做都做了&#xff0c;都给接上&#xff09;&#xff0c;硬盘使用N年的三星SSD 840 交换机&#xff1a;磊科GS10&#xff0c;带两个万兆口 Gen…

怎么理解ES6 Proxy

Proxy 可以理解成&#xff0c;在目标对象之前架设一层 “拦截”&#xff0c;外界对该对象的访问&#xff0c;都必须先通过这层拦截&#xff0c;因此提供了一种机制&#xff0c;可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理&#xff0c;用在这里表示由它来 “代理…

揭秘代码界的新挑战:低代码平台,为何让程序员头疼不已?

我最近在网上看到一个很有趣的话题&#xff1a;为什么程序员大多讨厌低代码&#xff1f;好家伙&#xff0c;这一下子就将低代码推到了程序员的对立面&#xff0c;两者直接到了水火不容的地步。 其实低代码倒也不是什么新鲜事物&#xff0c;它是一种只需用很少甚至不需要代码即可…

APP如何提升关键词排名?

提升关键词排名是ASO&#xff08;App Store Optimization&#xff09;策略中的关键环节&#xff0c;以下是一些有效的方法来提高App在应用商店中的关键词排名&#xff1a; 1. **关键词研究**&#xff1a; - 使用专业的ASO工具进行关键词研究&#xff0c;找出与你的App相关且…

ClickHouse 3节点集群安装

ClickHouse 简介 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。 官方网站&#xff1a;https://clickhouse.com/ 项目地址&#xff1a;https://github.com/ClickHouse/ClickHouse 横向扩展集群介绍 此示例架构旨在提供可扩展性。它包括三个节点&#xff…

基于springboot的在线投票系统,比赛实时投票平台的实现

1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a;windows 7…

UE4安卓打aab包时,同时存在“gradle”、“arm64/gradle”两个Gradle工程的原因

两个Gradle工程的现象 在出安卓aab包时&#xff0c;观察到存在以下两个Gradle工程&#xff1a; 1、Intermediate\Android\arm64\gradle &#xff08;称为arm64的Gradle&#xff09; 2、Intermediate\Android\gradle&#xff08;称为根下的Gradle&#xff09; 它们存在一些小…

在IDEA中运行Mybatis后发现取出的password值为null

问题&#xff1a; 解决方案&#xff1a;修改sql文如下&#xff08;取别名&#xff09; Select("select id,name,pwd as password from user where id #{id}") 重新运行即可

股票基础交易规则!最小变动数量规则!最大数量限制规则!

股票基础交易规则系列 数量规则 01 最小变动数量规则 沪深主板、创业板&#xff1a;单笔申报数量应当为100股或其整数倍。 科创板&#xff1a;单笔申报数量应当不小于200股&#xff0c;1股递增。 北交所&#xff1a;单笔申报数量应当不小于100股&#xff0c;1股递增。 举例…

Selenium自动化测试框架详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 设计思路 本文整理归纳以往的工作中用到的东西&#xff0c;现汇总成基础测试框架提供分享。 框架采用python3 selenium3 PO yaml ddt unittest等技术编写…

ChangeCLIP环境配置

看到有个现成的dockerfile&#xff0c;先试试 ok首先需要root权限的用户 才能用docker&#xff0c;其次要外网&#xff0c;要不然有些东西好像下载不了 &#xff08;失败&#xff09; 那就直接配吧 我看12服务器上有个openmmlab的环境&#xff0c;先基于这个环境吧 # 用lx账…

【MATLAB源码-第272期】基于matlab的OMP算法的毫米波MIMO通信系统的混合波束成形仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在现代无线通信系统中&#xff0c;随着频谱资源的日益紧张&#xff0c;毫米波&#xff08;mmWave&#xff09;技术成为5G及未来通信系统的重要组成部分。毫米波频段的宽频带提供了远超传统微波频段的频谱资源&#xff0c;能够…

【python】OpenCV—findContours(4.3)

文章目录 1、功能描述2、代码实现3、完整代码4、结果展示5、涉及到的库函数5.1、cv2.Canny5.2 cv2.boxPoints 6、参考 1、功能描述 找出图片中的轮廓&#xff0c;拟合轮廓外接椭圆和外接矩阵 2、代码实现 导入必要的库&#xff0c;固定好随机种子 import cv2 as cv import …

直播推流和拉流--系统篇

今天实现一下直播推流和拉流。服务器端使用opencloudos8系统。顺便把我之前写的小系统弄上去跑跑&#xff0c;搭建个git服务器&#xff0c;使用ssh协议&#xff0c;密钥方式。 先展示一下在iphone上推流效果图 再展示下在谷歌浏览器上的拉流效果图&#xff0c;safari浏览器和微…