项目 谷粒学院Day10-12

Day 10(07.08)

删除视频接口

后端

controller

//根据视频id删除阿里云视频
@DeleteMapping("removeAlyVideo/{id}")
public R removeAlyVideo(@PathVariable String id){
    try{
        //初始化对象
        DefaultAcsClient client = InitVodClient.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET);
        //创建删除视频的request对象
        DeleteVideoRequest request=new DeleteVideoRequest();
        //向request设置视频id
        request.setVideoIds(id);
        //调用初始化对象的方法实现删除
        client.getAcsResponse(request);
        return R.ok();
    }catch (Exception e){
        e.printStackTrace();
        throw new GuliException(20001,"删除视频失败");
    }
}

前端

video.js

//删除阿里云视频
    deleteAliyunvod(id){
        return request({
         url: `/eduvod/video/removeAlyVideo/`+id,//接口地址
         method: 'delete'
        })
    }

chapter.vue

//点击确定调用这个方法
      handleVodRemove(){
        //调用接口删除视频方法
        video.deleteAliyunvod(this.video.videoSourceId)
          .then(response =>{
             //提示信息
              this.$message({
                 type: 'success',
                 message: '删除成功!'
              });
              //把文件列表清空
              this.fileList=[]
              //把video视频id和视频名称值清空
                    //上传视频id赋值
                    this.video.videoSourceId = ''
                    //上传视频名称赋值
                    this.video.videoOriginalName = ''
          })
      },
      //点击×调用这个方法
      beforeVodRemove(file,fileList){
        return this.$confirm(`'确定删除' ${ file.name}?`)
      },

效果

在这里插入图片描述

微服务

微服务是一种架构风格

把一个项目拆分成独立的多个服务,多个服务独立运行,每个服务占用独立进程

微服务每个模块都可以使用不同的存储方式(比如有的用redis,有的用mysql等),数据库也是单个模块对应自己的数据库。

微服务每个模块都可以使用不同的开发技术,开发模式更灵活。

Spring Cloud

Spring Cloud不是一种技术,是很多技术的总称,是很多框架的集合

使用 Spring Cloud 里面的这些框架实现微服务操作

使用Spring Cloud需要依赖技术 Spring Boot,但Spring Boot可以单独使用,它就是Spring的升级版

Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架; Spring Boot使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,必须基于Spring Boot开发。可以单独使用Spring Boot开发项目,但是Spring Cloud离不开 Spring Boot。

NACOS

简介

Nacos是以服务为主要服务对象的中间件,Nacos支持所有主流的服务发现、配置和管理。

Nacos主要提供以下四大功能:

服务发现和服务健康监测

动态配置服务

动态DNS服务

服务及其元数据管理

安装

在这里插入图片描述

访问:http://localhost:8848/nacos

用户名密码:nacos/nacos

删除小节删除阿里云视频

在这里插入图片描述

把service_edu 和service_vod服务在Nacos注册
  1. 引入依赖

    <!--服务注册-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
  2. 在要注册的服务的配置文件中 application进行配置

    # nacos服务地址
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
    
  3. 在启动类添加注解

    @EnableDiscoveryClient//Nacos注册
    
  4. 在这里插入图片描述

Feign

用来调用服务

  1. 引入依赖

    !--服务调用-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  2. 调用

    在调用端写代码,即在service_edu 中,在启动类加注解

    @EnableFeignClients
    
  3. 在调用端创建 interface,使用注解指定调用服务名称,定义调用方法的路径

    @FeignClient("service-vod")
    @Component
    public interface VodClient {
        //定义调用方法的路径
        //根据视频id删除阿里云视频
        @DeleteMapping("/eduvod/video/removeAlyVideo/{id}")
        public R removeAlyVideo(@PathVariable("id") String id);
    }
    
  4. 实现

    //删除小节时,同时把里面的视频也删除
    @DeleteMapping("{id}")
    public R deleteVideo(@PathVariable String id){
        //根据小节id得到视频id,调用方法实现删除
        EduVideo eduVideo = videoService.getById(id);
        String videoSourceId=eduVideo.getVideoSourceId();
        //判断小节是否有视频id
        if (!StringUtils.isEmpty(videoSourceId)){
            //根据视频id,远程调用service_vod中的方法实现删除
            vodClient.removeAlyVideo(videoSourceId);
        }
        //删除小节
        videoService.removeById(id);
        return R.ok();
    }
    

删除课程同时删除视频

一个课程有多个章节,一个章节爷多个小节,每个小节都有视频

