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

时间:2024-11-15 11:59:57

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

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

需求整理

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

 

 

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

数据库设计

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

前端主要组件

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

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

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

  1. <template>
  2. <div>
  3. <el-cardclass="filter-container" shadow="never">
  4. <div>
  5. <el-formref="listQuery" :model="listQuery" :inline="true">
  6. <el-form-itemlabel="品牌名称:"prop="brandName">
  7. <el-inputv-model="" placeholder="请输入品牌名称" clearable />
  8. </el-form-item>
  9. <el-form-item>
  10. <el-buttontype="primary" icon="el-icon-edit"@click="addBrand()">新增</el-button>
  11. <el-buttontype="primary" icon="el-icon-search"@click="fetchData()">查询</el-button>
  12. <el-buttonicon="el-icon-s-tools" @click="resetForm('listQuery')">重置</el-button>
  13. <el-buttontype="primary" @click="enbleDataList()">全部启用</el-button>
  14. <el-buttontype="primary" @click="disableDataList()">全部停用</el-button>
  15. <el-buttontype="danger" @click="deleteDataList()">全部删除</el-button>
  16. </el-form-item>
  17. </el-form>
  18. </div>
  19. </el-card>
  20. <divstyle="height:20px;" />
  21. <divclass="table-container">
  22. <el-table
  23. ref="multipleTable"
  24. v-loading="listLoading"
  25. :data="list"
  26. style="width:100%"
  27. border
  28. @selection-change="handleSelectionChange"
  29. >
  30. <el-table-column type="selection" min-width="10%"/>
  31. <el-table-column label="编号" min-width="10%">
  32. <templateslot-scope="scope">{{ }}</template>
  33. </el-table-column>
  34. <el-table-column label="品牌名称">
  35. <templateslot-scope="scope">{{ }}</template>
  36. </el-table-column>
  37. <el-table-column label="品牌首字母" min-width="10%">
  38. <templateslot-scope="scope">{{ }}</template>
  39. </el-table-column>
  40. <el-table-columnlabel="品牌logo"align="center">
  41. <templateslot-scope="scope"><img style="width: 200px; height:200px" :src=""alt=""></template>
  42. </el-table-column>
  43. <el-table-column label="状态" min-width="10%">
  44. <templateslot-scope="scope">{{ == 1 ? "启用" : "停用"}}</template>
  45. </el-table-column>
  46. <el-table-column label="操作" width="220">
  47. <templateslot-scope="scope">
  48. <el-button
  49. type="primary"
  50. size="mini"
  51. @click="handleUpdate()"
  52. >编辑
  53. </el-button>
  54. <el-button
  55. v-if="==1"
  56. type="primary"
  57. size="mini"
  58. @click="handleDisable(scope.$index,)"
  59. >停用
  60. </el-button>
  61. <el-button
  62. v-if="==0"
  63. type="primary"
  64. size="mini"
  65. @click="handleEnable(scope.$index, )"
  66. >启用
  67. </el-button>
  68. <el-button
  69. size="mini"
  70. type="danger"
  71. @click="handleDelete(scope.$index, )"
  72. >删除
  73. </el-button>
  74. </template>
  75. </el-table-column>
  76. </el-table>
  77. </div>
  78. <paginationv-show="total>0" :total="total":="":="" @pagination="getList"/>
  79. <!-- 新增/编辑弹框 -->
  80. <el-dialog:title="textMap[dialogStatus]":="dialogFormVisible">
  81. <el-formref="dataForm" :rules="rules" :model="temp"label-position="right" label-width="100px"style="width: 500px; margin-left:50px;">
  82. <el-form-itemlabel="品牌名称:"prop="brandName">
  83. <el-inputv-model="" />
  84. </el-form-item>
  85. <el-form-itemlabel="品牌首字母:"prop="firstChar">
  86. <el-inputv-model="" maxlength="1"oninput="value=(/[^A-Z]/g,'');" alt="英文大写" />
  87. </el-form-item>
  88. <el-form-itemv-show="dialogVisible" label="品牌logo:" prop="logo"style="margin-top:15px;">
  89. <imgstyle="width: 200px; height: 200px" :src=""alt="">
  90. </el-form-item>
  91. <el-form-item>
  92. <el-upload
  93. ref="upload"
  94. :file-list="imgList"
  95. action="http://127.0.0.1:9201//upload/uploadFile?moudle=brand"
  96. list-type="picture-card"
  97. :on-preview="handlePictureCardPreview"
  98. :on-success="handleSuccess"
  99. :limit="1"
  100. accept="image/jpeg,image/gif,image/png,image/bmp"
  101. >
  102. <iclass="el-icon-plus" />
  103. </el-upload>
  104. </el-form-item>
  105. </el-form>
  106. <divslot="footer">
  107. <el-button@click="dialogFormVisible = false">
  108. 取消
  109. </el-button>
  110. <el-buttontype="primary"@click="dialogStatus==='create'?createData():updateData()">
  111. 确定
  112. </el-button>
  113. </div>
  114. </el-dialog>
  115. </div>
  116. </template>
  117. <style scoped>
  118. #brandManagementDiv /deep/ .el-form-item--mini.el-form-item__label {
  119. width: 100px !important;
  120. }
  121. </style>

