高效整合ssm——秒杀系统开发(5)开发service层接口

开发业务接口,一定要站在用户的角度去考虑问题。对于一个秒杀系统,我们需要以下几个接口:查询所有秒杀记录,查询单条秒杀记录,判断是否符合秒杀条件,以及秒杀逻辑执行。

package org.seckill.service;

import org.seckill.dto.Exposer;
import org.seckill.dto.SeckillExecution;
import org.seckill.exception.RepeatKillException;
import org.seckill.exception.SeckillCloseException;
import org.seckill.exception.SeckillException;
import org.seckill.pojo.Seckill;

import java.util.List;

// 业务接口
public interface SeckillService {

    // 查询所有秒杀记录
    List<Seckill> getSeckillList();

    // 查询一个秒杀记录
    Seckill getById(long seckillId);

    // 秒杀开启时输出秒杀接口的地址,否则输出系统时间和秒杀时间
    Exposer exportSeckillUrl(long seckillId);

    // 执行秒杀操作
    SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
            throws SeckillException, RepeatKillException, SeckillCloseException;
}

执行秒杀操作是,定义了三个异常:重复秒杀异常,秒杀关闭异常以及一个父类的异常,即出去前两个异常意外的所有异常都归为这个异常。后两个方法的返回值是两个dto层的类。dto层是一个很类似于pojo的层。pojo层只关心如何对数据库的表进行映射,即如何存储数据表中的数据,不进行任何的交互操作。而dto层里的类还需要负责service层的数据交互任务。首先,定义了一个dto类Exposer。该类的作用是存储秒杀的相关信息。

package org.seckill.dto;


// 暴露秒杀地址dtp
public class Exposer {

    // 是否可以开启秒杀
    private boolean exposed;

    // 地址加密
    private String md5;

    // 秒杀商品id
    private long seckillId;

    // 系统当前时间(mm)
    private long now;

    // 秒杀开启时间
    private long start;

    // 秒杀结束时间
    private long end;

    public Exposer(boolean exposed, String md5, long seckillId) {

        this.exposed = exposed;
        this.md5 = md5;
        this.seckillId = seckillId;
    }

    public Exposer(boolean exposed, long seckillId, long now, long start, long end) {
        this.exposed = exposed;
        this.seckillId = seckillId;
        this.now = now;
        this.start = start;
        this.end = end;
    }

    public Exposer(boolean exposed, long seckillId) {

        this.exposed = exposed;
        this.seckillId = seckillId;
    }

    public boolean isExposed() {

        return exposed;
    }

    public void setExposed(boolean exposed) {

        this.exposed = exposed;
    }

    public String getMd5() {

        return md5;
    }

    public void setMd5(String md5) {

        this.md5 = md5;
    }

    public long getSeckillId() {

        return seckillId;
    }

    public void setSeckillId(long seckillId) {

        this.seckillId = seckillId;
    }

    public long getNow() {

        return now;
    }

    public void setNow(long now) {

        this.now = now;
    }

    public long getStart() {

        return start;
    }

    public void setStart(long start) {

        this.start = start;
    }

    public long getEnd() {

        return end;
    }

    public void setEnd(long end) {

        this.end = end;
    }
}

另一个dto类是SeckillExecution。它存放着秒杀成功后系统记录的信息。

package org.seckill.dto;

import org.seckill.enums.SeckillStateEnum;
import org.seckill.pojo.SuccessKilled;

// 封装秒杀执行后结果
public class SeckillExecution {

    // 秒杀商品id
    private long seckillId;

    // 秒杀结果状态
    private int state;

    // 秒杀结果状态描述
    private String stateInfo;

    // 秒杀成功返回秒杀成功对象
    private SuccessKilled successKilled;

    public SeckillExecution(long seckillId, SeckillStateEnum stateEnum, SuccessKilled successKilled) {

        this.seckillId = seckillId;
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
        this.successKilled = successKilled;
    }

    public SeckillExecution(long seckillId, SeckillStateEnum stateEnum) {

        this.seckillId = seckillId;
        this.state = stateEnum.getState();
        this.stateInfo = stateEnum.getStateInfo();
    }

    public long getSeckillId() {

        return seckillId;
    }