删除课程的时候,删除的视频有多个

  1. 在service_vod创建接口,删除多个视频

    controller

    //删除多个阿里云视频的方法
    //参数是多个视频id
    @DeleteMapping("delete-batch")
    public R deleteBatch(@RequestParam("videoIdList") List videoIdList){
        vodService.removeMoreAlyVideo(videoIdList);
        return R.ok();
    }
    

    service

    @Override
    public void removeMoreAlyVideo(List videoIdList) {
        try{
            //初始化对象
            DefaultAcsClient client = InitVodClient.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET);
            //创建删除视频的request对象
            DeleteVideoRequest request=new DeleteVideoRequest();
    
            //videoList值转换成 1,12,35
            String videoIds = StringUtils.join(videoIdList.toArray(), ",");
            //向request设置视频id
            request.setVideoIds(videoIds);
            //调用初始化对象的方法实现删除
            client.getAcsResponse(request);
        }catch (Exception e){
            e.printStackTrace();
            throw new GuliException(20001,"删除视频失败");
        }
    }
    
  2. 在service_edu中调用

    EduVideoServiceImpl代码

    //1 根据课程id删除小节
    @Override
    public void removeVideoByCourseId(String courseId) {
    
        //根据课程id查询出课程所有的视频id
        QueryWrapper<EduVideo> wrapperVideo=new QueryWrapper<>();
        wrapperVideo.eq("course_id",courseId);
        wrapperVideo.select("video_source_id");
        List<EduVideo> eduVideoList = baseMapper.selectList(wrapperVideo);
    
        //把List<EduVideo>变成List<String>
        List<String> videoIds=new ArrayList<>();
        for (int i = 0; i < eduVideoList.size(); i++) {
            EduVideo eduVideo=eduVideoList.get(i);
            String videoSourceId=eduVideo.getVideoSourceId();
            if (!StringUtils.isEmpty(videoSourceId)){
                //如果视频id为空就不放到集合里面
                videoIds.add(videoSourceId);
            }
        }
        //根据多个视频id删除多个视频
        if (videoIds.size()>0){
            //如果集合为空,不做删除操作
            vodClient.deleteBatch(videoIds);
        }
    
        QueryWrapper<EduVideo> wrapper=new QueryWrapper<>();
        wrapper.eq("course_id",courseId);
        baseMapper.delete(wrapper);
    }
    
  3. 在这里插入图片描述

Hystrix

Spring Cloud 过程

Spring Cloud 在接口调用上,大致会经过如下几个组件配合:

Feign ----->Hystrix —>Ribbon —>Http Client(apache http components 或者 Okhttp)

Feign:服务发现。根据名字找到服务并调用

Hystrix:熔断器。如果Feign能够调到服务,则不做操作,执行调用,如果调不到服务,则执行熔断,切断调用过程

Ribbon:负载均衡。将请求平均分摊到集群的服务器中

Http CLient:真正的调用。

在这里插入图片描述

Hystrix概念与使用

概念

Hystrix 是一个供分布式系统使用,提供延迟和容错功能,保证复杂的分布系统在面临不可避免的失败时,仍能有其弹性。

使用
  1. 引入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
    
    <!--hystrix依赖,主要是用  @HystrixCommand -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
  2. 修改配置文件

    #开启熔断机制
    feign.hystrix.enabled=true
    # 设置hystrix超时时间,默认1000ms
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
    
  3. 在创建interface之后,需要创建对应的实现类

    @Component
    public class VodFileDegradeFeignClient implements VodClient{
    
        //出错之后会执行
        @Override
        public R removeAlyVideo(String id) {
            return R.error().message("删除视频出错");
        }
    
        @Override
        public R deleteBatch(List<String> videoIdList) {
            return R.error().message("删除多个视频出错");
        }
    }
    
  4. 在interface添加注解

    @FeignClient(name = "service-vod",fallback = VodFileDegradeFeignClient.class)//调用服务的名字和失败的实现类
    
  5. 在这里插入图片描述

Day 11(07.09)

搭建前台环境

NUXT

是node.js的一个框架,把数据一次性返回到浏览器中

在这里插入图片描述

框架目录结构

在这里插入图片描述

先加载layouts的default.vue页面再通过nuxt标签加载到pages的index.vue页面

路由

固定路由:路径是固定地址,不发生变化
通过to设置路由跳转地址
在这里插入图片描述

​ 做法:在pages文件夹course文件夹,创建index.vue

