谷粒学院——Day06【整合阿里云OSS、EasyExcel技术实现Excel导入分类】

news2024/11/23 2:21:34

阿里云存储OSS

一、对象存储OSS

1. 开通“对象存储OSS”服务

  1. 阿里云:https://www.aliyun.com/
  2. 申请阿里云账号
  3. 实名认证
  4. 开通“对象存储OSS”服务
  5. 进入管理控制台

2. 创建Bucket

选择:标准存储、公共读、不开通。

在这里插入图片描述
 

3.上传默认头像

在这里插入图片描述
 

4. 创建RAM子用户

在这里插入图片描述

在这里插入图片描述


二、使用SDK

在这里插入图片描述
 

1. 创建Mavaen项目

aliyun-oss

2. pom

<!--aliyunOSS-->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.1.0</version>
</dependency>

3. 找到编码时需要用到的常量值

(1)endpoint
(2)bucketName
(3)accessKeyId
(4)accessKeySecret

4. 测试创建Bucket的连接

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 创建存储空间。
ossClient.createBucket(bucketName);

// 关闭OSSClient。

5. 判断存储空间是否存在

@Test
public void testExist() {
// 创建OSSClient实例。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
boolean exists = ossClient.doesBucketExist(bucketName);
System.out.println(exists);
// 关闭OSSClient。
ossClient.shutdown();
}

6. 设置存储空间的访问权限

@Test
public void testAccessControl() {
// 创建OSSClient实例。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 设置存储空间的访问权限为:公共读。
ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
// 关闭OSSClient。
ossClient.shutdown();
}


讲师管理后端【上传讲师头像】

一、新建云存储微服务

1. 在service模块下创建子模块service-oss

在这里插入图片描述

2. 配置pom.xml

service-oss 上级模块 service 已经引入 service 的公共依赖,所以 service-oss 模块只需引入阿里云 oss相关依赖即可。
service 父模块已经引入了 service-base 模块,所以 Swagger 相关默认已经引入。

<dependencies>
        <!-- 阿里云oss依赖 -->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
        </dependency>
        <!--日期工具栏依赖-->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>

    </dependencies>

3. 配置application.properties

注意: 阿里云OSS那里的配置需要修改成自己的信息。

#服务端口
server.port=8002

#服务名
spring.application.name=service-oss

#环境设置:dev、test、prod
spring.profiles.active=dev

#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=your endpoint
aliyun.oss.file.keyid=your accessKeyId
aliyun.oss.file.keysecret=your accessKeySecret

#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=zwy-edu

4. 创建启动类

创建 OssApplication 启动类:

@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"})
public class OssApplication {
    public static void main(String[] args) {

        SpringApplication.run(OssApplication.class, args);

    }
}

5. 启动项目

启动项目后,会报以下的错误信息:
在这里插入图片描述

spring boot 会默认加载org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration这个类,
而DataSourceAutoConfiguration类使用了@Configuration注解向spring注入了dataSource bean,又因为项目(oss模块)中并没有关于dataSource相关的配置信息,所以当spring创建dataSource bean时因缺少相关的信息就会报错。

解决方案:

@SpringBootApplication 注解上加上 exclude,解除自动加载 DataSourceAutoConfiguration

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

 

二、实现文件上传

1. 从配置文件读取常量

创建常量读取工具类:ConstantPropertiesUtil.java

使用 @Value 读取 application.properties 里的配置内容。
用spring的 InitializingBeanafterPropertiesSet 来初始化配置信息,这个方法将在所有的属性被初始化后调用。

/**
 *  ConstantPropertiesUtil:常量类,读取配置文件application.properties中的配置
 */
// 当项目已启动,spring接口,spring加载之后,执行接口一个方法
@Component
public class ConstantPropertiesUtil implements InitializingBean {

    @Value("${aliyun.oss.file.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.file.keyid}")
    private String keyid;

