金山網(wǎng)站制作百度業(yè)務(wù)范圍
計(jì)算機(jī)畢業(yè)設(shè)計(jì)|基于SpringBoot+MyBatis框架的電腦商城的設(shè)計(jì)與實(shí)現(xiàn)(訂單和AOP)
該項(xiàng)目分析著重于設(shè)計(jì)和實(shí)現(xiàn)基于SpringBoot+MyBatis框架的電腦商城。首先,通過深入分析項(xiàng)目所需數(shù)據(jù),包括用戶、商品、商品類別、收藏、訂單、購物車、收貨地址,建立了數(shù)據(jù)模型。關(guān)于SpringBoot+MyBatis框架的電腦商城的設(shè)計(jì)與實(shí)現(xiàn),我會(huì)按照系統(tǒng)概述與環(huán)境搭建、用戶注冊(cè)登錄、用戶資料修改、用戶上傳頭像、-用戶收貨管理、商品、購物車、訂單、AOP的順序依次更新。本文內(nèi)容主要是項(xiàng)目訂單和AOP部分。
創(chuàng)建訂單
1 訂單-創(chuàng)建數(shù)據(jù)表
1.使用use命令先選中store數(shù)據(jù)庫。
USE store;
2.在store數(shù)據(jù)庫中創(chuàng)建t_order和t_order_item數(shù)據(jù)表。
CREATE TABLE t_order (oid INT AUTO_INCREMENT COMMENT '訂單id',uid INT NOT NULL COMMENT '用戶id',recv_name VARCHAR(20) NOT NULL COMMENT '收貨人姓名',recv_phone VARCHAR(20) COMMENT '收貨人電話',recv_province VARCHAR(15) COMMENT '收貨人所在省',recv_city VARCHAR(15) COMMENT '收貨人所在市',recv_area VARCHAR(15) COMMENT '收貨人所在區(qū)',recv_address VARCHAR(50) COMMENT '收貨詳細(xì)地址',total_price BIGINT COMMENT '總價(jià)',status INT COMMENT '狀態(tài):0-未支付,1-已支付,2-已取消,3-已關(guān)閉,4-已完成',order_time DATETIME COMMENT '下單時(shí)間',pay_time DATETIME COMMENT '支付時(shí)間',created_user VARCHAR(20) COMMENT '創(chuàng)建人',created_time DATETIME COMMENT '創(chuàng)建時(shí)間',modified_user VARCHAR(20) COMMENT '修改人',modified_time DATETIME COMMENT '修改時(shí)間',PRIMARY KEY (oid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE t_order_item (id INT AUTO_INCREMENT COMMENT '訂單中的商品記錄的id',oid INT NOT NULL COMMENT '所歸屬的訂單的id',pid INT NOT NULL COMMENT '商品的id',title VARCHAR(100) NOT NULL COMMENT '商品標(biāo)題',image VARCHAR(500) COMMENT '商品圖片',price BIGINT COMMENT '商品價(jià)格',num INT COMMENT '購買數(shù)量',created_user VARCHAR(20) COMMENT '創(chuàng)建人',created_time DATETIME COMMENT '創(chuàng)建時(shí)間',modified_user VARCHAR(20) COMMENT '修改人',modified_time DATETIME COMMENT '修改時(shí)間',PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2 訂單-創(chuàng)建實(shí)體類
1.在com.cy.store.entity包下創(chuàng)建Order實(shí)體類。
package com.cy.store.entity;
import java.io.Serializable;
import java.util.Date;/** 訂單數(shù)據(jù)的實(shí)體類 */
public class Order extends BaseEntity implements Serializable {private Integer oid;private Integer uid;private String recvName;private String recvPhone;private String recvProvince;private String recvCity;private String recvArea;private String recvAddress;private Long totalPrice;private Integer status;private Date orderTime;private Date payTime;// Generate: Getter and Setter、Generate hashCode() and equals()、toString()
}
2.在com.cy.store.entity包下創(chuàng)建OrderItem實(shí)體類。
package com.cy.store.entity;
import java.io.Serializable;/** 訂單中的商品數(shù)據(jù) */
public class OrderItem extends BaseEntity implements Serializable {private Integer id;private Integer oid;private Integer pid;private String title;private String image;private Long price;private Integer num;// Generate: Getter and Setter、Generate hashCode() and equals()、toString()
}
3 訂單-持久層
3.1 規(guī)劃需要執(zhí)行的SQL語句
1.插入訂單數(shù)據(jù)的SQL語句大致是。
INSERT INTO t_order (uid,recv_name,recv_phone,recv_province,recv_city,recv_area,recv_address,total_price,status,order_time,pay_time,created_user,created_time,modified_user,modified_time
)
VALUES (#對(duì)應(yīng)字段的值列表
)
2.插入訂單商品數(shù)據(jù)的SQL語句大致是。
INSERT INTO t_order_item ( oid, pid, title, image, price, num, created_user, created_time, modified_user, modified_time
)
VALUES ( #對(duì)應(yīng)字段的值列表
)
3.2 接口與抽象方法
在com.cy.store.mapper包下創(chuàng)建OrderMapper接口并在接口中添加抽象方法。
package com.cy.store.mapper;
import com.cy.store.entity.Order;
import com.cy.store.entity.OrderItem;/** 處理訂單及訂單商品數(shù)據(jù)的持久層接口 */
public interface OrderMapper {/*** 插入訂單數(shù)據(jù)* @param order 訂單數(shù)據(jù)* @return 受影響的行數(shù)*/Integer insertOrder(Order order);/*** 插入訂單商品數(shù)據(jù)* @param orderItem 訂單商品數(shù)據(jù)* @return 受影響的行數(shù)*/Integer insertOrderItem(OrderItem orderItem);
}
3.3 配置SQL映射
1.在main\resources\mapper文件夾下創(chuàng)建OrderMapper.xml文件,并添加抽象方法的映射。
<?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.OrderMapper"><!-- 插入訂單數(shù)據(jù):Integer insertOrder(Order order) --><insert id="insertOrder" useGeneratedKeys="true" keyProperty="oid">INSERT INTO t_order (uid, recv_name, recv_phone, recv_province, recv_city, recv_area, recv_address,total_price,status, order_time, pay_time, created_user, created_time, modified_user,modified_time) VALUES (#{uid}, #{recvName}, #{recvPhone}, #{recvProvince}, #{recvCity}, #{recvArea},#{recvAddress}, #{totalPrice}, #{status}, #{orderTime}, #{payTime}, #{createdUser},#{createdTime}, #{modifiedUser}, #{modifiedTime})</insert><!-- 插入訂單商品數(shù)據(jù):Integer insertOrderItem(OrderItem orderItem) --><insert id="insertOrderItem" useGeneratedKeys="true" keyProperty="id">INSERT INTO t_order_item (oid, pid, title, image, price, num, created_user,created_time, modified_user, modified_time) VALUES (#{oid}, #{pid}, #{title}, #{image}, #{price}, #{num}, #{createdUser},#{createdTime}, #{modifiedUser}, #{modifiedTime})</insert>
</mapper>
2.在com.cy.store.mapper包下創(chuàng)建OrderMapperTests測(cè)試類,并添加測(cè)試方法。
package com.cy.store.mapper;
import com.cy.store.entity.Order;
import com.cy.store.entity.OrderItem;
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 OrderMapperTests {@Autowiredprivate OrderMapper orderMapper;@Testpublic void insertOrder() {Order order = new Order();order.setUid(31);order.setRecvName("小王");Integer rows = orderMapper.insertOrder(order);System.out.println("rows=" + rows);}@Testpublic void insertOrderItem() {OrderItem orderItem = new OrderItem();orderItem.setOid(1);orderItem.setPid(2);orderItem.setTitle("高檔鉛筆");Integer rows = orderMapper.insertOrderItem(orderItem);System.out.println("rows=" + rows);}
}
4 訂單-業(yè)務(wù)層
4.1 規(guī)劃異常
說明:無異常。
4.2 接口與抽象方法
1.由于處理過程中還需要涉及收貨地址數(shù)據(jù)的處理,所以需要先在IAddressService接口中添加getByAid()方法。
/*** 根據(jù)收貨地址數(shù)據(jù)的id,查詢收貨地址詳情* @param aid 收貨地址id* @param uid 歸屬的用戶id* @return 匹配的收貨地址詳情*/
Address getByAid(Integer aid, Integer uid);
2.在AddressServiceImpl類中實(shí)現(xiàn)接口中的getByAid()抽象方法。
@Override
public Address getByAid(Integer aid, Integer uid) {// 根據(jù)收貨地址數(shù)據(jù)id,查詢收貨地址詳情Address address = addressMapper.findByAid(aid);if (address == null) {throw new AddressNotFoundException("嘗試訪問的收貨地址數(shù)據(jù)不存在");}if (!address.getUid().equals(uid)) {throw new AccessDeniedException("非法訪問");}address.setProvinceCode(null);address.setCityCode(null);address.setAreaCode(null);address.setCreatedUser(null);address.setCreatedTime(null);address.setModifiedUser(null);address.setModifiedTime(null);return address;
}
3.在com.cy.store.service包下創(chuàng)建IOrderService業(yè)務(wù)層接口并添加抽象方法。
package com.cy.store.service;
import com.cy.store.entity.Order;/** 處理訂單和訂單數(shù)據(jù)的業(yè)務(wù)層接口 */
public interface IOrderService {/*** 創(chuàng)建訂單* @param aid 收貨地址的id* @param cids 即將購買的商品數(shù)據(jù)在購物車表中的id* @param uid 當(dāng)前登錄的用戶的id* @param username 當(dāng)前登錄的用戶名* @return 成功創(chuàng)建的訂單數(shù)據(jù)*/Order create(Integer aid, Integer[] cids, Integer uid, String username);
}
4.3 實(shí)現(xiàn)抽象方法
1.在com.cy.store.service.impl包下創(chuàng)建OrderServiceImpl業(yè)務(wù)層實(shí)現(xiàn)類并實(shí)現(xiàn)IOrderService接口;在類定義之前添加@Service注解,在類中添加OrderMapper訂單持久層對(duì)象、IAddressService處理收貨地址對(duì)象、ICartService購物車數(shù)據(jù)對(duì)象,并都添加@Autowired注解進(jìn)行修飾。
package com.cy.store.service.impl;
import com.cy.store.entity.Address;
import com.cy.store.entity.Order;
import com.cy.store.entity.OrderItem;
import com.cy.store.mapper.OrderMapper;
import com.cy.store.service.IAddressService;
import com.cy.store.service.ICartService;
import com.cy.store.service.IOrderService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.vo.CartVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;/** 處理訂單和訂單數(shù)據(jù)的業(yè)務(wù)層實(shí)現(xiàn)類 */
@Service
public class OrderServiceImpl implements IOrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate IAddressService addressService;@Autowiredprivate ICartService cartService;// ...
}
2.在OrderServiceImpl類中重寫父接口中的create()抽象方法。
@Transactional
@Override
public Order create(Integer aid, Integer[] cids, Integer uid, String username) {// 創(chuàng)建當(dāng)前時(shí)間對(duì)象// 根據(jù)cids查詢所勾選的購物車列表中的數(shù)據(jù)// 計(jì)算這些商品的總價(jià)// 創(chuàng)建訂單數(shù)據(jù)對(duì)象// 補(bǔ)全數(shù)據(jù):uid// 查詢收貨地址數(shù)據(jù)// 補(bǔ)全數(shù)據(jù):收貨地址相關(guān)的6項(xiàng)// 補(bǔ)全數(shù)據(jù):totalPrice// 補(bǔ)全數(shù)據(jù):status// 補(bǔ)全數(shù)據(jù):下單時(shí)間// 補(bǔ)全數(shù)據(jù):日志// 插入訂單數(shù)據(jù)// 遍歷carts,循環(huán)插入訂單商品數(shù)據(jù)// 創(chuàng)建訂單商品數(shù)據(jù)// 補(bǔ)全數(shù)據(jù):oid(order.getOid())// 補(bǔ)全數(shù)據(jù):pid, title, image, price, num// 補(bǔ)全數(shù)據(jù):4項(xiàng)日志// 插入訂單商品數(shù)據(jù)// 返回
}
3.OrderServiceImpl類中的create()方法具體邏輯代碼實(shí)現(xiàn)見下。
@Transactional
@Override
public Order create(Integer aid, Integer[] cids, Integer uid, String username) {// 創(chuàng)建當(dāng)前時(shí)間對(duì)象Date now = new Date();// 根據(jù)cids查詢所勾選的購物車列表中的數(shù)據(jù)List<CartVO> carts = cartService.getVOByCids(uid, cids);// 計(jì)算這些商品的總價(jià)long totalPrice = 0;for (CartVO cart : carts) {totalPrice += cart.getRealPrice() * cart.getNum();}// 創(chuàng)建訂單數(shù)據(jù)對(duì)象Order order = new Order();// 補(bǔ)全數(shù)據(jù):uidorder.setUid(uid);// 查詢收貨地址數(shù)據(jù)Address address = addressService.getByAid(aid, uid);// 補(bǔ)全數(shù)據(jù):收貨地址相關(guān)的6項(xiàng)order.setRecvName(address.getName());order.setRecvPhone(address.getPhone());order.setRecvProvince(address.getProvinceName());order.setRecvCity(address.getCityName());order.setRecvArea(address.getAreaName());order.setRecvAddress(address.getAddress());// 補(bǔ)全數(shù)據(jù):totalPriceorder.setTotalPrice(totalPrice);// 補(bǔ)全數(shù)據(jù):statusorder.setStatus(0);// 補(bǔ)全數(shù)據(jù):下單時(shí)間order.setOrderTime(now);// 補(bǔ)全數(shù)據(jù):日志order.setCreatedUser(username);order.setCreatedTime(now);order.setModifiedUser(username);order.setModifiedTime(now);// 插入訂單數(shù)據(jù)Integer rows1 = orderMapper.insertOrder(order);if (rows1 != 1) {throw new InsertException("插入訂單數(shù)據(jù)時(shí)出現(xiàn)未知錯(cuò)誤,請(qǐng)聯(lián)系系統(tǒng)管理員");}// 遍歷carts,循環(huán)插入訂單商品數(shù)據(jù)for (CartVO cart : carts) {// 創(chuàng)建訂單商品數(shù)據(jù)OrderItem item = new OrderItem();// 補(bǔ)全數(shù)據(jù):setOid(order.getOid())item.setOid(order.getOid());// 補(bǔ)全數(shù)據(jù):pid, title, image, price, numitem.setPid(cart.getPid());item.setTitle(cart.getTitle());item.setImage(cart.getImage());item.setPrice(cart.getRealPrice());item.setNum(cart.getNum());// 補(bǔ)全數(shù)據(jù):4項(xiàng)日志item.setCreatedUser(username);item.setCreatedTime(now);item.setModifiedUser(username);item.setModifiedTime(now);// 插入訂單商品數(shù)據(jù)Integer rows2 = orderMapper.insertOrderItem(item);if (rows2 != 1) {throw new InsertException("插入訂單商品數(shù)據(jù)時(shí)出現(xiàn)未知錯(cuò)誤,請(qǐng)聯(lián)系系統(tǒng)管理員");}}// 返回return order;
}
4.在com.cy.store.service測(cè)試包下創(chuàng)建OrderServiceTests測(cè)試類,并添加create()方法進(jìn)行功能測(cè)試。
package com.cy.store.service;
import com.cy.store.entity.Order;
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 OrderServiceTests {@Autowiredprivate IOrderService orderService;@Testpublic void create() {try {Integer aid = 21;Integer[] cids = {4, 5, 6,7};Integer uid = 31;String username = "訂單管理員";Order order = orderService.create(aid, cids, uid, username);System.out.println(order);} catch (ServiceException e) {System.out.println(e.getClass().getSimpleName());System.out.println(e.getMessage());}}
}
5 訂單-控制器層
5.1 處理異常
說明:無異常。
5.2 設(shè)計(jì)請(qǐng)求
設(shè)計(jì)用戶提交的請(qǐng)求,并設(shè)計(jì)響應(yīng)的方式。
請(qǐng)求路徑:/orders/create
請(qǐng)求參數(shù):Integer aid, Integer[] cids, HttpSession session
請(qǐng)求類型:POST
響應(yīng)結(jié)果:JsonResult<Order>
5.3 處理請(qǐng)求
1.在com.cy.store.controller包下創(chuàng)建OrderController類,并繼承自BaseController類;并在類前添加@RequestMapping(“orders”)注解和@RestController注解;在類中聲明IOrderService業(yè)務(wù)對(duì)象,然后添加@Autowired注解修飾;最后在類中添加處理請(qǐng)求的方法。
package com.cy.store.controller;
import com.cy.store.entity.Order;
import com.cy.store.service.IOrderService;
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 javax.servlet.http.HttpSession;@RestController
@RequestMapping("orders")
public class OrderController extends BaseController {@Autowiredprivate IOrderService orderService;@RequestMapping("create")public JsonResult<Order> create(Integer aid, Integer[] cids, HttpSession session) {// 從Session中取出uid和usernameInteger uid = getUidFromSession(session);String username = getUsernameFromSession(session);// 調(diào)用業(yè)務(wù)對(duì)象執(zhí)行業(yè)務(wù)Order data = orderService.create(aid, cids, uid, username);// 返回成功與數(shù)據(jù)return new JsonResult<Order>(OK, data);}
}
2.完成后啟動(dòng)項(xiàng)目,先登錄再訪問http://localhost:8080/orders/create?aid=21&cids=4&cids=5&cids=6&cids=7進(jìn)行測(cè)試。
6 訂單-前端頁面
1.在orderConfirm.xml頁面中的body標(biāo)簽內(nèi)的script標(biāo)簽內(nèi)添加“在線支付”按鈕的點(diǎn)擊時(shí)間。
$("#btn-create-order").click(function() {$.ajax({url: "/orders/create",data: $("#form-create-order").serialize(),type: "POST",dataType: "JSON",success: function(json) {if (json.state == 200) {alert("創(chuàng)建訂單成功!");console.log(json.data);} else {alert("創(chuàng)建訂單失敗!" + json.message);}},error: function(xhr) {alert("您的登錄信息已經(jīng)過期,請(qǐng)重新登錄!HTTP響應(yīng)碼:" + xhr.status);location.href = "login.html";}});
});
2.完成后啟動(dòng)項(xiàng)目,先登錄再訪問http://localhost:8080/web/cart.html頁面,勾選購車中的商品,再點(diǎn)擊“結(jié)算”按鈕,最后在訂單確認(rèn)頁中點(diǎn)擊“在線支付”按鈕進(jìn)行功能的測(cè)試。
AOP
1 Spring AOP
AOP:面向切面(Aspect)編程。AOP并不是Spring框架的特性,只是Spring很好的支持了AOP。
如果需要在處理每個(gè)業(yè)務(wù)時(shí),都執(zhí)行特定的代碼,則可以假設(shè)在整個(gè)數(shù)據(jù)處理流程中存在某個(gè)切面,切面中可以定義某些方法,當(dāng)處理流程執(zhí)行到切面時(shí),就會(huì)自動(dòng)執(zhí)行切面中的方法。最終實(shí)現(xiàn)的效果就是:只需要定義好切面方法,配置好切面的位置(連接點(diǎn)),在不需要修改原有數(shù)據(jù)處理流程的代碼的基礎(chǔ)之上,就可以使得若干個(gè)流程都執(zhí)行相同的代碼。
2 切面方法
1.切面方法的訪問權(quán)限是public。
2.切面方法的返回值類型可以是void或Object,如果使用的注解是@Around時(shí),必須使用Object作為返回值類型,并返回連接點(diǎn)方法的返回值;如果使用的注解是@Before或@After等其他注解時(shí),則自行決定。
3.切面方法的名稱可以自定義。
4.切面方法的參數(shù)列表中可以添加ProceedingJoinPoint接口類型的對(duì)象,該對(duì)象表示連接點(diǎn),也可以理解調(diào)用切面所在位置對(duì)應(yīng)的方法的對(duì)象,如果使用的注解是@Around時(shí),必須添加該參數(shù),反之則不是必須添加。
3 統(tǒng)計(jì)業(yè)務(wù)方法執(zhí)行時(shí)長(zhǎng)
1.在使用Spring AOP編程時(shí),需要先在pom.xml文件中添加兩個(gè)關(guān)于AOP的依賴aspectjweaver和aspectjtools。
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjtools</artifactId>
</dependency>
2.在com.cy.store.aop包下創(chuàng)建TimerAspect切面類,在類之前添加@Aspect和@Component注解修飾。
package com.cy.store.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Aspect
@Component
public class TimerAspect {}
3.在類中添加切面方法around(ProceedingJoinPoint pjp)。
public Object around(ProceedingJoinPoint pjp) throws Throwable {// 記錄起始時(shí)間long start = System.currentTimeMillis();// 執(zhí)行連接點(diǎn)方法,即切面所在位置對(duì)應(yīng)的方法。本項(xiàng)目中表示執(zhí)行注冊(cè)或執(zhí)行登錄等Object result = pjp.proceed();// 記錄結(jié)束時(shí)間long end = System.currentTimeMillis();// 計(jì)算耗時(shí)System.err.println("耗時(shí):" + (end - start) + "ms.");// 返回連接點(diǎn)方法的返回值return result;
}
4.最后需要在方法之前添加@Around注解,以配置連接點(diǎn),即哪些方法需要應(yīng)用該切面。
@Around("execution(* com.cy.store.service.impl.*.*(..))")
5.啟動(dòng)項(xiàng)目,在前端瀏覽器訪問任意一個(gè)功能模塊進(jìn)行功能的測(cè)試。
至此,基于SpringBoot+MyBatis框架的電腦商城的設(shè)計(jì)與實(shí)現(xiàn)所有部分已經(jīng)全部更新完成