动态路由:每次生成路由地址不一样,如每个课程详情页面,每个课程id不同

​ 做法:NUXT的动态路由是以下划线开头的vue文件,参数名为下划线后边的文件名

整合前台页面

  1. 安装组件

    npm install vue-awesome-swiper@3.1.3
    
  2. 配置幻灯片插件

  3. 复制项目中使用的静态资源到assets中

  4. 在这里插入图片描述

首页显示banner数据

创建新模块service_cms

后台管理banner接口

@RestController
@RequestMapping("/educms/banneradmin")
@CrossOrigin
public class BannerAdminController {

    @Autowired
    private CrmBannerService bannerService;
    //1 分页查询banner
    @GetMapping("pageBanner/{page}/{limit}")
    public R pageBanner(@PathVariable long page,@PathVariable long limit){

        Page<CrmBanner> pageBanner=new Page<>(page,limit);
        bannerService.page(pageBanner,null);
        return R.ok().data("items",pageBanner.getRecords()).data("total",pageBanner.getTotal());
    }

    //2 添加banner
    @PostMapping("addBanner")
    public R addBanner(@RequestBody CrmBanner crmBanner){
        bannerService.save(crmBanner);
        return R.ok();
    }

    @ApiOperation(value = "获取Banner")
    @GetMapping("get/{id}")
    public R get(@PathVariable String id) {
        CrmBanner banner = bannerService.getById(id);
        return R.ok().data("item", banner);
    }

    @ApiOperation(value = "修改Banner")
    @PutMapping("update")
    public R updateById(@RequestBody CrmBanner banner) {
        bannerService.updateById(banner);
        return R.ok();
    }

    @ApiOperation(value = "删除Banner")
    @DeleteMapping("remove/{id}")
    public R remove(@PathVariable String id) {
        bannerService.removeById(id);
        return R.ok();
    }

}

前台显示banner接口

@RestController
@RequestMapping("/educms/bannerfront")
@CrossOrigin
public class BannerFrontController {
    @Autowired
    private CrmBannerService bannerService;

    //查询所有banner
    @ApiOperation(value = "获取首页banner")
    @GetMapping("getAllBanner")
    public R index() {
        List<CrmBanner> list = bannerService.selectAllBanner();
        return R.ok().data("list", list);
    }
}
@Service
public class CrmBannerServiceImpl extends ServiceImpl<CrmBannerMapper, CrmBanner> implements CrmBannerService {

    //查询所有banner
    @Override
    public List<CrmBanner> selectAllBanner() {
        //根据id降序排列,显示排列后的前两条记录
        QueryWrapper<CrmBanner> wrapper=new QueryWrapper<>();
        wrapper.orderByDesc("id");
        //last方法,拼接SQL语句
        wrapper.last("limit 2");
        List<CrmBanner> list=baseMapper.selectList(null);
        return list;
    }
}

首页热门课程名师

@RestController
@RequestMapping("/eduservice/indexfront")
@CrossOrigin
public class IndexFrontController {
    @Autowired
    private EduCourseService courseService;
    @Autowired
    private EduTeacherService teacherService;

    //查询前8条热门课程,查询前4条名师
    @GetMapping("index")
    public R index() {
        //查询前8条热门课程
        QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");
        wrapper.last("limit 8");
        List<EduCourse> eduList = courseService.list(wrapper);

        //查询前4条名师
        QueryWrapper<EduTeacher> wrapperTeacher = new QueryWrapper<>();
        wrapperTeacher.orderByDesc("id");
        wrapperTeacher.last("limit 4");
        List<EduTeacher> teacherList = teacherService.list(wrapperTeacher);

        return R.ok().data("eduList", eduList).data("teacherList", teacherList);
    }
}

前端页面准备工作

下载axios依赖

npm install axios

封装axios

首页banner数据显示

  1. 创建api文件夹,创建js文件,定义调用接口路径

    import request from '@/utils/request'
    export default {
      getListBanner() {//查询前2条banner信息
        return request({
          url: '/educms/bannerfront/getAllBanner',
          method: 'get'
        })
      }
    }
    
  2. 在index.vue进行调用

    created(){
        //调用查询banner数据的方法
        this.getBannerList()
        //调用查询热门课程和讲师
        this.getHotCourseTeacher()
      },
      methods:{
        //查询热门课程和讲师
        getHotCourseTeacher(){
          index.getIndexData()
            .then(response =>{
              this.eduList=response.data.data.eduList
              this.teacherList=response.data.data.teacherList
            })
        },
        //查询banner数据
        getBannerList(){
          banner.getListBanner()
            .then(response =>{
              this.bannerList=response.data.data.list
            })
        }
    
      }
    }
    
  3. nginx添加访问配置

