创建订单
(一)创建数据库
在store数据库中创建t_order和t_order_item数据表
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 '收货人所在区', recv_address VARCHAR(50) COMMENT '收货详细地址', total_price BIGINT COMMENT '总价', status INT COMMENT '状态:0-未支付,1-已支付,2-已取消,3-已关闭,4-已完成', order_time DATETIME COMMENT '下单时间', pay_time DATETIME COMMENT '支付时间', created_user VARCHAR(20) COMMENT '创建人', created_time DATETIME COMMENT '创建时间', modified_user VARCHAR(20) COMMENT '修改人', modified_time DATETIME COMMENT '修改时间', 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 '商品标题', image VARCHAR(500) COMMENT '商品图片', price BIGINT COMMENT '商品价格', num INT COMMENT '购买数量', created_user VARCHAR(20) COMMENT '创建人', created_time DATETIME COMMENT '创建时间', modified_user VARCHAR(20) COMMENT '修改人', modified_time DATETIME COMMENT '修改时间', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(二)创建实体类
在entity包下创建Order实体类并继承BaseEntity类
@Data @AllArgsConstructor @NoArgsConstructor public class Order extends baseEntity{ 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; }
在com.cy.store.entity包下创建OrderItem实体类并继承BaseEntity类
@Data @NoArgsConstructor @AllArgsConstructor public class OrderItem extends baseEntity{ private Integer id; private Integer oid; private Integer pid; private String title; private String image; private Long price; private Integer num; }
(三)创建订单(持久层)
1.规划sql
插入订单数据的SQL语句
inert into t_order (aid除外的所有字段) values (字段的值)
插入某一个订单中商品数据的SQL语句
inert into t_order (id除外的所有字段) values (字段的值)
2.实现接口和抽象方法
在mapper包下创建OrderMapper接口并在接口中添加抽象方法
public interface OrderMapper { /** * 插入订单数据 * @param order 订单数据 * @return 受影响的行数 */ Integer addOrder(Order order); /** * 插入某一个订单中商品数据 * @param orderItem 订单中商品数据 * @return 受影响的行数 */ Integer addOrderItem(OrderItem orderItem); }
(四)创建订单(业务层)
1.规划异常
无异常需要规划
2.实现接口和抽象方法及实现
在IAddressService接口添加getByAid()方法来获取选中的收货地址的详细数据
//根据aid查询 Address getByAid(Integer uid,Integer aid);
在AddressServiceImpl类中实现接口中的getByAid()抽象方法
@Override public Address getByAid(Integer uid, Integer aid) { Address address = addressMapper.findByAid(aid); if (address==null){ throw new AddressNotFoundException("收货地址不存在"); } 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; }
在service包下创建IOrderService业务层接口并添加抽象方法用于创建订单
返回值是Order是因为还要在下个页面展示订单详细信息
public interface IOrderService { Order addOrder(Integer aid,Integer[] cids,Integer uid,String username); }
在impl包下创建OrderServiceImpl并编写代码实现订单和订单中所有商品数据的插入操作
@Service public class OrderServiceImpl implements IOrderService { @Resource private IAddressService addressService; @Autowired private ICartService cartService; @Resource private OrderMapper orderMapper; @Autowired private IUserService userService; @Override public Order addOrder(Integer aid, Integer[] cids, Integer uid, String username) { List<CartVo> list = cartService.getByCids(uid, cids); Long totalPrice=0L; for (CartVo c:list ) { totalPrice+= c.getRealPrice()*c.getNum(); } Address address = addressService.getByAid(uid, aid); Order order=new Order(); order.setUid(uid); order.setRecvProvince(address.getProvinceName()); order.setRecvName(address.getName()); order.setRecvCity(address.getCityName()); order.setRecvArea(address.getAreaName()); order.setRecvAddress(address.getAddress()); order.setRecvPhone(address.getPhone()); order.setOrderTime(new Date()); order.setTotalPrice(totalPrice); order.setModifiedUser(username); order.setModifiedTime(new Date()); order.setCreatedTime(new Date()); order.setStatus(0); order.setCreatedUser(username); Integer integer = orderMapper.addOrder(order); if (integer!=1){ throw new InsertException("订单显示错误"); } for (CartVo c:list ) { OrderItem orderItem=new OrderItem(); orderItem.setOid(order.getOid()); orderItem.setTitle(c.getTitle()); orderItem.setPrice(c.getRealPrice()); orderItem.setPid(c.getPid()); orderItem.setNum(c.getNum()); orderItem.setImage(c.getImage()); orderItem.setCreatedTime(new Date()); orderItem.setCreatedUser(username); orderItem.setModifiedTime(new Date()); orderItem.setModifiedUser(username); Integer integer1 = orderMapper.addOrderItem(orderItem); if (integer1!=1){ throw new InsertException("订单项插入产生异常"); } } return order; } }
(五)创建订单(控制层)
1.处理异常
无异常需要处理
2.设计请求
请求路径:/orders/create
请求方式:GET
请求参数:Integer aid, Integer[] cids, HttpSession session
响应结果:JsonResult< Order>
3.处理请求
controller包下创建OrderController类,并继承自BaseController类,在类中编写请求方法
@RestController @RequestMapping("/orders") public class OrderController extends BaseController{ @Autowired private IOrderService orderService; @GetMapping("/create") public JsonResult<Order> createOrder(Integer[] cids, Integer aid, HttpSession session){ Order order = orderService.addOrder(aid, cids, getuidfromsession(session), getusernamesession(session)); return new JsonResult<>(ok,order); } }
(六)创建订单(前端页面)
在orderConfirm.html页面编写js代码,(请求参数是通过字符串拼接得到的,那么就必须用get请求,因为post请求不能拼接字符串)
$("#btn-create-order").click(function() { var aid = $("#address-list").val();//12 var cids = location.search.substr(1);//cids=4&cids=6&cids=8 $.ajax({ url: "/orders/create", data: "aid=" + aid + "&" + cids,//aid=12&cids=4&cids=6&cids=8 type: "GET", dataType: "JSON", success: function(json) { if (json.state == 200) { location.href = "payment.html"; } else { alert("创建订单失败!" + json.message); } }, error: function(xhr) { alert("创建订单数据时产生未知的异常" + xhr.status); } }); });
AOP
检测项目所有业务层方法的耗时(开始执行时间和结束执行时间只差值),再在不改变项目主体流程代码的前提条件下完成此功能,就要用到AOP
如果我们想对业务某一些方法同时添加相同的功能需求,并且在不改变业务功能逻辑的基础之上进行完成,就可以使用AOP的切面编程进行开发
(一)Spring AOP
AOP:面向切面(Aspect)编程。AOP并不是Spring框架的特性(Spring已经被整合到了SpringBoot中,所以如果AOP是Spring框架的特性,那么就不需要手动导包,只需要在一个类上写@Aspect注解,鼠标放到该注解上按alt+enter就可以自动导包了,但是事与愿违,所以说AOP并不是Spring框架的特性),只是Spring很好的支持了AOP。
使用步骤:
首先定义一个类,将这个类作为切面类
在这个类中定义切面方法(5种:前置,后置,环绕,异常,最终)
将这个切面方法中的业务逻辑对应的代码进行编写和设计
通过连接点来连接目标方法,就是用粗粒度表达式和细粒度表达式来进行连接
(二)切面方法
1.切面方法的访问权限是public。
2.切面方法的返回值类型可以是void或Object,如果该方法被@Around注解修饰,必须使用Object作为返回值类型,并返回连接点方法的返回值;如果使用的注解是@Before或@After等其他注解时,则自行决定。
3.切面方法的名称可以自定义。
4.切面方法可以接收参数,参数是ProccedingJoinPoint接口类型的参数.但是@Around所修饰的方法必须要传递这个参数.其他注解修饰的方法要不要该参数都可以
(三)统计业务方法执行时长
1.因为AOP不是Spring内部封装的技术,所以需要进行导包操作:在pom.xml文件中添加两个关于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包下创建TimerAspect切面类,给类添加两个注解进行修饰:
@Aspect(将当前类标记为切面类)
@Component(将当前类的对象创建使用维护交由Spring容器维护)
@Aspect @Component public class TimerAspect { }
3.在类中添加切面方法,这里使用环绕通知的方式来进行编写
参数ProceedingJoinPoint接口表示连接点,也就是是目标方法的对象
public Object around(ProceedingJoinPoint pjp) throws Throwable { //开始时间 long start = System.currentTimeMillis(); //调用目标方法,比如login方法,getByUid方法 Object result = pjp.proceed(); //结束时间 long end = System.currentTimeMillis(); System.out.println("耗时:"+(end-start)); return result; }
4.将当前环绕通知映射到某个切面上,也就是指定连接的点.给around方法添加注解@Around
@Around("execution(* com.cy.store.service.impl.*.*(..))")
第一个表示方法返回值是任意的
第二个表示imp包下的类是任意的
第三个*表示类里面的方法是任意的
(…)表示方法的参数是任意的
后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