2019_07_08stor热销商品的添加和购物车 第九天

博客详细介绍了电商系统中主页热销排行、商品查看详情、购物车等模块的开发。涵盖实体类、持久层、业务层、控制器层和前端界面的开发步骤,包括 SQL 规划、接口与抽象方法创建、配置映射、异常处理、请求设计与处理等内容。

49. 主页-热销排行-实体类

创建cn.tedu.store.entity.Product实体类,继承自BaseEntity

/**
 * 商品数据的实体类
 */
public class Product extends BaseEntity {

	private static final long serialVersionUID = -199568590252555336L;

	private Integer id;
	private Integer categoryId;
	private String itemType;
	private String title;
	private String sellPoint;
	private Long price;
	private Integer num;
	private Integer status;
	private String image;
	private Integer priority;

	// ...

}

50. 主页-热销排行-持久层

(a) SQL

应该按照数据的priority降序排列,取出排名最靠前的4样商品,则:

select * from t_product order by priority desc limit 0, 4

(b) 接口与抽象方法

创建cn.tedu.store.mapper.ProductMapper接口,声明抽象方法:

List<Product> findHotList();

© 配置映射

复制得到ProductMapper.xml配置文件,修改根节点的namespace属性值对应以上接口,然后配置以上抽象方法的映射:

<resultMap id="ProductEntityMap"
	type="cn.tedu.store.entity.Product">
	<id column="id" property="id"/>
	<result column="category_id" property="categoryId"/>
	<result column="item_type" property="itemType"/>
	<result column="title" property="title"/>
	<result column="sell_point" property="sellPoint"/>
	<result column="price" property="price"/>
	<result column="num" property="num"/>
	<result column="image" property="image"/>
	<result column="status" property="status"/>
	<result column="priority" property="priority"/>
	<result column="created_user" property="createdUser"/>
	<result column="created_time" property="createdTime"/>
	<result column="modified_user" property="modifiedUser"/>
	<result column="modified_time" property="modifiedTime"/>
</resultMap>

<!-- 查询热销的前4名的商品列表 -->
<!-- List<Product> findHotList() -->
<select id="findHotList"
	resultMap="ProductEntityMap">
	SELECT
		*
	FROM
		t_product
	ORDER BY
		priority DESC
	LIMIT
		0,4		
</select>

创建测试类,编写并执行单元测试:

@Test
public void findHotList() {
	List<Product> list = mapper.findHotList();
	System.err.println("count=" + list.size());
	for (Product item : list) {
		System.err.println(item);
	}
}

51. 主页-热销排行-业务层

(a) 规划异常

(b) 接口与抽象方法

创建cn.tedu.store.service.IProductService接口,然后添加抽象方法:

List<Product> getHotList();

© 实现

创建cn.tedu.store.service.impl.ProductServiceImpl,实现IProductService接口,添加@Service注解,在类中声明@Autowired private ProductMapper productMapper;持久层对象。

私有化实现持久层接口中的方法:

/**
 * 查询热销的前4名的商品列表
 * @return 热销的前4名的商品列表
 */
private List<Product> findHotList() {
	return productMapper.findHotList();
}

重写IProductService接口中的抽象方法:

@Override
public List<Product> getHotList() {
	List<Product> list = findHotList();
	for (Product product : list) {
		product.setCategoryId(null);
		product.setItemType(null);
		product.setSellPoint(null);
		product.setNum(null);
		product.setStatus(null);
		product.setPriority(null);
		product.setCreatedUser(null);
		product.setCreatedTime(null);
		product.setModifiedUser(null);
		product.setModifiedTime(null);
	}
	return list;
}

创建测试类,编写并执行单元测试:

@Test
public void getHotList() {
	List<Product> list = service.getHotList();
	System.err.println("count=" + list.size());
	for (Product item : list) {
		System.err.println(item);
	}
}

52. 主页-热销排行-控制器层

