谷粒学院16万字笔记+1600张配图(六)——上传讲师头像

项目源码与所需资料
链接:https://pan.baidu.com/s/1azwRyyFwXz5elhQL0BhkCA?pwd=8z59
提取码:8z59

demo06-上传讲师头像

1.阿里云oss

1.1介绍

为什么要使用对象存储oss?

我们在javaweb阶段应该也做过上传,那时候我们要么把文件存到tomcat中,要么把文件存到本地路径中,比如说我是存到本地路径中,那么你在你的电脑上是访问不到我电脑中的文件的(除非做特殊处理)。

所以我们需要把内容存到一个所有人都能访问到的地方,这个地方就是对象存储oss:存到oss中的文件可以被别人访问

1.2开通"对象存储oss"服务

1.进入阿里云官网https://www.aliyun.com

2.有账号的点击"登录",没有账号的点击"立即注册"来注册账号(建议使用支付宝注册,因为注册后需要做实名认证,使用支付宝注册的话比较方便)

在这里插入图片描述

3.注册成功后登录账号,进行实名认证

4.在搜索栏搜索"对象存储oss",点击"对象存储OSS"

在这里插入图片描述

5.开通oss服务

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.3创建Bucket

Bucket就相当于一个电脑中的包,或者说是文件夹

1.点击"创建Bucket"

在这里插入图片描述

2.填写信息

在这里插入图片描述

  • Bucket名称随便填写,但是别写中文
  • 存储类型选择"低频访问存储"就够用了
  • 区域使用默认的就可以了
  • 读写权限设为"公共读"或"公共读写"都可以,我设置的是"公共读"

1.4在阿里云后台上传默认头像

1.点击文件管理–>上传文件来上传讲师默认头像

在这里插入图片描述

2.将图片拖拽过来

在这里插入图片描述

3.可以看到此时显示"已扫描待上传",然后我们点击"上传文件"即可

在这里插入图片描述

4.回到"文件管理",点击"详情"就可以显示出我们刚刚上传的照片的详细信息

在这里插入图片描述

5.在这张照片的详细信息中我们可以看到oss为我们生成的图片地址https://edu-mxy.oss-cn-hangzhou.aliyuncs.com/default.jpg

在这里插入图片描述

6.在浏览器地址栏输入 https://edu-mxy.oss-cn-hangzhou.aliyuncs.com/default.jpg就可以下载保存这张图片了

在这里插入图片描述

1.5创建操作阿里云oss的许可证

实际开发中,是要使用java代码操作阿里云oss,然后上传文件到阿里云oss,使用java代码操作阿里云oss是需要许可证的(许可证就是阿里云给你颁发一个id和秘钥,只有拿着id和秘钥才可以操作).下面我们来创建许可证

1.点击头像中的"AccessKey 管理"

在这里插入图片描述

2.点击"继续使用 AccessKey"

在这里插入图片描述

3.点击"创建 AccessKey"

在这里插入图片描述

4.就会生成id和秘钥

在这里插入图片描述

2.后端环境搭建——后端集成oss

2.1在service下创建子模块service_oss

1.在service上右键,选择New–>Module…

在这里插入图片描述

2.我们这里是创建一个maven工程

在这里插入图片描述

3.填写信息

在这里插入图片描述

2.2添加依赖

在service_oss中添加下面这些依赖(在service中添加下面这些依赖也是可以的,但因为这些依赖只会在service_oss中使用,所以我们在service_oss添加就可以了)

<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>

在这里插入图片描述

2.3配置

1.进行配置前先看一下我们的地域节点:

点击对象存储–>Bucket列表–>edu-mxy–>概览,可以看到我的地域节点是oss-cn-hangzhou.aliyuncs.com(咱俩的地域节点可能不一样,你就看你的就行)

在这里插入图片描述

2.创建配置文件application.properties并编写配置

#服务端口
server.port=8002
#服务名
spring.application.name=service-oss

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

#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=oss-cn-hangzhou.aliyuncs.com
aliyun.oss.file.keyid=LTAI5tMUCkxmE6ouUc2dmbXm
aliyun.oss.file.keysecret=0Py10jHOPVkeFp6MiIm88c9QqyykUE
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=edu-mxy

