6 讲师、课程后端接口


实现讲师头像上传功能

一、阿里云OSS存储服务

  1. 打开阿里云网站:https://www.aliyun.com/
  2. 注册阿里云账号
  3. 使用注册好的账号登录
  4. 找到阿里云OSS
  5. 开通
  6. 管理控制台的使用
  7. 使用OSS,首先需要创建buckets
  8. 点击文件管理可以上传文件

二、Java代码操作阿里云OSS,上传文件到阿里云OSS操作

  1. 准备工作:创建操作阿里云OSS的许可证(阿里云颁发的id和密钥)

  2. 新建service_oss子模块,在pom.xml中添加依赖

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

    # 服务端口
    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=LTAI5tCw6f4FczR3g6NV5Wan
    aliyun.oss.file.keysecret=9m0CaAa2eITtKqkGhv1o1J4AqzINbU
    # bucket可以在控制台创建,也可以使用java代码创建
    aliyun.oss.file.bucketname=prannt-edu-1010
  4. 项目启动时报错:启动的时候去找数据库的配置了,但这个模块不需要操作数据库,只是做上传到oss功能

    解决方案:在启动类上添加属性,默认不加载数据库的配置:

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

三、上传讲师头像的代码

  1. 创建常量类,读取配置文件的相关内容

    // 创建常量类,读取配置文件的相关内容
    // 当项目一启动,spring中有一个接口,spring加载之后执行接口的一个方法
    @Component
    public class ConstantPropertiesUtils implements InitializingBean {
        // 读取配置文件的内容
        // @Value()注解的作用:将括号中的值注入到endPoint中
        @Value("${aliyun.oss.file.endpoint}")
        private String endPoint;    // 地域节点
        @Value("{aliyun.oss.file.keyid}")
        private String keyId;       // 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对外可以使用,使用方法:类名.END_POINT
            END_POINT = endPoint;
            ACCESS_KEY_ID = keyId;
            ACCESS_KEY_SECRET = keySecret;
            BUCKET_NAME = bucketName;
        }
    }
  2. 创建controller

    @RestController
    @RequestMapping("eduoss/fileoss")
    public class OssController {
        
        @Autowired
        private OssService ossService;
    
        /**
         * 上传头像的方法
         * @param file 上传的文件
         * @return 上传到 oss的路径(网址)
         */
        @PostMapping
        public R uploadOssFile(MultipartFile file){
            String url = ossService.uploadFileAvatar(file);
            return R.ok().data("url",url);
        }
    }
  3. 在service层实现上传文件到oss的过程

    @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;
            OSS ossClient = null;
    
            try {
                // 创建OSSClient实例。
                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 (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
  4. 在swagger中进行测试

    http://localhost:8002/swagger-ui.html
  5. 讲师头像上传功能完善

    • 多次上传相同名称的文件,造成最后一次上传把之前上传的文件覆盖

      // 在文件名称中添加随机唯一值,让每个文件名称不同
      // 1.在文件名称里添加随机唯一的值,让每个文件名称都不相同
      String uuid = UUID.randomUUID().toString().replaceAll("-","");
      filename = uuid + filename;
    • 把文件分类管理(根据日期分类,实现年月日分类)

      // 2.把文件按照日期进行分类
      // 2019/11/12/01.jpg
      // 获取当前日期
      String datePath = new DateTime().toString("yyyy/MM/dd");
      // 拼接
      filename = datePath + "/" + filename;

四、Nginx的使用

  1. Nginx:反向代理服务器,可以用来做请求转发、负载均衡、动静分离

  2. 什么是请求转发?

  3. 什么是负载均衡?

  4. 什么是动静分离?

    把Java代码和页面分开进行部署

  5. 使用cmd启动nginx

    nginx.exe
  6. 如果关闭cmd窗口,nginx不会停止,可以使用命令停止

    nginx.exe -s stop
  7. 配置nginx实现请求转发的功能

    • 找到nginx配置文件

    • 在nginx.conf里进行配置

    • 前端(config/dev.env.js)中的端口号改成

      BASE_API: '"http://localhost:9001"',
    • 重新启动nginx

      nginx.exe -s stop
      nginx.exe
    • 测试

      // 启动后端的两个端口(8001和8002)
      // 重启前端代码
      npm run dev

五、上传讲师头像前端实现

  1. 在讲师添加页面,创建上传组件,实现上传功能(使用element-ui中的组件)

  2. 在添加讲师页面使用这两个组件(以下几步都在save.vue中)

  3. 使用组件

  4. 引入组件和声明组件

添加课程分类的功能(使用EasyExcel读取excel内容添加数据)

一、创建数据库表

具体的sql语句见:**谷粒学院sql**

二、EasyTask操作

  1. 在service_edu的test下进行测试

  2. 引入EasyTask的依赖

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.5</version>
        </dependency>
    </dependencies>
    <!--还需要的依赖,已经在父工程中引入过了-->
  3. 创建实体类(需要和excel中的字段对应)

    @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 = "C:\\write.xls";
            // 2.调用EasyExcel里面的方法实现写操作
            // 参数1:文件的路径名称;参数2:实体类class
            EasyExcel.write(filename,DemoData.class).sheet("学生列表").doWrite(getData());
        }
    
        // 创建一个方法,返回list集合
        private static List<DemoData> getData(){
            List<DemoData> list = new ArrayList<>();
            DemoData data = new DemoData();
            for (int i = 0; i < 10; i++) {
                data.setSno(i);
                data.setSname("lucy" + i);
                list.add(data);
            }
            return list;
        }
    }
  5. excel读操作

    // 1.创建实体类
    @Data
    public class DemoData2 {
        // 设置excel表头的名称(一级分类和二级分类)
        @ExcelProperty(value = "学生编号",index = 0)
        private String sno;    // 学生编号
        @ExcelProperty(value = "学生姓名",index = 1)
        private String sname;   // 学生姓名
    }
    
    // 2.创建监听进行excel文件读取
    public class ExcelListener extends AnalysisEventListener<DemoData2> {
        // 一行一行的读取excel内容
        @Override
        public void invoke(DemoData2 demoData2, AnalysisContext analysisContext) {
            System.out.println("****" + demoData2);
        }
    
        // 读取表头的内容
        // 该方法可以在AnalysisEventListener类中直接复制
        @Override
        public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
            System.out.println("表头" + headMap);
        }
    
        // 读取完成之后做的事情
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    
        }
    }
    
    // 3.最终方法的调用
    public class TestEasyExcel2 {
        public static void main(String[] args) {
            // 实现excel的读操作
            String filename = "C:\\01.xls";
            EasyExcel.read(filename,DemoData2.class,new ExcelListener()).sheet().doRead();
        }
    
        // 创建一个方法,返回list集合
        private static List<DemoData> getData(){
            List<DemoData> list = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                DemoData data = new DemoData();
                data.setSno(i);
                data.setSname("lucy" + i);
                list.add(data);
            }
            return list;
        }
    }

