新增收货地址

3 新增收货地址-持久层

3.1 各功能的开发顺序

关于收货地址数据的管理,涉及的功能有:增加,删除,修改,设为默认,显示列表。这些功能的开发顺序为:增加-显示列表-设为默认-删除-修改。

3.2 规划需要执行的SQL语句

增加收货地址的本质是插入新的收货地址数据,需要执行的SQL语句大致是:

INSERT INTO t_address (除了aid以外的字段列表) VALUES (匹配的值列表)

后续在处理业务时,还需要确定“即将增加的收货地址是不是默认收货地址”;可以设定规则“用户的第1条收货地址是默认的,以后添加的每一条都不是默认的”;要应用该规则,就必须知道“即将增加的收货地址是不是第1条”,可以“根据用户id统计收货地址的数量”,如果统计结果为0,则即将增加的就是该用户的第1条收货地址,如果统计结果不是0,则该用户已经有若干条收货地址了,即将增加的就一定不是第1条。关于统计的SQL语句大致是:

SELECT count(*) FROM t_address WHERE uid=?

一般电商平台都会限制每个用户可以创建的收货地址的数量,如“每个用户最多只允许创建20个收货地址”,也可以通过以上查询来实现。

3.3 接口与抽象方法

创建com.cy.store.mapper.AddressMapper接口,并在接口中添加抽象方法。

package com.cy.store.mapper;
import com.cy.store.entity.Address;

/** 处理收货地址数据的持久层接口 */
public interface AddressMapper {
   /**
    * 插入收货地址数据
    * @param address 收货地址数据
    * @return 受影响的行数
    */
   Integer insert(Address address);

   /**
    * 统计某用户的收货地址数据的数量
    * @param uid 用户的id
    * @return 该用户的收货地址数据的数量
    */
   Integer countByUid(Integer uid);
}

3.4 配置SQL映射

1.在src/main/resources/mapper文件夹下复制粘贴得到AddressMapper.xml映射文件,修改根节点mapper的namespace属性的值为com.cy.store.mapper.AddressMapper,并在根节点中配置pojo类属性与数据库中表的字段映射。

<?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.cy.store.mapper.AddressMapper">
   <resultMap id="AddressEntityMap" type="com.cy.store.entity.Address">
       <id column="aid" property="aid"/>
       <result column="province_code" property="provinceCode"/>
       <result column="province_name" property="provinceName"/>
       <result column="city_code" property="cityCode"/>
       <result column="city_name" property="cityName"/>
       <result column="area_code" property="areaCode"/>
       <result column="area_name" property="areaName"/>
       <result column="is_default" property="isDefault"/>
       <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>
</mapper>

2.在AddressMapper.xml映射文件的根节点中配置以上两个抽象方法的映射。

<!-- 插入收货地址数据:Integer insert(Address address) -->
<insert id="insert" useGeneratedKeys="true" keyProperty="aid">
  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>

<!-- 统计某用户的收货地址数据的数量:Integer countByUid(Integer uid) -->
<select id="countByUid" resultType="java.lang.Integer">
  SELECT
  COUNT(*)
  FROM
  t_address
  WHERE
  uid=#{uid}
</select>

3.在src/test/java下创建com.cy.store.mapper.AddressMapperTests测试类,在类定义之前添加测试的两个注解,在类中编写并执行以上两个抽象方法的测试。

package com.cy.store.mapper;
import com.cy.store.entity.Address;
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.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class AddressMapperTests {
   @Autowired
   private AddressMapper addressMapper;

   @Test
   public void insert() {
       Address address = new Address();
       address.setUid(18);
       address.setName("admin");
       address.setPhone("17858802974");
       address.setAddress("雁塔区小寨赛格");
       Integer rows = addressMapper.insert(address);
       System.out.println("rows=" + rows);
  }

   @Test
   public void countByUid() {
       Integer uid = 18;
       Integer count = addressMapper.countByUid(uid);
       System.out.println("count=" + count);
  }
}

4 增收货地址-业务层

4.1 规划异常

1.无论用户将要增加的收货地址是不是默认收货地址,都需正常增加。即通过countByUid()方法统计的结果不管是不是0,都不能代表是错误的操作。

2.在执行插入收货地址数据之前,需判断countByUid()方法返回值是否超出上限值,如果超出上限值则抛AddressCountLimitException异常。

3.在执行插入数据时,还可能抛出InsertException异常,此异常无需再次创建。

4.创建com.cy.store.service.ex.AddressCountLimitException类后,需继承自ServiceException类。

package com.cy.store.service.ex;

/** 收货地址数量达到上限的异常 */
public class AddressCountLimitException extends ServiceException {
   // Override Methods...
}

