项目第六天
1、添加讲师实现头像上传功能
(1)阿里云oss存储服务
2、添加课程分类功能(复杂)
(1)使用EasyExcel读取Excel内容添加数据
3、课程分类的列表
(1)树形结构显示
4、Nginx的使用
为了解决海量数据存储与弹性扩容,项目中我们采用云存储的解决方案- 阿里云OSS
1、打开阿里云网站
2、注册阿里云
3、登录阿里云
4、打开对象存储oss
5、开通存储对象oss
6、阿里云oss管理控制台的使用
(1)使用oss,首先创建bucket
1、准备工作:创建操作阿里云oss许可证(阿里云颁发id和秘钥)
// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "" ;
String accessKeySecret = "" ;
String bucketName = "" ;
// 上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
String objectName = "" ;
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
String content = "Hello OSS";
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
// 关闭OSSClient。
ossClient.shutdown();
<dependencies>
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
dependency>
<dependency>
<groupId>joda-timegroupId>
<artifactId>joda-timeartifactId>
dependency>
dependencies>
#服务端口
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=guli-file
修改配置后如下所示
#服务端口
server.port=8002
#服务名
spring.application.name=service-oss
#环境设置:dev、test、prod
spring.profiles.active=dev
#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=oss-cn-beijing.aliyuncs.com
aliyun.oss.file.keyid=LTAI4G7xYsEo22tATjUHWT4x
aliyun.oss.file.keysecret=G9dNSk9puPxhukjmm4Mfp4l5Jgx02T
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=edu-997
注意:
秘钥不能加空格,前面或者后面都不能有
@SpringBootApplication
@ComponentScan(basePackages = {"com.example"})
public class OssApplication {
public static void main(String[] args) {
SpringApplication.run(OssApplication.class,args);
}
}
spring boot 会默认加载org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration这个类,
而DataSourceAutoConfiguration类使用了@Configuration注解向spring注入了dataSource bean,又因为项目(oss模块)中并没有关于dataSource相关的配置信息,所以当spring创建dataSource bean时因缺少相关的信息就会报错。
**解决方式:**在启动类添加属性,默认不去加载数据库配置
//当项目已启动,spring接口,spring加载之后,执行接口一个方法
@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 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;
}
}
编写controller
@RestController
@RequestMapping("/eduoss/fileoss")
@CrossOrigin
public class OssController {
@Autowired
private OssService ossService;
//上传头像的方法
@PostMapping
public R uploadOssFile(MultipartFile file){
//获取上传文件
String url=ossService.uploadFileAvatar(file);
return R.ok().data("url",url);
}
}
编写service,在service实现上传文件到oss过程
在阿里云的学习路径中copy,上传文件流
// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。
String accessKeyId = "" ;
String accessKeySecret = "" ;
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 上传文件流。
InputStream inputStream = new FileInputStream("" );
ossClient.putObject("" , "" , inputStream);
// 关闭OSSClient。
ossClient.shutdown();
@Service
public class OssServiceImpl implements OssService {
@Override
public String uploadFileAvatar(MultipartFile file) {
// 工具类获取值
String endpoint = ConstantPropertiesUtils.END_POINT ;
String accessKeyId = ConstantPropertiesUtils.ACCESS_KEY_ID;
String accessKeySecret = ConstantPropertiesUtils.ACCESS_KEY_SECRET;
String bucketName = ConstantPropertiesUtils.BUCKET_NAME;
try{
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 获取上传文件流。
InputStream inputStream = file.getInputStream();
//获取文件名称
String fileName=file.getOriginalFilename();
//调用oss方法实现上传
//第一个参数:bucket名称
//第二个参数:上传到oss的文件路径和文件名称
//第三个参数:上传文件的输入流
ossClient.putObject(bucketName, fileName, inputStream);
// 关闭OSSClient。
ossClient.shutdown();
//把上传之火文件路径返回
//需要把上传到阿里云oss路径手动拼接出来
String url="https://"+bucketName+"."+endpoint+"/"+fileName;
return url;
}catch (Exception e){
}
return null;
}
}
多次上传相同名称文件,造成最后一次上传把之前上传文件覆盖
**解决:**在文件名称添加随机唯一值,让每个文件名称不同
根据日期进行分类
Nginx 反向代理服务器
什么是请求转发
把请求平均分担到不同的服务中去
(到后面会用到网关)
在线教育项目使用windows的Nginx足够了
特点:多路复用,使用cmd启动nginx,,需要使用nginx.exe -s stop手动停止停止
第二步:配置nginx转发规则
server {
listen 9001;//监听端口需要修改前端端口
server_name localhost;//主机
location ~/serviceedu/ {
proxy_pass http://localhost:8001;
}
location ~/eduoss/ {
proxy_pass http://localhost:8002;
}
}
1、在添加讲师页面,创建上传组件,实现上传使用element-ui组件实现
复制到前端项目的src component里面
2、在添加讲师页面使用组件
更换头像
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200512000754166.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2NzAxODM4,size_16,color_FFFFFF,t_70)
4、修改上传接口地址
5、
课程名称:java基础开发课程 分类:后端开发
课程名称:vue高级开发课程 分类:前端开发
1、数据导入:减轻录入工作量
2、数据导出:统计信息归档
3、数据传输:异构系统之间数据传输
第一步:引入easyexcel依赖
<dependencies>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>2.1.1version>
dependency>
dependencies>
需要poi依赖
第二步:
创建实体类,和Excel数据对应
第三步:
新建
public class TestEasyExcel {
public static void main(String[] args) {
//实现excel写操作
//1、设置写入文件夹地址和excel文件名称
String filename="F:\\write.xlsx";
//2、调用easyExcel里面的方法来实现写操作
//write里面的两个参数分别代表
EasyExcel.write(filename,DemoDate.class).sheet("学生列表").doWrite(getData());
}
//创建方法返回list集合
private static List<DemoDate> getData(){
List<DemoDate> list=new ArrayList<>();
for(int i=0;i<10;i++){
DemoDate data=new DemoDate();
data.setSname("lucy"+i);
data.setSno(i);
list.add(data);
}
return list;
}
}
第一步:创建和excel对应实体类,标记对应列关系
第二步:创建监听进行excel
第三步:方法调用
课程分类添加功能
第一步:引入easyExcel依赖
第二步:使用代码生成器把课程分类代码生成
@CrossOrigin
第三步:创建实体类和excel对应的关系
第四步:
package com.example.serviceedu.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.servicebase.config.execptionhandler.ExampleException;
import com.example.serviceedu.entity.EduSubject;
import com.example.serviceedu.entity.excel.SubjectData;
import com.example.serviceedu.service.EduSubjectService;
public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {
//因为SubjectExcelListener不能交给spring进行管理,需要自己new,不能注入其他对象
//不能实现数据库操作
public EduSubjectService subjectService;
public SubjectExcelListener() {}
public SubjectExcelListener(EduSubjectService subjectService) {
this.subjectService = subjectService;
}
//读取excel内容,一行一行进行读取
@Override
public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
if(subjectData == null) {
throw new ExampleException(20001,"文件数据为空");
}
//一行一行读取,每次读取有两个值,第一个值一级分类,第二个值二级分类
//判断一级分类是否重复
EduSubject existOneSubject = this.existOneSubject(subjectService, subjectData.getOneSubjectName());
if(existOneSubject == null) { //没有相同一级分类,进行添加
existOneSubject = new EduSubject();
existOneSubject.setParentId((long) 0);
existOneSubject.setTitle(subjectData.getOneSubjectName());//一级分类名称
subjectService.save(existOneSubject);
}
//获取一级分类id值
long pid = existOneSubject.getId();
//添加二级分类
//判断二级分类是否重复
EduSubject existTwoSubject = this.existTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);
if(existTwoSubject == null) {
existTwoSubject = new EduSubject();
existTwoSubject.setParentId(pid);
existTwoSubject.setTitle(subjectData.getTwoSubjectName());//二级分类名称
subjectService.save(existTwoSubject);
}
}
//判断一级分类不能重复添加
private EduSubject existOneSubject(EduSubjectService subjectService,String name) {
QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
wrapper.eq("title",name);
wrapper.eq("parent_id","0");
EduSubject oneSubject = subjectService.getOne(wrapper);
return oneSubject;
}
//判断二级分类不能重复添加
private EduSubject existTwoSubject(EduSubjectService subjectService,String name,long pid) {
QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
wrapper.eq("title",name);
wrapper.eq("parent_id",pid);
EduSubject twoSubject = subjectService.getOne(wrapper);
return twoSubject;
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
第二步:配置nginx转发规则
server {
listen 9001;//监听端口需要修改前端端口
server_name localhost;//主机
location ~/serviceedu/ {
proxy_pass http://localhost:8001;
}
location ~/eduoss/ {
proxy_pass http://localhost:8002;
}
}
1、在添加讲师页面,创建上传组件,实现上传使用element-ui组件实现
复制到前端项目的src component里面
2、在添加讲师页面使用组件
更换头像
4、修改上传接口地址
5、
课程名称:java基础开发课程 分类:后端开发
课程名称:vue高级开发课程 分类:前端开发
1、数据导入:减轻录入工作量
2、数据导出:统计信息归档
3、数据传输:异构系统之间数据传输
第一步:引入easyexcel依赖
<dependencies>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>2.1.1version>
dependency>
dependencies>
需要poi依赖
第二步:
创建实体类,和Excel数据对应
第三步:
public class TestEasyExcel {
public static void main(String[] args) {
//实现excel写操作
//1、设置写入文件夹地址和excel文件名称
String filename="F:\\write.xlsx";
//2、调用easyExcel里面的方法来实现写操作
//write里面的两个参数分别代表
EasyExcel.write(filename,DemoDate.class).sheet("学生列表").doWrite(getData());
}
//创建方法返回list集合
private static List<DemoDate> getData(){
List<DemoDate> list=new ArrayList<>();
for(int i=0;i<10;i++){
DemoDate data=new DemoDate();
data.setSname("lucy"+i);
data.setSno(i);
list.add(data);
}
return list;
}
}
第二步:创建监听进行excel
课程分类添加功能
第一步:引入easyExcel依赖
第二步:使用代码生成器把课程分类代码生成
生成之后先在controller中解决跨域问题
@CrossOrigin
package com.example.serviceedu.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.servicebase.config.execptionhandler.ExampleException;
import com.example.serviceedu.entity.EduSubject;
import com.example.serviceedu.entity.excel.SubjectData;
import com.example.serviceedu.service.EduSubjectService;
public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {
//因为SubjectExcelListener不能交给spring进行管理,需要自己new,不能注入其他对象
//不能实现数据库操作
public EduSubjectService subjectService;
public SubjectExcelListener() {}
public SubjectExcelListener(EduSubjectService subjectService) {
this.subjectService = subjectService;
}
//读取excel内容,一行一行进行读取
@Override
public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
if(subjectData == null) {
throw new ExampleException(20001,"文件数据为空");
}
//一行一行读取,每次读取有两个值,第一个值一级分类,第二个值二级分类
//判断一级分类是否重复
EduSubject existOneSubject = this.existOneSubject(subjectService, subjectData.getOneSubjectName());
if(existOneSubject == null) { //没有相同一级分类,进行添加
existOneSubject = new EduSubject();
existOneSubject.setParentId((long) 0);
existOneSubject.setTitle(subjectData.getOneSubjectName());//一级分类名称
subjectService.save(existOneSubject);
}
//获取一级分类id值
long pid = existOneSubject.getId();
//添加二级分类
//判断二级分类是否重复
EduSubject existTwoSubject = this.existTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);
if(existTwoSubject == null) {
existTwoSubject = new EduSubject();
existTwoSubject.setParentId(pid);
existTwoSubject.setTitle(subjectData.getTwoSubjectName());//二级分类名称
subjectService.save(existTwoSubject);
}
}
//判断一级分类不能重复添加
private EduSubject existOneSubject(EduSubjectService subjectService,String name) {
QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
wrapper.eq("title",name);
wrapper.eq("parent_id","0");
EduSubject oneSubject = subjectService.getOne(wrapper);
return oneSubject;
}
//判断二级分类不能重复添加
private EduSubject existTwoSubject(EduSubjectService subjectService,String name,long pid) {
QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
wrapper.eq("title",name);
wrapper.eq("parent_id",pid);
EduSubject twoSubject = subjectService.getOne(wrapper);
return twoSubject;
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}