首页 > 其他分享 >SpringBoot自定义Starter(二十四)

SpringBoot自定义Starter(二十四)

时间:2022-11-10 15:34:56浏览次数:68  
标签:SpringBoot 自定义 ctx animal import org public Starter


即使有一天,我放弃了自己的身体,也请你,不要放弃我,我亲爱的灵魂.

上一章简单介绍了Spring_Session解决Session共享的问题(二十三),如果没有看过,​​请观看上一章​​

一. 自定义Starter 基础知识

一.一 自定义Starter

以前我们在学习 Spring 时,依赖的依赖,都是某一个具体的依赖信息。

在Spring Boot 阶段,我们导入的依赖 的 artifactId 都拥有 starter

如: mybatis-spring-boot-starter pagehelper-spring-boot-starter 等.

这些其实,都是比较官方的自定义 Starter。

在日常开发里面,对于独立于业务模块的一些功能,常常会放置在一个单独的包里,
如 切面实现日志功能, 在项目A里面使用到了,在项目B 里面也使用到了,
以前的做法,是什么样子的呢? 通常将这个日志功能实现的代码复制A项目里面,
同时复制到B项目里面,这样 A项目便拥有了日志的功能,B项目也拥有了日志的功能。
如果实现日志功能的代码发生改变,那么项目A,项目B都需要进行修改。

如果能够将 这个切面实现日志功能的代码 提取出来,变成一个 依赖的jar包,
项目A,项目B直接导入依赖,便可以使用,那就好了。

我们可以通过自定义Starter 实现这些功能。

SpringBoot提供的starter以​​spring-boot-starter-xxx​​的方式命名的。

官方建议自定义的starter使用​​xxx-spring-boot-starter​​命名规则。以区分SpringBoot生态提供的starter。

这一章节,先简单实现一个基础的自定义Starter 的功能。

下一章节,老蝴蝶带着大家通过自定义 Starter 实现切面日志记录的功能。

一.二 自定义Starter 需要什么

我们自定义 Starter 需要什么呢? 想一想,以前的配置, 如 redis的配置,mysql数据库的配置信息.

  1. 我们需要传入一些参数,可以更改配置 (在application.yml 中配置参数) ,同时有默认的配置参数.
  2. 有一个功能实现,可以获取到用户传入的配置参数,使用这些配置参数,可以实现我们想要的功能.
  3. 动态的进行配置,热插拔效果。达到 我们拥有这个自定义starter,就拥有这些东西,没有自定义starter,就没有这些东西的效果。
  4. 自动化的配置,可以被 SpringBoot 官方识别并承认 (需要固定的格式).

我们需要拥有这些东西,才可以进行自定义 Starter

二. 实现用户信息打印的 自定义 Starter

先创建一个默认的 Maven 项目, 非 SpringBoot 项目。

主要依靠的是 SpringBoot 的自动配置

我们做一个简单的,配置信息打印的 Starter

SpringBoot自定义Starter(二十四)_自定义

1,2,3,4 其实对应的就是 一.二 部分的 1,2,3,4

二.一 pom.xml 导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>top.yueshushu</groupId>
<artifactId>starter</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ButterflyStarter</name>

<dependencies>
<!--添加自动配置的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<!--添加配置文件引用的依赖信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.2.2.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>

</project>

除些之外,不需要引入其他的.

二.二 属性类接收用户自定义参数

在 application.yml 中配置参数,通常有很多个,且格式固定, 我们常常通过一个配置属性类进行接收用户的自定义参数。

我们传入 名称,年龄,描述 三个基础的参数 信息.

UserProperties.java

package top.yueshushu.starter.mode;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

import java.io.Serializable;

/**
* @ClassName:User
* @Description 自定义的一个实体
* @Author zk_yjl
* @Date 2021/10/22 16:57
* @Version 1.0
* @Since 1.0
**/
/**
不建议引用 @Data lombok 第三方插件
* @author yjl
*/
@SuppressWarnings("serial")
@ConfigurationProperties(prefix = "butterfly")
public class UserProperties implements Serializable {
/**
定义 final 常量,用于默认值
*/
private final String DEFAULT_NAME="两个蝴蝶飞";
private final Integer DEFAULT_AGE=26;
private final String DEFAULT_DESCRIPTION="一个快乐的程序员";

/**
定义属性,使用默认值.
*/
private String name=DEFAULT_NAME;
private Integer age=DEFAULT_AGE;
private String description=DEFAULT_DESCRIPTION;

/**
提示默认的构造方法
*/
public UserProperties() {

}

public UserProperties(String name, Integer age, String description) {
this.name = name;
this.age = age;
this.description = description;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", description='" + description + '\'' +
'}';
}
}

