反射、自定义注解、集合应用、Java基础 动态抽奖程序


前言

无聊之余写了点东西~~~


一、这是个啥?

功能图哦~~
       这个程序可以自定义多个条件抽取对象,如果做成web程序那么只要需要保证保证对象的一致性,从数据库拿到数据,理论上可以实现高可用的配置点。代码方面我就不介绍了,一定涛意会哦~~

二、源代码

1.AnnotationParameter

package com.zyd.tools.userReward;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @description:
 * @projectName:MyTool
 * @see:com.zyd.tools.userReward
 * @author:无忧歌
 * @createTime:2021/2/5 20:33
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationParameter {
    String value() default "";
    boolean isRatio() default false;
}

2.Parameter

package com.zyd.tools.userReward;

import lombok.Data;


/**
 * @description:
 * @projectName:MyTool
 * @see:com.zyd.tools.userReward
 * @author:无忧歌
 * @createTime:2021/2/5 13:22
 */
@Data
public class Parameter {
    private int ratioNum;
    private double ratio;
    private String ratioName;
    @AnnotationParameter(value = "sex")
    private String sex;
    @AnnotationParameter(value = "参数1")
    private int num;

    public Parameter(int ratioNum, double ratio, String ratioName, String sex, int num) {
        this.ratioNum = ratioNum;
        this.ratio = ratio;
        this.ratioName = ratioName;
        this.sex = sex;
        this.num = num;
    }
}

3.UserReward(核心)

package com.zyd.tools.userreward;

import com.zyd.tools.custom.datautil.RandomData;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.SecureRandom;
import java.util.*;

/**
 * @description: 抽奖
 * 需要的外部参数:
 * 1、抽奖人数或者抽奖比例;
 * 2、一组待抽取的数据,使用List形式传入;
 * 3、特定类别抽奖(可选参数)
 * @projectName:MyTool
 * @see:com.zyd.tools.userreward;
 * @author:无忧歌
 * @createTime:2021/2/4 22:19
 */
public class UserReward {

    //待抽取的数据
    private final List<User> sourceList;
    //此次的主题
    private final String ThisName;
    //给出的所有数据
    private final Map<String, Object> objMap = new HashMap<>();
    //初始大小
    private final int sourceSize;

    /**
     * 实例化时载入此次总人数和此次的主题
     *
     * @param sourceList 总人数
     * @param ThisName   主题
     */
    public UserReward(List<User> sourceList, String ThisName) {
        this.ThisName = ThisName;
        this.sourceList = sourceList;
        this.sourceSize = sourceList.size();
    }

    /**
     * 程序入口
     *
     * @param parameter 此次的参数
     * @return
     */
    public Map<String, Object> run(Parameter parameter) {
        if (null == parameter) {
            //实际开发使用日志代替
            throw new RuntimeException("未传入参数数据!");
        }
        List<User> tempList = new ArrayList<>();
        this.objMap.clear();
        try {
            Map<Method, Object> map = getParameterMethods(parameter);
            tempList = getTempList(map);
        } catch (InvocationTargetException | IllegalAccessException | IntrospectionException e) {
            e.printStackTrace();
        }
        if (tempList.isEmpty()) {
            //实际开发使用日志代替
            throw new RuntimeException("没有符合条件的对象!");
        }

        List<User> data = getReward(parameter.getRatio(), tempList);
        this.sourceList.removeAll(data);
        Map<String, Object> map = new HashMap<>(this.objMap);
        map.put("obj", data);
        map.put("SourceSize", this.sourceList.size());
        map.put("SourceList", this.sourceList);
        map.put("ThisName", this.ThisName);
        return map;
    }


    /**
     * 获取相关参数抽奖,并在当前剩余总人数中移除抽中的对象
     * 预留重载的方法
     *
     * @param list      当前剩余总人数
     * @param parameter 相关参数
     * @return 抽取到的对象集合
     */
    private List<User> getReward(List<User> list, Parameter parameter) {
        List<User> code = getReward(parameter.getRatio(), list);
        this.sourceList.removeAll(code);
        return code;
    }


    /**
     * 在当前剩余对象中抽取
     *
     * @param ratio 个数 | 比例
     * @param users 当前剩余对象
     * @return 抽取到的对象集合
     */
    private List<User> getReward(double ratio, List<User> users) {
        int ratioTemp;
        if (ratio < 1 && ratio > 0) {
            ratioTemp = (int) (ratio * sourceSize);
        } else if (ratio > 1 && ratio < this.sourceList.size()) {
            ratioTemp = (int) ratio;
        } else {
            //实际开发使用日志代替
            throw new RuntimeException("ratioSize < 0 or ratioSize > SourceSize" +
                    "\n\tat message: 当前抽取比率不合法!");
        }
        if (users.size() < ratioTemp) {
            //实际开发使用日志代替
            throw new RuntimeException(String.format(
                    "SourceSize < DestSize\n\t" +
                            "at message: (\033[1;95m%s\033[0m)----->" +
                            "(\033[1;95m%s\033[0m)----->" +
                            "当前类别剩余个数为\033[1;95m%s\033[0m,不足以抽取\033[1;95m%s\033[0m个目标个数!",
                    this.ThisName, this.objMap.get("ratioName"), users.size(), ratioTemp));
        }
        SecureRandom secureRandom = new SecureRandom();
        List<User> list = new ArrayList<>();

        for (int i = 0; i < ratioTemp; i++) {
            int x = secureRandom.nextInt(users.size());
            User user = users.remove(x);
            list.add(user);
        }
        return list;
    }