    @Value("${aliyun.oss.file.keysecret}")
    private String keysecret;

    @Value("${aliyun.oss.file.bucketname}")
    private String bucketname;

    // 定义公开静态变量
    public static String END_POINT;
    public static String KEY_ID;
    public static String KEY_SECRET;
    public static String BUCKET_NAME;


    @Override
    public void afterPropertiesSet() throws Exception {
        END_POINT = endpoint;
        KEY_SECRET = keysecret;
        KEY_ID = keyid;
        BUCKET_NAME = bucketname;
    }

}


2. 文件上传

创建Service接口:OssService.java

public interface OssService  {
    //上传头像到OSS
    String uploadFileAvatar(MultipartFile file);
}

创建Service接口的实现类:OssServiceImpl.java

参考SDK中的:Java->上传文件->简单上传->流式上传->上传文件流

@Service
public class OssServiceImpl implements OssService {

    //上传头像到OSS
    @Override
    public String uploadFileAvatar(MultipartFile file) {

        //工具类获取值
        String endpoint = ConstantPropertiesUtil.END_POINT;
        String accessKeyId = ConstantPropertiesUtil.KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.KEY_SECRET;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;


        InputStream inputStream = null;


        try {
            // 创建OSS实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // 获取上传文件的输入流
            inputStream = file.getInputStream();

            //获取文件名称
            String fileName = file.getOriginalFilename();

            //调用oss实例中的方法实现上传
            //参数1: Bucket名称
            //参数2: 上传到oss文件路径和文件名称 /aa/bb/1.jpg
            //参数3: 上传文件的输入流
            ossClient.putObject(bucketName, fileName, inputStream);

            // 关闭OSSClient。
            ossClient.shutdown();

            //把上传后文件路径返回
            //需要把上传到阿里云oss路径手动拼接出来
            //https://zwy-edu.oss-cn-hangzhou.aliyuncs.com/01.png
            String url = "http://"+bucketName+"."+endpoint+"/"+fileName ;

            return url;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}

3. 控制层

创建controller:OssController.java

@Api(description="阿里云文件管理")
@RestController
@RequestMapping("/eduoss/fileoss")
@CrossOrigin // 解决跨域问题
public class OssController {

    @Autowired
    private OssService ossService;

    // 上传头像
    @ApiOperation(value = "文件上传")
    @PostMapping
    public R uploadOssFile(MultipartFile file) {
        // 获取上传文件:MultipartFile

        // 获取上传到oss的路径
        String url = ossService.uploadFileAvatar(file);

        // 返回R对象
        return R.ok().data("url", url);
    }
}

4. 重启oss服务


5. Swagger中测试文件上传

启动项目后,访问:http://localhost:8002/swagger-ui.html
在这里插入图片描述
 
在这里插入图片描述
 
在这里插入图片描述
 


6. 后端接口完善

问题1: 多次上传相同名称文件,会造成最后一次上传把之前上传的文件进行覆盖。
解决方案: 在文件名称随机添加唯一值,让每个文件名称都不同。

问题2: 把文件进行分类管理
解决方案: 根据日期进行分类,实现年月日分类。

OssServiceImpl 实现类中对文件名进行修改:

 //获取文件名称
            String fileName = file.getOriginalFilename();

            // 1.在文件名称里面添加随机唯一的值
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            // qedfdfw01.jpg
            fileName = uuid + fileName;

            // 2.把文件按照日期分类
            // 2022/01/13/01.jpg
            // 获取当前日期
            String datePath = new DateTime().toString("yyyy/MM/dd");

            // 拼接日期
            //  2022/01/13/qedfdfw01.jpg
            fileName = datePath + "/" + fileName;

测试:
在这里插入图片描述
在这里插入图片描述


7. nginx回顾

nginx(反向代理服务器) 的优点:

  1. 请求转发
  2. 负载均衡
  3. 动静分离

在这里插入图片描述
 
在这里插入图片描述
 

下载官网:https://nginx.org/en/download.html
下载后解压到目录中。
在这里插入图片描述
浏览器中输入:http://localhost/, nginx 启动成功后会出现页面:
在这里插入图片描述
注意: 使用 cmd 启动 nginx, 如果关闭cmd窗口, nginx 不会停止的,需要手动停止再启动:
在这里插入图片描述


8. 配置nginx反向代理

/conf/nginx.conf 打开配置文件:
在这里插入图片描述
 
修改 nginx 默认端口:
在这里插入图片描述
 
配置 nginx转发规则:
在这里插入图片描述

server {
        	     listen       9001;
                     server_name  localhost;
		
	     location ~ /eduservice/ {
	          proxy_pass http://localhost:8001;
                    }
                    location ~ /eduoss/ {
                          proxy_pass http://localhost:8002;
        }

 
修改前端 端口号为9001:
在这里插入图片描述
 
测试:

  1. 启动前端端口9528
  2. 启动nginx端口81,用来监听端口9001
  3. 9001会监听请求转发
  4. 启动后端8001、8002

在这里插入图片描述
 


讲师管理前端【上传讲师头像】

一、前端整合图片上传组件

1. 复制头像上传组件

从vue-element-admin复制组件:
vue-element-admin/src/components/ImageCropper
vue-element-admin/src/components/PanThumb

在这里插入图片描述
 

2. 前端参考实现

src/views/components-demo/avatarUpload.vue
 

3. 前端添加文件上传组件

src\views\edu\teacher\save.vue:

<!-- 讲师头像 -->
        <el-form-item label="讲师头像">
            <!-- 头衔缩略图 -->
            <pan-thumb :image="String(teacher.avatar)" />
            
            <!-- 文件上传按钮 -->
            <el-button
                    type="primary"
                    icon="el-icon-upload"
                    @click="imagecropperShow = true"
                    >更换头像
            </el-button>
            <!--
            v-show:是否显示上传组件
            :key:类似于id,如果一个页面多个图片上传控件,可以做区分
            :url:后台上传的url地址
            @close:关闭上传组件
            @crop-upload-success:上传成功后的回调 -->
            <image-cropper
                        v-show="imagecropperShow"
                        :width="300"
                        :height="300"
                        :key="imagecropperKey"
                        :url="BASE_API +'/eduoss/fileoss'"
                        field="file"
                        @close="close"
                        @crop-upload-success="cropSuccess"
                        />
        </el-form-item>

 
引入组件模板:

//引入头像组件
import ImageCropper from '@/components/ImageCropper'
import PanThumb from '@/components/PanThumb'

 
声明组件:

export default {
  //声明引入的组件
  components:{ImageCropper,PanThumb},
    ...
    
}

 

4. js脚本实现上传和图片回显

export default {
     //声明引入的组件
    components:{ImageCropper,PanThumb},
    data() {
        return {
            // 其他数据类型
            .......,

            imagecropperShow:false, // 上传弹框组件是否显示
            imagecropperKey:0, // 上传组件key值
            BASE_API: process.env.BASE_API, // 接口API地址
        }
    },
 
     .........

    methods: { 
    	// 其他函数
    	.....,
        // 关闭上传弹框的方法
        close() {
            this.imagecropperShow = false
            // 上传组件初始化
            this.imagecropperKey = this.imagecropperKey+2
        },

        // 上传成功方法
        cropSuccess(data) {
            this.imagecropperShow = false
            // 上传之后接口返回图片地址
            this.teacher.avatar = data.url
            this.imagecropperKey = this.imagecropperKey+2
        },
         }
    }
}

 

二、测试文件上传

在这里插入图片描述
 
在这里插入图片描述
 


课程分类管理【EasyExcel导入课程分类】

一、课程分类存储结构

在这里插入图片描述


二、EasyExcel读写Excel的基本使用

1. Excel导入导出的应用场景

  1. 数据导入:减轻录入工作量
  2. 数据导出:统计信息归档
  3. 数据传输:异构系统之间数据传输

2. EasyExcel简介

  • Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
  • EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的-主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
  • EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。

三、EasyExcel实现对Excel写操作

1. 创建一个普通的maven项目

直接在 service_edu 这个模块中进行测试。
 

2. pom中引入xml相关依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.1</version>
</dependency>

由于 service 模块中已经引入依赖,所以不需要在 service_edu 中引入以下依赖:

 <!--xls-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
        </dependency>

 

3. 创建实体类

创建 DemoData 实体类:

@Data
public class DemoData {

    // 设置excel表头名称
    @ExcelProperty("学生编号")
    private Integer sno;

    @ExcelProperty("学生姓名")
    private String sname;

}

 

4. 实现写操作

创建方法循环设置要添加到Excel的数据

public class TestEasyExcel {

    public static void main(String[] args) {
        // 实现excel写的操作
        // 1. 设置写入文件夹地址和excel文件名称
        String filename = "D:\\write.xlsx";

        // 2.调用easyExcel里面的方法实现写操作
        // write方法有两个参数: 第一个参数 文件路径名称, 第二个参数实体类class
        EasyExcel.write(filename, DemoData.class).sheet("学生列表").doWrite(getLists());
    }

    // 创建方法返回List集合
    private static List<DemoData> getLists() {
        ArrayList<DemoData> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            DemoData demoData = new DemoData();
            demoData.setSno(i);
            demoData.setSname("lucy" + i);
            list.add(demoData);
        }
        return list;
    }
}

 

5. 测试

在这里插入图片描述


三、EasyExcel实现对Excel读操作

1. 创建实体类

@Data
public class DemoData {