二.三 做什么, 要实现的功能

我们拿到用户的自定义参数 (没有的话,走默认的参数)后,要做实现事情,即要实现的功能.

UserPropertiesService.java

package top.yueshushu.starter.service;
import java.util.logging.Logger;

/**
* @ClassName:UserService
* @Description 用户提示的服务,表示有这一个类。
* @Author zk_yjl
* @Date 2021/10/22 17:02
* @Version 1.0
* @Since 1.0
**/
public class UserPropertiesService {
//定义日志
Logger logger=Logger.getLogger(UserPropertiesService.class.getSimpleName());
//参数信息,自定义starter 提供的全部的参数信息。
private String name;
private Integer age;
private String description;
public UserPropertiesService() {

}
// 接收参数
public UserPropertiesService(String name,Integer age,String description) {
this.name=name;
this.age=age;
this.description=description;
}
/**
* 要实现的功能点, 这儿只做一个简单的打印。
* @date 2021/10/29 14:30
* @author zk_yjl
* @param
* @return void
*/
public String println(){
String message = String.format("大家好,我叫: %s, 今年 %s岁, 个人描述: %s",
name, age,description);
logger.info(">>>用户的信息:"+message);
return message;
}
}

二.四 动态热插拔配置

主要是将 这个 XxxService 管控起来。

UserPropertiesServiceConfiguration.java

package top.yueshushu.starter.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import top.yueshushu.starter.mode.UserProperties;
import top.yueshushu.starter.service.UserPropertiesService;

/**
* @ClassName:UserServiceConfiguration
* @Description 用户Service类的配置信息
* @Author zk_yjl
* @Date 2021/10/22 17:12
* @Version 1.0
* @Since 1.0
**/
//表示是一个配置类
@Configuration
//用户输入的参数信息,可以放置到 UserProperties参数里面。一一对应起来
@EnableConfigurationProperties(UserProperties.class)
//存在某个条件类时触发, 即寻找到 UserPropertiesService.class时,才生效
@ConditionalOnClass(UserPropertiesService.class)
public class UserPropertiesServiceConfiguration {

@Autowired
private UserProperties userProperties;

@Bean
public UserPropertiesService userPropertiesService(){
//注意,当条件触发时,才会创建 Bean
UserPropertiesService userService=new UserPropertiesService(
userProperties.getName(),
userProperties.getAge(),
userProperties.getDescription()
);
return userService;
}
}

二.五 配置,能被 SpringBoot 官方承认

必须要进行自动装配,否则这些东西,不被 SpringBoot 官方承认,那么在SpringBoot 项目里面进行引用,就找不到,造成功能不生效.

SpringBoot自定义Starter(二十四)_spring_02

在 resources 目录下 创建 META-INF 目录,下面放置 spring.factories 文件 (必须叫这个名字)

# 添加配置信息,后面跟的是 自定义的那个configuration的全限定类名
org.springframework.boot.autoconfigure.EnableAutoConfiguration=top.yueshushu.starter.configuration.UserPropertiesServiceConfiguration

现在,这个自定义配置的 ButterflyStarter 就算了成功了。

将其进行打包,安装到本地仓库 (老蝴蝶这儿是通过 mvn clean install 命令实现的)

SpringBoot自定义Starter(二十四)_xml_03

也可以通过 Lifecycle 生命周期按照进行实现

SpringBoot自定义Starter(二十四)_Boot 条件注解_04

二.六 测试自定义 Starter

新创建一个 SpringBoot 的项目, StarterApply, 可以正常的启动和访问即可。

二.六.一 pom.xml 中添加依赖

除了 SpringBoot 该有的依赖外,导入刚才 install 生成的自定义Starter 依赖

<!--添加我们自定义的依赖-->
<dependency>
<groupId>top.yueshushu</groupId>
<artifactId>starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

二.六.二 测试自定义Starter

在 StarterApply 项目里面,添加 StarterTest 测试类,进行测试

package top.yueshushu.learn;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import top.yueshushu.condition.Animal;
import top.yueshushu.condition.JavaAnimalConfig;
import top.yueshushu.starter.service.UserPropertiesService;