后端代码之实体层

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

  1. /**
  2. * Copyright(c) 2004-2020pangzi
  3. *
  4. */
  5. package ;
  6. import .;
  7. import ;
  8. /**
  9. *
  10. * @author pangzi
  11. * @date 2020-06-2211:28:19
  12. *
  13. *
  14. */
  15. public class BaseDO implements Serializable {
  16. private static final longserialVersionUID = 1L;
  17. /**
  18. * 如果字段值为null将不包含在toString中
  19. */
  20. @Override
  21. public String toString(){
  22. (this);
  23. }
  24. }
  25. package ;
  26. import ;
  27. import ;
  28. /**
  29. *
  30. * @author pangzi
  31. * @date 2020-06-2718:09:41
  32. *
  33. */
  34. public class MallBrand extends BaseDO {
  35. /**主键**/
  36. private Long id;
  37. /**品牌名**/
  38. private String brandName;
  39. /**logo图片地址**/
  40. private String logo;
  41. /**品牌首字母**/
  42. private String firstChar;
  43. /**状态1可用0不可用**/
  44. private Integer status;
  45. /**记录状态1有效0删除**/
  46. private Integer active;
  47. /**创建人**/
  48. private StringcreateUser;
  49. /**修改人**/
  50. private StringmodifyUser;
  51. /**创建时间**/
  52. private Date created;
  53. /**修改时间**/
  54. private Date modified;
  55. //getter setter省略
  56. }
  1. package ;
  2. import ;
  3. import ;
  4. /**
  5. *
  6. * @author pangzi
  7. * @date 2020-06-2718:09:41
  8. *
  9. *
  10. */
  11. public class QueryMallBrand extends PaginateBaseDO {
  12. /**主键**/
  13. private Long id;
  14. /**品牌名**/
  15. private String brandName;
  16. /**logo图片地址**/
  17. private String logo;
  18. /**品牌首字母**/
  19. private String firstChar;
  20. /**状态1可用0不可用**/
  21. private Integer status;
  22. /**记录状态1有效0删除**/
  23. private Integer active;
  24. /**创建人**/
  25. private StringcreateUser;
  26. /**修改人**/
  27. private StringmodifyUser;
  28. /**创建时间**/
  29. private Date created;
  30. /**修改时间**/
  31. private Date modified;
  32. /**支持品牌名称模糊查询**/
  33. private String brandNameLike;
  34. }

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

  1. package ;
  2. import ;
  3. /**
  4. *
  5. * @author pangzi
  6. * @date 2020-06-2211:28:19
  7. *
  8. *
  9. */
  10. public class PaginateBaseDO implements Serializable {
  11. /**
  12. * 默认每页的记录数量
  13. */
  14. public static finalint PAGESIZE_DEFAULT = 20;
  15. /**
  16. * 每页大小
  17. */
  18. private long pageSize;
  19. /**
  20. * 当前页。第一页是1
  21. */
  22. private long page;
  23. /**
  24. * 总记录数
  25. */
  26. private long totalItem;
  27. /**
  28. * 总页数
  29. */
  30. private long totalPage;
  31. /**
  32. * 分页后的记录开始的地方
  33. * 第一条记录是1
  34. */
  35. private long startRow;
  36. /**
  37. * 分页后的记录结束的地方
  38. */
  39. private long endRow;
  40. /**排序字段**/
  41. private String orderField;
  42. /**升序 还是 降序,true为升序,false为降序*/
  43. private Boolean isAsc;
  44. /**
  45. * 默认构造方法
  46. */
  47. public PaginateBaseDO() {
  48. repaginate();
  49. }
  50. /**
  51. * 带当前页和页大小的构造方法
  52. * @param page 当前页
  53. * @param pageSize 页大小
  54. */
  55. public PaginateBaseDO(long page, long pageSize) {
  56. this.page = page;
  57. this.pageSize =pageSize;
  58. repaginate();
  59. }
  60. public void setStartRow(long startRow) {
  61. this.startRow =startRow;
  62. }
  63. public void setEndRow(long endRow) {
  64. this.endRow =endRow;
  65. }
  66. /**
  67. * 表示是不是第一页
  68. * @return true 是; false 不是
  69. */
  70. public boolean isFirstPage(){
  71. return page <=1;
  72. }
  73. public boolean isMiddlePage() {
  74. return!(isFirstPage() || isLastPage());
  75. }
  76. public boolean isLastPage() {
  77. return page >=totalPage;
  78. }
  79. public boolean isNextPageAvailable() {
  80. return !isLastPage();
  81. }
  82. public boolean isPreviousPageAvailable() {
  83. return!isFirstPage();
  84. }
  85. /**
  86. * 下一页号
  87. * @return 取得下一页号
  88. */
  89. public long getNextPage() {
  90. if(isLastPage()) {
  91. returntotalItem;
  92. } else {
  93. return page+1;
  94. }
  95. }
  96. public long getPreviousPage() {
  97. if(isFirstPage()){
  98. return 1;
  99. } else {
  100. return page -1;
  101. }
  102. }
  103. /**
  104. * Method getPageSizereturns the pageSize of this PaginatedArrayList object.
  105. *
  106. * 每页大小
  107. *
  108. * @return thepageSize (type int) of this PaginatedArrayList object.
  109. */
  110. public long getPageSize() {
  111. return pageSize;
  112. }
  113. /**
  114. * Method setPageSizesets the pageSize of this PaginatedArrayList object.
  115. *
  116. * 每页大小
  117. *
  118. * @param pageSize thepageSize of this PaginatedArrayList object.
  119. *
  120. */
  121. public void setPageSize(long pageSize) {
  122. this.pageSize =pageSize;
  123. repaginate();
  124. }
  125. /**
  126. * Method getpagereturns the page of this PaginatedArrayList object.
  127. *
  128. * 当前页。第一页是1
  129. *
  130. * @return the page(type int) of this PaginatedArrayList object.
  131. */
  132. public long getPage(){
  133. return page;
  134. }
  135. /**
  136. * Method setpage setsthe page of this PaginatedArrayList object.
  137. *
  138. * 当前页。第一页是1
  139. *
  140. * @param page thepage of this PaginatedArrayList object.
  141. *
  142. */
  143. public void setPage(long page) {
  144. this.page = page;
  145. repaginate();
  146. }
  147. /**
  148. * Method getTotalItemreturns the totalItem of this PaginatedArrayList object.
  149. *
  150. * 总记录数
  151. *
  152. * @return thetotalItem (type int) of this PaginatedArrayList object.
  153. */
  154. public long getTotalItem() {
  155. return totalItem;
  156. }
  157. /**
  158. * Method setTotalItemsets the totalItem of this PaginatedArrayList object.
  159. *
  160. * 总记录数
  161. *
  162. * @param totalItemthe totalItem of this PaginatedArrayList object.
  163. *
  164. */
  165. public void setTotalItem(long totalItem) {
  166. this.totalItem =totalItem;
  167. if( this.totalItem<= 0){
  168. totalPage = 0;
  169. page = 1;
  170. startRow = 0;
  171. }
  172. repaginate();
  173. }
  174. /**
  175. * Method getTotalPagereturns the totalPage of this PaginatedArrayList object.
  176. *
  177. * 总页数
  178. *
  179. * @return thetotalPage (type int) of this PaginatedArrayList object.
  180. */
  181. public long getTotalPage() {
  182. return totalPage;
  183. }
  184. /**
  185. * Method getStartRowreturns the startRow of this PaginatedArrayList object.
  186. *
  187. * 分页后的记录开始的地方
  188. *
  189. * @return the startRow(type int) of this PaginatedArrayList object.
  190. */
  191. public long getStartRow() {
  192. if (startRow >0) {
  193. returnstartRow;
  194. }
  195. if (page <= 0){
  196. page = 1;
  197. }
  198. return (page - 1)* pageSize;
  199. }
  200. /**
  201. * Method getEndRowreturns the endRow of this PaginatedArrayList object.
  202. *
  203. * 分页后的记录结束的地方
  204. *
  205. * @return the endRow(type int) of this PaginatedArrayList object.
  206. */
  207. public long getEndRow() {
  208. if (endRow > 0){
  209. return endRow;
  210. }
  211. return page *pageSize;
  212. }
  213. public String getOrderField() {
  214. return orderField;
  215. }
  216. public void setOrderField(String orderField) {
  217. this.orderField =orderField;
  218. }
  219. public Boolean getIsAsc() {
  220. return isAsc;
  221. }
  222. public void setIsAsc(Boolean isAsc) {
  223. this.isAsc = isAsc;
  224. }
  225. /**
  226. * Method repaginate...
  227. */
  228. public void repaginate() {
  229. if (pageSize <1) { //防止程序偷懒,list和分页的混合使用
  230. pageSize =PAGESIZE_DEFAULT;
  231. }
  232. if (page < 1) {
  233. page = 1;//恢复到第一页
  234. }
  235. if (totalItem >0) {
  236. totalPage =totalItem / pageSize + (totalItem % pageSize > 0 ? 1 : 0);
  237. if(page >totalPage) {
  238. page =totalPage; //最大页
  239. }
  240. endRow = page* pageSize;
  241. startRow =(page - 1) * pageSize;
  242. if(endRow>totalItem) {
  243. endRow =totalItem;
  244. }
  245. }
  246. }
  247. }