    public void setSeckillId(long seckillId) {

        this.seckillId = seckillId;
    }

    public int getState() {

        return state;
    }

    public void setState(int state) {

        this.state = state;
    }

    public String getStateInfo() {

        return stateInfo;
    }

    public void setStateInfo(String stateInfo) {

        this.stateInfo = stateInfo;
    }

    public SuccessKilled getSuccessKilled() {

        return successKilled;
    }

    public void setSuccessKilled(SuccessKilled successKilled) {

        this.successKilled = successKilled;
    }
}

这里是用了枚举类SeckillStateEnum来存放常量数据字典:

package org.seckill.enums;

// 使用枚举表示常量数据字典
public enum SeckillStateEnum {

    CLOSE(0, "秒杀结束"),
    DATA_REWRITE(-3, "数据篡改"),
    INNER_ERROR(-2, "系统异常"),
    REPEAT(-1, "重复秒杀"),
    SUCCESS(1, "秒杀成功");

    private int state;
    private String stateInfo;

    SeckillStateEnum(int state, String stateInfo) {

        this.state = state;
        this.stateInfo = stateInfo;
    }

    public int getState() {

        return state;
    }

    public String getStateInfo() {

        return stateInfo;
    }

    public static SeckillStateEnum stateOf(int index) {

        for (SeckillStateEnum state : SeckillStateEnum.values()) {

            if (state.getState() == index) {

                return state;
            }
        }
        return null;
    }
}

下面是接口的实现:

package org.seckill.service.impl;

import org.seckill.dao.SeckillDao;
import org.seckill.dao.SuccessKilledDao;
import org.seckill.dto.Exposer;
import org.seckill.dto.SeckillExecution;
import org.seckill.enums.SeckillStateEnum;
import org.seckill.exception.RepeatKillException;
import org.seckill.exception.SeckillCloseException;
import org.seckill.exception.SeckillException;
import org.seckill.pojo.Seckill;
import org.seckill.pojo.SuccessKilled;
import org.seckill.service.SeckillService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.List;

@Service
public class SeckillServiceImpl implements SeckillService {

    @Autowired
    private SeckillDao seckillDao;

    @Autowired
    private SuccessKilledDao successKilledDao;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    // md5盐值字符串
    private final String slat = "s#(&BFdjhsd(*@hbe289fNI*A@E0";

    public List<Seckill> getSeckillList() {

        return seckillDao.queryAll(0, 100);
    }

    public Seckill getById(long seckillId) {

        return seckillDao.queryById(seckillId);
    }

    private String getMd5(long seckillId) {

        String base = seckillId + "/" + slat;
        String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
        return md5;
    }

    public Exposer exportSeckillUrl(long seckillId) {

        Seckill seckill = seckillDao.queryById(seckillId);
        if (seckill==null) {

            return new Exposer(false, seckillId);
        }

        Date nowTime = new Date();
        if (nowTime.getTime()<seckill.getStartTime().getTime() ||
            nowTime.getTime()>seckill.getEndTime().getTime()) {

            return new Exposer(false, seckillId, nowTime.getTime(),
                               seckill.getStartTime().getTime(), seckill.getEndTime().getTime());
        }

        String md5 = getMd5(seckillId);
        return new Exposer(true, md5, seckillId);
    }

    public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
            throws SeckillException, RepeatKillException, SeckillCloseException {

        if (md5==null||!md5.equals(getMd5(seckillId))) {

            throw new SeckillException("seckill data rewrite");
        }

        // 秒杀逻辑:减库存+记录秒杀行为
        Date nowTime = new Date();
        int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
        try {
            if (updateCount<=0) {

                throw new SeckillCloseException("seckill is closed");
            } else {

                int insertCount = successKilledDao.insertSuccessKilled(seckillId, userPhone);
                if (insertCount<=0) {

                    throw new RepeatKillException("seckill repeated");
                } else {

                    SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
                    return new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS, successKilled);
                }
            }
        } catch (SeckillCloseException e) {

            throw e;
        } catch (RepeatKillException e) {

            throw e;
        } catch (SeckillException e) {

            logger.error(e.getMessage(), e);
            throw new SeckillException("seckill inner error: "+e.getMessage());
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值