(a) 处理异常

(b) 设计请求

请求路径:/products/hot
请求参数:无
请求类型:GET
响应数据:JsonResult<List<Product>>
是否拦截:否,需要在拦截器的配置中将 /products/** 设置为白名单

© 处理请求

先找到拦截器的配置,将/products/**设置为白名单。

创建cn.tedu.store.controller.ProductController控制器类,继承自BaseController,在类之前添加@RestController@RequestMapping("products")注解,在类中声明@Autowired private IProductService productService;业务层对象。

然后,在类中添加处理请求的方法:

@GetMapping("hot")
public JsonResult<List<Product>> getHotList() {
	// 查询
	// 返回
}

完成后,打开浏览器,无需登录,通过http://localhost:8080/products/hot即可访问。

53. 主页-热销排行-前端界面

参考收货地址列表的处理方式。

54. 商品-查看详情-持久层

(a) 规划SQL语句

select * from t_product where id=?

(b) 接口与抽象方法

Product findById(Integer id);

© 配置映射

映射:

<!-- 根据商品id查询商品详情 -->
<!-- Product findById(Integer id) -->
<select id="findById"
	resultMap="ProductEntityMap">
	SELECT
		*
	FROM
		t_product
	WHERE
		id=#{id}		
</select>

测试:

@Test
public void findById() {
	Integer id = 10000022;
	Product data = mapper.findById(id);
	System.err.println(data);
}

55. 商品-查看详情-业务层

(a) 规划异常

可能存在:ProductNotFoundException

(b) 接口与抽象方法

Product getById(Integer id) throws ProductNotFoundException;

© 实现抽象方法

私有化实现持久层接口中的方法:

/**
 * 根据商品id查询商品详情
 * @param id 商品id
 * @return 匹配的商品详情,如果没有匹配的数据,则返回null
 */
private Product findById(Integer id) {
	return productMapper.findById(id);
}

实现业务层接口中的抽象方法:

public Product getById(Integer id) throws ProductNotFoundException {
	// 调用私有方法执行查询
	// 判断查询结果是否为null:ProductNotFoundException

	// 将查询结果中的部分属性设置为null,例如隐藏属性和日志
	// 返回结果
}

实现代码:

@Override
public Product getById(Integer id) {
	// 调用私有方法执行查询
	Product result = findById(id);
	// 判断查询结果是否为null:ProductNotFoundException
	if (result == null) {
		throw new ProductNotFoundException(
			"查询商品详情失败!尝试访问的数据不存在!");
	}

	// 将查询结果中的部分属性设置为null,例如隐藏属性和日志
	result.setPriority(null);
	result.setCreatedUser(null);
	result.setCreatedTime(null);
	result.setModifiedUser(null);
	result.setModifiedTime(null);
	// 返回结果
	return result;
}

测试:

@Test
public void getById() {
	Integer id = 10000022;
	Product data = service.getById(id);
	System.err.println(data);
}

56. 商品-查看详情-控制器层

(a) 统一处理异常

处理ProductNotFoundException

(b) 设计请求

设计“商品-查看详情”的请求方式:

请求路径:/products/{id}/details
请求参数:@PathVariable("id") Integer id
请求方式:GET
响应数据:JsonResult<Product>
是否拦截:否,不拦截,已经将 /products/** 添加到白名单,所以无需修改配置

© 处理请求

@GetMapping("{id}/details")
public JsonResult<Product> getById(
	@PathVariable("id") Integer id) {
	// 调用业务层对象执行查询
	Product data = productService.getById(id);
	// 响应成功与数据
	return new JsonResult<>(SUCCESS, data);
}

http://localhost:8080/products/10000022/details

57. 商品-查看详情-前端界面

58. 购物车-创建数据表

CREATE TABLE t_cart (
	cid INT AUTO_INCREMENT COMMENT '购物车数据id',
	uid INT NOT NULL COMMENT '用户id',
	pid INT NOT NULL COMMENT '商品id',
	num INT NOT NULL COMMENT '数量',
	price BIGINT NOT NULL COMMENT '商品单价',
	created_user VARCHAR(50) COMMENT '创建人',
	created_time DATETIME COMMENT '创建时间',
	modified_user VARCHAR(50) COMMENT '最后修改人',
	modified_time DATETIME COMMENT '最后修改时间',
	PRIMARY KEY (cid)
) DEFAULT CHARSET=UTF8;

59. 购物车-创建实体类

创建cn.tedu.store.entity.Cart继承自BaseEntity

60. 购物车-加入购物车-持久层

(a) 规划SQL语句

把商品添加到购物车:

insert into t_cart (除了cid以外的所有字段) values (...);

并不是每次“加入购物车”都会产生新的购物车数据,如果该用户添加的商品在购物车已经存在,则应该只增加数量:

update t_cart set num=?(新值),modified_user=?,modified_time=? where cid=?

到底是应该插入新的数据,还是只增加数量,应该先“检查该用户是否已经将该商品添加到购物车”:

select * from t_cart where uid=? and pid=?

(b) 接口与抽象方法

创建cn.tedu.store.mapper.CartMapper接口,并添加抽象方法:

Integer insert(Cart cart);

Integer updateNum(
	@Param("cid") Integer cid, 
	@Param("num") Integer num,
	@Param("username") String username, 
	@Param("modifiedTime") Date modifiedTime);

Cart findByUidAndPid(
	@Param("uid") Integer uid, 
	@Param("pid") Integer pid);

© 配置映射

映射:

<mapper namespace="cn.tedu.store.mapper.CartMapper">

	<resultMap id="CartEntityMap"
		type="cn.tedu.store.entity.Cart">
		<id column="cid" property="cid"/>
		<result column="uid" property="uid"/>
		<result column="pid" property="pid"/>
		<result column="num" property="num"/>
		<result column="price" property="price"/>
		<result column="created_user" property="createdUser"/>
		<result column="created_time" property="createdTime"/>
		<result column="modified_user" property="modifiedUser"/>
		<result column="modified_time" property="modifiedTime"/>
	</resultMap>

	<!-- 插入购物车数据 -->
	<!-- Integer insert(Cart cart) -->
	<insert id="insert"
		useGeneratedKeys="true"
		keyProperty="cid">
		INSERT INTO t_cart (
			uid, pid,
			num, price,
			created_user, created_time,
			modified_user, modified_time
		) VALUES (
			#{uid}, #{pid},
			#{num}, #{price},
			#{createdUser}, #{createdTime},
			#{modifiedUser}, #{modifiedTime}
		)
	</insert>
	
	<!-- 修改商品在购物车中的数量 -->
	<!-- Integer updateNum(
		@Param("cid") Integer cid, 
		@Param("num") Integer num,
		@Param("username") String username, 
		@Param("modifiedTime") Date modifiedTime) -->
	<update id="updateNum">
		UPDATE 
			t_cart 
		SET 
			num=#{num},
			modified_user=#{username},
			modified_time=#{modifiedTime}
		WHERE
			cid=#{cid}
	</update>
	
	<!-- 根据用户id和商品id查询购物车数据 -->
	<!-- Cart findByUidAndPid(
		@Param("uid") Integer uid, 
		@Param("pid") Integer pid) -->
	<select id="findByUidAndPid"
		resultMap="CartEntityMap">
		SELECT
			*
		FROM
			t_cart
		WHERE 
			uid=#{uid} AND pid=#{pid}
	</select>
	
</mapper>

测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CartMapperTests {

	@Autowired
	CartMapper mapper;
	
	@Test
	public void insert() {
		Cart cart = new Cart();
		cart.setUid(1);
		cart.setPid(2);
		cart.setNum(3);
		cart.setPrice(4L);
		Integer rows = mapper.insert(cart);
		System.err.println("rows=" + rows);
	}
	
	@Test
	public void updateNum() {
		Integer cid = 1;
		Integer num = 10;
		String username = "哈喽";
		Date modifiedTime = new Date();
		Integer rows = mapper.updateNum(cid, num, username, modifiedTime);
		System.err.println("rows=" + rows);
	}
	
	@Test
	public void findByUidAndPid() {
		Integer uid = 1;
		Integer pid = 2;
		Cart cart = mapper.findByUidAndPid(uid, pid);
		System.err.println(cart);
	}
	
}

61. 购物车-加入购物车-业务层

(a) 规划异常

此次的查询没有异常。

可能插入数据,也可能修改数据,则可能抛出对应的异常。

(b) 接口与抽象方法

创建cn.tedu.store.service.ICartService业务层接口,并添加抽象方法:

void addToCart(Integer uid, Integer pid, Integer num, String username);

© 实现抽象方法

创建cn.tedu.store.service.impl.CartServiceImpl,实现ICartService接口,添加@Service注解,在类中声明@Autowired private CartMapper cartMapper;持久层对象,另声明@Autowired private IProductService productService;商品的业务层对象。

私有化实现持久层接口中的3个方法:

/**
 * 插入购物车数据
 * @param cart 购物车数据
 * @throws InsertException 插入数据异常
 */
