MD5 is a nice guy / MD5 is a nice guy

md5 is a digest generation algorithm that can verify whether the message has been tampered by generating a unique digest for the message.

As we all know, md5 is widely used in the security control of http interface communication. By adding the merchant’s communication secret key to the original signature string, the MD5 operation is performed, and the resulting summary string is the signature result. Both sides of the interface use this to determine whether the packets are consistent.

As long as the message remains unchanged, its md5 value remains unchanged. Because of this, md5 is not only used for interface communication, but this feature can also be used in our programs to ensure the uniqueness of data.

For example, we often have redundant judgment mechanisms, such as verifying repeated requests, such as ensuring that a piece of logic cannot be executed repeatedly (in the money order system, user reminder messages cannot be resent; scheduled tasks prevent duplicates-scheduled tasks are executed within a specific period of time) Triggered repeatedly, but its internal logic does not allow repeated execution). In these scenarios, using redis distributed locks with md5 will be the perfect solution.

 public boolean remind(TradeOrder order, TradeRemindTypeEnum remindTypeEnum) {

        log.info("Order sending reminder starts. orderNo={}, notification type={}", order.getOrderNo(), remindTypeEnum);

        int exSeconds = 60 * 60; //Expiration time is 1 hour
        //If the key does not exist, perform the set operation and return the string OK; if the key already exists, return null
        String redisKey = remindTypeEnum + "_" + order.getOrderNo() + "_" + MD5Util.md5(JSONObject.toJSONString(order));
        if (null == JedisClusterUtil.getJedisCluster().set(redisKey, UUID.randomUUID().toString(), "NX", "EX", exSeconds)) {
            log.info("The order has been reminded and will not be reminded again this time. {}", redisKey);
            return false;
        }
        
        ....Send reminder message...
        
    }

View Code

To give another example, the amount of bill discount can be calculated in two ways: annual interest rate or handling fee per 100,000. There is a rule in the demand that when one of them has no value, it should be back-calculated based on the one with value. This algorithm was tested by QA a few days ago and it was discovered that there would be a few cents difference in the discount amount of the submitted transaction order. After a colleague modified the algorithm, the problem did not recur after testing again. However, this does not mean that it is completely fixed. Therefore, I wrote a testcase to randomly generate some test cases in batches to simulate exhaustive customer input. Among them, when comparing the two calculation results, md5 is used. If the md5 of the two results are different, it proves There are still problems with the algorithm. Finally, after running testcase, we found the shortcomings of the algorithm. After correcting it again and testing iteratively, the bug no longer recurred.

import com.emaxcard.codec.MD5Util;
import com.emaxcard.rpc.payment.model.FeeCalculateReq;
import com.emaxcard.rpc.payment.model.FeeCalculateRes;
import org.apache.commons.lang.math.RandomUtils;
import org.joda.time.DateTime;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class FeeCalculateServiceImplTest {

    // @Test
// public void feeCalculate() {<!-- -->
    public static void main(String[] args) throws Exception {

        for (int i = 1; i < 10000; i + + ) {
            System.out.println(i);
            int rand = RandomUtils.nextInt(10);
            BigDecimal divide = BigDecimal.valueOf(i).divide(BigDecimal.valueOf(rand == 0 ? Math.PI : rand), 12, RoundingMode.HALF_UP);
            BigDecimal draftAmt = BigDecimal.valueOf(500000).add(divide).setScale(0, RoundingMode.HALF_UP);
            BigDecimal unitAmt = BigDecimal.valueOf(RandomUtils.nextInt(10)).add(divide).setScale(2, RoundingMode.HALF_UP);
            BigDecimal saleRate = divide.divide(BigDecimal.valueOf(100)).setScale(6, RoundingMode.HALF_UP);
            calculateFee(draftAmt,unitAmt, saleRate);
        }
    }

    static void calculateFee(BigDecimal draftAmt, BigDecimal unitAmt, BigDecimal saleRate) throws Exception {
        if (null == unitAmt) {
            unitAmt = BigDecimal.ZERO;
        }
        if (null == saleRate) {
            saleRate = BigDecimal.ZERO;
        }
        FeeCalculateReq feeCalculateReq = new FeeCalculateReq();
        feeCalculateReq.setDraftAmt(draftAmt.toPlainString());
        feeCalculateReq.setUnitAmt(unitAmt.toPlainString());
        feeCalculateReq.setSaleRate(saleRate.toPlainString());
        feeCalculateReq.setDraftEndDate(DateTime.now().plusYears(1).toString("yyyy-MM-dd"));

        FeeCalculateRes feeCalculateRes = FeeCalculateServiceImpl.calculateFee(feeCalculateReq);
        String s1 = MD5Util.md5(feeCalculateRes.toString());

        feeCalculateReq.setUnitAmt(feeCalculateRes.getUnitAmt());
        feeCalculateReq.setSaleRate(feeCalculateRes.getSaleRate());
        feeCalculateRes = FeeCalculateServiceImpl.calculateFee(feeCalculateReq);
        String s2 = MD5Util.md5(feeCalculateRes.toString());

        boolean equals = s1.equals(s2);
        if (equals == false) {
            throw new Exception("bad luck!!!");
        }
    }
}

View Code

Wuwenxidong

Promotional song of the same name for the movie “Wonderful West and East”

Lyricist: Peng Qing

Composer: Peng Qing

Singer: Faye Wong

Producer: Zhang Yadong

Arranger: Peng Fei

Mixing: Yan Zhongkun @ JET Studio

Whose hand always holds my hand tightly?
Wandering in the crowd desert without looking back
Don’t look at me with tearful eyes
Listen to the cicada’s falling sound
Please raise your head and show your face tonight

Who healed me with dewy blades of grass
May we brave the storm and trek through the mud together
Who said that all roads passed by are necessary, and all the hardships are rewarded
Mountain clouds act as a curtain for rock climbing and watching fire

Please let me sing loudly, facing the sea breeze
Outside the world, in time, without asking anything about the West and the East
Just stand up and be a hero, your youthful courage is not in vain
May the freedom of the heart share the beauty of heaven and earth
Love and dreams

Who healed me with dewy blades of grass
May we brave the storm and trek through the mud together
Who said that all roads passed by are necessary, and all the hardships are rewarded
Mountain clouds act as a curtain for rock climbing and watching fire

Please let me sing loudly, facing the sea breeze
Outside the world, in time, without asking anything about the West and the East
Just stand up and be a hero, your youthful courage is not in vain
May the freedom of the heart share the beauty of heaven and earth
Love and dreams