preface

This article describes how to use MERN technology stack to develop a front and back end of a separate e-commerce project, level limited, shortcomings, please point out, Github.

The backend development

Install and start mongodb and create a new back-end project directory with the following structure

npm init

npm i express mongoose multer validator jsonwebtoken dotenv cors bcrypt -S

Image upload multer, validate form data Validator, configure environment variable Dotenv, and handle CORS across domains

Create a. Env file and configure parameters such as database in it

DB_HOST=localhost
DB_PORT=27017
DB_NAME=cake-shop
JWT_KEY=my_jwt_key
PORT=9090
HOSTNAME=http://localhost
Copy the code

You then define the data model product.js under the Models directory to represent the product, and so on

// product.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema

const productSchema = new Schema(
  {
    name: {
      type: String.required: true.default: ' '
    },
    description: {
      type: String.default: ' '
    },
    price: {
      type: Number.required: true
    },
    stock: {
      type: Number.default: 0
    },
    imgList: {
      type: Array.default: ' '
    },
    category: {
      type: Array
    },
    top: {
      type: Boolean.default: false
    },
    rate: {
      type: Number.default: 5.0
    },
    publish: {
      type: Boolean.default: false}}, {timestamps: { createdAt: 'created_at'.updatedAt: 'updated_at'}})module.exports = mongoose.model('Product', productSchema)
Copy the code

Create product.js in the routes directory to define the product-related route. Create index.js to export the product.js route. Then create product.js in the controllers directory to handle product-specific routes and use it in the entry file

// routes/product.js
const express = require('express')
const router = express.Router()
const auth = require('.. /middleware/auth')
const controller = require('.. /controllers/product')

router.get('/', controller.getAllProducts)
router.get('/top', controller.getTopProducts)
router.get('/recommend', controller.getRecommendProducts)
router.get('/detail/:productId', controller.getProductDetail)
router.get('/:sort', controller.getProducts)
router.post('/', controller.addProduct)

router
  .route('/:productId')
  .put(auth, controller.updateProduct)
  .delete(auth, controller.deleteProduct)

module.exports = router

Copy the code
// index.js
const routes = require('./routes')... app.use('/api/product', routes.product)
Copy the code

Write the logical code corresponding to the route in the controller, run the code logic with Postman, verify the field when the user registers, encrypt the user password, and return the token generated by JsonWENToken to the front end when the user logs in

// controllers/user.js
/ / register
async function signUp(req, res, next) {
  let { name, email, password } = req.body

  if(! isVerifiedField(name)) {return res.status(400).json({ success: false.message: 'Please enter a user name greater than 4 characters in length'})}if(! isVerifiedEmail(email)) {return res.status(400).json({ success: false.message: 'Please enter the correct email address'})}if(! isVerifiedField(password)) {return res.status(400).json({ success: false.message: 'Please set a password of at least 4 characters.'})}const oldUser = await User.findOne({ email }).exec() // Verify that the user already exists

  if(oldUser ! = =null) {
    return res.status(409).json({ success: false.message: 'User already exists' })
  }

  password = await bcrypt.hash(password, 10)  // Encrypt the user password

  const newUser = new User({ name, email, password })

  newUser
    .save()
    .then(result= > {
      return res.status(201).json({ success: true, result })
    })
    .catch(error= > {
      return res.status(500).json({ success: false, error })
    })
}
/ / login
async function login(req, res, next) {
  const { name, email, password } = req.body

  if (name) {
    checkField({ name })
  }

  if (email) {
    checkField({ email })
  }

  async function checkField(field) {
    const user = await User.findOne(field).exec()

    if (user === null) {
      return res.status(404).json({ success: false.message: 'User does not exist'})}const isMatch = await bcrypt.compare(password, user.password)

    if (isMatch) {
      const token = jwt.sign({ field, id: user._id }, process.env.JWT_KEY) / / token is generated

      return res.status(200).json({ success: true.message: 'Login successful', token }) / / returns a token
    } else {
      return res.status(401).json({ success: false.message: 'Password error'})}}}Copy the code