在这里插入图片描述

  • aliyun.oss.file.endpoint=oss-cn-hangzhou.aliyuncs.com是地域节点,就是第1步我让你看的那个
  • aliyun.oss.file.keyid=LTAI5tMUCkxmE6ouUc2dmbXmaliyun.oss.file.keysecret=0Py10jHOPVkeFp6MiIm88c9QqyykUE分别是id和秘钥(我们在"1.5创建操作阿里云oss的许可证"的第4步得到的)
    • 我平时习惯在等号(=)两边加空格,但是这里的id、秘钥一定不能在等号(=)右边加空格,加的空格会被识别为id、秘钥的一部分(地域节点和Bucket名称我不知道是不是也这样,但我懒得去试,我索性在等号右边都不加空格不就行了)
  • aliyun.oss.file.bucketname=edu-mxy是Bucket的名称,我们在"1.3创建Bucket"的第2步填写信息时填的Bucket名称

注意:

  • 因为地域节点、id、秘钥、Bucket名称,这些都是固定的,所以我们写到配置文件中,后面再使用常量类来读取("3.创建常量类"实现的)
  • 地域节点、id、秘钥、Bucket名称,都填你们自己的,别写成我的了

2.4创建启动类

创建包com.atguigu.oss,然后在该包下创建主启动类OssApplication,并在类中编写代码

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

在这里插入图片描述

2.5启动项目

1.在"main"上右键选择"Run ‘OssApplication’"启动项目

在这里插入图片描述

2.发现项目不能正常启动,我们来看一下报错描述

在这里插入图片描述

我们大概能够理解这段描述:就是说启动项目时会找数据库的配置使得能和数据库建立连接,但是我们这个service_oss项目并不需要和数据库建立连接,所以也就没有添加数据库的配置,最后结果就是无法正常启动项目

3.有两种解决方法(我这里使用的是方法二)

解决方法一:

在配置文件application.properties中添加数据库的配置

解决方法二(推荐):

给启动类的注解@SpringBootApplication添加属性exclude = DataSourceAutoConfiguration.class,该属性作用是:默认不加载数据库配置

在这里插入图片描述

4.再次启动该项目,发现现在可以正常启动了

3.创建常量类

1.在service_oss模块的oss包下创建包utils,然后在该包下创建常量类ConstantPropertiesUtils,该类的作用是读取配置文件application.properties中的地域节点、id、秘钥、Bucket名称

@Component
public class ConstantPropertiesUtils {
    
    
    //读取配置文件内容
    @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;
}

在这里插入图片描述

注意:这里的@Value注解导的是Spring里面的,别导错包了。该注解的作用是:就拿属性endpoint及其注解@Value("${aliyun.oss.file.endpoint}")来举例:在初始化bean时会读取到配置文件中aliyun.oss.file.endpoint的值并赋值给属性endpoint

2.我们确认读取到配置文件中的内容并且赋值给了属性,但是这些属性都是私有的呀,我们怎么才能获取到这些属性的值呢?

这就要借助于InitializingBean接口了:实现了InitializingBean接口的类在初始化bean时都会执行接口中的方法afterPropertiesSet。

完整的实现流程:

  • 给常量类添加注解@Component将其交给Spring管理
  • 给属性添加@Value
  • 定义public的静态常量
  • 让常量类实现InitializingBean接口,重写接口的方法afterPropertiesSet,方法内部将私有属性的值赋值给public的静态常量

这样的话,启动service_oss项目后,因为常量类被@Component修饰,所以会初始化bean,在初始化bean的过程中,会先读取配置文件的内容并赋值给私有属性,然后执行重写的afterPropertiesSet方法,方法内部将私有属性的值赋值给public的静态常量

@Component
public class ConstantPropertiesUtils 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的静态常量
    public static String END_POINT;
    public static String ACCESS_KEY_ID;
    public static String ACCESS_KEY_SECRET;
    public static String BUCKET_NAME;

    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        END_POINT = endpoint;
        ACCESS_KEY_ID = keyId;
        ACCESS_KEY_SECRET = keySecret;
        BUCKET_NAME = bucketName;
    }
}

在这里插入图片描述

4.后端接口实现

因为项目service_oss没有用到数据表,所以没办法用代码生成器来生成代码,只能我们全部手敲

4.1controller层

1.在oss包下创建包service,然后在service包下创建接口OssService、在service包下创建包impl,然后在impl包下创建类OssServiceImpl并且:①让该类其实现接口OssService②给该类添加注解@Service将其交给Spring管理

在这里插入图片描述

2.在oss包下创建包controller,然后在controller包下创建类OssController,并在类中编写代码

@RestController
@RequestMapping("/eduoss/fileoss")
@CrossOrigin //解决跨域问题
public class OssController {
    
    
    @Autowired
    private OssService ossService;

