Day6 - 头像存储与EasyExcel

一. 阿里云OSS存储

阿里云的对象存储 OSS 提供海量、安全、低成本、高可靠的云存储服务,很多公司都会使用它来进行数据存储。因此,我们将讲师头像存储在这里。

1. 注册并创建存储空间

进入阿里云官网,注册账号登录,并实名认证。之后找到 OSS 存储:
在这里插入图片描述
进入后点击【立即开通】,开通成功后,按钮变为【管理控制台】,点击后进入下列页面。点击【创建 Buket】即可创建一个存储空间:
在这里插入图片描述
点击刚创建的 bucket 名称,可以查看存储的东西,或者上传文件:
在这里插入图片描述

2. 获取 key

在主页面,有一个【Access Key】按钮,点击后按照要求获取 key 供后续代码使用:
在这里插入图片描述

3. 官方文档

阿里云 OSS Java 使用官方文档

(1)安装

在pom.xml中添加:

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.8.0</version>
</dependency>

(2)使用代码创建存储空间

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

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

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

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

(3)上传文件流

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

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

// 上传文件流。
InputStream inputStream = new FileInputStream("<yourlocalFile>");
ossClient.putObject("<yourBucketName>", "<yourObjectName>", inputStream);

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

二. 头像上传后台开发

1. service-oss 模块搭建

(1)在 service 下右键选择 New Module… 创建一个子模块 service-oss;
(2)在 pom.xml 中添加 oss 依赖(版本信息在主模块中已经配置了):

<dependencies>
	<!--阿里云oss依赖-->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
    </dependency>
</dependencies>

(3)创建 application.properties 以及启动类文件:

#服务端口号
server.port=8082

#服务名
spring.application.name=service-oss
#环境设置
spring.profiles.active=dev

#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=oss-cn-beijing.aliyuncs.com
aliyun.oss.file.keyid=LTAI4GEMTPi4AYWfHuxkiGA9
aliyun.oss.file.keysecret=ijJ10mCflSnbVc89V3zFIYT3zQqpze
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=guli-edu-avatar-2020

要注意一点,由于上述配置文件中不需要配置数据库相关内容,启动时会报错,因此下面 @SpringBootApplication 注解中要加上 exclude = DataSourceAutoConfiguration.class

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

2. 后台上传代码

(1)获取配置文件中的 OSS 各项值;

配置文件中的值可以通过 @Value(${xxx}) 注解进行获取,创建一个Util类专门用于获取配置文件中的值。但由于此时值是 private 的,所以需要将其赋值给一个public 对象。可以实现 InitializingBean 接口中的 afterPropertiesSet 方法,它在项目启动时,获取到值后即被调用。

注意这里不能直接定义 public 对象,再在它的上面加@Value注解,值会取不到。

@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_ID = keyId;
        KEY_SECRET = keySecret;
        BUCKET_NAME = bucketName;
    }
}

(2)创建 controler 和 service 类

我们是先创建了一个 service 接口,再创建了它的一个实现类,
在这里插入图片描述
controller中的注入可以注入接口,也可以注入具体的实现类。(当有多个实现类时只能注入实现类,否则会报错有多个 bean 是 OssService 类型):

@Autowired
private OssService ossService;

但是接口中只定义了方法:

public interface OssService {
    String uploadAvatar(MultipartFile file);
}

真正实现以及 @Service 注解都是在实现类上:

@Service
public class OssServiceImpl implements OssService {

    @Override
    public String uploadAvatar(MultipartFile file) {
        String endPoint = ConstantPropertiesUtil.END_POINT;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        String keyId = ConstantPropertiesUtil.KEY_ID;
        String keySecret = ConstantPropertiesUtil.KEY_SECRET;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint, keyId, keySecret);

