客户需求之控制软件使用有效期

1、需求分析

客户提了需求,希望能够限制软件使用的时长,具体实现细节没有做要求。 因为客户要将软件卖给他的客户,希望能够按照使用时长来收费,类似很多软件的会员机制,充值1个月,1年等等。 但我们的软件使用有一个前提,不会用到外网,使用的是局域网环境。所以,不会用到公司的云数据库。

2、实现方案

出于时间的考虑,采取了登录页面限制登录的方案来控制软件的使用时间。

  • 功能细节:进入登陆页面后,会判断当前设备的软件是否激活;如果没有激活,则弹出一个输入框,要求用户输入激活码,并且显示了当前设备的cpu序列号,激活成功后才能正常登录;如果已经激活,则不会显示激活码输入框,可以正常登录,并且在软件下方会显示软件的有效期。
  • 激活码的生成:激活码由两部分组成,cpu序列号 + 有效时间。 cpu序列号基本上是唯一的,可以作为每一台设备的唯一标识,因此在生成激活码时,需要用户提供当前设备的cpu序列号。

3、页面效果

  • 软件未激活

进入登录页面,如果软件未激活,则弹出输入框,并且给出当前电脑的cpu序列号。用户无法点击取消按钮,只有输入正确的激活码,并且点击以后弹框才会消失。

b45939af42240be0068a1d25bfe9b60f.png

b1a5ccc8301e9f5f6e82d0cc47b6c630.png

4、代码实现

  • 登录页jsp代码
(async function() {
  const response = await fetch('active/code/get');
  const code = await fetch('active/code/cpu');
  const codeString = (await code.text()).toString();
  const data = (await response.text()).toString();
  // 获取a标签元素
  var aTag = document.querySelector('a[href="https://beian.miit.gov.cn/"]');
  // 判断是否弹出激活框
  if (response.ok) {
      if (data === 'fail') {
          aTag.innerHTML = 'HZR-2023-3.0  软件有效期: 暂未激活';
          let userInput;
          while (true) {
              userInput = prompt("本机序列号是:" +codeString+"\n"+
                  "请提供序列号,联系管理员获取激活码激活", codeString);
              if (userInput == null) {
                  continue;
              }

              try {
                  const response = await $.ajax({
                      url: "active/code/check",
                      method: "GET",
                      data: {"code": userInput}
                  });

                  if (response === 'success') {
                      alert("激活成功!");
                      aTag.innerHTML = 'HZR-2023-3.0';
                      break;
                  } else {
                      alert("激活码错误或过期,请重新输入!");
                  }
              } catch (err) {
                  console.error(err);
                  alert("网络请求失败,请重试!");
              }
          }
      }
      else {
          aTag.innerHTML = 'HZR-2023-3.0  软件有效期: '+data;
      }
  } else {
  }
})();
  • 后台java逻辑代码

查询是否激活

public String get() throws SocketException {
    String cpuProcessorId = ServerAddressUtils.getCPUProcessorId();
    // 如果一台设备用了多个
    SoftwareActive softwareActive = activeMapper.selectByCPU(cpuProcessorId);
    if (softwareActive == null) {
        return "fail";
    }
    // 验证有效期
    long limitTimeMillis = 0;
    try {
        limitTimeMillis = JsonUtiles.JsonUtils.jsonToPojo(softwareActive.getTime(),Long.class);
    } catch (Exception e) {
        return "fail";
    }
    long currentTimeMillis = System.currentTimeMillis();

    if (currentTimeMillis >= limitTimeMillis) {
        // 删除该条记录, 避免影响重新激活
        activeMapper.deleteOneByCpu(cpuProcessorId);
        return "fail";
    }
    // 创建SimpleDateFormat对象用于格式化日期
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
    // 将毫秒值转换为指定格式的字符串
    String dateString = sdf.format(new Date(limitTimeMillis));
    return dateString;
}

输入激活码激活

public String test(String code) throws SocketException {
    if (code==null || code ==""){
        return "激活码不能为空";
    }
    // 1. 从数据库中查询激活码是否被使用
    SoftwareActive dbData = activeMapper.oneByActiveCode(code);
    if (dbData != null) {
        return "激活码已被使用";
    }
    // 2. 对激活码解码
    String decrypt = null;
    try {
        decrypt = AESUtils.Decrypt(code, "bslszmm,zyszcsz.");
    } catch (Exception e) {
        return "激活码不正确";
    }
    if(decrypt == null  || decrypt =="") {
        return "激活码不正确";
    }
    String[] split = decrypt.split(";"); // cup ; 时间
    long limitTimeMillis = JsonUtiles.JsonUtils.jsonToPojo(split[1],Long.class);
    long currentTimeMillis = System.currentTimeMillis();
    if (currentTimeMillis >= limitTimeMillis) {
        return "激活码已过期";
    }
    // 3.激活成功,将激活时间添加到数据库
//        String mac = getMac();
    // cup 和 code 编码, 到期时间
    activeMapper.insertOne(code,split[0],split[1]);
    return "success";
}

生成激活码工具方法

public static void main(String[] args) throws Exception {
    // 获取序列号
    String cpuProcessorId = "BFEBFBFF00906C1";
    // 获取当前时间的毫秒值
    long currentTimeMillis = System.currentTimeMillis();
    // 创建Calendar对象并设置时间为当前时间
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(currentTimeMillis);
    // 将时间加上3个月
    calendar.add(Calendar.MONTH, 3);// 3个月
    // 获取指定时间后的毫秒值
    long threeDaysLaterMillis = calendar.getTimeInMillis();
    // 拼接
    String code = cpuProcessorId + ";" + threeDaysLaterMillis;
    // 加密
    String decrypt = AESUtils.Encrypt(code, "bslszmm,zyszcsz.");
    System.out.println(decrypt);
}

获取本机cpu序列号

public static String getCPUProcessorId() {
    long start = System.currentTimeMillis();
    String serial = null;
    try {
       Process process = Runtime.getRuntime().exec(
               new String[] { "wmic", "cpu", "get", "ProcessorId" });
       process.getOutputStream().close();
       Scanner sc = new Scanner(process.getInputStream());
       String property = sc.next();
       serial = sc.next();
       System.out.println(property + ": " + serial);
       System.out.println("time:" + (System.currentTimeMillis() - start));
    } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
    }
    return serial;
}

5、后续改进

目前存在的问题是,激活码需要我们给客户生成。客户希望能够自己生成激活码,自己指定激活码的有效期,然后再给到他们的客户。

大概有两种思路,一种是将生成代码的工具放到我们的云网站上,客户登录云网站生成。二是,给用户写另外一个生成激活码的工具,单独生成。 目前考虑使用第二种方案。

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值