10天手敲一个SpringBoot网上商城项目(九)—— 确认订单、创建订单功能的实现及AOP
静态资源及sql文件分享
链接:https://pan.baidu.com/s/1X-yjmQcPD3PqS21x0HplNA?pwd=23gr
提取码:23gr
文章目录
- 确认订单
- 1.确认订单-持久层
- 1.1规划需要执行的SQL语句
- 1.2设计接口和抽象方法
- 1.3配置映射
- 1.4单元测试
- 2.确认订单-业务层
- 2.1规划异常
- 2.2设计接口和抽象方法及实现
- 2.3单元测试
- 3.确认订单-控制层
- 3.1处理异常
- 3.2设计请求
- 3.3处理请求
- 4.确认订单-前端页面
- 4.1显示勾选的购物车数据
- 4.2显示选择收货地址
- 创建订单
- 1.创建数据表
- 2.创建用户的实体类
- 3.创建订单-持久层
- 3.1规划需要执行的SQL语句
- 3.2实现接口和抽象方法
- 3.3编写映射
- 3.4单元测试
- 4.创建订单-业务层
- 4.1规划异常
- 4.2实现接口和抽象方法及实现
- 4.3单元测试
- 5.创建订单-控制层
- 5.1处理异常
- 5.2设计请求
- 5.3处理请求
- 6.创建订单-前端页面
- AOP
- 1.Spring AOP
- 2.切面方法
- 3 统计业务方法执行时长
确认订单
1.确认订单-持久层
1.1规划需要执行的SQL语句
用户在购物车列表页中通过随机勾选相关的商品,在点击"结算"按钮后跳转到"确认订单页",在这个页面中需要展示用户在上个页面所勾选的"购物车列表页"中对应的数据.说白了也就是列表展示,且展示的内容还是来自于购物车表.但是用户勾选了哪些商品呢,所以"购物车列表页"需要将用户勾选的商品id传递给"确认订单页"
所以在持久层需要完成“根据若干个不确定的id值,查询购物车数据表,显示购物车中的数据信息”。则需要执行的SQL语句大致是。
selectcid,uid,pid,t_cart.price,t_cart.num,title,t_product.price as realPrice,image
from t_cart
left join t_product on t_cart.pid = t_product.id
wherecid in (?,?,?)
order byt_cart.created_time desc
注意where cid in (?,?,?),这里是需要传入cid的集合
1.2设计接口和抽象方法
在CartMapper接口中添加findVOByCids抽象方法
List<CartVO> findVOByCids(Integer[] cids);
1.3配置映射
1.在CartMapper.xml文件中添加SQL语句的映射配置
<select id="findVOByCids" resultType="com.cy.store.vo.CartVO">selectcid,uid,pid,t_cart.price,t_cart.num,title,t_product.price as realPrice,imagefrom t_cartleft join t_product on t_cart.pid = t_product.idwherecid in (<foreach collection="array" item="cid" separator=",">#{cid}</foreach>)order byt_cart.created_time desc
</select>
foreach循环就是一个for循环
- collection标识循环的是list集合还是数组,如果是list集合就用collection=“list”
- item用来接收每次循环获取的值
- separator标识循环出来的值中间用什么隔开,且最后循环出来的值后面不加
1.4单元测试
在CartMapperTests测试类中添加findVOByCids方法进行测试
@Test
public void findVOByCids() {Integer[] cids = {1, 2, 6, 8, 100};//可以写表中不存在的,无非就是查不到数据,并不会报错List<CartVO> list = cartMapper.findVOByCids(cids);for (CartVO item : list) {System.out.println(item);}
}
2.确认订单-业务层
2.1规划异常
查询语句,没有需要规划的异常,在业务层判断这几条购物车商品的数据归属是否正确,如果不正确也不需要抛出异常,直接从查询到的数据中移除该商品就行了
2.2设计接口和抽象方法及实现
1.在ICartService接口中添加getVOByCids()抽象方法
List<CartVO> getVOByCids(Integer uid, Integer[] cids);//uid是为了判断数据归属是否正确
2.在CartServiceImpl类中重写业务接口中的抽象方法
@Override
public List<CartVO> getVOByCids(Integer uid, Integer[] cids) {List<CartVO> list = cartMapper.findVOByCids(cids);//可以使用for遍历,这里玩个新的,用迭代器遍历Iterator<CartVO> it = list.iterator();while (it.hasNext()) {//指向的是该元素之前,所以需要next得到该元素CartVO cart = it.next();if (!cart.getUid().equals(uid)) {/*** 不能用list.remove(cart)* 在迭代器进行遍历的时候不能使用集合的移除* 方法,需要用迭代器特有的移除方法*/it.remove();}}return list;
}
2.3单元测试
业务层只是调用持久层获取数据并判断归属是否正确,这里不再测试
3.确认订单-控制层
3.1处理异常
业务层没有抛出异常,所以不需要处理异常
3.2设计请求
- /carts/list
- GET
- Integer[] cids, HttpSession session
- JsonResult<List<CartVO>>
3.3处理请求
1.在CartController类中添加处理请求的getVOByCids()方法。
@RequestMapping("list")
public JsonResult<List<CartVO>> findVOByCids(Integer[] cids, HttpSession session) {List<CartVO> data = cartService.getVOByCids(getUidFromSession(session), cids);return new JsonResult<>(OK, data);
}
启动服务,登录后在地址栏输入http://localhost:8080/carts/list?cids=1&cids=5&cids=7进行测试
4.确认订单-前端页面
4.1显示勾选的购物车数据
1.检查cart.html页面,里面form标签的action="orderConfirm.html"属性(规定表单数据提交到哪里)和结算按钮的类型"type=submit"是必不可少的,这样点击"结算"时才能将数据传给"确认订单页"并在"确认订单页"展示选中的商品数据
2.在orderConfirm.html页面中实现自动加载从cart.html页面中传递过来的cids数据,再去请求ajax,然后将后端返回的数据填充在页面的某个区域中
3.orderConfirm.js文件中
$(“.link-pay”).click(……)作用:点击"在线支付"后跳转到支付页面,这个其实就是下个模块要做的"创建订单"功能,该功能需要和数据库交互,所以不是在前端实现的,所以这行代码无用
$(“.link-success”).click(…):在orderConfirm.html页面没有class为link-success的标签,所以这行代码不会被执行
综上两条,orderConfirm.js文件在orderConfirm.html页面中无用,但存在可能会和下个模块"创建订单"功能冲突(下个模块会实现点击"创建订单"后页面跳转),所以注释掉
下面在orderConfirm.html页面编写js代码
<script type="text/javascript">$(document).ready(function() {showCartList();});function showCartList() {$("#cart-list").empty();$.ajax({url: "/carts/list",type: "GET",data: location.search.substr(1),dataType: "JSON",success: function(json) {if (json.state == 200) {var list = json.data;console.log(location.search.substr(1));//调试用//声明两个变量用于更新"确认订单"页的总件数和总价var allCount = 0;var allPrice = 0;for (var i = 0; i < list.length; i++) {var tr = '<tr>\n' +'<td><img src="..#{image}collect.png" class="img-responsive" /></td>\n' +'<td>#{title}</td>\n' +'<td>¥<span>#{price}</span></td>\n' +'<td>#{num}</td>\n' +'<td><span>#{totalPrice}</span></td>\n' +'</tr>';tr = tr.replace("#{image}",list[i].image);tr = tr.replace("#{title}",list[i].title);tr = tr.replace("#{price}",list[i].realPrice);tr = tr.replace("#{num}",list[i].num);tr = tr.replace("#{totalPrice}",list[i].realPrice*list[i].num);$("#cart-list").append(tr);//更新"确认订单"页的总件数和总价allCount += list[i].num;allPrice += list[i].realPrice*list[i].num;}$("#all-count").html(allCount);$("#all-price").html(allPrice);}},error: function (xhr) {alert("在确认订单页加载勾选的购物车数据时发生未知的异常"+xhr.status);}});}
</script>
1.为什么点击购物车列表页面的"结算"按钮后地址栏中会请求http://localhost:8080/web/orderConfirm.html?cids=6&cids=5呢,因为该按钮有一个type=submit属性,且表单有一个action="orderConfirm.html"属性,所以点击该按钮后会携带表单中参数自动跳转
会携带哪些参数呢:把表单中有name属性的标签的value值传递出去,针对这个请求传递的是name"cids",其value值根据勾选的商品而定,可以是1或3或10
2.data: location.search.substr(1)这个API的参数为0表示截取地址栏中?后面的数据,即参数
如果这个API的参数为0则表示截取地址栏中?前面的数据,即请求地址
4.2显示选择收货地址
收货地址存放在前端的一个select下拉列表中,我们需要将查询到的当前登录用户的收货地址动态的加载到这个下拉列表中.从数据库的角度看,是一个select查询语句,在"收货地址列表展示"模块已经编写了该持久层,业务层,控制层,所以这里只需要编写对应的前端页面就可以了
1.在orderConfirm.html页面中的ready函数中添加showAddressList方法的调用,使确认订单页加载时能够自动从后端获取该用户地址填充到select控件中并将第一个地址显示出来
$(document).ready(function() {showCartList();showAddressList();
});
2.在orderConfirm.html页面中编写showAddressList方法
function showAddressList() {$("#address-list").empty();$.ajax({url: "/addresses",type: "GET",dataType: "JSON",success: function(json) {if (json.state == 200) {var list = json.data;for (var i = 0; i < list.length; i++) {/*value="#{aid}"在该模块没有用,但是扔写上,只要是从数据库查到到的数据,都要让前端页面的该条数据和id绑定(因为可能干别的什么时需要用到,就比如说下一个"创建订单"模块就需要根据前端传给后端的aid查询用户选中的是哪一个地址然后将其加入订单表)* */var opt = '<option value="#{aid}">#{name} #{tag} #{provinceName}#{cityName}#{areaName}#{address} #{tel}</option>';opt = opt.replace("#{aid}",list[i].aid);opt = opt.replace("#{name}",list[i].name);opt = opt.replace("#{tag}",list[i].tag);opt = opt.replace("#{provinceName}",list[i].provinceName);opt = opt.replace("#{cityName}",list[i].cityName);opt = opt.replace("#{areaName}",list[i].areaName);opt = opt.replace("#{address}",list[i].address);opt = opt.replace("#{tel}",list[i].tel);$("#address-list").append(opt);}}},error: function (xhr) {alert("在确认订单页加载用户地址时发生未知的异常"+xhr.status);}});
}
创建订单
1.创建数据表
1.使用use命令先选中store数据库。
USE store;
2.在store数据库中创建t_order和t_order_item数据表
针对该模块可以将t_order_item表和t_order表合并,但是以后可能开发某个模块可能单独用到t_order_item(比如用户查看订单时只需要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;
2.创建用户的实体类
1.entity包下创建Order实体类并继承BaseEntity类
/** 订单数据的实体类 */
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;/*** get,set* equals和hashCode* toString*/
}
2.在com.cy.store.entity包下创建OrderItem实体类并继承BaseEntity类
/** 订单中的商品数据 */
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;/*** get,set* equals和hashCode* toString*/
}
3.创建订单-持久层
3.1规划需要执行的SQL语句
1.插入订单数据的SQL语句
inert into t_order (aid除外的所有字段) values (字段的值)
2.插入某一个订单中商品数据的SQL语句
inert into t_order (id除外的所有字段) values (字段的值)
3.2实现接口和抽象方法
在mapper包下创建OrderMapper接口并在接口中添加抽象方法
public interface OrderMapper {/*** 插入订单数据* @param order 订单数据* @return 受影响的行数*/Integer insertOrder(Order order);/*** 插入某一个订单中商品数据* @param orderItem 订单中商品数据* @return 受影响的行数*/Integer insertOrderItem(OrderItem orderItem);
}
3.3编写映射
创建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"><!-- 插入订单数据 --><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><!-- 插入订单商品数据 --><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>
3.4单元测试
创建OrderMapperTests测试类并添加测试方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderMapperTests {@Autowiredprivate OrderMapper orderMapper;@Testpublic void insertOrder() {Order order = new Order();order.setUid(31);order.setRecvName("小王");order.setRecvPhone("133333");orderMapper.insertOrder(order);}@Testpublic void insertOrderItem() {OrderItem orderItem = new OrderItem();orderItem.setOid(1);orderItem.setPid(10000001);orderItem.setTitle("高档铅笔");orderMapper.insertOrderItem(orderItem);}
}
4.创建订单-业务层
4.1规划异常
无异常
4.2实现接口和抽象方法及实现
查看订单表的字段从而分析业务层方法需要哪些参数:
oid:主键自增,所以不需要该参数
uid:由控制层获取session中uid传给业务层,所以需要该参数
recv_name:通过"确认订单页"传递选中的地址aid,根据aid在在业务层调用已经声明的findByAid方法(该方法是在做"设置默认地址"模块时创建的,只在持久层创建了,并没有在业务层继续实现),所以需要参数aid
recv_phone:同上
recv_province:同上
recv_city:同上
recv_area:同上
recv_address:同上
total_price:根据前端传来的cids查询出每类商品数量和单价,然后相乘后求和,所以需要参数Integer[] cids
status:默认是0,所以不需要该参数
order_time:业务层实现方法内部可以声明,所以不需要该参数
pay_time:"创建订单"模块不需要此参数
created_user:由控制层获取session中username传给业务层,所以需要该参数
created_time:业务层实现方法内部可以声明,所以不需要该参数
modified_user:由控制层获取session中username传给业务层,所以需要该参数
modified_time:业务层实现方法内部可以声明,所以不需要该参数
综上分析,需要的参数是uid和aid,且需要在IAddressService接口添加getByAid()方法来获取选中的收货地址的详细数据:
1.在IAddressService接口中添加getByAid()方法
Address getByAid(Integer aid, Integer uid);
2.在AddressServiceImpl类中实现接口中的getByAid()抽象方法
@Override
public Address getByAid(Integer aid, Integer uid) {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;
}
3.在service包下创建IOrderService业务层接口并添加抽象方法用于创建订单
public interface IOrderService {Order create(Integer aid, Integer[] cids, Integer uid, String username);
}
返回值是Order是因为还要在下个页面展示订单详细信息
4.在impl包下创建OrderServiceImpl并编写代码实现订单和订单中所有商品数据的插入操作
@Service
public class OrderServiceImpl implements IOrderService {@Autowiredprivate OrderMapper orderMapper;//需要调用业务层的getByAid方法@Autowiredprivate IAddressService addressService;//需要调用业务层的getVOByCids方法@Autowiredprivate ICartService cartService;//需要调用业务层的getByUid方法private IUserService userService;@Overridepublic Order create(Integer aid, Integer[] cids, Integer uid, String username) {//返回的列表中的对象都是即将下单的List<CartVO> list = cartService.getVOByCids(uid, cids);long totalPrice = 0L;for (CartVO cartVO : list) {totalPrice += cartVO.getRealPrice()*cartVO.getNum();}Address address = addressService.getByAid(aid, uid);Order order = new Order();order.setUid(uid);//封装收货地址order.setRecvName(address.getName());order.setRecvPhone(address.getPhone());order.setRecvProvince(address.getProvinceName());order.setRecvCity(address.getCityName());order.setRecvArea(address.getAreaName());order.setRecvAddress(address.getAddress());//封装创建时间,支付状态和总价order.setOrderTime(new Date());order.setStatus(0);order.setTotalPrice(totalPrice);//封装四个日志order.setCreatedUser(username);order.setCreatedTime(new Date());order.setModifiedUser(username);order.setModifiedTime(new Date());Integer rows = orderMapper.insertOrder(order);if (rows != 1) {throw new InsertException("插入数据时产生未知的异常");}//插入数据——将某条订单的所有商品的详细数据插入for (CartVO cartVO : list) {OrderItem orderItem = new OrderItem();/*** 此时获取的oid不为空,因为在配置文件里面开启了oid主* 键自增,所以上面的代码执行插入时就自动将oid赋值了*/orderItem.setOid(order.getOid());orderItem.setPid(cartVO.getPid());orderItem.setTitle(cartVO.getTitle());orderItem.setImage(cartVO.getImage());orderItem.setPrice(cartVO.getRealPrice());orderItem.setNum(cartVO.getNum());orderItem.setCreatedUser(username);orderItem.setCreatedTime(new Date());orderItem.setModifiedUser(username);orderItem.setModifiedTime(new Date());rows = orderMapper.insertOrderItem(orderItem);if (rows != 1) {throw new InsertException("插入数据时产生未知的异常");}}return order;}
}
4.3单元测试
创建OrderServiceTests测试类并添加create()方法进行功能测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class OrderServiceTests {@Autowiredprivate IOrderService orderService;@AutowiredIUserService userService;@Testpublic void create() {Integer[] cids = {2,4,6};Order order = orderService.create(13, cids, 11, "小红");System.out.println(order);}
}
5.创建订单-控制层
5.1处理异常
没有异常需要处理
5.2设计请求
- /orders/create
- GET
- Integer aid, Integer[] cids, HttpSession session
- JsonResult<Order>
5.3处理请求
controller包下创建OrderController类,并继承自BaseController类,在类中编写请求方法
@RestController
@RequestMapping("orders")
public class OrderController extends BaseController {@Autowiredprivate IOrderService orderService;@RequestMapping("create")public JsonResult<Order> create(Integer aid, Integer[] cids, HttpSession session) {Order data = orderService.create(aid,cids,getUidFromSession(session),getUsernameFromSession(session));return new JsonResult<>(OK,data);}
}
6.创建订单-前端页面
在"确认订单页"添加发送请求的处理方法使点击"在线支付"按钮可以创建订单并跳转到"支付信息页"(支付页显示详细商品信息这个功能这里不做了)
请求参数是通过字符串拼接得到的,那么就必须用get请求,因为post请求不能拼接字符串
$("#btn-create-order").click(function() {var aid = $("#address-list").val();//12var 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=8type: "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的切面编程进行开发
1.Spring AOP
AOP:面向切面(Aspect)编程。AOP并不是Spring框架的特性(Spring已经被整合到了SpringBoot中,所以如果AOP是Spring框架的特性,那么就不需要手动导包,只需要在一个类上写@Aspect注解,鼠标放到该注解上按alt+enter就可以自动导包了,但是事与愿违,所以说AOP并不是Spring框架的特性),只是Spring很好的支持了AOP。
使用步骤:
- 首先定义一个类,将这个类作为切面类
- 在这个类中定义切面方法(5种:前置,后置,环绕,异常,最终)
- 将这个切面方法中的业务逻辑对应的代码进行编写和设计
- 通过连接点来连接目标方法,就是用粗粒度表达式和细粒度表达式来进行连接
2.切面方法
1.切面方法的访问权限是public。
2.切面方法的返回值类型可以是void或Object,如果该方法被@Around注解修饰,必须使用Object作为返回值类型,并返回连接点方法的返回值;如果使用的注解是@Before或@After等其他注解时,则自行决定。
3.切面方法的名称可以自定义。
4.切面方法可以接收参数,参数是ProccedingJoinPoint接口类型的参数.但是@Around所修饰的方法必须要传递这个参数.其他注解修饰的方法要不要该参数都可以
3 统计业务方法执行时长
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包下的类是任意的
- 第三个*表示类里面的方法是任意的
- (…)表示方法的参数是任意的
5.启动项目,在前端浏览器访问任意一个功能模块进行功能的测试
10天手敲一个SpringBoot网上商城项目(九)—— 确认订单、创建订单功能的实现及AOP相关推荐
- 10天手敲一个SpringBoot网上商城项目(四)——新增收货地址功能、获取省市区列表及名称功能的实现
静态资源及sql文件分享 链接:https://pan.baidu.com/s/1X-yjmQcPD3PqS21x0HplNA?pwd=23gr 提取码:23gr 文章目录 新增收货地址 1.创建数据 ...
- 【SSH网上商城项目实战17】购物车基本功能的实现
上一节我们将商品的详细页面做完了,并使用了hibernate的二级缓存加载详细页面来提高系统的性能.这节我们开始做购物车部分. 1. 添加新的表 首先我们向数据库中添加几张表:用户表.订单状态表.订单 ...
- 开发一个springboot+vue的项目【增加铃声制作的功能】
大家好呀,我是小孟! 参考的地址:https://github.com/Yin-Hongwei 前面小伙伴说要学习spring+vue的项目,我们录制了非常详细的教程,视频播放了突破了30w+,看来是 ...
- Android——教你10分钟手敲 Butter Knife(小刀注解)
教你10分钟手敲 Butter Knife(小刀注解) 在用 AndroidStudio 集成 Butter Knife(小刀注解)的时候感觉像极了J2EE的Spring IOC容器 自己研究了一下, ...
- SpringBoot网上商城(源代码+数据库)014
部分代码地址 https://gitee.com/ynwynwyn/starsea-mall-public SpringBoot网上商城(源代码+数据库) 一.系统介绍 前台商城系统:包含首页登录.商 ...
- SpringBoot网上商城(源代码+数据库+13000字文档)013
部分代码地址 https://gitee.com/ynwynwyn/mall-public SpringBoot网上商城(源代码+数据库+13000字文档)013 一.系统介绍 前台功能 商品分类查询 ...
- 【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示
转自:https://blog.csdn.net/eson_15/article/details/51405911 网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要 ...
- Django框架学习之网上商城项目一(后端设计)
目录 一.项目需求分析 1.项目介绍 1.技术难点 2.系统功能 3.项目环境 4.后台管理页面 二.数据库模型设计 一.准备工作 二.用户认证数据库模型设计 1. app/users/models. ...
- 【SSH网上商城项目实战21】从Demo中看易宝支付的流程
这一节我们先写一个简单点的Demo来测试易宝支付的流程,熟悉这个流程后,再做实际的开发,因为是一个Demo,所以我没有考虑一些设计模式的东西,就是直接实现支付功能.实现支付功能需要易宝给我们提供的AP ...
最新文章
- 『笔记』windows与CentOS间文件传输(win下实行)
- 静态库符号文件冲突的解决办法,已实践OK, mark
- 实现DFS之“骨头的诱惑”
- Java原型设计模式(Prototype)
- xml 属性value换行显示_python 标准库之xml.etree.ElementTree
- android palette组件用法,Palette颜色提取使用详解
- 5g理论速度_5G网络相当于500M宽带是真的吗?
- Centos下MySQL的安装及常见问题
- spring+hibernate+Struts2 整合(全注解及注意事项)
- cuSPARSE库:(十)cusparseCreateMatDescr()
- iis web服务扩展_Web服务器系统都有哪些类型?都有什么优点呢?
- laravel 集合从父中移除_在 Laravel 7 中优雅使用 UUID 教程
- c-free显示运行程序错误怎么办_Mac电脑没声音了怎么办?解决Mac上声音问题
- python学习笔记--python数据类型
- c# 使用NPOI按模板导出excel
- crash常用的调试命令
- Java基础知识(知识点)
- UINO优锘:产品实施“八步法”让客户感受DCV实施的专业性
- 亚马逊封号潮不断,亚马逊封号最新进展,亚马逊账号关联要怎么解决?怎么使用vmlogin浏览做到账号防关联
- 微信小程序实现一个简单的倒计时效果