    //上传头像的方法
    @PostMapping
    public R uploadOssFile(
            MultipartFile file) {
    
     //MultipartFile file用来得到用户上传的文件
        //上传文件到oss,并得到文件的url
        String url = ossService.uploadFileAvatar(file);
        return R.ok().data("url",url);
    }
}

在这里插入图片描述

  • 得到用户上传的文件后,我们需要将文件上传到阿里云oss,上传的方法在service层定义,控制层负责调用service层定义的上传文件的方法uploadFileAvatar(后面我们会去service层定义该方法)

  • 数据表edu_teacher的avatar字段用来存用户头像,但存的并不是头像文件,而是头像的地址:oss会为图片生成地址("1.4在阿里云后台上传默认头像"的第5步说过),我们将这个地址存到avatar字段中

    • 所以说,我们后面在service层定义的uploadFileAvatar方法需要返回图片的地址,然后在controller层用一个变量来接收这个地址,所以有了这行代码:String url = ossService.uploadFileAvatar(file);

4.2service层

4.2.1在接口OssService定义方法

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

在这里插入图片描述

4.2.2在实现类OssServiceImpl实现方法

@Service
public class OssServiceImpl implements OssService {
    
    
    //上传头像到oss
    @Override
    public String uploadFileAvatar(MultipartFile file) {
    
    
        //1.工具类获取数据
        String endpoint = ConstantPropertiesUtils.END_POINT;
        String accessKeyId = ConstantPropertiesUtils.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtils.ACCESS_KEY_SECRET;
        String bucketName = ConstantPropertiesUtils.BUCKET_NAME;

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

        try {
    
    
            //3.获取到将要上传的文件的输入流
            InputStream inputStream = file.getInputStream();

            //4.获取到将要上传的文件的名称
            String fileName = file.getOriginalFilename();

            //5.调用oss的方法实现上传
            ossClient.putObject(bucketName, fileName, inputStream);

            //6.关闭OSS对象
            ossClient.shutdown();

            //7.拼接路径
            String url = "https://" + bucketName + "." + endpoint + "/" + fileName;
            return url;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return null;
        }
    }
}

在这里插入图片描述

注意点一:putObject方法的三个参数:

  • 第一个参数:Bucket名称
  • 第二个参数:文件上传到oss的哪个地方(即文件路径)和文件名称。比如:/aa/bb/1.jpg
    • 我们目前是把图片全部存到oss的根目录下,所以参数只需要文件名称就可以了。我们以后可能会分类存图片,那么参数就需要是文件路径+文件名称比如:/aa/bb/1.jpg(在"4.4.2把文件进行分类管理"中实现了)
  • 第三个参数:上传的文件的输入流

注意点二:阿里云oss会为我们生成图片路径,但是人家没有给我们提供可以直接得到路径的接口,所以需要我们手动拼接图片路径。我们在"1.4在阿里云后台上传默认头像"的第5步看过阿里云oss为我们生成的图片路径,是:https://edu-mxy.oss-cn-hangzhou.aliyuncs.com/default.jpg,从这个路径中我们可以推出路径格式是:https//+Bucket名称+小数点+地域节点+单斜杠+文件名称,所以代码是String url = "https://" + bucketName + "." + endpoint + "/" + fileName;

4.3测试

接下来我们使用swagger进行测试:

1.先从控制台中将我们在"1.4在阿里云后台上传默认头像"上传的默认头像删掉

在这里插入图片描述

2.启动service_oss项目

3.在地址栏输入http://localhost:8002/swagger-ui.html

4.点击"选择文件",选择我们我们要上传的图片

在这里插入图片描述

5.点击"Try it out!"进行测试

在这里插入图片描述

6.可以看到测试成功,并且返回的数据中有图片的地址

在这里插入图片描述

7.刷新控制台,可以看到图片成功上传到了阿里云oss中

在这里插入图片描述

4.4后端接口完善

4.4.1文件名重复

如果这个用户上传了名字为default.jpg的图片,另一个用户后来也上传了名字为default.jpg的图片,那么后来上传的default.jpg会覆盖掉以前上传的default.jpg

解决方法:在文件名称中添加随机唯一值,使得每个文件的名称都不相同

接下来我们在实现类OssServiceImpl的uploadFileAvatar方法中添加如下代码:

//完善:在文件名称里面添加随机唯一的值
//wer4-43u5-323oo-...
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
fileName = uuid + fileName;

