从零开始,搭建一个简单的购物平台(三)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 从零开始,搭建一个简单的购物平台(三)

从零开始,搭建一个简单的购物平台(二):https://blog.csdn.net/time_____/article/details/105408640

项目源码(持续更新):https://gitee.com/DieHunter/myCode/tree/master/shopping


这篇文章在上次的服务端登录基础上增加前端界面


在开始前我们可以简单用postman测试一下token和登录的功能,可以先在后端生成一段token从前端请求


验证token(成功和失败)

2.png2.png



紧接着验证一下用户登录(前提事先在数据库添加用户信息,添加过程及加密不做详细说明)

2.png


测试成功后我们开始配置编写前端部分(只实现功能,对界面要求不高)


文件结构:

2.png



配置config.js文件夹,新建config.js文件用于存放配置常量(和服务端config.js一样)

export default class Config {
  static Agreement = "http://";
  static BaseUrl = "127.0.0.1";
  static ServerUrl = "";
  static ServerPort = ":1024";
  static Path = "/";
  static CryptoKey = "tokenkey";//加密信息关键字
  static FilePath = this.Agreement + this.BaseUrl + this.ServerPort + this.Path;
  static ServerApi = {//接口名
    token: "checkToken",
    user: {
      userLogin: "user/userLogin",
    }
  };
  static StorageName = {//本地缓存localstorage名称
    token: "token",
    userInfo: "userInfo"
  };
}

在utils文件中新建方法,将其放在react.component的原型中,使继承组件可以直接调用

storage:

import { Component } from "react";
class Utils {
  static saveStorage(key, val) {//添加缓存
    localStorage.setItem(key, JSON.stringify(val));
  }
  static getStorage(key) {//获取缓存
    try {
      return JSON.parse(localStorage.getItem(key));
    } catch (error) {}
  }
  static clearStorage(key) {//清除缓存
    try {
      localStorage.removeItem(key);
    } catch (error) {}
  }
}
Component.prototype.$utils = Utils;

axios:


import Config from "../config/config";
import Axios from "axios";
import { Component } from "react";
import { message } from "antd";
Axios.defaults.baseURL =
  Config.Agreement + Config.BaseUrl + Config.ServerPort + Config.Path;
// 添加请求拦截器
Axios.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    return config;
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);
// 添加响应拦截器
Axios.interceptors.response.use(
  function (response) {
    // 对响应数据做点什么
    if (response.data.result === -999) {
      //token验证失败
      return message.error(response.data.msg);
    }
    return response.data;
  },
  function (error) {
    console.log(error)
    // 对响应错误做点什么
    message.error("操作失败");
    return Promise.reject(error);
  }
);
Component.prototype.$axios = Axios;


Crypto:

import * as CryptoJS from "crypto-js";
import { Component } from "react";
import config from "../config/config";
const { CryptoKey } = config;
class CryptoTool {
  /* Crypto加密方法
   * @param {object} _data       对用户请求后端的参数进行加密
   */
  static setCrypto(_data) {
    let key = CryptoJS.enc.Utf8.parse(CryptoKey);
    let encrypted = CryptoJS.AES.encrypt(JSON.stringify(_data), key, {
      mode: CryptoJS.mode.ECB,
      padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.toString();
  }
   /* Crypto解密方法
   * @param {string} _token       将秘文解密成对象形式
   */
  static getCrypto(_token) {
    let key = CryptoJS.enc.Utf8.parse(CryptoKey);
    let decrypt = CryptoJS.AES.decrypt(_token, key, {
      mode: CryptoJS.mode.ECB,
      padding: CryptoJS.pad.Pkcs7
    });
    return JSON.parse(CryptoJS.enc.Utf8.stringify(decrypt).toString());
  }
}
Component.prototype.$crypto = CryptoTool;



在index.js中添加这些函数

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./util/axios";
import "./util/utils";
import "./util/cryptoTool";


随后在page/login中新增login.js,简单配置一下login页面后,在App.js中引入login页面

import React from "react";
import Login from "./page/login/login"
function App() {
  return (
    <div className="App">
      <Login></Login>
    </div>
  );
}
export default App;

在antd官网找到登录界面实例,直接把大部分复制到login界面,用less微调一下后实现以下界面

2.png2.png

login.js

import React from "react";
import "./login.less";
import { Card, Form, Input, Button, Checkbox, message } from "antd";
import { UserOutlined, LockOutlined } from "@ant-design/icons";
import config from "../../config/config";
const { ServerApi, StorageName } = config;
export default class Login extends React.Component {
  constructor(props) {
    super(props);
    this.checkToken(); //验证用户token是否过期
  }
  render() {
    return (
      <div className="cardBox">
        <Card title="登录">
          <Form
            name="normal_login"
            className="login-form"
            initialValues={{ remember: true }}
            onFinish={this.sendData}
          >
            <Form.Item
              name="username"
              rules={[
                {
                  required: true,
                  message: "请输入用户名/邮箱",
                },
              ]}
            >
              <Input
                className="infoInput"
                prefix={<UserOutlined className="site-form-item-icon" />}
                placeholder="用户名/邮箱"
              />
            </Form.Item>
            <Form.Item
              name="password"
              rules={[
                {
                  required: true,
                  message: "请输入密码",
                },
              ]}
            >
              <Input
                className="infoInput"
                prefix={<LockOutlined className="site-form-item-icon" />}
                type="password"
                placeholder="密码"
              />
            </Form.Item>
            <Form.Item>
              <Form.Item name="remember" valuePropName="checked" noStyle>
                <Checkbox>3天内免密</Checkbox>
              </Form.Item>
              <a className="login-form-forgot" href="#aaa">
                忘记密码
              </a>
            </Form.Item>
            <Form.Item>
              <Button
                type="primary"
                htmlType="submit"
                className="login-form-button"
              >
                登录
              </Button>
              或者<a href="#aaa">注册</a>
            </Form.Item>
          </Form>
        </Card>
      </div>
    );
  }
  checkToken() {
    let token = this.$utils.getStorage(StorageName.token);
    if (!token) return;
    this.$axios
      .get(ServerApi.token, {
        params: { token },
      })
      .then((res) => {
        switch (res.result) {
          case 1:
            message.success(res.msg).then(() => {
              // this.props.history.push({
              //   pathname: "/admin/findshop",
              //   query: res,
              // });
            });
            break;
          default:
            // message.warning(res.msg);
            break;
        }
      })
      .catch((err) => {
        console.log(err);
      });
  }
  sendData = (data) => {
    this.$axios
      .get(ServerApi.user.userLogin, {
        params: { crypto: this.$crypto.setCrypto(data) },
      })
      .then((res) => {
        switch (res.result) {
          case 1:
            this.$utils.saveStorage(StorageName.token, res.token);
            message.success(res.msg);
            // this.props.history.push({
            //   pathname: "/admin/findshop",
            //   query: res,
            // });
            break;
          default:
            message.warning(res.msg);
            break;
        }
      })
      .catch((err) => {
        console.log(err);
      });
  };
}


效果如下:

2.png2.png2.png

用户token验证,登录功能前端+后端基本实现


总结


前端与后端的项目搭建顺序可能有所不同,项目周期可能也不同,这时需要灵活使用前后端数据模拟和请求模拟工具,前端可以使用easymock和mockjs生成假数据,而后端最简单的直接放到浏览器url访问(仅限于get),或者使用postman,SoapUI等接口测试工具


相关文章
|
搜索推荐 SEO
从零开始搭建群众权益平台(十一)
从零开始搭建群众权益平台(十一)
34 0
|
前端开发 数据库连接 数据库
从零开始,搭建一个简单的购物平台(二)
从零开始,搭建一个简单的购物平台(二)
187 1
从零开始,搭建一个简单的购物平台(二)
|
前端开发 数据管理
从零开始,搭建一个简单的购物平台(五)
从零开始,搭建一个简单的购物平台(五)
318 1
从零开始,搭建一个简单的购物平台(五)
|
前端开发 JavaScript 数据库
从零开始,搭建一个简单的购物平台(十五)前端商城部分
从零开始,搭建一个简单的购物平台(十五)前端商城部分
218 1
从零开始,搭建一个简单的购物平台(十五)前端商城部分
|
前端开发
从零开始,搭建一个简单的购物平台(十六)前端商城部分
从零开始,搭建一个简单的购物平台(十六)前端商城部分
236 1
从零开始,搭建一个简单的购物平台(十六)前端商城部分
|
消息中间件 Java 应用服务中间件
大型电商网站:第三章:环境搭建
大型电商网站:第三章:环境搭建
140 0
大型电商网站:第三章:环境搭建
|
前端开发
从零开始,搭建一个简单的购物平台(九)
从零开始,搭建一个简单的购物平台(九)
229 0
从零开始,搭建一个简单的购物平台(九)
|
JavaScript 前端开发
从零开始,搭建一个简单的购物平台(六)
从零开始,搭建一个简单的购物平台(六)
158 0
从零开始,搭建一个简单的购物平台(六)
|
前端开发 数据库
从零开始,搭建一个简单的购物平台(十)
从零开始,搭建一个简单的购物平台(十)
238 0
从零开始,搭建一个简单的购物平台(十)
|
缓存 前端开发 数据库
从零开始,搭建一个简单的购物平台(四)
从零开始,搭建一个简单的购物平台(四)
135 0
从零开始,搭建一个简单的购物平台(四)