1. 程式人生 > 其它 >新增收貨地址

新增收貨地址

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());
      }
  }
}