三、课程分类添加功能

  1. 引入依赖

  2. 使用代码生成器把课程分类的代码生成出来

    // 将测试类(CodeGenerator)中的参数改为edu_subject表
    strategy.setInclude("edu_subject");
    // 运行
  3. 编写EduSubjectController

    @RestController
    @RequestMapping("/eduservice/subject")
    @CrossOrigin
    public class EduSubjectController {
        @Autowired
        private EduSubjectService subjectService;
    
        // 添加课程分类
        // 获取上传过来的文件,把文件内容读取出来
        @PostMapping("addSubject")
        public R addSubject(MultipartFile file){
            // 拿到上传过来的excel文件
            subjectService.saveSubject(file,subjectService);
            return R.ok();
        }
    }
  4. 创建实体类,和excel有对应关系

    // 创建和excel对应的实体类
    @Data
    public class SubjectData {
        @ExcelProperty(index = 0)
        private String oneSubjectName;
        @ExcelProperty(index = 1)
        private String twoSubjectName;
    }
  5. service层

    // 接口
    public interface EduSubjectService extends IService<EduSubject> {
        // 添加课程分类
        void saveSubject(MultipartFile file,EduSubjectService subjectService);
    }
    
    // 实现类
    @Service
    public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {
        // 添加课程分类
        @Override
        public void saveSubject(MultipartFile file,EduSubjectService subjectService) {
            try {
                // 文件输入流
                InputStream in = file.getInputStream();
                // 调用方法进行读取
                EasyExcel.read(in, SubjectData.class,new SubjectExcelListener(subjectService)).sheet().doRead();
            }catch (Exception e){
    			e.printStackTrace();
            }
        }
    }
  6. 监听器

    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 GuliException(20001,"文件数据为空");
            // 判断一级分类是否重复
            EduSubject existOneSubject = this.existOneSubject(subjectService, subjectData.getOneSubjectName());
            if (existOneSubject == null){
                // 没有相同的一级分类,进行添加
                existOneSubject = new EduSubject();
                existOneSubject.setParentId("0");
                existOneSubject.setTitle(subjectData.getOneSubjectName());  // 一级分类名称
                subjectService.save(existOneSubject);
            }
    
            // 获取一级分类的id值
            String 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,String 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) {
    
        }
    }

四、注意

// 1.添加注解@TableId
@ApiModelProperty(value = "课程类别ID")
@TableId(type = IdType.ID_WORKER_STR)
private String id;

// 2.时间自动填充    
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;

@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;

文章作者: Prannt
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Prannt !
评论
  目录