新用户注册入口 老用户登录入口

[转载]秒杀项目之秒杀商品操作

文章作者:转载 更新时间:2023-02-25 23:20:34 阅读数量:120
文章标签:秒杀商品显示添加实体类(VO)数据库表设计前端界面
本文摘要:该文章详述了基于Spring Boot与MyBatis Plus开发环境下,实现秒杀商品显示和添加功能的具体步骤。首先通过实体类VO设计、SQL查询语句定义及Service层、Controller层的接口和实现方法,实现了从数据库中连表查询并展示秒杀商品信息的功能。在前端界面利用layui的table组件渲染数据,实现实时刷新与显示。对于秒杀商品的添加功能,同样借助实体类VO处理时间格式,并在Mapper层编写批量插入SQL,完成Service层和Controller层接口的定义与实现,从而支持用户在前端页面触发添加操作,将商品批量加入秒杀活动。整体流程紧密围绕秒杀商品的显示与添加核心功能展开,兼顾后端业务逻辑处理和前端交互体验优化。
转载文章

本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_60389087/article/details/123601288。

该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。

作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。

如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。

一、秒杀商品显示

1、使用生成器生成对应的表

记得在每个mapper类加入注解供spring扫描:

@Repository

2、后端写得到秒杀商品的方法

①、建实体类vo

用于连表查询,得到商品名字

package com.example.seckill.vo;import com.example.seckill.pojo.SeckillGoods;
import lombok.Data;@Data
public class SeckillGoodsVo extends SeckillGoods {private String goodsName;
}

②、在SexkillGoodsMapper.xml文件中定义sql

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.seckill.mapper.SeckillGoodsMapper"><select id="queryAll" resultType="com.example.seckill.vo.SeckillGoodsVo">select sg.*,g.goods_namefrom t_seckill_goods sg,t_goods gwhere sg.goods_id = g.gid;</select>
</mapper>

③、在mapper中定义

package com.example.seckill.mapper;import com.example.seckill.pojo.SeckillGoods;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.seckill.vo.SeckillGoodsVo;
import org.springframework.stereotype.Repository;import java.util.List;/*** <p>* 秒杀商品信息表 Mapper 接口* </p>** @author lv* @since 2022-03-19*/
@Repository
public interface SeckillGoodsMapper extends BaseMapper<SeckillGoods> {List<SeckillGoodsVo> queryAll();
}

④、service层与controller层

service:

ISeckillGoodsService:

package com.example.seckill.service;import com.example.seckill.pojo.SeckillGoods;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.SeckillGoodsVo;import java.util.List;/*** <p>* 秒杀商品信息表 服务类* </p>** @author lv* @since 2022-03-19*/
public interface ISeckillGoodsService extends IService<SeckillGoods> {ResponseResult<List<SeckillGoodsVo>> queryAll();
}

SeckillGoodsServiceImpl:

package com.example.seckill.service.impl;import com.example.seckill.pojo.SeckillGoods;
import com.example.seckill.mapper.SeckillGoodsMapper;
import com.example.seckill.service.ISeckillGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.SeckillGoodsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** <p>* 秒杀商品信息表 服务实现类* </p>** @author lv* @since 2022-03-19*/
@Service
public class SeckillGoodsServiceImpl extends ServiceImpl<SeckillGoodsMapper, SeckillGoods> implements ISeckillGoodsService {@Autowiredprivate SeckillGoodsMapper seckillGoodsMapper;@Overridepublic ResponseResult<List<SeckillGoodsVo>> queryAll() {List<SeckillGoodsVo> list= seckillGoodsMapper.queryAll();return ResponseResult.success(list);}
}

controller:

SeckillGoodsController:

package com.example.seckill.controller;import com.example.seckill.service.ISeckillGoodsService;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.SeckillGoodsVo;
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;/*** <p>* 秒杀商品信息表 前端控制器* </p>** @author lv* @since 2022-03-19*/
@RestController
@RequestMapping("/seckillGoods")
public class SeckillGoodsController {@Autowiredprivate ISeckillGoodsService seckillGoodsService;@RequestMapping("/queryAll")public ResponseResult<List<SeckillGoodsVo>> queryAll(){return seckillGoodsService.queryAll();} }

