• 基于SpringMVC+Spring+MyBatis实现秒杀系统【业务逻辑】


    前言

           该篇主要实现秒杀业务层,秒杀业务逻辑里主要包括暴露秒杀接口地址、实现秒杀业务逻辑。同时声明了三个业务类:Exposer、SeckillExecution、SeckillResult。 Exposer主要用来实现暴露接口时一个md5的加密,防止用户在客户端篡改数据。根据seckillid生成md5,提交秒杀请求时会根据这个md5和seckillid比对是否是合法的请求。SeckillExecution主要封装秒杀时的返回值。

           SeckillExecution有2个属性,state、stateinfo,这里我没有封装枚举值,还是用整型和字符串给客户端传值,在Service里看着也直观些。

    准备工作

    1、spring-service.xml

         业务逻辑里的关键是开启事务,这里推荐用注解的方式实现。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    
        <!--1、注解包扫描-->
        <context:component-scan base-package="com.seckill.service"/>
    
        <!--2、配置声明式事务-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据库-->
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <!--3、配置基于注解的声明式事务-->
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    
    </beans>

    实现秒杀业务

         秒杀相关的关键方法就是最后两个方法,一个是对外暴漏秒杀地址,一个是秒杀方法。

    public interface SeckillService {
    
        List<Seckill> getSeckillList();
    
        Seckill getById(long seckillId);
    
    
    
        /**对外暴漏秒杀接口**/
        Exposer exposeSeckillUrl(long seckillId);
    
    
    
        /**
         * 执行秒杀操作,有可能成功,有可能失败,所以这里我们抛出自自定义异常
         * ***/
        SeckillExecution executeSeckill(long seckillId,long phone,String md5) throws SeckillException,
                RepeatKillException,
                SeckillCloseException;
    
    
    }
    

      

    @Service
    public class SeckillServiceImpl implements SeckillService {
    
    
        /***
         * 秒杀行为的枚举放在这里说明
         * 1、 秒杀成功
         * 0、 秒杀结束
         * -1、重复秒杀
         * -2、系统异常
         * -3、数据篡改
         * ***/
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        SeckillDao seckillDao;
    
        @Autowired
        SuccessKillDao successKillDao;
    
        private String salt = "zhangfei";
    
    
        @Override
        public List<Seckill> getSeckillList() {
            return seckillDao.queryAll(0, 100);
        }
    
        @Override
        public Seckill getById(long seckillId) {
            return seckillDao.queryById(seckillId);
        }
    
        @Override
        public Exposer exposeSeckillUrl(long seckillId) {
            Seckill seckill = getById(seckillId);
    
            Date startTime = seckill.getStartTime();
            Date endTime = seckill.getEndTime();
    
            Date now = new Date();
    
            if (now.getTime() < startTime.getTime() || now.getTime() > endTime.getTime()) {
                return new Exposer(false, seckillId, startTime.getTime(), endTime.getTime(), now.getTime());
            }
    
            String md5 = getMd5(seckillId);
    
            return new Exposer(true, md5, seckillId);
        }
    
        @Override
        @Transactional
        public SeckillExecution executeSeckill(long seckillId, long phone, String md5)
                throws SeckillException,RepeatKillException,SeckillCloseException {
    
            if (md5 == null || !md5.equals(getMd5(seckillId))) {
                throw new SeckillException("非法请求");
            }
    
            Date now = new Date();
    
            try {
                int insertCount = successKillDao.insertSuccessKilled(seckillId, phone);
                if (insertCount <= 0) {
                    throw new RepeatKillException("重复秒杀");
    
                } else {
                    int updateCount = seckillDao.reduceNumber(seckillId, now);
                    if (updateCount <= 0) {
                        throw new SeckillCloseException("秒杀已关闭");
                    } else {
                        //秒杀成功,可以把秒杀详情和商品详情实体返回
                        SuccessKilled successKilled = successKillDao.queryByIdWithSeckill(seckillId, phone);
                        return new SeckillExecution(seckillId, 1, "秒杀成功", successKilled);
                    }
                }
    
            } catch (SeckillCloseException e) {
                throw e;
            } catch (RepeatKillException e1) {
                throw e1;
            } catch (SeckillException e2) {
                logger.error(e2.getMessage(), e2);
                throw new SeckillException("Unkonwn error:" + e2.getMessage());
            }
    
        }
    
        private String getMd5(long seckillId) {
            String base = seckillId + "/" + salt;
            String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
    
            return md5;
    
        }
    }
    

      

  • 相关阅读:
    HTML 5 视频/音频
    vue 未完待续
    asp.net中使用log4net
    图片预加载:jquery 图片预加载功能,可以实现先模糊在清晰的显示
    IIS配置PHP环境
    学习ASP.Net的过滤器
    最好用的jQuery插件,240多个,绝对的JQUERY插件库
    Windows7&IIS7.5部署Discuz全攻略
    AjaxPro使用
    ASP.NET XML读取、增加、修改和删除操作
  • 原文地址:https://www.cnblogs.com/sword-successful/p/9230313.html
Copyright © 2020-2023  润新知