電腦商城--用戶收貨管理

新增收貨地址

1 新增收貨地址-創建數據表

1.使用use命令先選中store數據庫。

USE store;

2.在store數據庫中創建t_address用戶數據表。

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;

2 新增收貨地址-創建實體類

????????創建com.cy.store.entity.Address新增收獲地址的實體類,繼承自BaseEntity類,在類中聲明與數據表中對應的屬性,添加Getters and Setters方法,基于唯一標識aid生成hashCode()和equals()方法。

package com.cy.store.entity;/** 收貨地址數據的實體類 */
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;// Generate: Getter and Setter、Generate hashCode() and equals()、toString()
}

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 mapperPUBLIC "-//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">SELECTCOUNT(*)FROMt_addressWHEREuid=#{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 {@Autowiredprivate AddressMapper addressMapper;@Testpublic 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);}@Testpublic 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 {@Autowiredprivate AddressMapper addressMapper;@Overridepublic 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 {@Autowiredprivate AddressMapper addressMapper;@Value("${user.address.max-count}")private int maxCount;@Overridepublic void addNewAddress(Integer uid, String username, Address address) {// 根據參數uid調用addressMapper的countByUid(Integer uid)方法,統計當前用戶的收貨地址數據的數量Integer count = addressMapper.countByUid(uid);// 判斷數量是否達到上限值if (count > maxCount) {// 是:拋出AddressCountLimitExceptionthrow 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);// 判斷受影響行數是否不為1if (rows != 1) {// 是:拋出InsertExceptionthrow 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 {@Autowiredprivate IAddressService addressService;@Testpublic 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());}}
}

5 新增收貨地址-控制器

5.1 處理異常

????????在控制器層新增收貨地址時,如果收貨地址已經達到上限值,則拋出AddressCountLimitException異常,并在BaseController類中添加處理AddressCountLimitException的異常。

// ...
else if (e instanceof AddressCountLimitException) {result.setState(4003);
}
// ...
5.2 設計請求

????????設計用戶提交的請求,并設計響應的方式。

請求路徑:/addresses/add_new_address
請求參數:Address address, HttpSession session
請求類型:POST
響應結果:JsonResult<Void>

5.3 處理請求

1.創建com.cy.store.controller.AddressController控制器類繼承自BaseController類,在類的聲明添加@RequestMapping("addresses")和@RestController注解,在類中聲明業務層對象并添加Autowired注解修飾。

package com.cy.store.controller;
import com.cy.store.service.IAddressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("addresses")
public class AddressController extends BaseController {@Autowiredprivate IAddressService addressService;    
}

?2.然后在AddressController類中添加處理請求的addNewAddress(Address address, HttpSession session)方法。

@RequestMapping("add_new_address")
public JsonResult<Void> addNewAddress(Address address, HttpSession session) {// 從Session中獲取uid和usernameInteger uid = getUidFromSession(session);String username = getUsernameFromSession(session);// 調用業務對象的方法執行業務addressService.addNewAddress(uid, username, address);// 響應成功return new JsonResult<Void>(OK);
}

3.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/addresses/add_new_address進行測試。

6 新增收貨地址-前端頁面

1.在addAddress.html頁面中配置新增收貨地址表單的屬性。給form表單添加id="form-add-new-address"屬性、"請輸入收貨人姓名"添加name="name"屬性、"請輸入郵政編碼"添加name="zip"屬性、"輸入詳細的收貨地址,小區名稱、門牌號等"添加name="address"屬性、"請輸入手機號碼"添加name="phone"屬性、"請輸入固定電話號碼"添加name="tel"屬性、"請輸入地址類型,如:家、公司或者學校"添加name="tag"屬性、"保存"按鈕添加id="btn-add-new-address"屬性。以上屬性如果已經添加無需重復添加。

2.在addAddress.html頁面中body標簽內部的最后,添加script標簽用于編寫JavaScript程序。

<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("新增收貨地址失敗!" + json.message);}},error: function(xhr) {alert("您的登錄信息已經過期,請重新登錄!HTTP響應碼:" + xhr.status);location.href = "login.html";}});});
</script>

3.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/web/addAddress.html頁面。


獲取省/市/區的列表

1 獲取省/市/區的列表-數據庫

1.使用該數據庫:

USE store;?

2.向數據庫中導入省/市/區數據t_dict_district.sql文件,執行以下指令:

mysql> source C:/Users/yuanxin/t_dict_district.sql

?3.創建省/市/區數據的com.cy.store.entity實體類,在類中聲明與數據表中對應的屬性,添加Getters and Setters方法,基于唯一標識id生成equals()方法及hashCode()和toString()方法。

package com.cy.store.entity;
import java.io.Serializable;/** 省/市/區數據的實體類 */
public class District implements Serializable {private Integer id;private String parent;private String code;private String name;// Generate: Getter and Setter、Generate hashCode() and equals()、toString()
}

2 獲取省/市/區的列表-持久層

2.1 規劃需要執行的SQL語句

????????獲取全國所有省/某省所有市/某市所有區的查詢SQL語句大致是:

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

2.2 接口與抽象方法

????????創建com.cy.store.mapper.DistrictMapper接口,添加抽象方法。

package com.cy.store.mapper;
import com.cy.store.entity.District;
import java.util.List;/** 處理省/市/區數據的持久層接口 */
public interface DistrictMapper {/*** 獲取全國所有省/某省所有市/某市所有區* @param parent 父級代號,當獲取某市所有區時,使用市的代號;當獲取省所有市時,使用省的代號;當獲取全國所有省時,使用"86"作為父級代號* @return 全國所有省/某省所有市/某市所有區的列表*/List<District> findByParent(String parent);
}
?2.3 配置SQL映射