    // 设置excel表头名称
    @ExcelProperty(value = "学生编号", index = 0)
    private Integer sno;

    @ExcelProperty(value = "学生姓名", index = 1)
    private String sname;

}

 

2. 创建读取操作的监听器

public class ExcelListener extends AnalysisEventListener<DemoData> {

    // 一行一行去读取excel内容
    @Override
    public void invoke(DemoData data, AnalysisContext analysisContext) {
        System.out.println("***" + data);
    }

    // 读取excel表头信息
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头信息:"+headMap);
    }

    // 读取完成之后
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

 

3. 调用实现最终的读取

 public static void main(String[] args) {
        // 实现excel读的操作
        String filename = "D:\\read.xlsx";
        EasyExcel.read(filename, DemoData.class, new ExcelListener()).sheet().doRead();
    }

 

4. 测试

在这里插入图片描述


课程分类管理【添加课程分类】

1. 引入EasyExcel依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.1</version>
</dependency>

由于在上面的操作中 在 serviceservice_edu 模块中已经引入依赖了,此处不需要再引入。
 

2. 使用代码生成器生成课程分类代码

由于在 service_edu中使用过代码生成器,因此 只需要改数据库表为 edu_subject 即可。

public class CodeGenerator {

    @Test
    public void run() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("D:\\IDEA\\guli_parent\\service\\service_edu" + "/src/main/java"); //输出目录

