微服务电商实战(十一)搭建vue项目对接注册登陆接口,解决跨域问题,使用七牛云实现头像上传

一、简介

node.js版本:v12.16.3

node.js下载

vue官网教程

iview介绍

上传头像接口,图片存储在七牛云中,注册并实名认证之后可以免费使用

 

以下会描述使用vue搭建项目框架的过程,不涉及到具体页面的编写等,有兴趣的可以看一下,没兴趣的可以直接跳过,直接从github上克隆代码运行。

 

二、创建web项目

 

 

 

创建完成后进行相关配置

 

 

 

 

三、安装vue脚手架工具

 

3.1 首先在idea的Terminal中输入以下命令安装淘宝的npm镜像,这样下载速度快

 

执行以下命令

npm i -g cnpm --registry=https://registry.npm.taobao.org

 

 idea中执行“npm”命令,提示'node' 不是内部或外部命令,也不是可运行的程序

 

 

3.2 开始安装vue脚手架工具

 

执行以下命令

cnpm i -g vue-cli

 

测试是否安装成功

vue -V

 

 

 

四、构建vue项目

 

执行以下命令

vue init webpack shop-project-web

 

 

 

分别执行上图中的命令

 

 

访问http://localhost:8080/

 

 

ok,构建完成。 

 

 

 

五、安装iview并在项目引入(可以快速搭建页面)

 

首先先停止vue项目(在控制台按Ctrl+C,再按Y停止项目),停止以后执行以下命令

cnpm install view-design --save

 

在main.js中加入iview

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

//引入iview
import ViewUI from 'view-design';
import 'view-design/dist/styles/iview.css';
Vue.use(ViewUI);


Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

 

ok,到这里我们就可以通过使用iview来快速搭建页面,这里不再详述页面的搭建过程等。

 

 

 

六、安装axios并在项目引入(便于实现ajax请求)

 

首先先停止vue项目(在控制台按Ctrl+C,再按Y停止项目),停止以后执行以下命令

cnpm install axios -S

 

 在main.js中加入axios

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

//引入iview
import ViewUI from 'view-design';
import 'view-design/dist/styles/iview.css';
Vue.use(ViewUI);

//引入axios
import axios from 'axios'
Vue.prototype.$axios = axios

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

 

 

七、安装七牛云js用于实现客户端图片上传

cnpm i qiniu-js

 

八、安装缓存插件用于缓存数据

cnpm install good-storage

 

九、vue项目介绍

 

vue架构里各个部分的作用如下图所示

 

在index.js里配置路由,以此实现页面的跳转

 

 

使用axios发出ajax请求

 

ok,看到这里相信大家对vue已经有了初步的了解,这里不再继续详述页面相关的东西。

 

 

 

十、解决跨域问题

在我们的gateway服务中添加一个配置类即可搞定

package com.liazhan.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

/**
 * @version:V1.0
 * @Description: 解决跨域问题
 * @author: Liazhan
 * @date 2020/5/5 9:24
 */
@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter(){
        CorsConfiguration config=new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        //设置预检请求的缓存时间(秒),在这个时间段里,对于相同的跨域请求不会再预检了
        config.setMaxAge(18000L);
        UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**",config);
        return new CorsWebFilter(source);
    }
}

 

 

十一、使用七牛云实现头像上传

上传流程是客户端向服务端获取一个token,服务端生成token返回(添加同一个ip半小时内最多获取十次token限制),然后客户端用这个token去实现在七牛云上传图片。

 

shop-common-core添加ip工具类,需要添加servlet依赖

        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>
package com.liazhan.core.utils;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @version:V1.0
 * @Description: IP工具类
 * @author: Liazhan
 * @date 2020/5/7 11:15
 */

public class IPUtil {
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress="";
        }
        // ipAddress = this.getRequest().getRemoteAddr();

        return ipAddress;
    }
}

 

shop-service-impl-member添加七牛云sdk依赖,修改常量类,添加头像上传接口

        <!-- 七牛云 -->
        <dependency>
            <groupId>com.qiniu</groupId>
            <artifactId>qiniu-java-sdk</artifactId>
            <version>7.2.28</version>
        </dependency>

 

package com.liazhan.member.consts;

/**
 * @version:V1.0
 * @Description: 会员服务常量类
 * @author: Liazhan
 * @date 2020/4/28 10:11
 */
public interface MemberConst {
    //登录token在redis的key前缀
    String MEMBER_LOGIN_TOKEN_PREFIX = "login.token";
    //登录token过期时间  1小时
    Long MEMBER_LOGIN_TOKEN_TIMEOUT = 3600L;
    //登陆token失效状态
    Integer MEMBER_LOGIN_TOKEN_INVALID = 0;
    //登陆token有效状态
    Integer MEMBER_LOGIN_TOKEN_VALID = 1;
    //七牛云accessKey
    String QINIU_ACCESSKEY = "这里输入七牛云accessKey";
    //七牛云secretKey
    String QINIU_SECRETKEY = "这里输入七牛云secretKey";
    //七牛云头像存储空间名称
    String QINIU_HEADIMG_BUCKET = "这里输入七牛云存储空间名称";
    //用户获取上传头像token的次数在redis的key前缀
    String HEADIMG_TOKEN_COUNT_PREFIX = "headimg.token.count";
    //用户获取上传头像token的次数在redis的过期时间  半小时
    Long HEADIMG_TOKEN_COUNT_TIMEOUT = 1800L;
    //用户获取上传头像token的最大次数   10次
    Integer HEADIMG_TOKEN_COUNT_MAX = 10;
}

 