Management background

Create a project using create-react-app, and install dependency packages using YARN

npx create-react-app you-project

yarn add antd react-router-dom axios

Configure the CSS preprocessor according to the User Guide of create-React-app

Establish the project directory structure

Configuration axios

import axios from 'axios'

const token = localStorage.getItem('CAKE_SHOP_AUTH_TOKEN')

const Request = axios.create({
  baseURL: 'http://localhost:9090/api'.timeout: 5000.headers: {
    authorization: token ? token : ' ' // If you have a token, put it in the request headers}})export default Request

Copy the code

A page for administrator registration and login is set up in the Pages directory. After the user logs in, the token returned by the backend is stored in localStorage and the user jumps to the workbench home page

// pages/Login

import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { Layout, Form, Icon, Input, Button, Checkbox, message as Message } from 'antd'

import '.. /account.css'
import { ManagerContext } from '.. /.. /store/manager'
import ManagerService from '.. /.. /services/manager'
import { CAKE_SHOP_AUTH_TOKEN, CAKE_SHOP_USER_INFO } from '.. /.. /constant'

const { Item } = Form
const { Content, Footer } = Layout

class Login extends Component {
  handleSubmit = e= > {
    e.preventDefault()
    this.props.form.validateFields(async (err, values) => {
      if(! err) {const { name, password } = values

        ManagerService.login(name, password)  // Request the login interface
          .then(res= > {
            const { history, login } = this.props // The history object comes from react-router-dom
            const { message, token, manager } = res.data

            Message.success(message)
            localStorage.setItem(CAKE_SHOP_AUTH_TOKEN, `Bearer ${token}`)
            localStorage.setItem(CAKE_SHOP_USER_INFO, JSON.stringify(manager))
            login(manager)
            history.push('/dashboard')
          })
          .catch(error= > {
            const { data } = error.response

            Message.error(data.message)
          })
      }
    })
  }

  render() {
    const { getFieldDecorator } = this.props.form

    return( <ManagerContext.Consumer> {login => ( <Layout className="account" login={login}> <Content ClassName ="account__content"> <h1 className="account__title"> Store Management system </ H1 > <sub className="account__sub-title"> Login </sub> <Form className="account__form" onSubmit={this.handleSubmit}> <Item> {getFieldDecorator('name', { rules: [{ required: }]})(<Input prefix={<Icon type="user" style={{color: RGB (51, 51, 51); 'rgba(0,0,0,.25)'}} />} placeholder="Username admin" />)} </Item> <Item> {getFieldDecorator('password', {rules: [{required: true, message: 'Please enter your password!'}]})(<Input prefix={<Icon type="lock" style={{color: 'rgba(0,0,0,.25)'}} />} type="password" placeholder=" password admin" />) </Button> </Item> <Item> {getFieldDecorator('remember', {valuePropName: 'checked', initialValue: True})(<Checkbox> remember me </Checkbox>)} </Item> </Form> </Content> <Footer className="account__footer"> <a className="account__link" href="https://xrr2016.github/io" target="_blank" rel="noopener noreferrer" > <Icon type="github" /> </a> <a className="account__link" href="mailto:[email protected]"> <Icon type="mail" /> </a> </Footer> </Layout> )} </ManagerContext.Consumer> ) } } export default withRouter(Form.create()(Login))Copy the code

Create a subroute page in the workbench in the Routes directory, write the corresponding logic, and process different services. Finally, define the react-router-dom route in the entry file

The front page

Use create-react-app to create a project and use YARN to install required dependency packages

npx create-react-app you-project

yarn add antd-mobile react-router-dom axios

Establish the project directory structure

The main difference between the logic here and the management background is that the data interface of the request is different, as well as the UI of the page is different, and the specific implementation, UI interaction and so on depends on the individual.

The source address

The deployment of

After the function is developed, use Yanr build to package the front-end and management background projects, upload the code to the server, configure different domain names, use Nginx reverse proxy, prevent the refresh browser 404.

location / {
  try_files $uri $uri/ /index.html;
}
Copy the code