1.在src/main/resources/mapper中復制得到DistrictMapper.xml,修改根節點的namespace屬性的值為以上接口文件,并配置以上抽象方法的映射。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.store.mapper.DistrictMapper"><!-- 獲取全國所有省/某省所有市/某市所有區:List<District> findByParent(String parent) --><select id="findByParent" resultType="com.cy.store.entity.District">SELECT*FROMt_dict_districtWHEREparent=#{parent}ORDER BYcode ASC</select>
</mapper>

2.在src/test/java下創建com.cy.store.mapper.DistrictMapperTests測試類,編寫并執行以上抽象方法的測試。

package com.cy.store.mapper;
import com.cy.store.entity.District;
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;
import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class DistrictMapperTests {@Autowiredprivate DistrictMapper districtMapper;@Testpublic void findByParent() {String parent = "110100";List<District> list = districtMapper.findByParent(parent);System.out.println("count=" + list.size());for (District district : list) {System.out.println(district);}}
}

3 獲取省/市/區的列表-業務層

3.1 規劃異常

說明:無異常。

3.2 接口與抽象方法

????????創建com.cy.store.service.IDistrictService接口,并添加抽象方法。

package com.cy.store.service;
import com.cy.store.entity.District;
import java.util.List;/** 處理省/市/區數據的業務層接口 */
public interface IDistrictService {/*** 獲取全國所有省/某省所有市/某市所有區* @param parent 父級代號,當獲取某市所有區時,使用市的代號;當獲取某省所有市時,使用省的代號;當獲取全國所有省時,使用"86"作為父級代號* @return 全國所有省/某省所有市/某市所有區的列表*/List<District> getByParent(String parent);
}
3.3 實現抽象方法

1.創建com.cy.store.service.impl.DistrictServiceImpl類,實現IDistrictService接口,在類之前添加@Service注解,以及在類中添加持久層對象并使用@Autowired修飾。

package com.cy.store.service.impl;
import com.cy.store.entity.District;
import com.cy.store.mapper.DistrictMapper;
import com.cy.store.service.IDistrictService;
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service;
import java.util.List;/** 處理省/市/區數據的業務層實現類 */
@Service
public class DistrictServiceImpl implements IDistrictService {@Autowiredprivate DistrictMapper districtMapper;@Overridepublic List<District> getByParent(String parent) {return null;}
}

2.在DistrictServiceImpl實現類中實現getByParent(String parent)方法的具體代碼。

@Override
public List<District> getByParent(String parent) {List<District> list = districtMapper.findByParent(parent);for (District district : list) {district.setId(null);district.setParent(null);}return list;
}

3.在src/test/java下創建com.cy.store.service.DistrictServiceTests測試類,編寫并執行單元測試。

package com.cy.store.service;
import com.cy.store.entity.District;
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;
import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class DistrictServiceTests {@Autowiredprivate IDistrictService districtService;@Testpublic void getByParent() {try {String parent = "86";List<District> list = districtService.getByParent(parent);System.out.println("count=" + list.size());for (District item : list) {System.out.println(item);}} catch (ServiceException e) {System.out.println(e.getClass().getSimpleName());System.out.println(e.getMessage());}}
}

4 獲取省/市/區的列表-控制器

4.1 處理異常

說明:無異常。

4.2 設計請求

????????設計用戶提交的請求,并設計響應的方式。

請求路徑:/districts/
請求參數:String parent
請求類型:GET
響應結果:JsonResult<List<District>>
是否攔截:否,需要在攔截器的配置中添加白名單

4.3 處理請求

1.創建com.cy.store.controller.DistrictController控制器類,繼承自BaseController類,在類之前添加@RequestMapping("districts")和@RestController注解,并在類中添加業務層對象,對其使用@Autowired注解修飾。

package com.cy.store.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.tedu.store.entity.District;
import cn.tedu.store.service.IDistrictService;
import cn.tedu.store.util.JsonResult;@RequestMapping("districts")
@RestController
public class DistrictController extends BaseController {@Autowiredprivate IDistrictService districtService;}

2.在類中添加處理請求的方法getByParent(String parent)及方法的實現。

@GetMapping:是一個組合注解,等價于@RequestMapping(method={RequestMethod.GET}),它將HTTP的GET請求映射到特定的處理方法上。“/”表示方法將處理所有傳入的URI請求。簡化代碼。

@GetMapping({"", "/"})
public JsonResult<List<District>> getByParent(String parent) {List<District> data = districtService.getByParent(parent);return new JsonResult<>(OK, data);
}

?3.在攔截器LoginInterceptorConfigurer類的addInterceptors(InterceptorRegistry registry)方法中將“districts”請求添加為白名單。如果已經添加無需重復添加。

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

4.完成后啟動項目,打開瀏覽器(不需要登錄),直接訪問http://localhost:8080/districts?parent=86進行測試。

5 獲取省/市/區的列表-前端頁面

1.在addAddress.html頁面中的head標簽內導入的distpicker.data.js和distpicker.js文件注釋掉。

JQuery實現中國省市區地址三級聯動插件Distpicker。

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

2.在新增收貨地址表單中,給"選擇省"控件添加name="provinceCode"和id="province-list"屬性,給"選擇市"添加name="cityCode"和id="city-list"屬性,給"選擇區"控件添加name="areaCode"和id="area-list"屬性。以上屬性如果已經添加無需重復添加。

3.在addAddress.html頁面中body標簽內的script標簽中添加獲取省/市/區列表的代碼。