/**
* @ClassName:StarterTest
* @Description TODO
* @Author zk_yjl
* @Date 2021/10/22 17:26
* @Version 1.0
* @Since 1.0
**/
@RunWith(SpringRunner.class)
@SpringBootTest
public class StarterTest {

@Autowired
private UserPropertiesService userPropertiesService;
@Test
public void starterPrintlnTest(){
String message = userPropertiesService.println();
System.out.println("Apply项目输出信息:"+message);
}
}
二.六.二.一 进行测试

此时, application.yml 配置文件里面,没有关于自定义 Starter 的配置信息

进行测试,发现可以打印, 但是出现了乱码。 是 starter 本身出现的乱码。

SpringBoot自定义Starter(二十四)_自定义Starter_05

二.六.二.二 解决 Starter 乱码问题

在 自定义的Starter pom.xml 添加编译插件,设置编码为 UTF-8

<!--  spring boot 添加编辑方式-->
<build>
<plugins>
<!-- 打包成可执行jar,防止中文乱码,必须要下面这一个插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>

重新 mvn clean install ,然后刷新依赖即可。

SpringBoot自定义Starter(二十四)_spring_06

解决了中文乱码的问题,

自定义 starter 里面的 日志信息会输出,同时项目里面的输出打印语言也生效。 输出的信息,是默认的信息

二.六.二.三 用户自定义参数测试

在 application.yml 中, 输入 butt 发现,有相应的属性提示

SpringBoot自定义Starter(二十四)_spring_07

输入自定义的参数信息

butterfly:
name: 岳泽霖
age: 26
description: 一个孤独的小孩子

进行测试

SpringBoot自定义Starter(二十四)_自定义Starter_08

可以打印出用户自定义输入的参数信息。

说明 自定义 Starter 是生效的。

三. 自定义Starter 深入理解

自定义的Starter 能够起作用,条件注解起了很大的作用.

演示一下条件注解的使用.

仍然使用 刚才的自定义 Starter

三.一 pom.xml 中添加依赖

<dependencies>
<!--添加自动配置的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<!--添加配置文件引用的依赖信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.2.2.RELEASE</version>
<optional>true</optional>
</dependency>
<!--添加 spring-context依赖, 对应的 2.2.2 版本-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
</dependencies>

三.二 定义一个接口和两个实现类

定义 Animal 接口

package top.yueshushu.condition;

/**
* @ClassName:Animal
* @Description 定义一个动物的接口
* @Author zk_yjl
* @Date 2021/10/25 20:48
* @Version 1.0
* @Since 1.0
**/
public interface Animal {
/**
* 定义一个声音的接口
* @date 2021/10/25 20:49
* @author zk_yjl
* @param
* @return void
*/
public void voice();
}

有两个实现类, 一个是 Cat 一个是 Dog

Cat.java

package top.yueshushu.condition;

/**
* @ClassName:Cat
* @Description TODO
* @Author zk_yjl
* @Date 2021/10/25 20:50
* @Version 1.0
* @Since 1.0
**/
public class Cat implements Animal {

@Override
public void voice() {
System.out.println(">>>喵喵喵");
}
}

Dog.java

package top.yueshushu.condition;

/**
* @ClassName:Dog
* @Description 狗的实现类
* @Author zk_yjl
* @Date 2021/10/25 20:49
* @Version 1.0
* @Since 1.0
**/

public class Dog implements Animal {

@Override
public void voice() {
System.out.println(">>>>汪汪汪");
}
}

三.三 定义实现类起作用的条件

Animal 接口有两个实现类 Cat, Dog 在使用中,要使用哪一个呢?

总不能

@Resource("cat")
private Animal animal
@Resource("dog")
private Animal animal

这样肯定是不行的。

可以定义条件, 当Cat 的条件满足时,就用 Cat 的实现类, 当 Dog 的条件满足时,就用 Dog 的实现类

三.三.一 Cat 实现条件 CatCondition

package top.yueshushu.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
* @ClassName:CatCondition
* @Description TODO
* @Author zk_yjl
* @Date 2021/10/25 20:53
* @Version 1.0
* @Since 1.0
**/
// 实现 Condition 接口
public class CatCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String animal = context.getEnvironment().getProperty("animal");
//为空属性,不创建
if(StringUtils.isEmpty(animal)){
return false;
}
return "Cat".equalsIgnoreCase(animal);
}
}

