classfinal加密jar包

官网下载加密jar包:https://gitee.com/roseboy/classfinal

//加密jar
java -jar classfinal-fatjar-1.2.1.jar  -file kafka_flink_dm.jar -cfgfiles config,druid  -pwd 123456 -Y

//密码运行加密jar
java -javaagent:tianditu-encrypted.jar="-pwd 123456" -jar tianditu-encrypted.jar 

读取配置文件

//读取配置文件
        Properties prop = new Properties();
        InputStream is = Main.class.getClassLoader().getResourceAsStream("config.properties");
        prop.load(is);
        String property = prop.getProperty("bootstrap.servers");
        String propProperty = prop.getProperty("group.id");
//    一
        System.out.println("执行成功了呀!!!");
        InputStream in = Test.class.getResourceAsStream("/config.properties");

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line = reader.readLine();

//    二
InputStream is = Main.class.getClassLoader().getResourceAsStream("config.properties");

多线程添加数据库测试数据

public class Thread01 implements Runnable {

    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 6, 3, TimeUnit.HOURS,
                new LinkedBlockingQueue<>());
        threadPoolExecutor.execute(new Thread01());
        threadPoolExecutor.execute(new Thread01());
        threadPoolExecutor.execute(new Thread01());
    }

    @Override
    public void run() {
        String url = "jdbc:mysql:///test?serverTimezone=GMT%2B8&characterEncoding=utf8";
        String user = "root";
        String password = "";
        //定义连接、statement对象
        Connection conn = null;
        PreparedStatement pstm = null;
        try {
            //加载jdbc驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //连接mysql
            conn = DriverManager.getConnection(url, user, password);
            //将自动提交关闭
//             conn.setAutoCommit(false);
            //编写sql
            String sql = "INSERT INTO test.test01 (a, b, c) VALUES('榴莲煲鸡汤', '甲鱼炖鸡汤', '鲫鱼豆腐汤')";
            //预编译sql
            pstm = conn.prepareStatement(sql);
            //开始总计时
            long bTime1 = System.currentTimeMillis();
            System.out.println(Thread.currentThread().getName()+"开始插入数据");
            for (int i = 0; i < 3; i++) {
                //开启分段计时,计1W数据耗时
                long bTime = System.currentTimeMillis();
                for (int j = 0; j < 100000; j++) {
                    pstm.addBatch(sql);
                }
                pstm.executeBatch();
                //关闭分段计时
                long eTime = System.currentTimeMillis();
                //输出
                System.out.println(Thread.currentThread().getName()+"成功插入10W条数据耗时:" + (eTime - bTime));
            }
            //关闭总计时
            long eTime1 = System.currentTimeMillis();
            //输出
            System.out.println(Thread.currentThread().getName()+"插入30W数据共耗时:" + (eTime1 - bTime1));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                pstm.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

}

线程池介绍

启动任务submit()和execute()
Execute()方法只能接收Runnable类型的参数,而submit()方法可以接收Callable、Runnable两种类型的参数。Callable类型的任务是可以返回执行结果的,而Runnable类型的任务不可以返回执行结果。

/**
 * 1、corePoolSize:核心线程数,线程池中始终存活的线程数。
 * <p>
 * 2、maximumPoolSize:最大线程数,线程池中允许的最大线程数,当线程池的任务队列满了之后可以创建的最大线程数。
 * <p>
 * 3、keepAliveTime:最大线程数可以存活的时间,当线程中没有任务执行时,最大线程就会销毁一部分,最终保持核心线程数量的线程。
 * <p>
 * 4、unit:单位是和参数 3 存活时间配合使用的,合在一起用于设定线程的存活时间。参数 keepAliveTime 的时间单位有以下 7 种可选:
 * TimeUnit.DAYS:天
 * TimeUnit.HOURS:小时
 * TimeUnit.MINUTES:分
 * TimeUnit.SECONDS:秒
 * TimeUnit.MILLISECONDS:毫秒
 * TimeUnit.MICROSECONDS:微妙
 * TimeUnit.NANOSECONDS:纳秒
 * <p>
 * 5、workQueue:一个阻塞队列,用来存储线程池等待执行的任务,均为线程安全。它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种,
 * 包含以下 7 种类型:
 * ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
 * LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
 * SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
 * PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
 * DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素
 * LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
 * LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
 * 较常用的是 LinkedBlockingQueue 和 Synchronous,线程池的排队策略与 BlockingQueue 有关。
 * <p>
 * 6、threadFactory:线程工厂,主要用来创建线程。
 * <p>
 * 7、handler:拒绝策略,拒绝处理任务时的策略,系统提供了 4 种可选:
 * AbortPolicy:拒绝并抛出异常。
 * CallerRunsPolicy:使用当前调用的线程来执行此任务。
 * DiscardOldestPolicy:抛弃队列头部(最旧)的一个任务,并执行当前任务。
 * DiscardPolicy:忽略并抛弃当前任务。
 * 默认策略为 AbortPolicy。
 */
public class ThreadPool01 implements Runnable {

    /**
     * ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(核心线程数量,最大线程
     * 数量,空闲线程最大存活时间,时间单位,任务队列,创建线程工厂,任务的拒绝策略);
     * <p>
     * 1、直接提交队列:SynchronousQueue
     * 使用 SynchronousQueue 队列,提交的任务不会被保存,总是会马上提交执行。如果用于执行任务的线程数量小于maximumPoolSize,
     * 则尝试创建新的进程,如果达到maximumPoolSize设置的最大值,则根据你设置的handler执行拒绝策略。
     * 因此这种方式你提交的任务不会被缓存起来,而是会被马上执行,在这种情况下,你需要对你程序的并发量有个准确的评估,
     * 才能设置合适的maximumPoolSize数量,否则很容易就会执行拒绝策略
     * <p>
     * 2、有界的任务队列:ArrayBlockingQueue
     * 使用 ArrayBlockingQueue 有界任务队列,若有新的任务需要执行时,线程池会创建新的线程,
     * 直到创建的线程数量达到 corePoolSize 时,则会将新的任务加入到等待队列中。若等待队列已满,
     * 即超过 ArrayBlockingQueue 初始化的容量,则继续创建线程,直到线程数量达到 maximumPoolSize 设置的最大线程数量,
     * 若大于 maximumPoolSize,则执行拒绝策略。在这种情况下,线程数量的上限与有界任务队列的状态有直接关系,
     * 如果有界队列初始容量较大或者没有达到超负荷的状态,线程数将一直维持在 corePoolSize 以下,反之当任务队列已满时,
     * 则会以 maximumPoolSize 为最大线程数上限
     * <p>
     * 3、无界的任务队列:LinkedBlockingQueue
     * 使用无界任务队列,线程池的任务队列可以无限制的添加新的任务,而线程池创建的最大线程数量就是你 corePoolSize 设置的数量,
     * 也就是说在这种情况下 maximumPoolSize 这个参数是无效的,哪怕你的任务队列中缓存了很多未执行的任务,
     * 当线程池的线程数达到 corePoolSize 后,就不会再增加了;若后续有新的任务加入,则直接进入队列等待,
     * 当使用这种任务队列模式时,一定要注意你任务提交与处理之间的协调与控制,不然会出现队列中的任务由于无法及时处理导致一直增长,
     * 直到最后资源耗尽的问题。
     */

    public static void main(String[] args) {
        // 1. 创建一个线程池对象 核心线程为5, 最大线程数5, 临时线程存活6秒, 任务队列最大为5
        ExecutorService es = new ThreadPoolExecutor(3, 5, 6,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

//        无界的任务队列,核心线程1,最大线程数2,临时线程存活秒数3,单位秒,
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1, 2, 3, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());

//        ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 100, 600,
//                TimeUnit.SECONDS, new ArrayBlockingQueue<>(65536));
        Future<?> submit = es.submit(new ThreadPool01());
        try {
            Object o = submit.get();
            System.out.println(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 参数介绍:
     * <p>
     * 参数一:指定线程池的线程数量(核心线程): corePoolSize ----> 不能小于0
     * 参数二:指定线程池可支持的最大线程数: maximumPoolSize ----> 最大数量 >= 核心线程数量
     * 参数三:指定临时线程的最大存活时间: keepAliveTime ----> 不能小于0
     * 参数四:指定存活时间的单位(秒、分、时、天): unit ----> 时间单位
     * 参数五:指定任务队列: workQueue ----> 不能为null
     * 参数六:指定用哪个线程工厂创建线程: threadFactory ----> 不能为null
     * 参数七:指定线程忙,任务满的时候,新任务拒绝策略: handler ----> 不能为null
     */

    @Override
    public void run() {
        System.out.println("执行成功!!!");
    }

}

批量执行SQL语句

@Test
void insertMysql() {
        String url = "jdbc:mysql:///test?serverTimezone=GMT%2B8&characterEncoding=utf8";
        String user = "root";
        String password = "";
        //定义连接、statement对象
        Connection conn = null;
        PreparedStatement pstm = null;
        try {
            //加载jdbc驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //连接mysql
            conn = DriverManager.getConnection(url, user, password);
            //将自动提交关闭
//             conn.setAutoCommit(false);
            //编写sql
            String sql = "INSERT INTO test.test01 (a, b, c) VALUES('榴莲煲鸡汤', '甲鱼炖鸡汤', '鲫鱼豆腐汤')";
            //预编译sql
            pstm = conn.prepareStatement(sql);
            //开始总计时
            long bTime1 = System.currentTimeMillis();

            for (int i = 0; i < 3; i++) {
                //开启分段计时,计1W数据耗时
                long bTime = System.currentTimeMillis();
                for (int j = 0; j < 10000; j++) {
                    pstm.addBatch(sql);
                }
                pstm.executeBatch();
                //关闭分段计时
                long eTime = System.currentTimeMillis();
                //输出
                System.out.println("成功插入1W条数据耗时:" + (eTime - bTime));
            }
            //关闭总计时
            long eTime1 = System.currentTimeMillis();
            //输出
            System.out.println("插入3W数据共耗时:" + (eTime1 - bTime1));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                pstm.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

打成jar包读取配置文件

        InputStream in = Test.class.getResourceAsStream("/config.properties");

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line = reader.readLine();

        JSONArray topicList = JSONUtil.parseObj(line).getJSONArray("topicList");
        for (Object topic : topicList) {
            System.out.println(topic);
        }

流水号根据每天时间重置更新

    @Test
    void number(){
//        获取流水号最新一条数据
        String userCity = "";
        System.out.println("数据库最新 "+userCity);
//        截取数据最新日期
        String cityDate = userCity.substring(11, 19);
//        截取流水号
        String codeId = userCity.substring(20, userCity.length());
//        获取当前日期
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String newDate = dateFormat.format(new Date());
//        数据库日期和当前日期比较  相等+1    不等拼接当前日期拼接00001
        if (newDate.equals(cityDate)){
            int parseInt = Integer.parseInt(codeId);
            parseInt=parseInt+1;
            DecimalFormat format = new DecimalFormat("00000");
            String getSerialNumber = userCity.substring(0, 19) + format.format(parseInt);
//            return getSerialNumber;
        }else {
            String getSerialNumber = userCity.substring(0, 11)+newDate+"00001";
//            return getSerialNumber;
        }
    }

JDBC获取数据库信息

    @Test
    void mysqlDriver() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306", "root", "root");
        DatabaseMetaData metaData = conn.getMetaData();

//        获取数据库所有数据源
        ResultSet catalogs = metaData.getCatalogs();
        while (catalogs.next()){
            String db = catalogs.getString(".TABLE_CAT");
            System.out.print("数据源   "+db+" ");
        }
        System.out.println();

//        获取该数据源中的表
        ResultSet dataTables = metaData.getTables("api", null, null, new String[]{"TABLE"});
        while (dataTables.next()){
            String table = dataTables.getString("TABLE_NAME");
            System.out.print("表名   "+table+" ");
        }
        System.out.println();

//        获取该数据源中表的字段
        ResultSet columns = metaData.getColumns("api", null, "API_CONFIGURE", null);
        while (columns.next()){
//            数据库名
            String dbName = columns.getString(".TABLE_CAT");
//            表名
            String tableName = columns.getString(".TABLE_NAME");
//            字段
            String field = columns.getString(".COLUMN_NAME");
//            类型
            String type = columns.getString(".TYPE_NAME");
            System.out.println("数据库名 "+dbName+"   表名 "+tableName+"   字段 "+field+"   类型 "+type);
        }

        conn.close();
    }

解析xml

    /**
     * 依赖
     * <!-- dom4j -->
     *         <dependency>
     *             <groupId>dom4j</groupId>
     *             <artifactId>dom4j</artifactId>
     *             <version>1.6.1</version>
     *         </dependency>
     */
    public R SAXReader(String url) {
        try {
            String get = HttpClient.Get(url);
            Object data = JSONObject.parseObject(get).get("data");
//            log.info(data+"");
//            路径获取xml文件
            SAXReader reader = new SAXReader();
            Document read = reader.read("路径");
//            解析string类型的xml字符串
            Document document = DocumentHelper.parseText(data.toString());
//            获取根节点
            Element rootElement = document.getRootElement();
//            迭代器
            Iterator iterator = rootElement.elementIterator();
//            过滤 存放不重复的节点
            HashSet<String> keySet = new HashSet<>();
//            遍历
            while (iterator.hasNext()) {
                Element stu = (Element) iterator.next();
                Iterator iterator1 = stu.elementIterator();
                while (iterator1.hasNext()) {
                    Element stuChild = (Element) iterator1.next();
//                    存放节点
                    keySet.add(stuChild.getName());
                    System.out.println("节点 "+stuChild.getName());
                }
            }
            return R.ok(keySet);
        } catch (Exception e) {
            return R.failed("获取失败");
        }
    }

JAVA设置下载样式

public void download(HttpServletResponse response) {
                try {
            // path是指欲下载的文件的路径。
            File file = new File("/Users/linyanxia/Downloads/1.png");
            // 取得文件名。
            String filename = file.getName();
            // 取得文件的后缀名。
            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();

            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream("/Users/linyanxia/Downloads/1.png"));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.setContentType("image/jpeg");
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            response.addHeader("Content-Length", "" + file.length());
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

获取static路径文件

String path = this.getClass().getClassLoader().getResource("").getPath() + "static/1.ofd";

SM2加密解密

密钥生成:(https://i.goto327.top/CryptTools/SM2.aspx?tdsourcetag=s_pctim...)

    /**
     * 依赖
     * <dependency>
     *   <groupId>org.bouncycastle</groupId>
     *   <artifactId>bcprov-jdk15to18</artifactId>
     *   <version>1.69</version>
     * </dependency>
     */
    @Test
    void Test() {
        String privateKeyHex = "FD6853164CB0FA720E02214C84EC669AAEBC599B9DD13157BC4F8CFF307CE37E";
        String x = "6F5AA82AD98CFA3A3BABD7833CD0CFAE15C3CB99E299137F90BC67D1BED6A855";
        String y = "FF8B9F22D484264CBB302693077235C137374458B740AC6278E8EAE0B8FEB030";

        String text = "123456";

        final SM2 sm2 = new SM2(privateKeyHex, x, y);

        // 公钥加密
        String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
        System.out.println(encryptStr);
        // 私钥解密
        String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
        System.out.println(decryptStr);
    }

生成图形验证码

    /**
     * 验证码功能位于cn.hutool.captcha包中,核心接口为ICaptcha,此接口定义了以下方法:
     *
     * createCode 创建验证码,实现类需同时生成随机验证码字符串和验证码图片
     * getCode 获取验证码的文字内容
     * verify 验证验证码是否正确,建议忽略大小写
     * write 将验证码写出到目标流中
     * 其中write方法只有一个OutputStream,ICaptcha实现类可以根据这个方法封装写出到文件等方法。
     *
     * AbstractCaptcha为一个ICaptcha抽象实现类,此类实现了验证码文本生成、非大小写敏感的验证、写出到流和文件等方法,通过继承此抽象类只需实现createImage方法定义图形生成规则即可。
     */
    @Test
    void Test01(){
//        LineCaptcha 线段干扰的验证码
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        lineCaptcha.write("/Users/lin/Downloads/common/line1.png");
        Console.log(lineCaptcha.getCode());
        lineCaptcha.verify("1234");

        lineCaptcha.createCode();
        lineCaptcha.write("/Users/lin/Downloads/common/line2.png");
        Console.log(lineCaptcha.getCode());
        lineCaptcha.verify("1234");

//        CircleCaptcha 圆圈干扰验证码
        CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        circleCaptcha.write("/Users/lin/Downloads/common/line3.png");
        circleCaptcha.verify("1234");

//        ShearCaptcha 扭曲干扰验证码
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 4);
        captcha.write("/Users/lin/Downloads/common/line4.png");
        captcha.verify("1234");

//        自定义验证码
//        RandomGenerator generator = new RandomGenerator("0123456789", 4);
//        CircleCaptcha captcha1 = CaptchaUtil.createCircleCaptcha(200, 100);
//        captcha1.setGenerator(generator);
//        captcha1.createCode();

    }

身份证校验工具

    /**
     * IdcardUtil现在支持大陆15位、18位身份证,港澳台10位身份证。
     *
     * isValidCard 验证身份证是否合法
     * convert15To18 身份证15位转18位
     * getBirthByIdCard 获取生日
     * getAgeByIdCard 获取年龄
     * getYearByIdCard 获取生日年
     * getMonthByIdCard 获取生日月
     * getDayByIdCard 获取生日天
     * getGenderByIdCard 获取性别
     * getProvinceByIdCard 获取省份
     *
     */
@Test
    void IDCard (){
        String card="321083197812162119";
        boolean validCard = IdcardUtil.isValidCard(card);
        System.out.println(IdcardUtil.getProvinceByIdCard(card));
        System.out.println(validCard);
    }

图片处理

@Test
    void pressImage() throws IOException {
        // 旋转180度
        BufferedImage image = (BufferedImage) ImgUtil.rotate(ImageIO.read(FileUtil.file("/Users/linyanxia/Downloads/common/3.jpeg")), 180);
        ImgUtil.write(image, FileUtil.file("/Users/linyanxia/Downloads/common/4.jpeg"));

        // gray 彩色转为黑白
        ImgUtil.gray(FileUtil.file("/Users/linyanxia/Downloads/common/3.jpeg"), FileUtil.file("/Users/linyanxia/Downloads/common/5.jpeg"));

        // pressText 添加文字水印
        ImgUtil.pressText(//
                FileUtil.file("/Users/linyanxia/Downloads/common/3.jpeg"), //
                FileUtil.file("/Users/linyanxia/Downloads/common/6.jpeg"), //
                "版权所有", Color.WHITE, //文字
                new Font("黑体", Font.BOLD, 100), //字体
                0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
                0, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
                0.8f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
        );

        // flip 水平翻转图片
        ImgUtil.flip(FileUtil.file("/Users/linyanxia/Downloads/common/3.jpeg"), FileUtil.file("/Users/linyanxia/Downloads/common/7.jpeg"));

        // scale 缩放图片
        ImgUtil.scale(
                FileUtil.file("/Users/linyanxia/Downloads/common/4.jpeg"),
                FileUtil.file("/Users/linyanxia/Downloads/common/8.jpeg"),
                0.5f//缩放比例
        );
    }

解决跨域

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    /**
     * 解决拦截器无法注入的问题
     * @return
     */
    @Bean
    public HandlerInterceptor getTokenInterceptor(){
        return new TokenInterceptor();
    }

 /**
     * 配置拦截器、拦截路径
     * 每次请求到拦截的路径,就会去执行拦截器中的方法
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List<String> excludePath = new ArrayList<>();
        //排除拦截,除了注册登录(此时还没token),其他都拦截
        excludePath.add("/login");  //登录
        excludePath.add("/register");     //注册
        excludePath.add("/doc.html");     //swagger
        excludePath.add("/swagger-ui.html");     //swagger
        excludePath.add("/swagger-resources/**");     //swagger
        excludePath.add("/v2/api-docs");     //swagger
        excludePath.add("/webjars/**");     //swagger
//        excludePath.add("/static/**");  //静态资源
//        excludePath.add("/assets/**");  //静态资源
        registry.addInterceptor(getTokenInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(excludePath);
        WebMvcConfigurer.super.addInterceptors(registry);

    }


    /**
     * 解决跨域请求
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedHeaders("*")
                .allowedMethods("*")
//                .allowedOrigins("*")
                .allowedOriginPatterns("*")
                .allowCredentials(true);
    }

}

线程池调用(定长线程池)

public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) pool;
        poolExecutor.execute(new Number01());
        poolExecutor.execute(new Number02());
        poolExecutor.shutdown();
    }
}
class Number01 implements Runnable{
    private int ticket=100;
    @Override
    public void run() {
        while (true){
            if (ticket>0){
                System.out.println(Thread.currentThread().getName()+"   当前数量    "+ticket);
                ticket--;
            }else {
                break;
            }
        }
    }
}

class Number02 implements Runnable{
    private int ticket=100;
    @Override
    public void run() {
        while (true){
            if (ticket>0){
                System.out.println(Thread.currentThread().getName()+"   当前数量    "+ticket);
                ticket--;
            }else {
                break;
            }
        }
    }
}

SM2加密解密
密钥生成:https://i.goto327.top/CryptTools/SM2.aspx?tdsourcetag=s_pctim...

public class SM2Utils {

    private static final String privateKeyHex = "AB1032030D6901E0AF1511E73C5C089C8566AAC4F71D843495FEACAB6F76F4B0";
    private static final String x = "B4CFEB0485A9E835B2FA7604759DD42853E630709AA42349A40624D2F1CD1AC7";
    private static final String y = "7C0E2D8B9E0D8C2054DF73B656A8D0724CB13F463994E3F749DAAA3B95F85484";
    private static final SM2 getSm2 = new SM2(privateKeyHex, x, y);

    private static final String privateKeySign = "AB1032030D6901E0AF1511E73C5C089C8566AAC4F71D843495FEACAB6F76F4B0";
    private static final String Signx = "B4CFEB0485A9E835B2FA7604759DD42853E630709AA42349A40624D2F1CD1AC7";
    private static final String Signy = "7C0E2D8B9E0D8C2054DF73B656A8D0724CB13F463994E3F749DAAA3B95F85484";
    private static final SM2 getSign = new SM2(privateKeySign, Signx, Signy);

    /**
     * 加密
     * @param password
     * @return
     */
    public static String publicPassword(String password){
        String encryptionPassword = getSm2.encryptBcd(password, KeyType.PublicKey);
        return encryptionPassword;
    }

    /**
     * 解密
     * @param password
     * @return
     */
    public static String privatePassword(String password){
        String decryptPassword = StrUtil.utf8Str(getSm2.decryptFromBcd(password, KeyType.PrivateKey));
        return decryptPassword;
    }


    /**
     * 加密
     * @param password
     * @return
     */
    public static String publicSign(String password){
        String encryptionPassword = getSign.encryptBcd(password, KeyType.PublicKey);
        return encryptionPassword;
    }

    /**
     * 解密
     * @param password
     * @return
     */
    public static String privateSign(String password){
        String decryptPassword = StrUtil.utf8Str(getSign.decryptFromBcd(password, KeyType.PrivateKey));
        return decryptPassword;
    }

}

LLL_
15 声望3 粉丝