        gc.setAuthor("jyu_zwy"); //作者名
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖

        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER_STR); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("abc123");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();

        //生成包:com.atguigu.eduservice
        pc.setModuleName("eduservice"); //模块名
        pc.setParent("com.atguigu");

        //生成包:com.atguigu.controller
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("edu_subject");//根据数据库哪张表生成,有多张表就加逗号继续填写

        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);


        // 6、执行
        mpg.execute();

    }
}

 

3. EduSubjectController

@RestController
@CrossOrigin
@RequestMapping("/eduservice/subject")
public class EduSubjectController {

    @Autowired
    private EduSubjectService eduSubjectService;

    // 添加课程分类
    // 获取上传过来的文件,把文件内容读取出来
    @PostMapping("addSubject")
    public R addSubject(MultipartFile file) {
        // 获取上传过来的excel文件:MultipartFile
        eduSubjectService.addSubject(file, eduSubjectService);
        return R.ok();
    }
}

4. 创建和Excel对应的实体类

@Data
public class SubjectData {
    //一级分类
    @ExcelProperty(index = 0)
    private String oneSubjectName;

    //二级分类
    @ExcelProperty(index = 1)
    private String twoSubjectName;
}

5. SubjectExcelListener监听器

public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {

    //因为SubjectExcelListener態交给spring进行ioc管理,需要自己手动new,不能注入其他对象
    //不能实现数据库操作

    public EduSubjectService eduSubjectService;

    //有参,传递subjectService用于操作数据库
    public SubjectExcelListener(EduSubjectService eduSubjectService) {
        this.eduSubjectService = eduSubjectService;
    }

    //无参
    public SubjectExcelListener() {
    }


    //读取excel内容,一行一行读取
    @Override
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
        //表示excel中没有数据,就不需要读取了
        if (subjectData== null) {
            throw new GuliException(20001, "文件数据为空");
        }

        //一行一行读取,每次读取有两个值,第一个值一级分类,第二个值二级分类
        //判断是否有一级分类是否重复
        EduSubject existOneSubject = this.existOneSubject(eduSubjectService, subjectData.getOneSubjectName());
        if (existOneSubject == null){ //没有相同的一级分类,进行添加
            existOneSubject = new EduSubject();
            existOneSubject.setParentId("0"); //设置一级分类id值,0代表为一级分类
            existOneSubject.setTitle(subjectData.getOneSubjectName());//设置一级分类名
            eduSubjectService.save(existOneSubject);//给数据库添加一级分类
        }


        //获取一级分类的id值
        String pid = existOneSubject.getId();
        //判断是否有耳机分类是否重复
        EduSubject existTwoSubject = this.existTwoSubject(eduSubjectService, subjectData.getTwoSubjectName(), pid);
        if (existTwoSubject==null){//没有相同的二级分类,进行添加
            existTwoSubject = new EduSubject();
            existTwoSubject.setParentId(pid); //设置二级分类id值
            existTwoSubject.setTitle(subjectData.getTwoSubjectName());//设置二级分类名
            eduSubjectService.save(existTwoSubject);//给数据库添加二级分类
        }



    }

    //判断一级分类不能重复添加
    private EduSubject existOneSubject(EduSubjectService eduSubjectService, String name){
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name)
                .eq("parent_id","0");
        EduSubject oneSubject = eduSubjectService.getOne(wrapper);
        return oneSubject;
    }

    //判断二级分类不能重复添加
    private EduSubject existTwoSubject(EduSubjectService eduSubjectService, String name, String pid){
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name)
                .eq("parent_id", pid);
        EduSubject twoSubject = eduSubjectService.getOne(wrapper);
        return twoSubject;
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

