zoukankan      html  css  js  c++  java
  • Java高并发秒时啊API之Service层

    Java高并发秒时啊API之Service层1

    第一章 秒杀业务接口设计与实现

    ---1-1----------------------------------
    1.DAO层:接口设计+SQL编写(不需要其他杂七杂八的功能)
    2.代码和SQL的分离,方便Review(浏览)
    3.DAO拼接等逻辑在Service完成(DAO只需负责SQL语句,其他都由Service层完成)

    ---1-2 秒杀Service接口设计----------------------------------

    DTO设计:

    Exposer.java 暴露秒杀地址DTO

    package org.seckill.dto;
    
    /*
     * 暴露秒杀地址DTO
     * 
     * 
     * */
    public class Exposer {
        //是否开启秒杀
        private boolean exposed;
        //一种加密措施
        private String md5;
        
        private long seckillId;
        
        //系统当前时间(毫秒)
        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) {
            this.exposed = exposed;
            this.seckillId = seckillId;
        }
        public Exposer(boolean exposed, long seckillId, long now, long start, long end) {
            super();
            this.exposed = exposed;
            this.md5 = md5;
            this.seckillId = seckillId;
            this.now = now;
            this.start = start;
            this.end = end;
        }

    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; } }

    SeckillExecution.java 封装秒杀执行结果

    package org.seckill.dto;
    
    import org.seckill.entity.SuccessKilled;
    
    /*
     * 封装秒杀执行结果*/
    public class SeckillExecution {
        private long seckillId;
        //秒杀结果状态
        private int state;
        //状态表示
        private String stateInfo;
        //秒杀成功对象
        private SuccessKilled successKilled;
        
        public SeckillExecution(long seckillId, int state, String stateInfo, SuccessKilled successKilled) {
            this.seckillId = seckillId;
            this.state = state;
            this.stateInfo = stateInfo;
            this.successKilled = successKilled;
        }
        
        public SeckillExecution(long seckillId, int state, String stateInfo) {
            super();
            this.seckillId = seckillId;
            this.state = state;
            this.stateInfo = stateInfo;
        }
    
        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 SuccessKilled getSuccessKilled() {
            return successKilled;
        }
        public void setSuccessKilled(SuccessKilled successKilled) {
            this.successKilled = successKilled;
        }
        public String getStateInfo() {
            return stateInfo;
        }
        public void setStateInfo(String stateInfo) {
            this.stateInfo = stateInfo;
        }
    }

    Service层:

     业务接口:站在"使用者角"度设计接口
     三个方面:方法定义粒度,参数,返回类型(return 类型/exception )友好

    SeckillServic.java

    package org.seckill.service;
    
    import java.util.List;
    
    import javax.swing.text.html.parser.Entity;
    
    import org.seckill.dto.Exposer;
    import org.seckill.dto.SeckillExection;
    import org.seckill.entity.Seckill;
    import org.seckill.exception.RepeatKillExeception;
    import org.seckill.exception.SeckillCloseException;
    import org.seckill.exception.SeckillException;
    
    /*
     * 业务接口:站在"使用者角"度设计接口
     * 三个方面:方法定义粒度,参数,返回类型(return 类型/exception )友好
     * */
    public interface SeckillService {
        /*
         * 查询所有秒杀记录
         * @return
         * */
        List<Seckill> getSeckillList();
        /*查询单个秒杀记录
         * @param seckillId
         * @retrun
         */
        Seckill getById(long seckillId);
        
        /*
         * 秒杀开启时输出秒杀接口地址,
         * 否则输出系统时间和秒杀 时间
         *  @param seckillId
         *  @retrun
         * */
        Exposer exportSeckillUrl(long seckillId);
        /*
         * 执行秒杀操作
         * @param seckillId
         * @param userPhone
         * @param md5
         * */
        SeckillExecution executeSeckill(long seckillId,long userPhone,String md5)
            throws SeckillException,RepeatKillExeception,SeckillCloseException;
    }

    Exception:

    package org.seckill.exception;
    
    /*
     * 秒杀相关业务异常
     * */
    public class SeckillException extends RuntimeException{
    
        public SeckillException(String message, Throwable cause) {
            super(message, cause);
            // TODO Auto-generated constructor stub
        }
    
        public SeckillException(String message) {
            super(message);
            // TODO Auto-generated constructor stub
        }
    }
    package org.seckill.exception;
    
    /*
     * 重复秒杀异常(运行期异常,spring的声明式事务处理的是runtime异常,如果不是这类异常,那么他是不会回滚的)
     * */
    public class RepeatKillExeception extends SeckillException{
    
        public RepeatKillExeception(String message){
            super(message);
        }
        
        public RepeatKillExeception(String message,Throwable cause){
            super(message,cause);
        }
    }
    package org.seckill.exception;
    
    /*
     *秒杀关闭异常
     * */
    public class SeckillCloseException extends SeckillException{
    
        public SeckillCloseException(String message, Throwable cause) {
            super(message, cause);
            // TODO Auto-generated constructor stub
        }
    
        public SeckillCloseException(String message) {
            super(message);
            // TODO Auto-generated constructor stub
        }
    }

    ---1-3  1-4秒杀Service接口实现1----------------------------------

    SeckillServiceImpl.java

    package org.seckill.service.impl;
    
    import java.util.Date;
    import java.util.List;
    
    import org.seckill.dao.SeckillDao;
    import org.seckill.dao.SuccessKilledDao;
    import org.seckill.dto.Exposer;
    import org.seckill.dto.SeckillExecution;
    import org.seckill.entity.Seckill;
    import org.seckill.entity.SuccessKilled;
    import org.seckill.enums.SeckillStatEnum;
    import org.seckill.exception.RepeatKillExeception;
    import org.seckill.exception.SeckillCloseException;
    import org.seckill.exception.SeckillException;
    import org.seckill.service.SeckillService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.util.DigestUtils;
    
    public class SeckillServiceImpl implements SeckillService {
        private Logger logger = LoggerFactory.getLogger(this.getClass());
        
        private SeckillDao seckillDao;
        
        private SuccessKilledDao successKilledDao;
        
        //md5盐值字符串,用于混淆MD5
        private final String slat = "sldijfldkjfpaojj@#(#$sldfj`123";
        @Override
        public List<Seckill> getSeckillList() {
            return seckillDao.queryAll(0, 4);
        }
    
        @Override
        public Seckill getById(long seckillId) {
            // TODO Auto-generated method stub
            return seckillDao.queryById(seckillId);
        }
    
        @Override
        public Exposer exportSeckillUrl(long seckillId) {
            Seckill seckill = seckillDao.queryById(seckillId);
            if(seckill == null){
                return new Exposer(false,seckillId);
            }
            Date startTime = seckill.getStartTime();
            Date endTime = seckill.getEndTime();
            //系统当前时间
            Date nowTime = new Date();
            if(nowTime.getTime() < startTime.getTime()
                    || nowTime.getTime() > endTime.getTime()){
                return new Exposer(false,seckillId,nowTime.getTime(),startTime.getTime(),
                        endTime.getTime());
            }
            //转化特定字符串的过程,不可逆
            String md5 = getMD5(seckillId);//TODO
            return new Exposer(true,md5,seckillId);
        }
    
        private String getMD5(long seckillId){
            String base = seckillId+"/"+slat;
            String md5 = DigestUtils.md5DigestAsHex(base.getBytes());
            return md5;
        }
        @Override
        public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
                throws SeckillException, RepeatKillExeception, SeckillCloseException {
            if(md5==null|| !md5.equals(getMD5(seckillId))){
                throw new SeckillException("seckill data rewrite");
            }
            //执行秒杀逻辑:减库存 + 记录购买行为
            Date nowTime = new Date();
            try{
    
                int updateCount = seckillDao.reduceNumber(seckillId, nowTime);
                if(updateCount <=0){
                    //没有更新记录
                    throw new SeckillCloseException("seckill is closed");
                } else {
                    //记录购买行为
                    int insertCount= successKilledDao.insertSuccessKilled(seckillId, userPhone);
                    //唯一:insert ignore 
                    if(insertCount <=0){
                        //重复秒杀
                        throw new RepeatKillExeception("seckill repeated");
                    }else {
                        //秒杀成功
                        SuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);
                        //return new SeckillExecution(seckillId,1,"秒杀成功",successKilled);
                        return new  SeckillExecution(seckillId,SeckillStatEnum.SUCCESS);
                    }
                }
                
            } catch (SeckillCloseException e1) {
                throw e1;
            } catch (RepeatKillExeception e2) {
                throw e2;
            }catch (Exception e){
                logger.error(e.getMessage(),e);
                //所有编译期异常 转化为运行期异常
                //spring事务会做roll back
                throw new SeckillException("seckill inner error : "+e.getMessage());
            }
    
            return null;
        }
    
    }

    SeckillExecution.java

    package org.seckill.dto;
    
    import org.seckill.entity.SuccessKilled;
    import org.seckill.enums.SeckillStatEnum;
    
    /*
     * 封装秒杀执行结果*/
    public class SeckillExecution {
        private long seckillId;
        /*此处不做枚举类型的原因:会把这个对象转换为json,通过ajax返回给前端浏览器。
         * 默认的json的类库在转换枚举时有问题。
         * (可以做一个把枚举类型转换为json的transfer,不过比较复杂,此处不使用此方法。
        */
        //秒杀结果状态
        private int state;
        //状态表示
        private String stateInfo;
        //秒杀成功对象
        private SuccessKilled successKilled;
    
        public SeckillExecution(long seckillId, SeckillStatEnum statEnum) {
            super();
            this.seckillId = seckillId;
            this.state = statEnum.getState();
            this.stateInfo = statEnum.getStateInfo();
        }
    
        
        //public SeckillExecution(long seckillId, int state, String stateInfo, SuccessKilled successKilled) {
        public SeckillExecution(long seckillId, SeckillStatEnum statEnum, SuccessKilled successKilled) {
            super();
            this.seckillId = seckillId;
            this.state = statEnum.getState();
            this.stateInfo = statEnum.getStateInfo();
            this.successKilled = successKilled;
        }
    
        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 SuccessKilled getSuccessKilled() {
            return successKilled;
        }
        public void setSuccessKilled(SuccessKilled successKilled) {
            this.successKilled = successKilled;
        }
        public String getStateInfo() {
            return stateInfo;
        }
        public void setStateInfo(String stateInfo) {
            this.stateInfo = stateInfo;
        }
    }

    SeckillStatEnum.enum

    数据字典放入枚举中。

    package org.seckill.enums;
    
    //使用枚举表示常量数据
    public enum SeckillStatEnum {
        SUCCESS(1,"秒杀成功"),
        END(1,"秒杀结束"),
        REPEAT_KILL(-1,"重复"),
        INNER_ERROR(-2,"系统异常"),
        DATA_REWRITE(-3,"数据篡改");
        private int state;
        private String stateInfo;
        
        SeckillStatEnum(int state,String stateInfo) {
            this.state = state;
            this.stateInfo = stateInfo;
        }
    
        public int getState() {
            return state;
        }
    
        public String getStateInfo() {
            return stateInfo;
        }
        
        public static SeckillStatEnum stateOf(int index){
            for(SeckillStatEnum state :values()){
                if(state.getState() == index){
                    return state;
                }
            }
            return null;
        }
    }

    ---1-1----------------------------------

    ---1-1----------------------------------

  • 相关阅读:
    Spark——为数据分析处理提供更为灵活的赋能
    秋读|10本热门图书(人工智能、编程开发、架构、区块链等)免费送!
    使用Phaser开发你的第一个H5游戏(一)
    Java web 服务启动时Xss溢出异常处理笔记
    为什么我打的jar包没有注解?
    收集、分析线上日志数据实战——ELK
    阿里云PolarDB及其共享存储PolarFS技术实现分析(下)
    14.5 富文本编辑【JavaScript高级程序设计第三版】
    【收藏】15个常用的javaScript正则表达式
    C# 网络请求
  • 原文地址:https://www.cnblogs.com/charles999/p/7122286.html
Copyright © 2011-2022 走看看