java学习-排序及加密签名时数据排序方式
Posted 海绵般汲取
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java学习-排序及加密签名时数据排序方式相关的知识,希望对你有一定的参考价值。
排序有两种
在java中一般实现集合排序的方式有两种。
1. 类实现Comparable接口的compareTo(T o)接口方法 2. 使用 Comparator接口的 compare(T o1, T o2)接口方法
在具体的调用上。
1. 类实现comparable接口调用List.sort(null)或Collections.sort(List<T>)方法进行排序
jdk内置的基本类型包装类等都实现了Comparablel接口,默认是使用自然排序,即升序排序
自定义类实现Comparable接口必须要实现compareTo()方法,自己定义排序方式
2.List<T>中T没有实现Comparable类接口方法,又想将对象列表进行排序时,
使用Collections.sort(List<T>, Comparator )
or Arrays.sort(List<T>, Comparator )
排序
上面的两种排序方式底层都是采用归并排序算法,是稳定的排序算法。时间复杂度(nlog2n),空间复杂度(n) 十大经典排序算法(动图演示)
重写这两种方式的接口方法
这两个接口方法的重写逻辑是一样的,都要满足以下条件
关系满足传递性:(compare(x,y)> 0 )&&(compare(y,z)> 0))意味着compare(x,z)> 0
升序:o1>o2 返回1 并且 o1<o2 返回-1, o1==o2 返回0
降序:o1>o2 返回-1 并且 o1<o2 返回1, o1==o2 返回0
Comparable接口方法升序 public int compareTo(int o2){ if(this.value > o2){ return 1; } if(this.value = o2){ return 0; } if(this.value < o2){ return -1; } } Comparator接口方法升序 int compare(int o1, int o2); if(o1 > o2){ return 1; } if(o1 = o2){ return 0; } if(o1 < o2){ return -1; } }
使用场景:
1.调用别人接口获取数据时候,需要将参数按照字典排序排序对数据进行签名,与返回的签名数据进行对比,验证数据的完整性。
2.对获取的数据进行排序后返回给前端,除了使用sql的order asc命令外,也可以使用list.sort方法进行排序后返回给前端(有点傻^^)。
3. 用于复杂的排序场景,比如文件名的排序,广东-广州-期末测试1,广西-桂林-期末测试2,需要我们自己控制排序方法,这时候就需要用到上面两个排序。
实现Comparable接口的排序
consumInfo.java类
实现comparable接口,使用升序排序
public class ConsumInfo implements Comparable<ConsumInfo> { public double price; public String name; public ConsumInfo(double price, String name) { super(); this.price = price; this.name = name; } @Override public int compareTo(ConsumInfo o) { // 首先比较price,如果price相同 if (this.price > o.price) { return 1; } if (this.price == o.price) { return 0; } return -1; } }
来个简单的测试
ConsumInfo []cc=new ConsumInfo[4]; cc[0] = new ConsumInfo(1.1, "zwh"); cc[1] = new ConsumInfo(2.5, "abc"); cc[2] = new ConsumInfo(0.1, "zwh"); cc[3] = new ConsumInfo(0.1, "cdf"); Arrays.sort(cc); for(ConsumInfo consumInfo:cc) { System.out.println("name:"+consumInfo.name+" price:"+consumInfo.price); }
结果
name:zwh price:0.1
name:cdf price:0.1
name:zwh price:1.1
name:abc price:2.5
如果要先按照price排序,如果price相等,再按name进行升序排序呢
只需要修改conpareTo()方法,在price相等时,在比较name的值
@Override public int compareTo(ConsumInfo o) { // 首先比较price,如果price相同 if (this.price > o.price) { return 1; } if(this.price==o.price) { return this.name.compareTo(o.name); } return -1; }
修改后的输出结果,
这里name是String类型,默认是按照字典顺序排序,也就是升序排序。
cdf和zwh,,c比z小,所以调换了位置
name:cdf price:0.1 name:zwh price:0.1 name:zwh price:1.1 name:abc price:2.5
使用Comparator接口实现排序
还是使用上面的ConsumInfo.java类
ConsumInfo []cc=new ConsumInfo[4]; cc[0] = new ConsumInfo(1.1, "zwh"); cc[1] = new ConsumInfo(2.5, "abc"); cc[2] = new ConsumInfo(0.1, "zwh"); cc[3] = new ConsumInfo(0.1, "cdf"); Arrays.sort(cc,new Comparator<ConsumInfo>() { @Override public int compare(ConsumInfo o1, ConsumInfo o2) { if(o1.price<o2.price) { return -1; } if(o1.price==o2.price) { return o1.name.compareTo(o2.name); } return 1; } }); for(ConsumInfo consumInfo:cc) { System.out.println("name:"+consumInfo.name+" price:"+consumInfo.price); }
使用了Arrays.sort(T[] a, Comparator<? super T> c)排序方法,会把ConsumInfo所实现的Comparable接口的排序方法替换掉
也就是说只会使用Comparator接口进行排序。
上面的排序是用于List或者数组或集合的排序,
对于Map,需要对map的key值进行升序排序
使用TreeMap类进行自动排序,默认升序排序。
Map<String, String> para = new TreeMap<String, String>(); para.put("zwh", "123456"); para.put("abc", "123456"); para.put("wuv", "123456"); para.put("cdg", "123456"); for (Map.Entry<String, String> entry : para.entrySet()) { System.out.println("key:" + entry.getKey() + " value:" + entry.getValue()); }
结果
key:abc value:123456
key:cdg value:123456
key:wuv value:123456
key:zwh value:123456
或者我们自己手动对map的key值进行排序 参考:【支付宝,微信支付必备】Java实现url参数按照参数名Unicode码从小到大排序(字典序)
/** * * 方法用途: 对所有传入参数按照字段名的Unicode码从小到大排序(字典序),并且生成url参数串<br> * 实现步骤: <br> * * @param paraMap 要排序的Map对象 * @param urlEncode 是否需要对value的值进行编码 * @param keyToLower 是否需要将Key转换为全小写 * true:key转化成小写,false:不转化 * @return */ public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) { String buff = ""; Map<String, String> tmpMap = paraMap; try { List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet()); // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序) Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() { @Override public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) { return (o1.getKey()).toString().compareTo(o2.getKey()); } }); // 构造URL 键值对的格式 StringBuilder buf = new StringBuilder(); for (Map.Entry<String, String> item : infoIds) { if (item.getKey() != null) { String key = item.getKey(); String val = item.getValue(); if (urlEncode) { val = URLEncoder.encode(val, "utf-8"); } if (keyToLower) { buf.append(key.toLowerCase() + "=" + val); } else { buf.append(key + "=" + val); } buf.append("&"); } } buff = buf.toString(); if (buff.isEmpty() == false) { buff = buff.substring(0, buff.length() - 1); } } catch (Exception e) { return null; } return buff; }
参考支付宝的参数排序方法
剔除sign字段(这个根本不需要剔除,参数中是没有的),
剔除参数值为空的字段,这里做了个简单的判断,
对key进行排序,然后用&符号对key=value进行拼接。
Map<String, String> para = new TreeMap<String, String>(); para.put("app_id", "2014072300007148"); para.put("method", "alipay.mobile.public.menu.add"); para.put("charset", ""); para.put("sign_type", ""); para.put("timestamp", "2014-07-24 03:07:50"); para.put("biz_content", ""); para.put("sign_type", "123456"); para.put("version", "1.0"); List<String> keys= new ArrayList<>(para.keySet()); Collections.sort(keys); StringBuffer content=new StringBuffer(); for (int i=0; i<keys.size();i++) { String key = keys.get(i); String value = para.get(key); if(value!=null&&value.length()!=0) { content.append((i==0?"":"&")+key+"="+value); } } System.out.println(content.toString());
结果
app_id=2014072300007148&method=alipay.mobile.public.menu.add&sign_type=123456×tamp=2014-07-24 03:07:50&version=1.0
注意,上面字符串的空判断还少做了一个空白字符的判断,建议使用下面的值的非空判断代替
if(value!=null&&value.length()!=0)
public static boolean isBlank(String str) { int strLen; if (str == null || (strLen = str.length()) == 0) { return true; } for (int i = 0; i < strLen; i++) { if ((Character.isWhitespace(str.charAt(i)) == false)) { return false; } } return true; }
待看:http://www.cnblogs.com/interdrp/p/8970593.html Java Comparator字符排序(数字、字母、中文混合排序)
编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议70~74)
以上是关于java学习-排序及加密签名时数据排序方式的主要内容,如果未能解决你的问题,请参考以下文章
iOS 安全规范指南之对请求参数进行签名请求参数按照ASCII码从小到大排序拼接加密(采用递归的方式进行实现)应用案例:条码支付综合前置平台申请退款
iOS 安全规范指南之对请求参数进行签名请求参数按照ASCII码从小到大排序拼接加密(采用递归的方式进行实现)应用案例:条码支付综合前置平台申请退款