导言

不知道大家在网上购物的时候,有没有这样的念头,如果能把未付款的订单偷偷用一条SQL改成已付款,该多么美好啊。那么在实际开发过程中,我们应当如何保证数据库里的数据在保存后不会被偷偷更改?

大家好我是日暮与星辰之间,创作不易,如果觉得有用,求点赞,求收藏,求转发,谢谢。

理论

在介绍具体的内容之间,先介绍MD5算法,简单的来说,MD5能把任意大小、长度的数据转换成固定长度的一串字符,经常玩大型游戏的朋友应该都注意到过,各种补丁包、端游客户端之类的大型文件一般都附有一个MD5值,用于确保你下载文件的完整性。那么在这里,我们可以借鉴其思想,对订单的某些属性进行加密计算,得出来一个 MD5值一并保存在数据库当中。从数据库取出数据后第一时间进行校验,如果有异常更改,那么及时抛出异常进行人工处理。

实现

道理我都懂,但是我要如何做呢,别急,且听我一一道来。

这种需求听起来并不强绑定于某个具体的业务需求,这就要用到了我们熟悉的鼎鼎有名的AOP(面向切面编程)来实现。

首先定义四个类型的注解作为AOP的切入点。@Sign@Validate都是作用在方法层面的,分别用于对方法的入参进行加签和验证方法的返回值的签名。@SignField用于注解关键的不容篡改的字段。@ValidateField用于注解保存计算后得出的签名值。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sign {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SignField {
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidField {
}

以订单的实体为例 sn,amt,status,userId就是关键字段,绝不能允许有人在落单到数据库后对这些字段偷偷篡改。

public class Order {@SignFieldprivate String sn;@SignFieldprivate String amt;@SignFieldprivate int status;@SignFieldprivate int userId;@ValidFieldprivate String sign;
}

下面就到了重头戏的部分,如何通过AOP来进行实现。

1. 定义切入点

@Pointcut("execution(@com.example.demo.annotations.Sign * *(..))")
public void signPointCut() {}@Pointcut("execution(@com.example.demo.annotations.Validate * *(..))")
public void validatePointCut() {}

2.环绕切入点

@Around("signPointCut()")
public Object signAround(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs();for (Object o : args) {System.out.println(o);sign(o);}Object res = pjp.proceed(args);return res;
}@Around("validatePointCut()")
public Object validateAround(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs();Object res = pjp.proceed(args);valid(res);return res;
}

3. 签名的实现

1.获取需要签名字段

private Map<String, String> getSignMap(Object o) throws IllegalAccessException {Map<String, String> fieldNameToValue = new HashMap<>();for (Field f : o.getClass().getDeclaredFields()) {System.out.println(f.getName());for (Annotation annotation : f.getDeclaredAnnotations()) {if (annotation.annotationType().equals(SignField.class)) {String value = "";f.setAccessible(true);fieldNameToValue.put(f.getName(), f.get(o).toString());}}}return fieldNameToValue;
}

2.计算出签名值,这里在属性名和属性值以外加入了我的昵称以防止他人猜测,同时使用了自定义的分隔符来加强密码强度。

private String getSign(Map<String, String> fieldNameToValue) {List<String> names = new ArrayList<>(fieldNameToValue.keySet());StringBuilder sb = new StringBuilder();for (String name : names)sb.append(name).append("@").append(fieldNameToValue.get(name));System.out.println(sb.append("日暮与星辰之间").toString());String signValue = DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8));return signValue;
}
  1. 找到保存签名的字段

    private Field getValidateFiled(Object o) {for (Field f : o.getClass().getDeclaredFields()) {for (Annotation annotation : f.getDeclaredAnnotations()) {if (annotation.annotationType().equals(ValidField.class)) {return f;}}}return null;
    }
  2. 对保存签名的字段进行赋值
    public void sign(Object o) throws IllegalAccessException {Map<String, String> fieldNameToValue = getSignMap(o);if (fieldNameToValue.isEmpty()) {return;}Field validateField = getValidateFiled(o);if (validateField == null)return;String signValue = getSign(fieldNameToValue);validateField.setAccessible(true);validateField.set(o, signValue);
    }
  3. 对从数据库中取出的对象进行验证
    public void valid(Object o) throws IllegalAccessException {Map<String, String> fieldNameToValue = getSignMap(o);if (fieldNameToValue.isEmpty()) {return;}Field validateField = getValidateFiled(o);validateField.setAccessible(true);String signValue = getSign(fieldNameToValue);if (!Objects.equals(signValue, validateField.get(o))) {throw new RuntimeException("数据非法");}
    

}


## 使用示例
对将要保存到数据库的对象进行签名

@Sign public Order save( Order order){ orderList.add(order); return order; }

验证从数据库中取出的对象是否合理

@Validate public Order query(@ String sn){ return orderList.stream().filter(e -> e.getSn().equals(sn)).findFirst().orElse(null); }