        try {
            ossClient.putObject(bucketName, file.getOriginalFilename(), file.getInputStream());
            // 关闭OSSClient。
            ossClient.shutdown();
            return "https://" + bucketName + "." + endPoint + "/" + file.getOriginalFilename();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

上述代码会出现文件重名覆盖的问题,通过修改文件名解决文件重名覆盖问题,并按日期文件夹分类:

String fileName = file.getOriginalFilename();
//添加uuid防止文件重名
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
fileName = uuid + fileName ;
//添加日期,按日期创建文件夹对文件分类
String date = new DateTime().toString("yyyy/MM/dd");
fileName = date + "/" + fileName;

三. nginx 请求转发

1. nginx 基础概念

由于现在后端有两个服务(eduservice 和 oss),一个在 8081,一个 8082 端口,那前端发送的请求如何被正确转发到对应端口呢?答案是使用 **nginx **。

nginx 能够实现:

  1. 请求转发
  2. 负载均衡
  3. 动静分离(将静态的代码文件与动态文件分开存储)
    在这里插入图片描述
    在这里插入图片描述

2. 实现请求转发

如何使用 nginx 实现请求转发呢?

(1)首先下载 ngnix for windows,然后修改其配置文件 …\nginx-1.18.0\conf\nginx .conf

http {
	server {
        listen       9001; //修改监听的端口号防止冲突
        server_name  localhost;
		
		//添加需要转发的请求地址:~ 表示正则匹配
		location ~ /eduservice/ {
			proxy_pass http://localhost:8081;
		}
		
		location ~ /oss/ {
			proxy_pass http://localhost:8082;
		}
	}
}

(2)修改前端端口号为 nginx 中配置的端口号:
在这里插入图片描述
(3)前端重新启动,并启动后端两个服务。再启动 nginx 。注意启动 nginx 前最好先 stop 掉它之前的进程:

nginx -s stop

四. 头像上传前端代码

1. 导入上传文件模块

确保 components 模块下有这两个模块,没有的话下载拷贝过来就行:
在这里插入图片描述
前端代码导入模块:

<script>
//导入
import ImageCropper from '@/components/ImageCropper'
import PanThumb from '@/components/PanThumb'

export default {
    components: {ImageCropper, PanThumb} //声明
}

2. 头像上传组件

<el-form-item label="头像">
     <!--头像缩略图-->
     <pan-thumb :image="teacherForm.avatar"/>
     <el-button type="primary" icon="el-icon-upload" @click="imageUploadShow=true">更换头像
     </el-button>
     
	//点击上传文件后调用的组件
     <image-cropper
         v-show="imageUploadShow"
         :width="300"
         :height="300"
         :key="imageKey" //用于重新初始化组件
         :url="BASE_API + '/oss/fileupload/avatar'" //后端文件上传的url地址
         field="file"
         @close="close"
         @crop-upload-success="cropSuccess" //上传成功后调用的方法
     />
</el-form-item>
data() {
	return {
        imageUploadShow: false,
        BASE_API: process.env.BASE_API, //从dev.env.js文件中读取的内容
        imageKey: 0,
    }
},

添加方法的定义:

close() {
	this.imageUploadShow = false
	this.imageKey = this.imageKey + 1 //用于重新初始化组件,防止上次成功后第二次点击上传出现bug
},
//这是上传成功后调用的方法,自动封装data的内容
cropSuccess(data) {
    this.imageUploadShow = false
    this.teacherForm.avatar = data.url
    this.imageKey = this.imageKey + 1
}

五. EasyExcel的使用

后续内容要用到 EasyExcel,这里先介绍下如何使用EasyExcel进行读写。

1. 引入 pom 依赖

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

注意:其实还需要引入 poi 依赖,前面已经引入过了。

2. 写操作

建立一个实体类,用 @ExcelProperty 注解标识它在 excel 表中的列名

@Data
public class EasyExcelEntity {

    @ExcelProperty(value = "学生编号", index = 0)
    private Integer sno;

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

写操作:

String fileName = "D:\\stu.xlsx";
List<EasyExcelEntity> stuList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    EasyExcelEntity entity = new EasyExcelEntity();
    entity.setSno(i);
    entity.setSname("hi" + i);
    stuList.add(entity);
}
EasyExcel.write(fileName, EasyExcelEntity.class).sheet("学生列表").doWrite(stuList);

3. 读操作

同样需要上述一个实体类对应 excel 表中的列名,此外比 “写操作” 更麻烦一点的是需要建立一个监听器

public class EasyExcelListener extends AnalysisEventListener<EasyExcelEntity> {
    
    //一行一行读取代码时进行的操作
    @Override
    public void invoke(EasyExcelEntity easyExcelEntity, AnalysisContext analysisContext) {
        System.out.println(easyExcelEntity.getSno() + ": " + easyExcelEntity.getSname());
    }

	//读取完进行的操作
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

读操作:

EasyExcel.read(fileName, EasyExcelEntity.class, new EasyExcelListener()).sheet().doRead();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值