得到秒杀商品数据:

3、前端显示数据

 ①、编辑跳转秒杀界面

goodList.ftl:

<!DOCTYPE html>
<html lang="en">
<head><#include "../common/head.ftl"><style>.layui-this{background: deepskyblue !important;}</style></head>
<body class="layui-container layui-bg-orange">
<div class="layui-tab"><ul class="layui-tab-title"><li class="layui-this">普通商品</li><li>秒杀商品</li></ul><#--    普通商品--><div class="layui-tab-content"><div class="layui-tab-item layui-show"><div class="layui-form-item"><label class="layui-form-label">搜索栏</label><div class="layui-input-inline"><input type="text" id="normal_name" name="text" placeholder="请输入搜索内容" class="layui-input"></div><div class="layui-input-inline"><button class="layui-btn layui-btn-primary" id="normal_search">🔍</button><button class="layui-btn layui-btn-primary" id="normal_add">增加</button></div></div><table id="normal_goods" lay-filter="normal_goods"></table><script type="text/html" id="button_1"><a class="layui-btn layui-btn-xs" lay-event="normal_del">删除</a><a class="layui-btn layui-btn-xs" lay-event="normal_edit">编辑</a></script></div><#--秒杀界面--><div class="layui-tab-item"><div class="layui-form-item"><label class="layui-form-label">搜索栏</label><div class="layui-input-inline"><input type="text" id="seckill_name" name="text" placeholder="请输入搜索内容" class="layui-input"></div><div class="layui-input-inline"><button class="layui-btn layui-btn-primary" id="seckill_search">🔍</button><button class="layui-btn layui-btn-primary" id="seckill_add">增加</button></div></div><table id="seckill_goods" lay-filter="seckill_goods"></table></div></div></div>
</div>
<#--引入js-->
<script src="/static/asset/js/project/goodsList.js"></script>
</body>
</html>

②、获取数据

goodList.js:

    // 秒杀商品let seckill_table=table.render({elem: '#seckill_goods',height: 500,url: '/seckillGoods/queryAll' //数据接口,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},cols: [[ //表头{field: 'id', title: '秒杀商品编号', width:80, sort: true},{field: 'goodsId', title: '商品名字id'},{field: 'seckillPrice', title: '秒杀价格'},{field: 'stockCount', title: '秒杀库存'},{field: 'startDate', title: '活动开始时间'},{field: 'endDate', title: '活动结束时间'},{field: 'goodsName', title: '商品名称'}]]});

呈现界面:

 二、秒杀商品添加

1、后端:接收前端添加秒杀商品的数据

①、实体类vo:SeckillGoodsVo

  private List<Map<String,Object>> goods;

修改实体类时间的类型:SeckillGoods

    @ApiModelProperty("秒杀开始时间")@TableField("start_date")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Timestamp startDate;@ApiModelProperty("秒杀结束时间")@TableField("end_date")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Timestamp endDate;

②、mapper层:SeckillGoodsMapper

    int addGoods(SeckillGoodsVo seckillGoodsVo);

③、mapper.xml层:SeckillGoodsMapper

