主要内容
- 数据库设计
- 商品列表页
- 商品详情页
- 订单详情页
一、数据库设计
商品表goods
商品订单表order_info
秒杀商品表miaosha_goods
秒杀商品订单表miaosha_order
domain对象
1.Goods
public class Goods {
private Long id;
private String goodsName;
private String goodsTitle;
private String goodsImg;
private String goodsDetail;
private Double goodsPrice;
private Integer goodsStock;
2.OrderInfo
public class OrderInfo {
private Long id;
private Long userId;
private Long goodsId;
private Long deliveryAddrId;
private String goodsName;
private Integer goodsCount;
private Double goodsPrice;
private Integer orderChannel;
private Integer status;
private Date createDate;
private Date payDate;
3.MiaoshaGoods
public class MiaoshaGoods {
private Long id;
private Long goodsId;
private Integer stockCount;
private Date startDate;
private Date endDate;
4.MiaoshaOrder
public class MiaoshaOrder {
private Long id;
private Long userId;
private Long orderId;
private Long goodsId;
二、商品列表页
数据层
GoodsDao
@Repository
public interface GoodsDao {
//查询所有秒杀商品的信息并封装进GoodsVo
@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.miaosha_price from miaosha_goods mg left join goods g on mg.goods_id = g.id")
public List<GoodsVo> listGoodsVo();
}
为了展示秒杀商品的详情需要goods和miaosha_goods中的信息,所以封装一个GoodsVo
public class GoodsVo extends Goods {
private Double miaoshaPrice;
private Integer stockCount;
private Date startDate;
private Date endDate;
业务层
GoodsService
@Service
public class GoodsService {
@Autowired
GoodsDao goodsDao;
public List<GoodsVo> listGoodsVo(){
return goodsDao.listGoodsVo();
}
}
表现层
GoodsController
@Controller
@RequestMapping("/goods")
public class GoodsController {
@Autowired
GoodsService goodsService;
@RequestMapping("/to_list")
public String list(Model model, MiaoshaUser user) {
model.addAttribute("user", user);
//查询商品列表
List<GoodsVo> goodsList = goodsService.listGoodsVo();
model.addAttribute("goodsList", goodsList);
return "goods_list";
}
}
goods_list页面
三、商品详情页
查数据库时间的时候有个bug读取的时间总比数据库中的时间多一天
解决方法:serverTimezone设置时区
spring.datasource.url=jdbc:mysql://192.168.174.10:3306/miaosha?
useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&
useSSL=false&serverTimezone=Asia/Shanghai
数据层
GoodsDao 增加方法
@Repository
public interface GoodsDao {
。。。忽略以前代码
//根据商品id查商品信息
@Select("select g.*,mg.stock_count, mg.start_date, mg.end_date,mg.miaosha_price from miaosha_goods mg left join goods g on mg.goods_id = g.id where g.id = #{goodsId}")
public GoodsVo getGoodsVoByGoodsId(@Param("goodsId") long goodsId);
}
业务层
GoodsService
@Service
public class GoodsService {
。。。忽略以前代码
public GoodsVo getGoodsVoByGoodsId(long goodsId) {
return goodsDao.getGoodsVoByGoodsId(goodsId);
}
}
表现层
GoodsController
@Controller
@RequestMapping("/goods")
public class GoodsController {
。。。忽略以前代码
@Autowired
MiaoshaUserService userService;
@RequestMapping("/to_detail/{goodsId}")
public String detail(Model model,MiaoshaUser user,
@PathVariable("goodsId")long goodsId) {
model.addAttribute("user", user);
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
System.out.println(goods.getStartDate());
model.addAttribute("goods", goods);
long startAt = goods.getStartDate().getTime();
long endAt = goods.getEndDate().getTime();
long now = System.currentTimeMillis();
int miaoshaStatus = 0;
int remainSeconds = 0;
//这个用来设置距离秒杀结束多长时间
int endSeconds = 0;
if(now < startAt ) {//秒杀还没开始,倒计时
miaoshaStatus = 0;
remainSeconds = (int)((startAt - now )/1000);
endSeconds = (int)((endAt - now )/1000);
}else if(now > endAt){//秒杀已经结束
miaoshaStatus = 2;
remainSeconds = -1;
}else {//秒杀进行中
miaoshaStatus = 1;
remainSeconds = 0;
endSeconds = (int)((endAt - now )/1000);
}
model.addAttribute("miaoshaStatus", miaoshaStatus);
model.addAttribute("remainSeconds", remainSeconds);
model.addAttribute("endSeconds", endSeconds);
return "goods_detail";
}
}
goods_detail页面
倒计时处理
<script>
/*这是jQuery的写法
* 原本为:
*
* $(document).ready(function(){
// 开始写 jQuery 代码...
});
* 页面加载完之后才会执行
* */
$(function(){
countDown();
});
function countDown(){
var remainSeconds = $("#remainSeconds").val();
var endSeconds = $("#endSeconds").val();
var timeout;
var endtimeout;
if(remainSeconds > 0){//秒杀还没开始,倒计时
$("#buyButton").attr("disabled", true);
timeout = setTimeout(function(){
$("#countDown").text(remainSeconds - 1);
$("#remainSeconds").val(remainSeconds - 1);
$("#endSeconds").val(endSeconds - 1);
countDown();
},1000);
}else if(remainSeconds == 0){//秒杀进行中
$("#buyButton").attr("disabled", false);
if(timeout){
clearTimeout(timeout);
}
if(endSeconds>0){
$("#miaoshaTip").html("秒杀进行中");
}else{
$("#remainSeconds").val(remainSeconds - 1);
}
endtimeout = setTimeout(function(){
$("#endSeconds").val(endSeconds - 1);
countDown();
},1000);
}else{//秒杀已经结束
if(endtimeout){
clearTimeout(endtimeout);
}
$("#buyButton").attr("disabled", true);
$("#miaoshaTip").html("秒杀已经结束");
}
}
</script>
四、订单详情页
数据层
GoodsDao
@Repository
public interface GoodsDao {
。。。忽略以前代码
@Update("update miaosha_goods set stock_count = stock_count - 1 where goods_id = #{goodsId}")
public int reduceStock(MiaoshaGoods g);
}
OrderDao
@Repository
public interface OrderDao {
@Select("select * from miaosha_order where user_id=#{userId} and goods_id=#{goodsId}")
public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(@Param("userId") long userId, @Param("goodsId") long goodsId);
@Insert("insert into order_info(user_id, goods_id, goods_name, goods_count, goods_price, order_channel, status, create_date)values("
+ "#{userId}, #{goodsId}, #{goodsName}, #{goodsCount}, #{goodsPrice}, #{orderChannel},#{status},#{createDate} )")
@SelectKey(keyColumn="id", keyProperty="id", resultType=long.class, before=false, statement="select last_insert_id()")
//@Options(useGeneratedKeys = true,keyProperty = "id")
//@SelectKey和/@Options注解作用一样都是把插入的id好回写进OrderInfo中
public long insert(OrderInfo orderInfo);
@Insert("insert into miaosha_order (user_id, goods_id, order_id)values(#{userId}, #{goodsId}, #{orderId})")
public int insertMiaoshaOrder(MiaoshaOrder miaoshaOrder);
}
业务层
GoodsService
@Service
public class GoodsService {
。。。省略以前代码
@Autowired
GoodsDao goodsDao;
public void reduceStock(GoodsVo goods) {
MiaoshaGoods g = new MiaoshaGoods();
g.setGoodsId(goods.getId());
goodsDao.reduceStock(g);
}
}
MiaoshaService
@Service
public class MiaoshaService {
@Autowired
GoodsService goodsService;
@Autowired
OrderService orderService;
@Transactional
public OrderInfo miaosha(MiaoshaUser user, GoodsVo goods) {
//减库存 下订单 写入秒杀订单
goodsService.reduceStock(goods); //代码见上
//下订单 order_info maiosha_order
return orderService.createOrder(user, goods); //代码见下
}
}
OrderService
@Service
public class OrderService {
@Autowired
OrderDao orderDao;
public MiaoshaOrder getMiaoshaOrderByUserIdGoodsId(long userId, long goodsId) {
return orderDao.getMiaoshaOrderByUserIdGoodsId(userId, goodsId);
}
@Transactional
public OrderInfo createOrder(MiaoshaUser user, GoodsVo goods) {
//插入订单
OrderInfo orderInfo = new OrderInfo();
orderInfo.setCreateDate(new Date());
orderInfo.setDeliveryAddrId(0L);
orderInfo.setGoodsCount(1);
orderInfo.setGoodsId(goods.getId());
orderInfo.setGoodsName(goods.getGoodsName());
orderInfo.setGoodsPrice(goods.getMiaoshaPrice());
orderInfo.setOrderChannel(1);
orderInfo.setStatus(0);
orderInfo.setUserId(user.getId());
long orderId = orderDao.insert(orderInfo);
//插入秒杀订单
MiaoshaOrder miaoshaOrder = new MiaoshaOrder();
miaoshaOrder.setGoodsId(goods.getId());
miaoshaOrder.setOrderId(orderId);
miaoshaOrder.setUserId(user.getId());
orderDao.insertMiaoshaOrder(miaoshaOrder);
return orderInfo;
}
}
表现层
MiaoshaController
@Controller
@RequestMapping("/miaosha")
public class MiaoshaController {
@Autowired
MiaoshaUserService userService;
@Autowired
RedisService redisService;
@Autowired
GoodsService goodsService;
@Autowired
OrderService orderService;
@Autowired
MiaoshaService miaoshaService;
@RequestMapping(path = "/do_miaosha",method = RequestMethod.POST)
public String list(Model model, MiaoshaUser user,
@RequestParam("goodsId")long goodsId) {
model.addAttribute("user", user);
if(user == null) {
return "/login";
}
//判断库存
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
int stock = goods.getStockCount();
if(stock <= 0) {
model.addAttribute("errmsg", CodeMsg.MIAO_SHA_OVER.getMsg());
return "miaosha_fail";
}
//判断是否已经秒杀到了,不能重复秒杀
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if(order != null) {
model.addAttribute("errmsg", CodeMsg.REPEATE_MIAOSHA.getMsg());
return "miaosha_fail";
}
//减库存 下订单 写入秒杀订单
OrderInfo orderInfo = miaoshaService.miaosha(user, goods);
model.addAttribute("orderInfo", orderInfo);
model.addAttribute("goods", goods);
return "order_detail";
}
}
为了跳转到订单页面处理下goods_detail页面
order_detail页面
miaosha_fail页面