项目的一些操作

      一、发送qq邮箱验证码以及倒计时

                要发送验证码需要用到邮箱的授权码:

        qq邮箱获取方式,打开qq邮箱点设置找到如下界面:

然后获取授权码;

导入依赖

    <dependency>
         <groupId>com.sun.mail</groupId>
         <artifactId>javax.mail</artifactId>
         <version>1.6.2</version>
    </dependency>

这个依赖有些都不一样,尽量按最新的来

代码:

package com.kgc.ymw.util;
 
import java.security.GeneralSecurityException;
import java.util.Properties;
import java.util.Random;
 
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
 
import com.sun.mail.util.MailSSLSocketFactory;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.junit.jupiter.api.Test;
 
/**
 * @author: BruceYoung
 * @date: 2023/5/11
 */
@SuppressWarnings({"all"})
public class EmailTest {
    private static String yzm;
 
    @Test
    public void send1() {
        String email = "xxxxxx@qq.com";//接收人邮箱
        //HtmlEmail方式
        sendEmail(email);
    }
 
    @Test
    public void send2() {
//        yzm = random1();
        try {
            //javax.mail方式(发送方的邮箱,qq邮箱中申请的16位授权码,接收人邮箱,邮件标题,邮件内容)
            sendMail("xxxx@qq.com", "授权码", "xxxxxx@qq.com", "名称", "<html><h1>邀请您注册验证码:" + yzm + "</h1></html>");
        } catch (MessagingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (GeneralSecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
    /**
     * 方式1:发送QQ邮件
     */
    public static String sendEmail(String email) {
        HtmlEmail send = new HtmlEmail();//创建一个HtmlEmail实例对象
        // 获取随机验证码
        yzm = random1();
        String resultCode = yzm;
        try {
            send.setHostName("smtp.qq.com");
            send.setAuthentication("xxxxx@qq.com", "邮箱授权码"); //第一个参数是发送者的QQEamil邮箱   第二个参数是刚刚获取的授权码
 
            send.setFrom("xxxxxx@qq.com", "名称");//发送人的邮箱为自己的,用户名可以随便填  记得是自己的邮箱不是qq
//			send.setSmtpPort(465); 	//端口号 可以不开
            send.setSSLOnConnect(true); //开启SSL加密
            send.setCharset("utf-8");
            send.addTo(email);  //设置收件人    email为你要发送给谁的邮箱账户
            send.setSubject("标题"); //邮箱标题
            send.setMsg("您的验证码为:<font color='red' >   " + resultCode + " </font>,五分钟后失效"); //Eamil发送的内容
            send.send();  //发送
        } catch (EmailException e) {
            e.printStackTrace();
        }
        return yzm;
    }
 
 
    /**
     * 方式2:发送QQ邮件
     *
     * @param sender  发送方的邮箱
     * @param auth    qq邮箱中申请的16位授权码
     * @param to      接收人邮箱
     * @param title   邮件标题
     * @param content 邮件内容
     */
    public static String sendMail(String sender, String auth, String to, String title, String content) throws MessagingException, GeneralSecurityException, javax.mail.MessagingException {
        yzm = random1();
        //创建一个配置文件并保存
        Properties properties = new Properties();
        properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        properties.setProperty("mail.smtp.socketFactory.fallback", "false");
        properties.setProperty("mail.smtp.port", "465");
        properties.setProperty("mail.smtp.socketFactory.port", "465");
 
 
        properties.setProperty("mail.host", "smtp.qq.com");
        properties.setProperty("mail.transport.protocol", "smtp");
        properties.setProperty("mail.smtp.auth", "true");
        //QQ存在一个特性设置SSL加密
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        properties.put("mail.smtp.ssl.enable", "true");
        properties.put("mail.smtp.ssl.socketFactory", sf);
 
        //创建一个session对象
        Session session = Session.getDefaultInstance(properties, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(sender, auth);
            }
        });
        //开启debug模式
        session.setDebug(true);
        //获取连接对象
        Transport transport = session.getTransport();
        //连接服务器
        transport.connect("smtp.qq.com", sender, auth);
        //创建邮件对象
        MimeMessage mimeMessage = new MimeMessage(session);
        //邮件发送人
        mimeMessage.setFrom(new InternetAddress(sender));
        //邮件接收人
        mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
        //邮件标题
        mimeMessage.setSubject(title);
        //邮件内容
        mimeMessage.setContent(content, "text/html;charset=UTF-8");
        //发送邮件
        transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
        //关闭连接
        transport.close();
 
        return yzm;
    }
 
    //生成6位数  验证码
    public static String random1() {
        String code = "";
        Random rd = new Random();
        for (int i = 0; i < 6; i++) {
            int r = rd.nextInt(10); //每次随机出一个数字(0-9)
            code = code + r;  //把每次随机出的数字拼在一起
        }
        System.out.println(code);
        return code;
    }
 
}

倒计时:

private void startCountdown() {
        Thread countdownThread = new Thread(()->{

            while(countdownSeconds>0) {
                try {
                    Thread.sleep(1000);
                    countdownSeconds--;
                    updataButtonText(countdownSeconds+"s");


                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            Platform.runLater(() -> {
                SendCodeButton.setText("发送");
            });

        });
        countdownThread.start();
    }

    private void updataButtonText(String s) {
        Platform.runLater(()->SendCodeButton.setText(s));
    }

点击发送按钮后调用startCountdown即可

二、雪花算法

Twitter的分布式自增ID算法,经过测试snowflake每秒能够产生26万个自增可排序的ID

  1. Twitter的雪花算法生成ID能够按照时间有序生成
  2. 雪花算法生成id的结果是一个64bit大小的整数,为一个long
  3. 分布式系统内不会产生ID碰撞并且效率较高

号段解析:

  • 第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。
  • 时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年,2的41次方 -1毫秒值就是69年
  • 工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。可以部署在2^10=1024个节点,包括5位datacenterId和5位workerId
  • 序列号部分(12bit):自增值支持同一毫秒内同一个节点可以生成4096个ID。12位可以表示的最大正整数2^12-1=4095,即可以用0,1,2,3…4094这4095个数字,来表示同一机器同一时间(1毫秒)内产生4095个ID序号。
//雪花算法代码实现
public class IdWorker {
    // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
    private final static long twepoch = 1288834974657L;
    // 机器标识位数
    private final static long workerIdBits = 5L;
    // 数据中心标识位数
    private final static long datacenterIdBits = 5L;
    // 机器ID最大值
    private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
    // 数据中心ID最大值
    private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    // 毫秒内自增位
    private final static long sequenceBits = 12L;
    // 机器ID偏左移12位
    private final static long workerIdShift = sequenceBits;
    // 数据中心ID左移17位
    private final static long datacenterIdShift = sequenceBits + workerIdBits;
    // 时间毫秒左移22位
    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
 
    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
    /* 上次生产id时间戳 */
    private static long lastTimestamp = -1L;
    // 0,并发控制
    private long sequence = 0L;
 
    private final long workerId;
    // 数据标识id部分
    private final long datacenterId;
 
    public IdWorker(){
        this.datacenterId = getDatacenterId(maxDatacenterId);
        this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
    }
    /**
     * @param workerId
     *            工作机器ID
     * @param datacenterId
     *            序列号
     */
    public IdWorker(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
    /**
     * 获取下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
 
        if (lastTimestamp == timestamp) {
            // 当前毫秒内,则+1
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 当前毫秒内计数满了,则等待下一秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        // ID偏移组合生成最终的ID,并返回ID
        long nextId = ((timestamp - twepoch) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift) | sequence;
 
        return nextId;
    }
 
    private long tilNextMillis(final long lastTimestamp) {
        long timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }
 
    private long timeGen() {
        return System.currentTimeMillis();
    }
 
    /**
     * <p>
     * 获取 maxWorkerId
     * </p>
     */
    protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
        StringBuffer mpid = new StringBuffer();
        mpid.append(datacenterId);
        String name = ManagementFactory.getRuntimeMXBean().getName();
        if (!name.isEmpty()) {
            /*
             * GET jvmPid
             */
            mpid.append(name.split("@")[0]);
        }
        /*
         * MAC + PID 的 hashcode 获取16个低位
         */
        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
    }
 
    /**
     * <p>
     * 数据标识id部分
     * </p>
     */
    protected static long getDatacenterId(long maxDatacenterId) {
        long id = 0L;
        try {
            InetAddress ip = InetAddress.getLocalHost();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            if (network == null) {
                id = 1L;
            } else {
                byte[] mac = network.getHardwareAddress();
                id = ((0x000000FF & (long) mac[mac.length - 1])
                        | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
                id = id % (maxDatacenterId + 1);
            }
        } catch (Exception e) {
            System.out.println(" getDatacenterId: " + e.getMessage());
        }
        return id;
    }

    public static void main(String[] args) {
        IdWorker idWorker = new IdWorker(0, 0);
        for (int i = 0; i < 10; i++) {
            long id = idWorker.nextId();
            System.out.println(id);
            System.out.println("========================");
        }
    }

}

这个的话是源代码一般不用这个,下面这个将id缩短到16

    // 毫秒内自增位
//    private final static long sequenceBits = 12L;
    private final static long sequenceBits = 8L;
    // 时间毫秒左移22位
//    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private final static long timestampLeftShift = sequenceBits + workerIdBits;

    public synchronized long nextId() {
	.。。。。。。。。。。
        // ID偏移组合生成最终的ID,并返回ID
        long nextId = ((timestamp - twepoch) << timestampLeftShift)
//                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift) | sequence;
 
        return nextId;
    }

三、MD5加密

        MD5:即 Message Digest Algorithm 5 缩写,中文含义为信息摘要算法第5版,是一种被广泛使用的密码散列函数,可产生一个16字节的散列值,用来提供信息的完整性保护。对于软件开发者来说,经常使用 MD5 校验信息的完整性(比如,防止文件篡改或损坏),甚至将它当作加密算法使用。
 

MD5 作为一种摘要算法,具有以下特征:

1、产生固定长度的散列值。无论输入了多长的信息,经过 MD5 处理后都只会产生一个16字节的散列值。

2、不可逆。经过 MD5 处理后得到的散列结果,无法计算出原始数据,正是因为 MD5 无法从密文还原成明文,它不能用于解密了。

3、运算快。MD5 采用的是位运算,速度很快,几乎不占用 CPU 资源。

4、不安全。1996年后该算法被证实存在弱点,可以被加以破解。2004年,证实 MD5 算法无法防止碰撞,因此不适用于安全性认证,比如 SSL 公开密钥认证、数字签名等用途。2011年,RFC 6151 禁止 MD5 用作密钥散列消息认证码。

java代码:

import java.security.MessageDigest;
import java.util.Objects;
 
public class MD5Util {
    private static final char[] HEX_DIGITS
            = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    private static String characterEncoding;
 
    public static String encode(String str) {
        if (Objects.isNull(str)) {
            return null;
        }
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(Objects.nonNull(characterEncoding) 
                    ? str.getBytes(characterEncoding) : str.getBytes());
            byte[] bytes = md.digest();
            StringBuilder builder = new StringBuilder(bytes.length * 2);
            for (byte b : bytes) {
                builder.append(HEX_DIGITS[b >> 4 & 15]);
                builder.append(HEX_DIGITS[b & 15]);
            }
            return builder.toString();
        } catch (Exception e) {
            throw new RuntimeException("process failed ", e);
        }
    }
}

  • 22
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 作为联想公司的SAP项目操作手册,目的是为了协助联想公司员工能够更好的使用SAP系统。SAP系统是基于企业流程的管理软件,它被广泛应用于全球范围内的企业,能够帮助企业优化业务流程,提高效率和准确性。 这份操作手册涵盖了联想公司在SAP系统中的各类业务流程,比如采购、销售、财务等。在操作手册中,每个业务流程都有详细的步骤和说明,以及相应的截图和图表,使员工可以快速、准确地完成任务。此外,操作手册还包括SAP系统中的各类基础功能和操作技巧,如搜索、过滤、导出等。 另外,操作手册还为新员工提供了简明易懂的SAP系统介绍,并提供了一些常见问题的解答。从而帮助新员工快速掌握SAP系统的基本知识和使用方法,让他们更快更好地适应联想公司的工作环境。 综上所述,这份联想SAP项目操作手册是一份庞大、详细的文档,它对于联想公司员工的工作起到了巨大的协助作用,让员工能够更加高效、准确地使用SAP系统,从而为公司的数字化转型和业务升级提供了坚实的支撑。 ### 回答2: 联想SAP项目操作手册是一个详细的指南,旨在帮助联想的员工和业务合作伙伴熟悉和操作SAP系统。SAP系统是一个综合性的企业管理软件,可用于财务管理、物流管理、人力资源管理和销售等业务领域。在联想这样的大型企业中,SAP系统被广泛应用。 操作手册包含了SAP系统的基本知识和操作步骤,从系统登录到各个模块的使用,都有详细的说明和示例。手册还提供了常见问题解决方法和更高级的应用,如数据分析和报表制作等。操作手册涉及到的主要模块有财务会计、采购管理、销售和分销、供应链管理、生产计划和控制和人力资源管理。 SAP系统在企业管理中的重要性越来越受到关注,联想对该系统的广泛应用也体现出了这一点。操作手册的编写是为了提高联想员工和合作伙伴的工作效率和业务水平,有效地掌握SAP系统,更好地支持企业管理的发展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值