尚硅谷谷粒学院项目第六天内容之对象存储oss服务、使用EasyExcel添加课程分类功能、课程列表分类、ningx的使用
打开阿里云官网——对象存储——oss管理控制台
创建bucket:选择默认地域、低频访问、公共读
对象存储oss——概览——常用入口——Access key
点击继续使用Accesskey
创建AccessKey——复制——确定
在service下创建SpringBoot子模块service_oss
引入依赖
com.aliyun.oss
aliyun-sdk-oss
joda-time
joda-time
配置application.properties
注意:地域节点、key、密钥要换成你自己的
#服务端口
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=LTAI5t6R5cWusp7MeWpKgT1W
aliyun.oss.file.keysecret=Dd6Ku0j5dQja9jh4d7cl8ULepWcNE7
#bucket
aliyun.oss.file.bucketname=bucket--a
创建启动类,启动模块
报错
在启动类上添加:
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
创建一个常量类,用来读取配置文件中的属性值
创建utils.ConstantRead类
@Component
public class ConstantRead 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 ENDPOINT;
public static String KEY_ID;
public static String KEY_SECRET;
public static String BUCKET_NAME;
@Override
public void afterPropertiesSet() throws Exception {
ENDPOINT=endpoint;
KEY_ID=keyId;
KEY_SECRET=keySecret;
BUCKET_NAME=bucketName;
}
}
创建OssController
@RestController
@RequestMapping("/ossservice")
public class OssController {
@Autowired
private OssService ossService;
//上传头像
@PostMapping("uploadAvatar")
public R uploadFile(MultipartFile file){
String url = ossService.uploadAvatar(file);
return R.ok().data("url",url);
}
}
创建OssService
@Service
public interface OssService {
//上传头像
String uploadAvatar(MultipartFile file);
}
创建OssServiceImpl
@Component
public class OssServiceImpl implements OssService {
@Override
public String uploadAvatar(MultipartFile file) {
String endpoint = ConstantRead.ENDPOINT;
String accessKeyId = ConstantRead.KEY_ID;
String accessKeySecret = ConstantRead.KEY_SECRET;
String bucketName = ConstantRead.BUCKET_NAME;
String filename = file.getOriginalFilename();
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
InputStream inputStream = file.getInputStream();
// 创建PutObject请求。
ossClient.putObject(bucketName, filename, inputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return "http://"+bucketName+"."+endpoint+"/"+filename;
}
}
swagger测试
如果多个用户上传的文件名字相同,后上传的文件会把先上传的文件覆盖掉
我们在文件名前加上uuid值,让每个文件名都不同
在OssServiceImpl里添加
String filename = file.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
filename=uuid+filename;
此时上传的文件都是在bucket的根目录下
把文件按照日期进行分类
在OssServiceImpl里添加
String date = new DateTime().toString("yyyy/MM/dd");
filename=date+"/"+uuid+filename;
测试
nginx:反向代理服务器
功能:请求转发、负载均衡、动静分离
下载windows版的nginx,解压
在cmd中通过nginx.exe命令启动
关闭cmd窗口,nginx不会关闭
关闭nginx:nginx.exe -s stop
配置nginx实现请求转发功能
编辑nginx安装目录/conf/nginx.conf
将默认端口从80改为81,不改会端口冲突
添加端口映射规则
server {
listen 9001;
server_name localhost;
location ~ /eduservice/ {
proxy_pass http://localhost:8001;
}
location ~ /ossservice/ {
proxy_pass http://localhost:8002;
}
}
将前端模板中config/dev.env.js中的BASE_API端口号改为9001
重启ningx、重启前后端,测试
将组件 ImageCropper和PanThumb 复制到项目中的 src/components 目录下
在save.vue中添加上传头像的组件
更换头像
引入组件
import ImageCropper from '@/components/ImageCropper'
import PanThumb from '@/components/PanThumb'
声明组件
components: { ImageCropper, PanThumb },
定义变量
imagecropperShow:false,
imagecropperKey:0,
BASE_API:process.env.BASE_API,
修改上传url
写两个方法
close(){
this.imagecropperShow=false
},
cropSuccess(data){ //data是后端返回的数据,相当于response.data,这里做了封装
this.imagecropperShow=false
this.teacher.avatar=data.url
},
上传了头像后,再次点击更换头像,出现上传成功字样,而不是“将图片拖拽至此处”
解决:
改变imagecropperKey的值相当于让上传组件初始化
课程分类使用二级分类:通过parentId实现
创建edu_subject表
CREATE TABLE `edu_subject` (
`id` char(19) NOT NULL COMMENT '课程类别ID',
`title` varchar(10) NOT NULL COMMENT '类别名称',
`parent_id` char(19) NOT NULL DEFAULT '0' COMMENT '父ID',
`sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序字段',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程科目';
向edu_subject表中添加数据
INSERT INTO `edu_subject` VALUES ('1178214681118568449','后端开发','0',1,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681139539969','Java','1178214681118568449',1,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681181483010','前端开发','0',3,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681210843137','JavaScript','1178214681181483010',4,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681231814658','云计算','0',5,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681252786178','Docker','1178214681231814658',5,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681294729217','Linux','1178214681231814658',6,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681324089345','系统/运维','0',7,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681353449473','Linux','1178214681324089345',7,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681382809602','Windows','1178214681324089345',8,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681399586817','数据库','0',9,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681428946945','MySQL','1178214681399586817',9,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681454112770','MongoDB','1178214681399586817',10,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681483472898','大数据','0',11,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681504444418','Hadoop','1178214681483472898',11,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681529610242','Spark','1178214681483472898',12,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681554776066','人工智能','0',13,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681584136193','Python','1178214681554776066',13,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681613496321','编程语言','0',14,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681626079234','Java','1178214681613496321',14,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178585108407984130','Python','1178214681118568449',2,'2019-09-30 16:19:22','2019-09-30 16:19:22'),('1178585108454121473','HTML/CSS','1178214681181483010',3,'2019-09-30 16:19:22','2019-09-30 16:19:22');
EasyExcel是处理excel表格的工具,将excel里的数据一行一行读进内存,高效简单
新建一个SpringBoot模块用来测试easyexcel
创建excel表格,用于测试
首先,引入依赖,easyecxel(2.1.1)+poi(3.17),版本之间有对应关系
com.alibaba
easyexcel
2.1.1
org.apache.poi
poi
3.17
创建与excel表对应的实体类
@Data
public class Entity {
@ExcelProperty("学生编号")
private Integer sno;
@ExcelProperty("学生姓名")
private String name;
}
使用easyexcel向excel表格中写入数据
public class WriteTest {
public static void main(String[] args) {
String filename="F:\\temp\\test.xlsx";
EasyExcel.write(filename,Entity.class).sheet("学生列表").doWrite(getData());//会自动关流
}
public static List getData(){
ArrayList list = new ArrayList<>();
for (int i=0;i<10;i++){
Entity entity = new Entity();
entity.setSno(i);
entity.setName("lucy"+i);
list.add(entity);
}
return list;
}
}
执行结果
创建与excel表对应的实体类
@Data
public class ReadEntity {
@ExcelProperty(value = "学生编号",index = 0)
private Integer sno;
@ExcelProperty(value = "学生姓名",index = 1)
private String sname;
}
创建监听器
public class EasyExcelListener extends AnalysisEventListener {
//一行一行读取数据(不读表头),数据封装在 readEntity
@Override
public void invoke(ReadEntity readEntity, AnalysisContext analysisContext) {
System.out.println(readEntity);
}
//读取表头
@Override
public void invokeHeadMap(Map headMap, AnalysisContext context) {
System.out.println(headMap);
}
//读取完成后的处理
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
使用easyexcel读excel表格的数据
public class ReadTest {
public static void main(String[] args) {
String filename="F:\\temp\\test.xlsx";
EasyExcel.read(filename,ReadEntity.class,new EasyExcelListener()).sheet().doRead();
}
}
执行结果
生成代码框架:在service_edu模块,打开之前写的代码编辑器:src\test\java\com\jiabei\demo\CodeGenerator.java
修改数据库表名
执行后生成代码框架。
添加依赖
com.alibaba
easyexcel
2.1.1
创建与xlsx对应的实体类 com\jiabei\eduservice\entity\xlsx\SubjectSort.java
@Data
public class SubjectSort {
@ExcelProperty(index=0)
private String oneSubjectName;
@ExcelProperty(index=1)
private String twoSubjectName;
}
在实体类EduSubject中添加属性自动填充注解
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
@TableField(fill=FieldFill.INSERT)
private Date gmtCreate;
@TableField(fill=FieldFill.INSERT_UPDATE)
private Date gmtModified;
controller
@RestController
@RequestMapping("/eduservice/subject")
@CrossOrigin
public class EduSubjectController {
@Autowired
private EduSubjectService subjectService;
//添加学科类别:将上传的xlsx文件添加到数据库中
@PostMapping("addSubjectSort")
public R addSubjectSort(MultipartFile file){
subjectService.addSubjectSort(file);
return R.ok();
}
}
service
public interface EduSubjectService extends IService {
void addSubjectSort(MultipartFile file);
}
serviceImpl
@Service
public class EduSubjectServiceImpl extends ServiceImpl implements EduSubjectService {
@Autowired
private SubjectSortListener listener;
@Override
public void addSubjectSort(MultipartFile file) {
try {
InputStream in = file.getInputStream();
EasyExcel.read(in, SubjectSort.class,listener).sheet().doRead();//读取学科分类数据,listener.invoke()监听器负责将它们读到数据库
}catch (Exception e){
e.printStackTrace();
}
}
}
listener
@Component
public class SubjectSortListener extends AnalysisEventListener {
@Autowired
private EduSubjectService subjectService;
@Override
public void invoke(SubjectSort subjectSort, AnalysisContext analysisContext) {
if (subjectSort==null){
throw new GuliException(20001,"excel表中没有数据,读取失败");
}
String pid = addOne(subjectSort.getOneSubjectName());
addTwo(subjectSort.getTwoSubjectName(),pid);
}
//添加一级分类
private String addOne(String name){
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("title",name);
queryWrapper.eq("parent_id","0");
EduSubject subject = subjectService.getOne(queryWrapper);//该分类是否已存在
if (subject==null){//不存在时添加
EduSubject s = new EduSubject();
s.setParentId("0");
s.setTitle(name);
subjectService.save(s);
}
return subjectService.getOne(queryWrapper).getId();
}
//添加二级分类
private void addTwo(String name,String pid){
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("title",name);
queryWrapper.eq("parent_id",pid);
EduSubject subject = subjectService.getOne(queryWrapper);
if(subject==null){
EduSubject s = new EduSubject();
s.setTitle(name);
s.setParentId(pid);
subjectService.save(s);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) { }
}
将edu_subject表中数据清空,然后swagger测试,成功把excel表中的数据读到了数据库