猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是问题。想要一起实战吗?,关注公主号猿人工厂,获取基础代码,手把手带你开发一个完整的电商系统。
前后端框架已经搭建起来了,接下来的很长一段日子里,猿人君就带着大家撸一个电商系统出来玩耍。实战阶段的目的,是为了让你从需求梳理落地到实现有一个完整的认知,熟练掌握撸码的一些套路,让你具备设计和实现一个完整系统的能力。废话不多说,我们今天开始首战——品牌管理的设计和实现。
需求整理
根据之前的猿设计系列文章猿设计2——电商后台全逻辑需求挖掘,品牌数据是需要维护的,根据对设计文档的梳理,我们需要做的功能如下图所示:
品牌管理的功能包括,品牌列表——支持根据品牌名称模糊查询并分页展示,新增品牌、编辑品牌、删除品牌、停用/启用品牌,以及为了方便运营人员批量操作而提供的勾选记录批量停用/启用/删除功能。
数据库设计
由于之前的设计文章中,我们已经提及过品牌实体的一些属性了,而这些属性背后承载的信息,将为我们的电商系统提供数据支撑,毫无疑问,这些数据是需要持久的,为此我们自然需要建立相应的数据表来支持。
前端主要组件
由于我们使用了vue-作为基础的后天管理前端开发框架,前端中使用的主要组件,主要是element-ui,关于组件的具体使用办法,大家可以参考官方网站:
https://element./#/zh-CN
在品牌管理这一功能中,我们主要使用了el-card、el-input、el-button、el-table(列表)、el-pagination(分页)、el-upload(上传组件),考虑到你可能是第一次编写前端代码,很多东西都还不熟悉,这次就把前端的UI代码送给你了。
-
<template>
-
<div>
-
<el-cardclass="filter-container" shadow="never">
-
<div>
-
<el-formref="listQuery" :model="listQuery" :inline="true">
-
<el-form-itemlabel="品牌名称:"prop="brandName">
-
<el-inputv-model="" 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">{{ }}</template>
-
</el-table-column>
-
<el-table-column label="品牌名称">
-
<templateslot-scope="scope">{{ }}</template>
-
</el-table-column>
-
<el-table-column label="品牌首字母" min-width="10%">
-
<templateslot-scope="scope">{{ }}</template>
-
</el-table-column>
-
<el-table-columnlabel="品牌logo"align="center">
-
<templateslot-scope="scope"><img style="width: 200px; height:200px" :src=""alt=""></template>
-
</el-table-column>
-
<el-table-column label="状态" min-width="10%">
-
<templateslot-scope="scope">{{ == 1 ? "启用" : "停用"}}</template>
-
</el-table-column>
-
<el-table-column label="操作" width="220">
-
-
<templateslot-scope="scope">
-
<el-button
-
type="primary"
-
size="mini"
-
@click="handleUpdate()"
-
>编辑
-
</el-button>
-
<el-button
-
v-if="==1"
-
type="primary"
-
size="mini"
-
@click="handleDisable(scope.$index,)"
-
>停用
-
</el-button>
-
<el-button
-
v-if="==0"
-
type="primary"
-
size="mini"
-
@click="handleEnable(scope.$index, )"
-
>启用
-
</el-button>
-
<el-button
-
size="mini"
-
type="danger"
-
@click="handleDelete(scope.$index, )"
-
>删除
-
</el-button>
-
</template>
-
</el-table-column>
-
</el-table>
-
</div>
-
<paginationv-show="total>0" :total="total":="":="" @pagination="getList"/>
-
-
<!-- 新增/编辑弹框 -->
-
<el-dialog:title="textMap[dialogStatus]":="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="" />
-
</el-form-item>
-
<el-form-itemlabel="品牌首字母:"prop="firstChar">
-
<el-inputv-model="" maxlength="1"oninput="value=(/[^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=""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">
-
<el-button@click="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
-
*
-
*/
-
package ;
-
-
import .;
-
-
import ;
-
-
/**
-
*
-
* @author pangzi
-
* @date 2020-06-2211:28:19
-
*
-
*
-
*/
-
public class BaseDO implements Serializable {
-
-
private static final longserialVersionUID = 1L;
-
-
-
/**
-
* 如果字段值为null将不包含在toString中
-
*/
-
@Override
-
public String toString(){
-
(this);
-
}
-
}
-
-
-
-
-
-
package ;
-
-
import ;
-
-
import ;
-
-
-
/**
-
*
-
* @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 ;
-
import ;
-
-
import ;
-
-
-
/**
-
*
-
* @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 ;
-
-
import ;
-
-
/**
-
*
-
* @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
-
*
-
*/
-
package ;
-
import ;
-
import ;
-
-
import ;
-
-
-
-
/**
-
*
-
* @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文件.
-
<?xml version="1.0" encoding="UTF-8"?>
-
<!DOCTYPE mapper PUBLIC "-////DTD Mapper3.0//EN" "/dtd/" >
-
-
<mapper namespace="">
-
-
<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" >
-
<includeref />
-
</if>
-
-
LIMIT#{startRow},#{pageSize}
-
</select>
-
-
-
<select id="selectMallBrandById" resultMap="ResultMap"parameterType="" >
-
select
-
<include refid="ALL_TABLE_COLOUM" />
-
from mall_brand
-
where id = #{id}
-
</select>
-
<delete id="deleteMallBrandById" parameterType="">
-
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">
-
SELECT@@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">
-
SELECT@@IDENTITY AS ID
-
</selectKey>
-
</insert>
-
-
-
<select id="countByQuery" parameterType="QueryMallBrand" resultType="" >
-
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的总控文件中增加需要用到的别名和引用。
后端代码之service层
我们之前已经说了,service层是编写业务的核心逻辑,通过调用dao方式完成业务逻辑对应的数据操作。
-
/**
-
* Copyright(c) 2004-2020 pangzi
-
*
-
*/
-
package ;
-
import ;
-
import ;
-
import ;
-
-
import ;
-
-
-
-
/**
-
* service层,组装外部接口和 本地业务,为本业务 或者其他业务提供服务,统一返回Result
-
* 通过判断调用是否成功
-
* 此类中新增业务接口设计(接口命令,入参数据,返回值)要能尽量完整的表达业务 含义
-
* @author pangzi
-
* @date 2020-06-26 11:20:40
-
*/
-
public interface MallBrandService {
-
-
/**
-
* 新增 mallBrand
-
* 返回result,通过()判断服务调用是否成功
-
* 通过()得到新增mallBrand
-
* @param mallBrand
-
* @return
-
*/
-
public Result<MallBrand> addMallBrand(MallBrand mallBrand) ;
-
-
/**
-
* 按照主键id更新mallBrand,请重新new MallBrand 的更新对象,设置要更新的字段
-
* 返回result,通过()判断更新是否成功
-
* @param mallBrand
-
* @return
-
*/
-
public Result updateMallBrandById(MallBrandmallBrand);
-
-
/**
-
* 按照主键id 删除 记录
-
* 返回result,通过()判断删除是否成功
-
* @return
-
*/
-
public Result deleteMallBrandById(MallBrandmallBrand);
-
-
/**
-
* 查询列表,此接口不包含分页查询
-
* 返回result,通过()判断服务调用是否成功
-
* 通过()得到列表信息
-
* @param queryMallBrand
-
* @return
-
*/
-
public Result<List<MallBrand>> getMallBrandsByQuery(QueryMallBrand queryMallBrand);
-
-
/**
-
* 通过主键id查询MallBrand
-
* 返回result,通过()判断服务调用是否成功
-
* 通过()得到查询的单条mallBrand信息
-
* @param id
-
* @return
-
*/
-
public Result<MallBrand> getMallBrandById(long id);
-
-
/**
-
* 查询列表,包含分页查询
-
* 查询分页信息,请设置
-
* (设置当前页数)
-
*(设置当前页面数据行数)
-
* 返回result,通过()判断服务调用是否成功
-
* 通过()返回结果总数
-
* 通过()得到查询的单页列表信息
-
* @param queryMallBrand
-
* @return
-
*/
-
public Result<List<MallBrand>> getMallBrandsByPage(QueryMallBrand queryMallBrand);
-
-
/**
-
* 查询总数
-
* @param queryMallBrand
-
* @return
-
*/
-
public Result<Long> count(QueryMallBrand queryMallBrand);
-
-
/**
-
* 停用启用品牌列表
-
* 返回result,通过()判断服务调用是否成功
-
* 通过()得到列表信息
-
* @param brandList
-
* @param disable true 停用 false 启用
-
* @return
-
*/
-
public Result disableEnableMallBrandList(List<MallBrand>brandList, boolean disable);
-
-
/**
-
* 逻辑删除品牌列表
-
* 返回result,通过()判断服务调用是否成功
-
* 通过()得到列表信息
-
* @param brandList
-
* @return
-
*/
-
public Result deleteMallBrandList(List<MallBrand>brandList);
-
-
}
-
-
/**
-
* Copyright(c) 2004-2020 pangzi
-
*
-
*/
-
package ;
-
import ;
-
-
import ;
-
import ;
-
-
import ;
-
import ;
-
import ;
-
import ;
-
import ;
-
-
import ;
-
-
-
/**
-
*
-
* @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();
-
(());
-
long count = (query);
-
if(count>0){
-
(false);
-
("品牌名已存在");
-
return result;
-
}
-
(DataStatusEnum.STATUS_ENABLE.getStatusValue());
-
(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
-
(mallBrand);
-
(mallBrand);
-
} catch(Exception e) {
-
(false);
-
}
-
return result;
-
}
-
-
public Result updateMallBrandById(MallBrandmallBrand) {
-
Result result = new Result();
-
try {
-
int count=(mallBrand);
-
if(count>0){
-
(true);
-
}
-
} catch(Exception e) {
-
(false);
-
}
-
return result;
-
}
-
-
public Result deleteMallBrandById(MallBrandmallBrand) {
-
Result result = new Result();
-
try {
-
int count=0;
-
MallBrand modifiedMallBrand = new MallBrand();
-
(());
-
(DataActiveStatusEnum.STATUS_DELETED.getStatusValue());
-
count=(modifiedMallBrand);
-
if(count>0){
-
(true);
-
}
-
} catch(Exception e) {
-
(false);
-
}
-
return result;
-
}
-
-
public Result<List<MallBrand>> getMallBrandsByQuery(QueryMallBrand queryMallBrand) {
-
Result<List<MallBrand>> result = newResult<List<MallBrand>>();
-
try {
-
(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
-
("MallBrands",(queryMallBrand));
-
} catch(Exception e) {
-
(false);
-
}
-
return result;
-
}
-
-
public Result<MallBrand> getMallBrandById(longid) {
-
Result<MallBrand> result = new Result<MallBrand>();
-
try {
-
("MallBrand",(id));
-
} catch(Exception e) {
-
(false);
-
}
-
return result;
-
}
-
-
-
public Result<List<MallBrand>> getMallBrandsByPage(QueryMallBrand queryMallBrand) {
-
-
Result<List<MallBrand>> result = newResult<List<MallBrand>>();
-
(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
-
long totalItem =(queryMallBrand);
-
(totalItem);
-
();
-
if (totalItem > 0) {
-
((queryMallBrand));
-
} else {
-
(new ArrayList<MallBrand>());
-
}
-
(totalItem);
-
(());
-
(());
-
-
return result;
-
}
-
-
public Result<Long> count(QueryMallBrand queryMallBrand) {
-
Result<Long> result = new Result<Long>();
-
(DataActiveStatusEnum.STATUS_ACTIVE.getStatusValue());
-
try {
-
((queryMallBrand));
-
} catch(Exception e) {
-
(false);
-
}
-
return result;
-
}
-
-
-
public Result disableEnableMallBrandList(List<MallBrand>brandList, boolean disable) {
-
-
Result result = new Result();
-
try {
-
for (MallBrand brand : brandList) {
-
if (disable) {
-
(DataStatusEnum.STATUS_DISABLE.getStatusValue());
-
} else {
-
(DataStatusEnum.STATUS_ENABLE.getStatusValue());
-
}
-
(brand);
-
}
-
}catch(Exception e){
-
(false);
-
}
-
return result;
-
}
-
-
public Result deleteMallBrandList(List<MallBrand> brandList){
-
Result result = new Result();
-
try {
-
for (MallBrand brand : brandList) {
-
(DataActiveStatusEnum.STATUS_DELETED.getStatusValue());
-
(brand);
-
}
-
}catch(Exception e){
-
(false);
-
}
-
return result;
-
}
-
}
最后,不要忘记了,在增加service的配置
<bean id="mallBrandService"class=""/>
后端代码之Controller层
我们提供给前端访问的数据接口,是通过Controller暴露出去的,前端通过HttpJSON的方式到后端获取需要的数据。在这一点上,我们使用SpringMVC的RestController能够获得比较好的支持。
-
/**
-
* Copyright(c) 2004-2020pangzi
-
*
-
*/
-
package ;
-
-
import ;
-
import ;
-
import ;
-
import ;
-
import ;
-
import .annotation.RequestBody;
-
import .annotation.RequestMapping;
-
import .annotation.RestController;
-
-
import ;
-
-
-
/**
-
*
-
* @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 (mallBrand);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
-
/**
-
* 修改品牌
-
* @param mallBrand
-
* @return
-
*/
-
@RequestMapping("/updateMallBrand")
-
public Result updateMallBrand(@RequestBody MallBrand mallBrand){
-
try{
-
return (mallBrand);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
/**
-
* 启用品牌
-
* @param mallBrand
-
* @return
-
*/
-
@RequestMapping("/enableMallBrand")
-
public Result enableMallBrand(@RequestBody MallBrand mallBrand){
-
try{
-
MallBrandmodifiedData =new MallBrand ();
-
(());
-
(DataStatusEnum.STATUS_ENABLE.getStatusValue());
-
return (modifiedData);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
-
/**
-
* 停用品牌
-
* @param mallBrand
-
* @return
-
*/
-
@RequestMapping("/disableMallBrand")
-
public Result disableMallBrand(@RequestBody MallBrand mallBrand){
-
try{
-
MallBrandmodifiedData =new MallBrand ();
-
(());
-
(DataStatusEnum.STATUS_DISABLE.getStatusValue());
-
return (modifiedData);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
/**
-
* 删除品牌
-
* @param mallBrand
-
* @return
-
*/
-
@RequestMapping("/deleteMallBrand")
-
public Result deleteMallBrand(@RequestBody MallBrand mallBrand){
-
try{
-
return (mallBrand);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
-
/**
-
* 分页返回品牌列表
-
* @paramqueryMallBrand
-
* @return
-
*/
-
@RequestMapping("/findByPage")
-
public Result<List<MallBrand>> findByPage(@RequestBody QueryMallBrandqueryMallBrand){
-
(queryMallBrand);
-
}
-
-
-
/**
-
* 修改品牌
-
* @param brandList
-
* @return
-
*/
-
@RequestMapping("/disableMallBrandList")
-
public Result disableMallBrandList(@RequestBody List<MallBrand> brandList){
-
try{
-
return (brandList,true);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
/**
-
* 修改品牌
-
* @param brandList
-
* @return
-
*/
-
@RequestMapping("/enableMallBrandList")
-
public Result enableMallBrandList(@RequestBody List<MallBrand> brandList){
-
try{
-
return (brandList,false);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
/**
-
* 修改品牌
-
* @param brandList
-
* @return
-
*/
-
@RequestMapping("/deleteMallBrandList")
-
public Result deleteMallBrandList(@RequestBody List<MallBrand> brandList){
-
try{
-
return (brandList);
-
}catch(Exceptione){
-
();
-
return newResult(false);
-
}
-
}
-
-
}
到目前为止,后端代码的编写告一段落。
前端代码之API层
后端接口的主要作用是为前端提供数据支撑,前端针对这些后端接口,可以做一些封装,然后交由需要调用的页面使用。为了保证功能的相对独立和后续前端代码的维护,我们需要对品牌管理相关的功能做一些封装——在api目录下建立basedataManage目录,然后建立文件,之后基础数据相关的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了,那么接下来的事情,自然是引入我们需要的组件了。在文件中,建立如下标记。
-
<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 =
-
this.total =
-
// 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
-
})
-
})
-
}
-
})
-
},
前端代码之其它功能
前端的停用/启用/删除功能,大家可以看下,篇幅有限,就不一一例举了——最主要的是你不能懒惰,敲代码的事情,必须自己搞了。给你一些例子,自己去完善!
自己去完善!
到此为止,我们项目的开发框架搭建完毕。
如学习过程中遇到疑难杂症,自己实在搞不定,可以加我的微信,帮你解决。