    /**
     * @param map 目标方法与参数对接表
     * @return Destination User to List
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private List<User> getTempList(Map<Method, Object> map) throws InvocationTargetException, IllegalAccessException {
        List<List<User>> tempList = new ArrayList<>();
        int i = 1;
        for (Map.Entry<Method, Object> entry : map.entrySet()) {
            tempList.add(getRet(entry));
            if (i < tempList.size()) {
                tempList.get(0).retainAll(tempList.get(i++));
            }
        }
        return tempList.get(0);
    }

    /**
     * 筛选指定条件的对象
     *
     * @param entry 当前条件
     * @return This term User to List
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private List<User> getRet(Map.Entry<Method, Object> entry) throws InvocationTargetException, IllegalAccessException {
        List<User> list = new LinkedList<>();
        for (User user : this.sourceList) {
            //这里似乎有一个优化点,但是目前没想到
            if (entry.getKey().invoke(user).equals(entry.getValue())) {
                list.add(user);
            }
        }
        return !list.isEmpty() ? list : this.sourceList;
    }


    /**
     * 对接参数 User to Method  ==> Parameter to MethodValue
     *
     * @param parameter 参数对象
     * @return Map(User to Method, Parameter to MethodValue)
     * @throws IntrospectionException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private Map<Method, Object> getParameterMethods(Parameter parameter) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        Class<User> userClass = User.class;
        Class<Parameter> parameterClass = Parameter.class;
        Class<AnnotationParameter> annotation = AnnotationParameter.class;
        Field[] userFields = userClass.getDeclaredFields();
        Field[] parameterFields = parameterClass.getDeclaredFields();
        Map<Method, Object> map = new HashMap<>();
        for (Field p : parameterFields) {
            if (!p.isAnnotationPresent(annotation)) {
                PropertyDescriptor p_pd = new PropertyDescriptor(p.getName(), parameterClass);
                Object result = p_pd.getReadMethod().invoke(parameter);
                this.objMap.put(p.getName(), result);
            }
            for (Field u : userFields) {
                if ((u.isAnnotationPresent(annotation) && p.isAnnotationPresent(annotation))
                        && (u.getAnnotation(annotation).value().equals(p.getAnnotation(annotation).value()))) {
                    PropertyDescriptor u_pd = new PropertyDescriptor(u.getName(), userClass);
                    PropertyDescriptor p_pd = new PropertyDescriptor(p.getName(), parameterClass);
                    Object result = p_pd.getReadMethod().invoke(parameter);
                    map.put(u_pd.getReadMethod(), result);
                }
            }
        }
        return map;
    }

4.测试

其中RandomData工具请参考:数据自动生成工具类

@Test
    public void rewardTest() {
        List<User> users = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < 100; i++) {
            int x = random.nextInt(4);
            users.add(new User(RandomData.getRandomID(),
                    RandomData.getChineseName(),
                    RandomData.getSex(), x));
            if (i > 80) {
                users.get(i - 20).setSex("妖");
            }
        }
        Parameter parameter = new Parameter(1, 5, "第一次抽奖", "女", 3);
        Parameter parameter2 = new Parameter(2, 5, "第二次抽奖", "男", 2);
        Parameter parameter3 = new Parameter(3, 5, "第三次抽奖", "女", 2);
        UserReward uc = new UserReward(users, "测试抽奖!!!");
        long a = System.currentTimeMillis();
        Map<String, Object> map1 = uc.run(parameter);
        long b = System.currentTimeMillis();
        System.out.printf("%d2\n",(b - a)/1000);

        Map<String, Object> map2 = uc.run(parameter2);
        Map<String, Object> map3 = uc.run(parameter3);
        System.out.printf("%s----%s--%s--结果:\n%s\n", map1.get("ThisName"), map1.get("ratioName"), map1.get("SourceSize"), map1.get("obj"));
        System.out.printf("%s----%s--%s--结果:\n%s\n", map2.get("ThisName"), map2.get("ratioName"), map2.get("SourceSize"), map2.get("obj"));
        System.out.printf("%s----%s--%s--结果:\n%s\n", map3.get("ThisName"), map3.get("ratioName"), map3.get("SourceSize"), map3.get("obj"));
    }

5.结果

13933
02
测试抽奖!!!----第一次抽奖--95--结果:
[User(id=611615198302171020, name=焦新之, sex=, num=3), User(id=410426198302172997, name=路婕, sex=, num=3), User(id=310108198302179271, name=田雨珍, sex=, num=3), User(id=131223198302178601, name=卢悦, sex=, num=3), User(id=531220198302176358, name=叔孙凌玉, sex=, num=3)]
测试抽奖!!!----第二次抽奖--90--结果:
[User(id=310925198302176598, name=熊松, sex=, num=2), User(id=440225198302174704, name=谯阳煦, sex=, num=2), User(id=330924198302175765, name=娄东, sex=, num=2), User(id=511528198302176369, name=段干磊, sex=, num=2), User(id=821409198302173010, name=须永宁, sex=, num=2)]
测试抽奖!!!----第三次抽奖--85--结果:
[User(id=510801198302177121, name=惠采蝶, sex=, num=2), User(id=810118198302174278, name=麻寒竹, sex=, num=2), User(id=621408198302173349, name=纪婷, sex=, num=2), User(id=420727198302177512, name=苗访双, sex=, num=2), User(id=460325198302171038, name=揭馨, sex=, num=2)]

总结

啦啦啦,冲鸭~~

欢迎大家关注我的 CSDN 账号,如果觉得这篇文章不错的话,还请给这篇文章点赞哟!
今天的不开心就到此为止吧,明天又是光芒万丈的一天哦~~

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值