yangyoupeng

第一次提交

Showing 74 changed files with 4122 additions and 0 deletions
.settings
.project
coupon-core/.settings
coupon-core/target
coupon-core/.classpath
coupon-core/.project
coupon-core/bin
coupon-dispatcher/.settings
coupon-dispatcher/target
coupon-dispatcher/.classpath
coupon-dispatcher/.project
coupon-dispatcher/bin
coupon-dispatcher-api/.settings
coupon-dispatcher-api/target
coupon-dispatcher-api/.classpath
coupon-dispatcher-api/.project
coupon-dispatcher-api/bin
coupon-generator/.settings
coupon-generator/target
coupon-generator/.classpath
coupon-generator/.project
coupon-generator/bin
coupon-processor/.settings
coupon-processor/target
coupon-processor/.classpath
coupon-processor/.project
coupon-processor/bin
.idea
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="NewModuleRootManager" inherit-compiler-output="false">
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:1.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:18.0" level="project" />
<orderEntry type="library" name="Maven: joda-time:joda-time:2.9.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.8.1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.8.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.8.1" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.21" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.1.7" level="project" />
<orderEntry type="library" name="Maven: com.zhaoonline:microservice-redis:1.0.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: redis.clients:jedis:2.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.4.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:1.7.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:1.1.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:1.12.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: aopalliance:aopalliance:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.slf4j:jcl-over-slf4j:1.7.21" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-all:1.10.19" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="library" name="Maven: com.auth0:java-jwt:3.0.1" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15on:1.55" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.7.0" level="project" />
<orderEntry type="library" name="Maven: org.bitbucket.b_c:jose4j:0.5.2" level="project" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>com.zhaoonline.coupon</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>coupon-core</artifactId>
<dependencies>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>com.zhaoonline</groupId>
<artifactId>microservice-redis</artifactId>
<exclusions>
<exclusion>
<groupId>com.zhaoonline</groupId>
<artifactId>alpaca-config-zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- test相关 -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- jwt相关 -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.zhaoonline.coupon.bean;
import org.joda.time.DateTime;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 11:13<br/>
* Description:活动
*/
public class Activity {
private String activityName;
private Integer activityID;
//活动开启时间
protected DateTime startDate;
//活动结束时间
protected DateTime endDate;
public Activity(){
}
public Activity(Integer ID,String name){
this.activityName = name;
this.activityID=ID;
}
public String getActivityName() {
return activityName;
}
public void setActivityName(String activityName) {
this.activityName = activityName;
}
public Integer getActivityID() {
return activityID;
}
public void setActivityID(Integer activityID) {
this.activityID = activityID;
}
public DateTime getStartDate() {
return startDate;
}
public void setStartDate(DateTime startDate) {
this.startDate = startDate;
}
public DateTime getEndDate() {
return endDate;
}
public void setEndDate(DateTime endDate) {
this.endDate = endDate;
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 11:06<br/>
* Description:业务类型:投资币、自营等
*/
public class BizType {
private Integer bizTypeID;
private String bizTypeName;
public BizType(){
}
public BizType(Integer ID,String name){
this.bizTypeName = name;
this.bizTypeID=ID;
}
public Integer getBizTypeID() {
return bizTypeID;
}
public void setBizTypeID(Integer bizTypeID) {
this.bizTypeID = bizTypeID;
}
public String getBizTypeName() {
return bizTypeName;
}
public void setBizTypeName(String bizTypeName) {
this.bizTypeName = bizTypeName;
}
}
package com.zhaoonline.coupon.bean;
import org.joda.time.DateTime;
import java.math.BigDecimal;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 19:16<br/>
* Description:please descript you class
*/
public class CommonCouponEntity {
protected CommonCouponSeed seed;
protected BigDecimal amount;
protected String coupenID;
protected OwnerUser ownerUser;
//预定分发日期。
protected DateTime distributeDate;
public CommonCouponSeed getSeed() {
return seed;
}
public void setSeed(CommonCouponSeed seed) {
this.seed = seed;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public String getCoupenID() {
return coupenID;
}
public void setCoupenID(String coupenID) {
this.coupenID = coupenID;
}
public DateTime getDistributeDate() {
return distributeDate;
}
public void setDistributeDate(DateTime distributeDate) {
this.distributeDate = distributeDate;
}
public OwnerUser getOwnerUser() {
return ownerUser;
}
public void setOwnerUser(OwnerUser ownerUser) {
this.ownerUser = ownerUser;
}
}
package com.zhaoonline.coupon.bean;
import org.joda.time.DateTime;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 10:41<br/>
* Description:please descript you class
*/
public class CommonCouponSeed {
protected Activity activity;
protected String seedID;
protected CouponCatagory catagory;
protected BizType bizType;
protected BigDecimal totalAmount=new BigDecimal(0);
//红包的个数至少为1;
protected @NotNull Integer coupenCount=new Integer(1);
//validStartDate和validEndDate为有效期
protected DateTime validStartDate;
protected DateTime validEndDate;
//最后领取时间
protected DateTime drawDeadlineDate;
protected DistributeType distributeStrategy;
protected DrawType drawType;
public Activity getActivity() {
return activity;
}
public void setActivity(Activity activity) {
this.activity = activity;
}
public String getSeedID() {
return seedID;
}
public void setSeedID(String seedID) {
this.seedID = seedID;
}
public CouponCatagory getCatagory() {
return catagory;
}
public void setCatagory(CouponCatagory catagory) {
this.catagory = catagory;
}
public BizType getBizType() {
return bizType;
}
public void setBizType(BizType bizType) {
this.bizType = bizType;
}
public BigDecimal getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(BigDecimal totalAmount) {
this.totalAmount = totalAmount;
}
public Integer getCoupenCount() {
return coupenCount;
}
public void setCoupenCount(Integer coupenCount) {
this.coupenCount = coupenCount;
}
public DateTime getDrawDeadlineDate() {
return drawDeadlineDate;
}
public void setDrawDeadlineDate(DateTime drawDeadlineDate) {
this.drawDeadlineDate = drawDeadlineDate;
}
public DateTime getValidStartDate() {
return validStartDate;
}
public void setValidStartDate(DateTime validStartDate) {
this.validStartDate = validStartDate;
}
public DateTime getValidEndDate() {
return validEndDate;
}
public void setValidEndDate(DateTime validEndDate) {
this.validEndDate = validEndDate;
}
public DistributeType getDistributeStrategy() {
return distributeStrategy;
}
public void setDistributeStrategy(DistributeType distributeStrategy) {
this.distributeStrategy = distributeStrategy;
}
public DrawType getDrawType() {
return drawType;
}
public void setDrawType(DrawType drawType) {
this.drawType = drawType;
}
}
package com.zhaoonline.coupon.bean;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 19:14<br/>
* Description:Context表示上下文的意思,其中可以包括CoupenEnttity
*/
public class CoupenContext<T extends CommonCouponEntity,R extends CommonCouponSeed> {
private R seed=null;
private List<T> coupens =new ArrayList<T>(0);
public List<T> getCoupens() {
return coupens;
}
public void setCoupens(List<T> coupens) {
this.coupens = coupens;
}
public R getSeed() {
return seed;
}
public void setSeed(R seed) {
this.seed = seed;
}
public static CoupenContext empty() {
CoupenContext context =new CoupenContext();
return context;
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 11:03<br/>
* Description:分类:可以是红包、可以优惠券
*/
public class CouponCatagory {
private Integer catagoryID;
private String catagoryName;
public CouponCatagory(){
}
public CouponCatagory(Integer ID, String name){
this.catagoryName = name;
this.catagoryID=ID;
}
public Integer getCatagoryID() {
return catagoryID;
}
public void setCatagoryID(Integer catagoryID) {
this.catagoryID = catagoryID;
}
public String getCatagoryName() {
return catagoryName;
}
public void setCatagoryName(String catagoryName) {
this.catagoryName = catagoryName;
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 11:18<br/>
* Description:分配类型。该类作为元数据。
*/
public class DistributeType {
private Integer typeID;
private String typeName;
public Integer getTypeID() {
return typeID;
}
public void setTypeID(Integer typeID) {
this.typeID = typeID;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 11:14<br/>
* Description:领取类型,该类作为元数据
*/
public class DrawType {
private Integer typeID;
private String typeName;
public Integer getTypeID() {
return typeID;
}
public void setTypeID(Integer typeID) {
this.typeID = typeID;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 10:45<br/>
* Description:HelpOpenCoupenSeed即 帮拆红包。
* 用户在领取红包后,红包并不能立刻生效。用户必须邀请一定数目的好友进行帮拆
* 帮拆的红包,也可以分为:1)满足全部帮拆好友数目后,红包才生效。
* 2)即拆即用,好友每帮忙拆一个红包。其帮拆的一部分立刻生效,红包的主人可以立即使用该红包。
*/
public class HelpOpenCouponSeed extends CommonCouponSeed {
//帮拆的数目
private Integer helperCount=new Integer(0);
private HelpOpenType helpOpenType=HelpOpenType.VALIDE_LAST_TIME;
public Integer getHelperCount() {
return helperCount;
}
public void setHelperCount(Integer helperCount) {
this.helperCount = helperCount;
}
public HelpOpenType getHelpOpenType() {
return helpOpenType;
}
public void setHelpOpenType(HelpOpenType helpOpenType) {
this.helpOpenType = helpOpenType;
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by 杨有鹏 on 2016/12/15.
* 帮拆类型
*/
public enum HelpOpenType {
UNKNOWN(0),//未知
VALIDE_LAST_TIME(1),//最后时刻生效即帮拆
VALIDE_ON_TIME(2);//帮拆就生效
private final int type;
HelpOpenType(int type){
this.type=type;
}
public static HelpOpenType build(int type){
switch (type){
case 1:return VALIDE_LAST_TIME;
case 2:return VALIDE_ON_TIME;
default:return UNKNOWN;
}
}
public boolean is(HelpOpenType helpOpenType) {
return this.type == helpOpenType.type;
}
public boolean isNot(HelpOpenType helpOpenType){
return !is(helpOpenType);
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 10:29<br/>
* Description:该红包类型。主要服务对象是好友帮拆的即拆即用的Counpen
* 所谓即拆即用的Coupen:用户在领取红包后,红包并不能立刻生效。用户必须邀请一定数目的好友进行帮拆,
* 每个好友帮拆之后,红包中其中一部分就生效,用户在这部分红包生效之后立刻使用该红包。可使用的额度只是好友帮拆的内容
*/
public class LeafCouponEntity extends CommonCouponEntity {
private CommonCouponEntity parentCoupen;
public CommonCouponEntity getParentCoupen() {
return parentCoupen;
}
public void setParentCoupen(CommonCouponEntity parentCoupen) {
this.parentCoupen = parentCoupen;
}
}
package com.zhaoonline.coupon.bean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 14:33<br/>
* Description:用户信息
*/
public class OwnerUser {
private String ownerUserID;
private String ownerUserType;
public String getOwnerUserID() {
return ownerUserID;
}
public void setOwnerUserID(String ownerUserID) {
this.ownerUserID = ownerUserID;
}
public String getOwnerUserType() {
return ownerUserType;
}
public void setOwnerUserType(String ownerUserType) {
this.ownerUserType = ownerUserType;
}
}
package com.zhaoonline.coupon.cache;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 17:55<br/>
* Description:please descript you class
*/
public class CacheEntry<T> {
String key;
T value;
CacheEntry pre;
CacheEntry next;
}
package com.zhaoonline.coupon.cache;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 17:54<br/>
* Description:
*/
public class LRUCache<T> {
private ConcurrentHashMap<String, T> caches = null;
private CacheEntry<T> first;
private CacheEntry<T> last;
private int capacity = 0;
public LRUCache() {
this(200);
}
public LRUCache(int capacity) {
this.capacity=capacity;
this.caches = new ConcurrentHashMap<String,T>(capacity);
}
public synchronized T put(String key, T value) {
CacheEntry<T> entry = getEntry(key);
if (entry == null) {
if (caches.size() >= capacity) {
caches.remove(last.key);
removeLast();
}
entry = new CacheEntry<T>();
entry.key = key;
}else{
entry.value=null;
}
entry.value = value;
moveToFirst(entry);
return caches.put(key, value);
}
public int getSize() {
return caches.size();
}
public synchronized T get(String key) {
CacheEntry<T> entry = getEntry(key);
if (entry == null){
return null;
}
moveToFirst(entry);
return entry.value;
}
public synchronized void remove(String key) {
CacheEntry<T> entry = getEntry(key);
if (entry != null) {
if (entry.pre != null)
entry.pre.next = entry.next;
if (entry.next != null)
entry.next.pre = entry.pre;
if (entry == first)
first = entry.next;
if (entry == last)
last = entry.pre;
}
caches.remove(key);
}
private void removeLast() {
if (last != null) {
last = last.pre;
if (last == null)
first = null;
else
last.next = null;
}
}
private void moveToFirst(CacheEntry<T> entry) {
if (entry == first)
return;
if (entry.pre != null)
entry.pre.next = entry.next;
if (entry.next != null)
entry.next.pre = entry.pre;
if (entry == last)
last = last.pre;
if (first == null || last == null) {
first = last = entry;
return;
}
entry.next = first;
first.pre = entry;
first = entry;
entry.pre = null;
}
private CacheEntry<T> getEntry(String key) {
T item = caches.get(key);
if (item == null) {
return null;
}
CacheEntry<T> entry = new CacheEntry<T>();
entry.key = key;
entry.value = item;
return entry;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
CacheEntry<T> entry = first;
while (entry != null) {
sb.append(String.format("%s:%s ", entry.key, entry.value));
entry = entry.next;
}
return sb.toString();
}
public Set<String> keySet(){
Set<String> keSet=new HashSet<String>();
ConcurrentHashMap.KeySetView<String, T> keysSetView= caches.keySet();
Iterator<String> iter=keysSetView.iterator();
while(iter.hasNext()){
String key=iter.next();
keSet.add(key);
}
return keSet;
}
}
package com.zhaoonline.coupon.cache;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 18:13<br/>
* Description:随机缓存
*/
public class RandomCache<K,V> {
private ConcurrentHashMap<K,V> caches = null;
private int capacity = 0;
private List<K> keys=null;
public RandomCache() {
this(200);
}
public RandomCache(int capacity) {
this.capacity=capacity;
this.caches = new ConcurrentHashMap<K,V>(capacity);
this.keys= Collections.synchronizedList(new ArrayList<K>(capacity));
}
public synchronized void put(K key,V value){
caches.put(key, value);
keys.add(key);
}
public synchronized void remove(K key){
caches.remove(key);
keys.remove(key);
}
public K randomKey(){
Random random = new Random();
if(keys.size() == 0){
return null;
}
int keyIndex=random.nextInt(keys.size());
K key=keys.get(keyIndex);
return key;
}
public synchronized K shuffledRandomKey(){
List<K> clonedKeys=new ArrayList<>(keys);
Collections.shuffle(clonedKeys);
if(clonedKeys.size() == 0){
return null;
}
return clonedKeys.get(0);
}
public int size(){
return caches.size();
}
public boolean isEmpty(){
return caches.isEmpty();
}
public List<K> allKeys(){
return keys;
}
public V getCache(String key){
if(key == null){
return null;
}
return caches.get(key);
}
public synchronized void clear() {
this.caches = new ConcurrentHashMap<K,V>(capacity);
this.keys= Collections.synchronizedList(new ArrayList<K>(capacity));
}
}
package com.zhaoonline.coupon.concurrent;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 17:48<br/>
* Description:please descript you class
*/
public interface ConcurrentStrategy {
public boolean proceeding();
public boolean proceeding(long timeout);
}
package com.zhaoonline.coupon.concurrent;
import com.zhaoonline.coupon.concurrent.tokenbucket.TokenBucket;
import com.zhaoonline.coupon.concurrent.tokenbucket.TokenBuckets;
import java.util.concurrent.TimeUnit;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 17:49<br/>
* Description:please descript you class
*/
public class TokenBucktStrategy implements ConcurrentStrategy {
TokenBucket bucket = null;
public TokenBucktStrategy(){
bucket = TokenBuckets.builder()
.withCapacity(1000)
.withFixedIntervalRefillStrategy(400, 1, TimeUnit.SECONDS)
.build();
}
/**
* 立即返回
* @return
*/
@Override
public boolean proceeding() {
return bucket.tryConsume();
}
/**
* @param 令牌桶的timemout等同于从令牌桶里面获取多少个令牌。
* @return
*/
@Override
public boolean proceeding(long timeout) {
bucket.consume(timeout);
return true;
}
}
package com.zhaoonline.coupon.concurrent.tokenbucket;
import com.google.common.base.Ticker;
import java.util.concurrent.TimeUnit;
/**
* A token bucket refill strategy that will provide N tokens for a token bucket to consume every T units of time.
* The tokens are refilled in bursts rather than at a fixed rate. This refill strategy will never allow more than
* N tokens to be consumed during a window of time T.
*/
public class FixedIntervalRefillStrategy implements TokenBucketImpl.RefillStrategy {
private final Ticker ticker;
private final long numTokensPerPeriod;
private final long periodDurationInNanos;
private long lastRefillTime;
private long nextRefillTime;
/**
* Create a FixedIntervalRefillStrategy.
*
* @param ticker A ticker to use to measure time.
* @param numTokensPerPeriod The number of tokens to add to the bucket every period.
* @param period How often to refill the bucket.
* @param unit Unit for period.
*/
public FixedIntervalRefillStrategy(Ticker ticker, long numTokensPerPeriod, long period, TimeUnit unit) {
this.ticker = ticker;
this.numTokensPerPeriod = numTokensPerPeriod;
this.periodDurationInNanos = unit.toNanos(period);
this.lastRefillTime = -periodDurationInNanos;
this.nextRefillTime = -periodDurationInNanos;
}
@Override
public synchronized long refill() {
long now = ticker.read();
if (now < nextRefillTime) {
return 0;
}
// We now know that we need to refill the bucket with some tokens, the question is how many. We need to count how
// many periods worth of tokens we've missed.
long numPeriods = Math.max(0, (now - lastRefillTime) / periodDurationInNanos);
// Move the last refill time forward by this many periods.
lastRefillTime += numPeriods * periodDurationInNanos;
// ...and we'll refill again one period after the last time we refilled.
nextRefillTime = lastRefillTime + periodDurationInNanos;
return numPeriods * numTokensPerPeriod;
}
@Override
public long getDurationUntilNextRefill(TimeUnit unit) {
long now = ticker.read();
return unit.convert(Math.max(0, nextRefillTime - now), TimeUnit.NANOSECONDS);
}
}
\ No newline at end of file
package com.zhaoonline.coupon.concurrent.tokenbucket;
import java.util.concurrent.TimeUnit;
/**
* A token bucket is used for rate limiting access to a portion of code.
*
* @see <a href="http://en.wikipedia.org/wiki/Token_bucket">Token Bucket on Wikipedia</a>
* @see <a href="http://en.wikipedia.org/wiki/Leaky_bucket">Leaky Bucket on Wikipedia</a>
*/
public interface TokenBucket {
/**
* Returns the capacity of this token bucket. This is the maximum number of tokens that the bucket can hold at
* any one time.
*
* @return The capacity of the bucket.
*/
long getCapacity();
/**
* Returns the current number of tokens in the bucket. If the bucket is empty then this method will return 0.
*
* @return The current number of tokens in the bucket.
*/
long getNumTokens();
/**
* Returns the amount of time in the specified time unit until the next group of tokens can be added to the token
* bucket.
*
* @param unit The time unit to express the return value in.
* @return The amount of time until the next group of tokens can be added to the token bucket.
* @see org.isomorphism.util.TokenBucket.RefillStrategy#getDurationUntilNextRefill(java.util.concurrent.TimeUnit)
*/
long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperationException;
/**
* Attempt to consume a single token from the bucket. If it was consumed then {@code true} is returned, otherwise
* {@code false} is returned.
*
* @return {@code true} if a token was consumed, {@code false} otherwise.
*/
boolean tryConsume();
/**
* Attempt to consume a specified number of tokens from the bucket. If the tokens were consumed then {@code true}
* is returned, otherwise {@code false} is returned.
*
* @param numTokens The number of tokens to consume from the bucket, must be a positive number.
* @return {@code true} if the tokens were consumed, {@code false} otherwise.
*/
boolean tryConsume(long numTokens);
/**
* Consume a single token from the bucket. If no token is currently available then this method will block until a
* token becomes available.
*/
void consume();
/**
* Consumes multiple tokens from the bucket. If enough tokens are not currently available then this method will block
* until
*
* @param numTokens The number of tokens to consume from teh bucket, must be a positive number.
*/
void consume(long numTokens);
/**
* Refills the bucket with the specified number of tokens. If the bucket is currently full or near capacity then
* fewer than {@code numTokens} may be added.
*
* @param numTokens The number of tokens to add to the bucket.
*/
void refill(long numTokens);
/**
* Encapsulation of a refilling strategy for a token bucket.
*/
static interface RefillStrategy {
/**
* Returns the number of tokens to add to the token bucket.
*
* @return The number of tokens to add to the token bucket.
*/
long refill();
/**
* Returns the amount of time in the specified time unit until the next group of tokens can be added to the token
* bucket. Please note, depending on the {@code SleepStrategy} used by the token bucket, tokens may not actually
* be added until much after the returned duration. If for some reason the implementation of
* {@code RefillStrategy} doesn't support knowing when the next batch of tokens will be added, then an
* {@code UnsupportedOperationException} may be thrown. Lastly, if the duration until the next time tokens will
* be added to the token bucket is less than a single unit of the passed in time unit then this method will
* return 0.
*
* @param unit The time unit to express the return value in.
* @return The amount of time until the next group of tokens can be added to the token bucket.
*/
long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperationException;
}
/**
* Encapsulation of a strategy for relinquishing control of the CPU.
*/
static interface SleepStrategy {
/**
* Sleep for a short period of time to allow other threads and system processes to execute.
*/
void sleep();
}
}
\ No newline at end of file
package com.zhaoonline.coupon.concurrent.tokenbucket;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A token bucket implementation that is of a leaky bucket in the sense that it has a finite capacity and any added
* tokens that would exceed this capacity will "overflow" out of the bucket and are lost forever.
* <p>
* In this implementation the rules for refilling the bucket are encapsulated in a provided {@code RefillStrategy}
* instance. Prior to attempting to consume any tokens the refill strategy will be consulted to see how many tokens
* should be added to the bucket.
* <p>
* In addition in this implementation the method of yielding CPU control is encapsulated in the provided
* {@code SleepStrategy} instance. For high performance applications where tokens are being refilled incredibly quickly
* and an accurate bucket implementation is required, it may be useful to never yield control of the CPU and to instead
* busy wait. This strategy allows the caller to make this decision for themselves instead of the library forcing a
* decision.
*/
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 17:42<br/>
* Description:please descript you class
*/
public class TokenBucketImpl implements TokenBucket {
private final long capacity;
private final RefillStrategy refillStrategy;
private final SleepStrategy sleepStrategy;
private long size;
TokenBucketImpl(long capacity, long initialTokens, RefillStrategy refillStrategy, SleepStrategy sleepStrategy) {
checkArgument(capacity > 0);
checkArgument(initialTokens <= capacity);
this.capacity = capacity;
this.refillStrategy = checkNotNull(refillStrategy);
this.sleepStrategy = checkNotNull(sleepStrategy);
this.size = initialTokens;
}
/**
* Returns the capacity of this token bucket. This is the maximum number of tokens that the bucket can hold at
* any one time.
*
* @return The capacity of the bucket.
*/
@Override
public long getCapacity() {
return capacity;
}
/**
* Returns the current number of tokens in the bucket. If the bucket is empty then this method will return 0.
*
* @return The current number of tokens in the bucket.
*/
@Override
public synchronized long getNumTokens() {
// Give the refill strategy a chance to add tokens if it needs to so that we have an accurate
// count.
refill(refillStrategy.refill());
return size;
}
/**
* Returns the amount of time in the specified time unit until the next group of tokens can be added to the token
* bucket.
*
* @see org.isomorphism.util.TokenBucket.RefillStrategy#getDurationUntilNextRefill(java.util.concurrent.TimeUnit)
* @param unit The time unit to express the return value in.
* @return The amount of time until the next group of tokens can be added to the token bucket.
*/
@Override
public long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperationException {
return refillStrategy.getDurationUntilNextRefill(unit);
}
/**
* Attempt to consume a single token from the bucket. If it was consumed then {@code true} is returned, otherwise
* {@code false} is returned.
*
* @return {@code true} if a token was consumed, {@code false} otherwise.
*/
public boolean tryConsume() {
return tryConsume(1);
}
/**
* Attempt to consume a specified number of tokens from the bucket. If the tokens were consumed then {@code true}
* is returned, otherwise {@code false} is returned.
*
* @param numTokens The number of tokens to consume from the bucket, must be a positive number.
* @return {@code true} if the tokens were consumed, {@code false} otherwise.
*/
public synchronized boolean tryConsume(long numTokens) {
checkArgument(numTokens > 0, "Number of tokens to consume must be positive");
checkArgument(numTokens <= capacity, "Number of tokens to consume must be less than the capacity of the bucket.");
refill(refillStrategy.refill());
// Now try to consume some tokens
if (numTokens <= size) {
size -= numTokens;
return true;
}
return false;
}
/**
* Consume a single token from the bucket. If no token is currently available then this method will block until a
* token becomes available.
*/
public void consume() {
consume(1);
}
/**
* Consumes multiple tokens from the bucket. If enough tokens are not currently available then this method will block
* until
*
* @param numTokens The number of tokens to consume from teh bucket, must be a positive number.
*/
public void consume(long numTokens) {
while (true) {
if (tryConsume(numTokens)) {
break;
}
sleepStrategy.sleep();
}
}
/**
* Refills the bucket with the specified number of tokens. If the bucket is currently full or near capacity then
* fewer than {@code numTokens} may be added.
*
* @param numTokens The number of tokens to add to the bucket.
*/
public synchronized void refill(long numTokens) {
long newTokens = Math.min(capacity, Math.max(0, numTokens));
size = Math.max(0, Math.min(size + newTokens, capacity));
}
}
package com.zhaoonline.coupon.concurrent.tokenbucket;
import com.google.common.base.Ticker;
import com.google.common.util.concurrent.Uninterruptibles;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 17:42<br/>
* Description:please descript you class
*/
/**
* Static utility methods pertaining to creating {@link TokenBucketImpl} instances.
*/
public final class TokenBuckets {
private TokenBuckets() {
}
/**
* Create a new builder for token buckets.
*/
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Long capacity = null;
private long initialTokens = 0;
private TokenBucketImpl.RefillStrategy refillStrategy = null;
private TokenBucketImpl.SleepStrategy sleepStrategy = YIELDING_SLEEP_STRATEGY;
private final Ticker ticker = Ticker.systemTicker();
/**
* Specify the overall capacity of the token bucket.
*/
public Builder withCapacity(long numTokens) {
checkArgument(numTokens > 0, "Must specify a positive number of tokens");
capacity = numTokens;
return this;
}
/**
* Initialize the token bucket with a specific number of tokens.
*/
public Builder withInitialTokens(long numTokens) {
checkArgument(numTokens > 0, "Must specify a positive number of tokens");
initialTokens = numTokens;
return this;
}
/**
* Refill tokens at a fixed interval.
*/
public Builder withFixedIntervalRefillStrategy(long refillTokens, long period, TimeUnit unit) {
return withRefillStrategy(new FixedIntervalRefillStrategy(ticker, refillTokens, period, unit));
}
/**
* Use a user defined refill strategy.
*/
public Builder withRefillStrategy(TokenBucket.RefillStrategy refillStrategy) {
this.refillStrategy = checkNotNull(refillStrategy);
return this;
}
/**
* Use a sleep strategy that will always attempt to yield the CPU to other processes.
*/
public Builder withYieldingSleepStrategy() {
return withSleepStrategy(YIELDING_SLEEP_STRATEGY);
}
/**
* Use a sleep strategy that will not yield the CPU to other processes. It will busy wait until more tokens become
* available.
*/
public Builder withBusyWaitSleepStrategy() {
return withSleepStrategy(BUSY_WAIT_SLEEP_STRATEGY);
}
/**
* Use a user defined sleep strategy.
*/
public Builder withSleepStrategy(TokenBucket.SleepStrategy sleepStrategy) {
this.sleepStrategy = checkNotNull(sleepStrategy);
return this;
}
/**
* Build the token bucket.
*/
public TokenBucket build() {
checkNotNull(capacity, "Must specify a capacity");
checkNotNull(refillStrategy, "Must specify a refill strategy");
return new TokenBucketImpl(capacity, initialTokens, refillStrategy, sleepStrategy);
}
}
private static final TokenBucketImpl.SleepStrategy YIELDING_SLEEP_STRATEGY = new TokenBucketImpl.SleepStrategy() {
@Override
public void sleep() {
// Sleep for the smallest unit of time possible just to relinquish control
// and to allow other threads to run.
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.NANOSECONDS);
}
};
private static final TokenBucketImpl.SleepStrategy BUSY_WAIT_SLEEP_STRATEGY = new TokenBucketImpl.SleepStrategy() {
@Override
public void sleep() {
// Do nothing, don't sleep.
}
};
}
package com.zhaoonline.coupon.jwt;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 14:58<br/>
* Description:please descript you class
*/
public class JWTConfig {
private String issuer;
private String password;
private String encodeKeyName;
public String getIssuer() {
return issuer;
}
public void setIssuer(String issuer) {
this.issuer = issuer;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEncodeKeyName() {
return encodeKeyName;
}
public void setEncodeKeyName(String encodeKeyName) {
this.encodeKeyName = encodeKeyName;
}
}
package com.zhaoonline.coupon.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 10:38<br/>
* Description:please descript you class
*/
public class JWTDecoder {
private static ObjectMapper objectMapper =new ObjectMapper();
JWTVerifier verifier = null;
JWTConfig config =new JWTConfig();
public JWTDecoder(JWTConfig config) throws UnsupportedEncodingException {
this.config= config;
verifier =JWT.require(Algorithm.HMAC256(config.getPassword()))
.withIssuer(config.getIssuer())
.build();
}
public <T> T decode(String jwtToken,Class<T> clazz ) throws IOException {
DecodedJWT jwt = verifier.verify(jwtToken);
java.lang.String coupenJsonString= jwt.getClaim(config.getEncodeKeyName()).asString();
T decodeCoupen= objectMapper.readValue(coupenJsonString,clazz);
return decodeCoupen;
}
}
package com.zhaoonline.coupon.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.UnsupportedEncodingException;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 10:38<br/>
* Description:please descript you class
*/
public class JWTEncoder {
private static ObjectMapper objectMapper =new ObjectMapper();
JWTConfig config =new JWTConfig();
public JWTEncoder(JWTConfig config){
this.config= config;
}
public String encode(Object object) throws JsonProcessingException, UnsupportedEncodingException {
String coupenSeedString =objectMapper.writeValueAsString(object);
String token = JWT.create()
.withIssuer(config.getIssuer())
.withClaim(config.getEncodeKeyName(),coupenSeedString)
.sign(Algorithm.HMAC256(config.getPassword()));
return token;
}
}
/*
* jwt即json web token,将对象转json之后,对其进行加密和解密。
*
* */
package com.zhaoonline.coupon.jwt;
\ No newline at end of file
package com.zhaoonline.coupon.lifecycle;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 15:22<br/>
* Description:please descript you class
*/
public class LifeCycle {
private AtomicBoolean start=new AtomicBoolean(false);
private AtomicBoolean needReload=new AtomicBoolean(false);
public void markNeedReload(){
needReload.set(true);
}
public void resetNeedReload(){
needReload.set(false);
}
public boolean checkNeedReload(){
return needReload.get();
}
public void markStart(){
start.compareAndSet(false,true);
}
public void markShutDown(){
start.set(false);
}
public void resetAll(){
needReload.set(false);
start.set(false);
}
}
package com.zhaoonline.coupon.repository;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 16:06<br/>
* Description:活动的增删改查
*/
public class ActivityRepository {
}
package com.zhaoonline.coupon.repository;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.redis.repository.DataValueRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 16:08<br/>
* Description:CoupenEntity(具体的Counpen实体)的增删改查
*/
public class CouponEntityRepository {
private static final String radisKeyCoupenPreffix="coupon";
private static final String radisKeyActivityPreffix="activity";
private static final String radisKeySeedPreffix="seed";
private DataValueRepository<CommonCouponEntity> coupenRepository =null;
private RedisTemplate<String,CommonCouponEntity> redisTemplate;
private static GenericJackson2JsonRedisSerializer valueDeSe= new GenericJackson2JsonRedisSerializer();
@Autowired
public CouponEntityRepository(DataValueRepository<CommonCouponEntity> coupenRepository){
this.coupenRepository=coupenRepository;
redisTemplate = this.coupenRepository.getRedisTemplate();
}
public boolean saveCoupenEntity(CommonCouponEntity coupen) {
String coupenKey=concatCoupenRedisKey(coupen.getCoupenID());
CommonCouponSeed seed=coupen.getSeed();
byte[] activityKeyBytes =null;
byte[] seedKeyBytes=null;
if(seed !=null){
String seedKey=concatSeedRedisKey(seed.getSeedID());
seedKeyBytes=redisTemplate.getStringSerializer().serialize(seedKey);
Activity activity= seed.getActivity();
if(activity != null){
String activityKey=concatActivityRedisKey(activity.getActivityID());
activityKeyBytes=redisTemplate.getStringSerializer().serialize(activityKey);
}
}
byte[] coupenKeyBytes=redisTemplate.getStringSerializer().serialize(coupenKey);
byte[] valueBytes=valueDeSe.serialize(coupen);
CoupenAddRedisCallBack addRedisCallBack = new CoupenAddRedisCallBack(activityKeyBytes,seedKeyBytes,coupenKeyBytes,valueBytes);
redisTemplate.executePipelined(addRedisCallBack);
return true;
}
private String concatActivityRedisKey(Integer activityID) {
return radisKeyActivityPreffix+":"+activityID;
}
private String concatSeedRedisKey(String seedID) {
return radisKeySeedPreffix+":"+seedID;
}
public void deleteCoupenEntityByKey(CommonCouponEntity coupen){
String coupenKey=concatCoupenRedisKey(coupen.getCoupenID());
CommonCouponSeed seed=coupen.getSeed();
String seedKey=concatSeedRedisKey(seed.getSeedID());
byte[] coupenKeyBytes=redisTemplate.getStringSerializer().serialize(coupenKey);
byte[] seedKeyBytes=redisTemplate.getStringSerializer().serialize(seedKey);
redisTemplate.executePipelined(new RedisCallback<CommonCouponEntity>() {
@Override
public CommonCouponEntity doInRedis(RedisConnection connection) throws DataAccessException {
connection.del(coupenKeyBytes);
connection.sRem(seedKeyBytes,coupenKeyBytes);
//必须要返回null。否则会抛出异常
// org.springframework.dao.InvalidDataAccessApiUsageException: Callback cannot return a non-null value as it gets overwritten by the pipeline
return null;
}
});
//coupenRepository.delete(activitySaveedKey);
}
public CommonCouponEntity getCoupenEntityByKey(String coupenID){
String activitySaveedKey=concatCoupenRedisKey(coupenID);
CommonCouponEntity result= coupenRepository.get(activitySaveedKey);
return result;
}
private String concatCoupenRedisKey(String key){
return radisKeyCoupenPreffix+":"+key;
}
public class CoupenAddRedisCallBack implements RedisCallback<CommonCouponEntity>{
private byte[] activityKeyBytes =null;
private byte[] seedKeyBytes =null;
private byte[] coupenKeyBytes =null;
private byte[] valueBytes =null;
public CoupenAddRedisCallBack(byte[] activityKeyBytes , byte[] seedKeyBytes,byte[] coupenKeyBytes, byte[] valueBytes){
this.activityKeyBytes=activityKeyBytes;
this.seedKeyBytes = seedKeyBytes;
this.coupenKeyBytes = coupenKeyBytes;
this.valueBytes = valueBytes;
}
@Override
public CommonCouponEntity doInRedis(RedisConnection connection) throws DataAccessException {
// connection.watch(coupenKeyBytes);
// connection.multi();
if(activityKeyBytes != null){
connection.sAdd(activityKeyBytes,seedKeyBytes);
}
if(seedKeyBytes != null){
connection.sAdd(seedKeyBytes,coupenKeyBytes);
}
connection.setNX(coupenKeyBytes,valueBytes);
// connection.exec();
// connection.unwatch();
return null;
}
}
}
package com.zhaoonline.coupon.repository;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 16:07<br/>
* Description:CoupenSeed的增删改查
*/
public class CouponSeedRepository {
}
package com.zhaoonline.coupon.repository;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 16:36<br/>
* Description:用户与Coupen之间映射关系的增删改查
*/
public class UserCouponMappingRepository {
}
package com.zhaoonline.coupon.utils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 20:00<br/>
* Description:please descript you class
*/
public class JsonUtils {
private static ObjectMapper mapper= new ObjectMapper();
/**
* Method name: toObject <BR>
* Description: 读取失败就返回null <BR>
* Remark: <BR>
* @param inputStram
* @param clazz
* @return T<BR>
* @throws IOException
* @throws JsonMappingException
* @throws JsonParseException
*/
public static <T> T toObject(InputStream inputStram , Class<T> clazz) throws JsonParseException, JsonMappingException, IOException {
return mapper.readValue(inputStram, clazz);
}
public static String toJson(Object object) throws JsonProcessingException {
return mapper.writeValueAsString(object);
}
public static <T> T toObject(String jsonString,Class<T> clazz) throws IOException {
return mapper.readValue(jsonString, clazz);
}
public static Map toMap(String jsonString) throws IOException {
return toObject(jsonString,Map.class);
}
}
package com.zhaoonline.coupon.utils;
import java.io.Closeable;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 19:57<br/>
* Description:please descript you class
*/
public class Utils {
public static void closeStream(Closeable stream){
if(stream!=null){
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String getRandomForDate(String param){
SimpleDateFormat simpleDateFormat;
simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
String str = simpleDateFormat.format(date);
Random random = new Random();
int rannum = (int) (random.nextDouble() * (9999 - 100 + 1)) + 100;// 获取5位随机数
return param + str + rannum;
}
}
package com.zhaoonline.coupon.concurrent.tokenbucket;
import com.google.common.base.Ticker;
import com.zhaoonline.coupon.concurrent.tokenbucket.FixedIntervalRefillStrategy;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
public class FixedIntervalRefillStrategyTest {
private static final long N = 5; // 5 tokens
private static final long P = 10; // every 10
private static final TimeUnit U = TimeUnit.SECONDS; // seconds
private final MockTicker ticker = new MockTicker();
private final FixedIntervalRefillStrategy strategy = new FixedIntervalRefillStrategy(ticker, N, P, U);
@Test
public void testFirstRefill() {
assertEquals(N, strategy.refill());
}
@Test
public void testNoRefillUntilPeriodUp() {
strategy.refill();
// Another refill shouldn't come for P time units.
for (int i = 0; i < P - 1; i++) {
ticker.advance(1, U);
assertEquals(0, strategy.refill());
}
}
@Test
public void testRefillEveryPeriod() {
strategy.refill();
ticker.advance(P, U);
assertEquals(N, strategy.refill());
ticker.advance(P, U);
assertEquals(N, strategy.refill());
ticker.advance(P, U);
assertEquals(N, strategy.refill());
}
@Test
public void testRefillEveryOtherPeriod() {
strategy.refill();
// Move time forward two periods, since we're skipping a period next time we should add double the tokens.
ticker.advance(2 * P, U);
assertEquals(2 * N, strategy.refill());
ticker.advance(2 * P, U);
assertEquals(2 * N, strategy.refill());
}
@Test
public void testRefillOnNonEvenPeriods() {
// The strategy is configured to refill tokens every P time units. So we should only get refills at 0, P, 2P, 3P,
// etc. Any other time should return 0 tokens.
// t = 0
assertEquals(N, strategy.refill());
// t = P+1
ticker.advance(P + 1, U);
assertEquals(N, strategy.refill());
// t = 2P+1
ticker.advance(P, U);
assertEquals(N, strategy.refill());
// t = 3P
ticker.advance(P - 1, U);
assertEquals(N, strategy.refill());
// t = 4P-1
ticker.advance(P - 1, U);
assertEquals(0, strategy.refill());
// t = 4P
ticker.advance(1, U);
assertEquals(N, strategy.refill());
}
@Test
public void testDurationUntilFirstRefill() {
// A refill has never happened, so one is supposed to happen immediately.
assertEquals(0, strategy.getDurationUntilNextRefill(TimeUnit.SECONDS));
}
@Test
public void testDurationAfterFirstRefill() {
strategy.refill();
for (int i = 0; i < P - 1; i++) {
assertEquals(P - i, strategy.getDurationUntilNextRefill(TimeUnit.SECONDS));
ticker.advance(1, U);
}
}
@Test
public void testDurationAtSecondRefillTime() {
strategy.refill();
ticker.advance(P, U);
assertEquals(0, strategy.getDurationUntilNextRefill(TimeUnit.SECONDS));
}
@Test
public void testDurationInProperUnits() {
strategy.refill();
assertEquals(10000, strategy.getDurationUntilNextRefill(TimeUnit.MILLISECONDS));
}
private static final class MockTicker extends Ticker {
private long now = 0;
@Override
public long read() {
return now;
}
public void advance(long delta, TimeUnit unit) {
now += unit.toNanos(delta);
}
}
}
\ No newline at end of file
package com.zhaoonline.coupon.concurrent.tokenbucket;
import com.zhaoonline.coupon.concurrent.tokenbucket.TokenBuckets;
import org.junit.Test;
public class TokenBucketBuilderTest {
private final TokenBuckets.Builder builder = TokenBuckets.builder();
@Test(expected = IllegalArgumentException.class)
public void testNegativeCapacity() {
builder.withCapacity(-1);
}
@Test(expected = IllegalArgumentException.class)
public void testZeroCapacity() {
builder.withCapacity(0);
}
@Test(expected = IllegalArgumentException.class)
public void testNegativeInitialTokens() {
builder.withInitialTokens(-1);
}
}
\ No newline at end of file
package com.zhaoonline.coupon.concurrent.tokenbucket;
import com.zhaoonline.coupon.concurrent.tokenbucket.TokenBucket;
import com.zhaoonline.coupon.concurrent.tokenbucket.TokenBucketImpl;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class TokenBucketImplTest {
private static final long CAPACITY = 10;
private final MockRefillStrategy refillStrategy = new MockRefillStrategy();
private final TokenBucket.SleepStrategy sleepStrategy = mock(TokenBucket.SleepStrategy.class);
private final TokenBucketImpl bucket = new TokenBucketImpl(CAPACITY, 0, refillStrategy, sleepStrategy);
@Test(expected = IllegalArgumentException.class)
public void testNegativeCapacity() {
new TokenBucketImpl(-1, 0, refillStrategy, sleepStrategy);
}
@Test(expected = IllegalArgumentException.class)
public void testZeroCapacity() {
new TokenBucketImpl(0, 0, refillStrategy, sleepStrategy);
}
@Test(expected = IllegalArgumentException.class)
public void testMoreInitialTokensThanCapacity() {
new TokenBucketImpl(1, 2, refillStrategy, sleepStrategy);
}
@Test
public void testGetCapacity() {
assertEquals(CAPACITY, bucket.getCapacity());
}
@Test
public void testEmptyBucketHasZeroTokens() {
assertEquals(0, bucket.getNumTokens());
}
@Test
public void testBucketWithInitialTokens() {
TokenBucketImpl bucket = new TokenBucketImpl(CAPACITY, CAPACITY, refillStrategy, sleepStrategy);
assertEquals(CAPACITY, bucket.getNumTokens());
}
@Test
public void testAddingTokenIncreasesNumTokens() {
refillStrategy.addToken();
assertEquals(1, bucket.getNumTokens());
}
@Test
public void testAddingMultipleTokensIncreasesNumTokens() {
refillStrategy.addTokens(2);
assertEquals(2, bucket.getNumTokens());
}
@Test
public void testAtCapacityNumTokens() {
refillStrategy.addTokens(CAPACITY);
assertEquals(CAPACITY, bucket.getNumTokens());
}
@Test
public void testOverCapacityNumTokens() {
refillStrategy.addTokens(CAPACITY + 1);
assertEquals(CAPACITY, bucket.getNumTokens());
}
@Test
public void testConsumingTokenDecreasesNumTokens() {
refillStrategy.addTokens(1);
bucket.consume();
assertEquals(0, bucket.getNumTokens());
}
@Test
public void testConsumingMultipleTokensDecreasesNumTokens() {
refillStrategy.addTokens(CAPACITY);
bucket.consume(2);
assertEquals(CAPACITY - 2, bucket.getNumTokens());
}
@Test
public void testEmptyNumTokens() {
refillStrategy.addTokens(CAPACITY);
bucket.consume(CAPACITY);
assertEquals(0, bucket.getNumTokens());
}
@Test
public void testFailedConsumeKeepsNumTokens() {
refillStrategy.addTokens(1);
bucket.tryConsume(2);
assertEquals(1, bucket.getNumTokens());
}
@Test(expected = IllegalArgumentException.class)
public void testTryConsumeZeroTokens() {
bucket.tryConsume(0);
}
@Test(expected = IllegalArgumentException.class)
public void testTryConsumeNegativeTokens() {
bucket.tryConsume(-1);
}
@Test(expected = IllegalArgumentException.class)
public void testTryConsumeMoreThanCapacityTokens() {
bucket.tryConsume(100);
}
@Test
public void testTryConsumeOnEmptyBucket() {
assertFalse(bucket.tryConsume());
}
@Test
public void testTryConsumeOneToken() {
refillStrategy.addToken();
assertTrue(bucket.tryConsume());
}
@Test
public void testTryConsumeMoreTokensThanAreAvailable() {
refillStrategy.addToken();
assertFalse(bucket.tryConsume(2));
}
@Test
public void testTryManuallyRefillOneToken() {
bucket.refill(1);
assertTrue(bucket.tryConsume());
}
@Test
public void testTryManuallyRefillCapacityTokens() {
bucket.refill(CAPACITY);
assertTrue(bucket.tryConsume(CAPACITY));
assertFalse(bucket.tryConsume(1));
}
@Test
public void testTryManuallyRefillMoreThanCapacityTokens() {
bucket.refill(CAPACITY + 1);
assertTrue(bucket.tryConsume(CAPACITY));
assertFalse(bucket.tryConsume(1));
}
@Test
public void testTryManualRefillAndStrategyRefill() {
bucket.refill(CAPACITY);
refillStrategy.addTokens(CAPACITY);
assertTrue(bucket.tryConsume(CAPACITY));
assertFalse(bucket.tryConsume(1));
}
@Test
public void testTryRefillMoreThanCapacityTokens() {
refillStrategy.addTokens(CAPACITY + 1);
assertTrue(bucket.tryConsume(CAPACITY));
assertFalse(bucket.tryConsume(1));
}
@Test
public void testTryRefillWithTooManyTokens() {
refillStrategy.addTokens(CAPACITY);
assertTrue(bucket.tryConsume());
refillStrategy.addTokens(Long.MAX_VALUE);
assertTrue(bucket.tryConsume(CAPACITY));
assertFalse(bucket.tryConsume(1));
}
private static final class MockRefillStrategy implements TokenBucketImpl.RefillStrategy {
private long numTokensToAdd = 0;
public long refill() {
long numTokens = numTokensToAdd;
numTokensToAdd = 0;
return numTokens;
}
@Override
public long getDurationUntilNextRefill(TimeUnit unit) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public void addToken() {
numTokensToAdd++;
}
public void addTokens(long numTokens) {
numTokensToAdd += numTokens;
}
}
}
\ No newline at end of file
package com.zhaoonline.coupon.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.BizType;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.math.BigDecimal;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 10:42<br/>
* Description:please descript you class
*/
public class TestJWTEncoder {
ObjectMapper objectMapper = new ObjectMapper();
/**
* 测试使用原生的JWT来对对象进行编码和解码
* @throws IOException
*/
@Test
public void testEncodeAndDecodeWithoriginalJWT() throws IOException {
CommonCouponSeed coupenSeed =new CommonCouponSeed();
Activity activity= new Activity(1,"新年大礼包");
BigDecimal totalAmount = new BigDecimal(8880);
Integer coupenCount = 10;
coupenSeed.setActivity(activity);
coupenSeed.setTotalAmount(totalAmount);
coupenSeed.setBizType(new BizType(1,"TZB"));
coupenSeed.setCoupenCount(coupenCount);
JWTConfig config =new JWTConfig();
config.setIssuer("zhaoonline");
config.setPassword("hellowwolrd");
String coupenSeedString =objectMapper.writeValueAsString(coupenSeed);
String token = JWT.create()
.withIssuer(config.getIssuer())
.withClaim("counpen",coupenSeedString)
.sign(Algorithm.HMAC256(config.getPassword()));
System.out.println(token);
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(config.getPassword()))
.withIssuer(config.getIssuer())
.build();
DecodedJWT jwt = verifier.verify(token);
String coupenJsonString= jwt.getClaim("counpen").asString();
CommonCouponSeed decodeCoupen= objectMapper.readValue(coupenJsonString,CommonCouponSeed.class);
Assert.assertEquals(activity.getActivityName(), decodeCoupen.getActivity().getActivityName());
Assert.assertEquals(coupenCount, decodeCoupen.getCoupenCount());
}
/**
* 使用我们封装过得getCoupenCountJWTEncoder和JWTDecoder来测试编码和解码
*/
@Test
public void testEncodeAndDecodeWithWrappedJWT() throws IOException {
CommonCouponSeed coupenSeed =new CommonCouponSeed();
Activity activity= new Activity(1,"新年大礼包");
BigDecimal totalAmount = new BigDecimal(8880);
Integer coupenCount = 10;
coupenSeed.setActivity(activity);
coupenSeed.setTotalAmount(totalAmount);
coupenSeed.setBizType(new BizType(1,"TZB"));
coupenSeed.setCoupenCount(coupenCount);
JWTConfig config =new JWTConfig();
config.setIssuer("zhaoonline");
config.setPassword("hellowwolrd");
config.setEncodeKeyName("coupon");
JWTEncoder encoder= new JWTEncoder(config);
String token= encoder.encode(coupenSeed);
JWTDecoder decoder=new JWTDecoder(config);
CommonCouponSeed decodeCoupen= decoder.decode(token,CommonCouponSeed.class);
Assert.assertEquals(activity.getActivityName(), decodeCoupen.getActivity().getActivityName());
Assert.assertEquals(coupenCount, decodeCoupen.getCoupenCount());
}
}
package com.zhaoonline.coupon.repository;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.redis.repository.DataValueRepository;
import com.zhaoonline.redis.template.RedisTemplateFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/19<br/>
* Time: 10:52<br/>
* Description:please descript you class
*/
public class TestCounponEntityRepository {
RedisTemplateFactory factory=null;
JedisConnectionFactory connectionFactory=null;
@Before
public void prepare(){
connectionFactory=createSimpleFactory();
factory=new RedisTemplateFactory();
factory.setConnectionFactory(connectionFactory);
}
@Test
public void testSaveCounponRepository(){
DataValueRepository<CommonCouponEntity> redisRepository=new DataValueRepository<CommonCouponEntity>(factory);
CouponEntityRepository repository = new CouponEntityRepository(redisRepository);
CommonCouponEntity couppen = new CommonCouponEntity();
Activity activity = new Activity();
activity.setActivityID(1);
activity.setActivityName("testActivity");
CommonCouponSeed seed= new CommonCouponSeed();
seed.setSeedID("testSeed1");
seed.setActivity(activity);
couppen.setCoupenID("testCoupen1");
couppen.setSeed(seed);
repository.saveCoupenEntity(couppen);
CommonCouponEntity saveedCoupen= repository.getCoupenEntityByKey("testCoupen1");
Assert.assertEquals(couppen.getCoupenID(),saveedCoupen.getCoupenID());
repository.deleteCoupenEntityByKey(couppen);
CommonCouponEntity coupenAfterDelete= repository.getCoupenEntityByKey("testCoupen1");
Assert.assertNull(coupenAfterDelete);
}
@After
public void after(){
connectionFactory.destroy();
}
private JedisConnectionFactory createSimpleFactory(){
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName("192.168.0.188");
factory.setPort(6377);
factory.setUsePool(true);
factory.setDatabase(1);
factory.afterPropertiesSet();
return factory;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="coupen-core" />
<orderEntry type="module" module-name="coupon-core" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:1.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:18.0" level="project" />
<orderEntry type="library" name="Maven: joda-time:joda-time:2.9.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.8.1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.8.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.8.1" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.21" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.1.7" level="project" />
<orderEntry type="library" name="Maven: com.zhaoonline:microservice-redis:1.0.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: redis.clients:jedis:2.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.4.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:1.7.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:1.1.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:1.12.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: aopalliance:aopalliance:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.slf4j:jcl-over-slf4j:1.7.21" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-all:1.10.19" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: com.auth0:java-jwt:3.0.1" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15on:1.55" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.7.0" level="project" />
<orderEntry type="library" name="Maven: org.bitbucket.b_c:jose4j:0.5.2" level="project" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>com.zhaoonline.coupon</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>coupon-dispatcher-api</artifactId>
<dependencies>
<dependency>
<groupId>com.zhaoonline.coupon</groupId>
<artifactId>coupon-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.zhaoonline.coupon.dispatcher;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 15:38<br/>
* Description:红包派发器
*/
public interface CoupenDispatchHandler {
/**根据活动来获取一个红包种子
* @param activity
* @return
*/
public List<CommonCouponEntity> dispatchCoupenEntityUsingActivity(Activity activity);
/**根据活动来获取一个红包种子
* @param activity
* @return
*/
public List<CommonCouponSeed> dispatchCoupenSeedUsingActivity(Activity activity);
/**
*根据红包seed来获取一个红包
* @param
* @return
*/
public List<CommonCouponEntity> dispacthCoupenEntityUsingSeed(CommonCouponSeed seed);
/**
*根据红包coupen来获取一个红包
* @param
* @return
*/
public List<CommonCouponEntity> dispacthCoupenEntityUsingCoupen(CommonCouponEntity coupenEntity);
}
package com.zhaoonline.coupon.dispatcher;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.OwnerUser;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 16:34<br/>
* Description:用户与Coupen的关系映射处理器,
* 同时还包括帮拆的好友信息记录
*/
public interface UserCoupenMappingHandler {
List<CommonCouponEntity> getMappingOfUser(Activity activity, OwnerUser user);
CommonCouponEntity mappingCoupen2User(CommonCouponEntity coupenEntity, OwnerUser user);
boolean recordHelpOpen(CommonCouponEntity coupenEntity, OwnerUser helper);
List<CommonCouponEntity> getHelpOpenCoupenOfUser(CommonCouponEntity coupenEntity, OwnerUser drawOwner);
}
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="NewModuleRootManager" inherit-compiler-output="false">
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="module" module-name="coupon-core" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:1.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:18.0" level="project" />
<orderEntry type="library" name="Maven: joda-time:joda-time:2.9.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.8.1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.8.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.8.1" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.21" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.1.7" level="project" />
<orderEntry type="library" name="Maven: com.zhaoonline:microservice-redis:1.0.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: redis.clients:jedis:2.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.4.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:1.7.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:1.1.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:1.12.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: aopalliance:aopalliance:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.slf4j:jcl-over-slf4j:1.7.21" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-all:1.10.19" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: com.auth0:java-jwt:3.0.1" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15on:1.55" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.7.0" level="project" />
<orderEntry type="library" name="Maven: org.bitbucket.b_c:jose4j:0.5.2" level="project" />
<orderEntry type="module" module-name="coupon-dispatcher-api" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>com.zhaoonline.coupon</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>coupon-dispatcher</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.zhaoonline.coupon</groupId>
<artifactId>coupon-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.zhaoonline.coupon</groupId>
<artifactId>coupon-dispatcher-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.zhaoonline.coupon.dispatcher;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 16:04<br/>
* Description:please descript you class
*/
public class DefaultCoupenDispatchHandler implements CoupenDispatchHandler {
@Override
public List<CommonCouponEntity> dispatchCoupenEntityUsingActivity(Activity activity) {
return null;
}
@Override
public List<CommonCouponSeed> dispatchCoupenSeedUsingActivity(Activity activity) {
return null;
}
@Override
public List<CommonCouponEntity> dispacthCoupenEntityUsingSeed(CommonCouponSeed seed) {
return null;
}
@Override
public List<CommonCouponEntity> dispacthCoupenEntityUsingCoupen(CommonCouponEntity coupenEntity) {
return null;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="coupen-core" />
<orderEntry type="module" module-name="coupon-core" />
<orderEntry type="library" name="Maven: com.google.guava:guava:18.0" level="project" />
<orderEntry type="library" name="Maven: joda-time:joda-time:2.9.4" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.8.1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.8.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.8.1" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.21" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.1.7" level="project" />
<orderEntry type="library" name="Maven: com.zhaoonline:microservice-redis:1.0.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: redis.clients:jedis:2.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.4.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:1.7.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:1.1.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:1.12.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:4.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: aopalliance:aopalliance:1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.slf4j:jcl-over-slf4j:1.7.21" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-all:1.10.19" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.2.RELEASE" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: com.auth0:java-jwt:3.0.1" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15on:1.55" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.7.0" level="project" />
<orderEntry type="library" name="Maven: org.bitbucket.b_c:jose4j:0.5.2" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:1.1.0.Final" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>com.zhaoonline.coupon</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>coupon-generator</artifactId>
<dependencies>
<dependency>
<groupId>com.zhaoonline.coupon</groupId>
<artifactId>coupon-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.zhaoonline.coupon.generator;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 20:29<br/>
* Description:please descript you class
*/
public class CoupenGenerator {
}
package com.zhaoonline.coupon.generator.distribute;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.coupon.bean.CoupenContext;
import com.zhaoonline.coupon.utils.Utils;
import org.springframework.util.ObjectUtils;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 19:15<br/>
* Description:总金额平均分配
*/
public class AverageStrategy implements DistributeStrategy{
private static final String STRATEGY_NAME="avr";
@Override
public CoupenContext<CommonCouponEntity,CommonCouponSeed> distribute(@NotNull CommonCouponSeed seed) {
if(ObjectUtils.isEmpty(seed)){
return CoupenContext.empty();
}
BigDecimal amountPerCoupen = this.amountPerCoupen(seed);
Integer expectCount=seed.getCoupenCount();
List<CommonCouponEntity> newCreatedCoupens=new ArrayList<CommonCouponEntity>(expectCount);
for(int i=0 ;i<expectCount.intValue();i++){
CommonCouponEntity coupenEntity =new CommonCouponEntity();
coupenEntity.setCoupenID(generateCoupenID());
coupenEntity.setSeed(seed);
coupenEntity.setAmount(amountPerCoupen);
newCreatedCoupens.add(coupenEntity);
}
CoupenContext<CommonCouponEntity,CommonCouponSeed> coupenContext=new CoupenContext<CommonCouponEntity,CommonCouponSeed>();
coupenContext.setSeed(seed);
coupenContext.setCoupens(newCreatedCoupens);
return coupenContext;
}
@Override
public String distributeName() {
return STRATEGY_NAME;
}
private String generateCoupenID(){
return Utils.getRandomForDate(STRATEGY_NAME);
}
/**计算每个红包的金额
* @param seed
* @return
*/
public BigDecimal amountPerCoupen(CommonCouponSeed seed){
Integer expectCoupneCount=seed.getCoupenCount();
BigDecimal totalAmount=seed.getTotalAmount();
return totalAmount.divide(new BigDecimal(expectCoupneCount),3,BigDecimal.ROUND_HALF_UP);
}
}
package com.zhaoonline.coupon.generator.distribute;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.coupon.bean.CoupenContext;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 19:12<br/>
* Description:please descript you class
*/
public interface DistributeStrategy {
public CoupenContext distribute(CommonCouponSeed seed);
public String distributeName();
}
package com.zhaoonline.coupon.generator.distribute;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/14<br/>
* Time: 20:31<br/>
* Description:根据每一个红包的distributeStrategy生成相应的分配策略
*/
public class DistributeStrategyFactory {
}
package com.zhaoonline.coupon.generator.distribute;
import com.zhaoonline.coupon.bean.*;
import com.zhaoonline.coupon.utils.Utils;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 10:20<br/>
* Description:此测试适用于。将每一个大红包的金额。按照所需帮拆好友的数目,再划分若干等分
*/
public class LeafAverageStrategy implements DistributeStrategy {
private static final String STRATEGY_NAME="iavr";
AverageStrategy averageStatragy=new AverageStrategy();
@Override
public CoupenContext<LeafCouponEntity,HelpOpenCouponSeed> distribute(CommonCouponSeed seed) {
if(ObjectUtils.isEmpty(seed)){
return CoupenContext.empty();
}
CoupenContext<CommonCouponEntity,CommonCouponSeed> contextOfSeed= averageStatragy.distribute(seed);
HelpOpenCouponSeed helpOpenCoupenSeed=null;
if(contextOfSeed.getSeed() instanceof HelpOpenCouponSeed){
helpOpenCoupenSeed=(HelpOpenCouponSeed)contextOfSeed.getSeed();
}
List<CommonCouponEntity> coupenListFromSeed=contextOfSeed.getCoupens();
List<LeafCouponEntity> newCreatedCoupens=new ArrayList<LeafCouponEntity>();
//帮拆的朋友个数
Integer helperCount=helpOpenCoupenSeed.getHelperCount();
HelpOpenType helpOpenType=helpOpenCoupenSeed.getHelpOpenType();
switch (helpOpenType){
case VALIDE_LAST_TIME:{
for(CommonCouponEntity coupenEntity:coupenListFromSeed){
LeafCouponEntity leafCoupenEntity=new LeafCouponEntity();
leafCoupenEntity.setParentCoupen(coupenEntity);
leafCoupenEntity.setSeed(helpOpenCoupenSeed);
leafCoupenEntity.setAmount(coupenEntity.getAmount());
leafCoupenEntity.setCoupenID(generateCoupenID());
newCreatedCoupens.add(leafCoupenEntity);
}
break;
}
case VALIDE_ON_TIME:{
for(CommonCouponEntity coupenEntity:coupenListFromSeed){
BigDecimal amountPerChildCoupne= amountPerCoupen(coupenEntity.getAmount(),helpOpenCoupenSeed.getHelperCount());
for(int i=0;i< helperCount.intValue();i++){
LeafCouponEntity leafCoupenEntity=new LeafCouponEntity();
leafCoupenEntity.setParentCoupen(coupenEntity);
leafCoupenEntity.setSeed(helpOpenCoupenSeed);
leafCoupenEntity.setAmount(amountPerChildCoupne);
leafCoupenEntity.setCoupenID(generateCoupenID());
newCreatedCoupens.add(leafCoupenEntity);
}
};
break;
}
default:{
break;
}
}
CoupenContext<LeafCouponEntity,HelpOpenCouponSeed> newContext= new CoupenContext<LeafCouponEntity,HelpOpenCouponSeed>();
newContext.setCoupens(newCreatedCoupens);
newContext.setSeed(helpOpenCoupenSeed);
return newContext;
}
/** 计算每个红包的金额
* @param totalAmount
* @param divideCount
* @return
*/
private BigDecimal amountPerCoupen(BigDecimal totalAmount,Integer divideCount){
return totalAmount.divide(new BigDecimal(divideCount),3,BigDecimal.ROUND_HALF_UP);
}
@Override
public String distributeName() {
return STRATEGY_NAME;
}
private String generateCoupenID(){
return Utils.getRandomForDate(STRATEGY_NAME);
}
}
package com.zhaoonline.coupon.generator.distribute;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.coupon.bean.CoupenContext;
import org.junit.Test;
import org.junit.Assert;
import java.math.BigDecimal;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 11:15<br/>
* Description:please descript you class
*/
public class TestAverageStrategy {
AverageStrategy strategy = new AverageStrategy();
@Test
public void testDistributeNullSeed() {
CommonCouponSeed seed =null;
CoupenContext context = strategy.distribute(seed);
Assert.assertNull(context.getSeed());
}
@Test
public void testDistributeSeed() {
Integer expectCoupenCount=new Integer(10);
BigDecimal totalAmount= new BigDecimal(8880);
CommonCouponSeed seed = new CommonCouponSeed();
seed.setTotalAmount(totalAmount);
seed.setCoupenCount(expectCoupenCount);
CoupenContext<CommonCouponEntity,CommonCouponSeed> context = strategy.distribute(seed);
Assert.assertEquals(expectCoupenCount.intValue(), context.getCoupens().size());
Assert.assertEquals(strategy.amountPerCoupen(seed), context.getCoupens().get(0).getAmount());
}
}
package com.zhaoonline.coupon.generator.distribute;
import com.zhaoonline.coupon.bean.HelpOpenCouponSeed;
import com.zhaoonline.coupon.bean.LeafCouponEntity;
import com.zhaoonline.coupon.bean.CoupenContext;
import org.junit.Assert;
import org.junit.Test;
import java.math.BigDecimal;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 13:30<br/>
* Description:please descript you class
*/
public class TestItemAverageStrategy {
LeafAverageStrategy strategy = new LeafAverageStrategy();
@Test
public void testDistribute(){
HelpOpenCouponSeed helpOpenSeed =new HelpOpenCouponSeed();
Integer helperCount=new Integer(20);
helpOpenSeed.setHelperCount(helperCount);
Integer expectCoupenCount=new Integer(10);
BigDecimal totalAmount= new BigDecimal(8880);
helpOpenSeed.setTotalAmount(totalAmount);
helpOpenSeed.setCoupenCount(expectCoupenCount);
CoupenContext<LeafCouponEntity,HelpOpenCouponSeed> context = strategy.distribute(helpOpenSeed);
Assert.assertEquals(helperCount*expectCoupenCount, context.getCoupens().size());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/../coupen-processor/target/classes" />
<output-test url="file://$MODULE_DIR$/../coupen-processor/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="coupon-core" />
<orderEntry type="module" module-name="coupon-dispatcher-api" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>com.zhaoonline.coupen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>coupen-processor</artifactId>
<dependencies>
<dependency>
<groupId>com.zhaoonline.coupen</groupId>
<artifactId>coupen-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.zhaoonline.coupen</groupId>
<artifactId>coupen-dispatcher-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.coupon.bean.OwnerUser;
import com.zhaoonline.coupon.cache.RandomCache;
import com.zhaoonline.coupon.dispatcher.CoupenDispatchHandler;
import com.zhaoonline.coupon.dispatcher.UserCoupenMappingHandler;
import com.zhaoonline.coupon.lifecycle.LifeCycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 15:19<br/>
* Description:活动处理器,该处理器的作用,是处理通过活动的入口进来领取红包。
*/
public class ActivityHandler {
private Logger logger= LoggerFactory.getLogger(ActivityHandler.class);
private CoupenDispatchHandler coupenDispatcher = null;
private UserCoupenMappingHandler userCoupenMappingHandler= null;
private LifeCycle lifeCycle = new LifeCycle();
//保存有seed的缓存
private RandomCache<String,CommonCouponSeed> seedRandomCache=new RandomCache<String,CommonCouponSeed>();
private RandomCache<String,RandomCache<String,CommonCouponEntity>> seedAndCoupenRandomCache=new RandomCache<String,RandomCache<String,CommonCouponEntity>>();
@Autowired
public ActivityHandler(CoupenDispatchHandler coupenDispatcher,UserCoupenMappingHandler userCoupenMappingHandler){
this.coupenDispatcher = coupenDispatcher;
this.userCoupenMappingHandler = userCoupenMappingHandler;
lifeCycle.markStart();
}
/**
* @param activity
* @param user 点击活动入口的用户信息。领取红包,对于同一个用户。不可以重复获取
* @return
*/
public CommonCouponEntity processRequest(Activity activity, OwnerUser user){
warmCache(activity);
CommonCouponEntity mappedCoupenEntity = null;
//首先会随机从获取一个seedID,然后获取seedID对应其中一个coupenEntity,如果仍然无法获得未分配的红包。那么就尝试去其他CounpenSeed。
while(ObjectUtils.isEmpty(mappedCoupenEntity)) {
if(seedRandomCache.isEmpty()){
return null;
}
mappedCoupenEntity = tryDrawCoupen(seedRandomCache,seedAndCoupenRandomCache,user);
}
return mappedCoupenEntity;
}
private void warmCache(Activity activity) {
//如果标记了,不需要进行缓存重置
if(lifeCycle.checkNeedReload()){
seedRandomCache.clear();
seedAndCoupenRandomCache.clear();
}
if(seedRandomCache.isEmpty()){
boolean coupenSeedWarmResult= warmCommonSeed(activity);
}
if(seedAndCoupenRandomCache.isEmpty()){
boolean coupenEntityWarmResult=warmSeedAndCoupenRandmon(seedRandomCache,seedAndCoupenRandomCache);
}
}
/**尝试获取一个红包
* @param seedCache
* @param seedAndCoupenCache
* @param user
* @return
*/
private CommonCouponEntity tryDrawCoupen(RandomCache<String,CommonCouponSeed> seedCache, RandomCache<String,RandomCache<String,CommonCouponEntity>> seedAndCoupenCache, OwnerUser user) {
String randomSeedID=seedCache.randomKey();
CommonCouponSeed seed=seedCache.getCache(randomSeedID);
if(ObjectUtils.isEmpty(seed)){
return null;
}
RandomCache<String,CommonCouponEntity> coupenCacheOfSeed= seedAndCoupenCache.getCache(seed.getSeedID());
CommonCouponEntity unmappedCoupenEntity=null;
CommonCouponEntity mappedCoupenEntity=null;
while(ObjectUtils.isEmpty(mappedCoupenEntity)){
unmappedCoupenEntity =randomGetCoupenFromCache(coupenCacheOfSeed);
//如果最终cache里面的都coupenEntity都为空,那么则跳出循环。同时删除seedAndCoupenRandomCache中的CacheSeed
if(ObjectUtils.isEmpty(unmappedCoupenEntity)){
seedAndCoupenCache.remove(randomSeedID);
break;
}
//若是该Coupen已经被领取了。直接删除缓存,然后直接返回
if(!ObjectUtils.isEmpty(unmappedCoupenEntity.getOwnerUser())){
coupenCacheOfSeed.remove(unmappedCoupenEntity.getCoupenID());
break;
}
//这一步主要是将coupen和用户进行关系映射
mappedCoupenEntity=userCoupenMappingHandler.mappingCoupen2User(unmappedCoupenEntity,user);
//都需要将已经处理过的entity从缓存中删除
coupenCacheOfSeed.remove(unmappedCoupenEntity.getCoupenID());
}
if(ObjectUtils.isEmpty(unmappedCoupenEntity)){
seedCache.remove(randomSeedID);
}
return mappedCoupenEntity;
}
private boolean warmSeedAndCoupenRandmon(RandomCache<String, CommonCouponSeed> seedRandomCache, RandomCache<String,RandomCache<String,CommonCouponEntity>> cacheResult) {
List<String> keys=seedRandomCache.allKeys();
if(ObjectUtils.isEmpty(keys)){
return false;
}
for(String seedID:keys){
CommonCouponSeed seed=seedRandomCache.getCache(seedID);
List<CommonCouponEntity> allCoupenOfSeed= coupenDispatcher.dispacthCoupenEntityUsingSeed(seed);
if(ObjectUtils.isEmpty(allCoupenOfSeed)){
continue;
}
RandomCache<String,CommonCouponEntity> coupenCache =new RandomCache<String,CommonCouponEntity>();
for(CommonCouponEntity counpen:allCoupenOfSeed){
coupenCache.put(counpen.getCoupenID(),counpen);
}
cacheResult.put(seed.getSeedID(),coupenCache);
}
return true;
}
private CommonCouponEntity randomGetCoupenFromCache(RandomCache<String,CommonCouponEntity> coupenCacheOfSeed){
//随机获取一个红包ID
String coupenEntityID=coupenCacheOfSeed.randomKey();
CommonCouponEntity coupenEntity=coupenCacheOfSeed.getCache(coupenEntityID);
return coupenEntity;
}
private boolean warmCommonSeed(Activity activity) {
List<CommonCouponSeed> seedList = coupenDispatcher.dispatchCoupenSeedUsingActivity(activity);
if (!ObjectUtils.isEmpty(seedList)){
for (CommonCouponSeed seed : seedList) {
seedRandomCache.put(seed.getSeedID(), seed);
}
return true;
}
return false;
}
public LifeCycle getLifeCycle() {
return lifeCycle;
}
}
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.coupon.bean.OwnerUser;
import com.zhaoonline.coupon.dispatcher.CoupenDispatchHandler;
import com.zhaoonline.coupon.dispatcher.UserCoupenMappingHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/15<br/>
* Time: 14:30<br/>
* Description:红包处理器,该处理器的作用,是处理分享红包
* 帮拆的用户。首先是自己获取一个红包。同时会帮拆好友进行技术
*/
public class CoupenHelpOpenHandler {
private CoupenDispatchHandler coupenDispatcher = null;
private UserCoupenMappingHandler userCoupenMappingHandler= null;
ActivityHandler activityHandler =null;
@Autowired
public CoupenHelpOpenHandler(CoupenDispatchHandler coupenDispatcher, UserCoupenMappingHandler userCoupenMappingHandler){
this.coupenDispatcher = coupenDispatcher;
this.userCoupenMappingHandler = userCoupenMappingHandler;
activityHandler = new ActivityHandler(coupenDispatcher,userCoupenMappingHandler);
}
/**
* @param coupenEntity
* @param helper 帮拆好友的信息
* @return
*/
public CommonCouponEntity processRequest(CommonCouponEntity coupenEntity, OwnerUser helper){
CommonCouponSeed seed = coupenEntity.getSeed();
if(ObjectUtils.isEmpty(seed)){
return null;
}
//帮拆的朋友,自己获得一个红包。
CommonCouponEntity coupenOftheHelper=activityHandler.processRequest(seed.getActivity(),helper);
//记录帮拆信息。。。
boolean helpOpenResult=this.userCoupenMappingHandler.recordHelpOpen(coupenEntity,helper);
return coupenOftheHelper;
}
}
package com.zhaoonline.coupon.handler;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/17<br/>
* Time: 10:40<br/>
* Description:配置。每个业务、或者活动的DrawConfig不一样。我们这里只对一些基本进行设置
*
*/
public class DrawConfig {
//重复领取的次数
private int repeatDrawCount=1;
public int getRepeatDrawCount() {
return repeatDrawCount;
}
public void setRepeatDrawCount(int repeatDrawCount) {
this.repeatDrawCount = repeatDrawCount;
}
//每个帮拆好友的帮拆次数
private int helpOpenCountPerUser=1;
public int getHelpOpenCountPerUser() {
return helpOpenCountPerUser;
}
public void setHelpOpenCountPerUser(int helpOpenCountPerUser) {
this.helpOpenCountPerUser = helpOpenCountPerUser;
}
}
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.OwnerUser;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/17<br/>
* Time: 10:39<br/>
* Description:领取上下文
*/
public class DrawContext {
//领取人
private OwnerUser drawOwner;
//领取的相关设定.给予默认配置
private DrawConfig config=new DrawConfig();
public DrawConfig getConfig() {
return config;
}
public void setConfig(DrawConfig config) {
this.config = config;
}
public OwnerUser getDrawOwner() {
return drawOwner;
}
public void setDrawOwner(OwnerUser drawOwner) {
this.drawOwner = drawOwner;
}
}
package com.zhaoonline.coupon.handler;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/17<br/>
* Time: 11:12<br/>
* Description:处理器的分配器
*/
public class HandlerDispatcher {
}
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.coupon.bean.LeafCouponEntity;
import com.zhaoonline.coupon.bean.OwnerUser;
import com.zhaoonline.coupon.cache.RandomCache;
import com.zhaoonline.coupon.dispatcher.CoupenDispatchHandler;
import com.zhaoonline.coupon.dispatcher.UserCoupenMappingHandler;
import com.zhaoonline.coupon.lifecycle.LifeCycle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 13:57<br/>
* Description:该类主要服务于用户投资币。适用于即拆即用的帮拆红包。由于帮拆的好友,一个帮拆好友可以帮三个好友拆。
*/
public class LeafCoupenHelpOpenHandler {
private CoupenDispatchHandler coupenDispatcher = null;
private UserCoupenMappingHandler userCoupenMappingHandler= null;
private ActivityHandler activityHandler =null;
private LifeCycle lifeCycle = new LifeCycle();
private RandomCache<String,RandomCache<String,LeafCouponEntity>> coupen2LeafCoupenCache=new RandomCache<String,RandomCache<String,LeafCouponEntity>>();
@Autowired
public LeafCoupenHelpOpenHandler(CoupenDispatchHandler coupenDispatcher, UserCoupenMappingHandler userCoupenMappingHandler){
this.coupenDispatcher = coupenDispatcher;
this.userCoupenMappingHandler = userCoupenMappingHandler;
activityHandler = new ActivityHandler(coupenDispatcher,userCoupenMappingHandler);
lifeCycle.markStart();
}
/**
* 要对好友的帮拆次数进行判断
* @param coupenEntity
* @param helper 帮拆好友的信息.
* @return
*/
public CommonCouponEntity processRequest(CommonCouponEntity coupenEntity, OwnerUser helper){
CommonCouponSeed seed = coupenEntity.getSeed();
if(ObjectUtils.isEmpty(seed)){
return null;
}
warmCache(coupenEntity);
//帮拆的朋友,自己获得一个红包。
CommonCouponEntity coupenOftheHelper=activityHandler.processRequest(seed.getActivity(),helper);
//根据coupenEntity实体获取该coupen对应的叶子CoupenEntity
RandomCache<String,LeafCouponEntity> leafCouppenEntityCache=coupen2LeafCoupenCache.getCache(coupenEntity.getCoupenID());
if(ObjectUtils.isEmpty(leafCouppenEntityCache)){
getOrcacheLeafCounpens(coupenEntity, leafCouppenEntityCache);
}
//分配一个叶子CoupenEntity
CommonCouponEntity mappedCoupenEntity = dispacthOneLeafCoupen(coupenEntity, leafCouppenEntityCache);
if(!ObjectUtils.isEmpty(mappedCoupenEntity)){
//记录帮拆信息。。。
boolean helpOpenResult=this.userCoupenMappingHandler.recordHelpOpen(mappedCoupenEntity,helper);
}
return coupenOftheHelper;
}
private boolean warmCache(CommonCouponEntity coupenEntity) {
//如果标记了,不需要进行缓存重置
if(lifeCycle.checkNeedReload()){
activityHandler.getLifeCycle().markNeedReload();
coupen2LeafCoupenCache.clear();
}
return true;
}
private void getOrcacheLeafCounpens(CommonCouponEntity coupenEntity, RandomCache<String, LeafCouponEntity> leafCouppenEntityCache) {
List<CommonCouponEntity> leafCoupens= coupenDispatcher.dispacthCoupenEntityUsingCoupen(coupenEntity);
for(CommonCouponEntity counpen:leafCoupens){
LeafCouponEntity leafCoupenEntity = new LeafCouponEntity();
leafCoupenEntity.setCoupenID(counpen.getCoupenID());
leafCoupenEntity.setParentCoupen(coupenEntity);
leafCoupenEntity.setAmount(counpen.getAmount());
leafCoupenEntity.setOwnerUser(counpen.getOwnerUser());
leafCoupenEntity.setSeed(counpen.getSeed());
leafCoupenEntity.setDistributeDate(counpen.getDistributeDate());
leafCouppenEntityCache.put(leafCoupenEntity.getCoupenID(),leafCoupenEntity);
}
}
private CommonCouponEntity dispacthOneLeafCoupen(CommonCouponEntity coupenEntity, RandomCache<String, LeafCouponEntity> leafCouppenEntityCache) {
OwnerUser owner = coupenEntity.getOwnerUser();
LeafCouponEntity unmappedLeafCoupenEntity=null;
CommonCouponEntity mappedCoupenEntity=null;
while(ObjectUtils.isEmpty(unmappedLeafCoupenEntity)){
unmappedLeafCoupenEntity=randomGetCoupenFromCache(leafCouppenEntityCache);
if(ObjectUtils.isEmpty(unmappedLeafCoupenEntity)){
leafCouppenEntityCache.remove(coupenEntity.getCoupenID());
break;
}
//若是该Coupen已经被领取了。直接删除缓存,然后直接返回
if(!ObjectUtils.isEmpty(unmappedLeafCoupenEntity.getOwnerUser())){
leafCouppenEntityCache.remove(unmappedLeafCoupenEntity.getCoupenID());
break;
}
//这一步主要是将coupen和用户进行关系映射
mappedCoupenEntity=userCoupenMappingHandler.mappingCoupen2User(unmappedLeafCoupenEntity,owner);
//都需要将已经处理过的entity从缓存中删除
leafCouppenEntityCache.remove(unmappedLeafCoupenEntity.getCoupenID());
}
return mappedCoupenEntity;
}
private LeafCouponEntity randomGetCoupenFromCache(RandomCache<String,LeafCouponEntity> coupenCacheOfSeed){
//随机获取一个红包ID
String coupenEntityID=coupenCacheOfSeed.randomKey();
LeafCouponEntity coupenEntity=coupenCacheOfSeed.getCache(coupenEntityID);
return coupenEntity;
}
}
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.dispatcher.UserCoupenMappingHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/17<br/>
* Time: 10:22<br/>
* Description:在处理红包之前。
*/
public class PreActivityHandler {
private UserCoupenMappingHandler userCoupenMappingHandler= null;
@Autowired
public PreActivityHandler(UserCoupenMappingHandler userCoupenMappingHandler){
this.userCoupenMappingHandler = userCoupenMappingHandler;
}
/**
* 这是是要对根据用户和Activity来判断
* @param activity
* @param context
* @return
*/
public boolean preProcessRequest(Activity activity,DrawContext context){
List<CommonCouponEntity> coupnesOfUserInOneActivity=this.userCoupenMappingHandler.getMappingOfUser(activity,context.getDrawOwner());
if(ObjectUtils.isEmpty(coupnesOfUserInOneActivity) || checkBeyondDrawLimit(context, coupnesOfUserInOneActivity)){
return true;
}
return false;
}
/**判断是否用户领取已经超出了限制次数。正常逻辑,每个用户在一个活动中只允许领取一个红包
* @param context
* @param coupnesOfUserInOneActivity
* @return
*/
private boolean checkBeyondDrawLimit(DrawContext context, List<CommonCouponEntity> coupnesOfUserInOneActivity) {
return coupnesOfUserInOneActivity.size() <context.getConfig().getRepeatDrawCount();
}
}
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.dispatcher.UserCoupenMappingHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/17<br/>
* Time: 11:04<br/>
* Description:please descript you class
*/
public class PreCoupenHelpOpenHandler {
private UserCoupenMappingHandler userCoupenMappingHandler= null;
@Autowired
public PreCoupenHelpOpenHandler(UserCoupenMappingHandler userCoupenMappingHandler){
this.userCoupenMappingHandler = userCoupenMappingHandler;
}
/**
* 这是是要对根据用户和Activity来判断
* @param coupenEntity
* @param context
* @return
*/
public boolean preProcessRequest(CommonCouponEntity coupenEntity, DrawContext context){
List<CommonCouponEntity> coupnesOfUserInOneActivity=this.userCoupenMappingHandler.getHelpOpenCoupenOfUser(coupenEntity,context.getDrawOwner());
if(ObjectUtils.isEmpty(coupnesOfUserInOneActivity) || checkBeyondhelpOpenLimit(context, coupnesOfUserInOneActivity)){
return true;
}
return false;
}
private boolean checkBeyondhelpOpenLimit(DrawContext context, List<CommonCouponEntity> coupnesOfUserInOneActivity) {
return coupnesOfUserInOneActivity.size() <context.getConfig().getHelpOpenCountPerUser();
}
}
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.Activity;
import com.zhaoonline.coupon.bean.CommonCouponEntity;
import com.zhaoonline.coupon.bean.CommonCouponSeed;
import com.zhaoonline.coupon.bean.OwnerUser;
import com.zhaoonline.coupon.dispatcher.CoupenDispatchHandler;
import com.zhaoonline.coupon.dispatcher.UserCoupenMappingHandler;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 11:18<br/>
* Description:please descript you class
*/
@RunWith(MockitoJUnitRunner.class)
public class TestActivityHandler {
private CoupenDispatchHandler coupenDispatcher = Mockito.mock(CoupenDispatchHandler.class);
private UserCoupenMappingHandler userCoupenMappingHandler= Mockito.mock(UserCoupenMappingHandler.class);
/**
* 同一个用户在同一个Activity中只允许抢一个红包.
* 一个CoupenSeed、2个CoupenEntity
*/
@Test
public void testSameUserOnlyGetOneCoupenIntheSameActivity(){
Activity testActivity= new Activity();
testActivity.setActivityID(1);
CommonCouponSeed seed =new CommonCouponSeed();
seed.setSeedID("testSeedID123456");
seed.setActivity(testActivity);
List<CommonCouponSeed> mockedSeedList=new ArrayList<CommonCouponSeed>();
mockedSeedList.add(seed);
CommonCouponEntity coupenEntity=new CommonCouponEntity();
coupenEntity.setSeed(seed);
coupenEntity.setCoupenID("testCoupenID1234556");
coupenEntity.setAmount(new BigDecimal(880));
CommonCouponEntity coupenEntity2=new CommonCouponEntity();
coupenEntity2.setSeed(seed);
coupenEntity2.setCoupenID("testCoupenID1234552");
coupenEntity2.setAmount(new BigDecimal(880));
List<CommonCouponEntity> mockCoupenEntityList=new ArrayList<CommonCouponEntity>();
mockCoupenEntityList.add(coupenEntity);
mockCoupenEntityList.add(coupenEntity2);
Mockito.when(coupenDispatcher.dispacthCoupenEntityUsingSeed(Mockito.any(CommonCouponSeed.class))).thenReturn(mockCoupenEntityList);
Mockito.when(coupenDispatcher.dispatchCoupenSeedUsingActivity(Mockito.any(Activity.class))).thenReturn(mockedSeedList);
Mockito.when(userCoupenMappingHandler.mappingCoupen2User(Mockito.any(CommonCouponEntity.class),Mockito.any(OwnerUser.class)))
.then(new Answer<CommonCouponEntity>() {
int invokeCount=0;
@Override
public CommonCouponEntity answer(InvocationOnMock invocation) throws Throwable {
//如果invoke>1 调用多次,表示对于同一个用户在同一个活动中进行了多次领取。
if(invokeCount>=1){
return null;
}
invokeCount=invokeCount+1;
Object[] args=invocation.getArguments();
CommonCouponEntity coupen= (CommonCouponEntity) args[0];
OwnerUser owner= (OwnerUser) args[1];
coupen.setOwnerUser(owner);
return coupen;
}
});
OwnerUser owner=new OwnerUser();
owner.setOwnerUserID("testOwner1");
ActivityHandler activityHandler = new ActivityHandler(coupenDispatcher,userCoupenMappingHandler);
CommonCouponEntity coupenOfUserFirstDraw=activityHandler.processRequest(testActivity,owner);
Assert.assertNotNull(coupenOfUserFirstDraw);
Assert.assertEquals("testOwner1",coupenOfUserFirstDraw.getOwnerUser().getOwnerUserID());
CommonCouponEntity coupenOfUserSecondDraw=activityHandler.processRequest(testActivity,owner);
Assert.assertNull(coupenOfUserSecondDraw);
CommonCouponEntity coupenOfUserThirdDraw=activityHandler.processRequest(testActivity,owner);
Assert.assertNull(coupenOfUserThirdDraw);
}
/**
*一个Activity
* 2个CoupenSeed
* 每个CoupenSeed有两个CoupenEntity
*/
@Test
public void testNoEnoughCoupen(){
Activity testActivity= new Activity();
testActivity.setActivityID(1);
String seedID1="testSeedID123456";
String seedID2="testSeedID123457";
CommonCouponSeed seed =new CommonCouponSeed();
seed.setSeedID(seedID1);
seed.setActivity(testActivity);
CommonCouponSeed seed2 =new CommonCouponSeed();
seed2.setSeedID(seedID2);
seed2.setActivity(testActivity);
List<CommonCouponSeed> mockedSeedList=new ArrayList<CommonCouponSeed>();
mockedSeedList.add(seed);
mockedSeedList.add(seed2);
CommonCouponEntity coupenEntity1=new CommonCouponEntity();
coupenEntity1.setSeed(seed);
coupenEntity1.setCoupenID("testCoupenID1234551");
coupenEntity1.setAmount(new BigDecimal(880));
CommonCouponEntity coupenEntity2=new CommonCouponEntity();
coupenEntity2.setSeed(seed);
coupenEntity2.setCoupenID("testCoupenID1234552");
coupenEntity2.setAmount(new BigDecimal(880));
CommonCouponEntity coupenEntity3=new CommonCouponEntity();
coupenEntity3.setSeed(seed2);
coupenEntity3.setCoupenID("testCoupenID1234553");
coupenEntity3.setAmount(new BigDecimal(580));
CommonCouponEntity coupenEntity4=new CommonCouponEntity();
coupenEntity4.setSeed(seed2);
coupenEntity4.setCoupenID("testCoupenID1234554");
coupenEntity4.setAmount(new BigDecimal(580));
List<CommonCouponEntity> mockCoupenEntityList=new ArrayList<CommonCouponEntity>();
mockCoupenEntityList.add(coupenEntity1);
mockCoupenEntityList.add(coupenEntity2);
List<CommonCouponEntity> mockCoupenEntityList2=new ArrayList<CommonCouponEntity>();
mockCoupenEntityList2.add(coupenEntity3);
mockCoupenEntityList2.add(coupenEntity4);
Map<String,List<CommonCouponEntity>> seedCoupenMap=new HashMap<String,List<CommonCouponEntity>>();
seedCoupenMap.put(seedID1,mockCoupenEntityList);
seedCoupenMap.put(seedID2,mockCoupenEntityList2);
//
Mockito.when(coupenDispatcher.dispacthCoupenEntityUsingSeed(Mockito.any(CommonCouponSeed.class)))
.then(new Answer<List<CommonCouponEntity>>() {
Map<String,Integer> invokerCountMap=new HashMap<String, Integer>();
@Override
public List<CommonCouponEntity> answer(InvocationOnMock invocation) throws Throwable {
Object[] args=invocation.getArguments();
CommonCouponSeed coupenSeed= (CommonCouponSeed) args[0];
List<CommonCouponEntity> mockCoupenEntityList = seedCoupenMap.get(coupenSeed.getSeedID());
Integer invokerCount= invokerCountMap.get(coupenSeed.getSeedID());
if(invokerCount == null){
invokerCountMap.put(coupenSeed.getSeedID(),new Integer(0));
}else{
if(invokerCount >=1){
for(CommonCouponEntity coupen :mockCoupenEntityList){
coupen.setOwnerUser(new OwnerUser());
}
}
invokerCountMap.put(coupenSeed.getSeedID(),new Integer(invokerCount.intValue()+1));
}
return mockCoupenEntityList;
}
});
Mockito.when(coupenDispatcher.dispatchCoupenSeedUsingActivity(Mockito.any(Activity.class))).thenReturn(mockedSeedList);
Mockito.when(userCoupenMappingHandler.mappingCoupen2User(Mockito.any(CommonCouponEntity.class),Mockito.any(OwnerUser.class)))
.then(new Answer<CommonCouponEntity>() {
@Override
public CommonCouponEntity answer(InvocationOnMock invocation) throws Throwable {
Object[] args=invocation.getArguments();
CommonCouponEntity coupen= (CommonCouponEntity) args[0];
OwnerUser owner= (OwnerUser) args[1];
coupen.setOwnerUser(owner);
return coupen;
}
});
ActivityHandler activityHandler = new ActivityHandler(coupenDispatcher,userCoupenMappingHandler);
int userCount=4;
for(int i=0;i<userCount;i++){
OwnerUser owner=new OwnerUser();
owner.setOwnerUserID("testOwner"+i);
CommonCouponEntity coupenOfUserFirstDraw=activityHandler.processRequest(testActivity,owner);
Assert.assertNotNull(coupenOfUserFirstDraw);
Assert.assertEquals(owner.getOwnerUserID(),coupenOfUserFirstDraw.getOwnerUser().getOwnerUserID());
}
//更多的用来来抢有限的红包
for(int i=5;i<10;i++){
OwnerUser owner=new OwnerUser();
owner.setOwnerUserID("testOwner"+i);
CommonCouponEntity coupenOfUserFirstDraw=activityHandler.processRequest(testActivity,owner);
Assert.assertNull(coupenOfUserFirstDraw);
}
}
}
package com.zhaoonline.coupon.handler;
import com.zhaoonline.coupon.bean.*;
import com.zhaoonline.coupon.dispatcher.CoupenDispatchHandler;
import com.zhaoonline.coupon.dispatcher.UserCoupenMappingHandler;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ZhaoOnline<br/>
* User: yangyoupeng<br/>
* Date: 2016/12/16<br/>
* Time: 11:19<br/>
* Description:please descript you class
*/
@RunWith(MockitoJUnitRunner.class)
public class TestCoupenHelpOpenHandler {
private CoupenDispatchHandler coupenDispatcher = Mockito.mock(CoupenDispatchHandler.class);
private UserCoupenMappingHandler userCoupenMappingHandler= Mockito.mock(UserCoupenMappingHandler.class);
/**
*
*/
@Test
public void testProcessRequest(){
HelpOpenCouponSeed seed =new HelpOpenCouponSeed();
seed.setSeedID("testSeedID123456");
List<CommonCouponSeed> mockedSeedList=new ArrayList<CommonCouponSeed>();
mockedSeedList.add(seed);
OwnerUser owner=new OwnerUser();
owner.setOwnerUserID("testOwner1");
CommonCouponEntity coupenEntity=new CommonCouponEntity();
coupenEntity.setOwnerUser(owner);
coupenEntity.setCoupenID("testCoupenID1234556");
coupenEntity.setAmount(new BigDecimal(880));
coupenEntity.setSeed(seed);
OwnerUser owner2=new OwnerUser();
owner2.setOwnerUserID("testOwner2");
CommonCouponEntity coupenEntity2=new CommonCouponEntity();
coupenEntity2.setCoupenID("testCoupenID1234552");
coupenEntity2.setAmount(new BigDecimal(880));
coupenEntity2.setSeed(seed);
OwnerUser helper=new OwnerUser();
helper.setOwnerUserID("testHelper1");
List<CommonCouponEntity> mockCoupenEntityList=new ArrayList<CommonCouponEntity>();
mockCoupenEntityList.add(coupenEntity);
mockCoupenEntityList.add(coupenEntity2);
Mockito.when(coupenDispatcher.dispacthCoupenEntityUsingSeed(Mockito.any(CommonCouponSeed.class))).thenReturn(mockCoupenEntityList);
Mockito.when(coupenDispatcher.dispatchCoupenSeedUsingActivity(Mockito.any(Activity.class))).thenReturn(mockedSeedList);
Mockito.when(userCoupenMappingHandler.mappingCoupen2User(Mockito.any(CommonCouponEntity.class),Mockito.any(OwnerUser.class)))
.then(new Answer<CommonCouponEntity>() {
@Override
public CommonCouponEntity answer(InvocationOnMock invocation) throws Throwable {
Object[] args=invocation.getArguments();
CommonCouponEntity coupen= (CommonCouponEntity) args[0];
OwnerUser owner= (OwnerUser) args[1];
coupen.setOwnerUser(owner);
return coupen;
}
});
CoupenHelpOpenHandler helpOpenHandler = new CoupenHelpOpenHandler(coupenDispatcher,userCoupenMappingHandler);
CommonCouponEntity helperGetNewCoupenAfterHelpOpen=helpOpenHandler.processRequest(coupenEntity,helper);
OwnerUser ownerAfterHelpOpen = helperGetNewCoupenAfterHelpOpen.getOwnerUser();
Assert.assertEquals("testHelper1",ownerAfterHelpOpen.getOwnerUserID());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zhaoonline.coupon</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.1.7</logback.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
<version>0.5.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>com.zhaoonline</groupId>
<artifactId>microservice-redis</artifactId>
<version>1.0.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.zhaoonline</groupId>
<artifactId>alpaca-config-zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version><!--$NO-MVN-MAN-VER$ -->
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<modules>
<module>coupon-generator</module>
<module>coupon-dispatcher</module>
<module>coupon-processor</module>
<module>coupon-core</module>
<module>coupon-dispatcher-api</module>
</modules>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file