day09_商品管理订单管理SpringTaskEcharts

news2024/9/24 7:23:05

文章目录

  • 1 商品管理
    • 1.1 添加功能
      • 1.1.1 需求说明
      • 1.1.2 核心概念
        • SPU
        • SKU
      • 1.1.3 加载品牌数据
        • CategoryBrandController
        • CategoryBrandService
        • CategoryBrandMapper
        • CategoryBrandMapper.xml
      • 1.1.4 加载商品单元数据
        • ProductUnit
        • ProductUnitController
        • ProductUnitService
        • ProductUnitMapper
        • ProductUnitMapper.xml
      • 1.1.5 加载商品规格数据
        • ProductSpecController
        • ProductSpecService
        • ProductSpecMapper
        • ProductSpecMapper.xml
      • 1.1.6 保存商品数据接口
        • 思路分析
        • Product
        • ProductSku
        • ProductDetails
        • ProductController
        • ProductService
        • ProductMapper
        • ProductMapper.xml
        • ProductSkuMapper
        • ProductSkuMapper.xml
        • ProductDetailsMapper
        • ProductDetailsMapper.xml
    • 1.2 修改功能
      • 1.2.1 需求说明
      • 1.2.2 查询商品详情
        • ProductController
        • ProductService
        • ProductMapper
        • ProductMapper.xml
        • ProductSkuMapper
        • ProductSkuMapper.xml
        • ProductDetailsMapper
        • ProductDetailsMapper.xml
      • 1.2.3 保存修改数据接口
        • ProductController
        • ProductService
        • ProductMapper
        • ProductMapper.xml
        • ProductSkuMapper
        • ProductSkuMapper.xml
        • ProductDetailsMapper
        • ProductDetailsMapper.xml
    • 1.3 删除商品
      • 1.3.1 需求说明
      • 1.3.2 后端接口
        • ProductController
        • ProductService
        • ProductMapper
        • ProductMapper.xml
        • ProductSkuMapper
        • ProductSkuMapper.xml
        • ProductDetailsMapper
        • ProductDetailsMapper.xml
    • 1.4 商品审核
      • 1.4.1 需求说明
      • 1.4.2 后端接口
        • ProductController
        • ProductService
    • 1.5 商品上下架
      • 1.5.1 需求说明
      • 1.5.2 后端接口
        • ProductController
        • ProductService
  • 2 订单管理
    • 2.1 订单数据统计需求说明
    • 2.2 Echarts
      • 2.2.1 Echarts简介
      • 2.2.2 Echarts入门
    • 2.3 订单相关数据库表介绍
    • 2.4 订单数据统计实现思路
    • 2.5 Spring Task
      • 2.5.1 Spring Task简介
      • 2.5.2 Spring Task入门案例
      • 2.5.3 cron表达式
    • 2.6 订单数据统计
      • 2.6.1 数据库表介绍
      • 2.6.3 代码实现
        • OrderStatistics
        • OrderInfo
        • OrderStatisticsTask
        • OrderInfoMapper
        • OrderInfoMapper.xml
        • OrderStatisticsMapper
        • OrderStatisticsMapper.xml
    • 2.7 统计查询
      • 2.7.1 后端接口
        • OrderStatisticsDto
        • OrderStatisticsVo
        • OrderInfoController
        • OrderInfoService
        • OrderStatisticsMapper
        • OrderStatisticsMapper.xml
      • 2.7.2 前端对接

1 商品管理

商品管理就是对电商项目中所涉及到的商品数据进行维护。

1.1 添加功能

1.1.1 需求说明

当用户点击添加按钮的时候,那么此时就弹出对话框,在该对话框中需要展示添加商品的表单。当用户在该表单中点击提交按钮的时候那么此时就需要将表单进行提交,在后端需要将提交过来的表单数据保存到数据库中即可。

如下所示:

在这里插入图片描述

1.1.2 核心概念

在完成商品添加功能之前,必须先要了解电商系统中常见的两个核心的概念。

SPU

SPU = Standard Product Unit (标准化产品单元), SPU是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。通俗点讲就是泛指一类商品,这种商品具有相同的属性。

SKU

SKU = stock keeping unit(库存量单位) SKU即库存进出计量的单位(买家购买、商家进货、供应商备货、工厂生产都是依据SKU进行的)。是和具体的属性值有直接的关联关系。SKU是物理上不可分割的最小存货单元。也就是说一款商品,可以根据SKU来确定具体的货物存量。

以手机为例,假设有一款名为 “XPhone” 的手机品牌,它推出了一款型号为 “X10” 的手机。这款手机一共有以下几种属性:

1、颜色:黑色、白色、金色

2、存储容量:64GB、128GB

3、内存大小:4GB、6GB

那么,“X10” 这款手机就是这个商品的 SPU,它包含所有属性。而根据不同的属性组合,可以形成多个不同的 SKU。如下所示:

SPUSKU颜色存储容量内存大小
X10SKU1黑色64GB4GB
X10SKU2白色64GB4GB
X10SKU3金色64GB4GB
X10SKU4黑色128GB4GB
X10SKU5白色128GB4GB
X10SKU6金色128GB4GB
X10SKU7黑色64GB6GB
X10SKU8白色64GB6GB
X10SKU9金色64GB6GB
X10SKU10黑色128GB6GB
X10SKU11白色128GB6GB
X10SKU12金色128GB6GB

再以衣服为例,假设有一家服装网店推出了一款名为 “A衬衫” 的衣服。这款衣服一共有以下几种属性:

1、尺寸:S、M、L、XL

2、颜色:白色、黑色、灰色、蓝色

那么,“A衬衫” 这款衣服就是这个商品的 SPU,它包含所有属性。而根据不同的属性组合,可以形成多个不同的 SKU。如下所示:

SPUSKU尺寸颜色
A衬衫SKU1S白色
A衬衫SKU2M白色
A衬衫SKU3L白色
A衬衫SKU4XL白色
A衬衫SKU5S黑色
A衬衫SKU6M黑色
A衬衫SKU7L黑色
A衬衫SKU8XL黑色
A衬衫SKU9S灰色
A衬衫SKU10M灰色
A衬衫SKU11L灰色
A衬衫SKU12XL灰色
A衬衫SKU13S蓝色
A衬衫SKU14M蓝色
A衬衫SKU15L蓝色
A衬衫SKU16XL蓝色

1.1.3 加载品牌数据

需求:当用户选择了三级分类以后,此时需要将三级分类所对应的品牌数据查询出来在品牌下拉框中进行展示

CategoryBrandController

表现层代码实现:

// com.atguigu.spzx.manager.controller
@GetMapping("/findBrandByCategoryId/{categoryId}")
public Result findBrandByCategoryId(@PathVariable Long categoryId) {
    List<Brand> brandList =   categoryBrandService.findBrandByCategoryId(categoryId);
    return Result.build(brandList , ResultCodeEnum.SUCCESS) ;
}
CategoryBrandService

