• 学成在线第一天


    学完以下技术栈后,可进行本项目的学习
    应用到的技术
    开始学习:

    项目的简单介绍

    从在线教育的火热到如今,在线教育的模式出现多种多样,包括:B2C、C2C、B2B2C等业务模式。学成在线采用B2B2C业务模式,即向企业或个人在线教育平台提供教学服务,老师和学生通过平台完成整个教学和学习的过程,市场上类似的平台有:网易云课堂、腾讯课堂等,学成在线的特点是IT职业课程在线教学。

    学成在线包括在线教育平台、业务支持系统、基础服务来构建整个功能架构

    架构图:
    在这里插入图片描述
    技术栈列表:

    在这里插入图片描述

    模块功能列表:

    1.在线教育平台

    功能模块名称功能说明
    门户在首页、活动页、专题页等页面提供课程学习入口。
    教学管理平台教学机构登录系统的入口,通过此来管理机构中的课程相关的数据。
    运营平台教师登录教学管理中心进行课程管理、资源管理、考试管理等教学活动。

    2.业务系统支撑

    功能模块名称功能说明
    内容管理系统内容管理中对教学机构的课程、课程计划、课程教师、课程营销数据进行管理
    教学管理中心对平台的入住教学机构数据进行管理和审核,以及课程中设计到的课程作业。
    学习中心对课程中的学员学习课程的记录数据来进行管理。
    社交系统论坛系统、问答系统、消息系统、评论系统等信息的管理
    媒资管理课程计划所关联的课程流媒体资源数据进行管理(直播、录播)。

    3.基础服务

    功能模块名称功能说明
    系统管理对学成在线后端服务提供系统的基础数据。
    支付系统管理收费课程的交易记录和订单数据。
    文件服务管理系统中的文件资源,包括课程图片、教师图片等。
    验证码服务生成系统中的验证码并通过短息服务发送验证码、校验验证码等。
    统一认证服务对系统中的所有用户资源进行管理,并提供服务中用户资源的认证功能
    视频点直播在课程学习时需要通过此服务来对视频资源进行播放。

    剩下的流程图、UML我就不介绍了,直接开始实战

    环境搭建

    导入linux镜像,并使用docker容器开启组件:
    在这里插入图片描述
    启动nginx导入前端页面:
    在这里插入图片描述
    配置访问host
    前端项目中,各个页面跳转都是由域名构成。为了方便需要修改本机host地址。

    进入C:\Windows\System32\drivers\etc目录,修改hosts文件。添加如下内容。温馨提示:做好备份

    #门户网站域名
    127.0.0.1 www.xuecheng.com
    #企业管理后台
    127.0.0.1 admin.xuecheng.com
    #机构管理后台
    127.0.0.1 manage.xuecheng.com
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    配置成功后,在浏览器打开http://admin.xuecheng.com即可进入企业管理后台页面

    后端环境搭建

    在这里插入图片描述
    在这里插入图片描述
    项目基于前后端分离的架构进行开发,前后端分离架构总体上包括前端和服务端,通常是多人协作开发

    • 前后端分离开发基于HTTP+JSON交互

    • 通过接口文档(API文档)定义规范

    • 前后端按照文档定义请求及响应数据

    这里我们使用YAPI接口文档管理

    登录功能

    在写代码前,我们可以回想一下以前是怎么进行身份验证的?
    没错 cookie 或session,但是对于前端来说,有移动端页面,h5页面,VUE页面,对于手机端页面可能就没有session,所以用这俩存登录信息,权限检验,就不行了
    下面介绍一个新的身份校验工具——JWT
    在这里插入图片描述
    在这里插入图片描述
    小实例:
    首先导入依赖:

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试类:

    @Test
    public void testCreateToken() {
        //生成token
        //1 准备数据
        Map map = new HashMap();
        map.put("id",1);
        map.put("mobile","13800138000");
        //2 使用JWT的工具类生成token
        long now = System.currentTimeMillis();
        String token = Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, "zjf") //指定加密算法
                .setClaims(map) //写入数据
                .setExpiration(new Date(now + 30000)) //失效时间
                .compact();
        System.out.println(token);
    }
    
    //解析token
    
    /**
     * SignatureException : token不合法
     * ExpiredJwtException:token已过期
     */
    @Test
    public void testParseToken() {
        String token = "...";//这里面换成上面测试打印的token
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey("zjf")
                    .parseClaimsJws(token)
                    .getBody();
            Object id = claims.get("id");
            Object mobile = claims.get("mobile");
            System.out.println(id + "--" + mobile);
        }catch (ExpiredJwtException e) {
            System.out.println("token已过期");
        }catch (SignatureException e) {
            System.out.println("token不合法");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    基本介绍完毕, 下面完成登录功能:

    在这里插入图片描述
    接口文档:
    在这里插入图片描述
    在这里插入图片描述
    需要使用的数据表:
    在这里插入图片描述
    后端代码显示:

    web层:
    在这里插入图片描述

    package com.xuecheng.system.controller;
    
    import com.xuecheng.commons.model.dto.LoginDto;
    import com.xuecheng.commons.model.vo.ResponseResult;
    import com.xuecheng.system.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class LoginController {
        @Autowired
        private UserService userService;
    
        @PostMapping("/login")
        public ResponseResult organizationLogin(@RequestBody LoginDto loginDto){
            return userService.organizationLogin(loginDto);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    service层:
    在这里插入图片描述

    public interface UserService extends IService<User> {
    
        ResponseResult organizationLogin(LoginDto loginDto);
    }
    
    • 1
    • 2
    • 3
    • 4

    serviceImpl层:

    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public ResponseResult organizationLogin(LoginDto loginDto) {
            if (StrUtil.isBlank(loginDto.getUsername())) {
                throw new BusinessException(ErrorCode.DATAERROR);
            }
            if (StrUtil.isBlank(loginDto.getPassword())) {
                throw new BusinessException(ErrorCode.DATAERROR);
            }
            if (StrUtil.isBlank(loginDto.getUtype())) {
                throw new BusinessException(ErrorCode.DATAERROR);
            }
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getPhone, loginDto.getUsername());
            wrapper.eq(User::getUtype, loginDto.getUtype());
            User user = userMapper.selectOne(wrapper);
            if (BeanUtil.isEmpty(user)){
                User u = new User();
                u.setPhone(loginDto.getUsername());
                u.setPassword(DigestUtil.md5Hex(loginDto.getPassword()));
                u.setUtype(loginDto.getUtype());
                userMapper.insert(u);
            }
            if (!StrUtil.equals(DigestUtil.md5Hex(loginDto.getPassword()), user.getPassword())) {
                throw new BusinessException(ErrorCode.LOGINERROR);
            }
            HashMap<String, Object> map = new HashMap<>();
            map.put("userId",user.getId());
            map.put("companyId",user.getCompanyId());
            map.put("companyName",user.getCompanyName());
            String token = JwtUtils.createToken(map, 180);
    
            LoginVo loginVo = new LoginVo();
            loginVo.setAccess_token(token);
            loginVo.setUsername(user.getPhone());
    
            return ResponseResult.okResult(loginVo);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    mapper层:

    public interface UserMapper extends BaseMapper<User> {
    
    }
    
    • 1
    • 2
    • 3

    搭建网关

    网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等。学成在线也是通过网关介入所有请求,进行路由转发在这里插入图片描述
    在这里插入图片描述

    统一异常处理

    在这里插入图片描述
    在这里插入图片描述

    package com.xuecheng.web.exception;
    
    
    import com.xuecheng.commons.enums.ErrorCode;
    import lombok.Data;
    
    @Data
    public class BusinessException extends RuntimeException{
    
        private ErrorCode errorCode;
    
        public BusinessException(ErrorCode errorCode) {
            super(errorCode.getDesc());
            this.errorCode = errorCode;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    package com.xuecheng.web.exception;
    
    import com.xuecheng.commons.enums.ErrorCode;
    import com.xuecheng.commons.model.vo.ResponseResult;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    @RestControllerAdvice
    public class GlobalException {
        @ExceptionHandler(RuntimeException.class)
        public ResponseResult exception(RuntimeException e){
             e.printStackTrace();
             return ResponseResult.errorResult(ErrorCode.ERROR);
        }
    
        @ExceptionHandler(BusinessException.class)
        public ResponseResult  BusinessException(BusinessException e){
            ErrorCode errorCode = e.getErrorCode();
            return ResponseResult.errorResult(errorCode);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    结果展示:
    登录成功会进入商家页面

    在这里插入图片描述
    创建git,以天为单位作为分支,提交到gitee上,用以练习git操作
    在这里插入图片描述

    第一天任务完成

  • 相关阅读:
    C语言复习遇到的有趣的知识
    Google Earth Engine 教程——降低影像分辨率从0.6降分辨率到30米
    Remote & Local File Inclusion (RFI/LFI)-文件包含漏洞
    如何在Jupyter Lab中安装不同的Kernel
    安装stable-diffusion
    SpringBoot SpringBoot 运维实用篇 4 日志 4.4 文件记录日志
    Javaweb之Vue指令的详细解析
    12月7日即将讲解激发态与非绝热分子动力学
    美团前端一面必会手写面试题汇总
    一道线段树相关算法题
  • 原文地址:https://blog.csdn.net/weixin_44233087/article/details/126026171