<script type="text/javascript">let defaultOption = '<option value="0">----- 請選擇 -----</option>';$(document).ready(function() {showProvinceList();$("#city-list").append(defaultOption);$("#area-list").append(defaultOption);});$("#province-list").change(function() {showCityList();});$("#city-list").change(function() {showAreaList();});function showProvinceList() {$("#province-list").append(defaultOption);$.ajax({url: "/districts",type: "GET",data: "parent=86",dataType: "JSON",success: function(json) {if (json.state == 200) {let list = json.data;console.log("count=" + list.length);for (let i = 0; i < list.length; i++) {console.log(list[i].name);let option = '<option value="' + list[i].code + '">' + list[i].name + '</option>';$("#province-list").append(option);}}}});}function showCityList() {let parent = $("#province-list").val();$("#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;console.log("count=" + list.length);for (let i = 0; i < list.length; i++) {console.log(list[i].name);let option = '<option value="' + list[i].code + '">' + list[i].name + '</option>';$("#city-list").append(option);}}}});}function showAreaList() {let parent = $("#city-list").val();$("#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;console.log("count=" + list.length);for (let i = 0; i < list.length; i++) {console.log(list[i].name);let option = '<option value="' + list[i].code + '">' + list[i].name + '</option>';$("#area-list").append(option);}}}});}
</script>

JQuery事件-change()方法

1.定義和用法

(1)當元素的值發生改變時,會發生change事件。

(2)該事件僅適用于文本域(textfield),以及textarea和select元素。

(3)change()函數觸發change事件,或規定當發生change事件時運行的函數。

當用于select元素時,change事件會在選擇某個選項時發生。當用于textfield或textarea時,該事件會在元素失去焦點時發生。

2.觸發change事件

觸發被選元素的change事件。語法:$(selector).change()

3.將函數綁定到change事件

規定當被選元素的 change 事件發生時運行的函數。語法:$(selector).change(function)

4.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/web/addAddress.html頁面。

5.說明:如果輸入的郵政編碼位數大于6位數字,則會拋MysqlDataTruncation異常。


獲取省/市/區的名稱

????????此功能模塊主要實現根據省/市/區的行政代號獲取省/市/區的名稱。

1 獲取省/市/區的名稱-持久層

1.1 規劃需要執行的SQL語句

????????根據省/市/區的行政代號獲取省/市/區的名稱,需要執行的SQL語句大致是:

select name from t_dict_district where code=??

1.2 接口與抽象方法

????????在DistrictMapper接口中添加根據省/市/區的行政代號獲取省/市/區的名稱findNameByCode(String code)抽象方法。

/*** 根據省/市/區的行政代號獲取省/市/區的名稱* @param code 省/市/區的行政代號* @return 匹配的省/市/區的名稱,如果沒有匹配的數據則返回null*/
String findNameByCode(String code);
1.3 配置SQL映射

1.在DistrictMapper.xml文件中配置映射。

<!-- 根據省/市/區的行政代號獲取省/市/區的名稱:String findNameByCode(String code) -->
<select id="findNameByCode" resultType="java.lang.String">SELECTnameFROMt_dict_districtWHEREcode=#{code}
</select>

?2.然后在DistrictMapperTests測試類中編寫并執行測試方法。

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

2 獲取省/市/區的名稱-業務層

2.1 規劃異常

說明:無異常。

2.2 接口與抽象方法

在業務層IDistrictService接口中添加getNameByCode(String code)抽象方法。

/*** 根據省/市/區的行政代號獲取省/市/區的名稱* @param code 省/市/區的行政代號* @return 匹配的省/市/區的名稱,如果沒有匹配的數據則返回null*/
String getNameByCode(String code);
2.3 實現抽象方法

1.在業務層DistrictServiceImpl類中重寫getNameByCode(String code)方法。

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

2.然后在DistrictServiceTests測試類中編寫并執行測試方法。

@Test
public void getNameByCode() {try {String code = "430000";String result = districtService.getNameByCode(code);System.out.println(result);} catch (ServiceException e) {System.out.println(e.getClass().getSimpleName());System.out.println(e.getMessage());}
}

3 新增收貨地址-業務層優化

1.在AddressServiceImpl類中聲明處理省/市/區數據的業務層對象。

@Autowired
private IDistrictService districtService;

?2.在addNewAddress(Integer uid, String username, 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);

4 新增收貨地址-前端頁面測試

1.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/web/addAddress.html頁面。輸入收貨人相關的信息并保存。

2.在后臺數據庫中檢查數據是否被正常的插入到t_address表中。


?收貨地址列表

1 收貨地址列表顯示-持久層

1.1 規劃需要執行的SQL語句

????????顯示當前登錄用戶的收貨地址列表的SQL語句大致是:

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

1.2 接口與抽象方法

????????在AddressMapper接口中添加findByUid(Integer uid)抽象方法。

/*** 查詢某用戶的收貨地址列表數據* @param uid 收貨地址歸屬的用戶id* @return 該用戶的收貨地址列表數據*/
List<Address> findByUid(Integer uid);
1.3 配置SQL映射

1.在AddressMapper.xml文件中配置findByUid(Integer uid)方法的映射。

<!--
<resultMap id="AddressEntityMap" type="cn.tedu.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>
--><!-- 查詢某用戶的收貨地址列表數據:List<Address> findByUid(Integer uid) -->
<select id="findByUid" resultMap="AddressEntityMap">SELECT*FROMt_addressWHEREuid=#{uid}ORDER BYis_default DESC, created_time DESC
</select>

?2.在AddressMapperTests測試類中添加findByUid()測試方法。

@Test
public void findByUid() {Integer uid = 26;List<Address> list = addressMapper.findByUid(uid);System.out.println("count=" + list.size());for (Address item : list) {System.out.println(item);}
}

?

2 收貨地址列表顯示-業務層

2.1 規劃異常

說明:無異常。

2.2 接口與抽象方法

????????在IAddressService接口中添加getByUid(Integer uid)抽象方法。

/*** 查詢某用戶的收貨地址列表數據* @param uid 收貨地址歸屬的用戶id* @return 該用戶的收貨地址列表數據*/
List<Address> getByUid(Integer uid);
2.3 實現抽象方法

1.在AddressServiceImpl類中實現getByUid(Integer uid)抽象方法。

@Override
public List<Address> getByUid(Integer uid) {List<Address> list = addressMapper.findByUid(uid);for (Address address : list) {address.setUid(null);address.setProvinceCode(null);address.setCityCode(null);address.setAreaCode(null);address.setCreatedUser(null);address.setCreatedTime(null);address.setModifiedUser(null);address.setModifiedTime(null);}return list;
}

2.在AddressServiceTests測試類中添加getByUid()測試方法。

@Test
public void getByUid() {Integer uid = 26;List<Address> list = addressService.getByUid(uid);System.out.println("count=" + list.size());for (Address item : list) {System.out.println(item);}
}

3 收貨地址列表顯示-控制器

3.1 處理異常

說明:無異常。

3.2 設計請求

設計用戶提交的請求,并設計響應的方式。

請求路徑:/addresses
請求參數:HttpSession session
請求類型:GET
響應結果:JsonResult<List<Address>>?

3.3 處理請求

1.在AddressController類中添加處理請求的getByUid(HttpSession session)方法。

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

?2.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/addresses頁面。

4 收貨地址列表顯示-前端頁面

1.在address.html頁面中body標簽內部的最后,添加展示用戶收貨地址列表數據的JavaScript代碼。

<script type="text/javascript">
$(document).ready(function () {showAddressList();
});function showAddressList() {$("#address-list").empty();$.ajax({url: "/addresses",type: "GET",dataType: "JSON",success: function (json) {let list = json.data;for (let i = 0; i < list.length; i++) {console.log(list[i].name);let address = '<tr>'+ '<td>#{tag}</td>'+ '<td>#{name}</td>'+ '<td>#{province}#{city}#{area}#{address}</td>'+ '<td>#{phone}</td>'+ '<td><a class="btn btn-xs btn-info"><span class="fa fa-edit"></span> 修改</a></td>'+ '<td><a class="btn btn-xs add-del btn-info"><span class="fa fa-trash-o"></span> 刪除</a></td>'+ '<td><a class="btn btn-xs add-def btn-default">設為默認</a></td>'+ '</tr>';address = address.replace(/#{aid}/g, list[i].aid);address = address.replace(/#{tag}/g, list[i].tag);address = address.replace("#{name}", list[i].name);address = address.replace("#{province}", list[i].provinceName);address = address.replace("#{city}", list[i].cityName);address = address.replace("#{area}", list[i].areaName);address = address.replace("#{address}", list[i].address);address = address.replace("#{phone}", list[i].phone);$("#address-list").append(address);}$(".add-def:eq(0)").hide();}});
}
</script>

?2.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/web/address.html頁面。


默認收貨地址

1 默認收貨地址-持久層

1.1 規劃需要執行的SQL語句

1.將某用戶的所有收貨地址設置為非默認地址(是否默認:0-不默認,1-默認)

update t_address set is_default=0 where uid=?

2.將某用戶指定的收貨地址設置為默認地址。

update t_address set is_default=1, modified_user=?, modified_time=? where aid=??

3.檢查該收貨地址是否存在,并檢查數據歸屬是否正確。可根據收貨地址aid值,查詢收貨地址詳情數據。

select * from t_address where aid=??

1.2 接口與抽象方法

????????在AddressMapper接口中聲明三個抽象方法。

/*** 將某用戶的所有收貨地址設置為非默認地址* @param uid 收貨地址歸屬的用戶id* @return 受影響的行數*/
Integer updateNonDefaultByUid(Integer uid);/*** 將指定的收貨地址設置為默認地址* @param aid 收貨地址id* @param modifiedUser 修改執行人* @param modifiedTime 修改時間* @return 受影響的行數*/
Integer updateDefaultByAid(@Param("aid") Integer aid,@Param("modifiedUser") String modifiedUser,@Param("modifiedTime") Date modifiedTime);/*** 根據收貨地址aid值,查詢收貨地址詳情* @param aid 收貨地址id* @return 匹配的收貨地址詳情,如果沒有匹配的數據,則返回null*/
Address findByAid(Integer aid);
1.3 配置SQL映射

1.在AddressMapper.xml映射文件,配置以上三個抽象方法的映射。

<!-- 將某用戶的所有收貨地址設置為非默認地址:Integer updateNonDefaultByUid(Integer uid) -->
<update id="updateNonDefaultByUid">UPDATEt_addressSETis_default=0WHEREuid=#{uid}
</update><!-- 將指定的收貨地址設置為默認地址:Integer updateDefaultByAid(@Param("aid") Integer aid,@Param("modifiedUser") String modifiedUser,@Param("modifiedTime") Date modifiedTime) -->
<update id="updateDefaultByAid">UPDATEt_addressSETis_default=1,modified_user=#{modifiedUser},modified_time=#{modifiedTime}WHEREaid=#{aid}
</update><!-- 根據收貨地址aid值,查詢收貨地址詳情:Address findByAid(Integer aid) -->
<select id="findByAid" resultMap="AddressEntityMap">SELECT*FROMt_addressWHEREaid=#{aid}
</select>

2.在AddressMapperTests類中編寫并執行以上三個抽象方法的測試。

@Test
public void updateNonDefaultByUid() {Integer uid = 26;Integer rows = addressMapper.updateNonDefaultByUid(uid);System.out.println("rows=" + rows);
}@Test
public void updateDefaultByAid() {Integer aid = 11;String modifiedUser = "管理員";Date modifiedTime = new Date();Integer rows = addressMapper.updateDefaultByAid(aid, modifiedUser, modifiedTime);System.out.println("rows=" + rows);
}@Test
public void findByAid() {Integer aid = 11;Address result = addressMapper.findByAid(aid);System.out.println(result);
}

2 默認收貨地址-業務層

2.1 規劃異常

1.在執行設置默認收貨地址之前,需要先檢查該收貨地址數據是否存在,如果不存在則拋出AddressNotFoundException異常。

2.然后還需要檢查數據歸屬是否正確,也就是不可以操作他人的數據,如果該數據中記錄的uid與當前登錄的用戶的uid不一致,則拋出AccessDeniedException異常。

3.檢查通過后先全部設置為非默認,然后將指定的收貨地址設置為默認;這兩種操作都是更新數據的操作,則可能拋出UpdateException異常。

4.在com.cy.store.service.ex包下創建AddressNotFoundException和AccessDeniedException異常類。

package com.cy.store.service.ex;/** 收貨地址數據不存在的異常 */
public class AddressNotFoundException extends ServiceException {// Override Methods...
}
package com.cy.store.service.ex;/** 非法訪問的異常 */
public class AccessDeniedException extends ServiceException {// Override Methods...
}
2.2 接口與抽象方法

????????在IAddressService接口中添加setDefault(Integer aid, Integer uid, String username)抽象方法。

/*** 設置默認收貨地址* @param aid 收貨地址id* @param uid 歸屬的用戶id* @param username 當前登錄的用戶名*/
void setDefault(Integer aid, Integer uid, String username);
2.3 實現抽象方法

1.在AddressServiceImpl類中重寫setDefault(Integer aid, Integer uid, String username)方法。該方法需要添加@Transactional注解。

????????事務:基于Spring JDBC的事務(Transaction)處理,使用事務可以保證一系列的增刪改操作,要么全部執行成功,要么全部執行失敗。@Transactional注解可以用來修飾類也可以用來修飾方法。如果添加在業務類之前,則該業務類中的方法均以事務的機制運行,但是一般并不推薦這樣處理。

@Transactional
@Override
public void setDefault(Integer aid, Integer uid, String username) {// 根據參數aid,調用addressMapper中的findByAid()查詢收貨地址數據// 判斷查詢結果是否為null// 是:拋出AddressNotFoundException// 判斷查詢結果中的uid與參數uid是否不一致(使用equals()判斷)// 是:拋出AccessDeniedException:非法訪問// 調用addressMapepr的updateNonDefaultByUid()將該用戶的所有收貨地址全部設置為非默認,并獲取返回的受影響的行數// 判斷受影響的行數是否小于1(不大于0)// 是:拋出UpdateException// 調用addressMapepr的updateDefaultByAid()將指定aid的收貨地址設置為默認,并獲取返回的受影響的行數// 判斷受影響的行數是否不為1// 是:拋出UpdateException
}

2.setDefault(Integer aid, Integer uid, String username)方法的具體代碼實現。

@Transactional
@Override
public void setDefault(Integer aid, Integer uid, String username) {// 根據參數aid,調用addressMapper中的findByAid()查詢收貨地址數據Address result = addressMapper.findByAid(aid);// 判斷查詢結果是否為nullif (result == null) {// 是:拋出AddressNotFoundExceptionthrow new AddressNotFoundException("嘗試訪問的收貨地址數據不存在");}// 判斷查詢結果中的uid與參數uid是否不一致(使用equals()判斷)if (!result.getUid().equals(uid)) {// 是:拋出AccessDeniedExceptionthrow new AccessDeniedException("非法訪問的異常");}// 調用addressMapper的updateNonDefaultByUid()將該用戶的所有收貨地址全部設置為非默認,并獲取返回受影響的行數Integer rows = addressMapper.updateNonDefaultByUid(uid);// 判斷受影響的行數是否小于1(不大于0)if (rows < 1) {// 是:拋出UpdateExceptionthrow new UpdateException("設置默認收貨地址時出現未知錯誤[1]");}// 調用addressMapper的updateDefaultByAid()將指定aid的收貨地址設置為默認,并獲取返回的受影響的行數rows = addressMapper.updateDefaultByAid(aid, username, new Date());// 判斷受影響的行數是否不為1if (rows != 1) {// 是:拋出UpdateExceptionthrow new UpdateException("設置默認收貨地址時出現未知錯誤[2]");}
}

3.在AddressServiceTests測試類,編寫并執行單元測試。

@Test
public void setDefault() {try {Integer aid = 13;Integer uid = 27;String username = "系統管理員";addressService.setDefault(aid, uid, username);System.out.println("OK.");} catch (ServiceException e) {System.out.println(e.getClass().getSimpleName());System.out.println(e.getMessage());}
}

3 默認收貨地址-控制器

3.1 處理異常

????????在BaseController類中添加處理AddressNotFoundException和AccessDeniedException的異常。

// ...
else if (e instanceof AddressNotFoundException) {result.setState(4004);
} else if (e instanceof AccessDeniedException) {result.setState(4005);
}
// ...
3.2 設計請求

????????設計用戶提交的請求,并設計響應的方式。

請求路徑:/addresses/{aid}/set_default
請求參數:@PathVaraible("aid") Integer aid, HttpSession sesion
請求類型:POST
響應結果:JsonResult<Void>

????????REST即表述性狀態傳遞(Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格。它是一種針對網絡應用的設計和開發方式,可以降低開發的復雜性,提高系統的可伸縮性。 ?

3.3 處理請求

1.在AddressController類中添加處理請求的setDefault(@PathVariable("aid") Integer aid, HttpSession session)方法。

@RequestMapping("{aid}/set_default")
public JsonResult<Void> setDefault(@PathVariable("aid") Integer aid, HttpSession session) {Integer uid = getUidFromSession(session);String username = getUsernameFromSession(session);addressService.setDefault(aid, uid, username);return new JsonResult<Void>(OK);
}

2.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/addresses/13/set_default進行測試。

4 默認收貨地址-前端頁面

1.在address.html頁面中body標簽內部的script標簽內,添加設置用戶默認收貨地址的代碼。

function setDefault(aid) {$.ajax({url: "/addresses/" + aid + "/set_default",type: "POST",dataType: "JSON",success: function(json) {if (json.state == 200) {showAddressList();} else {alert("設置默認收貨地址失敗!" + json.message);}},error: function(xhr) {alert("您的登錄信息已經過期,請重新登錄!HTTP響應碼:" + xhr.status);location.href = "login.html";}});
}

2.給showAddressList()方法中的“設為默認”超鏈接按鈕添加設置默認收貨地址的點擊事件。

<td><a onclick="setDefault(#{aid})" class="btn btn-xs add-def btn-default">設為默認</a></td>

3.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/web/address.html頁面,點擊“設為默認”超鏈接按鈕進行功能測試。
?


刪除收貨地址

1 刪除收貨地址-持久層

1.1 規劃需要執行的SQL語句

1.在刪除之前,需檢查數據是否存在,數據歸屬是否正確。此功能已完成,無需再次開發。

2.刪除指定的收貨地址的SQL語句大致是。

delete from t_address where aid=?

3.如果刪除的這條數據是默認收貨地址,則應該將剩余的收貨地址中的某一條設置為默認收貨地址,可以設定規則“將最近修改的設置為默認收貨地址”,要實現此功能就必須要知道“最近修改的收貨地址的id是多少”。則通過以下查詢語句完成。

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

4.在執行以上操作之前,還需檢查該用戶的收貨地址數據的數量,如果刪除的收貨地址是最后一條收貨地址,則刪除成功后無需再執行其他操作。統計收貨地址數量的功能此前已經完成,無需再次開發。

1.2 接口與抽象方法

????????在AddressMapper接口中添加抽象方法。

/*** 根據收貨地址id刪除數據* @param aid 收貨地址id* @return 受影響的行數*/
Integer deleteByAid(Integer aid);/*** 查詢某用戶最后修改的收貨地址* @param uid 歸屬的用戶id* @return 該用戶最后修改的收貨地址,如果該用戶沒有收貨地址數據則返回null*/
Address findLastModified(Integer uid);
?1.3 配置SQL映射

1.在AddressMapper.xml文件中添加以上兩個抽象方法的映射。

<!-- 根據收貨地址id刪除數據:Integer deleteByAid(Integer aid) -->
<delete id="deleteByAid">DELETE FROMt_addressWHEREaid=#{aid}
</delete><!-- 查詢某用戶最后修改的收貨地址:Address findLastModified(Integer uid) -->
<select id="findLastModified" resultMap="AddressEntityMap">SELECT*FROMt_addressWHEREuid=#{uid}ORDER BYmodified_time DESCLIMIT 0,1
</select>

2.在AddressMapperTests測試類中添加單元測試方法。

@Test
public void deleteByAid() {Integer aid = 4;Integer rows = addressMapper.deleteByAid(aid);System.out.println("rows=" + rows);
}@Test
public void findLastModified() {Integer uid = 30;Address result = addressMapper.findLastModified(uid);System.out.println(result);
}

2 刪除收貨地址-業務層

2.1 規劃異常

????????在執行刪除操作時,可能會刪除數據失敗,此時拋出DeleteException異常。在創建com.cy.store.service.ex.DeleteException異常類,并繼承自ServiceException類。

package com.cy.store.service.ex;/** 刪除數據失敗的異常 */
public class DeleteException extends ServiceException {// Override Methods...
}
2.2 接口與抽象方法

????????在IAddressService接口中添加刪除收貨地址的抽象方法。

/*** 刪除收貨地址* @param aid 收貨地址id* @param uid 歸屬的用戶id* @param username 當前登錄的用戶名*/
void delete(Integer aid, Integer uid, String username);
2.3 實現抽象方法

1.在AddressServiceImpl實現類中實現以上兩個抽象方法。

@Transactional
@Override
public void delete(Integer aid, Integer uid, String username) {// 根據參數aid,調用findByAid()查詢收貨地址數據Address result = addressMapper.findByAid(aid);// 判斷查詢結果是否為nullif (result == null) {// 是:拋出AddressNotFoundExceptionthrow new AddressNotFoundException("嘗試訪問的收貨地址數據不存在");}// 判斷查詢結果中的uid與參數uid是否不一致(使用equals()判斷)if (!result.getUid().equals(uid)) {// 是:拋出AccessDeniedException:非法訪問throw new AccessDeniedException("非常訪問");}// 根據參數aid,調用deleteByAid()執行刪除Integer rows1 = addressMapper.deleteByAid(aid);if (rows1 != 1) {throw new DeleteException("刪除收貨地址數據時出現未知錯誤,請聯系系統管理員");}// 判斷查詢結果中的isDefault是否為0if (result.getIsDefault() == 0) {return;}// 調用持久層的countByUid()統計目前還有多少收貨地址Integer count = addressMapper.countByUid(uid);// 判斷目前的收貨地址的數量是否為0if (count == 0) {return;}// 調用findLastModified()找出用戶最近修改的收貨地址數據Address lastModified = addressMapper.findLastModified(uid);// 從以上查詢結果中找出aid屬性值Integer lastModifiedAid = lastModified.getAid();// 調用持久層的updateDefaultByAid()方法執行設置默認收貨地址,并獲取返回的受影響的行數Integer rows2 = addressMapper.updateDefaultByAid(lastModifiedAid, username, new Date());// 判斷受影響的行數是否不為1if (rows2 != 1) {// 是:拋出UpdateExceptionthrow new UpdateException("更新收貨地址數據時出現未知錯誤,請聯系系統管理員");}
}

2.在AddressServiceTests測試類中添加單元測試方法。

@Test
public void delete() {try {Integer aid = 18;Integer uid = 30;String username = "明明";addressService.delete(aid, uid, username);System.out.println("OK.");} catch (ServiceException e) {System.out.println(e.getClass().getSimpleName());System.out.println(e.getMessage());}
}

3 刪除收貨地址-控制器

3.1 處理異常

????????在BaseController類中添加DeleteException異常的處理。

// ...
else if (e instanceof DeleteException) {result.setState(5002);
}
// ...
3.2 設計請求

????????設計用戶提交的請求,并設計響應的方式。

請求路徑:/addresses/{aid}/delete
請求參數:@PathVariable("aid") Integer aid, HttpSession session
請求類型:POST
響應結果:JsonResult<Void>

3.3 處理請求

1.在AddressController類中添加處理請求的delete()方法。

@RequestMapping("{aid}/delete")
public JsonResult<Void> delete(@PathVariable("aid") Integer aid, HttpSession session) {Integer uid = getUidFromSession(session);String username = getUsernameFromSession(session);addressService.delete(aid, uid, username);return new JsonResult<Void>(OK);
}

?2.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/addresses/26/delete進行測試。

4 刪除收貨地址-前端頁面

1.在address.html頁面中body標簽內部的script標簽內,添加設置用戶刪除收貨地址的代碼。

function deleteByAid(aid) {$.ajax({url: "/addresses/" + aid + "/delete",type: "POST",dataType: "JSON",success: function(json) {if (json.state == 200) {showAddressList();} else {alert("刪除收貨地址失敗!" + json.message);}},error: function(json) {alert("您的登錄信息已經過期,請重新登錄!HTTP響應碼:" + json.status);location.href = "login.html";}});
}

?2.給showAddressList()方法中的“設為默認”超鏈接按鈕添加設置默認收貨地址的點擊事件。

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

3.完成后啟動項目,打開瀏覽器先登錄,再訪問http://localhost:8080/web/address.html頁面,點擊“刪除”超鏈接按鈕進行功能測試。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/85731.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/85731.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/85731.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開發者避坑:接入Flux-Kontext API實現文生圖、圖生圖功能

在數字化浪潮背景下&#xff0c;人工智能&#xff08;Artificial Intelligence, AI&#xff09;技術正加速重塑圖像創作領域。智創聚合API平臺近日宣布整合Flux-Kontext系列模型&#xff0c;通過API接口支持圖生圖和文生圖功能&#xff0c;為開發者及創作者提供高效解決方案。此…

.Net Core 獲取與bin目錄相同文件路徑的文件

在 .NET Core 中&#xff0c;您可以使用以下方法來獲取與 bin 目錄相同的文件路徑。通常&#xff0c;bin 目錄是應用程序編譯后生成的輸出目錄&#xff0c;您可以使用 AppContext.BaseDirectory 或 Directory.GetCurrentDirectory() 來獲取該目錄的路徑。 以下是一些常用的方法…

RN(React Native)技術應用中常出現的錯誤及解決辦法

React Native 作為跨平臺開發框架&#xff0c;在實際應用中可能會遇到一些常見的錯誤。以下是React Native 技術應用中常出現的錯誤及解決辦法&#xff1a; 1. 網絡請求失敗&#xff08;Network Request Failed&#xff09; 原因&#xff1a; 請求地址不正確網絡權限未配置i…

Java 21 的虛擬線程與橋接模式:構建高性能并發系統

Java 21 的虛擬線程與橋接模式&#xff1a;構建高性能并發系統 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用代碼丈量世界&…

HTML5 火焰字體效果教程

HTML5 火焰字體效果教程 這里寫目錄標題 HTML5 火焰字體效果教程前言項目概述基本原理項目結構詳細實現步驟1. HTML結構2. CSS樣式3. JavaScript實現 代碼詳解1. 初始化設置2. 粒子系統3. 生成粒子4. 動畫循環5. 交互控制 擴展和優化建議總結完整代碼 前言 在這篇教程中&#…

SMOTE-XGBoost實戰:金融風控中欺詐檢測的樣本不平衡解決方案

1. 行業問題背景 &#xff08;1&#xff09;金融欺詐檢測的特殊性 在支付風控領域&#xff0c;樣本不平衡是核心痛點。Visa 2023年度報告顯示&#xff0c;全球信用卡欺詐率約為0.6%&#xff0c;但單筆欺詐交易平均損失高達$500。傳統機器學習模型在此場景下表現堪憂&#xff1…

Instagram下載保存 -下載狗解析工具

在日常瀏覽Instagram時&#xff0c;是否有過這樣的煩惱&#xff1a;看到一個精彩的視頻&#xff0c;想要保存下來&#xff0c;卻不知道如何操作&#xff1f;有時候我們會看到一些特別的旅行視頻、搞笑片段&#xff0c;甚至是喜歡的名人分享的內容&#xff0c;簡直是舍不得錯過。…

flink如何基于Pekko實現RPC調用

摘要 通過閱讀flink源碼&#xff0c;了解flink是如何基于Pekko實現遠程RPC調用的 Pekko實現遠程調用 Flink 的 RPC 框架底層是構建在 Pekko 的 actor 模型之上的&#xff0c;了解Pekko如何使用&#xff0c;對后續源碼的閱讀有幫助。 Apache Pekko&#xff08;原為 Akka 的一…

Kafka節點注冊沖突問題分析與解決

一、核心錯誤分析 ERROR Error while creating ephemeral at /brokers/ids/1, node already exists and owner does not match org.apache.zookeeper.KeeperException$NodeExistsException: KeeperErrorCode NodeExists問題本質&#xff1a;ZooKeeper中已存在ID為1的broker節…

突破PPO訓練效率瓶頸!字節跳動提出T-PPO,推理LLM訓練速度提升2.5倍

突破PPO訓練效率瓶頸&#xff01;字節跳動提出T-PPO&#xff0c;推理LLM訓練速度提升2.5倍 在大語言模型&#xff08;LLM&#xff09;通過長思維鏈&#xff08;CoT&#xff09;展現出強大推理能力的當下&#xff0c;強化學習&#xff08;RL&#xff09;作為關鍵技術卻面臨訓練…

【Python】dictionary

1 字典功能 字典是可變容器模型&#xff0c;且可存儲任意類型對象&#xff1b; 字典的每個鍵值對 <key: value> 用冒號 : 分割&#xff0c;每個對之間用逗號(,)分割&#xff0c;整個字典包括在花括號 {} 中 ,格式如下所示&#xff1a; d {key1 : value1, key2 : value…

【python】If 語句

1 使用if 進行條件判斷 1.1 檢查字符串是否相等 car bmw car BMW # FALSEcar bmw car.upper() BMW # true # 變小寫用方法&#xff1a;lower1.2 檢查字符串是否不相等 my_car yadeaif my_car ! Audi:print("Buy one! Buy one! Buy one!")1.3 比較數字 answe…

Knife4j 使用詳解

一、概述 Knife4j 是一款基于 Swagger 的開源 API 文檔工具&#xff0c;旨在為 Java 開發者提供更美觀、功能更強大的 API 文檔生成、展示和調試體驗。它是 Swagger-Bootstrap-UI 的升級版&#xff0c;通過增強 UI 界面和擴展功能&#xff0c;解決了原生 Swagger UI 界面簡陋、…

Java excel坐標計算

package com.common.base.util.excel;/*** excel 坐標計算*/ public class UtilExcelPosi {/*** deepseek生成 ExcelProperty(index UtilExcelPosi.pA)*/public final static int pA 0;public final static int pB 1;public final static int pC 2;public final static i…

【JavaWeb】Servlet+JSP 實現分頁功能

文章目錄 思路數據抽出功能設計 功能模塊工具類前端內容用戶端數據處理 思路 數據抽出 需要顯示的數據&#xff0c;查詢的數據抽出&#xff1b;進行分頁顯示&#xff0c;需要統計抽出的件數&#xff0c;然后根據頁面顯示尺寸調整顯示頁面內容&#xff1b; 功能設計 翻頁需要…

SpringBoot-準備工作-工程搭建

目錄 1.創建空項目 2.檢查項目jdk版本 3.檢查Maven的全局配置 4.配置項目的字符集 5.創建SpringBoot工程 1.創建空項目 2.檢查項目jdk版本 3.檢查Maven的全局配置 4.配置項目的字符集 5.創建SpringBoot工程

01、python實現matlab的插值算法,以及驗證

import numpy as np from scipy.interpolate import griddata import sys def griddata_wrapper(x, y, v, xq, yq, method): """ 包裝scipy的griddata函數,支持單個點或多個點的插值 """ try: # 將輸入轉換為numpy數組…

React ahooks——useRequest

目錄 簡介 1. 核心功能 2. 基本用法 3. 高級用法 &#xff08;1&#xff09;輪詢請求&#xff08;Polling&#xff09; &#xff08;2&#xff09;防抖&#xff08;Debounce&#xff09; &#xff08;3&#xff09;依賴刷新&#xff08;refreshDeps&#xff09; &#x…

re正則、Xpath、BeautifulSouplxml 區別

目錄 1. re 正則表達式2. XPath3. BeautifulSoup + lxml4. 功能特性對比5.對比與建議在網頁數據解析中,正則表達式(re)XPath(常結合lxml)BeautifulSoup(常依賴解析器如lxml)是三種主流技術,各有核心差異和適用場景。 1. re 正則表達式 優勢:文本匹配效率高,尤其適用于…

教師辦工專用 資源包|課件+手抄報+PPT模板+常用表格 PDF格式93GB

如果家里親戚或朋友有走上教育之路的人&#xff0c;給他這份整合可以減輕不少工作負擔&#xff0c;更快地適應教育的節奏。也可以發給孩子的老師讓他在平時做個班級活動的參考 《老師教學辦工資源包》包括手抄報大全、教學計劃、工作總結、培訓手冊、課程表等教學、辦公常用資…