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

更多相关文章

  1. java返回值是list的时候获取list的参数类型
  2. 如何知道Object是否为String类型对象?
  3. 如何让BlockingQueue接受多种类型?
  4. 当只使用get()和set()方法时,用原始类型替换AtomicBoolean?
  5. Java中的数据类型
  6. Java反射---getGenericSuperclass和ParameterizedType参数化类型
  7. 怎么用java 实现两个web service之间调用各自的接口 实现数据的
  8. 黑马程序员——Java学习笔记 String类和基本数据类型对象包装类
  9. 接口之命令模式

随机推荐

  1. c语言include<stdlib.h>什么意思?
  2. \0在c语言中代表什么?
  3. C语言中typedef的用法有哪些?
  4. c源程序中不允许出现空语句吗?
  5. c++11新特性有哪些
  6. C语言中main函数可以在什么位置
  7. 在一个C语言程序中,main函数可以在任何地
  8. c语言代码如何实现贪吃蛇动画
  9. C和C++有什么区别
  10. putchar函数在C语言中是什么意思