```

本文由博客一文多发平台 OpenWrite 发布!

把数据库里的未付款订单改成已付款,会发生什么相关推荐

  1. Java 中Timer定时器设置订单提交后24小时未付款订单状态为已关闭。

    1. 简单的Timer定时器方法 public class CommTimer {/*** 设置指定24小时后执行*/public static void orderClose() {final Ti ...

  2. Access数据库id类型由自动编号改成数字类型后如何再从数字类型改成自动编号

    1.给数据库备份(如果你没有先备份的习惯,那就从现在起开始养成这个习惯) 2.打开数据库,发现原数据库表名为test.单击选定,然后点上面的"设计",将id字段的数据类型改为&qu ...

  3. matlab excel 新建sheet,MATLAB怎么在保存结果的EXCEL里面添加内容?比如把 'sheet1‘ 改成 ‘已知点’ ,在第一行加上 '已知点' ,'x', 'y' 等....

    优质解答 1.我觉得最简单的操作是,直接写入制定名字的工作表,然后手动删除sheet1,sheet2,sheet3这些不要的表格. 例如: YZD=rand(4,3); warning off MAT ...

  4. matlab将程序变量写入标题,如何该这段MATLAB程序(把一个常量改成变量)

    原题目是这样的: 在反应器中进行液相反应制备产物B,反应可在180~260℃的温度范围内进行,反应物X大量过剩,而C, D和E为副产物.各反应均为一级动力学关系:r=-kC,式中已知参数:k01=5. ...

  5. 未付款订单占用库存的MQ实现方案

    用户下完订单到支付完成期间,需要锁定库存防止超卖,如何不依赖数据库,实现较高负载呢? 常见的方案是频繁的读取数据库中的订单,统计总库存占用,检查是否付款超时.如果系统的负载量较高,这种方案很快将数据库 ...

  6. 淘宝怎么多个订单一起付款_淘宝未付款订单如何催付?

    淘宝未付款订单如何催付? 很多人只认为运营就是技巧,其实客服也是需要技巧的,客服也是关键的数据支撑. 一个好的客服团队,能够很好地提高转化率.客单价.复购率,有效的降低退款率.纠纷等售后问题. 今天和 ...

  7. 下单后半小时未付款订单自动取消的实现,延迟队列

    下单后半小时未付款订单自动取消的实现,延迟队列 类似的需要: 订单的评论如果7天未评价,系统需要自动产生一条评论 订单的15天之后未点击收货,系统需要自动更改为已收货. ... 因为是需要一个常驻进程 ...

  8. 订单失效怎么做的_携程技术专家:数据库压力降低90%,订单缓存系统架构实践...

    来源:携程技术(ID:ctriptech) 本文旨在分享携程机票后服务订单处理团队,在构建机票订单缓存系统过程中的一些思考总结,希望能给大家一些启发或帮助.通篇分为以下七大部分:背景,瓶颈,选型,架构 ...

  9. Redis key过期事件监听实现 - 30分钟自动取消未支付订单

    目录 一.前言 二.实现方案分析 三.Redis key过期事件方案实现步骤 3.1 Redis 安装步骤详见 3.2 修改 Redis 配置 3.3 在获取支付链接视图中设置key过期事件 3.4 ...

最新文章

  1. 免费送书啦!《3D计算机视觉:原理、算法及应用》一本全搞定
  2. c8051单片机注意事项:
  3. 检测html输入框是否一样,如何测试一个输入框
  4. 局域网聊天工具的设计与实现 java设计代写代做代码源代码
  5. 标题:浅析图卷积神经网络
  6. 工作按钮(216):点击按钮报错--bug修复--直接写接口里面
  7. gnome硬盘分析_解决八种Linux硬盘问题的技巧
  8. android 遍历所有view,Android 算法:遍历ViewGroup找出所有子View
  9. python面试题_01
  10. 终于搞懂了网红主播的套路
  11. 如何让元素支持 height:100%效果
  12. sublime3 配置go的开发环境
  13. http系列---Apache AB测试工具
  14. 傅里叶变换(时域频域)
  15. “C:\Users\用户名\AppData\里面的文件是什么?可以删除么??
  16. linux系统怎么使用优盘,教你如何使用u盘安装Linux系统
  17. Unity XR开发之入门介绍(一)
  18. 计算机使用水平怎么填,计算机水平怎么填写?
  19. 关于Windows Paint的基础图层透明背景的操作说明
  20. 6.电报机与继电器qk

热门文章

  1. HP惠普M281打印机升级后不兼容国产硒鼓,系统固件降级步骤
  2. 个税专项附加扣除政策要点
  3. 创建本地oracle数据库
  4. java我的世界行尸走肉_我的世界行尸走肉游戏下载_我的世界行尸走肉整合包下载_快吧单机游戏...
  5. CLAHE和改进型CLAHE红外成像质量对比
  6. 自选图形无法保存在HTML中,win7在网页保存图片不能另存为的解决方法
  7. Android兼容之libc++_shared.so库冲突方案
  8. java咨询师,心理咨询师的三种人生境界
  9. GDB苹果网页一键打包工具使用说明
  10. 你还在通宵做报表?自定义生成报表,教你做报表达人!