package com.liazhan.member.service;

import com.alibaba.fastjson.JSONObject;
import com.liazhan.base.BaseResponse;
import com.liazhan.member.input.dto.UserRegistInpDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

/**
 * @version:V1.0
 * @Description: 会员注册相关接口
 * @author: Liazhan
 * @date 2020/4/24 11:13
 */
@Api(tags = "会员注册相关接口")
public interface MemberRegistService {

    @PostMapping("/regist")
    @ApiOperation(value = "会员注册接口")
    BaseResponse<JSONObject> regist(@RequestBody @Valid UserRegistInpDTO userInpDTO);

    @GetMapping("/getUploadHeadImgToken")
    @ApiOperation(value = "会员注册获取上传头像token接口")
    BaseResponse<JSONObject> getUploadHeadImgToken(HttpServletRequest request);
}

 

package com.liazhan.member.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.liazhan.base.BaseResponse;
import com.liazhan.base.BaseServiceImpl;
import com.liazhan.base.consts.BaseConst;
import com.liazhan.core.utils.DtoUtil;
import com.liazhan.core.utils.IPUtil;
import com.liazhan.core.utils.RedisUtil;
import com.liazhan.member.consts.MemberConst;
import com.liazhan.member.dao.UserDao;
import com.liazhan.member.dao.entity.UserDO;
import com.liazhan.member.feign.WeiXinVerificationCodeServiceFeign;
import com.liazhan.member.input.dto.UserRegistInpDTO;
import com.liazhan.member.service.MemberRegistService;
import com.qiniu.util.Auth;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RestController;


import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;


/**
 * @version:V1.0
 * @Description: 会员注册相关接口实现类
 * @author: Liazhan
 * @date 2020/4/24 11:18
 */
@RestController
public class MemberRegistServiceImpl extends BaseServiceImpl<JSONObject> implements MemberRegistService {
    @Autowired
    private WeiXinVerificationCodeServiceFeign weiXinVerificationCodeServiceFeign;
    @Autowired
    private UserDao userDao;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public BaseResponse<JSONObject> regist(@Valid UserRegistInpDTO userInpDTO) {
        //1.校验验证码是否正确
        BaseResponse<JSONObject> checkResponse = weiXinVerificationCodeServiceFeign.checkVerificationCode(userInpDTO.getPhone(), userInpDTO.getVerificationCode());
        if(!BaseConst.HTTP_RES_CODE_200.equals(checkResponse.getCode())){
            return getResultError(checkResponse.getMsg());
        }
        //2.密码用md5加密
        String encodePassword = DigestUtils.md5DigestAsHex(userInpDTO.getPassword().getBytes());
        userInpDTO.setPassword(encodePassword);
        //3.DTO转do
        UserDO userDO = DtoUtil.dtoToDo(userInpDTO, UserDO.class);
        //4.保存到数据库
        UserDO save = userDao.save(userDO);
        return save.getUserId()==null?getResultError("注册失败!"):getResultSuccess("注册成功!");
    }

    @Override
    public BaseResponse<JSONObject> getUploadHeadImgToken(HttpServletRequest request) {
        //1.获取请求方ip,判断是否已超过请求次数,若是,则返回操作繁忙,否则次数+1
        String ipAddr = IPUtil.getIpAddr(request);
        String tokenCount = redisUtil.getString(MemberConst.HEADIMG_TOKEN_COUNT_PREFIX + ipAddr);
        if(StringUtils.isBlank(tokenCount)){
            redisUtil.setString(MemberConst.HEADIMG_TOKEN_COUNT_PREFIX+ipAddr,
                    "1",MemberConst.HEADIMG_TOKEN_COUNT_TIMEOUT);
        }else{
            Integer tokenCountInt = Integer.valueOf(tokenCount);
            if(tokenCountInt<MemberConst.HEADIMG_TOKEN_COUNT_MAX){
                tokenCountInt++;
                redisUtil.setString(MemberConst.HEADIMG_TOKEN_COUNT_PREFIX+ipAddr,
                        tokenCountInt+"",MemberConst.HEADIMG_TOKEN_COUNT_TIMEOUT);
            }else{
                return getResultError("图片上传繁忙,请稍后再试!");
            }
        }
        //2.生成token
        Auth auth = Auth.create(MemberConst.QINIU_ACCESSKEY, MemberConst.QINIU_SECRETKEY);
        String upToken = auth.uploadToken(MemberConst.QINIU_HEADIMG_BUCKET);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("token",upToken);

        return getResultSuccess(jsonObject);
    }

}

 

 

ok,最终效果如下

 

 

 

页面还很简陋,登陆还没有添加验证码之类的校验,后续会完善一下。

由于目前还没有编写需要登陆token才能获取数据的接口,因此后续再添加axios响应拦截器,当请求响应token错误失败码时,将自动跳转到登陆页面。

 

 

后端项目github地址:https://github.com/liazhan/shop-project/tree/845fd2f6cf4633d1f23ec5d11565737834e177ac

前端项目github地址:https://github.com/liazhan/shop-project-web/tree/d071343165ab5a84c859dc4a8a10d6b72cd657e9

 

前端项目的运行方式如下:

1、clone下来之后用idea打开,打开Terminal界面

 

 

2、输入以下命令安装,若没有CNPM则根据上文提到的方式安装CNPM

cnpm install

 

3、运行

npm run dev

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值