在这里插入图片描述

使用UUID的方式生成的随机值里面会有横杠(-),比如:wer4-43u5-323oo-…

这个横杠想去掉就去掉,不想去掉就不去掉,我这里使用replaceAll方法将横杠去掉了

4.4.2把文件进行分类管理

这里我们根据日期进行分类

//完善:把文件按照日期进行分类:2022/08/17/01.jpg
//1.获取当前时间
String datePath = new DateTime().toString("yyyy/MM/dd");
//2.拼接
fileName = datePath + "/" + fileName;

在这里插入图片描述

获取当前日期:我们可以先new Date(),然后用SimpleDateFormat对日期进行格式转换,转换为我们想要的形式:2022/08/17,但这样做太麻烦了,我们在"2.2添加依赖"中添加了日期工具栏依赖,我们用这个依赖提供的方法来达到我们想要的效果

4.4.3测试

接下来我们使用swagger进行测试:

1.先从控制台中将我们在"1.4在阿里云后台上传默认头像"上传的默认头像删掉

在这里插入图片描述

2.重启service_oss项目

3.在地址栏输入http://localhost:8002/swagger-ui.html

4.点击"选择文件",选择我们我们要上传的图片,然后点击"Try it out!"进行测试

在这里插入图片描述

5.可以看到测试成功,并且返回的数据中有图片的地址

在这里插入图片描述

6.刷新控制台,可以看到图片成功上传到了阿里云oss中,并且把文件按照日期进行分类

在这里插入图片描述

5.nginx

5.1简介

nginx的官方描述:反向代理服务器

nginx的常用功能:

  • 请求转发
  • 负载均衡
  • 动静分离

5.2nginx常用功能

5.2.1请求转发

在这里插入图片描述

假设我们现在有一个9001端口的nginx,还有两个服务器,一个是8001端口的eduservice,一个是8002端口的eduoss。我们先通过浏览器发送请求到nginx,然后nginx根据不同的请求转发到对应的服务器中

问题:我们有好几个服务器,那么nginx是怎么找到对应的服务器呢?方式有很多种,我们这里说一种常用的方式:根据路径匹配进行转发。比如说,如果关于eduservice服务器的所有请求路径中都含有eduservice,那么我们就在nginx中设置一个规则:当请求路径中包含有eduservice,就把请求转发到8001端口

5.2.2负载均衡

要做负载均衡有一个特点:需要用到集群。集群:比如说我现在有两台服务器,一个端口是8081,另一个端口是8082,但是这两台服务器放的都是edu这个项目

在这里插入图片描述

假设我现在有两台服务器,一个端口是8081,另一个端口是8082,但是这两台服务器放的都是edu这个项目,我们先通过浏览器发送请求到nginx,然后nginx会将请求平均分摊到这两个服务器中,假设我们现在有四个请求,那么8081端口的服务器和8082端口的服务器就会分别处理两个请求

问题:nginx是怎么做到平均分摊请求的呢?nginx中有很多算法:①轮询:一个一个来,先给第一个服务器一个请求,然后给第二个服务器一个请求,再给第一个服务器一个请求,然后再给第二个服务器一个请求,直到将nginx中的请求全都分出去②根据请求时间,谁的时间最短就先去访问谁③权重…

我们以后做负载均衡不会使用nginx,会使用网关,因为网关帮我们将功能做了封装,更加方便、简单

5.2.3动静分离

我们在tomcat里面放了java代码部分,然后又专门找了个服务器放静态资源(html、图片…),当我们访问java代码时就去请求tomcat,当我们访问静态资源时就去请求我们的静态服务器

5.3为什么需要使用nginx

我们以前是只有一个端口号为8001的服务器,所以在前端项目的config–>dev.env.js中写了BASE_API: '"http://localhost:8001"',(忘了这行代码作用的去看"demo05-讲师管理前端"的"3.1修改前端项目访问路径"的第3步),但是我们现在又有了一个端口号为8002的服务器(阿里云oss项目),那么我们怎么应该怎么在前端项目中改呢?如下图,在dev.env.js中加一行代码BASE_API1: '"http://localhost:8002"',(注意:马上就会说到,这种做法是不可行的,我加了这行代码并截图后就立马把这行代码删掉了)

在这里插入图片描述

这种做法是不可行的:如果这样做,那么前端项目中的很多规则就都要改,比如src–>utils–>request.js,如下图所示,画方框的这部分代码就需要修改,修改后的代码中需要有判断

