27. 收货地址-分析
关于“收货地址”数据的管理,涉及的功能有:增加,修改,删除,设为默认,显示列表。
以上功能的开发顺序应该是:增加 > 显示列表 > 设为默认 > 删除 > 修改。
28. 收货地址-创建数据表
创建收货地址数据表:
CREATE TABLE t_address (
aid INT AUTO_INCREMENT COMMENT '收货地址id',
uid INT COMMENT '用户id',
name VARCHAR(50) COMMENT '收货人姓名',
province_code CHAR(6) COMMENT '省代号',
province_name VARCHAR(50) COMMENT '省名称',
city_code CHAR(6) COMMENT '市代号',
city_name VARCHAR(50) COMMENT '市名称',
area_code CHAR(6) COMMENT '区代号',
area_name VARCHAR(50) COMMENT '区名称',
zip CHAR(6) COMMENT '邮编',
address VARCHAR(100) COMMENT '详细地址',
phone VARCHAR(20) COMMENT '手机',
tel VARCHAR(20) COMMENT '固话',
tag VARCHAR(30) COMMENT '地址类型',
is_default INT COMMENT '是否默认,0-非默认,1-默认',
created_user VARCHAR(50) COMMENT '创建人',
created_time DATETIME COMMENT '创建时间',
modified_user VARCHAR(50) COMMENT '最后修改人',
modified_time DATETIME COMMENT '最后修改时间',
PRIMARY KEY (aid)
) DEFAULT CHARSET=UTF8;
29. 收货地址-创建实体类
创建cn.tedu.store.entity.Address
,继承自BaseEntity
:
/**
* 收货地址数据的实体类
*/
public class Address extends BaseEntity {
private static final long serialVersionUID = 6946915401608396201L;
private Integer aid;
private Integer uid;
private String name;
private String provinceCode;
private String provinceName;
private String cityCode;
private String cityName;
private String areaCode;
private String areaName;
private String zip;
private String address;
private String phone;
private String tel;
private String tag;
private Integer isDefault;
}
30. 收货地址-增加-持久层
(a) 规划SQL语句
增加收货地址需要执行的SQL语句大致是:
insert into t_address (除了aid以外的所有字段) values (匹配的值列表)
后续,在执行插入数据时,需要确定插入的收货地址数据是不是默认收货地址,每个用户都应该有且仅有1条默认收货地址,当新创建收货地址时,第1条是默认的,其它的都不是默认的!则需要判断出“即将创建的收货地址是不是第1条”,可以通过“查询某用户的收货地址数据的数量”来判断,即数量为0时,即将创建的就是第1条,数量不为0时,即将创建就不是第1条:
select count(*) from t_address where uid=?
另外,还可以限制每个用户最多允许创建多少条收货地址,该功能也可以通过以上查询来完成!
(b) 接口与抽象方法
创建cn.tedu.store.mapper.AddressMapper
接口,并在接口中添加抽象方法:
Integer addnew(Address address);
Integer countByUid(Integer uid);
© 配置映射
将原有的UserMapper.xml
复制,并粘贴为AddressMapper.xml
,删除其中各子级节点的配置,将根节点对应的接口修改为AddressMapper
接口,然后,在该文件中配置以上2个抽象方法的映射:
<mapper namespace="cn.tedu.store.mapper.AddressMapper">
<!-- 增加收货地址数据 -->
<!-- Integer addnew(Address address) -->
<insert id="addnew"
useGeneratedKeys="true"
keyProperty="aid">
INSERT INTO t_address (
uid, name,
province_code, province_name,
city_code, city_name,
area_code, area_name,
zip, address,
phone, tel,
tag, is_default,
created_user, created_time,
modified_user, modified_time
) VALUES (
#{uid}, #{name},
#{provinceCode}, #{provinceName},
#{cityCode}, #{cityName},
#{areaCode}, #{areaName},
#{zip}, #{address},
#{phone}, #{tel},
#{tag}, #{isDefault},
#{createdUser}, #{createdTime},
#{modifiedUser}, #{modifiedTime}
)
</insert>
<!-- 统计某用户的收货地址的数量 -->
<!-- Integer countByUid(Integer uid) -->
<select id="countByUid"
resultType="java.lang.Integer">
SELECT
COUNT(*)
FROM
t_address
WHERE
uid=#{uid}
</select>
</mapper>
在src/test/java下创建cn.tedu.store.mapper.AddressMapperTests
测试类,编写并执行单元测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class AddressMapperTests {
@Autowired
AddressMapper mapper;
@Test
public void addnew() {
Address address = new Address();
address.setUid(1);
address.setName("小刘同学");
Integer rows = mapper.addnew(address);
System.err.println("rows=" + rows);
}
@Test
public void countByUid() {
Integer uid = 100;
Integer count = mapper.countByUid(uid);
System.err.println("count=" + count);
}
}
31. 收货地址-增加-业务层
(a) 规划异常
插入数据可能产生InsertException
。
如果需要限制用户创建的收货地址数据,则达到上限仍尝试创建,就会产生cn.tedu.store.service.ex.AddressCountLimitException
。
(b) 接口与抽象方法
创建cn.tedu.store.service.IAddressService
接口,然后,在接口中添加抽象方法:
void create(Integer uid, String username, Address address) throws AddressCountLimitException, InsertException;
© 实现抽象方法
创建cn.tedu.store.service.impl.AddressServiceImpl
类,实现IAddressService
接口,在类之前添加@Service
注解,在类中添加@Autowired private AddressMapper addressMapper;
持久层对象:
@Service
public class AddressServiceImpl implements IAddressService {
@Autowired
private AddressMapper addressMapper;
}
然后,复制持久层接口中的2个抽象方法,粘贴到该实现类中,然后,私有化实现这2个方法:
/**
* 增加收货地址数据
* @param address 收货地址数据
* @throws InsertException
*/
private void addnew(Address address) {
Integer rows = addressMapper.addnew(address);
if (rows != 1) {
throw new InsertException("...");
}
}
/**
* 统计某用户的收货地址的数量
* @param uid 用户的id
* @return 用户的收货地址的数量
*/
private Integer countByUid(Integer uid) {
if (uid == null || uid < 1) {
throw new IllegalArgumentException();
}
return addressMapper.countByUid(uid);
}
重写接口中的抽象方法:
public void create(Integer uid, String username, Address address) throws AddressCountLimitException, InsertException {
// 基于参数uid查询该用户的收货地址数量
// 判断数量是否达到上限值
// 是:AddressCountLimitException
// 补全参数address中的数据:uid
// TODO 补全参数address中的数据:省市区的名称
// 补全参数address中的数据:isDefault,根据收货地址数量确定该属性的值
// 创建当前时间对象
// 补全参数address中的数据:4项日志
// 执行增加
}
具体实现代码为:
@Override
public void create(Integer uid, String username, Address address)
throws AddressCountLimitException, InsertException {
// 基于参数uid查询该用户的收货地址数量
Integer count = countByUid(uid);
// 判断数量是否达到上限值
if (count >= MAX_COUNT) {
// 是:AddressCountLimitException
throw new AddressCountLimitException(
"增加收货地址失败!当前收货地址的数量(" + count + ")已经达到上限(" + MAX_COUNT + ")!");
}
// 补全参数address中的数据:uid
address.setUid(uid);
// TODO 补全参数address中的数据:省市区的名称