刪除收獲地址
1?刪除收獲地址-持久層
1.1 規劃sql語句
- 在刪除操作之前判斷該數據是否存在,判斷該條地址的歸屬是否是當前的用戶
- 執行刪除收貨地址的操作
delete from t_address where aid=?
- 如果用戶刪除的時默認地址,將剩下地址的某一條作為默認收貨地址,自定義規則是:最新修改的收貨地址信息是默認地址,可以通過修改時間進行降序排列
????????limit 0,1?limit(n-1)*n,pageSize,第一個參數時第幾頁,第二個參數是當前頁展示多少條
select * from t_address where uid=? order by modified_time DESC limit 0,1
- 如果用戶本身只有一條收貨地址,刪除后就不用進行其他操作了
1.2 編寫接口層以及抽象方法
/*** 根據aid刪除收貨地址數據* @param* @return*/Integer deleteByAid(Integer aid);/*** 根據用戶id查詢用戶最后一次修改的收貨地址數據* @param uid 用戶id* @return 返回值是用戶最后一次修改的收貨地址數據*/Address findLastModified(Integer uid);
1.3 xml文件中進行sql映射
<delete id="deleteByAid">DELETE FROM t_address WHERE aid=#{aid}</delete><!-- 查詢該用戶最新修改地址的信息 第一頁,一條 --><select id="findLastModified" resultMap="AddressEntityMap">select * from t_address where uid=#{uid} order by modified_time desc limit 0,1</select>
1.4 進行測試
? ? ? ? 在AddressMapperTest類中進行測試
@Testvoid deleteByAid() {Integer integer = addressMapper.deleteByAid(7);System.out.println(integer);}@Testpublic void findLastModified() {Address address = addressMapper.findLastModified(9);System.out.println(address);}
2?刪除收獲地址-業務層
2.1 異常規劃
? ? ? ? 在執行刪除的時候哦可能會產生未知的刪除異常導致數據不能刪除成功,則拋出DeleteException異常
package com.cy.store.service.ex;/**刪除數據時產生的異常*/
public class DeleteException extends ServiceException{public DeleteException() {super();}public DeleteException(String message) {super(message);}public DeleteException(String message, Throwable cause) {super(message, cause);}public DeleteException(Throwable cause) {super(cause);}protected DeleteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}
}
2.2 service層接口和抽象方法
/*** 刪除收貨地址* @param aid 收貨地址id* @param uid 用戶id* @param username 用戶名*/void delete(Integer aid, Integer uid, String username);
2.3 實現類實現接口重寫抽象方法
/*** 刪除收貨地址* @param aid 收貨地址id* @param uid 用戶id* @param username 用戶名*/@Overridepublic void delete(Integer aid, Integer uid, String username) {
// 判斷收貨地址是否存在Address address = addressMapper.findByAid(aid);if (address==null){throw new AddressNotFoundException("收貨地址數據不存在");}
// 判斷用戶id與收貨地址數據中的用戶id是否相同if (!address.getUid().equals(uid)){throw new AccessDeniedException("非法數據訪問");}
// 刪除收貨地址操作Integer rows = addressMapper.deleteByAid(aid);
// 如果刪除失敗,拋出刪除異常if (rows!=1){throw new DeleteException("刪除數據時產生未知的異常");}
// 統計用戶的收貨地址數量,如果為0,就直接終止程序Integer count = addressMapper.countByUid(uid);if (count==0){
// 直接終止程序return;}
// 如果刪除的收貨地址是默認收貨地址,則將用戶最新修改的收貨地址設置為默認收貨地址if (address.getIsDefault()==1){
// 查詢 用戶最新修改的收貨地址Address lastModified = addressMapper.findLastModified(uid);
// 設置為默認值Integer integer = addressMapper.updateDefaultByAid(lastModified.getAid(), username, new Date());if (integer!=1){throw new UpdateException("更新數據時產生未知的異常");}}}
2.4 測試業務
? ? ? ? 在assressServiceTest中進行測試
@Testvoid delete() {addressService.delete(6,9,"admin");}
3?刪除收獲地址-控制層
3.1 處理DeleteException異常
? ? ? ? 在BaseController中需要處理DeleteException
/*** 控制層基類*/
public class BaseController {//操作成功的狀態碼public static final int OK = 200;/*** 全局異常處理器,用于捕獲并處理業務層拋出的異常。** @param e 捕獲的異常對象* @return 返回封裝后的 JsonResult 對象,包含狀態碼和錯誤信息*/
// 該項目中產生了異常,會被統一攔截到此方法中,這個方法此時就充當了請求處理方法,方法的返回值直接給前端瀏覽器,返回給前端的數據中,狀態碼,狀態碼對應信息,數據@ExceptionHandler({ServiceException.class, FileUploadException.class})public JsonResult<Void> handleException(Throwable e) {// 創建一個 JsonResult 實例,并初始化異常消息JsonResult<Void> result = new JsonResult<>(e);// 判斷異常類型,設置對應的狀態碼和提示信息if (e instanceof UsernameDuplicatedException){// 用戶名被占用時返回 400 狀態碼和相應提示result.setState(4000);result.setMessage("用戶名被占用");} else if (e instanceof InsertException){// 插入數據失敗時返回 500 狀態碼和相應提示result.setState(4000);result.setMessage("注冊時產生未知的異常");}else if (e instanceof UsernameNotFoundException){result.setState(4001);result.setMessage("用戶數據不存在");}else if (e instanceof PasswordNotMatchException){result.setState(4002);result.setMessage("用戶密碼錯誤");}else if (e instanceof AddressCountLimitException){result.setState(4003);result.setMessage("收貨地址超出上限");}else if (e instanceof AccessDeniedException){result.setState(4004);result.setMessage("收貨地址數據非法訪問");}else if (e instanceof AddressNotFoundException){result.setState(4005);result.setMessage("收貨地址數據不存在");}else if (e instanceof DeleteException){result.setState(5002);result.setMessage("刪除數據時產生未知的異常");}else if (e instanceof UpdateException){result.setState(5003);result.setMessage("更新數據時產生未知的異常");} else if (e instanceof FileEmptyException) {result.setState(6000);} else if (e instanceof FileSizeException) {result.setState(6001);} else if (e instanceof FileTypeException) {result.setState(6002);} else if (e instanceof FileStateException) {result.setState(6003);} else if (e instanceof FileUploadIOException) {result.setState(6004);}// 返回最終的響應結果return result;}/*** 從Session中獲取當前登錄用戶的uid* * @param session HttpSession對象,用于獲取會話中的用戶ID* @return 當前登錄用戶的uid* * `protected` 表示該方法只能被同一個包內的類或子類訪問。* `final` 表示該方法不能被子類重寫。*/protected final Integer getUidFromSession(HttpSession session) {// 從Session中獲取uid// 從會話中獲取uid屬性并轉換為整數類型返回return Integer.valueOf(session.getAttribute("uid").toString());}/*** 從Session中獲取當前登錄用戶的用戶名* @param session HttpSession對象,用于獲取會話中的用戶名* @return 當前登錄用戶的用戶名*/protected final String getUsernameFromSession(HttpSession session) {// 從Session中獲取當前登錄的用戶名return session.getAttribute("username").toString();}}
3.2 設計請求
請求路徑:/address/delete/{aid}
請求方式:POST
請求參數:Integer aid,HttpSession session
返回值類型:JsonResult<Void>
3.3 編寫AddressController類代碼,實現請求
/*** 刪除收貨地址* @param aid 收貨地址id* @param session 當前登錄的用戶的會話* @return*/@RequestMapping("/delete/{aid}")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<>(OK);}
4 Address.html前端頁面
4.1 給刪除按鈕綁定點擊事件
?4.2 編寫deleteById()函數方法,發送請求
function deleteById(aid){$.ajax({url: "/addresses/delete/"+ aid,type: "POST",dataType: "json",success: function (json) {if (json.state == 200) {alert("刪除收貨地址成功")// 將列表的tr清空,替代成新的tr// 重新調用獲取列表的方法showAddressList();}else{alert("刪除地址失敗")}},error: function (xhr) {alert("刪除收貨地址時產生未知的異常"+xhr.message)}})};
? ? ? ? 但是!!!可能會出現這個問題
Uncaught SyntaxError: Invalid or unexpected token (at address.html:1:12)
?在檢查代碼和業務邏輯沒有問題后,發現可能是 #{aid} 是占位符,在后續被替換為真實值。但如果替換失敗或未正確處理,最終渲染出來的 HTML 可能會是
<a οnclick="setDefault()" class="btn btn-xs add-def btn-default">設為默認</a>
????????此時 setDefault() 調用缺少參數,如果函數定義要求必須傳參(如 function setDefault(aid)),當點擊按鈕時就會因為參數缺失導致 JS 報錯,甚至出現 Invalid or unexpected token 這類錯誤?
解決方法:
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 onclick="deleteById(#{aid})" class="btn btn-xs add-del btn-info"><span class="fa fa-trash-o"></span> 刪除</a></td>\n' +'<td><a onclick="setDefault(#{aid})" class="btn btn-xs add-def btn-default">設為默認</a></td>\n' +'</tr>';tr = tr.replace("#{tag}", list[i].tag).replace("#{name}", list[i].name).replace("#{address}", list[i].address).replace("#{phone}", list[i].phone).replace(/#{aid}/g, list[i].aid); // 注意這里使用全局替換
????????使用 .replace(/#{aid}/g, ...) 可以確保所有匹配的 #{aid} 都被替換
????????重啟項目運行就沒有問題了?
熱銷排行
1. 創建數據庫表
CREATE TABLE t_product (id int(20) NOT NULL COMMENT '商品id',category_id int(20) DEFAULT NULL COMMENT '分類id',item_type varchar(100) DEFAULT NULL COMMENT '商品系列',title varchar(100) DEFAULT NULL COMMENT '商品標題',sell_point varchar(150) DEFAULT NULL COMMENT '商品賣點',price bigint(20) DEFAULT NULL COMMENT '商品單價',num int(10) DEFAULT NULL COMMENT '庫存數量',image varchar(500) DEFAULT NULL COMMENT '圖片路徑',`status` int(1) DEFAULT '1' COMMENT '商品狀態 1:上架 2:下架 3:刪除',priority int(10) DEFAULT NULL COMMENT '顯示優先級',created_time datetime DEFAULT NULL COMMENT '創建時間',modified_time datetime DEFAULT NULL COMMENT '最后修改時間',created_user varchar(50) DEFAULT NULL COMMENT '創建人',modified_user varchar(50) DEFAULT NULL COMMENT '最后修改人',PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. 創建實體類
package com.cy.store.entity;import lombok.Data;/** 商品數據的實體類 */
@Data
public class Product extends BaseEntity {private Integer id;private Integer categoryId;private String itemType;private String title;private String sellPoint;private Long price;private Integer num;private String image;private Integer status;private Integer priority;
}
3. 持久層
3.1 編寫sql
????????priority根據優先級進行排序降序
select * from t_product where status=1 order by priority desc limit 0,4
3.2 編寫mapper接口以及抽象方法
? ? ? ? 創建ProductMapper 接口,編寫抽象方法,返回值是一個集合
@Mapper
public interface ProductMapper {/*** 查詢熱銷商品* @return 熱銷商品列表*/List<Product> findHotList();
}
3.3 編寫sql映射
<?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.ProductMapper"><resultMap id="ProductEntityMap" type="com.cy.store.entity.Product"><id column="id" property="id"/><result column="category_id" property="categoryId"/><result column="item_type" property="itemType"/><result column="sell_point" property="sellPoint"/><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><!-- 查詢熱銷商品列表 --><!-- 返回值為商品列表,包含id,categoryId,itemType,sellPoint等字段 --><!-- SQL說明:從t_product表中查詢狀態為1(上架)的商品,按優先級降序排列,取前4條記錄 --><select id="findHotList" resultMap="ProductEntityMap">select * from t_product where status=1 order by priority desc limit 0,4</select>
</mapper>
4. 業務層
4.1 service接口編寫抽象方法
public interface ProductService {/** 查詢熱銷商品 */List<Product> findHotList();
}
4.2 實現類實現接口,重寫抽象方法
@Service
public class ProductServiceImpl implements ProductService {@Autowiredprivate ProductMapper productMapper;/*** 查詢熱銷商品列表* @return 熱銷商品列表*/@Overridepublic List<Product> findHotList() {List<Product> list = productMapper.findHotList();
// 將前端用戶到的數據設為null,減小體量for (Product product : list) {product.setPriority(null);product.setCreatedUser(null);product.setCreatedTime(null);product.setModifiedUser(null);product.setModifiedTime(null);}return list;}}
5. controller控制層
5.1 設計請求
請求路徑:/products/hotList
請求方式:GET
響應結果:JsonResult<List<Product>>
5.2 將商品的頁面進行白名單放行
? ? ? ? 在LoginInterceptorConfigure類中配置放行白名單
5.3?PruductController類實現請求
package com.cy.store.controller;import com.cy.store.entity.Product;
import com.cy.store.service.ProductService;
import com.cy.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/products")
public class ProductController extends BaseController{@Autowiredprivate ProductService productService;@RequestMapping("/hotList")public JsonResult<List<Product>> getHotList(){List<Product> data = productService.findHotList();return new JsonResult<>(OK,data);}
}
6. 前端頁面
- 當頁面展示時就調用方法獲取熱門商品列表信息進行渲染
- href="product.html?id=#{id}"?將id拼接到href上,當點擊商品信息時,跳轉到對應的商品詳情頁
- /#{image}/g,將所有的屬性進行替換
<script type="text/javascript">$(document).ready(function() {showHotList();});function showHotList() {$("#hot-list").empty();$.ajax({url: "/products/hotList",type: "GET",success: function(json) {var list = json.data;for (var i = 0; i < list.length; i++) {console.log(list[i].title);//調試用var html = '<div class="col-md-12">'+ '<div class="col-md-7 text-row-2"><a href="product.html?id=#{id}">#{title}</a></div>'+ '<div class="col-md-2">¥#{price}</div>'+ '<div class="col-md-3"><img src="..#{image}collect.png" class="img-responsive" /></div>'+ '</div>';html = html.replace(/#{id}/g, list[i].id);html = html.replace(/#{title}/g, list[i].title);html = html.replace(/#{price}/g, list[i].price);html = html.replace(/#{image}/g, list[i].image);$("#hot-list").append(html);}}});}</script>