在这里插入图片描述

这个时候就要用到我们的nginx了:我们将config–>dev.env.js的BASE_API: '"http://localhost:8001"',中的端口号改为nginx的9001,然后nginx再做请求转发

5.4安装nginx

1.nginx的压缩包在资料里面有(和老师的版本一样),我们将其解压

在这里插入图片描述

2.在解压后的在地址栏中输入cmd后按回车进入命令行窗口

在这里插入图片描述

3.使用命令nginx.exe启动nginx,如果看到光标在闪就说明启动成功

在这里插入图片描述

5.5重启nginx

1.关闭nginx

在上一步使用cmd启动nginx后,如果关闭cmd窗口,nginx不会停止,我们需要使用命令nginx.exe -s stop关闭nginx

在这里插入图片描述

2.启动nginx

使用命令nginx.exe启动nginx(具体操作看"5.4安装nginx"的第2步和第3步)

5.6使用nginx配置项目请求转发

1.打开nginx的配置文件nginx.conf

在这里插入图片描述

2.nginx默认端口号是80,我们将它改为81(不改也可以,但可能有冲突)

在这里插入图片描述

3.配置nginx转发规则

在http{…}里面编写以下代码来创建配置

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

在这里插入图片描述

  • listen 9001;表示对外的监听端口是9001
  • location ~ /eduoss/ {...}中的~表示此时的匹配方式是正则匹配,这样的话只要路径里面包含/eduoss/就可以匹配上,不加~的话代表只有路径就是/eduoss/时才可以匹配上
  • location ~ /eduservice/ {...}location ~ /eduoss/ {...}里面的/eduservice/、/eduoss/的来源如下截图:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.在config–>dev.env.js中将前端请求地址修改为nginx的地址

在这里插入图片描述

5.7测试

1.修改nginx配置后需要重启nginx(忘了的可以去看"5.5重启nginx")

2.启动8001项目和8002项目

3.修改了前端了配置文件,所以需要重启前端项目

①在终端按Ctrl+c,然后输入y并按回车即可停掉前端项目

在这里插入图片描述

②在终端使用命令npm run dev启动前端项目

4.在地址栏输入http://localhost:9528可以看到登录页面,此时按F12点开开发者工具,然后点击按钮"Sign in"按钮

在这里插入图片描述

5.在"NetWork"菜单栏下的"Fetch/XHR"菜单栏下,这两个请求我们随便点一个看看,发现请求路径中的端口号是9001,这说明我们成功配置请求转发。

再说一下具体请求流程:浏览器先将请求发送给nginx,然后nginx根据路径匹配规则将请求发送给相应的服务器

在这里插入图片描述

6.前端页面(在save.html整合上传组件)

6.1得到上传组件

1.我们可以像以前一样,去element-ui官网复制一个上传组件过来,但里面的组件都太难看了。还记不记得"demo05-讲师管理前端"的"1.搭建项目前端页面环境"的第1步?我们当时说了资料中有一个"vue-element-admin"的压缩文件,我们开发过程中想要什么功能都可以从这里去找

2.可以看到vue-element-admin–>src–>components下有很多组件,其中我们上传需要的组件是"ImageCropper"和"PanThumb"

在这里插入图片描述

3.你不用将资料中的"vue-element-admin.zip"解压缩,然后从解压后的文件中找到上传组件。我直接将上传组件的这两个文件夹放到了资料中

在这里插入图片描述

4.将上传组件的两个文件夹复制到前端项目的src–>components中

在这里插入图片描述

6.2在save.html添加上传组件

在save.html中添加如下代码(只要会修改就可以了,不需要手敲)

<!-- 讲师头像:TODO -->
<el-form-item label="讲师头像">

  <!-- 头衔缩略图 -->
  <pan-thumb :image="teacher.avatar"/>
  <!-- 文件上传按钮 -->
  <el-button type="primary" icon="el-icon-upload" @click="imagecropperShow=true">更换头像
  </el-button>

  <image-cropper
                v-show="imagecropperShow"
                :width="300"
                :height="300"
                :key="imagecropperKey"
                :url="BASE_API+'/admin/oss/file/upload'"
                field="file"
                @close="close"
                @crop-upload-success="cropSuccess"/>
</el-form-item>