后端代码之数据持久层

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

  1. /**
  2. * Copyright(c) 2004-2020pangzi
  3. *
  4. */
  5. package ;
  6. import ;
  7. import ;
  8. import ;
  9. /**
  10. *
  11. * @author pangzi
  12. * @date 2020-06-2610:56:01
  13. */
  14. public interface MallBrandDao {
  15. /**
  16. * 根据条件查询总数
  17. * @param query
  18. * @return
  19. */
  20. long countByQuery(QueryMallBrand query);
  21. /**
  22. * 根据条件删除记录
  23. * @param query
  24. * @return
  25. */
  26. int deleteMallBrandByQuery(QueryMallBrand query);
  27. /**
  28. * 根据ID删除记录
  29. * @param id
  30. * @return
  31. */
  32. int deleteMallBrandById(long id);
  33. /**
  34. * 新增记录
  35. * @param record
  36. * @return
  37. */
  38. long insertMallBrand(MallBrand record);
  39. /**
  40. * 新增记录 注意:有值的记录才新增
  41. * @param record
  42. * @return
  43. */
  44. long insertMallBrandModified(MallBrand record);
  45. /**
  46. * 根据查询条件返回列表
  47. * @param query
  48. * @return
  49. */
  50. List<MallBrand> selectMallBrandByQuery(QueryMallBrand query);
  51. /**
  52. * 根据查询条件返回列表
  53. * @param query
  54. * @return
  55. */
  56. List<MallBrand> selectMallBrandByPage(QueryMallBrand query);
  57. /**
  58. * 根据ID查询对象
  59. * @param id
  60. * @return
  61. */
  62. MallBrand selectMallBrandById(long id);
  63. /**
  64. * 根据id修改记录 注意:有值的字段才更新
  65. * @param record
  66. * @return
  67. */
  68. int updateMallBrandByIdModified(MallBrandrecord);
  69. }