三.三.二 Dog 实现条件 DogCondition

package top.yueshushu.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;

/**
* @ClassName:DogCondition
* @Description TODO
* @Author zk_yjl
* @Date 2021/10/25 20:51
* @Version 1.0
* @Since 1.0
**/
public class DogCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//没有获取到这个属性时,走 Dog
String animal = context.getEnvironment().getProperty("animal");
if(StringUtils.isEmpty(animal)){
return true;
}
return "Dog".equalsIgnoreCase(animal);
}
}

三.四 让条件被管控

现在有 Cat 的条件,也有 Dog 的条件。

但这两个条件,只是实现了 Condition 接口, 并没有添加形如 @Component @Configuration 等类似的注解

说明,这两个条件,还没有办法被SpringBoot 管控到.

JavaAnimalConfig 管控条件

package top.yueshushu.condition;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

/**
* @ClassName:JavaAnimalConfig
* @Description TODO
* @Author zk_yjl
* @Date 2021/10/25 20:54
* @Version 1.0
* @Since 1.0
**/
@Configuration
public class JavaAnimalConfig {
/**
条件符合时,创建
*/
@Bean("animal")
@Conditional(DogCondition.class)
Animal dog(){
return new Dog();
}
/**
条件符合时,创建
*/
@Bean("animal")
@Conditional(CatCondition.class)
Animal cat(){
return new Cat();
}
}

两者创建的,bean 都是 animal

三.五 测试

public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
// ctx.getEnvironment().getSystemProperties().put("animal", "Dog");
// ctx.getEnvironment().getSystemProperties().put("animal", "YJL");
ctx.register(JavaAnimalConfig.class);
ctx.refresh();
Animal animal = (Animal) ctx.getBean("animal");
animal.voice();
}
}

设置环境变量值的信息, 都去掉, 会生成默认的 Dog

当使用 Cat 时, 会打印 Cat 的实现类

当使用 Dog 时,会打印 Dog 的实现类

当使用 YJL 时, 因为都不符合,所以创建不了相应的 Bean

SpringBoot自定义Starter(二十四)_Boot 条件注解_09

也可以将这个自定义的Starter clean install 安装后, StarterApply 引用

@RunWith(SpringRunner.class)
@SpringBootTest
public class StarterTest {

@Autowired
private UserPropertiesService userPropertiesService;
@Test
public void starterPrintlnTest(){
String message = userPropertiesService.println();
System.out.println("Apply项目输出信息:"+message);
}
// 运行测试一下
@Test
public void animalJavaTes(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
ctx.register(JavaAnimalConfig.class);
ctx.refresh();
Animal animal = (Animal) ctx.getBean("animal");
animal.voice();
}
}

发现,也是相同的测试结果.

三.六 Profile 多环境配置

在多环境配置时,我们使用到了 Profile

在 JavaAnimalConfig 里面,

public class JavaAnimalConfig {
/**
条件符合时,创建
*/
@Bean("animal")
@Conditional(DogCondition.class)
Animal dog(){
return new Dog();
}
/**
条件符合时,创建
*/
@Bean("animal")
@Conditional(CatCondition.class)
Animal cat(){
return new Cat();
}
}

我们定义了 DogCondition, 能不能将这个换成 Profile 呢? 这样就不用根据环境变量的值来确定实例化哪一个实现了,而是根据环境配置来实现化具体的实现.

@Configuration
public class JavaAnimalConfig {
/**
条件符合时,创建
*/
@Bean("animal")
// @Conditional(DogCondition.class) 不使用
@Profile("Dog") //触发条件
Animal dog(){
return new Dog();
}
/**
条件符合时,创建
*/
@Bean("animal")
//@Conditional(CatCondition.class)
@Profile("Cat") //触发条件
Animal cat(){
return new Cat();
}
}

进行测试

public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
// ctx.getEnvironment().getSystemProperties().put("animal", "Dog");
// ctx.getEnvironment().getSystemProperties().put("animal", "YJL");


// ctx.getEnvironment().setActiveProfiles("Dog");
//ctx.getEnvironment().setActiveProfiles("Cat");
// ctx.getEnvironment().setActiveProfiles("YJL");

ctx.register(JavaAnimalConfig.class);
ctx.refresh();
Animal animal = (Animal) ctx.getBean("animal");
animal.voice();
}
}

