欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

手把手教你搭建一个完整的电商系统之品牌管理

程序员文章站 2022-04-14 21:37:11
...

猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是问题。想要一起实战吗?,关注公主号猿人工厂获取基础代码,手把手带你开发一个完整的电商系统。

前后端框架已经搭建起来了,接下来的很长一段日子里,猿人君就带着大家撸一个电商系统出来玩耍。实战阶段的目的,是为了让你从需求梳理落地到实现有一个完整的认知,熟练掌握撸码的一些套路,让你具备设计和实现一个完整系统的能力。废话不多说,我们今天开始首战——品牌管理的设计和实现。

需求整理

根据之前的猿设计系列文章猿设计2——电商后台全逻辑需求挖掘,品牌数据是需要维护的,根据对设计文档的梳理,我们需要做的功能如下图所示:

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

 

 

品牌管理的功能包括,品牌列表——支持根据品牌名称模糊查询并分页展示,新增品牌、编辑品牌、删除品牌、停用/启用品牌,以及为了方便运营人员批量操作而提供的勾选记录批量停用/启用/删除功能。

数据库设计

由于之前的设计文章中,我们已经提及过品牌实体的一些属性了,而这些属性背后承载的信息,将为我们的电商系统提供数据支撑,毫无疑问,这些数据是需要持久的,为此我们自然需要建立相应的数据表来支持。

手把手教你搭建一个完整的电商系统之品牌管理

前端主要组件

由于我们使用了vue-element-admin.git作为基础的后天管理前端开发框架,前端中使用的主要组件,主要是element-ui,关于组件的具体使用办法,大家可以参考官方网站:

https://element.eleme.cn/#/zh-CN

在品牌管理这一功能中,我们主要使用了el-card、el-input、el-button、el-table(列表)、el-pagination(分页)、el-upload(上传组件),考虑到你可能是第一次编写前端代码,很多东西都还不熟悉,这次就把前端的UI代码送给你了。

<template>
  <divid="brandManagementDiv">
    <el-cardclass="filter-container" shadow="never">
      <div>
        <el-formref="listQuery" :model="listQuery" :inline="true">
          <el-form-itemlabel="品牌名称:"prop="brandName">
            <el-inputv-model="listQuery.brandName" placeholder="请输入品牌名称" clearable />
         </el-form-item>
         <el-form-item>
            <el-buttontype="primary" icon="el-icon-edit"@click="addBrand()">新增</el-button>
            <el-buttontype="primary" icon="el-icon-search"@click="fetchData()">查询</el-button>
            <el-buttonicon="el-icon-s-tools" @click="resetForm('listQuery')">重置</el-button>
            <el-buttontype="primary" @click="enbleDataList()">全部启用</el-button>
            <el-buttontype="primary" @click="disableDataList()">全部停用</el-button>
            <el-buttontype="danger" @click="deleteDataList()">全部删除</el-button>
         </el-form-item>
        </el-form>
      </div>
    </el-card>
    <divstyle="height:20px;" />
    <divclass="table-container">
      <el-table
       ref="multipleTable"
       v-loading="listLoading"
       :data="list"
        style="width:100%"
        border
        @selection-change="handleSelectionChange"
      >
       <el-table-column type="selection" min-width="10%"/>
       <el-table-column label="编号" min-width="10%">
          <templateslot-scope="scope">{{ scope.row.id }}</template>
       </el-table-column>
       <el-table-column label="品牌名称">
          <templateslot-scope="scope">{{ scope.row.brandName }}</template>
       </el-table-column>
       <el-table-column label="品牌首字母" min-width="10%">
          <templateslot-scope="scope">{{ scope.row.firstChar }}</template>
       </el-table-column>
        <el-table-columnlabel="品牌logo"align="center">
          <templateslot-scope="scope"><img style="width: 200px; height:200px" :src="scope.row.logo"alt=""></template>
       </el-table-column>
       <el-table-column label="状态" min-width="10%">
          <templateslot-scope="scope">{{ scope.row.status == 1 ? "启用" : "停用"}}</template>
       </el-table-column>
       <el-table-column label="操作" width="220">

          <templateslot-scope="scope">
            <el-button
              type="primary"
             size="mini"
             @click="handleUpdate(scope.row)"
            >编辑
           </el-button>
            <el-button
             v-if="scope.row.status==1"
             type="primary"
             size="mini"
              @click="handleDisable(scope.$index,scope.row)"
            >停用
           </el-button>
            <el-button
             v-if="scope.row.status==0"
             type="primary"
             size="mini"
             @click="handleEnable(scope.$index, scope.row)"
            >启用
           </el-button>
            <el-button
             size="mini"
             type="danger"
             @click="handleDelete(scope.$index, scope.row)"
            >删除
           </el-button>
          </template>
       </el-table-column>
      </el-table>
    </div>
    <paginationv-show="total>0" :total="total":page.sync="listQuery.page":limit.sync="listQuery.pageSize" @pagination="getList"/>

    <!-- 新增/编辑弹框 -->
    <el-dialog:title="textMap[dialogStatus]":visible.sync="dialogFormVisible">
      <el-formref="dataForm" :rules="rules" :model="temp"label-position="right" label-width="100px"style="width: 500px; margin-left:50px;">
        <el-form-itemlabel="品牌名称:"prop="brandName">
          <el-inputv-model="temp.brandName" />
       </el-form-item>
        <el-form-itemlabel="品牌首字母:"prop="firstChar">
          <el-inputv-model="temp.firstChar" maxlength="1"oninput="value=value.replace(/[^A-Z]/g,'');" alt="英文大写" />
       </el-form-item>
        <el-form-itemv-show="dialogVisible" label="品牌logo:" prop="logo"style="margin-top:15px;">
          <imgstyle="width: 200px; height: 200px" :src="temp.logo"alt="">
       </el-form-item>
       <el-form-item>
          <el-upload
            ref="upload"
           :file-list="imgList"
           action="http://127.0.0.1:9201//upload/uploadFile?moudle=brand"
           list-type="picture-card"
           :on-preview="handlePictureCardPreview"
           :on-success="handleSuccess"
            :limit="1"
           accept="image/jpeg,image/gif,image/png,image/bmp"
          >
            <iclass="el-icon-plus" />
         </el-upload>
       </el-form-item>
      </el-form>
      <divslot="footer">
        <aaa@qq.com="dialogFormVisible = false">
          取消
        </el-button>
        <el-buttontype="primary"@click="dialogStatus==='create'?createData():updateData()">
          确定
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>
<style scoped>
#brandManagementDiv /deep/ .el-form-item--mini.el-form-item__label {
 width: 100px !important;
}
</style>