首页数据使用Redis

Redis

基于key-value进行存储

支持多种数据结构:string;list;hash;set;zset(有序集合)

支持持久化,通过内存进行存储,可以存到硬盘里面

支持过期时间,支持事务

一般把经常进行查询,不经常修改,不是特别重要的数据放到Redis作为缓存

  1. 创建Redis配置类,写到common里面

  2. 在查询所有banner方法上天极爱注解@Cacheable

在这里插入图片描述

连接Redis

  1. 关闭iunx防火墙

  2. 找到redis配置文件, 注释一行配置

    #bind 127.0.0.1
    
  3. 修改 protected-mode yes为no

在service_cms配置Redis

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000

spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

存在问题

  1. 搭建前台环境出错

在这里插入图片描述

解决方案,输入以下命令

npm install @babel/core @babel/preset-env

接着报下一个错误

在这里插入图片描述

原因是@babel/preset-env的版本原因,解决方案,输入以下命令

 npm i @babel/preset-env@7.12.17

成功解决问题

在这里插入图片描述

Day 12(07.09)

登录

单一服务器登录

使用session对象实现,把用户数据放到session里面,判断是否登录,从session获取数据,可以获取到登录

session.setAttribute(“user”,user)
session.getAttribute(user)

单点登录(Single Sign On)

概念:项目中多个模块,在任何一个模块登录,其他任何模块就不用再登录了

实现方式:

  1. session广播机制

    session的复制,把登录模块的session复制到所有模块

    缺点:当模块过多时造成资源浪费,数据重复

  2. cookie+Redis实现

    cookie是客户端机制,每次发送请求,带着cookie进行发送

    1. 在项目中任何一个模块进行登录,登陆之后,把数据放到两地方

      Redis:key:生成唯一随机值(id、ip等等) value:用户数据

      cookie:把Redis生成的key放到cookie中

    2. 访问项目中其他模块,发送请求带着cookie发送,获取cookie值,拿着cookie做事情:

      把cookie获取值放到Redis中根据key查询,查得到数据就是登录

  3. token实现

    token:按照一定规则生成字符串,字符串可以包含用户信息

    1. 在项目某个模块进行登录,登录之后,按照规则生成字符串,把登录之后用户包含到生成字符串里面,把字符串返回
      1. 可以把字符串通过cookie返回
      2. 把字符串通过地址栏返回
    2. 再去访问其他模块,每次访问在地址栏获取字符串,根据字符串获取用户信息,如果可以获取,就是一个登录

JWT

JWT规定好了token规则,可以删除字符串,包含用户信息

在这里插入图片描述

三部分:

第一部分:JWT 头信息

第二部分:有效载荷,包含主题信息(用户信息)

第三部分:签名哈希 防伪标志

使用
  1. 引入依赖

    <dependencies>
        <!-- JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
    </dependencies>
    

短信服务

阿里云短信服务
申请模板管理

在这里插入图片描述

申请签名管理

在这里插入图片描述

创建service_msm模块
创建包结构,创建controller和service,配置类,启动类

controller

@RestController
@RequestMapping("/edumsm/msm")
@CrossOrigin

public class MsmController {

    @Autowired
    private MsmService msmService;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @GetMapping("send/{phone}")
    public R sendMsm(@PathVariable String phone){
        //1 从Redis中获取验证码,获取的到直接返回
        String code = redisTemplate.opsForValue().get(phone);
        if (!StringUtils.isEmpty(code)){
            return R.ok();
        }
        //2 Redis获取不到,进行阿里云发送
        //生成随机值,传递阿里云进行发送
        code= RandomUtil.getFourBitRandom();
        Map<String,Object> param=new HashMap<>();
        param.put("code",code);
        //调用service发送短信的方法
        boolean isSend=msmService.send(param,phone);
        if (isSend){
            //发送成功,把发送成功验证码放到Redis里面
            //设置有效时间
            redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES);
            return R.ok();
        }else {
            return R.error().message("短信发送失败");
        }
    }
}

service