当启用 Dog 时, 实现的是 Dog

当启用的是 Cat 时,实现的是 Cat 实现

当启用的是 YJL 时,会报异常信息。与上面的测试结果一致.

也同样可以在 StarterTest 类中进行测试,

@Test
public void animalJavaTes(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//ctx.getEnvironment().getSystemProperties().put("animal", "Cat");
// ctx.getEnvironment().getSystemProperties().put("animal", "Dog");
// ctx.getEnvironment().getSystemProperties().put("animal", "YJL");

ctx.getEnvironment().setActiveProfiles("Dog");
//ctx.getEnvironment().setActiveProfiles("Cat");
// ctx.getEnvironment().setActiveProfiles("YJL");

ctx.register(JavaAnimalConfig.class);
ctx.refresh();
Animal animal = (Animal) ctx.getBean("animal");
animal.voice();
}

测试结果,也是一样的。

但如果将 setActiveProfiles 都去掉,在 application.yml 中进行设置

SpringBoot自定义Starter(二十四)_spring_10

是不可以的。 还是会报错误

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘animal’ available

本章节的代码放置在 github 上:

​https://github.com/yuejianli/springboot/tree/develop/ButterflyStarter​

​https://github.com/yuejianli/springboot/tree/develop/StarterApply​

谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!



标签:SpringBoot,自定义,ctx,animal,import,org,public,Starter
From: https://blog.51cto.com/u_13420484/5841780

相关文章

  • 微信小程序自定义showModel后怎么获取获取input框输入值
    先看下效果自己调样式太好玩了哈哈哈参考官方文档用官方的直接copy过来就可以实现https://developers.weixin.qq.com/miniprogram/dev/component/input.htmlwxml......
  • SpringBoot上传和下载文件(二十七)
    当死亡来临,每一个人都不会接受自己的命运,他们会反抗.上一章简单介绍了SpringBoot启用Https(二十六),如果没有看过,​​请观看上一章​​文件上传和下载,是常用的功能可以看老......
  • SpringBoot全局异常处理(三十)
    生活打了我们一巴掌,我们,一定要想办法再打回来上一章简单介绍了SpringBoot上传文件到远程服务器(二十九),如果没有看过,​​请观看上一章​​一.为什么要实现异常信息自定义......
  • SpringBoot自定义日志Starter(二十五)
    即使有一天,我放弃了自己的身体,也请你,不要放弃我,我亲爱的灵魂.上一章简单介绍了SpringBoot自定义Starter(二十四),如果没有看过,​​请观看上一章​​一.AOP实现日志功能......
  • SpringBoot整合Ehcache缓存(二十二)
    二八佳人体似酥,腰间仗剑斩愚夫。虽然不见人头落,暗里教君骨髓枯。上一章简单介绍了SpringBoot整合Cache缓存技术(二十一),如果没有看过,​​请观看上一章​​一.Ehcache关于......
  • SpringBoot整合Redis_Jedis版(二十)
    二八佳人体似酥,腰间仗剑斩愚夫。虽然不见人头落,暗里教君骨髓枯。上一章简单介绍了SpringBoot整合Redis(十九),如果没有看过,​​请观看上一章​​SpringBoot2.0版本之后,采......
  • SpringBoot整合MyBatisPlus(十四)
    二八佳人体似酥,腰间仗剑斩愚夫。虽然不见人头落,暗里教君骨髓枯。上一章简单介绍了SpringBoot整合Thymeleaf(十三),如果没有看过,​​请观看上一章​​一.MyBatisPlus的简......
  • SpringBoot系统启动任务(三十二)的方式
    当我们离开世界的时候,那些人,知道我们来过就好.上一章简单介绍了SpringBoot通过Cors解决跨域问题(三十一),如果没有看过,​​请观看上一章​​本章节参考江南一点雨大神的文......
  • el-calendar 自定义我的日程
    效果图1. el-calendar官方文档内容太少,具体需要css样式,可以根据ui设置自行修改,一下的代码只展示JS的逻辑.2. 遍历日期,确定显示内容<el-calendarv-model="value"><te......
  • simpread-(127 条消息) npm run serve 自定义端口和指定临时端口_欲饮琵琶码上催的博
    本文由简悦SimpRead转码,原文地址blog.csdn.net临时指定端口方式一port=5000npmrunserve方式二npmrunserve----port8081注意:--是不能省略的。永久......