在这里插入图片描述

  • image-cropper是真正的上传组件,是一个表单,用来上传头像

    • 我们以前发送请求都是使用ajax,但是ajax不能直接上传文件,所以我们需要用提交表单的方式来上传文件
  • :v-show:是否显示上传组件

    • 当点击"更换头像"后,会触发@click="imagecropperShow=true",此时就会显示上传组件
  • :key:类似于标签的id属性

  • :url:表单提交的路径

  • field="file":我们在前端学过,上传按钮的代码是:<input type="file" name="file"/>field="file"就相当于以前上传按钮中的name="file"

  • @close:关闭上传组件

  • @crop-upload-success:上传成功后会调用这里面的方法

6.3使用组件

data() {...}中创建数据模型

imagecropperShow: false, //上传组件是否显示(默认不显示)
imagecropperKey: 0, //上传组件的key值
BASE_API: process.env.BASE_API, //固定写法,表示获得dev.env.js里面的BASE_API值

在这里插入图片描述

6.4引入组件和声明组件

1.引入组件模块

import ImageCropper from '@/components/ImageCropper'
import PanThumb from '@/components/PanThumb'

在这里插入图片描述

2.在export default {...}中做一个声明,这样才可以使用这个组件

components: {
    
     ImageCropper, PanThumb },

在这里插入图片描述

6.5修改上传接口地址

在这里插入图片描述

6.6定义close和cropSuccess方法

定义close方法,点击弹框的关闭按钮时执行此方法,方法内部来关闭弹框;

定义cropSuccess方法,上传成功后回调

//点击弹框的关闭按钮时执行此方法
close() {
    
    
  //关掉弹框
  this.imagecropperShow = false
},
//上传成功后回调
cropSuccess(data) {
    
    
  //1.关掉弹框
  this.imagecropperShow = false
  //2.得到图片地址并赋值
  this.teacher.avatar = data.url
},

在这里插入图片描述

cropSuccess(data) {...}的参数data是后端返回的数据,就和"demo04-前端技术"的"4.axios"的第7步的②里面的.then(response => {...})中的参数response类似,只是后者想要得到url需要response.data.data.url,而前者因为人家给做了封装,想要得到url只需要data.url

6.7设置默认头像

我们在"4.4.3测试"中上传的默认头像的地址是https://edu-mxy.oss-cn-hangzhou.aliyuncs.com/2022/08/17/66e307e5727c41d7a3617891509278dcdefault.jpg所以我们在init方法中添加如下一行代码来设置默认头像

this.teacher.avatar = 'https://edu-mxy.oss-cn-hangzhou.aliyuncs.com/2022/08/17/66e307e5727c41d7a3617891509278dcdefault.jpg'

在这里插入图片描述

6.8测试

1.刷新页面,在"添加讲师"路由上传图片

在这里插入图片描述

2.点击"保存"后就成功添加了这条讲师数据

在这里插入图片描述

3.去数据库看,可以看到确实成功添加讲师数据

在这里插入图片描述

4.去阿里云控制台看刚刚上传的图片的详情:

在这里插入图片描述

发现一个问题:红框圈的这里是file而不是我们本地的文件名233

这是因为:考虑到我们有的人给文件起名会起中文,所以上传组件内部给我们做了优化:我们通过该组件上传的所有文件这个位置都固定是file而不再是本地的文件名

6.9bug

1.点击"更换头像"成功上传头像后,如果再点"更换头像",会出现下图所示的弹框。这个弹框显示"上传成功"而不是让我们选择图片重新上传,这显然不是我们想要的弹框

在这里插入图片描述

2.我们只有将这个弹框关闭后再次点击"更换头像"才会出现我们想要的弹框

在这里插入图片描述

3.想要解决这个bug需要每次关闭弹框或上传成功后都初始化上传组件:

给close方法和cropSuccess方法都添加一行代码this.imagecropperKey = this.imagecropperKey + 1;

在这里插入图片描述

为什么这行代码可以初始化上传组件?

  • 在这两处都加上这行代码后,无论是关闭弹框还是成功上传头像,imagecropperKey的值都会自增1,且在"6.2在save.html添加上传组件"中我们说过:key="imagecropperKey"的作用类似于标签的id属性,也就说无论是关闭弹框还是成功上传头像,上传组件的id都会自增1,所以每次点击"更换头像"后打开的都是新的上传组件,这样就实现了初始化上传组件
    • 当然,我这里是每次让imagecropperKey自增1,其实,让他自增多少,自减多少都是可以的,因为我们的目的仅仅是让每次的imagecropperKey的值不一样就可以了

猜你喜欢

转载自blog.csdn.net/maxiangyu_/article/details/127025750