@Service
public class MsmServiceImpl implements MsmService {
    //发送短信验证码
    @Override
    public boolean send(Map<String, Object> param, String phone) {
        if(StringUtils.isEmpty(phone)) return false;

        DefaultProfile profile =
                DefaultProfile.getProfile("default", "LTAI4FvvVEWiTJ3GNJJqJnk7", "9st82dv7EvFk9mTjY01XXbM632fRbG");
        IAcsClient client = new DefaultAcsClient(profile);

        //设置相关固定的参数
        CommonRequest request = new CommonRequest();
        //request.setProtocol(ProtocolType.HTTPS);
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");

        //设置发送相关参数
        request.putQueryParameter("PhoneNumbers", phone);//手机号
        request.putQueryParameter("SignName", "我的谷粒在线教育网站");//签名名称
        request.putQueryParameter("TemplateCode", "SMS_180051135");//模板code
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));//验证码数据,转换成json数据

        //最终发送
        try {
            CommonResponse response = client.getCommonResponse(request);
            boolean success=response.getHttpResponse().isSuccess();
            return success;
        } catch (Exception e) {
            e.printStackTrace();
             return false;
        }
       
    }

Redis解决验证码的有效时间

登录注册接口

创建service_ucenter模块
数据库创建用户表,使用代码生成器

在这里插入图片描述

在这里插入图片描述

启动类
@ComponentScan("com.lujin")
@SpringBootApplication
@MapperScan("com.lujin.educenter.mapper")
public class UcenterApplication {
    public static void main(String[] args) {
        SpringApplication.run(UcenterApplication.class,args);
    }
}
登录
  1. controller

    //登录
    @PostMapping("login")
    public R loginUser(@RequestBody UcenterMember member){
        //调用service方法实现登录
        //返回token值
        String token= memberService.login(member);
        return R.ok().data("token",token);
    }
    
  2. service

    //登录的方法
    @Override
    public String login(UcenterMember member) {
        //获取登录的手机号和密码
        String mobile=member.getMobile();
        String password = member.getPassword();
        //手机号和密码非空判断
        if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)){
            throw new GuliException(20001,"登录失败");
        }
        //判断手机号是否正确
        QueryWrapper<UcenterMember> wrapper=new QueryWrapper<>();
        wrapper.eq("monbile",mobile);
        UcenterMember mobileMember = baseMapper.selectOne(wrapper);
        //判断查询对象是否为空
        if (mobileMember==null){
            throw new GuliException(20001,"登录失败");
        }
        //判断密码是否正确
        //因为存储到数据库中的密码是加密的,先将输入的密码进行加密再和数据库比较
        //加密方式MD5(只能加密,本身不能解密)
        if (!MD5.encrypt(password).equals(mobileMember.getPassword())){
            throw new GuliException(20001,"登录失败");
        }
        //判断用户是否被禁用
        if (mobileMember.getIsDisabled()){
            throw new GuliException(20001,"登录失败");
        }
        //登录成功
        //生成token字符串,使用JWT工具
        String jwtToken = JwtUtils.getJwtToken(mobileMember.getId(), mobileMember.getNickname());
        return jwtToken;
    }
    

    在这里插入图片描述

注册
  1. 创建实体类用于封装注册的数据,包含验证码属性

    @Data
    @ApiModel(value="注册对象", description="注册对象")
    public class RegisterVo {
    
        @ApiModelProperty(value = "昵称")
        private String nickname;
    
        @ApiModelProperty(value = "手机号")
        private String mobile;
    
        @ApiModelProperty(value = "密码")
        private String password;
    
        @ApiModelProperty(value = "验证码")
        private String code;
    }
    
  2. controller

    //注册
    @PostMapping("register")
    public R registerUser(@RequestBody RegisterVo registerVo){
        memberService.register(registerVo);
        return R.ok();
    }
    
  3. service

    //注册的方法
    @Override
    public void register(RegisterVo registerVo) {
        //获取注册的数据
        String code = registerVo.getCode();//验证码
        String mobile = registerVo.getMobile();//手机号
        String nickname = registerVo.getNickname();//昵称
        String password = registerVo.getPassword();//密码
    
        //非空判断
        if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)
            || StringUtils.isEmpty(code) ||  StringUtils.isEmpty(nickname)){
            throw new GuliException(20001,"登录失败");
        }
        //判断手机验证码是否正确
        //获取Redis验证码
        String redisCode = redisTemplate.opsForValue().get(mobile);
        if (!code.equals(redisCode)){
            throw new GuliException(20001,"注册失败");
        }
        //判断手机号是否重复,表中存在相同手机号,不进行添加
        QueryWrapper<UcenterMember> wrapper=new QueryWrapper<>();
        wrapper.eq("mobile",mobile);
        Integer count = baseMapper.selectCount(wrapper);
        if (count>0){
            throw new GuliException(20001,"注册失败");
        }
        //将数据添加到数据库中
        UcenterMember member=new UcenterMember();
        member.setMobile(mobile);
        member.setNickname(nickname);
        member.setPassword(MD5.encrypt(password));//密码需要加密
        member.setIsDisabled(false);//默认不禁用
        member.setAvatar("");//头像
        baseMapper.insert(member);
    }
    
  4. 在这里插入图片描述

    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 创建token获取用户信息

    //根据token获取用户信息
    @GetMapping("getMenberInfo")
    public R getMenberInfo(HttpServletRequest request){
        //调用JWT工具类方法,得到request对象的头信息,返回用户id
        String memberId = JwtUtils.getMemberIdByJwtToken(request);
        //查询数据库,根据用户id获取用户信息
        UcenterMember member = memberService.getById(memberId);
        return R.ok().data("userInfo",member);
    }
    