对应的mapper文件.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-////DTD Mapper3.0//EN" "/dtd/" >
  3. <mapper namespace="">
  4. <resultMap id="ResultMap" type="MallBrand">
  5. <id property="id" column="id"/>
  6. <id property="brandName" column="brand_name"/>
  7. <id property="logo" column="logo"/>
  8. <id property="firstChar" column="first_char"/>
  9. <id property="status" column="status"/>
  10. <id property="active" column="active"/>
  11. <id property="createUser" column="create_user"/>
  12. <id property="modifyUser" column="modify_user"/>
  13. <id property="created" column="created"/>
  14. <id property="modified" column="modified"/>
  15. </resultMap>
  16. <sql id="ALL_TABLE_COLOUM">
  17. id,
  18. brand_name,
  19. logo,
  20. first_char,
  21. status,
  22. active,
  23. create_user,
  24. modify_user,
  25. created,
  26. modified
  27. </sql>
  28. <sql id="Query_Where_Clause" >
  29. <where >
  30. 1=1
  31. <if test="id != null and id != ''">
  32. and id = #{id}
  33. </if>
  34. <if test="brandName != null and brandName != ''">
  35. and brand_name = #{brandName}
  36. </if>
  37. <if test="logo != null and logo != ''">
  38. and logo = #{logo}
  39. </if>
  40. <if test="firstChar != null and firstChar != ''">
  41. and first_char = #{firstChar}
  42. </if>
  43. <if test="status!= null and status != ''">
  44. and status = #{status}
  45. </if>
  46. <if test="active != null and active != ''">
  47. and active = #{active}
  48. </if>
  49. <if test="createUser != null and createUser != ''">
  50. and create_user = #{createUser}
  51. </if>
  52. <if test="modifyUser != null and modifyUser != ''">
  53. and modify_user = #{modifyUser}
  54. </if>
  55. <if test="created != null and created != ''">
  56. and created = #{created}
  57. </if>
  58. <if test="modified !=null and modified != ''">
  59. and modified = #{modified}
  60. </if>
  61. <if test="brandNameLike != null and brandNameLike != ''">
  62. and brand_name likeconcat(#{brandNameLike},'%')
  63. </if>
  64. </where>
  65. </sql>
  66. <select id="selectMallBrandByQuery" resultMap="ResultMap"parameterType="QueryMallBrand" >
  67. select
  68. <include refid="ALL_TABLE_COLOUM" />
  69. from mall_brand
  70. <if test="page!= null" >
  71. <include refid="Query_Where_Clause" />
  72. </if>
  73. </select>
  74. <select id="selectMallBrandByPage" resultMap="ResultMap"parameterType="QueryMallBrand" >
  75. select
  76. <include refid="ALL_TABLE_COLOUM" />
  77. from mall_brand
  78. <iftest="page != null" >
  79. <includeref />
  80. </if>
  81. LIMIT#{startRow},#{pageSize}
  82. </select>
  83. <select id="selectMallBrandById" resultMap="ResultMap"parameterType="" >
  84. select
  85. <include refid="ALL_TABLE_COLOUM" />
  86. from mall_brand
  87. where id = #{id}
  88. </select>
  89. <delete id="deleteMallBrandById" parameterType="">
  90. delete from mall_brand
  91. where id = #{id}
  92. </delete>
  93. <delete id="deleteMallBrandByQuery" parameterType= "QueryMallBrand">
  94. delete from mall_brand
  95. <if test="page!= null" >
  96. <include refid="Query_Where_Clause" />
  97. </if>
  98. </delete>
  99. <insert id="insertMallBrand" parameterType="MallBrand" >
  100. INSERT INTO
  101. mall_brand(id,brand_name,logo,first_char,status,active,create_user,modify_user,created,modified)
  102. VALUES(#{id},#{brandName},#{logo},#{firstChar},#{status},#{active},#{createUser},#{modifyUser},#{created},#{modified})
  103. <select Key resultType="long" keyProperty="id">
  104. SELECT@@IDENTITY AS ID
  105. </selectKey>
  106. </insert>
  107. <insert id="insertMallBrandModified" parameterType="MallBrand" >
  108. insert into mall_brand
  109. <trimprefix="(" suffix=")" suffixOverrides="," >
  110. <if test="id != null" >
  111. id,
  112. </if>
  113. <if test="brandName != null" >
  114. brand_name,
  115. </if>
  116. <iftest="logo != null" >
  117. logo,
  118. </if>
  119. <if test="firstChar != null" >
  120. first_char,
  121. </if>
  122. <if test="status != null" >
  123. status,
  124. </if>
  125. <if test="active != null" >
  126. active,
  127. </if>
  128. <if test="createUser != null" >
  129. create_user,
  130. </if>
  131. <if test="modifyUser != null" >
  132. modify_user,
  133. </if>
  134. <if test="created != null" >
  135. created,
  136. </if>
  137. <if test="modified != null" >
  138. modified,
  139. </if>
  140. </trim>
  141. <trim prefix="values (" suffix=")" suffixOverrides=",">
  142. <if test="id !=null" >
  143. #{id},
  144. </if>
  145. <iftest="brandName != null" >
  146. #{brandName},
  147. </if>
  148. <if test="logo != null">
  149. #{logo},
  150. </if>
  151. <iftest="firstChar != null" >
  152. #{firstChar},
  153. </if>
  154. <iftest="status != null" >
  155. #{status},
  156. </if>
  157. <iftest="active != null" >
  158. #{active},
  159. </if>
  160. <iftest="createUser != null" >
  161. #{createUser},
  162. </if>
  163. <iftest="modifyUser != null" >
  164. #{modifyUser},
  165. </if>
  166. <if test="created!= null" >
  167. now(),
  168. </if>
  169. <iftest="modified != null" >
  170. now(),
  171. </if>
  172. </trim>
  173. <selectKey resultType="long" keyProperty="id">
  174. SELECT@@IDENTITY AS ID
  175. </selectKey>
  176. </insert>
  177. <select id="countByQuery" parameterType="QueryMallBrand" resultType="" >
  178. select count(*) frommall_brand
  179. <if test="page!= null" >
  180. <include refid="Query_Where_Clause"/>
  181. </if>
  182. </select>
  183. <update id="updateMallBrandByIdModified" parameterType="MallBrand">
  184. update mall_brand
  185. <set >
  186. <iftest="brandName != null" >
  187. brand_name = #{brandName},
  188. </if>
  189. <iftest="logo != null" >
  190. logo= #{logo},
  191. </if>
  192. <iftest="firstChar != null" >
  193. first_char = #{firstChar},
  194. </if>
  195. <iftest="status != null" >
  196. status = #{status},
  197. </if>
  198. <iftest="active != null" >
  199. active = #{active},
  200. </if>
  201. <iftest="createUser != null" >
  202. create_user = #{createUser},
  203. </if>
  204. <iftest="modifyUser != null" >
  205. modify_user = #{modifyUser},
  206. </if>
  207. <iftest="created != null" >
  208. created = #{created},
  209. </if>
  210. <iftest="modified != null" >
  211. modified=now(),
  212. </if>
  213. </set>
  214. where id = #{id}
  215. </update>
  216. </mapper>

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

后端代码之service层

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

  1. /**
  2. * Copyright(c) 2004-2020 pangzi
  3. *
  4. */
  5. package ;
  6. import ;
  7. import ;
  8. import ;
  9. import ;
  10. /**
  11. * service层,组装外部接口和 本地业务,为本业务 或者其他业务提供服务,统一返回Result
  12. * 通过判断调用是否成功
  13. * 此类中新增业务接口设计(接口命令,入参数据,返回值)要能尽量完整的表达业务 含义
  14. * @author pangzi
  15. * @date 2020-06-26 11:20:40
  16. */
  17. public interface MallBrandService {
  18. /**
  19. * 新增 mallBrand
  20. * 返回result,通过()判断服务调用是否成功
  21. * 通过()得到新增mallBrand
  22. * @param mallBrand
  23. * @return
  24. */
  25. public Result<MallBrand> addMallBrand(MallBrand mallBrand) ;
  26. /**
  27. * 按照主键id更新mallBrand,请重新new MallBrand 的更新对象,设置要更新的字段
  28. * 返回result,通过()判断更新是否成功
  29. * @param mallBrand
  30. * @return
  31. */
  32. public Result updateMallBrandById(MallBrandmallBrand);
  33. /**
  34. * 按照主键id 删除 记录
  35. * 返回result,通过()判断删除是否成功
  36. * @return
  37. */
  38. public Result deleteMallBrandById(MallBrandmallBrand);
  39. /**
  40. * 查询列表,此接口不包含分页查询
  41. * 返回result,通过()判断服务调用是否成功
  42. * 通过()得到列表信息
  43. * @param queryMallBrand
  44. * @return
  45. */
  46. public Result<List<MallBrand>> getMallBrandsByQuery(QueryMallBrand queryMallBrand);
  47. /**
  48. * 通过主键id查询MallBrand
  49. * 返回result,通过()判断服务调用是否成功
  50. * 通过()得到查询的单条mallBrand信息
  51. * @param id
  52. * @return
  53. */
  54. public Result<MallBrand> getMallBrandById(long id);
  55. /**
  56. * 查询列表,包含分页查询
  57. * 查询分页信息,请设置
  58. * (设置当前页数)
  59. *(设置当前页面数据行数)
  60. * 返回result,通过()判断服务调用是否成功
  61. * 通过()返回结果总数
  62. * 通过()得到查询的单页列表信息
  63. * @param queryMallBrand
  64. * @return
  65. */
  66. public Result<List<MallBrand>> getMallBrandsByPage(QueryMallBrand queryMallBrand);
  67. /**
  68. * 查询总数
  69. * @param queryMallBrand
  70. * @return
  71. */
  72. public Result<Long> count(QueryMallBrand queryMallBrand);
  73. /**
  74. * 停用启用品牌列表
  75. * 返回result,通过()判断服务调用是否成功
  76. * 通过()得到列表信息
  77. * @param brandList
  78. * @param disable true 停用 false 启用
  79. * @return
  80. */
  81. public Result disableEnableMallBrandList(List<MallBrand>brandList, boolean disable);
  82. /**
  83. * 逻辑删除品牌列表
  84. * 返回result,通过()判断服务调用是否成功
  85. * 通过()得到列表信息
  86. * @param brandList
  87. * @return
  88. */
  89. public Result deleteMallBrandList(List<MallBrand>brandList);
  90. }
  1. /**
  2. * Copyright(c) 2004-2020 pangzi
  3. *
  4. */
  5. package ;
  6. import ;
  7. import ;
  8. import ;
  9. import ;
  10. import ;
  11. import ;
  12. import ;
  13. import ;
  14. import ;
  15. /**
  16. *
  17. * @author pangzi
  18. * @date 2020-06-26 11:25:00
  19. */
  20. public class MallBrandServiceImpl implements MallBrandService {
  21. private MallBrandDao mallBrandDao;
  22. public void setMallBrandDao(MallBrandDao mallBrandDao) {
  23. this.mallBrandDao =mallBrandDao;
  24. }
  25. public Result<MallBrand> addMallBrand(MallBrand mallBrand) {
  26. Result<MallBrand> result = new Result<MallBrand>();
  27. try {
  28. QueryMallBrand query = new QueryMallBrand();
  29. (());
  30. long count = (query);
  31. if(count>0){
  32. (false);
  33. ("品牌名已存在");
  34. return result;
  35. }
  36. (DataStatusEnum.STATUS_ENABLE.getStatusValue());
  37. (DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
  38. (mallBrand);
  39. (mallBrand);
  40. } catch(Exception e) {
  41. (false);
  42. }
  43. return result;
  44. }
  45. public Result updateMallBrandById(MallBrandmallBrand) {
  46. Result result = new Result();
  47. try {
  48. int count=(mallBrand);
  49. if(count>0){
  50. (true);
  51. }
  52. } catch(Exception e) {
  53. (false);
  54. }
  55. return result;
  56. }
  57. public Result deleteMallBrandById(MallBrandmallBrand) {
  58. Result result = new Result();
  59. try {
  60. int count=0;
  61. MallBrand modifiedMallBrand = new MallBrand();
  62. (());
  63. (DataActiveStatusEnum.STATUS_DELETED.getStatusValue());
  64. count=(modifiedMallBrand);
  65. if(count>0){
  66. (true);
  67. }
  68. } catch(Exception e) {
  69. (false);
  70. }
  71. return result;
  72. }
  73. public Result<List<MallBrand>> getMallBrandsByQuery(QueryMallBrand queryMallBrand) {
  74. Result<List<MallBrand>> result = newResult<List<MallBrand>>();
  75. try {
  76. (DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
  77. ("MallBrands",(queryMallBrand));
  78. } catch(Exception e) {
  79. (false);
  80. }
  81. return result;
  82. }
  83. public Result<MallBrand> getMallBrandById(longid) {
  84. Result<MallBrand> result = new Result<MallBrand>();
  85. try {
  86. ("MallBrand",(id));
  87. } catch(Exception e) {
  88. (false);
  89. }
  90. return result;
  91. }
  92. public Result<List<MallBrand>> getMallBrandsByPage(QueryMallBrand queryMallBrand) {
  93. Result<List<MallBrand>> result = newResult<List<MallBrand>>();
  94. (DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
  95. long totalItem =(queryMallBrand);
  96. (totalItem);
  97. ();
  98. if (totalItem > 0) {
  99. ((queryMallBrand));
  100. } else {
  101. (new ArrayList<MallBrand>());
  102. }
  103. (totalItem);
  104. (());
  105. (());
  106. return result;
  107. }
  108. public Result<Long> count(QueryMallBrand queryMallBrand) {
  109. Result<Long> result = new Result<Long>();
  110. (DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
  111. try {
  112. ((queryMallBrand));
  113. } catch(Exception e) {
  114. (false);
  115. }
  116. return result;
  117. }
  118. public Result disableEnableMallBrandList(List<MallBrand>brandList, boolean disable) {
  119. Result result = new Result();
  120. try {
  121. for (MallBrand brand : brandList) {
  122. if (disable) {
  123. (DataStatusEnum.STATUS_DISABLE.getStatusValue());
  124. } else {
  125. (DataStatusEnum.STATUS_ENABLE.getStatusValue());
  126. }
  127. (brand);
  128. }
  129. }catch(Exception e){
  130. (false);
  131. }
  132. return result;
  133. }
  134. public Result deleteMallBrandList(List<MallBrand> brandList){
  135. Result result = new Result();
  136. try {
  137. for (MallBrand brand : brandList) {
  138. (DataActiveStatusEnum.STATUS_DELETED.getStatusValue());
  139. (brand);
  140. }
  141. }catch(Exception e){
  142. (false);
  143. }
  144. return result;
  145. }
  146. }

最后,不要忘记了,在增加service的配置

<bean id="mallBrandService"class=""/>

后端代码之Controller层

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

  1. /**
  2. * Copyright(c) 2004-2020pangzi
  3. *
  4. */
  5. package ;
  6. import ;
  7. import ;
  8. import ;
  9. import ;
  10. import ;
  11. import .annotation.RequestBody;
  12. import .annotation.RequestMapping;
  13. import .annotation.RestController;
  14. import ;
  15. /**
  16. *
  17. * @author pangzi
  18. * @date 2020-06-2220:47:27
  19. *
  20. *
  21. */
  22. @RestController
  23. @RequestMapping("/brandManage")
  24. public class MallBrandController {
  25. private MallBrandService mallBrandService;
  26. public void setMallBrandService(MallBrandService mallBrandService) {
  27. this.mallBrandService= mallBrandService;
  28. }
  29. /**
  30. * 新增品牌
  31. * @param mallBrand
  32. * @return
  33. */
  34. @RequestMapping("/addMallBrand")
  35. public Result<MallBrand> addMallBrand(@RequestBody MallBrand mallBrand){
  36. try{
  37. return (mallBrand);
  38. }catch(Exceptione){
  39. ();
  40. return newResult(false);
  41. }
  42. }
  43. /**
  44. * 修改品牌
  45. * @param mallBrand
  46. * @return
  47. */
  48. @RequestMapping("/updateMallBrand")
  49. public Result updateMallBrand(@RequestBody MallBrand mallBrand){
  50. try{
  51. return (mallBrand);
  52. }catch(Exceptione){
  53. ();
  54. return newResult(false);
  55. }
  56. }
  57. /**
  58. * 启用品牌
  59. * @param mallBrand
  60. * @return
  61. */
  62. @RequestMapping("/enableMallBrand")
  63. public Result enableMallBrand(@RequestBody MallBrand mallBrand){
  64. try{
  65. MallBrandmodifiedData =new MallBrand ();
  66. (());
  67. (DataStatusEnum.STATUS_ENABLE.getStatusValue());
  68. return (modifiedData);
  69. }catch(Exceptione){
  70. ();
  71. return newResult(false);
  72. }
  73. }
  74. /**
  75. * 停用品牌
  76. * @param mallBrand
  77. * @return
  78. */
  79. @RequestMapping("/disableMallBrand")
  80. public Result disableMallBrand(@RequestBody MallBrand mallBrand){
  81. try{
  82. MallBrandmodifiedData =new MallBrand ();
  83. (());
  84. (DataStatusEnum.STATUS_DISABLE.getStatusValue());
  85. return (modifiedData);
  86. }catch(Exceptione){
  87. ();
  88. return newResult(false);
  89. }
  90. }
  91. /**
  92. * 删除品牌
  93. * @param mallBrand
  94. * @return
  95. */
  96. @RequestMapping("/deleteMallBrand")
  97. public Result deleteMallBrand(@RequestBody MallBrand mallBrand){
  98. try{
  99. return (mallBrand);
  100. }catch(Exceptione){
  101. ();
  102. return newResult(false);
  103. }
  104. }
  105. /**
  106. * 分页返回品牌列表
  107. * @paramqueryMallBrand
  108. * @return
  109. */
  110. @RequestMapping("/findByPage")
  111. public Result<List<MallBrand>> findByPage(@RequestBody QueryMallBrandqueryMallBrand){
  112. (queryMallBrand);
  113. }
  114. /**
  115. * 修改品牌
  116. * @param brandList
  117. * @return
  118. */
  119. @RequestMapping("/disableMallBrandList")
  120. public Result disableMallBrandList(@RequestBody List<MallBrand> brandList){
  121. try{
  122. return (brandList,true);
  123. }catch(Exceptione){
  124. ();
  125. return newResult(false);
  126. }
  127. }
  128. /**
  129. * 修改品牌
  130. * @param brandList
  131. * @return
  132. */
  133. @RequestMapping("/enableMallBrandList")
  134. public Result enableMallBrandList(@RequestBody List<MallBrand> brandList){
  135. try{
  136. return (brandList,false);
  137. }catch(Exceptione){
  138. ();
  139. return newResult(false);
  140. }
  141. }
  142. /**
  143. * 修改品牌
  144. * @param brandList
  145. * @return
  146. */
  147. @RequestMapping("/deleteMallBrandList")
  148. public Result deleteMallBrandList(@RequestBody List<MallBrand> brandList){
  149. try{
  150. return (brandList);
  151. }catch(Exceptione){
  152. ();
  153. return newResult(false);
  154. }
  155. }
  156. }

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

前端代码之API层

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

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

  1. export function fetchBrandList(query) {
  2. return request({
  3. url:'/brandManage/findByPage',
  4. method: 'post',
  5. data: query
  6. })
  7. }
  8. export function createBrand(data) {
  9. return request({
  10. url:'/brandManage/addMallBrand',
  11. method: 'post',
  12. data: data
  13. })
  14. }
  15. export function updateBrand(data) {
  16. return request({
  17. url: '/brandManage/updateMallBrand',
  18. method: 'post',
  19. data: data
  20. })
  21. }
  22. export function disableMallBrandList(data) {
  23. return request({
  24. url:'/brandManage/disableMallBrandList',
  25. method: 'post',
  26. data: data
  27. })
  28. }
  29. export function enableMallBrand(data) {
  30. return request({
  31. url:'/brandManage/enableMallBrand',
  32. method: 'post',
  33. data: data
  34. })
  35. }
  36. export function deleteMallBrand(data) {
  37. return request({
  38. url:'/brandManage/deleteMallBrand',
  39. method: 'post',
  40. data: data
  41. })
  42. }
  43. export function disableMallBrand(data) {
  44. return request({
  45. url:'/brandManage/disableMallBrand',
  46. method: 'post',
  47. data: data
  48. })
  49. }
  50. export function enableMallBrandList(data) {
  51. return request({
  52. url:'/brandManage/enableMallBrandList',
  53. method: 'post',
  54. data: data
  55. })
  56. }
  57. export function deleteMallBrandList(data) {
  58. return request({
  59. url:'/brandManage/deleteMallBrandList',
  60. method: 'post',
  61. data: data
  62. })
  63. }

前端代码之组件引入

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

  1. <script>
  2. import { fetchBrandList, createBrand, updateBrand,disableMallBrand, enableMallBrand, deleteMallBrand, disableMallBrandList,enableMallBrandList, deleteMallBrandList } from'@/api/basedataManage/basedataManage'
  3. import Pagination from '@/components/Pagination' // secondarypackage based on el-pagination
  4. export default {
  5. components: { Pagination},
  6. data() {
  7. return {
  8. }
  9. },
  10. created() {
  11. },
  12. methods: {
  13. }
  14. }
  15. </script>

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

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

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

前端代码之列表数据

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

  1. // table数据集合
  2. list: null,
  3. listQuery: {
  4. brandName: '',
  5. firsChar: '',
  6. page: 1,
  7. pageSize: 10
  8. }

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

  1. // 列表方法查询
  2. getList() {
  3. this.listLoading =true
  4. fetchBrandList(this.listQuery).then(response => {
  5. this.list =
  6. this.total =
  7. // Just to simulatethe time of the request
  8. setTimeout(()=> {
  9. this.listLoading= false
  10. }, 1.5 * 1000)
  11. })
  12. }

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

  1. created() {
  2. // 列表查询
  3. this.getList()
  4. }

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

前端代码之新增/编辑

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

  1. temp: {
  2. id: undefined,
  3. // 品牌名称
  4. brandName: '',
  5. // 品牌首字母
  6. firsChar: '',
  7. logo: '',
  8. imageUrl: ''
  9. },
  10. dialogStatus: '',
  11. textMap: {
  12. update: '编辑品牌',
  13. create: '新增品牌'
  14. },
  15. // 弹框是否显示
  16. dialogFormVisible:false,

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

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

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

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

  1. resetTemp() {
  2. this.temp = {
  3. id: undefined,
  4. // 品牌名称
  5. brandName: '',
  6. // 品牌首字母
  7. firstChar: '',
  8. logo: ''
  9. }
  10. this.dialogVisible =false
  11. if(this.$refs.upload !== null && undefined !== this.$refs.upload) {
  12. this.$refs.upload.clearFiles()
  13. }
  14. console.log(this.$refs.upload)
  15. },
  16. // 新增
  17. addBrand() {
  18. this.resetTemp()
  19. this.dialogStatus ='create'
  20. this.dialogFormVisible = true
  21. this.$nextTick(()=> {
  22. this.$refs['dataForm'].clearValidate()
  23. })
  24. },
  25. 至于数据持久,同样也是button绑定函数的方式来完成。
  26. // 更新保存方法
  27. updateData() {
  28. this.$refs['dataForm'].validate((valid)=> {
  29. if (valid) {
  30. const tempData =Object.assign({}, this.temp)
  31. updateBrand(tempData).then(() => {
  32. const index =this.list.findIndex(v => v.id === this.temp.id)
  33. this.list.splice(index, 1, this.temp)
  34. this.dialogFormVisible = false
  35. this.$notify({
  36. title:'Success',
  37. message:'Update Successfully',
  38. type:'success',
  39. duration:2000
  40. })
  41. })
  42. }
  43. })
  44. },
  45. // 创建保存方法
  46. createData() {
  47. this.$refs['dataForm'].validate((valid) => {
  48. if (valid) {
  49. createBrand(this.temp).then((res) => {
  50. this.temp.id =res.model.id
  51. this.list.unshift(this.temp)
  52. this.dialogFormVisible = false
  53. this.$notify({
  54. title:'Success',
  55. message:'Created Successfully',
  56. type:'success',
  57. duration:2000
  58. })
  59. })
  60. }
  61. })
  62. },

 

前端代码之其它功能

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

 

自己去完善!

到此为止,我们项目的开发框架搭建完毕。
  如学习过程中遇到疑难杂症,自己实在搞不定,可以加我的微信,帮你解决。