收货地址

  • 1. 新增收获地址
    • 1.1 数据库表创建
    • 1.2 创建实体类
    • 1.3 持久层
    • 1.4 业务层
    • 1.5 控制层
    • 1.6 前端页面
  • 2. 获取省市区列表
    • 2.1 数据库表
    • 2.2 实体类
    • 2.3 持久层
    • 2.4 业务层
    • 2.5 控制层
    • 2.6 前端页面
  • 3. 获取省市区的名称
    • 3.1 持久层
    • 3.2 业务层
    • 3.3 业务层优化
    • 3.4 前端页面
  • 4. 收货地址列表展示
    • 4.1 持久层
    • 4.2 业务层
    • 4.3 控制层
    • 4.4 前端页面
  • 5. 设置默认收货地址
    • 5.1 持久层
    • 5.2 业务层
    • 5.3 控制层
    • 5.4 前端页面
  • 6. 删除收货地址
    • 6.1 持久层
    • 6.2 业务层
    • 6.3 控制层
    • 6.4 前端页面

1. 新增收获地址

1.1 数据库表创建

CREATE TABLE t_address (aid INT AUTO_INCREMENT COMMENT '收货地址id',uid INT COMMENT '归属的用户id',name VARCHAR(20) COMMENT '收货人姓名',province_name VARCHAR(15) COMMENT '省-名称',province_code CHAR(6) COMMENT '省-行政代号',city_name VARCHAR(15) COMMENT '市-名称',city_code CHAR(6) COMMENT '市-行政代号',area_name VARCHAR(15) COMMENT '区-名称',area_code CHAR(6) COMMENT '区-行政代号',zip CHAR(6) COMMENT '邮政编码',address VARCHAR(50) COMMENT '详细地址',phone VARCHAR(20) COMMENT '手机',tel VARCHAR(20) COMMENT '固话',tag VARCHAR(6) COMMENT '标签',is_default INT COMMENT '是否默认:0-不默认,1-默认',created_user VARCHAR(20) COMMENT '创建人',created_time DATETIME COMMENT '创建时间',modified_user VARCHAR(20) COMMENT '修改人',modified_time DATETIME COMMENT '修改时间',PRIMARY KEY (aid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.2 创建实体类

/** 收货地址数据的实体类 */
public class Address extends BaseEntity implements Serializable {private Integer aid;private Integer uid;private String name;private String provinceName;private String provinceCode;private String cityName;private String cityCode;private String areaName;private String areaCode;private String zip;private String address;private String phone;private String tel;private String tag;private Integer isDefault;//....

1.3 持久层

  • 规划需要执行的SQL语句
    1.对应的是插入语句:

    insert into t_address values ();
    

    2.一个用户的收货地址规定最多只能有20条数据对应。所以,在插入用户数据之前先做查询操作,如果收货地址已经20条记录,抛收货地址逻辑控制方面的一个异常。

    select count(*) t_address where uid = ?;
    
  • 接口与抽象方法
    创建一个接口AddressMapper,在这个接口中来定义上面两个Sql语句抽象方法定义。

    /** 收货地址持久层的接口 */
    public interface AddressMapper {//插入用户的收获地址数据Integer insert(Address address);//根据用户的id统计收获地址数量Integer countByUid(Integer uid);
    }
    
  • 配置SQL映射
    创建一个AddressMapper.xml映射文件,在这个文件中添加SQL的映射。

    <?xml version="1.0" encoding="UTF8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.cy.store.mapper.AddressMapper"><resultMap type="com.cy.store.entity.Address" id="AddressEntityMap"><id property="aid" column="aid"/><result property="provinceCode" column="province_code"/><result property="provinceName" column="province_name"/><result property="cityCode" column="city_code"/><result property="cityName" column="city_name"/><result property="areaCode" column="area_code"/><result property="areaName" column="area_name"/><result property="isDefault" column="is_default"/><result property="createdUser" column="created_user"/><result property="createdTime" column="created_time"/><result property="modifiedUser" column="modified_user"/><result property="modifiedTime" column="modified_time"/></resultMap><insert id="insert" keyProperty="aid" useGeneratedKeys="true">INSERT INTO t_address (uid, name, province_name, province_code, city_name, city_code, area_name, area_code, zip,address, phone, tel, tag, is_default, created_user, created_time, modified_user, modified_time) VALUES (#{uid}, #{name}, #{provinceName}, #{provinceCode}, #{cityName}, #{cityCode}, #{areaName},#{areaCode}, #{zip}, #{address}, #{phone}, #{tel}, #{tag}, #{isDefault}, #{createdUser},#{createdTime}, #{modifiedUser}, #{modifiedTime})</insert><select id="countByUid" resultType="java.lang.Integer">select count(*) from t_address where uid = #{uid}</select></mapper>
    

    然后,在test下的mapper文件夹下创建AddressMapperTest

    @Autowired
    private AddressMapper addressMapper;@Test
    public void insert() {Address address = new Address();address.setUid(9);address.setPhone("1234242");address.setName("女朋友");addressMapper.insert(address);
    }@Test
    public void countByUid() {System.out.println(addressMapper.countByUid(9));
    }
    

1.4 业务层

  • 规划异常
    如果用户是第一次插入用户的收获地址,规则:当用户插入的地址是第一条时,需要将当前地址作为默认的收货地址,如果查询到统计总数为,则将当前地址的 is_default 值设置为1。注意:查询统计的结果为0不代表异常,只是还没插入过数据。

    查询到的结果大于20,这时候抛出业务控制的异常AddressCountLimitException。

    /** 收货地址总数超出限制的异常(不超过20条)**/
    public class AddressCountLimitException extends ServiceException{//...
    

    插入数据时产生异常。

  • 接口与抽象方法
    创建一个IAddressService接口,在接口中定义业务的抽象方法

    /** 收获地址业务层接口 */
    public interface IAddressService {void addNewAddress(Integer uid, String username, Address address);
    }
    
  • 实现抽象方法
    创建一个AddressServiceImpl实现类,去实现接口中抽象方法。

    在配置文件中定义最大收获地址总数,这样如果以后想要修改总数就会很方便。

    # Spring读取配置文件中数据:@Value("${user.address.max-count}")
    user.address.max-count=20
    
    @Service
    public class AddressServiceImpl implements IAddressService {@Autowiredprivate AddressMapper addressMapper;@Value("${user.address.max-count}")private Integer maxCount;@Overridepublic void addNewAddress(Integer uid, String username, Address address) {//统计收货地址总数Integer count = addressMapper.countByUid(uid);if(count >= maxCount) {throw new AddressCountLimitException("用户收获地址超出上限");}address.setUid(uid);Integer isDefault = count == 0 ? 1 : 0; //isDefault设置为1,表示默认地址address.setIsDefault(isDefault);//补全4项日志address.setCreatedUser(username);address.setModifiedUser(username);address.setCreatedTime(new Date());address.setModifiedTime(new Date());//插入收获地址的方法Integer rows = addressMapper.insert(address);if(rows != 1) {throw new InsertException("插入用户的收获地址产生未知异常");}}
    }
    

    测试业务层功能是否正常。

    @Autowired
    private IAddressService addressService;@Test
    public void addNewAddress() {Address address = new Address();address.setPhone("432312121");address.setName("男朋友");addressService.addNewAddress(23,"管理员",address);
    }
    

1.5 控制层

  • 处理异常
    业务层抛出了收货地址总数超标的异常,在BaseController中进行处理。

    else if (e instanceof AddressCountLimitException) {result.setState(4003);result.setMessage("用户收获地址超出上限的异常");
    }
    
  • 设计请求
    /addresses/add_new_address
    post
    Address address, HttpSession session
    JsonResult<Void>
    
  • 处理请求
    在控制层创建AddressController来处理用户收获地址的请求和响应。

    @RequestMapping("addresses")
    @RestController
    public class AddressController extends BaseController {@Autowiredprivate IAddressService addressService;@RequestMapping("add_new_address")public JsonResult<Void> addNewAddress(Address address, HttpSession session) {Integer uid = getuidFromSession(session);String username = getUsernameFromSession(session);addressService.addNewAddress(uid, username, address);return new JsonResult<>(OK);}
    }
    

    测试:http://localhost:8080/addresses/add_new_address?name=tom&phone=2323121

1.6 前端页面

<script type="text/javascript">$("#btn-add-new-address").click(function () {$.ajax({url: "/addresses/add_new_address",type: "post",data: $("#form-add-new-address").serialize(),dataType: "JSON",success: function (json) {if(json.state == 200) {alert("新增收货地址成功");} else {alert("新增收获地址失败");}},error: function (xhr) {alert("新增收获地址时产生未知的异常" + xhr.message);}});});
</script>

2. 获取省市区列表


地区列表从数据库获取出来。

2.1 数据库表

CREATE TABLE t_dict_district (id int(11) NOT NULL AUTO_INCREMENT,parent varchar(6) DEFAULT NULL,code varchar(6) DEFAULT NULL,name varchar(16) DEFAULT NULL,PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO t_dict_district VALUES (1,'110100','110101','东城区'),...

parent字段表示的是父区域代码号,省的父代码号+86。

2.2 实体类

/* 表示省市区的数据实体类 */
public class District extends BaseEntity {private Integer id;private String parent;private String code;private String name;

2.3 持久层

查询语句,根据父代号进行查询。

select * from t_dict_district where parent = ? order by code ASC;

抽象方法定义。DistrictMapper接口。

public interface DistrictMapper {/*** 根据父代号查询区域信息* @param parent 父代号* @return 某个父区域下的所有区域列表*/List<District> findByParent(String parent);
}

映射mapper

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.store.mapper.DistrictMapper"><select id="findByParent" resultType="com.cy.store.entity.District">select * from t_dict_district where parent=#{parent}order by code ASC</select></mapper>

单元测试

@Autowired
private DistrictMapper districtMapper;@Test
public void findByParent() {List<District> list = districtMapper.findByParent("210100");for (District district : list) {System.out.println(district);}
}

2.4 业务层

1.创建接口IDistrictService,并定义抽象方法

public interface IDistrictService {/*** 根据父代号来查询区域信息(省市区)* @param parent* @return*/List<District> getByParent(String parent);
}

2.创建IDistrictServiceImpl实现类,实现抽象方法。

@Service
public class IDistrictServiceImpl implements IDistrictService {@Autowiredprivate DistrictMapper districtMapper;@Overridepublic List<District> getByParent(String parent) {List<District> list = districtMapper.findByParent(parent);//在进行网路数据传输时,为了尽量避免无效数据的传递,可以将无效数据设置为nullfor (District district : list) {district.setId(null);district.setParent(null);}return list;}
}

3.单元测试

@Autowired
private IDistrictService districtService;@Test
public void getByParent() {List<District> list = districtService.getByParent("86");for (District district : list) {System.out.println(district);}
}

2.5 控制层

  • 设计请求

    /district/
    get
    String parent
    JsonResult<List<District>>
    
  • 请求处理
    创建一个DistrictController类,编写处理请求的方法

    @RequestMapping("districts")
    @RestController
    public class DistrictController extends BaseController{@Autowiredprivate IDistrictService districtService;@RequestMapping({"/",""})public JsonResult<List<District>> getByParent(String parent) {List<District> data = districtService.getByParent(parent);return new JsonResult<>(OK,data);}
    }
    

    district请求添加到白名单中。

    pattrens.add("/districts/**");
    

    然后启动服务器,访问 http://localhost:8080/districts/?parent=86 进行测试。

2.6 前端页面

1.注释掉通过js来完成省市区列表加载的js代码

<!--  <script type="text/javascript" src="../js/distpicker.data.js"></script>-->
<!-- <script type="text/javascript" src="../js/distpicker.js"></script>-->

2.检查前端页面在提交省市区数据时是否有相关name属性和id属性。
3.运行前端看是否还可以正常保存数据(除了省市区以外)

3. 获取省市区的名称

将行政区下拉框动态的从数据库中获取

3.1 持久层

1.规划根据当前code来获取当前省市区的名称,对应的就是一条查询语句。

select * from t_dist_district where code = ?;

2.在DistrictMapper接口定义出来

String findNameByCode(String code);

3.在DistrictMapper.xml文件中添加抽象方法的映射

<select id="findNameByCode" resultType="java.lang.String">select name from t_dict_district where code=#{code}
</select>

4.单元测试

@Test
public void findNameByCode() {String name = districtMapper.findNameByCode("610000");System.out.println(name);
}

3.2 业务层

1.在业务层没有异常需要进行处理
2.定义对应的业务层接口中的抽象方法

String getNameByCode(String code);

3.在子类中进行实现

@Override
public String getNameByCode(String code) {return districtMapper.findNameByCode(code);
}

4.测试可以省略不写(一般超过8行建议测试)

3.3 业务层优化

1.添加地址层AddressServiceImpl,依赖于IDistrictService层

//在添加用户的收获地址的业务层依赖于IDistrictService的业务层接口
@Autowired
private IDistrictService districtService;

2.在 AddressServiceImpl 添加地址的 addNewAddress方法中,将districtService接口中获取到的省市区数据转移到address对象,这个对象中就包含了所有的用户收获地址的数据。

//对address对象中的数据进行补全:省市区
String provinceName = districtService.getNameByCode(address.getProvinceCode());
String cityName = districtService.getNameByCode(address.getCityCode());
String areaName = districtService.getNameByCode(address.getAreaCode());
address.setProvinceName(provinceName);
address.setCityName(cityName);
address.setAreaName(areaName);

3.4 前端页面

1.addAddress.html页面中来编写对应的省市区展示及根据用户的不同选择来限制对应的标签中的内容。
2.编写相关事件的代码

//value属性用于表示当前的这个区域的code值
let defaultOption = "<option value='0'>---- 请选择 ----</option>"
$(document).ready(function () {showProvinceList();//设置默认的“请选择”的值,作为控件的默认值$("#city-list").append(defaultOption);$("#area-list").append(defaultOption);
});$("#city-list").change(function () {//获取行政区父代码let parent = $("#city-list").val();//表示清空select下拉列表中的所有option元素$("#area-list").empty();//填充默认值$("#area-list").append(defaultOption);if(parent == 0) {return;}$.ajax({url: "/districts/",type: "get",data: "parent="+parent,dataType: "JSON",success: function (json) {if(json.state == 200) {let list = json.data;for (let i = 0; i < list.length; i++) {let opt = "<option value='"+list[i].code+"'>"+list[i].name+"</option>";$("#area-list").append(opt);}} else {alert("区县信息加载失败");}}});
});//change()函数用于监听某个控件是否发生改变,一旦发生改变就会触发参数的函数
$("#province-list").change(function () {//获取行政区父代码let parent = $("#province-list").val();//表示清空select下拉列表中的所有option元素$("#city-list").empty();$("#area-list").empty();//填充默认值$("#city-list").append(defaultOption);$("#area-list").append(defaultOption);if(parent == 0) {return;}$.ajax({url: "/districts/",type: "get",data: "parent="+parent,dataType: "JSON",success: function (json) {if(json.state == 200) {let list = json.data;for (let i = 0; i < list.length; i++) {let opt = "<option value='"+list[i].code+"'>"+list[i].name+"</option>";$("#city-list").append(opt);}} else {alert("城市信息加载失败");}}});
});/* 省的下拉列表数据展示 */
function showProvinceList() {$.ajax({url: "/districts/",type: "post",data: "parent=86",dataType: "JSON",success: function (json) {if(json.state == 200) {let list = json.data;for (let i = 0; i < list.length; i++) {let opt = "<option value='"+list[i].code+"'>"+list[i].name+"</option>";$("#province-list").append(opt);}} else {alert("省/直辖区信息加载失败");}}});
}


说明:省、城市、区县,三者有依赖关系,城市依赖省、区县依赖城市。所以省发生改变,城市和区县都要恢复默认值,城市发生改变,则区县恢复默认值。

4. 收货地址列表展示

4.1 持久层

1.数据库数据的查询操作

select * from t_address where uid = ? order by is_default desc, created_time desc;

2.接口和抽象方法

//根据用户id查询用户的收货地址数据
List<Address> findByUid(Integer uid);

3.在xml中添加对应SQL语句映射

<select id="findByUid">select * from t_address where uid=#{uid}order by is_default desc, created_time desc;
</select>

4.测试

@Test
public void findByUid() {List<Address> list = addressMapper.findByUid(9);System.out.println(list);
}

4.2 业务层

1.不用抛出相关的异常,不用进行异常的设计
2.设计业务层的接口和抽象方法

List<Address> getByUid(Integer uid);

3.在实现类中实现此方法的逻辑

@Override
public List<Address> getByUid(Integer uid) {List<Address> list = addressMapper.findByUid(uid);for (Address address : list) {//不需要的数据设置为null,节省资源address.setProvinceCode(null);address.setCityCode(null);address.setAreaCode(null);address.setTel(null);address.setIsDefault(null);address.setCreatedTime(null);address.setCreatedUser(null);address.setModifiedTime(null);address.setModifiedUser(null);}return list;
}

4.3 控制层

1.请求设计

/addresses
HttpSession session
get
JsonResult<List<Address>>

2.实现请求方法的编写

@RequestMapping({"/",""})
public JsonResult<List<Address>> getByUid(HttpSession session) {Integer uid = getuidFromSession(session);List<Address> data = addressService.getByUid(uid);return new JsonResult<>(OK, data);
}

3.先登录,再访问请求的地址进行数据的测试

4.4 前端页面

在address.html页面中,编写查询用户收货地址数据的展示列表。

<script type="text/javascript">$(document).ready(function () {showAddressList();});//展示用户收货地址数据列表function showAddressList() {$.ajax({url: "/addresses/",type: "get",dataType: "JSON",success: function (json) {if(json.state == 200) {let list = json.data;$("#address-list").empty();for (let i = 0; i < list.length; i++) {let tr = '<tr>\n' +'<td>#{tag}</td>\n' +'<td>#{name}</td>\n' +'<td>#{address}</td>\n' +'<td>#{phone}</td>\n' +'<td><a class="btn btn-xs btn-info"><span class="fa fa-edit"></span> 修改</a></td>\n' +'<td><a class="btn btn-xs add-del btn-info"><span class="fa fa-trash-o"></span> 删除</a></td>\n' +'<td><a class="btn btn-xs add-def btn-default">设为默认</a></td>\n' +'</tr>';//两种替换方式tr = tr.replace(/#{tag}/g, list[i].tag);tr = tr.replace(/#{name}/g, list[i].name);tr = tr.replace("#{phone}", list[i].phone);tr = tr.replace("#{address}", list[i].address);$("#address-list").append(tr);}//如果是默认地址,则隐藏“设为默认地址”按钮$(".add-def:eq(0)").hide();} else {alert("用户收货地址信息加载失败");}}});}
</script>

5. 设置默认收货地址

5.1 持久层

  • SQL语句规划
    检测当前用户想设置为默认收货地址的这条数据是否存在

    select * from t_address aid = ?
    

    在修改用户的默认收货地址之前,先将该用户的所有收货地址设置为非默认。

    update t_address set is_default = 0 where uid = ?
    

    将用户当前选中的这条记录设置为默认收货地址

    update t_address set is_default = 1, modified_user = ?, modified_time = ? where aid = ?
    
  • 设计抽象方法
    在AddressMapper接口中进行定义和声明

    //根据aid查询收货地址数据
    Address findByAid(Integer aid);//根据用户的uid值来修改用户的收货地址默认为非默认
    Integer updateNonDefault(Integer uid);Integer updatDefaultByAid(@Param("aid") Integer aid,@Param("modifiedUser") String modifiedUser,@Param("modifiedTime") Date modifiedTime);
    
  • 配置SQL映射
    在AddressMapper.xml中进行配置

    <select id="findByAid" resultMap="AddressEntityMap">select * from t_address where aid=#{aid}
    </select><update id="updateNonDefault">update t_addressset is_default = 0where uid=#{uid}
    </update>
    <update id="updatDefaultByAid">update t_addressset is_default = 1, modified_user=#{modifiedUser}, modified_time=#{modifiedTime}where aid = #{aid}
    </update>
    

    测试

    @Test
    public void findByAid() {System.out.println(addressMapper.findByAid(5));
    }@Test
    public void updateNonDefault() {addressMapper.updateNonDefault(10);
    }
    @Test
    public void updatDefaultByAid() {addressMapper.updatDefaultByAid(3,"明明",new Date());
    }
    

5.2 业务层

  • 异常规划
    1.在执行更新时产生未知的UpdateException异常(已经创建)。
    2.访问的数据不是当前登录用户的收货地址数据,非法访问:AccessDefindException。
    3.收货地址可能不存在异常AddressNotFoundException

    /** 非法访问的异常 */
    public class AccessDeniedException extends ServiceException {/** 收货地址数据不存在的异常 */
    public class AddressNotFoundException extends ServiceException {
  • 设计业务层抽象方法
    在接口IAddressService中编写抽象方法

    /*** 修改某个用户的某条收货地址数据为默认收货地址* @param aid 收货地址的id* @param uid 用户的id* @param username 表示修改执行的人*/
    void setDefault(Integer aid, Integer uid, String username);
    
  • 实现抽象方法
    在AddressServiceImpl类中进行开发和业务设计。

    @Override
    public void setDefault(Integer aid, Integer uid, String username) {Address result = addressMapper.findByAid(aid);if (result == null) {throw new AddressNotFoundException("收货地址不存在");}//检测当前获取到的收货地址数据的归属if(!result.getUid().equals(uid)) {throw new AccessDeniedException("非法数据访问");}//先将所有的收货地址设置非默认Integer rows = addressMapper.updateNonDefault(uid);if(rows < 1) {throw new UpdateException("更新数据产生未知的异常");}//将用户选中的某条地址设置为默认收货地址rows = addressMapper.updatDefaultByAid(aid, username, new Date());if(rows != 1) {throw new UpdateException("更新数据产生未知的异常");}
    }
    

    测试

    @Test
    public void setDefault() {addressService.setDefault(3,10,"管理员");
    }
    

5.3 控制层

  • 处理异常
    在BaseController类中进行统一处理

    else if (e instanceof AddressNotFoundException) {result.setState(4004);result.setMessage("用户的收货地址数据不存在的异常");
    }else if (e instanceof AccessDeniedException) {result.setState(4005);result.setMessage("收货地址数据非法访问的异常");
    }
    
  • 设计请求
    /address/{aid}/set_default
    @PathVariable("aid") Integer aid, HttpSession session
    get
    JsonResult<Void>
    
  • 完成请求
    在AddressController类中编写请求处理方法

    //RestFul风格的请求
    @RequestMapping("{aid}/set_default")
    public JsonResult<Void> setDefault(@PathVariable("aid") Integer aid, HttpSession session) {addressService.setDefault(aid, getuidFromSession(session),getUsernameFromSession(session));return new JsonResult<>(OK);
    }
    

    在浏览器先登录再访问一个请求:http://localhost:8080/addresses/4/set_default

5.4 前端页面

1.给设置默认收货地址超链接添加一个onclick属性,指向一个方法的调用,在这个方法中完成ajax请求的发送。

for (let i = 0; i < list.length; i++) {let tr = '<tr>\n' +'<td>#{tag}</td>\n' +'<td>#{name}</td>\n' +'<td>#{address}</td>\n' +'<td>#{phone}</td>\n' +'<td><a class="btn btn-xs btn-info"><span class="fa fa-edit"></span> 修改</a></td>\n' +'<td><a class="btn btn-xs add-del btn-info"><span class="fa fa-trash-o"></span> 删除</a></td>\n' +'<td><a οnclick="setDefault(#{aid})" class="btn btn-xs add-def btn-default">设为默认</a></td>\n' +'</tr>';//两种替换方式tr = tr.replace(/#{tag}/g, list[i].tag);tr = tr.replace(/#{name}/g, list[i].name);tr = tr.replace("#{phone}", list[i].phone);tr = tr.replace("#{address}", list[i].address);tr = tr.replace("#{aid}", list[i].aid);$("#address-list").append(tr);
}

2.在address.html页面点击“设置默认”按钮,发送ajax。完成setDefault()方法的声明和定义。

function setDefault(aid) {$.ajax({url: "/addresses/" + aid + "/set_default",type: "post",//因为用的RestFul风格,参数在url中发送dataType: "JSON",success: function (json) {if(json.state == 200) {//重新加载收货地址列表页面showAddressList();} else {alert("设置默认收货地址失败");}},error: function (xhr) {alert("设置默认收货地址时产生未知的异常" + xhr.message);}});
}

6. 删除收货地址

6.1 持久层

  • 规划需要执行的SQL语句
    1.在删除之前判断该数据是否存在,判断该条地址数据的归属是否是当前的用户。

    2.执行删除收货地址的信息

    delete from t_address where aid = ?
    

    3.如果用户删除的是默认收货地址,将剩下的地址中的某一条设置为默认的收货地址。规则可以自定义:最新修改的收货地址设置为默认的收货地址(modified_time的字段值)。

    select * from t_address where uid = ? order by modified_time desc limit 0,1
    

    4.如果用户本身就只有一条收货地址的数据,删除后其他操作就可以不进行了。

  • 设计抽象方法
    在AddressMapper接口中进行抽象方法的设计

    //根据收获地址id删除收货地址数据
    Integer deleteByAid(Integer aid);//根据用户uid查询当前用户最后一次被修改的收货地址数据
    //如果删除的是默认收货地址,则将它设置为默认收货地址
    Address findLastModified(Integer uid);
    
  • 映射SQL语句
    在AddressMapper.xml文件中进行映射

    <delete id="deleteByAid">delete from t_address where aid=#{aid}
    </delete>
    <select id="findLastModified" resultMap="AddressEntityMap">select * from t_addresswhere uid=#{uid}order by modified_time desc limit 0,1
    </select>
    

    测试

    @Test
    public void deleteByAid(){addressMapper.deleteByAid(3);
    }@Test
    public void findLastModified(){System.out.println(addressMapper.findLastModified(10));
    }
    

6.2 业务层

  • 规划异常
    在删除的时候可能会产生未知的删除异常导致数据不能删除成功,则抛出DeleteException异常。需要定义和创建。

    /** 删除数据时产生的异常 */
    public class DeleteException extends ServiceException{//...
    
  • 抽象方法设计
    在IAddressService接口中进行设计抽象方法

    /*** 删除用户选中的收货地址* @param aid 收货地址aid* @param uid 用户uid* @param username 用户名*/
    void delete(Integer aid, Integer uid, String username);
    
  • 实现抽象方法
    @Override
    public void delete(Integer aid, Integer uid, String username) {Address result = addressMapper.findByAid(aid);if (result == null) {throw new AddressNotFoundException("收货地址不存在");}//检测当前获取到的收货地址数据的归属if(!result.getUid().equals(uid)) {throw new AccessDeniedException("非法数据访问");}Integer rows = addressMapper.deleteByAid(aid);if(rows != 1) {throw new DeleteException("删除数据产生未知的异常");}Integer count = addressMapper.countByUid(uid);if(count == 0) {return; //如果没有收货地址,终止程序,不走下面的代码}if(result.getIsDefault() == 0) return; //删除的不是默认地址,就不走下面的代码//将这条数据的is_default字符的值设置为1Address address = addressMapper.findLastModified(uid);rows = addressMapper.updatDefaultByAid(address.getAid(),username,new Date());if(rows != 1) {throw new UpdateException("更新数据时产生未知的异常");}}
    

    测试

    @Test
    public void delete(){addressService.delete(5,10,"管理员");
    }
    

6.3 控制层

  • 处理异常DeleteException类

    else if (e instanceof UpdateException) {result.setState(5004);result.setMessage("删除数据时产生未知的异常");
    }
    
  • 设计请求
    /addresses/{aid}/delete
    post
    Integer aid, HttpSession session
    JsonResult<Void>
    
  • 编写请求处理方法
    @RequestMapping("{aid}/delete")
    public JsonResult<Void> delete(@PathVariable("aid") Integer aid, HttpSession session) {addressService.delete(aid,getuidFromSession(session),getUsernameFromSession(session));return new JsonResult<>(OK);
    }
    

6.4 前端页面

在address.html页面中来添加删除按钮的事件

<td><a onclick="deleteByAid(#{aid})" class="btn btn-xs add-del btn-info"><span class="fa fa-trash-o"></span> 删除</a></td>

再去编写delete(aid)方法的具体实现

function deleteByAid(aid) {$.ajax({url: "/addresses/" + aid + "/delete",type: "post",//因为用的RestFul风格,参数在url中发送dataType: "JSON",success: function (json) {if(json.state == 200) {//重新加载收货地址列表页面showAddressList();} else {alert("删除收货地址失败");}},error: function (xhr) {alert("删除收货地址时产生未知的异常" + xhr.message);}});
}

SpringBoot电脑商城-收货地址相关推荐

  1. php商城手机端省市显示,jQuery仿手机京东商城收货地址城市选择

    jQuery仿手机京东商城收货地址城市选择 js代码 /** * 默认调用 */ !function () { var $target = $('#J_Address'); $target.cityS ...

  2. 24-微信小程序商城 收货地址列表(微信小程序商城开发、小程序毕业设计、小程序源代码)(黄菊华-微信小程序开发教程)

    收货地址列表 本节主要讲解收货地址列表界面的实现.效果如图15-5所示. 1.布局分析 结构布局分析示意如图15-6所示. 根据上面的布局分析,我们会产生基础的框架,代码示例如下: <view ...

  3. web电商、商城pc端、商城、购物车、订单、线上支付、web商城、pc商城、登录注册、人工客服、收货地址、现金券、优惠券、礼品卡、团购订单、评价晒单、消息通知、电子产品商城、手机商城、电脑商城

    web电商.商城pc端.商城.购物车.订单.线上支付.web商城.pc商城.登录注册.人工客服.收货地址.现金券.优惠券.礼品卡.团购订单.评价晒单.消息通知.电子产品商城.手机商城.电脑商城 Axu ...

  4. 设置默认收货地址【项目 商城】

    设置默认收货地址[项目 商城] 设置默认收货地址 1. 持久层 1.1 规划SQL语句 1.2 设计抽象方法 1.3 配置SQL映射 测试 2.业务层 2.1 异常规划 2.2 抽象方法 2.3 实现 ...

  5. 移动商城第五篇(用户模块)【用户登陆、回显用户、拦截器、收货地址】

    移动商城[用户登陆.回显用户] 我们来实现用户登陆的功能: 当点击的时候,出来的是一个弹出框,我们想要切换成一个页面. 找到对应的事件.切换成我们的页面就行了. $("#loginAlert ...

  6. Django 19购物商城项目(收货地址:添加、修改)

    dDjango 19购物商城项目 1.新建axf_addr,收货地址表 2.路由 3.cart页面,添加默认收货地址 4.视图(主要修改了cart.新建了收货地址相关方法) 5.收货地址列表 6.收货 ...

  7. 美多商城之用户中心(收货地址3)

    三.收货地址 3.4 修改地址前后端逻辑 1. 修改地址接口设计和定义 1.请求方式 选项 方案 请求方法 PUT 请求地址 /addresses/(?P<address_id>\d+)/ ...

  8. 美多商城之用户中心(收货地址2)

    三.收货地址 3.2 新增地址前后端逻辑 1. 定义用户地址模型类 1.用户地址模型类 from meiduo_mall.utils.models import BaseModelclass Addr ...

  9. 美多商城之用户中心(收货地址1)

    三.收货地址 用户地址的主要业务逻辑有: 展示省市区数据 用户地址的增删改查处理 设置默认地址 设置地址标题 3.1 省市区三级联动 1. 展示收货地址界面 提示: 省市区数据是在收货地址界面展示的, ...

最新文章

  1. 独家揭秘!阿里大规模数据中心的性能分析
  2. 计算机二级aoa软件_国产软件WPS进入全国计算机二级考试 明年3月实施
  3. Spring中的Events
  4. python的内存分配
  5. linux mysql数据库备份并删除前一分钟的数据
  6. gson-2.2.api简单
  7. 一、项目管理框架【PMP 】
  8. C艹 指针和const的关系和注意事项(非常有意思)
  9. 微课|中学生可以这样学Python(5.8.1节):使用切片访问列表元素
  10. 前端开发者如何利用 CSS 实现酷炫的变色方案?
  11. 算法与数据结构1800题
  12. centos php ioncube_Linux安装Zend Guard和ioncube
  13. AAAI 2022 论文列表
  14. 解析一个PHP木马,PHP文件上传安全检测组件
  15. js Array的push pop shift unshift 方法
  16. dcdc升压电源模块可调直流HRB5v24v12v转50v120v165v110v180v350v
  17. LFSR和PRBS是什么关系?prbs怎么产生?
  18. 剑指offer:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
  19. 【NDN实验】ndnSIM: NDN simulator for NS-3 全文翻译
  20. Beta冲刺总结随笔

热门文章

  1. 全网最全最新最细的MYSQL5.7下载安装图文教程
  2. Python中文文本聚类
  3. jsp页面控制浏览器兼容
  4. 射频day4:史密斯圆图
  5. 【ML】EM(期望最大)算法
  6. Java 根据经纬度计算两点间的距离
  7. 接口之----手机号验证接口api
  8. ODBC 连接数据库 SQL server 2008
  9. Linux下安装curl
  10. matlab simulink仿真设计 锂电池主动均衡仿真