后端代码之实体层

前端页面的初步代码有了,我们开始后端数据访问层的设计。根据数据库表结构,我们可以迅速的得到我们所需要的实体MallBrand和QueryMallBrand.为什么是两个实体?因为数据查询和持久是两回事情,在查询实体中,可能为了匹配页面的查询条件而增加一些不需要持久的条件,所以我们需要分开。实体层的代码编写在哪里?自然是我们的pzmall-basic-domain模块了。

/**
 * Copyright(c) 2004-2020pangzi
 *com.pz.basic.mall.domain.sys.MallCity.java
 */
package com.pz.basic.mall.domain.base;

import org.apache.commons.lang3.builder.ToStringBuilder;

import java.io.Serializable;

/**
 *
 * @author pangzi
 * @date 2020-06-2211:28:19
 *
 *
 */
public class BaseDO implements Serializable {

  private static final longserialVersionUID = 1L;


  /**
   * 如果字段值为null将不包含在toString中
   */
  @Override
  public String toString(){
     returnToStringBuilder.reflectionToString(this);
  }
}


 


package com.pz.basic.mall.domain.sys;

import com.pz.basic.mall.domain.base.BaseDO;

import java.util.Date;


/**
 *
 * @author pangzi
 * @date 2020-06-2718:09:41
 *
 */
public class MallBrand extends BaseDO {

    /**主键**/
  private Long id;

    /**品牌名**/
  private String brandName;

    /**logo图片地址**/
  private String logo;

    /**品牌首字母**/
  private String firstChar;

    /**状态1可用0不可用**/
  private Integer status;

    /**记录状态1有效0删除**/
  private Integer active;

    /**创建人**/
  private StringcreateUser;

    /**修改人**/
  private StringmodifyUser;

    /**创建时间**/
  private Date created;

    /**修改时间**/
  private Date modified;
    //getter setter省略

}
package com.pz.basic.mall.domain.sys.query;
import com.pz.basic.mall.domain.base.PaginateBaseDO;

import java.util.Date;


/**
 *
 * @author pangzi
 * @date 2020-06-2718:09:41
 *
 *
 */
public class QueryMallBrand extends PaginateBaseDO {

    /**主键**/
  private Long id;

    /**品牌名**/
  private String brandName;

    /**logo图片地址**/
  private String logo;

    /**品牌首字母**/
  private String firstChar;

    /**状态1可用0不可用**/
  private Integer status;

    /**记录状态1有效0删除**/
  private Integer active;

    /**创建人**/
  private StringcreateUser;

    /**修改人**/
  private StringmodifyUser;

    /**创建时间**/
  private Date created;

    /**修改时间**/
  private Date modified;

     /**支持品牌名称模糊查询**/
  private String brandNameLike;
}

大家可能注意到了,两个类都是子类,为什么这样设计?猿人君先卖个关子,先给出实现,至于你猜到几分,也可以考验你功力深浅噢。

package com.pz.basic.mall.domain.base;

import java.io.Serializable;

/**
 *
 * @author pangzi
 * @date 2020-06-2211:28:19
 *
 *
 */
public class PaginateBaseDO implements Serializable {
    /**
     * 默认每页的记录数量
     */
    public static finalint PAGESIZE_DEFAULT = 20;
    /**
     * 每页大小
     */
    private long pageSize;
    /**
     * 当前页。第一页是1
     */
    private long page;

    /**
     * 总记录数
     */
    private long totalItem;
    /**
     * 总页数
     */
    private long totalPage;

    /**
     * 分页后的记录开始的地方
     * 第一条记录是1
     */
    private long startRow;
    /**
     * 分页后的记录结束的地方
     */
    private long endRow;

    /**排序字段**/
    private String orderField;

    /**升序 还是 降序,true为升序,false为降序*/
    private Boolean isAsc;

    /**
     * 默认构造方法
     */
    public PaginateBaseDO() {
        repaginate();
    }

    /**
     * 带当前页和页大小的构造方法
     * @param page 当前页
     * @param pageSize 页大小
     */
    public PaginateBaseDO(long page, long pageSize) {
        this.page = page;
        this.pageSize =pageSize;
        repaginate();
    }

    public void setStartRow(long startRow) {
        this.startRow =startRow;
    }

    public void setEndRow(long endRow) {
        this.endRow =endRow;
    }

    /**
     * 表示是不是第一页
     * @return true 是; false 不是
     */
    public boolean isFirstPage(){
        return page <=1;
    }


    public boolean isMiddlePage() {
        return!(isFirstPage() || isLastPage());
    }


    public boolean isLastPage() {
        return page >=totalPage;
    }


    public boolean isNextPageAvailable() {
        return !isLastPage();
    }