4.2 接口与抽象方法

创建com.cy.store.service.IAddressService业务层接口,并添加抽象方法。

package com.cy.store.service;
import com.cy.store.entity.Address;

/** 处理收货地址数据的业务层接口 */
public interface IAddressService {
   /**
    * 创建新的收货地址
    * @param uid 当前登录的用户的id
    * @param username 当前登录的用户名
    * @param address 用户提交的收货地址数据
    */
   void addNewAddress(Integer uid, String username, Address address);
}

4.3 实现抽象方法

1.创建com.cy.store.service.impl.AddressServiceImpl业务层实现类,在类定义之前添加@Service注解,并实现IAddressService接口,最后在类中添加持久层对象并使用@Autowired注解修饰。

package com.cy.store.service.impl;
import com.cy.store.entity.Address;
import com.cy.store.mapper.AddressMapper;
import com.cy.store.service.IAddressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AddressServiceImpl implements IAddressService {
   @Autowired
   private AddressMapper addressMapper;

   @Override
   public void addNewAddress(Integer uid, String username, Address address) {
// TODO
  }
}

2.分析重写的addNewAddress(Integer uid, String username, Address address)抽象方法中的业务逻辑。

@Override
public void addNewAddress(Integer uid, String username, Address address) {
   // 根据参数uid调用addressMapper的countByUid()方法,统计当前用户的收货地址数据的数量
   // 判断数量是否达到上限值
   // 是:抛出AddressCountLimitException

   // 补全数据:将参数uid封装到参数address中
   // 补全数据:根据以上统计的数量,得到正确的isDefault值(是否默认:0-不默认,1-默认),并封装
   // 补全数据:4项日志

   // 调用addressMapper的insert()方法插入收货地址数据,并获取返回的受影响行数
   // 判断受影响行数是否不为1
   // 是:抛出InsertException
}

3.addNewAddress(Integer uid, String username, Address address)方法的具体代码实现。

package com.cy.store.service.impl;
import com.cy.store.entity.Address;
import com.cy.store.mapper.AddressMapper;
import com.cy.store.service.IAddressService;
import com.cy.store.service.ex.AddressCountLimitException;
import com.cy.store.service.ex.InsertException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Date;

@Service
public class AddressServiceImpl implements IAddressService {
   @Autowired
   private AddressMapper addressMapper;

   @Value("${user.address.max-count}")
   private int maxCount;

   @Override
   public void addNewAddress(Integer uid, String username, Address address) {
       // 根据参数uid调用addressMapper的countByUid(Integer uid)方法,统计当前用户的收货地址数据的数量
       Integer count = addressMapper.countByUid(uid);
       // 判断数量是否达到上限值
       if (count > maxCount) {
           // 是:抛出AddressCountLimitException
           throw new AddressCountLimitException("收货地址数量已经达到上限(" + maxCount + ")!");
      }

       // 补全数据:将参数uid封装到参数address中
       address.setUid(uid);
       // 补全数据:根据以上统计的数量,得到正确的isDefault值(是否默认:0-不默认,1-默认),并封装
       Integer isDefault = count == 0 ? 1 : 0;
       address.setIsDefault(IsDefault);
       // 补全数据:4项日志
       Date now = new Date();
       address.setCreatedUser(username);
       address.setCreatedTime(now);
       address.setModifiedUser(username);
       address.setModifiedTime(now);

       // 调用addressMapper的insert(Address address)方法插入收货地址数据,并获取返回的受影响行数
       Integer rows = addressMapper.insert(address);
       // 判断受影响行数是否不为1
       if (rows != 1) {
           // 是:抛出InsertException
           throw new InsertException("插入收货地址数据时出现未知错误,请联系系统管理员!");
      }
  }
}

4.在application.properties文件中添加收货地址数据上限值的配置。

user.address.max-count=20

5.在src/test/java下创建com.cy.store.service.AddressServiceTests测试类,在测试类中测试以上方法。

package com.cy.store.service;
import com.cy.store.entity.Address;
import com.cy.store.service.ex.ServiceException;
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.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class AddressServiceTests {
   @Autowired
   private IAddressService addressService;

   @Test
   public void addNewAddress() {
       try {
           Integer uid = 20;
           String username = "管理员";
           Address address = new Address();
           address.setName("张三");
           address.setPhone("17858805555");
           address.setAddress("雁塔区小寨华旗");
           addressService.addNewAddress(uid, username, address);
           System.out.println("OK.");
      } catch (ServiceException e) {
           System.out.println(e.getClass().getSimpleName());
           System.out.println(e.getMessage());
      }
  }
}

 

posted @   爽爽子的秃头生活  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示