1. 程式人生 > >搭建JAVA電商平臺——後端

搭建JAVA電商平臺——後端

目錄

1.前言

2.正文

程式框架

資料庫

程式碼結構

程式碼

結語

1.前言

電商是當今最火爆的一種商業模式,學習springMVC等網頁後端技術的我們,都很難找得到相關的例項,而往往很多公司在招聘的時候都會或多或少地要求有電商平臺開發的相關經驗。而筆者的一個朋友分享了一個電商平臺的前端程式碼,但是後端程式碼是沒有的,筆者找到了一小部分,但是是無法支撐整個電商平臺的執行,於是,筆者只能自己分析前端的程式碼再去推敲出後端的邏輯,也許你能在網上找到有相似的網站,但是內部邏輯也許是不盡相同的。

接下來我們上幾張效果圖大家看看,如果有興趣再往下讀。

2.正文

程式框架

使用者瀏覽商品——加入到購物車——生成訂單——支付——發貨——完成 

資料庫

talk is cheap ,show me the code。資料庫是一切系統的基礎,程式是資料結構+演算法。而我覺得,資料結構的基礎就是資料庫的設計。 

首先,作為一個電商系統,我們需要的是使用者,那麼我們就首先需要一個使用者表 

DROP TABLE IF EXISTS `mmall_user`;
CREATE TABLE `mmall_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '使用者表id',
  `username` varchar(50) NOT NULL COMMENT '使用者名稱',
  `password` varchar(50) NOT NULL COMMENT '使用者密碼,MD5加密',
  `email` varchar(50) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `question` varchar(100) DEFAULT NULL COMMENT '找回密碼問題',
  `answer` varchar(100) DEFAULT NULL COMMENT '找回密碼答案',
  `role` int(4) NOT NULL COMMENT '角色0-管理員,1-普通使用者',
  `wechat_openid` varchar(255) DEFAULT NULL, 微信的openid
  `create_time` datetime NOT NULL COMMENT '建立時間',
  `update_time` datetime NOT NULL COMMENT '最後一次更新時間',
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_name_unique` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8;

接下來作為一個電商平臺我們當然是以產品為主

DROP TABLE IF EXISTS `mmall_product`;
CREATE TABLE `mmall_product` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '商品id',
  `category_id` int(11) NOT NULL COMMENT '分類id,對應mmall_category表的主鍵',
  `activity_id` int(11) DEFAULT NULL,
  `name` varchar(100) NOT NULL COMMENT '商品名稱',
  `subtitle` varchar(200) DEFAULT NULL COMMENT '商品副標題',
  `main_image` varchar(500) DEFAULT NULL COMMENT '產品主圖,url相對地址',
  `sub_images` text COMMENT '圖片地址,json格式,擴充套件用',
  `detail` text COMMENT '商品詳情',
  `price` decimal(20,2) NOT NULL COMMENT '價格,單位-元保留兩位小數',
  `stock` int(11) NOT NULL COMMENT '庫存數量',
  `status` int(6) DEFAULT '1' COMMENT '商品狀態.1-在售 2-下架 3-刪除',
  `create_time` datetime DEFAULT NULL COMMENT '建立時間',
  `update_time` datetime DEFAULT NULL COMMENT '更新時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;

對於產品,我們通常為了更好的進行管理,會對其進行分品類,所以一個品類表是必不可少的

DROP TABLE IF EXISTS `mmall_category`;
CREATE TABLE `mmall_category` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '類別Id',
  `parent_id` int(11) DEFAULT NULL COMMENT '父類別id當id=0時說明是根節點,一級類別',
  `name` varchar(50) DEFAULT NULL COMMENT '類別名稱',
  `status` tinyint(1) DEFAULT '1' COMMENT '類別狀態1-正常,2-已廢棄',
  `sort_order` int(4) DEFAULT NULL COMMENT '排序編號,同類展示順序,數值相等則自然排序',
  `create_time` datetime DEFAULT NULL COMMENT '建立時間',
  `update_time` datetime DEFAULT NULL COMMENT '更新時間',
  `main_image` varchar(500) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100053 DEFAULT CHARSET=utf8;