    public boolean isPreviousPageAvailable() {
        return!isFirstPage();
    }

    /**
     * 下一页号
     * @return 取得下一页号
     */
    public long getNextPage() {
        if(isLastPage()) {
            returntotalItem;
        } else {
            return page+1;
        }
    }

    public long getPreviousPage() {
        if(isFirstPage()){
            return 1;
        } else {
            return page -1;
        }
    }
    /**
     * Method getPageSizereturns the pageSize of this PaginatedArrayList object.
     *
     *  每页大小
     *
     * @return thepageSize (type int) of this PaginatedArrayList object.
     */

    public long getPageSize() {
        return pageSize;
    }

    /**
     * Method setPageSizesets the pageSize of this PaginatedArrayList object.
     *
     *  每页大小
     *
     * @param pageSize thepageSize of this PaginatedArrayList object.
     *
     */

    public void setPageSize(long pageSize) {
        this.pageSize =pageSize;
        repaginate();
    }

    /**
     * Method getpagereturns the page of this PaginatedArrayList object.
     *
     *  当前页。第一页是1
     *
     * @return the page(type int) of this PaginatedArrayList object.
     */

    public long getPage(){
        return page;
    }

    /**
     * Method setpage setsthe page of this PaginatedArrayList object.
     *
     *  当前页。第一页是1
     *
     * @param page thepage of this PaginatedArrayList object.
     *
     */

    public void setPage(long page) {
        this.page = page;
        repaginate();
    }

    /**
     * Method getTotalItemreturns the totalItem of this PaginatedArrayList object.
     *
     *  总记录数
     *
     * @return thetotalItem (type int) of this PaginatedArrayList object.
     */

    public long getTotalItem() {
        return totalItem;
    }

    /**
     * Method setTotalItemsets the totalItem of this PaginatedArrayList object.
     *
     *  总记录数
     *
     * @param totalItemthe totalItem of this PaginatedArrayList object.
     *
     */

    public void setTotalItem(long totalItem) {
        this.totalItem =totalItem;
        if( this.totalItem<= 0){
            totalPage = 0;
            page = 1;
            startRow = 0;
        }
        repaginate();
    }



    /**
     * Method getTotalPagereturns the totalPage of this PaginatedArrayList object.
     *
     *  总页数
     *
     * @return thetotalPage (type int) of this PaginatedArrayList object.
     */

    public long getTotalPage() {
        return totalPage;
    }

    /**
     * Method getStartRowreturns the startRow of this PaginatedArrayList object.
     *
     *  分页后的记录开始的地方
     *
     * @return the startRow(type int) of this PaginatedArrayList object.
     */

    public long getStartRow() {
        if (startRow >0) {
            returnstartRow;
        }
        if (page <= 0){
            page = 1;
        }
        return (page - 1)* pageSize;
    }

    /**
     * Method getEndRowreturns the endRow of this PaginatedArrayList object.
     *
     *  分页后的记录结束的地方
     *
     * @return the endRow(type int) of this PaginatedArrayList object.
     */

    public long getEndRow() {
        if (endRow > 0){
            return endRow;
        }
        return page *pageSize;
    }

    public String getOrderField() {
        return orderField;
    }


    public void setOrderField(String orderField) {
        this.orderField =orderField;
    }

    public Boolean getIsAsc() {
        return isAsc;
    }

    public void setIsAsc(Boolean isAsc) {
        this.isAsc = isAsc;
    }

    /**
     * Method repaginate...
     */
    public void repaginate() {
        if (pageSize <1) { //防止程序偷懒,list和分页的混合使用
            pageSize =PAGESIZE_DEFAULT;
        }
        if (page < 1) {
            page = 1;//恢复到第一页
        }
        if (totalItem >0) {
            totalPage =totalItem / pageSize + (totalItem % pageSize > 0 ? 1 : 0);
            if(page >totalPage) {
                page =totalPage; //最大页
            }
            endRow = page* pageSize;
            startRow =(page - 1) * pageSize;
           if(endRow>totalItem) {
                endRow =totalItem;
            }
        }
    }
}

后端代码之数据持久层

实体层的代码我们已经完成了,接下拉我们自然需要完成数据持久层的代码了。考虑到前端页面的功能,查询/新增/修改/编辑/停用/启用的功能,我们在编写的时候,可以让数据操作更加面向对象一些。我们来看代码:

/**
 * Copyright(c) 2004-2020pangzi
 *com.pz.basic.mall.dao.sys.MallBrandDao.java
 */
package com.pz.basic.mall.dao.sys;
import com.pz.basic.mall.domain.sys.MallBrand;
import com.pz.basic.mall.domain.sys.query.QueryMallBrand;

import java.util.List;



/**
 *
 * @author pangzi
 * @date 2020-06-2610:56:01
 */
public interface MallBrandDao {

  /**
   * 根据条件查询总数
   * @param query
   * @return
   */
    long countByQuery(QueryMallBrand query);

    /**
   * 根据条件删除记录
   * @param query
   * @return
   */
    int deleteMallBrandByQuery(QueryMallBrand query);

    /**
   * 根据ID删除记录
   * @param id
   * @return
   */
    int deleteMallBrandById(long id);

    /**
   * 新增记录
   * @param record
   * @return
   */
    long insertMallBrand(MallBrand record);

     /**
   * 新增记录 注意:有值的记录才新增
   * @param record
   * @return
   */
    long insertMallBrandModified(MallBrand record);

    /**
   * 根据查询条件返回列表
   * @param query
   * @return
   */
    List<MallBrand> selectMallBrandByQuery(QueryMallBrand query);

