热销商品排行

image-20230811225640333

image-20230811225700167

商品数据库创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE TABLE t_product (
id int(20) NOT NULL COMMENT '商品id',
category_id int(20) DEFAULT NULL COMMENT '分类id',
item_type varchar(100) DEFAULT NULL COMMENT '商品系列',
title varchar(100) DEFAULT NULL COMMENT '商品标题',
sell_point varchar(150) DEFAULT NULL COMMENT '商品卖点',
price bigint(20) DEFAULT NULL COMMENT '商品单价',
num int(10) DEFAULT NULL COMMENT '库存数量',
image varchar(500) DEFAULT NULL COMMENT '图片路径',
status int(1) DEFAULT '1' COMMENT '商品状态 1:上架 2:下架 3:删除',
priority int(10) DEFAULT NULL COMMENT '显示优先级',
created_time datetime DEFAULT NULL COMMENT '创建时间',
modified_time datetime DEFAULT NULL COMMENT '最后修改时间',
created_user varchar(50) DEFAULT NULL COMMENT '创建人',
modified_user varchar(50) DEFAULT NULL COMMENT '最后修改人',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

商品实体类的创建

com.bang.store.pojo包下新建Product实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.bang.store.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 商品对应实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product extends BasePojo{
Integer id;
Integer category_id;
String item_type;
String title;
String sell_point;
Long price;
Integer num;
String image;
Integer status;
Integer priority;

}

持久层

规划执行的SQL语句

热销商品展示,本质是查询语句,根据优先级对所有已上架的商品进行排序,选取优先级最高的四条记录在页面进行展示

1
select * from t_product where status=1 order by priority DESC limit 0,4;

接口和抽象方法

新建商品持久层接口ProductMapper,在其中编写对应的抽象方法

1
2
3
4
5
6
7
8
9
10
/**
* 商品持久层接口
*/
public interface ProductMapper {
/**
* 查询热销商品前四位
* @return 前四位热销商品数据列表
*/
List<Product> findHotProductList();
}

SQL映射文件配置

resource/mapper文件夹下创建映射文件ProductMapper.xml,编写对应SQL映射语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bang.store.mapper.ProductMapper">

<resultMap id="productPojoMap" type="com.bang.store.pojo.Product">
<id column="id" property="id"/>
<result column="category_id" property="categoryId"/>
<result column="item_type" property="itemType"/>
<result column="sell_point" property="sellPoint"/>
<result column="created_time" property="createdTime"/>
<result column="modified_time" property="modifiedTime"/>
<result column="created_user" property="createdUser"/>
<result column="modified_user" property="modifiedUser"/>
</resultMap>

<select id="findHotProductList" resultMap="productPojoMap">
select * from t_product where status=1 order by priority DESC limit 0,4;
</select>

</mapper>

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.bang.store.mapper;

import com.bang.store.pojo.Product;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;
import java.util.List;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class ProductMapperTest {

@Resource
ProductMapper productMapper;
@Test
public void findHotProductList(){
List<Product> productList = productMapper.findHotProductList();
for (Product product : productList) {
System.out.println(product);
}
}
}

业务层

规划异常

无明显异常

接口和抽象方法

新建商品业务层接口IProductService,在其中申明对应的抽象方法

1
2
3
4
5
6
7
public interface IProductService {
/**
* 查询返回热销商品的前四条数据列表
* @return
*/
List<Product> findHotProducts();
}

抽象方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.bang.store.service.impl;

import com.bang.store.mapper.ProductMapper;
import com.bang.store.pojo.Product;
import com.bang.store.service.IProductService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class ProductServiceImpl implements IProductService {

@Resource
ProductMapper productMapper;
@Override
public List<Product> findHotProducts() {
List<Product> hotProductList = productMapper.findHotProductList();
//前端页面只需要id、title、price和image四个字段,
//为了减小数据传输带宽消耗,可以将其他字段设置为null
//这里为了便利,我们不做此处理
return hotProductList;
}
}

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.bang.store.service;


import com.bang.store.pojo.Product;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class ProductServiceTest {

@Autowired
IProductService productService;
@Test
public void hotProductList(){
List<Product> hotProducts = productService.findHotProducts();
for (Product hotProduct : hotProducts) {
System.out.println(hotProduct);
}
}
}

控制层

异常处理

业务层无新增异常,所以控制层无新增异常处理逻辑

设计请求

1
2
3
4
request url: /product
request method: GET
request params: null
response data: new JsonResult<List<Product>>

处理请求

创建商品控制层类ProductController,继承于控制层基类BaseController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.bang.store.controller;

import com.bang.store.pojo.Product;
import com.bang.store.service.IProductService;
import com.bang.store.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/product")
public class ProductController extends BaseController{
@Autowired
IProductService productService;
@RequestMapping({"/",""})
public JsonResult<List<Product>> findHotProducts(){
List<Product> hotProducts = productService.findHotProducts();
return new JsonResult<>(OK,"热销商品数据获取成功",hotProducts);
}
}

前端页面

index.html页面一加载,就像后端发送请求,获取热销商品数据并展示在前端页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<script>
$(document).ready(function (){
showHotList();
});

function showHotList() {
$.ajax({
url: "/product/"
,type: "GET"
,success: function (data){
if(data.state == 200){
alert("热销商品数据获取成功");
//将数据展示在对应的页面
//清空原始页面
$("#hot-list").empty();
let hotProducts = data.data;
for(let i=0;i<hotProducts.length;i++){
let htmlContent = "<div class=\"col-md-12\">\n" +
"<div class=\"col-md-7 text-row-2\"><a href=\"product.html?id#{id}\">#{title}</a></div>\n" +
"<div class=\"col-md-2\">¥#{price}</div>\n" +
"<div class=\"col-md-3\"><img src=../#{image}/collect.png class=\"img-responsive\" /></div>\n" +
"</div>"
htmlContent = htmlContent.replace("#{title}",hotProducts[i].title);
htmlContent = htmlContent.replace("#{price}",hotProducts[i].price);
htmlContent = htmlContent.replace("#{image}","../"+hotProducts[i].image);
$("#hot-list").append(htmlContent);
}
}else{
alert("热销商品数据获取失败 "+data.message);
}
}
,error:function (xmh){
alert("热销商品数据获取发生未知错误"+xmh.status);
}
});
}
</script>

热销商品详情展示

用户点击热销商品列表中的某个商品名,即跳转到对应的商品详情页

热销商品列表页和商品详情页之间的关联,通过<a href=\"product.html?id#{id}\">#{title}</a>进行关联

持久层

规划执行的SQL语句

根据用户点击商品id查询对应的商品信息

1
select * from t_product where id=?;

接口和抽象方法

ProductMapper接口中编写对应抽象方法

1
2
3
4
5
6
/**
* 根据id查询商品信息数据
* @param id 商品id
* @return 商品数据对象
*/
Product findById(Integer id);

SQL映射文件配置

1
2
3
<select id="findById" resultMap="productPojoMap">
select * from t_product where id=#{id};
</select>

单元测试

1
2
3
4
5
@Test
public void findById(){
Product product = productMapper.findById(10000017);
System.out.println(product);
}

业务层

规划异常

查询时,数据库中可能不存在该商品信息,此时应触发ProductNotFoundException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.bang.store.service.ex;

public class ProductNotFoundException extends ServiceException{
public ProductNotFoundException() {
super();
}

public ProductNotFoundException(String message) {
super(message);
}

public ProductNotFoundException(String message, Throwable cause) {
super(message, cause);
}

public ProductNotFoundException(Throwable cause) {
super(cause);
}

protected ProductNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

接口和抽象方法

IProductAddress中编写对应抽象方法

1
2
3
4
5
6
/**
* 根据id查询商品数据
* @param id 商品id
* @return 商品数据
*/
Product getById(Integer id);

抽象方法实现

1
2
3
4
5
6
7
8
@Override
public Product getById(Integer id) {
Product product = productMapper.findById(id);
if(product==null){
throw new ProductNotFoundException("商品不存在异常");
}
return product;
}

单元测试

1
2
3
4
5
@Test
public void getById(){
Product product = productService.getById(10000017);
System.out.println(product);
}

控制层

异常处理

业务层新增ProductNotFound异常,需要在控制层基类BaseController中添加对应的异常处理逻辑

1
2
3
4
else if (e instanceof ProductNotFoundException) {
result.setState(8000);
result.setMessage("商品不存在");
}

设计请求

1
2
3
4
request url: /address/{id}
request method: GET
request params: Integer id
response data: new JsonResult<Product>

处理请求

1
2
3
4
5
@RequestMapping("/{id}")
public JsonResult<Product> getById(@PathVariable("id") Integer id){
Product product = productService.getById(id);
return new JsonResult<>(OK,"商品数据获取成功",product);
}

前端页面

通过$.getUrlParam("id")获取传递的参数值(商品堵塞id)

需要引入相关的库文件

1
<script type="text/javascript" src="../js/jquery-getUrlParam.js"></script>
1
let id =$.getUrlParam("id");

编写商品数据加载代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<script>
$(document).ready(function (){
//解析url传递的参数值
let id =$.getUrlParam("id");
showProduct(id);
});

function showProduct(id) {
$.ajax({
url: "/product/"+id
,type: "GET"
,success: function (data){
if(data.state == 200){
alert("商品数据获取成功");
//将数据展示在对应的页面
$("#product-title").html(data.data.title);
$("#product-sell-point").html(data.data.sellPoint);
$("#product-price").html(data.data.price);
//图片属性
for(let i=1;i<=5;i++){
$("#product-image-"+i).attr("src",".."+data.data.image+i+".jpg")
$("#product-image-"+i+"-big").attr("src",".."+data.data.image+i+"_big.png")
}

}else{
alert("商品数据获取失败 "+data.message);
}
}
,error:function (xmh){
alert("商品数据获取发生未知错误"+xmh.status);
}
});
}
</script>