private void insert(Cart cart) throws InsertException {
	Integer rows = cartMapper.insert(cart);
	if (rows != 1) {
		throw new InsertException(
			"将商品添加到购物车失败!插入数据时发生未知错误!");
	}
}

/**
 * 修改商品在购物车中的数量
 * @param cid 购物车数据的id
 * @param num 新的数量
 * @param username 操作执行人
 * @param modifiedTime 操作执行时间
 * @throws UpdateException 更新数据异常
 */
private void updateNum(Integer cid, Integer num,
	String username, Date modifiedTime) {
	Integer rows = cartMapper.updateNum(cid, num, username, modifiedTime);
	if (rows != 1) {
		throw new UpdateException(
			"调整商品数量失败!修改数据时发生未知错误!");
	}
}

/**
 * 根据用户id和商品id查询购物车数据
 * @param uid 用户id
 * @param pid 商品id
 * @return 匹配的购物车数据,如果没有匹配的数据,则返回null
 */
private Cart findByUidAndPid(Integer uid, Integer pid) {
	return cartMapper.findByUidAndPid(uid, pid);
}

重写ICartService接口中的抽象方法:

public void addToCart(Integer uid, Integer pid, Integer num, String username) {
	// 基于参数uid和pid查询数据
	// 判断查询结果是否为null
	// 是:需要新增购物车数据
	//	自行创建Cart对象
	//	调用productService的getById()方法获取单价并封装到Cart对象
	//	将uid、pid、num参数封装到Cart对象
	//	创建当前时间对象,将时间和username封装到Cart对象的日志属性
	//	执行插入
	// 否:需要修改欲购物的商品的数量
	//	从查询结果中获取当前数量num和数据的cid
	//	将以上查询结果中的当前数量num和参数增量num相加,得到新的数量
	//	执行更新数量
}

测试:

@Test
public void addToCart() {
	try {
		Integer uid = 100;
		Integer pid = 10000017;
		Integer num = 3;
		String username = "土豪";
		service.addToCart(uid, pid, num, username);
		System.err.println("OK.");
	} catch (ServiceException e) {
		System.err.println(e.getClass().getName());
		System.err.println(e.getMessage());
	}
}

62. 购物车-加入购物车-控制器层

(a) 统一处理异常

(b) 设计请求

设计“购物车-加入购物车”的请求方式:

请求路径:/users/reg
请求参数:User user
请求方式:POST
响应数据:JsonResult<Void>

© 处理请求

63. 购物车-加入购物车-前端界面

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员西柚柚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值