  /**
  * 根据查询条件返回列表
  * @param  query
  * @return
  */
     List<MallBrand> selectMallBrandByPage(QueryMallBrand query);

     /**
   * 根据ID查询对象
   * @param id
   * @return
   */
    MallBrand selectMallBrandById(long id);


    /**
   * 根据id修改记录 注意:有值的字段才更新
   * @param record
   * @return
   */
    int updateMallBrandByIdModified(MallBrandrecord);
}

对应的mapper文件MallBrandMapper.xml.

手把手教你搭建一个完整的电商系统之品牌管理

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.pz.basic.mall.dao.sys.MallBrandDao">

  <resultMap id="ResultMap" type="MallBrand">
          <id property="id" column="id"/>
                   <id property="brandName" column="brand_name"/>
                   <id property="logo" column="logo"/>
                   <id property="firstChar" column="first_char"/>
                   <id property="status" column="status"/>
                   <id property="active" column="active"/>
                   <id property="createUser" column="create_user"/>
                   <id property="modifyUser" column="modify_user"/>
                   <id property="created" column="created"/>
                   <id property="modified" column="modified"/>
                                      </resultMap>

  <sql id="ALL_TABLE_COLOUM">
                   id,
                     brand_name,
                     logo,
                     first_char,
                     status,
                     active,
                     create_user,
                     modify_user,
                     created,
                     modified
          </sql>

  <sql id="Query_Where_Clause" >
    <where >
          1=1

                               <if test="id != null and id != ''">
                  and     id =  #{id}
               </if>
                               <if test="brandName != null and brandName != ''">
                  and      brand_name =  #{brandName}
               </if>
                               <if test="logo != null and logo != ''">
                  and      logo = #{logo}
               </if>
                               <if test="firstChar != null and firstChar != ''">
                  and      first_char =  #{firstChar}
               </if>
                                <if test="status!= null and status != ''">
                  and      status = #{status}
               </if>
                               <if test="active != null and active != ''">
                  and      active = #{active}
               </if>
                               <if test="createUser != null and createUser != ''">
                  and      create_user =  #{createUser}
               </if>
                               <if test="modifyUser != null and modifyUser != ''">
                  and      modify_user =  #{modifyUser}
               </if>
                               <if test="created != null and created != ''">
                  and      created = #{created}
               </if>
                                <if test="modified !=null and modified != ''">
                  and      modified =  #{modified}
               </if>

                    <if test="brandNameLike != null and brandNameLike != ''">
                        and      brand_name likeconcat(#{brandNameLike},'%')
                    </if>

    </where>
  </sql>


  <select id="selectMallBrandByQuery" resultMap="ResultMap"parameterType="QueryMallBrand" >
    select
    <include refid="ALL_TABLE_COLOUM" />
    from mall_brand
    <if test="page!= null" >
      <include refid="Query_Where_Clause" />
    </if>

  </select>


    <select id="selectMallBrandByPage" resultMap="ResultMap"parameterType="QueryMallBrand" >
        select
        <include refid="ALL_TABLE_COLOUM" />
        from mall_brand
        <iftest="page != null" >
            <includerefid="Query_Where_Clause" />
        </if>

        LIMIT#{startRow},#{pageSize}
    </select>


  <select id="selectMallBrandById" resultMap="ResultMap"parameterType="java.lang.Long" >
    select
    <include refid="ALL_TABLE_COLOUM" />
    from mall_brand
    where id = #{id}
  </select>
  <delete id="deleteMallBrandById" parameterType="java.lang.Integer">
    delete from mall_brand
    where id = #{id}
  </delete>


  <delete id="deleteMallBrandByQuery" parameterType= "QueryMallBrand">
    delete from mall_brand
    <if test="page!= null" >
      <include refid="Query_Where_Clause" />
    </if>
  </delete>


  <insert id="insertMallBrand" parameterType="MallBrand" >
    INSERT INTO
  mall_brand(id,brand_name,logo,first_char,status,active,create_user,modify_user,created,modified)
  VALUES(#{id},#{brandName},#{logo},#{firstChar},#{status},#{active},#{createUser},#{modifyUser},#{created},#{modified})
      <select Key resultType="long" keyProperty="id">
          aaa@qq.com@IDENTITY AS ID
      </selectKey>
  </insert>


  <insert id="insertMallBrandModified" parameterType="MallBrand" >
    insert into mall_brand
    <trimprefix="(" suffix=")" suffixOverrides="," >


             <if test="id != null" >
                 id,
             </if>


             <if test="brandName != null" >
                brand_name,
             </if>


             <iftest="logo != null" >
                 logo,
             </if>


             <if test="firstChar != null" >
                first_char,
             </if>


             <if test="status != null" >
                 status,
             </if>


             <if test="active != null" >
                 active,
             </if>


             <if test="createUser != null" >
                create_user,
             </if>


             <if test="modifyUser != null" >
                modify_user,
             </if>


             <if test="created != null" >
                 created,
             </if>


             <if test="modified != null" >
                 modified,
             </if>

       </trim>

    <trim prefix="values (" suffix=")" suffixOverrides=",">
                                 <if test="id !=null" >
                   #{id},
               </if>

                                <iftest="brandName != null" >
                  #{brandName},
               </if>

                                <if test="logo != null">
                  #{logo},
               </if>

                                <iftest="firstChar != null" >
                  #{firstChar},
               </if>

                                <iftest="status != null" >
                  #{status},
               </if>

                                <iftest="active != null" >
                  #{active},
               </if>

                                <iftest="createUser != null" >
                  #{createUser},
               </if>

                                <iftest="modifyUser != null" >
                  #{modifyUser},
               </if>

                                <if test="created!= null" >
                   now(),
               </if>

                                <iftest="modified != null" >
                   now(),
               </if>

          </trim>

      <selectKey resultType="long" keyProperty="id">
          aaa@qq.com@IDENTITY AS ID
      </selectKey>
  </insert>


  <select id="countByQuery" parameterType="QueryMallBrand"  resultType="java.lang.Long" >
    select count(*) frommall_brand
    <if test="page!= null" >
      <include refid="Query_Where_Clause"/>
    </if>
  </select>



  <update id="updateMallBrandByIdModified" parameterType="MallBrand">
    update mall_brand
    <set >

                                                          <iftest="brandName != null" >
                     brand_name =  #{brandName},
                </if>

                                                <iftest="logo != null" >
                     logo=  #{logo},
                </if>

                                                <iftest="firstChar != null" >
                    first_char =  #{firstChar},
                </if>

                                                <iftest="status != null" >
                    status =  #{status},
                </if>

                                                <iftest="active != null" >
                    active =  #{active},
                </if>

                                                <iftest="createUser != null" >
                    create_user =  #{createUser},
                </if>

                                                <iftest="modifyUser != null" >
                    modify_user =  #{modifyUser},
                 </if>

                                                <iftest="created != null" >
                    created =  #{created},
                </if>

                                                <iftest="modified != null" >
                    modified=now(),
                </if>


    </set>
    where id = #{id}
  </update>


</mapper>

最后别忘了在mybatis的总控文件SqlMapConfig.xml中增加需要用到的别名和引用。

手把手教你搭建一个完整的电商系统之品牌管理

后端代码之service层

   我们之前已经说了,service层是编写业务的核心逻辑,通过调用dao方式完成业务逻辑对应的数据操作。

/**
 * Copyright(c) 2004-2020 pangzi
 *com.pz.basic.mall.service.sys.MallBrandService.java
 */
package com.pz.basic.mall.service.sys;
import com.pz.basic.mall.domain.base.Result;
import com.pz.basic.mall.domain.sys.MallBrand;
import com.pz.basic.mall.domain.sys.query.QueryMallBrand;

import java.util.List;



/**
 * service层,组装外部接口和 本地业务,为本业务 或者其他业务提供服务,统一返回Result
 * 通过Result.isSuccess判断调用是否成功
 * 此类中新增业务接口设计(接口命令,入参数据,返回值)要能尽量完整的表达业务 含义
 * @author pangzi
 * @date 2020-06-26 11:20:40
 */
public interface MallBrandService {

   /**
    * 新增 mallBrand
    * 返回result,通过result.isSuccess()判断服务调用是否成功
    * 通过result.getModel()得到新增mallBrand
    * @param mallBrand
    * @return
    */
    public Result<MallBrand> addMallBrand(MallBrand mallBrand) ;

    /**
     * 按照主键id更新mallBrand,请重新new MallBrand 的更新对象,设置要更新的字段
    * 返回result,通过result.isSuccess()判断更新是否成功
     * @param mallBrand
     * @return
     */
    public Result updateMallBrandById(MallBrandmallBrand);

    /**
     * 按照主键id 删除 记录
    * 返回result,通过result.isSuccess()判断删除是否成功
     * @return
     */
    public Result deleteMallBrandById(MallBrandmallBrand);

    /**
     * 查询列表,此接口不包含分页查询
    * 返回result,通过result.isSuccess()判断服务调用是否成功
    * 通过result.getModel()得到列表信息
     * @param queryMallBrand
     * @return
     */
    public Result<List<MallBrand>> getMallBrandsByQuery(QueryMallBrand queryMallBrand);

    /**
     * 通过主键id查询MallBrand
    * 返回result,通过result.isSuccess()判断服务调用是否成功
    * 通过result.getModel()得到查询的单条mallBrand信息
     * @param id
     * @return
     */
    public Result<MallBrand> getMallBrandById(long id);

    /**
     * 查询列表,包含分页查询
    * 查询分页信息,请设置
    * QueryMallBrand.setIndex(设置当前页数)
    *QueryMallBrand.setPageSize(设置当前页面数据行数)
    * 返回result,通过result.isSuccess()判断服务调用是否成功
    * 通过result.getTotal()返回结果总数
    * 通过result.getModel()得到查询的单页列表信息
     * @param queryMallBrand
     * @return
     */
    public Result<List<MallBrand>> getMallBrandsByPage(QueryMallBrand queryMallBrand);

    /**
     * 查询总数
     * @param queryMallBrand
     * @return
     */
    public Result<Long> count(QueryMallBrand queryMallBrand);

   /**
    * 停用启用品牌列表
    * 返回result,通过result.isSuccess()判断服务调用是否成功
    * 通过result.getModel()得到列表信息
    * @param brandList
    * @param disable true 停用 false 启用
    * @return
    */
   public Result disableEnableMallBrandList(List<MallBrand>brandList, boolean disable);

   /**
    * 逻辑删除品牌列表
    * 返回result,通过result.isSuccess()判断服务调用是否成功
    * 通过result.getModel()得到列表信息
    * @param brandList
    * @return
    */
   public Result deleteMallBrandList(List<MallBrand>brandList);

}

/**
 * Copyright(c) 2004-2020 pangzi
 *com.pz.basic.mall.service.sys.impl.MallBrandService.java
 */
package com.pz.basic.mall.service.sys.impl;
import com.pz.basic.mall.dao.sys.MallBrandDao;

import java.util.ArrayList;
import java.util.List;

import com.pz.basic.mall.domain.base.Result;
import com.pz.basic.mall.domain.base.enums.DataActiveStatusEnum;
import com.pz.basic.mall.domain.base.enums.DataStatusEnum;
import com.pz.basic.mall.domain.sys.query.QueryMallBrand;
import com.pz.basic.mall.service.sys.MallBrandService;

import com.pz.basic.mall.domain.sys.MallBrand;


/**
 *
 * @author pangzi
 * @date 2020-06-26 11:25:00
 */
public class MallBrandServiceImpl implements MallBrandService {


   private MallBrandDao mallBrandDao;

   public void setMallBrandDao(MallBrandDao mallBrandDao) {
      this.mallBrandDao =mallBrandDao;
   }
    public Result<MallBrand> addMallBrand(MallBrand mallBrand) {
      Result<MallBrand> result = new Result<MallBrand>();
      try {
        QueryMallBrand query = new QueryMallBrand();
        query.setBrandName(mallBrand.getBrandName());
        long count = mallBrandDao.countByQuery(query);
        if(count>0){
           result.setSuccess(false);
           result.setMessage("品牌名已存在");
           return result;
        }
      mallBrand.setStatus(DataStatusEnum.STATUS_ENABLE.getStatusValue());
      mallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
      mallBrandDao.insertMallBrand(mallBrand);
            result.addDefaultModel(mallBrand);
      } catch(Exception e) {
        result.setSuccess(false);
      }
      return result;
    }

    public Result updateMallBrandById(MallBrandmallBrand) {
      Result result = new Result();
      try {
        int count=mallBrandDao.updateMallBrandByIdModified(mallBrand);
        if(count>0){
        result.setSuccess(true);
           }
      } catch(Exception e) {
        result.setSuccess(false);
      }
      return result;
    }

    public Result deleteMallBrandById(MallBrandmallBrand) {
      Result result = new Result();
      try {
        int count=0;
        MallBrand modifiedMallBrand = new MallBrand();
        modifiedMallBrand.setId(mallBrand.getId());
      modifiedMallBrand.setActive(DataActiveStatusEnum.STATUS_DELETED.getStatusValue());
         count=mallBrandDao.updateMallBrandByIdModified(modifiedMallBrand);
        if(count>0){
        result.setSuccess(true);
            }
      } catch(Exception e) {
        result.setSuccess(false);
      }
      return result;
    }

    public Result<List<MallBrand>> getMallBrandsByQuery(QueryMallBrand queryMallBrand) {
      Result<List<MallBrand>> result = newResult<List<MallBrand>>();
      try {
      queryMallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
        result.addDefaultModel("MallBrands",mallBrandDao.selectMallBrandByQuery(queryMallBrand));
      } catch(Exception e) {
        result.setSuccess(false);
      }
      return result;  
    }

    public Result<MallBrand> getMallBrandById(longid) {
      Result<MallBrand> result = new Result<MallBrand>();
      try {  
        result.addDefaultModel("MallBrand",mallBrandDao.selectMallBrandById(id));
      } catch(Exception e) {
        result.setSuccess(false);
      }
      return result;  
    }


   public Result<List<MallBrand>> getMallBrandsByPage(QueryMallBrand queryMallBrand) {

      Result<List<MallBrand>> result = newResult<List<MallBrand>>();
   queryMallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
        long totalItem =mallBrandDao.countByQuery(queryMallBrand);
      queryMallBrand.setTotalItem(totalItem);
      queryMallBrand.repaginate();
      if (totalItem > 0) {
   result.addDefaultModel(mallBrandDao.selectMallBrandByPage(queryMallBrand));
      } else {
      result.addDefaultModel(new ArrayList<MallBrand>());
      }
      result.setTotalItem(totalItem);
      result.setPageSize(queryMallBrand.getPageSize());
      result.setPage(queryMallBrand.getPage());

      return result;
    }

    public Result<Long> count(QueryMallBrand queryMallBrand) {
      Result<Long> result = new Result<Long>();
   queryMallBrand.setActive(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
      try {
         result.addDefaultModel(mallBrandDao.countByQuery(queryMallBrand));
      } catch(Exception e) {
        result.setSuccess(false);
      }
      return result;  
    }


   public Result disableEnableMallBrandList(List<MallBrand>brandList, boolean disable) {

      Result result = new Result();
      try {
        for (MallBrand brand : brandList) {
           if (disable) {
              brand.setStatus(DataStatusEnum.STATUS_DISABLE.getStatusValue());
           } else {
              brand.setStatus(DataStatusEnum.STATUS_ENABLE.getStatusValue());
           }
           mallBrandDao.updateMallBrandByIdModified(brand);
        }
      }catch(Exception e){
        result.setSuccess(false);
      }
      return result;
   }
 
   public Result deleteMallBrandList(List<MallBrand> brandList){
      Result result = new Result();
      try {
        for (MallBrand brand : brandList) {
        brand.setActive(DataActiveStatusEnum.STATUS_DELETED.getStatusValue());
           mallBrandDao.updateMallBrandByIdModified(brand);
        }
      }catch(Exception e){
        result.setSuccess(false);
      }
      return result;
   }
}

最后,不要忘记了,在spring-service.xml增加service的配置

<bean id="mallBrandService"class="com.pz.basic.mall.service.sys.impl.MallBrandServiceImpl"/>

后端代码之Controller层

我们提供给前端访问的数据接口,是通过Controller暴露出去的,前端通过HttpJSON的方式到后端获取需要的数据。在这一点上,我们使用SpringMVC的RestController能够获得比较好的支持。

/**
 * Copyright(c) 2004-2020pangzi
 *com.pz.basic.mall.controller.sys.MallBrandController.java
 */
package com.pz.basic.mall.controller.sys;

import com.pz.basic.mall.domain.base.Result;
import com.pz.basic.mall.domain.base.enums.DataStatusEnum;
import com.pz.basic.mall.domain.sys.MallBrand;
import com.pz.basic.mall.domain.sys.query.QueryMallBrand;
import com.pz.basic.mall.service.sys.MallBrandService;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


/**
 *
 * @author pangzi
 * @date 2020-06-2220:47:27
 *
 *
 */
@RestController
@RequestMapping("/brandManage")
public class MallBrandController {


    private MallBrandService mallBrandService;


    public void setMallBrandService(MallBrandService mallBrandService) {
        this.mallBrandService= mallBrandService;
    }



    /**
     * 新增品牌
     * @param mallBrand
     * @return
     */
   @RequestMapping("/addMallBrand")
    public Result<MallBrand> addMallBrand(@RequestBody MallBrand mallBrand){
        try{

            return   mallBrandService.addMallBrand(mallBrand);
        }catch(Exceptione){
           e.printStackTrace();
            return newResult(false);
        }
    }


    /**
     * 修改品牌
     * @param mallBrand
     * @return
     */
   @RequestMapping("/updateMallBrand")
    public Result updateMallBrand(@RequestBody MallBrand mallBrand){
        try{
            return mallBrandService.updateMallBrandById(mallBrand);
        }catch(Exceptione){
           e.printStackTrace();
            return newResult(false);
        }
    }

    /**
     * 启用品牌
     * @param mallBrand
     * @return
     */
   @RequestMapping("/enableMallBrand")
    public Result enableMallBrand(@RequestBody MallBrand mallBrand){
        try{
            MallBrandmodifiedData =new MallBrand ();
           modifiedData.setId(mallBrand.getId());
           modifiedData.setStatus(DataStatusEnum.STATUS_ENABLE.getStatusValue());
            return mallBrandService.updateMallBrandById(modifiedData);
        }catch(Exceptione){
            e.printStackTrace();
            return newResult(false);
        }
    }


    /**
     * 停用品牌
     * @param mallBrand
     * @return
     */
   @RequestMapping("/disableMallBrand")
    public Result disableMallBrand(@RequestBody MallBrand mallBrand){
        try{
            MallBrandmodifiedData =new MallBrand ();
           modifiedData.setId(mallBrand.getId());
           modifiedData.setStatus(DataStatusEnum.STATUS_DISABLE.getStatusValue());
            return  mallBrandService.updateMallBrandById(modifiedData);
        }catch(Exceptione){
           e.printStackTrace();
            return newResult(false);
        }
    }

    /**
     * 删除品牌
     * @param mallBrand
     * @return
     */
   @RequestMapping("/deleteMallBrand")
    public Result deleteMallBrand(@RequestBody MallBrand mallBrand){
        try{
            return mallBrandService.deleteMallBrandById(mallBrand);
        }catch(Exceptione){
           e.printStackTrace();
            return newResult(false);
        }
    }


    /**
     * 分页返回品牌列表
     * @paramqueryMallBrand
     * @return
     */
   @RequestMapping("/findByPage")
    public  Result<List<MallBrand>> findByPage(@RequestBody  QueryMallBrandqueryMallBrand){
        returnmallBrandService.getMallBrandsByPage(queryMallBrand);
    }


    /**
     * 修改品牌
     * @param brandList
     * @return
     */
   @RequestMapping("/disableMallBrandList")
    public Result disableMallBrandList(@RequestBody List<MallBrand> brandList){
        try{
            return  mallBrandService.disableEnableMallBrandList(brandList,true);
        }catch(Exceptione){
           e.printStackTrace();
            return newResult(false);
        }
    }

    /**
     * 修改品牌
     * @param brandList
     * @return
     */
    @RequestMapping("/enableMallBrandList")
    public Result enableMallBrandList(@RequestBody List<MallBrand> brandList){
        try{
            return mallBrandService.disableEnableMallBrandList(brandList,false);
        }catch(Exceptione){
           e.printStackTrace();
            return newResult(false);
        }
    }

    /**
     * 修改品牌
     * @param brandList
     * @return
     */
   @RequestMapping("/deleteMallBrandList")
    public Result deleteMallBrandList(@RequestBody List<MallBrand> brandList){
        try{
            return mallBrandService.deleteMallBrandList(brandList);
        }catch(Exceptione){
           e.printStackTrace();
            return newResult(false);
        }
    }

}

到目前为止,后端代码的编写告一段落。

前端代码之API层

后端接口的主要作用是为前端提供数据支撑,前端针对这些后端接口,可以做一些封装,然后交由需要调用的页面使用。为了保证功能的相对独立和后续前端代码的维护,我们需要对品牌管理相关的功能做一些封装——在api目录下建立basedataManage目录,然后建立basedataManage.js文件,之后基础数据相关的api我们都维护在这里。

根据页面后端提供的数据接口,我们需要封装如下封装。

export function fetchBrandList(query) {
  return request({
    url:'/brandManage/findByPage',
    method: 'post',
    data: query
  })
}

export function createBrand(data) {
  return request({
    url:'/brandManage/addMallBrand',
    method: 'post',
    data: data
  })
}

export function updateBrand(data) {
  return request({
    url: '/brandManage/updateMallBrand',
    method: 'post',
    data: data
  })
}

export function disableMallBrandList(data) {
  return request({
    url:'/brandManage/disableMallBrandList',
    method: 'post',
    data: data
  })
}

export function enableMallBrand(data) {
  return request({
    url:'/brandManage/enableMallBrand',
    method: 'post',
    data: data
  })
}

export function deleteMallBrand(data) {
  return request({
    url:'/brandManage/deleteMallBrand',
    method: 'post',
    data: data
  })
}

export function disableMallBrand(data) {
  return request({
    url:'/brandManage/disableMallBrand',
    method: 'post',
    data: data
  })
}

export function enableMallBrandList(data) {
  return request({
    url:'/brandManage/enableMallBrandList',
    method: 'post',
    data: data
  })
}

export function deleteMallBrandList(data) {
  return request({
    url:'/brandManage/deleteMallBrandList',
    method: 'post',
    data: data
  })
}

前端代码之组件引入

我们已经封装好了数据操作相关的API了,那么接下来的事情,自然是引入我们需要的组件了。在brand-management.vue文件中,建立如下标记。

<script>
import { fetchBrandList, createBrand, updateBrand,disableMallBrand, enableMallBrand, deleteMallBrand, disableMallBrandList,enableMallBrandList, deleteMallBrandList } from'@/api/basedataManage/basedataManage'
import Pagination from '@/components/Pagination' // secondarypackage based on el-pagination
export default {
  components: { Pagination},
  data() {
    return {

    }
  },
  created() {

  },
  methods: {
  }
}
</script>

其中import的就是我们封装的API以及Pagination组件了。注意这个结构,components暴露出来的就是组件在页面具体使用的名称。

data()函数的返回值,就是页面中需要的数据。created函数,会在页面创建时执行,如果有一些需要初始化的事情,可以交由它进行处理。

methods中我们可以定义页面所需要的函数。

前端代码之列表数据

我们怎样才能实现品牌列表的功能呢?自然是需要前端页面来调用后端接口来完成了。由于我们还要支持品牌名的模糊查询,所以我们还要为此定义一个数据结构用于存放查询条件。定义一个数组用于存放返回的数据。

// table数据集合
list: null,
listQuery: {
        brandName: '',
        firsChar: '',
        page: 1,
        pageSize: 10
      }

注意噢,以json的格式放在data()函数中,作为返回值的一部分返回就好。同时在methods区域编写获取列表的函数:

// 列表方法查询
    getList() {
      this.listLoading =true
     fetchBrandList(this.listQuery).then(response => {
        this.list =response.model
        this.total =response.totalItem
        // Just to simulatethe time of the request
        setTimeout(()=> {
          this.listLoading= false
        }, 1.5 * 1000)
      })
    }

为了方便页面初始化的时候有数据展示,我们可以在created函数中调用它。

created() {
    // 列表查询
    this.getList()
  }

至于列表数据的展示,当然是的el-table去展示了。

手把手教你搭建一个完整的电商系统之品牌管理

前端代码之新增/编辑

新增和修改品牌的功能主要是由el-dialog组件来实现的,通过表单,隐藏和展示的方式来完成新增/编辑工作。为此我们同样需要定义数据来处理这些页面逻辑。

temp: {
        id: undefined,
        // 品牌名称
        brandName: '',
        // 品牌首字母
        firsChar: '',
        logo: '',
        imageUrl: ''
      },
      dialogStatus: '',
      textMap: {
        update: '编辑品牌',
        create: '新增品牌'
      },
      // 弹框是否显示
      dialogFormVisible:false,

至于页面数据的前端校验,我们可以使用定义Rule规则的方式完成。

rules: {
        brandName: [{required: true, message: '请输入品牌名称',trigger: 'change' }],
        firstChar: [{required: true, message: '请输入品牌首字母(英文大写)', trigger: 'change' }],
        logo: [{ required:true, message: '请上传品牌logo', trigger:'change' }]
      }

注意噢,每一种规则都是一个数组,一个规则是支持同时存在多条的噢。

至于新增/编辑弹出页面动作,则是通过定义函数,通过button的事件触发来完成的。

resetTemp() {
      this.temp = {
        id: undefined,
        // 品牌名称
        brandName: '',
        // 品牌首字母
        firstChar: '',
        logo: ''
      }
      this.dialogVisible =false
      if(this.$refs.upload !== null && undefined !== this.$refs.upload) {
       this.$refs.upload.clearFiles()
      }
     console.log(this.$refs.upload)
    },
    // 新增
    addBrand() {
      this.resetTemp()
      this.dialogStatus ='create'
     this.dialogFormVisible = true
      this.$nextTick(()=> {
       this.$refs['dataForm'].clearValidate()
      })
    },
至于数据持久,同样也是button绑定函数的方式来完成。
// 更新保存方法
    updateData() {
      this.$refs['dataForm'].validate((valid)=> {
        if (valid) {
          const tempData =Object.assign({}, this.temp)
         updateBrand(tempData).then(() => {
            const index =this.list.findIndex(v => v.id === this.temp.id)
           this.list.splice(index, 1, this.temp)
           this.dialogFormVisible = false
            this.$notify({
              title:'Success',
              message:'Update Successfully',
              type:'success',
              duration:2000
            })
          })
        }
      })
    },
    // 创建保存方法
    createData() {
     this.$refs['dataForm'].validate((valid) => {
        if (valid) {
         createBrand(this.temp).then((res) => {
            this.temp.id =res.model.id
           this.list.unshift(this.temp)
           this.dialogFormVisible = false
            this.$notify({
              title:'Success',
              message:'Created Successfully',
              type:'success',
              duration:2000
            })
          })
        }
      })
    },

 

前端代码之其它功能

前端的停用/启用/删除功能,大家可以看下,篇幅有限,就不一一例举了——最主要的是你不能懒惰,敲代码的事情,必须自己搞了。给你一些例子,自己去完善!

 

自己去完善!

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

手把手教你搭建一个完整的电商系统之品牌管理

到此为止,我们项目的开发框架搭建完毕。
  如学习过程中遇到疑难杂症,自己实在搞不定,可以加我的微信,帮你解决。
   手把手教你搭建一个完整的电商系统之品牌管理