批量插入秒杀商品的sql语句:

    <insert id="addGoods">insert into t_seckill_goods(goods_id, seckill_price, stock_count, start_date, end_date)values<foreach collection="goods" item="g" separator=",">(#{g.gid},#{g.goodsPrice},#{g.goodsStock},#{startDate},#{endDate})</foreach></insert>

④、service层

ISeckillGoodsService:

  ResponseResult<List<SeckillGoodsVo>> addGoods(SeckillGoodsVo seckillGoodsVo);

SeckillGoodsServiceImpl:

    @Overridepublic ResponseResult<List<SeckillGoodsVo>> addGoods(SeckillGoodsVo seckillGoodsVo) {int goods=seckillGoodsMapper.addGoods(seckillGoodsVo);return ResponseResult.success(goods);}

⑤、controller层

    @RequestMapping("/add")public ResponseResult<List<SeckillGoodsVo>> add(@RequestBody SeckillGoodsVo seckillGoodsVo){return seckillGoodsService.addGoods(seckillGoodsVo);}

2、前端

①、定义数据与刷新、添加

goodsList.js:

var layer,row,seckill_table// 添加秒杀商品$("#seckill_add").click(()=>{layer.open({type:2,content: '/goods/SeckillGoodsOperate',area: ['800px','600px']})})// 秒杀商品刷新
var seckill_reload = ()=> {seckill_table.reload({page:{curr:1 //current} });
}
var layer,row,seckill_tablelayui.define(()=>{let table=layui.tablelayer=layui.layerlet $=layui.jquerylet normal_table=table.render({elem: '#normal_goods',height: 500,url: '/goods/queryAll' //数据接口,page: true //开启分页,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},//用于对分页请求的参数:page、limit重新设定名称request: {pageName: 'page' //页码的参数名称,默认:page,limitName: 'rows' //每页数据量的参数名,默认:limit},cols: [[ //表头{field: 'gid', title: '商品编号', width:80, sort: true, fixed: 'left'},{field: 'goodsName', title: '商品名字'},{field: 'goodsTitle', title: '商品标题'},{field: 'goodsImg',title: '商品图片',width:200,templet: (goods)  => `<b onmouseover='showImg("${goods.goodsImg}",this)'>` + goods.goodsImg + `</b>` },{field: 'goodsDetail', title: '商品详情'},{field: 'goodsPrice', title: '商品价格', sort: true},{field: 'goodsStock', title: '商品库存', sort: true},{field: 'operate', title: '商品操作',toolbar: '#button_1'}]]});// 刷新表格let reloadTable=()=>{let goodsName=$("#normal_value").val()// 【JS】自动化渲染的重载,重载表格normal_table.reload({where: {//设定异步数据接口的额外参数,height: 300goodsName},page:{curr:1 //current} });}// 搜索$("#normal_search").click(reloadTable)// 增加$("#normal_add").click(()=>{row = nullopenDialog()})//工具条事件table.on('tool(normal_goods)', function(obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"let data = obj.data; //获得当前行数据let layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)let tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)if (layEvent === 'normal_del') { //删除row = data//获得当前行的数据let url="/goods/del/"+data.gidlayer.confirm('确定删除吗?',{title:'删除'}, function(index){//向服务端发送删除指令og$.getJSON(url,{gid:data.gid}, function(ret){layer.close(index);//关闭弹窗reloadTable()});layer.close(index);//关闭弹窗});}if (layEvent === 'normal_edit') { //编辑row = dataopenDialog()} })// 页面弹出let openDialog=()=>{// 如果是iframe层layer.open({type: 2,content: '/goods/goodsOperate', //这里content是一个URL,如果你不想让iframe出现滚动条,你还可以content: ['http://sentsin.com', 'no']area:['800px','600px'],btn: ['确定','取消'],yes(index,layero){let url="/goods/insert"// 拿到表格数据let data=$(layero).find("iframe")[0].contentWindow.getFormData()if(row) {url="/goods/edit"}$.ajax({url,data,datatype: "json",success(res){layer.closeAll()reloadTable()layer.msg(res.message)} })} });}
// -------------------------秒杀商品-------------------------------------------seckill_table=table.render({elem: '#seckill_goods',height: 500,url: '/seckillGoods/queryAll' //数据接口,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},cols: [[ //表头{field: 'id', title: '秒杀商品编号', width:80, sort: true},{field: 'goodsId', title: '商品名字id'},{field: 'seckillPrice', title: '秒杀价格'},{field: 'stockCount', title: '秒杀库存'},{field: 'startDate', title: '活动开始时间'},{field: 'endDate', title: '活动结束时间'},{field: 'goodsName', title: '商品名称'}]]});// 添加秒杀商品$("#seckill_add").click(()=>{layer.open({type:2,content: '/goods/SeckillGoodsOperate',area: ['800px','600px']})})})// 图片显示
let showImg = (src,obj)=> {layer.tips(`<img src="${src}" width="100px">`, obj);
}// 秒杀商品刷新
var seckill_reload = ()=> {seckill_table.reload({page:{curr:1 //current} });
}

②、增加秒杀商品弹出页面样式

<!DOCTYPE html>
<html lang="en">
<head><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><link rel="stylesheet" href="/static/asset/js/layui/css/layui.css" media="all">
</head>
<body>
<div style="padding:15px 0px;"><div class="layui-condition"><form id="fm" name="fm" action="/" method="post" class="layui-form"><div class="layui-form-item"><div class="layui-inline"><label class="layui-form-label" style="width: 100px;text-align: left;">秒杀活动时间:</label><div class="layui-input-inline" style="width:280px;"><input type="text" class="layui-input" id="dt"></div><div class="layui-input-inline"><button class="layui-btn" id="btn_save" type="button"><i class="fa fa-search fa-right"></i>保 存</button></div></div></div></form></div><div class="layui-fluid" style="margin-top:-18px;"><table id="tb_goods" class="layui-table" lay-filter="tb_goods" style="margin-top:-5px;"></table></div>
</div>
<script src="/static/asset/js/layui/layui.js"></script>
<script src="/static/asset/js/project/seckillGoodsOperate.js"></script>
</body>
</html>

③、实现增加秒杀商品

seckillGoodsOperate.js:

layui.define(()=>{let table=layui.tablelet laydate = layui.laydatelet $=layui.jquerylet layer=layui.layer// 读取普通商品table.render({elem: '#tb_goods',height: 500,url: '/goods/queryAll' //数据接口,page: true //开启分页,parseData(res){ //res 即为原始返回的数据return {"code": res.code===200?0:1, //解析接口状态"msg": res.message, //解析提示文本"count": res.total, //解析数据长度"data": res.data //解析数据列表};},//用于对分页请求的参数:page、limit重新设定名称request: {pageName: 'page' //页码的参数名称,默认:page,limitName: 'rows' //每页数据量的参数名,默认:limit},cols: [[ //表头// 全选按钮{field: '', type:"checkbox"},{field: 'gid', title: '商品编号', width:80},{field: 'goodsName', title: '商品名字'},{field: 'goodsTitle', title: '商品标题'},{field: 'goodsDetail', title: '商品详情'},{field: 'goodsPrice', title: '商品价格', sort: true},{field: 'goodsStock', title: '商品库存', sort: true}]]});// 构建时间选择器//执行一个laydate实例laydate.render({elem: '#dt', //指定元素type: "datetime",range: "~"});$("#btn_save").click(()=>{// 获取时间let val=$("#dt").val()if(!val){layer.msg("请选择时间")return}// 解析时间2022-2-2 ~2022-5-2let startDate=new Date(val.split("~")[0]).getTime()let endDate=new Date(val.split("~")[1]).getTime()// 获得选中的普通商品,获取选中行的数据let rows= table.checkStatus('tb_goods').data; //idTest 即为基础参数 id 对应的值if(!rows||rows.length===0){layer.msg("请选择数据")return}layer.prompt(function(value, index, elem){// 修改每个商品的数量rows.forEach(e=>{e.goodsStock=value})let data={startDate,endDate,goods:rows}// 访问后台的秒杀商品的接口$.ajax({url: "/seckillGoods/add",contentType:'application/json',data: JSON.stringify(data),datatype:"json",//返回类型type:"post",success(res){parent.seckill_reload()layer.closeAll()parent.layer.closeAll()layer.msg(res.message)} })});})})

④、展示结果

 增加成功:

 三、秒杀商品的操作

1、后端操作秒杀单个商品详情

①、mapper层

SeckillGoodsMapper:

    Map<String,Object> querySeckillGoodsById(Long id);

mapper.xml文件:SeckillGoodsMapper.xml

    <select id="querySeckillGoodsById" resultType="map">select sg.id,sg.goods_id,sg.seckill_price,sg.stock_count,sg.start_date,sg.end_date,g.goods_img,g.goods_title,g.goods_detail,g.goods_name,(casewhen current_timestamp &lt; sg.start_date then 0when (current_timestamp between sg.start_date and sg.end_date) then 1when current_timestamp &gt; sg.end_date then 2end) goods_statusfrom t_goods g,t_seckill_goods sgwhere g.gid = sg.goods_idand sg.id = #{0}</select>

②、service层

ISeckillGoodsService:

    Map<String,Object> querySeckillGoodsById(Long id);

SeckillGoodsServiceImpl:

    @Overridepublic Map<String, Object> querySeckillGoodsById(Long id) {return seckillGoodsMapper.querySeckillGoodsById(id);}

③、controller层:SeckillGoodsController 

package com.example.seckill.controller;import com.example.seckill.service.ISeckillGoodsService;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.SeckillGoodsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;import java.util.List;/*** <p>* 秒杀商品信息表 前端控制器* </p>** @author lv* @since 2022-03-19*/
@Controller
@RequestMapping("/seckillGoods")
public class SeckillGoodsController {@Autowiredprivate ISeckillGoodsService seckillGoodsService;//    返回json@ResponseBody@RequestMapping("/queryAll")public ResponseResult<List<SeckillGoodsVo>> queryAll(){return seckillGoodsService.queryAll();}@ResponseBody@RequestMapping("/add")public ResponseResult<List<SeckillGoodsVo>> add(@RequestBody SeckillGoodsVo seckillGoodsVo){return seckillGoodsService.addGoods(seckillGoodsVo);}//    正常跳转界面
@RequestMapping("/query/{id}")
public ModelAndView querySeckillGoodsById(@PathVariable("id") Long id) {ModelAndView mv = new ModelAndView("/goods/goodsSeckill");mv.addObject("goods", seckillGoodsService.querySeckillGoodsById(id));return mv;
} }

2、前端展示

①、在goodsList.js增加列的操作

{field: '', title: '操作', width: 140,templet: function (d) {return `<div><a class="layui-btn layui-btn-xs layui-btn-danger">删除</a><a href="/seckillGoods/query/${d.id}" class="layui-btn layui-btn-xs layui-btn-normal">秒杀</a></div>`;} }

②、添加秒杀详情界面 :goodsSkill.ftl

<!DOCTYPE html>
<html lang="en">
<head><#include "../common/head.ftl"/>
</head>
<body>
<table style="position: absolute;top:-10px;" class="layui-table" border="1" cellpadding="0" cellspacing="0"><tr><td style="width:120px;">商品图片</td><td><img src="${goods['goods_img']}" alt=""></td></tr><tr><td>商品名称</td><td>${goods['goods_name']}</td></tr><tr><td>商品标题</td><td>${goods['goods_title']}</td></tr><tr><td>商品价格</td><td>${goods['seckill_price']}</td></tr><tr><td>开始时间</td><td><div style="position: relative;${(goods['goods_status']==1)?string('top:10px;','')}">${goods['start_date']?string("yyyy-MM-dd HH:mm:ss")}-${goods['end_date']?string("yyyy-MM-dd HH:mm:ss")}<#if goods['goods_status']==0>活动未开始<#elseif goods['goods_status']==1>活动热卖中<div style="position:relative;top:-10px;float:right;"><input type="hidden" id="goodsId" value="${goods['goods_id']}" name="goodsId"/><button class="layui-btn" id="buy">立即抢购</button></div><#else>活动已结束</#if></div></td></tr>
</table>
<script src="/static/asset/js/project/goodsSeckill.js"></script>
</body>
</html>

③、实现:goodsSkill.js

let layer, form, $;layui.define(() => {layer = layui.layerform = layui.form$ = layui.jquery$('#buy').click(() => {$.ajax({url: '/seckillOrder/addOrder',data: {goodsId: $('#goodsId').val()},dataType: 'json',type: 'post',async: false,success: function (rs) {if (rs.code === 200)layer.msg(rs.message)elselayer.msg(rs.message)} })});})

④、展示效果

点击秒杀: 

3、后端操作秒杀抢购功能

①、导入雪花id工具包:SnowFlake 

package com.example.seckill.util;@SuppressWarnings("all")
public class SnowFlake {/*** 起始的时间戳*/private final static long START_STMP = 1480166465631L;/*** 每一部分占用的位数*/private final static long SEQUENCE_BIT = 12; //序列号占用的位数private final static long MACHINE_BIT = 5;   //机器标识占用的位数private final static long DATACENTER_BIT = 5;//数据中心占用的位数/*** 每一部分的最大值*/private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);/*** 每一部分向左的位移*/private final static long MACHINE_LEFT = SEQUENCE_BIT;private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;private long datacenterId;  //数据中心private long machineId;     //机器标识private long sequence = 0L; //序列号private long lastStmp = -1L;//上一次时间戳public SnowFlake(long datacenterId, long machineId) {if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");}if (machineId > MAX_MACHINE_NUM || machineId < 0) {throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");}this.datacenterId = datacenterId;this.machineId = machineId;}public static void main(String[] args) {SnowFlake snowFlake = new SnowFlake(2, 3);long start = System.currentTimeMillis();for (int i = 0; i < 1000000; i++) {System.out.println(snowFlake.nextId());}System.out.println(System.currentTimeMillis() - start);}/*** 产生下一个ID** @return*/public synchronized long nextId() {long currStmp = getNewstmp();if (currStmp < lastStmp) {throw new RuntimeException("Clock moved backwards.  Refusing to generate id");}if (currStmp == lastStmp) {//相同毫秒内,序列号自增sequence = (sequence + 1) & MAX_SEQUENCE;//同一毫秒的序列数已经达到最大if (sequence == 0L) {currStmp = getNextMill();} } else {//不同毫秒内,序列号置为0sequence = 0L;}lastStmp = currStmp;return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分| datacenterId << DATACENTER_LEFT       //数据中心部分| machineId << MACHINE_LEFT             //机器标识部分| sequence;                             //序列号部分}private long getNextMill() {long mill = getNewstmp();while (mill <= lastStmp) {mill = getNewstmp();}return mill;}private long getNewstmp() {return System.currentTimeMillis();} }

②、service层

ISeckillOrderService :

package com.example.seckill.service;import com.example.seckill.pojo.SeckillOrder;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.seckill.pojo.User;
import com.example.seckill.util.response.ResponseResult;/*** <p>* 秒杀订单信息表 服务类* </p>** @author lv* @since 2022-03-19*/
public interface ISeckillOrderService extends IService<SeckillOrder> {ResponseResult<?> addOrder(Long goodsId, User user);
}

SeckillOrderServiceImpl :

package com.example.seckill.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.seckill.exception.BusinessException;
import com.example.seckill.mapper.GoodsMapper;
import com.example.seckill.mapper.OrderMapper;
import com.example.seckill.mapper.SeckillGoodsMapper;
import com.example.seckill.pojo.*;
import com.example.seckill.mapper.SeckillOrderMapper;
import com.example.seckill.service.ISeckillOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.seckill.util.SnowFlake;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.util.response.ResponseResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** <p>* 秒杀订单信息表 服务实现类* </p>** @author lv* @since 2022-03-19*/
@Service
public class SeckillOrderServiceImpl extends ServiceImpl<SeckillOrderMapper, SeckillOrder> implements ISeckillOrderService {@Autowiredprivate SeckillGoodsMapper seckillGoodsMapper;@Autowiredprivate GoodsMapper goodsMapper;@Autowiredprivate OrderMapper orderMapper;@Transactional(rollbackFor = Exception.class)@Overridepublic ResponseResult<?> addOrder(Long goodsId, User user) {
//        下单前判断库存数SeckillGoods goods = seckillGoodsMapper.selectOne(new QueryWrapper<SeckillGoods>().eq("goods_id", goodsId));if (goods == null) {throw new BusinessException(ResponseResultCode.SECKILL_ORDER_ERROR);}if (goods.getStockCount() < 1) {throw new BusinessException(ResponseResultCode.SECKILL_ORDER_ERROR);}
//         限购SeckillOrder one = this.getOne(new QueryWrapper<SeckillOrder>().eq("user_id", user.getId()).eq("goods_id", goodsId));if (one != null) {throw new BusinessException(ResponseResultCode.SECKILL_ORDER_EXISTS_ERROR);}
//       库存减一int i = seckillGoodsMapper.update(null, new UpdateWrapper<SeckillGoods>().eq("goods_id", goodsId).setSql("stock_count=stock_count-1"));
//       根据商品编号查询对应的商品(拿名字)Goods goodsInfo = goodsMapper.selectOne(new QueryWrapper<Goods>().eq("gid", goodsId));//       生成订单//生成雪花idSnowFlake snowFlake = new SnowFlake(5, 9);long id = snowFlake.nextId();//生成对应的订单Order normalOrder = new Order();normalOrder.setOid(id);normalOrder.setUserId(user.getId());normalOrder.setGoodsId(goodsId);normalOrder.setGoodsName(goodsInfo.getGoodsName());normalOrder.setGoodsCount(1);normalOrder.setGoodsPrice(goods.getSeckillPrice());orderMapper.insert(normalOrder);//生成秒杀订单SeckillOrder seckillOrder = new SeckillOrder();seckillOrder.setUserId(user.getId());seckillOrder.setOrderId(normalOrder.getOid());seckillOrder.setGoodsId(goodsId);this.save(seckillOrder);return ResponseResult.success();}
}

③、controller层

SeckillOrderController :

package com.example.seckill.controller;import com.example.seckill.pojo.User;
import com.example.seckill.service.ISeckillOrderService;
import com.example.seckill.util.response.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** <p>* 秒杀订单信息表 前端控制器* </p>** @author lv* @since 2022-03-19*/
@RestController
@RequestMapping("/seckillOrder")
public class SeckillOrderController {@Autowiredprivate ISeckillOrderService seckillOrderService;@RequestMapping("/addOrder")public ResponseResult<?> addOrder(Long goodsId, User user){return seckillOrderService.addOrder(goodsId,user);} }

④、呈现结果

限购次数:

 

 本期内容结束,下期内容更完善!!!!!!!!!!!!!!!!!!!!!1

本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_60389087/article/details/123601288。

该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。

作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。

如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。

相关阅读
文章标题:[转载][洛谷P1082]同余方程

更新时间:2023-02-18
[转载][洛谷P1082]同余方程
文章标题:[转载]webpack优化之HappyPack实战

更新时间:2023-08-07
[转载]webpack优化之HappyPack实战
文章标题:[转载]oracle 同时更新多表,在Oracle数据库中同时更新两张表的简单方法

更新时间:2023-09-10
[转载]oracle 同时更新多表,在Oracle数据库中同时更新两张表的简单方法
文章标题:[转载][Unity] 包括场景互动与射击要素的俯视角闯关游戏Demo

更新时间:2024-03-11
[转载][Unity] 包括场景互动与射击要素的俯视角闯关游戏Demo
文章标题:[转载]程序员也分三六九等?等级差异,一个看不起一个!

更新时间:2024-05-10
[转载]程序员也分三六九等?等级差异,一个看不起一个!
文章标题:[转载]海贼王 动漫 全集目录 分章节 精彩打斗剧集

更新时间:2024-01-12
[转载]海贼王 动漫 全集目录 分章节 精彩打斗剧集
名词解释
作为当前文章的名词解释,仅对当前文章有效。
MyBatis PlusMyBatis Plus是基于MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,简化开发、提高效率。在本文中,MyBatis Plus用于简化SQL操作和实体类映射关系的处理,通过注解、自动生成代码等方式,帮助开发者快速实现数据访问层的操作,如查询所有秒杀商品信息。
Spring BootSpring Boot是由Pivotal团队提供的全新框架,它为基于Spring的应用程序提供了快速构建和运行的解决方案。在该文章语境下,Spring Boot作为后端技术栈的核心部分,负责整个应用的启动、自动配置、组件扫描等功能,使得开发者能够快速搭建稳定、高效且易于维护的后端服务,例如定义Service和Controller层接口并实现相关业务逻辑。
TimestampTimestamp是一种数据库中的时间戳类型,表示从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,精确到微秒级别。在文中提到的SeckillGoods实体类中,startDate和endDate字段采用了Timestamp类型,以便精确记录秒杀活动的开始和结束时间,并使用DateTimeFormat注解进行格式化处理,确保与前端展示的时间格式一致。
VO(Value Object)VO是值对象(Value Object)的简称,在面向对象编程领域中,VO通常用来封装从数据库查询或由用户输入的数据,仅包含属性以及它们的getter和setter方法,不包含行为。在本文中,创建了SeckillGoodsVo这个实体类VO,用于连表查询时接收和展示商品名字等多张表的关联数据,便于前后端之间的数据传输和展示。
前后端分离架构前后端分离架构是一种常见的Web应用程序设计模式,其中前端专注于用户界面的设计和交互逻辑,而后端则关注业务逻辑处理、数据存储和API接口提供。在本篇文章中,前端通过Ajax请求调用后端提供的RESTful API获取数据并渲染页面,实现了前后端职责清晰、开发并行且可独立部署升级的现代Web应用架构。
延伸阅读
作为当前文章的延伸阅读,仅对当前文章有效。
在阅读了关于使用Spring Boot和MyBatis Plus构建秒杀商品显示与添加功能的文章后,进一步了解当前电商领域对高并发秒杀场景的处理技术将有助于深化理解。近期,某知名电商平台在“双十一”活动中成功应对了数以亿计的用户抢购请求,其背后的关键技术之一就是优化秒杀系统的架构设计。
据《2023年电商行业技术报告》指出,针对秒杀活动,企业普遍采用分布式缓存、数据库读写分离、队列服务以及异步处理等手段来提升系统性能和稳定性。例如,在商品秒杀开始前,将商品信息预加载至Redis等缓存中,减少实时查询数据库的压力;同时通过消息队列实现削峰填谷,避免瞬间涌入的请求压垮服务器,保证下单流程的平稳进行。
此外,结合最新的Serverless架构理念,部分企业已尝试利用阿里云函数计算等服务,实现按需扩容、自动弹性伸缩,有效应对秒杀高峰期流量突增的问题。在数据一致性方面,则可通过分布式事务解决方案如TCC(Try-Confirm-Cancel)模式确保在高并发环境下的交易数据准确无误。
深入探讨这一话题,可以参考《大型电商网站架构实战》一书,作者详细剖析了包括秒杀在内的各类复杂业务场景下,如何运用微服务、容器化、服务网格等前沿技术构建高性能、高可用的电商系统。同时,《Java并发编程实战》也从并发控制角度提供了宝贵的实践指导,对于开发高效稳定的秒杀功能具有重要意义。综上所述,关注最新技术和实战案例,将帮助开发者更好地应对类似秒杀场景的技术挑战,为用户带来更流畅的购物体验。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
curl -I http://example.com - 获取HTTP头部信息。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
HessianRPC在高负载下服务降级与熔断器模式保障用户体验 05-01 jQuery和TweenMax简单实用的水平手风琴特效 01-20 jquery选择国家下拉列表框插件 01-21 Sqoop在Hadoop集群中的数据传输机制及数据库迁移、收集与备份恢复应用实践 12-23 简约渔具批发牧渔企业类网站前端模板下载 11-09 基于bootstrap功能齐全的jQuery进度条插件 10-20 简约大气男性护肤产品HTML5网站模板 09-22 宽屏大气机械设备制造公司网站模板 08-13 演讲会门票销售网站模板下载 07-30 本次刷新还10个文章未展示,点击 更多查看。
经典响应式投资理财企业前端模板 06-26 基于Redis的键值对存储实现用户阅读状态跟踪与管理 06-24 Netty框架中CannotFindServerSelection异常:服务器地址配置错误与通道类型匹配详解 06-18 简洁设计公司响应式网站模板下载 05-06 绿色苗木草坪种植绿化类企业前端CMS模板下载 04-30 怎么在cmd开启mysql服务 04-15 保洁公司家庭保洁服务网站模板 03-26 SpringCloud微服务中分布式锁的死锁问题与状态一致性维护:避免循环依赖、公平锁及超时重试机制在Redisson中的实践运用 03-19 HBase性能测试与RegionServer配置、架构及数据模型调优实践:关注响应时间、并发处理能力与BlockCache优化 03-14 jquery控制radio触发事件 02-15 简约HTML5软件营销业务公司网站模板 02-09
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"