6. SubjctService

EduSubjectService:

public interface EduSubjectService extends IService<EduSubject> {

    // 添加课程分类
    void addSubject(MultipartFile file, EduSubjectService eduSubjectService);
}

EduSubjectServiceImpl:

@Service
public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {

    // 添加课程分类
    @Override
    public void addSubject(MultipartFile file, EduSubjectService eduSubjectService) {

        try {
            // 文件输入流
            InputStream in = file.getInputStream();
            // 调用方法进行读取
            EasyExcel.read(in, SubjectData.class, new SubjectExcelListener(eduSubjectService)).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7. 测试

首先把数据库表 edu_subject 中的数据清空。
启动项目后,在 localhost:8001/swagger-ui.html 中进行测试。
在这里插入图片描述
01.xlsx:
在这里插入图片描述
 
在这里插入图片描述
 
在这里插入图片描述
 
 
创作不易,如果有帮助到你,请给文章点个赞和收藏,让更多的人看到!!!
关注博主不迷路,内容持续更新中。

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

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

相关文章

如何手写一个单向链表?看这里

一. 问题展现 通常我们在大多数的面试中&#xff0c;遇到关于集合的问题都是比较多的。一般情况下&#xff0c;许多面试官通常都会问我们关于Set集合和Map集合的相关知识点&#xff0c;并对此进行重重陷阱的布置&#xff0c;此时很多面试者往往就很容易被带到面试官挖好的陷阱…

netstat命令详解

netstat命令详情一、前言二、netstat查看端口命令三、显示每个协议的统计信息四、显示核心路由信息五、netstat的其他参数一、前言 个人主页: ζ小菜鸡大家好我是ζ小菜鸡&#xff0c;小伙伴们&#xff0c;让我们一起来学习netstat命令使用&#xff0c;netstat命令是一个监控TC…

echarts疑难杂症

echarts疑难杂症1.调整柱状图、饼图的大小2.嵌套饼图且颜色保持一致3.并排展示饼图且中间展示文字4.折线图&#xff08;柱状图&#xff09;双y轴5.使用echarts56.图形不展示的问题1.调整柱状图、饼图的大小 //柱状图主要根据grid属性中的top/bottom/left/right属性调整大小 le…

【毕业设计】机器视觉行人口罩佩戴检测系统 - python 深度学习

文章目录0 前言1 简介2 效果展示3 实现方法3.1 模型介绍3.2 获取数据集3.3 数据集获取4 最后0 前言 &#x1f525; Hi&#xff0c;大家好&#xff0c;这里是丹成学长的毕设系列文章&#xff01; &#x1f525; 对毕设有任何疑问都可以问学长哦! 这两年开始&#xff0c;各个学…

164页5万字轨道交通BIM方案建议书

目录 1、 概况 1.1. BIM国内外现状 1.1.1. 国外BIM现状 1.1.2. 国内BIM现状 1.2. BIM在轨道交通工程领域的发展概况 1.3. 中铁二院BIM发展总体思路的建议 2、 解决方案总体架构 2.1. 解决方案应具备的要素 2.2. 解决方案整体架构 2.3匹配度分析 3、 设计阶段解决方案…

数据库的基本操作(5)

先回顾一下在上一篇中的内容&#xff1a; 聚合查询&#xff1a;行和行之间的数据的加工。 聚合函数&#xff1a;count&#xff0c;avg&#xff0c;sum...... group..by...进行分组&#xff0c;将指定列的值进行分组&#xff0c;将相同的记录合并到一个组中。每个组还可以进行…

Golang入门笔记(10)—— 包

使用包的原因&#xff1a; 1.不可能把所有的不同业务功能的函数都放在一个源文件中&#xff0c;这样不便于管理。通常的做法是&#xff1a;我们会把具有相同一些功能和业务的维度的函数&#xff0c;分门别类的放在不同的源文件中。 2.不同的包名&#xff0c;可以解决两个函数…

【SQL 中级语法 3】三值逻辑和NULL

普通语言里的布尔型只有true和false两个值&#xff0c;这种逻辑体系被称为二值逻辑。而SQL语言里&#xff0c;除此之外还有第三个值unknown&#xff0c;因此这种逻辑体系被称为三值逻辑&#xff08;three-valued logic&#xff09;。 为什么SQL语言采用了三值逻辑呢&#xff1…

java项目-第139期ssm博客系统-ssm毕业设计_计算机毕业设计

java项目-第139期ssm博客系统-ssm毕业设计_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm博客系统》 该项目分为前台和后台2个部分。 前台不需要登录&#xff0c;游客都可以访问&#xff0c;并发表评论 管理员登录后可以进行文章的发表&#xff0c;分类&…

德鲁克《卓有成效的管理者》学习读书-总结

有幸学习了管理大师德鲁克先生的《卓有成效的管理者》&#xff0c;帮助学习者理清了在理论和实践之间建立桥梁&#xff0c;使其生根落地&#xff0c;开花结果&#xff1b;管理不是常识&#xff0c;管理是个实践学科&#xff0c;要不断温习&#xff0c;不断与领导同事联接&#…

人肠道宏病毒与其宿主和环境因素的关联分析

近期《Nature Communications》期刊上(IF17.694)发表的“Extensive gut virome variation and its associations with host and environmental factors in a population-level cohort”研究论文中&#xff0c;对从4198个个体的肠道宏基因组中获得的人类肠道病毒进行分析&#x…

PCB设计时如何选择合适的叠层方案

大家在画多层PCB的时候都要进行层叠的设置&#xff0c;其中层数越多的板子层叠方案也越多&#xff0c;很多人对多层PCB的层叠不够了解&#xff0c;通常一个好的叠层方案可以降低板子产生的干扰&#xff0c;我们的层叠结构是影响PCB板EMC性能的重要因素,下面我们以四层板和六层板…

刨根问底 Redis, 面试过程真好使

充满寒气的互联网如何在面试中脱颖而出&#xff0c;平时积累很重要&#xff0c;八股文更不能少&#xff01;下面带来的这篇 Redis 问答希望能够在你的 offer 上增添一把&#x1f525;。 在 Web 应用发展的初期阶段&#xff0c;一个网站的访问量本身就不是很高&#xff0c;直接使…

SRM供应商关系管理系统解决方案

SRM供应商关系管理系统解决方案供应商关系管理(SRM)软件的采购指南 什么是供应商关系管理(SRM)软件? 供应商关系管理(SRM)软件是一个通讯解决方案制造商、分销商和零售商的供应链。供应商管理用于将所有有关组织的供应商通讯和颜色编码索引卡片。现在SRM管理的数字由一个国家…

OOM内存溢出分析

Mat内存溢出dump文件分析工具http://www.eclipse.org/mat/downloads.php 模拟OOM Java 程序 package org.cj.oom;import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit;/*** 创建内存分析* java启动参数指定内存 -Xms1m -Xmx1m* author…

没有上司的舞会 - 树形DP

目录题目描述前言C代码题目描述 Ural 大学有 NNN 名职员&#xff0c;编号为 1∼N1∼N1∼N。 他们的关系就像一棵以校长为根的树&#xff0c;父节点就是子节点的直接上司。 每个职员有一个快乐指数&#xff0c;用整数 HiH_iHi​ 给出&#xff0c;其中 1≤i≤N1≤i≤N1≤i≤N。…

ElasticSearch分布式搜索引擎安装保姆级教程

ElasticSearch分布式搜索引擎安装教程 一.Hr&#xff1a;ElasticSearch是什么&#xff1f; 答&#xff1a;Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口。Elasticsearch是用Java语言开发的&#…

后端API接口性能优化的10种方案,真有用!

后端API接口性能优化的10种方案&#xff0c;真有用&#xff01; 批量思想&#xff1a;批量操作数据库 优化前&#xff1a; //for循环单笔入库 for(TransDetail detail:transDetailList){insert(detail); } 优化后&#xff1a; batchInsert(transDetailList); 打个比喻&…

docker-compose的安装与卸载

compose项目是docker官方的开源项目,负责实现对Docker容器的快速编排 定位 定位是定义与运行多个docker容器的应用,同时可以对多个容器进行编排Compose 中有两个重要的概念&#xff1a; 服务 (service)&#xff1a;一个应用的容器&#xff0c;实际上可以包括若干运行相同镜像的…

电压跌落检测

1.前言 根据国际上较为权威的 IEEE 制定的标准可知&#xff0c;电压跌落是指电力系统中某点工频电压方均根值突然降低至 0.1p.u. ~ 0.9p.u.&#xff0c;并在短暂持续10ms~1min 后恢复正常的现象。在对电压跌落进行检测时一般都需要检测起止时刻、相位跳变、跌落深度这三个特征…