整合页面

在nuxt环境安装element-ui

npm install element-ui

修改配置文件

import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'
import VueQriously from 'vue-qriously'
import ElementUI from 'element-ui' //element-ui的全部组件
import 'element-ui/lib/theme-chalk/index.css'//element-ui的css
Vue.use(ElementUI) //使用elementUI
Vue.use(VueQriously)
Vue.use(VueAwesomeSwiper)

整合注册页面

  1. 在layouts文件夹创建登录注册布局页面sign.vue

    <template>
      <div class="sign">
        <!--标题-->
        <div class="logo">
          <img src="~/assets/img/logo.png" alt="logo">
        </div>
        <!--表单-->
        <nuxt/>
      </div>
    </template>
    
  2. 修改layouts文件夹里面default.vue页面,修改登录和注册超链接地址

在这里插入图片描述

  1. 在pages文件夹下创建注册页面

  2. 在这里插入图片描述

  3. 创建登录页面

在这里插入图片描述

前端

验证码倒计时通过js 定时器的方法,每个一段时间执行一次js方法

<script>
setInterval("alert('test')",3000);
</script>

前端代码

//注册提交方法
      submitRegister(){
          registerApi.registerMember(this.params)
            .then(response =>{
                //提示信息
              this.$message({
                type: 'success',
                message: "注册成功"
              })
                //跳转到登录页面
                this.$router.push({path: '/login'})
            })
      },

      //通过输入手机号发送验证码
    getCodeFun(){
        registerApi.sendCode(this.params.mobile)
            .then(response =>{
                this.sending=false
                //调用倒计时的方法
                this.timeDown()
            })
    },

      //倒计时
      timeDown() {
        let result = setInterval(() => {
          --this.second;
          this.codeTest = this.second
          if (this.second < 1) {
            clearInterval(result);
            this.sending = true;
            //this.disabled = false;
            this.second = 60;
            this.codeTest = "获取验证码"
          }
        }, 1000);

      },
      checkPhone (rule, value, callback) {
        //debugger
        if (!(/^1[34578]\d{9}$/.test(value))) {
          return callback(new Error('手机号码格式不正确'))
        }
        return callback()
      }
    }

自动校验,失去焦点触发规则

:rules="[{ required: true, message: '请输入手机号码', trigger: 'blur' },{validator: checkPhone, trigger: 'blur'}]//validator为自己写的规则
        })
            //跳转到登录页面
            this.$router.push({path: '/login'})
        })
  },

  //通过输入手机号发送验证码
getCodeFun(){
    registerApi.sendCode(this.params.mobile)
        .then(response =>{
            this.sending=false
            //调用倒计时的方法
            this.timeDown()
        })
},

  //倒计时
  timeDown() {
    let result = setInterval(() => {
      --this.second;
      this.codeTest = this.second
      if (this.second < 1) {
        clearInterval(result);
        this.sending = true;
        //this.disabled = false;
        this.second = 60;
        this.codeTest = "获取验证码"
      }
    }, 1000);

  },
  checkPhone (rule, value, callback) {
    //debugger
    if (!(/^1[34578]\d{9}$/.test(value))) {
      return callback(new Error('手机号码格式不正确'))
    }
    return callback()
  }
}

自动校验,失去焦点触发规则

```js
:rules="[{ required: true, message: '请输入手机号码', trigger: 'blur' },{validator: checkPhone, trigger: 'blur'}]//validator为自己写的规则
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值