有了品類,產品以及使用者,那麼自然就是我們作為電商系統的一個最重要也是業務最繁忙的表,訂單表

DROP TABLE IF EXISTS `mmall_order`;
CREATE TABLE `mmall_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '訂單id',
  `order_no` bigint(20) DEFAULT NULL COMMENT '訂單號',
  `user_id` int(11) DEFAULT NULL COMMENT '使用者id',
  `shipping_id` int(11) DEFAULT NULL,
  `payment` decimal(20,2) DEFAULT NULL COMMENT '實際付款金額,單位是元,保留兩位小數',
  `payment_type` int(4) DEFAULT NULL COMMENT '支付型別,1-線上支付',
  `postage` int(10) DEFAULT NULL COMMENT '運費,單位是元',
  `status` int(10) DEFAULT NULL COMMENT '訂單狀態:0-已取消-10-未付款,20-已付款,40-已發貨,50-交易成功,60-交易關閉',
  `payment_time` datetime DEFAULT NULL COMMENT '支付時間',
  `send_time` datetime DEFAULT NULL COMMENT '發貨時間',
  `end_time` datetime DEFAULT NULL COMMENT '交易完成時間',
  `close_time` datetime DEFAULT NULL COMMENT '交易關閉時間',
  `create_time` datetime DEFAULT NULL COMMENT '建立時間',
  `update_time` datetime DEFAULT NULL COMMENT '更新時間',
  PRIMARY KEY (`id`),
  UNIQUE KEY `order_no_index` (`order_no`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=145 DEFAULT CHARSET=utf8;

大概幾個核心的資料表就是這樣,剩下的一些不那麼重要的表我們就不在這裡放出了。

在上面的表結構當中我們看到了,主要的關係是通過user_id去維繫。

程式碼結構

大概根據主流的分層結構MVC

  • controller這個大家都熟知是web層的邏輯處理層
  • dao就是我們的資料庫控制層,對於資料庫的控制我們都會在這裡編寫
  • pojo所有orm的實體類我們都存放在這裡

另外一些我們就不在這裡詳解了

程式碼

對於程式碼,其實在這裡我需要講的也並不多,因為都是一些業務邏輯的問題,在這裡也不需要太多的解析,需要了解的話可以到文末我提供的GitHub地址去pull下來或者star一下大家自己就可以去領會了,但是有必要說幾個需要注意的地方,在此篇我們就說兩個類

為什麼要特意抽出這兩個類來解析一下呢。因為我們這個電商系統是完全前後端分離的,但是我們系統往往是有一個團隊或者是多個開發者共同合作完成的,但是既然是前後端完全分離那麼我們自然就是要規定好統一返回到前端的格式。才能夠更好的開展開發工作,那麼眾口難調,對於不同開發者來說,喜歡用的狀態或者結構都不盡相同,另外就是每次都要重複編寫返回程式碼是非常麻煩的。所以我們這兩個類就是統一了返回結果,作為不同模組的開發者我們只需要呼叫就可以返回一個規範的返回結果了,也省去了重複程式碼的編寫,那麼接下來我們來看看這兩個類吧

package com.ppmall.common;

import java.io.IOException;
import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 服務response封裝工具
 * @author rex
 *
 * @param <T>
 */
@JsonInclude(JsonInclude.Include.NON_NULL) // 這是Jackson的一個註解,是排除為空的欄位
public class ServerResponse<T> implements Serializable {
// 在這裡我們運用了泛型,那麼可以很好確保儘管是不同型別的物件需要返回到前端都可以很好地進行格式化
   /**
    * 狀態
    */
	private int status;
	
	/**
	 * 返回訊息
	 */
    private String msg;
    
    /**
     * 返回資料(泛型)
     */
    private T data;
    
    public ServerResponse() {
		// TODO Auto-generated constructor stub
    	// 用於GenericJacksonSerializable 反序列化
	}

    private ServerResponse(int status) {
        this.status = status;
    }

    private ServerResponse(int status, String msg) {
        this.status = status;
        this.msg = msg;
    }

    private ServerResponse(int status, String msg, T data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    private ServerResponse(int status, T data) {
        this.status = status;
        this.data = data;
    }

    @JsonIgnore
    public boolean isSuccess() {
        return this.status == ResponseCode.SUCCESS.getCode();
    }

    public int getStatus() {
        return this.status;
    }

    public String getMsg() {
        return this.msg;
    }

    public T getData() {
        return this.data;
    }

    /**
     * 建立一個只有成功狀態的response
     * @return
     */
    public static <T> ServerResponse<T> createSuccess() {
        return new ServerResponse<T>(ResponseCode.SUCCESS.getCode());
    }

    /**
     * 建立一個帶成功資訊的response
     * @return
     */
    public static <T> ServerResponse<T> createSuccessMessage(String msg) {
        return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg);
    }

    /**
     * 建立一個帶訊息以及資料的response
     * @return
     */
    public static <T> ServerResponse<T> createSuccess(String msg, T data) {
        return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg, data);
    }
    
    /**
     * 建立一個只有資料的response
     * @return
     */
    public static <T> ServerResponse<T> createSuccess(T data) {
        return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), data);
    }

    /**
     * 建立一個錯誤狀態的response
     * @return
     */
    public static <T> ServerResponse<T> createError(){
        return new ServerResponse<T>(ResponseCode.ERROR.getCode(),ResponseCode.ERROR.getDesc());
    }

    /**
     * 建立一個帶錯誤訊息的response
     * @return
     */
    public static <T> ServerResponse<T> createErrorMessage(String errorMsg){
        return new ServerResponse<T>(ResponseCode.ERROR.getCode(),errorMsg);
    }

    /**
     * 建立一個自定義錯誤狀態與訊息的response
     * @param status
     * @param errorMsg
     * @return
     */
    public static <T> ServerResponse<T> createErrorStatus(int status,String errorMsg){
        return new ServerResponse<T>(status,errorMsg);
    }
    
    public static <T> ServerResponse<T> createErrorStatus(ResponseCode code){
        return new ServerResponse<T>(code.getCode(),code.getDesc());
    }

    
    @Override
    public String toString() {
    	// jackson序列化
        ObjectMapper mapper = new ObjectMapper();
        try {
            String returnString =  mapper.writeValueAsString(this);
            return returnString;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.toString();
    }
}

這裡運用到了java的泛型以及函式過載。既然已經定義好那麼我們在開發的時候只需要簡單的呼叫就可以了

if (user == null) {
    return ServerResponse.createErrorMessage("使用者名稱或密碼錯誤");
	      }
// todo 密碼MD5
return ServerResponse.createSuccess("登陸成功", user);
{
    "status": 0,
    "msg": "登陸成功",
    "data":{
        "id": 34,
        "username": "test",
        "password": "02C75FB22C75B23DC963C7EB91A062CC",
        "email": "[email protected]",
        "phone": "13252566523",
        "question": "test",
        "answer": "test",
        "role": 0,
        "wechatOpenid": null,
        "createTime": 1528124324000,
        "updateTime": 1528124324000
    }
}

上邊就是返回的結果,根據ServerResponse這個類的幾個靜態方法我們只是會改變裡面的資料,格式是恆定不變的。

結語

好了,以上就是我們一個簡單的電商平臺的簡單部分,只講述了簡單的一些資料結構以及比較重要的類,至於一些配置還有核心程式碼邏輯我們會在接下來分期進行解析,喜歡的朋友們可以繼續關注。在最後,放出這個專案的GitHub地址,裡面有詳細的程式碼,有興趣的朋友可以Star一下。這是本人的第一篇部落格,寫的不好請多多包涵。

關注愛養貓的程式狗可以最快獲取系列更新哦