业务层代码实现:

// com.atguigu.spzx.manager.service.impl
@Override
public List<Brand> findBrandByCategoryId(Long categoryId) {
    return categoryBrandMapper.findBrandByCategoryId(categoryId);
}
CategoryBrandMapper

持久层代码实现:

// com.atguigu.spzx.manager.mapper
@Mapper
public interface CategoryBrandMapper {
    public abstract List<Brand> findBrandByCategoryId(Long categoryId);
}
CategoryBrandMapper.xml

在CategoryBrandMapper.xml映射文件中添加如下sql语句:

<resultMap id="brandMap" type="com.atguigu.spzx.model.entity.product.Brand" autoMapping="true"></resultMap>
<select id="findBrandByCategoryId" resultMap="brandMap">
    select
    b.*
    from category_brand cb
    left join brand b  on b.id = cb.brand_id
    where cb.category_id = #{categoryId} and cb.is_deleted = 0
    order by cb.id desc
</select>

1.1.4 加载商品单元数据

需求:当添加商品的表单对话框展示出来以后,此时就需要从数据库中查询出来所有的商品单元数据,并将查询到的商品单元数据在商品单元下拉框中进行展示。

ProductUnit
//com.atguigu.spzx.model.entity.product

@Data
public class ProductUnit extends BaseEntity {
    private String name;
}
ProductUnitController

表现层代码实现:

// com.atguigu.spzx.manager.controller
@GetMapping("findAll")
public Result<List<ProductUnit>> findAll() {
    List<ProductUnit> productUnitList = productUnitService.findAll();
    return Result.build(productUnitList , ResultCodeEnum.SUCCESS) ;
}
ProductUnitService

业务层代码实现:

// com.atguigu.spzx.manager.service.impl
@Override
public List<ProductUnit> findAll() {
    return productUnitMapper.findAll() ;
}
ProductUnitMapper

持久层代码实现:

// com.atguigu.spzx.manager.mapper
@Mapper
public interface ProductUnitMapper {
    public abstract List<ProductUnit> findAll();
}
ProductUnitMapper.xml

在ProductUnitMapper.xml映射文件中添加如下的sql语句:

<select id="findAll" resultMap="productUnitMap">
    select <include refid="columns" />
    from product_unit
    where is_deleted = 0
    order by id
</select>

1.1.5 加载商品规格数据

需求:当添加商品的表单对话框展示出来以后,此时就需要从数据库中查询出来所有的商品规格数据,并将查询到的商品规格数据在商品规格下拉框中进行展示。

ProductSpecController

表现层代码实现:

// com.atguigu.spzx.manager.controller
@GetMapping("findAll")
public Result findAll() {
    List<ProductSpec> list = productSpecService.findAll();
    return Result.build(list , ResultCodeEnum.SUCCESS) ;
}
ProductSpecService

业务层代码实现:

// com.atguigu.spzx.manager.service.impl;
@Override
public List<ProductSpec> findAll() {
    return productSpecMapper.findAll();;
}
ProductSpecMapper

持久层代码实现:

// com.atguigu.spzx.manager.mapper
@Mapper
public interface ProductSpecMapper {
    public abstract List<ProductSpec> findAll();
}
ProductSpecMapper.xml

在ProductSpecMapper.xml映射文件中添加如下sql语句:

<select id="findAll" resultMap="productSpecMap">
    select <include refid="columns" />
    from product_spec
    order by id desc
</select>

1.1.6 保存商品数据接口

思路分析

思路分析:

1、前端提交过来的数据,包含了SPU的基本数据,SKU的列表数据,商品详情数据

2、后端可以直接使用Product接收请求参数,但是需要扩展对应的属性

3、保存数据的时候需要操作三张表:product、product_sku、product_detail

Product

修改Product实体类,添加接收sku列表和商品详情的属性,如下所示:

// com.atguigu.spzx.model.entity.product;
@Data
public class Product extends BaseEntity {

	private String name;					// 商品名称
	private Long brandId;					// 品牌ID
	private Long category1Id;				// 一级分类id
	private Long category2Id;				// 二级分类id
	private Long category3Id;				// 三级分类id
	private String unitName;				// 计量单位
	private String sliderUrls;				// 轮播图
	private String specValue;				// 商品规格值json串
	private Integer status;					// 线上状态:0-初始值,1-上架,-1-自主下架
	private Integer auditStatus;			// 审核状态
	private String auditMessage;			// 审核信息

	// 扩展的属性,用来封装响应的数据
	private String brandName;				// 品牌
	private String category1Name;			// 一级分类
	private String category2Name;			// 二级分类
	private String category3Name;			// 三级分类


	private List<ProductSku> productSkuList;		// sku列表集合
	private String detailsImageUrls;				// 图片详情列表

}
ProductSku

商品sku实体类定义:

// com.atguigu.spzx.model.entity.product;
@Data
public class ProductSku extends BaseEntity { 

	private String skuCode;
	private String skuName;
	private Long productId;
	private String thumbImg;
	private BigDecimal salePrice;
	private BigDecimal marketPrice;
	private BigDecimal costPrice;
	private Integer stockNum;
	private Integer saleNum;
	private String skuSpec;
	private String weight;
	private String volume;
	private Integer status;

}
ProductDetails

商品详情实体类:

// com.atguigu.spzx.model.entity.product;
@Data
public class ProductDetails extends BaseEntity {

	private Long productId;
	private String imageUrls;

}
ProductController

表现层代码:

// com.atguigu.spzx.manager.controller;
@PostMapping("/save")
public Result save(@RequestBody Product product) {
    productService.save(product);
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
ProductService

业务层代码:

// com.atguigu.spzx.manager.service.impl;
@Transactional
@Override
public void save(Product product) {

    // 保存商品数据
    product.setStatus(0);              // 设置上架状态为0
    product.setAuditStatus(0);         // 设置审核状态为0
    productMapper.save(product);

    // 保存商品sku数据
    List<ProductSku> productSkuList = product.getProductSkuList();
    for(int i=0,size=productSkuList.size(); i<size; i++) {

        // 获取ProductSku对象
        ProductSku productSku = productSkuList.get(i);
        productSku.setSkuCode(product.getId() + "_" + i);       // 构建skuCode
        productSku.setProductId(product.getId());               // 设置商品id
        productSku.setSkuName(product.getName() + productSku.getSkuSpec());
        productSku.setSaleNum(0);                               // 设置销量
        productSku.setStatus(0);
        productSkuMapper.save(productSku);                    // 保存数据

    }

    // 保存商品详情数据
    ProductDetails productDetails = new ProductDetails();
    productDetails.setProductId(product.getId());
    productDetails.setImageUrls(product.getDetailsImageUrls());
    productDetailsMapper.save(productDetails);

}
ProductMapper

商品持久层代码:

// com.atguigu.spzx.manager.mapper
@Mapper
public interface ProductMapper {
    public abstract void save(Product product);
}
ProductMapper.xml

在ProductMapper.xml文件中添加如下的SQL语句:

<insert id="save" useGeneratedKeys="true" keyProperty="id">
    insert into product (
        id,
        name,
        brand_id,
        category1_id,
        category2_id,
        category3_id,
        unit_name,
        slider_urls,
        spec_value,
        status,
        audit_status,
        audit_message,
        create_time,
        update_time,
        is_deleted
    ) values (
        #{id},
        #{name},
        #{brandId},
        #{category1Id},
        #{category2Id},
        #{category3Id},
        #{unitName},
        #{sliderUrls},
        #{specValue},
        #{status},
        #{auditStatus},
        #{auditMessage},
        now(),
        now() ,
        0
    )
</insert>
ProductSkuMapper

商品SKU的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductSkuMapper {
    public abstract void save(ProductSku productSku);
}
ProductSkuMapper.xml

在ProductSkuMapper.xml映射文件中添加如下的SQL语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.spzx.manager.mapper.ProductSkuMapper">

    <insert id="save" useGeneratedKeys="true" keyProperty="id">
        insert into product_sku (
            id,
            sku_code,
            sku_name,
            product_id,
            thumb_img,
            sale_price,
            market_price,
            cost_price,
            stock_num,
            sku_spec,
            weight,
            volume,
            status,
            sale_num,
            create_time,
            update_time,
            is_deleted
        ) values (
             #{id},
             #{skuCode},
             #{skuName},
             #{productId},
             #{thumbImg},
             #{salePrice},
             #{marketPrice},
             #{costPrice},
             #{stockNum},
             #{skuSpec},
             #{weight},
             #{volume},
             #{status},
             #{saleNum},
             now(),
             now(),
             0
         )
    </insert>

</mapper>
ProductDetailsMapper

商品详情的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductDetailsMapper {
    public abstract void save(ProductDetails productDetails);
}
ProductDetailsMapper.xml

在ProductDetailsMapper.xml映射文件中添加如下的SQL语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.spzx.manager.mapper.ProductDetailsMapper">

    <insert id="save" useGeneratedKeys="true" keyProperty="id">
        insert into product_details (
        	id,
            product_id,
            image_urls,
            create_time,update_time,is_deleted
        ) values (
            #{id},
            #{productId},
            #{imageUrls},
            now(),
            now(),
            0
        )
    </insert>

</mapper>

1.2 修改功能

1.2.1 需求说明

当用户点击修改按钮的时候,那么此时就弹出对话框,在该对话框的商品表单中回显商品相关数据,此时用户对商品数据进行修改,修改完毕以后点击

提交按钮将表单进行提交,后端服务修改数据库中数据即可。

效果如下所示:

在这里插入图片描述

修改功能实现的时候需要开发两个接口:

1、根据id查询商品详情

2、保存修改数据接口

1.2.2 查询商品详情

ProductController

表现层代码:

// com.atguigu.spzx.manager.controller;
@GetMapping("/getById/{id}")
public Result<Product> getById(@PathVariable Long id) {
    Product product = productService.getById(id);
    return Result.build(product , ResultCodeEnum.SUCCESS) ;
}
ProductService

业务层代码:

// com.atguigu.spzx.manager.service.impl;
@Override
public Product getById(Long id) {

    // 根据id查询商品数据
    Product product = productMapper.selectById(id);

    // 根据商品的id查询sku数据
    List<ProductSku> productSkuList = productSkuMapper.selectByProductId(id);
    product.setProductSkuList(productSkuList);

    // 根据商品的id查询商品详情数据
    ProductDetails productDetails = productDetailsMapper.selectByProductId(product.getId());
    product.setDetailsImageUrls(productDetails.getImageUrls());

    // 返回数据
    return product;
}
ProductMapper

商品持久层代码:

// com.atguigu.spzx.manager.mapper
@Mapper
public interface ProductMapper {
    public abstract Product selectById(Long id);
}
ProductMapper.xml

在ProductMapper.xml文件中添加如下的SQL语句:

<select id="selectById" resultMap="productMap">
    select
        p.id, p.name , p.brand_id , p.category1_id , p.category2_id , p.category3_id, p.unit_name,
        p.slider_urls , p.spec_value , p.status , p.audit_status , p.audit_message , p.create_time , p.update_time , p.is_deleted ,
        b.name brandName , c1.name category1Name , c2.name category2Name , c2.name category3Name
    from product p
        LEFT JOIN brand b on b.id = p.brand_id
        LEFT JOIN category c1 on c1.id = p.category1_id
        LEFT JOIN category c2 on c2.id = p.category2_id
        LEFT JOIN category c3 on c3.id = p.category2_id
    where
    p.id = #{id}
</select>
ProductSkuMapper

商品SKU的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductSkuMapper {
    public abstract List<ProductSku> selectByProductId(Long id);
}
ProductSkuMapper.xml

在ProductSkuMapper.xml映射文件中添加如下的SQL语句:

<resultMap id="productSkuMap" type="com.atguigu.spzx.model.entity.product.ProductSku" autoMapping="true"></resultMap>

<!-- 用于select查询公用抽取的列 -->
<sql id="columns">
    id,sku_code,sku_name,product_id,thumb_img,sale_price,market_price,cost_price,stock_num,sku_spec,weight,volume,status,create_time,update_time,is_deleted
</sql>

<select id="selectByProductId" resultMap="productSkuMap">
    select <include refid="columns" />
    from product_sku
    where product_id = #{productId}
    and is_deleted = 0
    order by id desc
</select>
ProductDetailsMapper

商品详情的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductDetailsMapper {
    public abstract ProductDetails selectByProductId(Long id);
}
ProductDetailsMapper.xml

在ProductDetailsMapper.xml映射文件中添加如下的SQL语句:

<resultMap id="productDetailsMap" type="com.atguigu.spzx.model.entity.product.ProductDetails" autoMapping="true"></resultMap>

<!-- 用于select查询公用抽取的列 -->
<sql id="columns">
    id,product_id,image_urls,create_time,update_time,is_deleted
</sql>

<select id="selectByProductId" resultMap="productDetailsMap">
    select <include refid="columns" />
    from product_details
    where
    product_id = #{productId}
</select>

1.2.3 保存修改数据接口

ProductController

表现层代码:

// com.atguigu.spzx.manager.controller;
@PutMapping("/updateById")
public Result updateById(@Parameter(name = "product", description = "请求参数实体类", required = true) @RequestBody Product product) {
    productService.updateById(product);
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
ProductService

业务层代码:

// com.atguigu.spzx.manager.service.impl;
@Transactional
@Override
public void updateById(Product product) {

    // 修改商品基本数据
    productMapper.updateById(product);

    // 修改商品的sku数据
    List<ProductSku> productSkuList = product.getProductSkuList();
    productSkuList.forEach(productSku -> {
        productSkuMapper.updateById(productSku);
    });

    // 修改商品的详情数据
    ProductDetails productDetails = productDetailsMapper.selectByProductId(product.getId());
    productDetails.setImageUrls(product.getDetailsImageUrls());
    productDetailsMapper.updateById(productDetails);

}
ProductMapper

商品持久层代码:

// com.atguigu.spzx.manager.mapper
@Mapper
public interface ProductMapper {
    public abstract  void updateById(Product product);
}
ProductMapper.xml

在ProductMapper.xml文件中添加如下的SQL语句:

<update id="updateById" >
    update product set
    <if test="name != null and name != ''">
        name = #{name},
    </if>
    <if test="brandId != null and brandId != ''">
        brand_id = #{brandId},
    </if>
    <if test="category1Id != null and category1Id != ''">
        category1_id = #{category1Id},
    </if>
    <if test="category2Id != null and category2Id != ''">
        category2_id = #{category2Id},
    </if>
    <if test="category3Id != null and category3Id != ''">
        category3_id = #{category3Id},
    </if>
    <if test="unitName != null and unitName != ''">
        unit_name = #{unitName},
    </if>
    <if test="sliderUrls != null and sliderUrls != ''">
        slider_urls = #{sliderUrls},
    </if>
    <if test="specValue != null and specValue != ''">
        spec_value = #{specValue},
    </if>
    <if test="status != null and status != ''">
        status = #{status},
    </if>
    <if test="auditStatus != null and auditStatus != ''">
        audit_status = #{auditStatus},
    </if>
    <if test="auditMessage != null and auditMessage != ''">
        audit_message = #{auditMessage},
    </if>
    update_time =  now()
    where
    id = #{id}
</update>
ProductSkuMapper

商品SKU的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductSkuMapper {
    public abstract  void updateById(ProductSku productSku);
}
ProductSkuMapper.xml

在ProductSkuMapper.xml映射文件中添加如下的SQL语句:

<update id="updateById" >
    update product_sku set
    <if test="skuCode != null and skuCode != ''">
        sku_code = #{skuCode},
    </if>
    <if test="skuName != null and skuName != ''">
        sku_name = #{skuName},
    </if>
    <if test="productId != null and productId != ''">
        product_id = #{productId},
    </if>
    <if test="thumbImg != null and thumbImg != ''">
        thumb_img = #{thumbImg},
    </if>
    <if test="salePrice != null and salePrice != ''">
        sale_price = #{salePrice},
    </if>
    <if test="marketPrice != null and marketPrice != ''">
        market_price = #{marketPrice},
    </if>
    <if test="costPrice != null and costPrice != ''">
        cost_price = #{costPrice},
    </if>
    <if test="stockNum != null and stockNum != ''">
        stock_num = #{stockNum},
    </if>
    <if test="skuSpec != null and skuSpec != ''">
        sku_spec = #{skuSpec},
    </if>
    <if test="weight != null and weight != ''">
        weight = #{weight},
    </if>
    <if test="volume != null and volume != ''">
        volume = #{volume},
    </if>
    <if test="status != null and status != ''">
        status = #{status},
    </if>
    update_time =  now()
    where
    id = #{id}
</update>
ProductDetailsMapper

商品详情的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductDetailsMapper {
    public abstract void updateById(ProductDetails productDetails);
}
ProductDetailsMapper.xml

在ProductDetailsMapper.xml映射文件中添加如下的SQL语句:

<update id="updateById" >
    update product_details set
    <if test="productId != null and productId != ''">
        product_id = #{productId},
    </if>
    <if test="imageUrls != null and imageUrls != ''">
        image_urls = #{imageUrls},
    </if>
    update_time =  now()
    where
    id = #{id}
</update>

1.3 删除商品

1.3.1 需求说明

当点击删除按钮的时候此时需要弹出一个提示框,询问是否需要删除数据?如果用户点击是,那么此时向后端发送请求传递id参数,后端接收id参数进

行逻辑删除。

效果如下所示:

在这里插入图片描述

1.3.2 后端接口

ProductController

表现层代码:

// com.atguigu.spzx.manager.controller;
@DeleteMapping("/deleteById/{id}")
public Result deleteById(@Parameter(name = "id", description = "商品id", required = true) @PathVariable Long id) {
    productService.deleteById(id);
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
ProductService

业务层代码:

// com.atguigu.spzx.manager.service.impl;
@Transactional
@Override
public void deleteById(Long id) {
    productMapper.deleteById(id);                   // 根据id删除商品基本数据
    productSkuMapper.deleteByProductId(id);         // 根据商品id删除商品的sku数据
    productDetailsMapper.deleteByProductId(id);     // 根据商品的id删除商品的详情数据
}
ProductMapper

商品持久层代码:

// com.atguigu.spzx.manager.mapper
@Mapper
public interface ProductMapper {
    public abstract void deleteById(Long id);
}
ProductMapper.xml

在ProductMapper.xml文件中添加如下的SQL语句:

<update id="deleteById">
    update product set
    update_time = now() ,
    is_deleted = 1
    where
    id = #{id}
</update>
ProductSkuMapper

商品SKU的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductSkuMapper {
    public abstract void deleteByProductId(Long id);
}
ProductSkuMapper.xml

在ProductSkuMapper.xml映射文件中添加如下的SQL语句:

<update id="deleteByProductId">
    update product_sku set
    update_time = now() ,
    is_deleted = 1
    where
    product_id = #{productId}
</update>
ProductDetailsMapper

商品详情的持久层代码:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface ProductDetailsMapper {
    public abstract void deleteByProductId(Long id);
}
ProductDetailsMapper.xml

在ProductDetailsMapper.xml映射文件中添加如下的SQL语句:

<update id="deleteByProductId">
    update product_details set
    update_time = now() ,
    is_deleted = 1
    where
    product_id = #{productId}
</update>

1.4 商品审核

1.4.1 需求说明

当点击审核按钮的时候此时需要弹出一个对话框,在该对话框中展示商品的详情信息,用户可以在该对话框中点击通过或者驳回按钮对商品进行审核操

作。

效果如下所示:

在这里插入图片描述

1.4.2 后端接口

ProductController

表现层代码:

// com.atguigu.spzx.manager.controller;
@GetMapping("/updateAuditStatus/{id}/{auditStatus}")
public Result updateAuditStatus(@PathVariable Long id, @PathVariable Integer auditStatus) {
    productService.updateAuditStatus(id, auditStatus);
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
ProductService

业务层代码:

// com.atguigu.spzx.manager.service.impl;
@Override
public void updateAuditStatus(Long id, Integer auditStatus) {
    Product product = new Product();
    product.setId(id);
    if(auditStatus == 1) {
        product.setAuditStatus(1);
        product.setAuditMessage("审批通过");
    } else {
        product.setAuditStatus(-1);
        product.setAuditMessage("审批不通过");
    }
    productMapper.updateById(product);
}

1.5 商品上下架

1.5.1 需求说明

当用户点击上架按钮的时候对商品进行上架操作,点击下架按钮的时候对商品进行下架操作。

实现思路:更改商品的上下架状态

效果如下所示:

在这里插入图片描述

1.5.2 后端接口

ProductController

表现层代码:

// com.atguigu.spzx.manager.controller;
@GetMapping("/updateStatus/{id}/{status}")
public Result updateStatus(@PathVariable Long id, @PathVariable Integer status) {
    productService.updateStatus(id, status);
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}
ProductService

业务层代码:

// com.atguigu.spzx.manager.service.impl;
@Override
public void updateStatus(Long id, Integer status) {
    Product product = new Product();
    product.setId(id);
    if(status == 1) {
        product.setStatus(1);
    } else {
        product.setStatus(-1);
    }
    productMapper.updateById(product);
}

2 订单管理

用户在前台系统中购买完商品以后生成对应的订单统计数据,在后台管理系统中就可以查看到订单数据,在后台管理系统中也可以对订单数据进行统计,形成图形化报表【柱状图、饼状图、曲线图、散点图…】用于数据分析。

2.1 订单数据统计需求说明

需求说明:统计指定时间段每一天订单的总金额,并且以柱状图的形式进行展示。

效果如下所示:

在这里插入图片描述

2.2 Echarts

要想将统计的数据以图表的方式进行展示,那么就需要使用到一些图形报表工具。常见的图形报表工具:Echarts

2.2.1 Echarts简介

官网地址:https://echarts.apache.org/zh/index.html

在这里插入图片描述

Echarts是一个基于JavaScript的开源可视化图表库,由百度前端开发团队研发和维护。它提供了丰富的图表类型、数据统计分析、动态数据更新、多

维数据展示等功能,可以帮助开发人员在 Web 应用、大屏展示、移动端等各种场景下,快速构建出高度定制化的交互式可视化图表。

Echarts支持多种图表类型,如线图、柱状图、饼图、雷达图、散点图等,还支持动态数据显示、图表联动、混搭图表等复杂功能。同时,ECharts还支持多种数据格式、数据预处理和自定义附加组件等扩展功能,让用户能够方便地实现各种需求和定制化要求。

ECharts易于上手,提供了丰富的API,以及完善的文档和示例,使得开发人员可以更快速、更便捷地使用它来进行数据可视化。

2.2.2 Echarts入门

需求:使用Echarts的柱状图展示每一天的商品的订单总金额。

效果如下所示:在这里插入图片描述

实现步骤:

1、安装Echarts,官网地址:https://echarts.apache.org/handbook/zh/basics/import

npm install echarts --save

2、添加订单管理菜单

通过系统管理的菜单管理,添加订单管理菜单,如下所示:

在这里插入图片描述

给管理员角色分配订单管理访问权限如下所示:

在这里插入图片描述

在src/views目录下创建orderStatistics.vue文件,如下所示:

在这里插入图片描述

在src/router/modules目录下创建order.js文件,配置路由:

const Layout = () => import('@/layout/index.vue')
const orderStatistics = () => import('@/views/order/orderStatistics.vue')

export default [
    {
      path: '/order',
      component: Layout,
      name: 'order',
      meta: {
        title: '订单管理',
      },
      icon: 'Operation',
      children: [
            {
            path: '/orderStatistics',
            name: 'orderStatistics',
            component: orderStatistics,
            meta: {
                title: '订单统计',
            },
            }
        ],
    },
  ]

在src/router/index.js中添加订单管理路由:

import order from './modules/order'

// 动态菜单
export const asyncRoutes = [...system,...base,...product,...order]

3、参考官方文档示例代码,完成入门案例,代码如下所示:

<template>
    <div ref="orderTotalAmountDiv" style="width: 100%; height: 100%;"></div>
</template>

<script setup>
import { ref , onMounted } from 'vue'
import * as echarts from 'echarts';         // 导入Echart库中所有的图形报表组件

// 定义chart数据模型,用来选中div组件
const orderTotalAmountDiv = ref() 

// 需要在onMounted钩子函数中对div区域使用echarts进行初始化
onMounted( () => {

    // 基于准备好的dom,初始化echarts实例
    var orderTotalAmountChart = echarts.init(orderTotalAmountDiv.value);

    // 绘制图表
    orderTotalAmountChart.setOption({
        title: {
            text: '订单数据统计'
        },
        tooltip: {},
        xAxis: {
            data: ['2023-06-01', '2023-06-02', '2023-06-03', '2023-06-04', '2023-06-05', '2023-06-06']
        },
        yAxis: {},
        series: [
            {
                name: '订单总金额(万元)',
                type: 'bar',
                data: [20, 40, 30, 100, 50, 25]
            }
        ]
	});

})

</script>

<style scoped>

</style>

其他的常见的配置项以及属性介绍可以参看官方文档:https://echarts.apache.org/zh/option.html#tooltip.axisPointer

2.3 订单相关数据库表介绍

要进行订单数据的统计,首先就需要了解一下和订单相关的数据库表,如下所示:

-- 订单信息表
CREATE TABLE `order_info` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
  `user_id` bigint NOT NULL DEFAULT '0' COMMENT '会员_id',
  `nick_name` varchar(200) DEFAULT NULL COMMENT '昵称',
  `order_no` char(64) NOT NULL DEFAULT '' COMMENT '订单号',
  `coupon_id` bigint DEFAULT NULL COMMENT '使用的优惠券',
  `total_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单总额',
  `coupon_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠券',
  `original_total_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '原价金额',
  `feight_fee` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '运费',
  `pay_type` tinyint DEFAULT NULL COMMENT '支付方式【1->微信】',
  `order_status` tinyint NOT NULL DEFAULT '0' COMMENT '订单状态【0->待付款;1->待发货;2->已发货;3->待用户收货,已完成;-1->已取消】',
  `receiver_name` varchar(100) DEFAULT NULL COMMENT '收货人姓名',
  `receiver_phone` varchar(32) DEFAULT NULL COMMENT '收货人电话',
  `receiver_post_code` varchar(32) DEFAULT NULL COMMENT '收货人邮编',
  `receiver_province` bigint DEFAULT NULL COMMENT '省份/直辖市',
  `receiver_city` bigint DEFAULT NULL COMMENT '城市',
  `receiver_district` bigint DEFAULT NULL COMMENT '区',
  `receiver_address` varchar(200) DEFAULT NULL COMMENT '详细地址',
  `payment_time` datetime DEFAULT NULL COMMENT '支付时间',
  `delivery_time` datetime DEFAULT NULL COMMENT '发货时间',
  `receive_time` datetime DEFAULT NULL COMMENT '确认收货时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '订单备注',
  `cancel_time` datetime DEFAULT NULL COMMENT '取消订单时间',
  `cancel_reason` varchar(255) DEFAULT NULL COMMENT '取消订单原因',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记(0:不可用 1:可用)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=165 DEFAULT CHARSET=utf8mb3 COMMENT='订单';

-- 订单明细表
CREATE TABLE `order_item` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
  `order_id` bigint DEFAULT NULL COMMENT 'order_id',
  `sku_id` bigint DEFAULT NULL COMMENT '商品sku编号',
  `sku_name` varchar(255) DEFAULT NULL COMMENT '商品sku名字',
  `thumb_img` varchar(500) DEFAULT NULL COMMENT '商品sku图片',
  `sku_price` decimal(10,2) DEFAULT NULL COMMENT '商品sku价格',
  `sku_num` int DEFAULT NULL COMMENT '商品购买的数量',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记(0:不可用 1:可用)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=364 DEFAULT CHARSET=utf8mb3 COMMENT='订单项信息';

注意:订单和订单明细之间的关系是一对多

2.4 订单数据统计实现思路

在入门案例中展示柱状图所需要的数据是假数据,现在就需要将数据换成真实统计数据。

数据统计的实现方案:

方案一:每一次展示数据的时候都从订单数据库中进行一次统计查询,对应的SQL语句如下所示

select DATE_FORMAT(oi.create_time ,'%Y-%m-%d') date , sum(oi.total_amount)  totalAmount from order_info oi GROUP BY DATE_FORMAT(oi.create_time ,'%Y-%m-%d');

弊端:在进行分组查询时,如果数据量较大,直接进行分组查询的效率会受到一定影响,因为需要对所有数据进行聚合计算,耗费时间和资源。

方案二:将分组结果计算好,写入到一张数据统计结果表中,然后从该表中直接查询统计以后的结果数据,不需要进行额外的计算,提高了查询效率。

实现思路如下图所示:

在这里插入图片描述

流程说明:

1、定时任务程序每天凌晨2点运行一次,从order_info表中查询出前一天的订单总金额数据,然后将总金额数据写入到统计结果表中

2、当用户发起查询订单统计结果请求的时候,此时后端系统从统计结果表中查询到对应的数据返回给前端系统

3、前端系统通过Echarts的柱状图展示数据

2.5 Spring Task

2.5.1 Spring Task简介

官网地址:https://docs.spring.io/spring-framework/reference/6.1-SNAPSHOT/integration/scheduling.html

Spring Task是Spring框架中的一个定时任务调度模块,它提供了一种简单的方式来实现基于时间的调度任务。

使用Spring Task,可以通过Java代码配置或注解的方式定义定时任务,并设置任务的执行时间、间隔周期、触发条件等。当达到指定的时间或条件

时,Spring Task会自动触发任务的执行,可以执行任何有意义的操作,例如数据备份、缓存清理、邮件发送等。

Spring Task还具有以下特点:

1、简单易用:简单的XML或注解配置即可实现定时任务调度。

2、易于集成:与Spring框架集成无缝,支持Spring Boot应用快速启动。

3、可靠性高:支持在分布式环境下进行任务调度,并支持并发控制和异常管理。

4、监控调试:支持日志记录、任务执行状态监控和调试,方便排除问题。

总之,Spring Task是一种非常有效和灵活的定时任务调度方案,适用于各种规模的Web应用和后台系统。

2.5.2 Spring Task入门案例

需求:每5秒在控制台输出一次"HelloWorld"

代码实现:

1、定义一个任务方法,在该方法上使用**@Scheduled**注解,并通常cron属性来指定该方法的执行的时间规则

@Component
@Slf4j
public class OrderStatisticsTask {

    @Scheduled(cron = "0/5 * * * * ?")  // 定义定时任务,使用@Scheduled注解指定调度时间表达式
    public void helloWorldTask() {
        log.info("HelloWorld");
    }

}

2、在启动类上添加**@EnableScheduling**注解开启定时任务功能

...
@EnableScheduling
public class ManagerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ManagerApplication.class , args) ;
    }

}

启动程序进行测试。

2.5.3 cron表达式

cron表达式

定时任务触发时间的一个字符串表达形式,分为6或7个域,每一个域代表一个含义。

cron的结构从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份

这些字段的取值范围如下所示:

字段允许的值允许的特殊字符
秒(Seconds)0-59, - * /
分(Minutes)0-59, - * /
时(Hours)0-23, - * /
日(DayofMonth)1-31, - * ? / L W
月(Month)1-12 or JAN-DEC, - * /
周(DayofWeek)0-6 or SUN-SAT (0表示星期天), - * ? / L #
年(Year)留空或1970-2099, - * /

注:如日和月同时维护,例如:3 50 18 15 2 4,需要注意二月的星期四,不一定是15号,此时星期和日是有冲突的,通常需要舍掉一个,被舍掉的参数用**?**占位

Cron表达式的时间字段除允许设置数值外,还可使用一些特殊的字符,提供列表、范围、通配符等功能。

可查看阿里云开发者社区手册:https://developer.aliyun.com/article/942392

2.6 订单数据统计

2.6.1 数据库表介绍

统计数据结果表结构如下所示:

CREATE TABLE `order_statistics` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `order_date` date DEFAULT NULL COMMENT '订单统计日期',
  `total_amount` decimal(10,2) DEFAULT NULL COMMENT '总金额',
  `total_num` int DEFAULT NULL COMMENT '订单总数',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记(0:不可用 1:可用)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=191 DEFAULT CHARSET=utf8mb3 COMMENT='订单统计';

2.6.3 代码实现

OrderStatistics

创建一个与订单统计结果表相对应的实体类:

// com.atguigu.spzx.model.entity.order;
@Data
public class OrderStatistics extends BaseEntity {

    private Date orderDate;
    private BigDecimal totalAmount;
    private Integer totalNum;
    
}
OrderInfo

创建一个与订单数据库表对应的实体类:

// com.atguigu.spzx.model.entity.order;
@Data
@Schema(description = "OrderInfo")
public class OrderInfo extends BaseEntity {

	private Long userId;
	private String nickName;
	private String orderNo;
	private Long couponId;
	private BigDecimal totalAmount;
	private BigDecimal couponAmount;
	private BigDecimal originalTotalAmount;
	private BigDecimal feightFee;
	private Integer payType;
	private Integer orderStatus;
	private String receiverName;
	private String receiverPhone;
	private String receiverTagName;
	private String receiverProvince;
	private String receiverCity;
	private String receiverDistrict;
	private String receiverAddress;
	private Date paymentTime;
	private Date deliveryTime;
	private Date receiveTime;
	private String remark;
	private Date cancelTime;
	private String cancelReason;

}
OrderStatisticsTask

定时任务程序代码实现:

// com.atguigu.spzx.manager.task
@Component
@Slf4j
public class OrderStatisticsTask {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderStatisticsMapper orderStatisticsMapper;

    @Scheduled(cron = "0 0 2 * * ?")
    public void orderTotalAmountStatistics() {
        String createTime = DateUtil.offsetDay(new Date(), -1).toString(new SimpleDateFormat("yyyy-MM-dd"));
        OrderStatistics orderStatistics = orderInfoMapper.selectOrderStatistics(createTime);
        if(orderStatistics != null) {
            orderStatisticsMapper.insert(orderStatistics) ;
        }
    }

}
OrderInfoMapper

OrderInfo持久层代码

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface OrderInfoMapper {

    // 查询指定日期产生的订单数据
    public abstract OrderStatistics selectOrderStatistics(String creatTime);

}
OrderInfoMapper.xml

在OrderInfoMapper.xml映射文件中添加如下的SQL语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.spzx.manager.mapper.OrderInfoMapper">

    <select id="selectOrderStatistics" resultType="com.atguigu.spzx.model.entity.order.OrderStatistics">
        select DATE_FORMAT(oi.create_time ,'%Y-%m-%d') orderDate, sum(oi.total_amount)  totalAmount , count(oi.id) totalNum
        from order_info oi where DATE_FORMAT(oi.create_time ,'%Y-%m-%d') = #{createTime}
        GROUP BY DATE_FORMAT(oi.create_time ,'%Y-%m-%d')
    </select>

</mapper>
OrderStatisticsMapper

OrderStatisticsMapper持久层代码

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface OrderStatisticsMapper {

    public abstract void insert(OrderStatistics orderStatistics);

}
OrderStatisticsMapper.xml

在OrderStatisticsMapper.xml映射文件中添加如下的SQL语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.spzx.manager.mapper.OrderStatisticsMapper">

    <!-- 用于select查询公用抽取的列 -->
    <sql id="columns">
        id,order_date,total_amount,total_num,create_time,update_time,is_deleted
    </sql>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into order_statistics (
            id,
            order_date,
            total_amount,
            total_num
        ) values (
             #{id},
             #{orderDate},
             #{totalAmount},
             #{totalNum}
         )
    </insert>

</mapper>

2.7 统计查询

2.7.1 后端接口

OrderStatisticsDto

创建封装查询参数的实体类:

// com.atguigu.spzx.model.dto.order;
@Data
public class OrderStatisticsDto {

    private String createTimeBegin;
    private String createTimeEnd;

}
OrderStatisticsVo

创建封装响应结果的实体类:

// com.atguigu.spzx.model.vo.order;
@Data
public class OrderStatisticsVo {

    private List<String> dateList ;
    private List<BigDecimal> amountList ;
}
OrderInfoController

表现层代码实现:

// com.atguigu.spzx.manager.controller;
@RestController
@RequestMapping(value="/admin/order/orderInfo")
public class OrderInfoController {

    @Autowired
    private OrderInfoService orderInfoService ;

    @GetMapping("/getOrderStatisticsData")
    public Result<OrderStatisticsVo> getOrderStatisticsData( OrderStatisticsDto orderStatisticsDto) {
        OrderStatisticsVo orderStatisticsVo = orderInfoService.getOrderStatisticsData(orderStatisticsDto) ;
        return Result.build(orderStatisticsVo , ResultCodeEnum.SUCCESS) ;
    }

}
OrderInfoService

业务层代码实现:

// com.atguigu.spzx.manager.service.impl;
@Service
public class OrderInfoServiceImpl implements OrderInfoService {

    @Autowired
    private OrderStatisticsMapper orderStatisticsMapper ;

    @Override
    public OrderStatisticsVo getOrderStatisticsData(OrderStatisticsDto orderStatisticsDto) {

        // 查询统计结果数据
        List<OrderStatistics> orderStatisticsList = orderStatisticsMapper.selectList(orderStatisticsDto) ;

        //日期列表
        List<String> dateList = orderStatisticsList.stream().map(orderStatistics -> DateUtil.format(orderStatistics.getOrderDate(), "yyyy-MM-dd")).collect(Collectors.toList());

        //统计金额列表
        List<BigDecimal> amountList = orderStatisticsList.stream().map(OrderStatistics::getTotalAmount).collect(Collectors.toList());

        // 创建OrderStatisticsVo对象封装响应结果数据
        OrderStatisticsVo orderStatisticsVo = new OrderStatisticsVo() ;
        orderStatisticsVo.setDateList(dateList);
        orderStatisticsVo.setAmountList(amountList);

        // 返回数据
        return orderStatisticsVo;
    }
}
OrderStatisticsMapper

持久层代码实现:

// com.atguigu.spzx.manager.mapper;
@Mapper
public interface OrderStatisticsMapper {
    List<OrderStatistics> selectList(OrderStatisticsDto orderStatisticsDto);
}
OrderStatisticsMapper.xml

在OrderStatisticsMapper.xml映射文件中添加如下的sql语句:

<resultMap id="orderStatisticsMap" type="com.atguigu.spzx.model.entity.order.OrderStatistics" autoMapping="true"></resultMap>

<select id="selectList" resultMap="orderStatisticsMap">
    select <include refid="columns" />
    from order_statistics
    <where>
        <if test="createTimeBegin != null and createTimeBegin != ''">
            and order_date >= #{createTimeBegin}
        </if>
        <if test="createTimeEnd != null and createTimeEnd != ''">
            and order_date &lt;= #{createTimeEnd}
        </if>
    </where>
    order by order_date
</select>

2.7.2 前端对接

导入课程资料中所提供的orderInfo.js和orderStatistics.vue到指定的目录下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1486846.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt 简约美观的动画 摆钟风格 第十季

&#x1f60a; 今天给大家分享一个摆钟风格的加载动画 &#x1f60a; 效果如下: 最近工作忙起来了 , 后续再分享其他有趣的加载动画吧. 一共三个文件 , 可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <Q…

构建安全的REST API:OAuth2和JWT实践

引言 大家好&#xff0c;我是小黑&#xff0c;小黑在这里跟咱们聊聊&#xff0c;为什么REST API这么重要&#xff0c;同时&#xff0c;为何OAuth2和JWT在构建安全的REST API中扮演着不可或缺的角色。 想象一下&#xff0c;咱们每天都在使用的社交媒体、在线购物、银行服务等等…

Spring框架精髓:带你手写IoC

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

C语言之OJ刷题

今天刷一下题 刷的不多 第一道 链表的回文结构 仔细看这个题它是有限制条件的 首先是时间复杂度和空间复杂度 所以我们并不是用数组去做 但怎么做呢&#xff1f; 思路 既然是判断是否是回文结构&#xff0c;那么我们就找一下他的中间节点 然后将后半段倒置 进行比较…

【简说八股】Redisson的守护线程是怎么实现的

Redisson Redisson 是一个 Java 语言实现的 Redis SDK 客户端&#xff0c;在使用分布式锁时&#xff0c;它就采用了「自动续期」的方案来避免锁过期&#xff0c;这个守护线程我们一般也把它叫做「看门狗」线程。 Redission是一个在Java环境中使用的开源的分布式缓存和分布式锁实…

C2远控Loader红队技巧

inlineHook技术(钩子技术) MessageBoxA C自带弹窗函数 test_MessageBoxA 代码中自定义函数 InlineHook技术&#xff1a;testA原本插入jmp指令跳转到testB&#xff0c;实现testB自定义的函数 实现方式&#xff1a;X86&#xff1a; // 方式一&#xff0c;使用jmp相对地址跳转…

基于springboot音乐翻唱与分享平台源码和论文

1.1研究背景 随着网络不断的普及发展&#xff0c;音乐网站与分享平台依靠网络技术的支持得到了快速的发展&#xff0c;首先要从用户的实际需求出发&#xff0c;通过了解用户的需求开发出具有针对性的首页、音乐资讯、音乐翻唱、在线听歌、留言反馈、个人中心、后台管理、客服功…

ABAP - SALV教程16 合计、小计

虽然ALV的标准状态栏功能就能实现合计、小计、平均值、最大值等这些功能&#xff0c;但用户更希望一进去ALV就希望ALV已经对数量&#xff0c;金额的字段进行合计&#xff0c;小计。SALV实现合计&#xff0c;调用CL_SALV_AGGREGATIONS的ADD_AGGREGATION即可 DATA(lo_aggrs) …

[数据结构]链表OJ--环形链表判断是否有环(快慢指针法)

141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 这里我采用的是快慢指针法,这是我认为最容易理解的方法,这个方法的思路是这样的. 我们可以定义两个指针一个快一个慢,如果这个链表有环,则快慢指针一定会相遇. 这里我画图举个例子: 我们很明显的可以看出,有环链表,快指…

成功解决git clone遇到的error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush af

成功解决git clone遇到的error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush af 问题描述解决方案 问题描述 用git的时候可能会遇到这个问题&#xff1a; (base) zhouzikang7443-8x4090-120:~/project$ git clone https://github.com/123/12…

Outlook邮箱IMAP密码怎么填写?账户设置?

Outlook邮箱IMAP密码是什么&#xff1f;Outlook如何设置IMAP&#xff1f; 许多用户会选择通过IMAP协议将邮箱与各种邮件客户端进行连接。而在设置过程中&#xff0c;填写IMAP密码是必不可少的一步。那么&#xff0c;Outlook邮箱的IMAP密码应该如何填写呢&#xff1f;接下来&am…

Matlab 最小二乘插值(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 在多项式插值时,当数据点个数较多时,插值会导致多项式曲线阶数过高,带来不稳定因素。因此我们可以通过固定幂基函数的最高次数 m(m < n),来对我们要拟合的曲线进行降阶。之前的函数形式就可以变为: 二、实现…

【硬件工程师面经整理13_电容电阻电感等效电路】

1 电容/电阻/电感的等效电路 ①电容的等效电路是由一个电容和一个电阻组成的&#xff0c;其中电阻称为ESR&#xff08;Equivalent Series Resistance&#xff0c;等效串联电阻&#xff09;。在真实情况下&#xff0c;一个电容会被表示成由“一个电容一个电阻一个电感”组合而成…

冒泡排序 和 qsort排序

目录 冒泡排序 冒泡排序部分 输出函数部分 主函数部分 总代码 控制台输出显示 总代码解释 冒泡排序优化 冒泡排序 主函数 总代码 代码优化解释 qsort 排序 qsort 的介绍 使用qsort排序整型数据 使用qsort排序结构数据 冒泡排序 首先&#xff0c;我先介绍我的冒泡…

解决虚拟机启动报错:“End kernel panic - not syncing: attempted to kill the idle task”

原本能正常运行的虚拟机&#xff0c;很长一段时间没用后&#xff0c;今天再次启动&#xff0c;然后就出现下面的问题&#xff1a; 然后走了一些弯路&#xff0c;比如说删除该虚拟机然后新建一个虚拟机&#xff08;问题未解决&#xff09;、直接删除VitualBox重新安装&#xff0…

wordpress外贸独立站

WordPress外贸电商主题 简洁实用的wordpress外贸电商主题&#xff0c;适合做外贸跨境的电商公司官网使用。 https://www.jianzhanpress.com/?p5025 华强北面3C数码WordPress外贸模板 电脑周边、3C数码产品行业的官方网站使用&#xff0c;用WordPress外贸模板快速搭建外贸网…

计算机指令、指令跳转原理

文章目录 前言存储程序型计算机代码怎么变成机器码&#xff1f;解析指令和机器码CPU 是如何执行指令的&#xff1f;CPU中的寄存器 if…else 来看程序的执行和跳转分析 通过 if…else 和 goto 来实现循环 前言 大家好我是jiantaoyab&#xff0c;这是我所总结作为学习的笔记第三篇…

最新版风车IM通讯iosapph5三端源码及视频教程

最新版风车IM通讯iosapph5三端源码及视频教程 1.宝塔环境如下: Nginx 1.20 Tomcat 8 MySQL 8.0 Redis 7 2.放行端口如下&#xff1a; 666 6600 6700 7000&#xff08;用作前端&#xff09; 7001&#xff08;用作后端&#xff09; 3.宝塔数据库添加数据库旁边有个ro…

【大厂AI课学习笔记NO.62】模型的部署

我们历尽千辛万苦&#xff0c;总算要部署模型了。这个系列也写到62篇&#xff0c;不要着急&#xff0c;后面还有很多。 这周偷懒了&#xff0c;一天放出太多的文章&#xff0c;大家可能有些吃不消&#xff0c;从下周开始&#xff0c;本系列将正常更新。 这套大厂AI课&#xf…

随机背景个人引导页源码

随机背景个人引导页源码&#xff0c;每五秒进行淡进淡出切换背景图片&#xff0c;适合作为个人引导页。喜欢的朋友拿去吧 下载地址 https://www.qqmu.com/2357.html