侧边栏壁纸
“学习日记” 共(28)篇
  • 数据库加密工具类编写(springboot) 在配置文件中,明文编写一些敏感数据是不安全的,所以通常会进行加密,这里我使用druid连接池的工具来进行加密处理package com.jingdianjichi.subject.infra.basic.service.utils; import com.alibaba.druid.filter.config.ConfigTools; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; public class DruidEncryptUtil { private static String publicKey; private static String privateKey; static { try { String[] keyPair = ConfigTools.genKeyPair(512); privateKey = keyPair[0]; System.out.println("privateKey:" + privateKey); publicKey = keyPair[1]; System.out.println("publicKey:" + publicKey); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { throw new RuntimeException(e); } } public static String encrypt(String plainText) throws Exception { String encrypt = ConfigTools.encrypt(privateKey, plainText); System.out.println("encrypt:" + encrypt); return encrypt; } public static String decrypt(String encryptText) throws Exception { String decrypt = ConfigTools.decrypt(publicKey, encryptText); System.out.println("decrypt:" + decrypt); return decrypt; } public static void main(String[] args) throws Exception { //这里我设置的密码是123456 String encrypt = encrypt("123456"); System.out.println("encrypt:" + encrypt); } } 运行此类后,控制台将打印出私钥和公钥以及解密后的密文,随后将相应数据填入yml配置文件中。password放密文;publicKey放公钥;还需要配置config:enabled以及connect-propertie;如下所示server: port: 3000 spring: datasource: username: root password: da6IO6pMIxKQS2Ir2E2WHVChJCBM++Jj86xWX8QFUC9P8GWwVmUI6JcC9eiS4CvC6OYdslgQX0CS0Bkr+9VGhQ== url: jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&useSSL=true driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: # 初始的连接数量 initial-size: 20 # 最小的空闲连接数 min-idle: 20 # 最大的活动连接数 max-active: 100 # 最大等待时间 max-wait: 60000 # 启用统计功能 stat-view-servlet: enabled: true # 统计功能的URL模式 url-pattern: /druid public class BaoZiPu { //代表包子的count private int count; //代表是否有包子的flag private boolean flag; public BaoZiPu() { } public BaoZiPu(int count, boolean flag) { this.count = count; this.flag = flag; } public void getCount() { System.out.println("消费了..............第"+count+"个包子"); } public void setCount() { count++; System.out.println("生产了...第"+count+"个包子"); } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } } public class Product implements Runnable{ private BaoZiPu baoZiPu; public Product(BaoZiPu baoZiPu) { this.baoZiPu = baoZiPu; } @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (baoZiPu){ //1.判断flag是否为true,如果是true,证明有包子,生产线程等待 if (baoZiPu.isFlag()==true){ try { baoZiPu.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //2.如果flag为false,证明没有包子,开始生产 baoZiPu.setCount(); //3.改变flag状态,为true,证明生产完了,有包子了 baoZiPu.setFlag(true); //4.唤醒消费线程 baoZiPu.notify(); } } } } public class Consumer implements Runnable{ private BaoZiPu baoZiPu; public Consumer(BaoZiPu baoZiPu) { this.baoZiPu = baoZiPu; } @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (baoZiPu){ //1.判断flag是否为false,如果是false,证明没有包子,消费线程等待 if (baoZiPu.isFlag()==false){ try { baoZiPu.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //2.如果flag为true,证明有包子,开始消费 baoZiPu.getCount(); //3.改变flag状态,为false,证明消费完了,没 有包子了 baoZiPu.setFlag(false); //4.唤醒生产线程 baoZiPu.notify(); } } } } public class Test01 { public static void main(String[] args) { BaoZiPu baoZiPu = new BaoZiPu(); Product product = new Product(baoZiPu); Consumer consumer = new Consumer(baoZiPu); Thread t1 = new Thread(product); Thread t2 = new Thread(consumer); t1.start(); t2.start(); } }3.用同步方法改造等待唤醒案例 public class BaoZiPu { //代表包子的count private int count; //代表是否有包子的flag private boolean flag; public BaoZiPu() { } public BaoZiPu(int count, boolean flag) { this.count = count; this.flag = flag; } public synchronized void getCount() { //1.判断flag是否为false,如果是false,证明没有包子,消费线程等待 if (this.flag == false) { try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //2.如果flag为true,证明有包子,开始消费 System.out.println("消费了..............第" + count + "个包子"); //3.改变flag状态,为false,证明消费完了,没 有包子了 this.flag = false; //4.唤醒生产线程 this.notify(); } public synchronized void setCount() { //1.判断flag是否为true,如果是true,证明有包子,生产线程等待 if (this.flag == true) { try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //2.如果flag为false,证明没有包子,开始生产 count++; System.out.println("生产了...第" + count + "个包子"); //3.改变flag状态,为true,证明生产完了,有包子了 this.flag = true; //4.唤醒消费线程 this.notify(); } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } } public class Product implements Runnable{ private BaoZiPu baoZiPu; public Product(BaoZiPu baoZiPu) { this.baoZiPu = baoZiPu; } @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } baoZiPu.setCount(); } } } public class Consumer implements Runnable{ private BaoZiPu baoZiPu; public Consumer(BaoZiPu baoZiPu) { this.baoZiPu = baoZiPu; } @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } baoZiPu.getCount(); } } } public class Test01 { public static void main(String[] args) { BaoZiPu baoZiPu = new BaoZiPu(); Product product = new Product(baoZiPu); Consumer consumer = new Consumer(baoZiPu); Thread t1 = new Thread(product); Thread t2 = new Thread(consumer); t1.start(); t2.start(); } }第二章.多等待多唤醒1.解决多生产多消费问题(if改为while,将notify改为notifyAll)public class Test01 { public static void main(String[] args) { BaoZiPu baoZiPu = new BaoZiPu(); Product product = new Product(baoZiPu); Consumer consumer = new Consumer(baoZiPu); new Thread(product).start(); new Thread(product).start(); new Thread(product).start(); new Thread(consumer).start(); new Thread(consumer).start(); new Thread(consumer).start(); } } public class BaoZiPu { //代表包子的count private int count; //代表是否有包子的flag private boolean flag; public BaoZiPu() { } public BaoZiPu(int count, boolean flag) { this.count = count; this.flag = flag; } public synchronized void getCount() { //1.判断flag是否为false,如果是false,证明没有包子,消费线程等待 while (this.flag == false) { try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //2.如果flag为true,证明有包子,开始消费 System.out.println("消费了..............第" + count + "个包子"); //3.改变flag状态,为false,证明消费完了,没 有包子了 this.flag = false; //4.唤醒所有等待线程 this.notifyAll(); } public synchronized void setCount() { //1.判断flag是否为true,如果是true,证明有包子,生产线程等待 while (this.flag == true) { try { this.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } //2.如果flag为false,证明没有包子,开始生产 count++; System.out.println("生产了...第" + count + "个包子"); //3.改变flag状态,为true,证明生产完了,有包子了 this.flag = true; //4.唤醒所有等待线程 this.notifyAll(); } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } } public class Product implements Runnable{ private BaoZiPu baoZiPu; public Product(BaoZiPu baoZiPu) { this.baoZiPu = baoZiPu; } @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } baoZiPu.setCount(); } } } public class Consumer implements Runnable{ private BaoZiPu baoZiPu; public Consumer(BaoZiPu baoZiPu) { this.baoZiPu = baoZiPu; } @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } baoZiPu.getCount(); } } } 第三章.Lock锁1.Lock对象的介绍和基本使用1.概述:Lock是一个接口 2.实现类:ReentrantLock 3.方法: lock() 获取锁 unlock() 释放锁public class MyTicket implements Runnable { //定义100张票 int ticket = 100; //创建Lock对象 Lock lock = new ReentrantLock(); @Override public void run() { while (true) { try { Thread.sleep(100L); //获取锁 lock.lock(); if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票"); ticket--; } } catch (InterruptedException e) { throw new RuntimeException(e); }finally { //释放锁 lock.unlock(); } } } } public class Test01 { public static void main(String[] args) { MyTicket myTicket = new MyTicket(); Thread t1 = new Thread(myTicket, "赵四"); Thread t2 = new Thread(myTicket, "刘能"); Thread t3 = new Thread(myTicket, "广坤"); t1.start(); t2.start(); t3.start(); } } synchronized:不管是同步代码块还是同步方法,都需要在结束一对{}之后,释放锁对象 Lock:是通过两个方法控制需要被同步的代码,更灵活第四章.Callable接口_实现多线程方式三1.概述:Callable<V>是一个接口,类似于Runnable 2.方法: V call() -> 设置线程任务的,类似于run方法 3.call方法和run方法的区别: a.相同点:都是设置线程任务的 b.不同点: call方法有返回值,而且有异常可以throws run方法没有返回值,而且有异常不可以throws 4.<V> a.<V>叫做泛型 b.泛型:用于指定我们操作什么类型的数据,<>中只能写引用数据类型,如果泛型不写,默认是Object类型数据 c.实现Callable接口时,指定泛型是什么类型的,重写的call方法返回值就是什么类型的 5.获取call方法返回值: FutureTask<V> a. FutureTask<V> 实现了一个接口: Future <V> b. FutureTask<V>中有一个方法: V get() -> 获取call方法的返回值public class MyCallable implements Callable<String> { @Override public String call() throws Exception { return "涛哥和金莲...的故事"; } }public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { MyCallable myCallable = new MyCallable(); FutureTask<String> futureTask = new FutureTask<>(myCallable); //创建Thread对象-> Thread(Runnable target) Thread t1 = new Thread(futureTask); t1.start(); //调用get方法获取call方法返回值 System.out.println(futureTask.get()); } } 第五章.线程池_实现多线程方式四1.问题:之前来一个线程任务,就需要创建一个线程对象去执行,用完还要销毁线程对象,如果线程任务多了,就需要频繁创建线程对象和销毁线程对象,这样会耗费内存资源,所以我们就想线程对象能不能循环利用,用的时候直接拿线程对象,用完还回去1.如何创建线程池对象:用具类-> Executors 2.获取线程池对象:Executors中的静态方法: static ExecutorService newFixedThreadPool(int nThreads) a.参数:指定线程池中最多创建的线程对象条数 b.返回值ExecutorService 是线程池,用来管理线程对象 3.执行线程任务: ExecutorService中的方法 Future<?> submit(Runnable task) 提交一个Runnable任务用于执行 Future<T> submit(Callable<T> task) 提交一个Callable任务用于执行 4.submit方法的返回值:Future接口 用于接收run方法或者call方法返回值的,但是run方法没有返回值,所以可以不用Future接收,执行call方法需要用Future接收 Future中有一个方法:V get() 用于获取call方法返回值 5. ExecutorService中的方法: void shutdown() 启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务public class MyRunnable implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"...执行了"); } }public class Test01 { public static void main(String[] args) { //创建线程池对象 ExecutorService es = Executors.newFixedThreadPool(2); es.submit(new MyRunnable()); es.submit(new MyRunnable()); es.submit(new MyRunnable()); //es.shutdown();//关闭线程池对象 } }public class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { return 1; } }public class Test02 { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService es = Executors.newFixedThreadPool(2); Future<Integer> future = es.submit(new MyCallable()); System.out.println(future.get()); } } 练习需求:创建两个线程任务,一个线程任务完成1-100的和,一个线程任务返回一个字符串public class MyString implements Callable<String> { @Override public String call() throws Exception { return "那一夜,你没有拒绝我,那一夜,你伤害了我"; } }public class MySum implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 1; i <= 100; i++) { sum+=i; } return sum; } }public class Test01 { public static void main(String[] args) throws ExecutionException, InterruptedException { //创建线程池对象 ExecutorService es = Executors.newFixedThreadPool(2); Future<String> f1 = es.submit(new MyString()); Future<Integer> f2 = es.submit(new MySum()); System.out.println(f1.get()); System.out.println(f2.get()); } }第六章.定时器_Timer1.概述:定时器 2.构造: Timer() 3.方法: void schedule(TimerTask task, Date firstTime, long period) task:抽象类,是Runnable的实现类 firstTime:从什么时间开始执行 period: 每隔多长时间执行一次,设置的是毫秒值 public class Demo01Timer { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("金莲对涛哥说:涛哥,快起床了~~~"); } },new Date(),2000L); } }
    • 1个月前
    • 84
    • 2
    • 0
  • 尚硅谷java多线程笔记(上) java多线程 重点: 1.会使用多线程方法,主要是start() 2.会使用继承Thread的方式创建多线程 3.会使用实现Runnable接口的方式实现多线程 4.会使用同步代码块解决线程不安全问题 5.会使用同步方法解决线程不安全问题第一章.多线程基本了解1.多线程_线程和进程进程:在内存中执行的应用程序线程:是进程中最小的执行单元 线程作用:负责当前进程中程序的运行.一个进程中至少有一个线程,一个进程还可以有多个线程,这样的应用程序就称之为多线程程序 简单理解:一个功能就需要一条线程取去执行 1.使用场景: 软件中的耗时操作 -> 拷贝大文件, 加载大量的资源​ 所有的聊天软件​ 所有的后台服务器​ 一个线程可以干一件事,我们就可以同时做多件事了,提高了CPU的利用率2.并发和并行并行:在同一个时刻,有多个执行在多个CPU上(同时)执行(好比是多个人做不同的事儿) 比如:多个厨师在炒多个菜并发:在同一个时刻,有多个指令在单个CPU上(交替)执行 比如:一个厨师在炒多个菜细节: 1.之前CPU是单核,但是在执行多个程序的时候好像是在同时执行,原因是CPU在多个线程之间做高速切换 2.现在咱们的CPU都是多核多线程的了,比如2核4线程,那么CPU可以同时运行4个线程,此时不同切换,但是如果多了,CPU就要切换了,所以现在CPU在执行程序的时候并发和并行都存在 3.CPU调度1.分时调度:值的是让所有的线程轮流获取CPU使用权,并且平均分配每个线程占用CPU的时间片 2.抢占式调度:多个线程轮流抢占CPU使用权,哪个线程先抢到了,哪个线程先执行,一般都是优先级高的先抢到CPU使用权的几率大,我们java程序就是抢占式调度 4.主线程介绍主线程:CPU和内存之间开辟的转门为main方法服务的线程第二章.创建线程的方式(重点)1.第一种方式_extends Thread1.定义一个类,继承Thread 2.重写run方法,在run方法中设置线程任务(所谓的线程任务指的是此线程要干的具体的事儿,具体执行的代码) 3.创建自定义线程类的对象 4.调用Thread中的start方法,开启线程,jvm自动调用run方法public class Test01 { public static void main(String[] args) { //创建线程对象 MyThread t1 = new MyThread(); //调用start方法,开启线程,jvm自动调用run方法 t1.start(); for (int i = 0; i < 10; i++) { System.out.println("main线程..........执行了"+i); } } }public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("MyThread...执行了"+i); } } }2.多线程在内存中的运行原理注意:同一个线程对象不能连续调用多次start,如果想要再次调用start,那么咱们就new一个新的线程对象3.Thread类中的方法void start() -> 开启线程,jvm自动调用run方法 void run() -> 设置线程任务,这个run方法是Thread重写的接口Runnable中的run方法 String getName() -> 获取线程名字 void setName(String name) -> 给线程设置名字 static Thread currentThread() -> 获取正在执行的线程对象(此方法在哪个线程中使用,获取的就是哪个线程对象) static void sleep(long millis)->线程睡眠,超时后自动醒来继续执行,传递的是毫秒值 public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { //线程睡眠 try { Thread.sleep(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()+"...执行了"+i); } } } public class Test01 { public static void main(String[] args) throws InterruptedException { //创建线程对象 MyThread t1 = new MyThread(); //给线程设置名字 t1.setName("金莲"); //调用start方法,开启线程,jvm自动调用run方法 t1.start(); for (int i = 0; i < 10; i++) { Thread.sleep(1000L); System.out.println(Thread.currentThread().getName()+"线程..........执行了"+i); } } } 问题:为啥在重写的run方法中有异常只能try,不能throws原因:继承的Thread中的run方法没有抛异常,所以在子类中重写完run方法之后就不能抛,只能try4.Thread中其他的方法void setPriority(int newPriority) -> 设置线程优先级,优先级越高的线程,抢到CPU使用权的几率越大,但是不是每次都先抢到 int getPriority() -> 获取线程优先级 void setDaemon(boolean on) -> 设置为守护线程,当非守护线程执行完毕,守护线程就要结束,但是守护线程也不是立马结束,当非守护线程结束之后,系统会告诉守护线程人家结束了,你也结束吧,在告知的过程中,守护线程会执行,只不过执行到半路就结束了 static void yield() -> 礼让线程,让当前线程让出CPU使用权 void join() -> 插入线程或者叫做插队线程 4.1.线程优先级public class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"执行了......"+i); } } }public class Test01 { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); t1.setName("金莲"); MyThread1 t2 = new MyThread1(); t2.setName("阿庆"); //System.out.println(t1.getPriority()); //System.out.println(t2.getPriority()); //设置优先级 t1.setPriority(1); t2.setPriority(10); t1.start(); t2.start(); } } 4.2.守护线程public class Test01 { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); t1.setName("金莲"); MyThread2 t2 = new MyThread2(); t2.setName("阿庆"); //将t2设置成守护线程 t2.setDaemon(true); t1.start(); t2.start(); } } public class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"执行了......"+i); } } }public class MyThread2 extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName()+"执行了..."+i); } } } 4.3.礼让线程场景说明:如果两个线程一起执行,可能会执行一会儿线程A,再执行一会线程B,或者可能线程A执行完毕了,线程B在执行 那么我们能不能让两个线程尽可能的平衡一点 -> 尽量让两个线程交替执行 注意:只是尽可能的平衡,不是绝对的你来我往,有可能线程A线程执行,然后礼让了,但是回头A又抢到CPU使用权了 public class Test01 { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); t1.setName("金莲"); MyThread1 t2 = new MyThread1(); t2.setName("阿庆"); t1.start(); t2.start(); } }public class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"执行了......"+i); Thread.yield(); } } } 4.4.插入线程public class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"执行了......"+i); } } }public class Test01 { public static void main(String[] args) throws InterruptedException { MyThread1 t1 = new MyThread1(); t1.setName("金莲"); t1.start(); t1.join(); for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"执行了......"+i); } } }5.第二种方式_实现Runnable接口1.创建类,实现Runnable接口 2.重写run方法,设置线程任务 3.利用Thread类的构造方法:Thread(Runnable target),创建Thread对象(线程对象),将自定义的类当参数传递到Thread构造中 -> 这一步是让我们自己定义的类成为一个真正的线程类对象 4.调用Thread中的start方法,开启线程,jvm自动调用run方法 public class Test01 { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread t1 = new Thread(myRunnable); //调用Thread中的start方法,开启线程 t1.start(); for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"...执行了"+i); } } }public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"...执行了"+i); } } }6.两种实现多线程的方式区别1.继承Thread:继承只支持单继承,有继承的局限性 2.实现Runnable:没有继承的局限性, MyThread extends Fu implements Runnable7.第三种方式_匿名内部类创建多线程严格意义上来说,匿名内部类方式不属于创建多线程方式其中之一,因为匿名内部类形式建立在实现Runnable接口的基础上完成的匿名内部类回顾: 1.new 接口/抽象类(){ 重写方法 }.重写的方法(); 2.接口名/类名 对象名 = new 接口/抽象类(){ 重写方法 } 对象名.重写的方法();public class Test02 { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"...执行了"+i); } } },"阿庆").start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"...执行了"+i); } } },"金莲").start(); } } 第三章.线程安全1.什么时候发生:当多个线程访问同一个资源时,导致了数据有问题1.线程安全问题-->线程不安全的代码public class MyTicket implements Runnable{ //定义100张票 int ticket = 100; @Override public void run() { while(true){ if (ticket>0){ System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票"); ticket--; } } } } public class Test01 { public static void main(String[] args) { MyTicket myTicket = new MyTicket(); Thread t1 = new Thread(myTicket, "赵四"); Thread t2 = new Thread(myTicket, "刘能"); Thread t3 = new Thread(myTicket, "广坤"); t1.start(); t2.start(); t3.start(); } }原因:CPU在多个线程之间做高速切换导致的2.解决线程安全问题的第一种方式(使用同步代码块)1.格式: synchronized(任意对象){ 线程可能出现不安全的代码 } 2.任意对象:就是我们的锁对象 3.执行: 一个线程拿到锁之后,会进入到同步代码块中执行,在此期间,其他线程拿不到锁,就进不去同步代码块,需要在同步代码块外面等待排队,需要等着执行的线程执行完毕,出了同步代码块,相当于释放锁了,等待的线程才能抢到锁,才能进入到同步代码块中执行public class MyTicket implements Runnable{ //定义100张票 int ticket = 100; //任意new一个对象 Object obj = new Object(); @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (obj){ if (ticket>0){ System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票"); ticket--; } } } } }public class Test01 { public static void main(String[] args) { MyTicket myTicket = new MyTicket(); Thread t1 = new Thread(myTicket, "赵四"); Thread t2 = new Thread(myTicket, "刘能"); Thread t3 = new Thread(myTicket, "广坤"); t1.start(); t2.start(); t3.start(); } }3.解决线程安全问题的第二种方式:同步方法3.1.普通同步方法_非静态1.格式: 修饰符 synchronized 返回值类型 方法名(参数){ 方法体 return 结果 } 2.默认锁:thispublic class MyTicket implements Runnable{ //定义100张票 int ticket = 100; @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } //method01(); method02(); } } public void method02(){ synchronized(this){ System.out.println(this+".........."); if (ticket>0){ System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票"); ticket--; } } } } public class Test01 { public static void main(String[] args) { MyTicket myTicket = new MyTicket(); System.out.println(myTicket); Thread t1 = new Thread(myTicket, "赵四"); Thread t2 = new Thread(myTicket, "刘能"); Thread t3 = new Thread(myTicket, "广坤"); t1.start(); t2.start(); t3.start(); } } 3.2.静态同步方法1.格式: 修饰符 static synchronized 返回值类型 方法名(参数){ 方法体 return 结果 } 2.默认锁:class对象public class MyTicket implements Runnable{ //定义100张票 static int ticket = 100; @Override public void run() { while(true){ try { Thread.sleep(100L); } catch (InterruptedException e) { throw new RuntimeException(e); } //method01(); method02(); } } public static void method02(){ synchronized(MyTicket.class){ if (ticket>0){ System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票"); ticket--; } } } }public class Test01 { public static void main(String[] args) { MyTicket myTicket = new MyTicket(); Thread t1 = new Thread(myTicket, "赵四"); Thread t2 = new Thread(myTicket, "刘能"); Thread t3 = new Thread(myTicket, "广坤"); t1.start(); t2.start(); t3.start(); } } 第四章.死锁(了解)1.死锁介绍(锁嵌套就有可能产生死锁)指的是两个或者两个以上的线程在执行的过程中由于竞争同步锁而产生的一种阻塞现象;如果没有外力的作用,他们将无法继续执行下去,这种情况称之为死锁根据上图所示:线程1正在持有锁1,但是线程1必须再拿到锁2,才能继续执行 而线程2正在持有锁2,但是线程2需要再拿到锁1,才能继续执行 此时两个线程处于互相等待的状态,就是死锁,在程序中的死锁将出现在同步代码块的嵌套中2.死锁的分析3.代码实现public class LockA { public static LockA lockA = new LockA(); } public class LockB { public static LockB lockB = new LockB(); }public class DieLock implements Runnable{ private boolean flag; public DieLock(boolean flag) { this.flag = flag; } @Override public void run() { if (flag){ synchronized (LockA.lockA){ System.out.println("if...lockA"); synchronized (LockB.lockB){ System.out.println("if...lockB"); } } }else{ synchronized (LockB.lockB){ System.out.println("else...lockB"); synchronized (LockA.lockA){ System.out.println("else...lockA"); } } } } } public class Test01 { public static void main(String[] args) { DieLock dieLock1 = new DieLock(true); DieLock dieLock2 = new DieLock(false); new Thread(dieLock1).start(); new Thread(dieLock2).start(); } } 只需要知道死锁出现的原因即可(锁嵌套),以后尽量避免锁嵌套第五章.线程状态1.线程状态介绍 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,有几种状态呢?在API中java.lang.Thread.State这个枚举中给出了六种线程状态: 这里先列出各个线程状态发生的条件,下面将会对每种状态进行详细解析。线程状态导致状态发生条件NEW(新建)线程刚被创建,但是并未启动。还没调用start方法。Runnable(可运行)线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。Blocked(锁阻塞)当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。Waiting(无限等待)一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。Timed Waiting(计时等待)同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。Terminated(被终止)因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。或者调用过时方法stop()
    • 1个月前
    • 70
    • 1
    • 0
  • JDBC三种参数传入方式 第一种(三种参数)三种参数分别是URL,user,password//当数据库ip和端口为本机3306端口(localhost:3306/127.0.0.1:3306)时,可省略为“/” Connection connection = DriverManager.getConnection("jdbc:mysql:///example","root","123456");第二种(两种参数)两种参数分别是URL和外部文件Properties info = new Properties(); //这里模拟外部文件 info.put("user","root"); info.put("password","123456"); Connection connection = DriverManager.getConnection("jdbc:mysql:///example", info);第三种(一个参数)URLConnection connection = DriverManager.getConnection("jdbc:mysql:///example?user=root&password=123456");URL参数以下是MySQL 8及更新版本中用于URL的常见属性设置:属性描述user数据库连接的用户名。password连接数据库所需的密码。host数据库主机地址或IP地址。port数据库服务器监听的端口号。database要连接的数据库名称。sslmodeSSL连接模式,可能的值包括:'DISABLED'(禁用SSL)、'REQUIRED'(必须启用SSL)、'VERIFY_CA'(验证CA)、'VERIFY_IDENTITY'(验证身份)。sslcert客户端SSL证书文件的路径。sslkey客户端SSL私钥文件的路径。sslrootcert用于验证服务器证书的CA证书文件的路径。charset连接使用的字符集。connectTimeout连接超时时间,以秒为单位。maxRetryDelay在重新连接之前的最大延迟时间,以毫秒为单位。loginTimeout登录超时时间,以秒为单位。socketTimeout套接字超时时间,以毫秒为单位。allowPublicKeyRetrieval是否允许在安全连接期间从服务器检索公钥。useSSL是否使用SSL连接。allowLoadLocalInfile是否允许使用LOAD DATA LOCAL INFILE语句。serverSslCert服务器SSL证书文件的路径。serverSslKey服务器SSL私钥文件的路径。serverSslCaCert服务器SSL CA证书文件的路径。useAffectedRows是否使用受影响的行数作为UPDATE和DELETE查询的返回值。readOnly是否将连接设置为只读模式。allowPublicKeyRetrieval是否允许在安全连接期间从服务器检索公钥。useCursorFetch是否使用游标获取来提取大结果集。useCursorFetch是否使用游标获取来提取大结果集。socket指定连接到MySQL服务器的UNIX套接字文件的路径。以上是常用的一些属性设置,具体可以根据实际情况进行配置。
    • 2个月前
    • 81
    • 0
    • 1
  • JDBC的基本使用 JDBC使用教程JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、特定网络和特定硬件平台的接口,用于执行SQL语句。以下是使用JDBC的基本步骤:1. 注册驱动要与数据库建立连接,首先需要注册数据库的驱动。这一步是告诉Java应用程序要连接的数据库类型。try{ // 加载数据库驱动类 //DriverManager.registerDriver(new Driver())这一步在驱动4+版本已不是必须的 //驱动版本8+:com.mysql.cj.jdbc.Driver //驱动版本5+:com.mysql.jdbc.Driver forName("com.mysql.cj.jdbc.Driver") ; } catch (ClassNotFoundException e) { e. printStackTrace(); }这里以MySQL为例,com.mysql.jdbc.Driver是MySQL的驱动类名称。2.获取连接注册驱动后,下一步是使用DriverManager获取数据库连接。String url = "jdbc:mysql://localhost:3306/数据库名?useSSL=false" ; String username = "用户名" ; String password = "密码" ; try{ Connection conn = DriverManager.getConnection (url, username, password) ; } catch (SQLException e){ e. printStackTrace(); }网址是数据库的URL,其中包含数据库的地址、端口号和数据库名。用户名和密码分别是数据库登录的用户名和密码。3.创建发送SQL语句的对象有了数据库连接后,需要创建一个用于发送SQL语句的对象。try (Connection conn = DriverManager.getConnection ( url ,username,password) ) {​ Statement stmt = conn.createStatement() ; } catch (SQLException e){ e.printStackTrace(); }Statement对象用于执行静态SQL语句并返回其生成的结果。4.发送SQL语句,获取返回结果通过Statement对象发送SQL语句结果,并接收查询。String sql = "SELECT * FROM 表名" ; try (Connection conn = DriverManager.getConnection (url ,username,password) ;​ Statement stmt = conn.createStatement()){ ResultSet rs = stmt.executeQuery(sql) ; // 处理结果集 } catch (SQLException e){ e.printStackTrace(); }5.结果集解析获取到结果集后,可以搜索结果集获取数据。try (Connection conn = DriverManager.getConnection (url ,username,password) ;​ Statement stmt = conn.createStatement( ) ; ResultSet rs = stmt.executeQuery(sql)){ while (rs.next()){ // 通过列名或列索引获取数据 String data = rs.getString("列名"); // 处理数据 } } catch (SQLException e) { e.printStackTrace(); }6. 资源关闭最后,确保打开的数据库资源被关闭,避免内存泄漏。try (Connection conn = DriverManager.getConnection (url ,username,password) ;​ Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)){ // 使用资源 // 手动关闭 //rs.close(); //stmt.close(); //conn.close() } catch ( SQLException e ) { e.printStackTrace(); } // 自动关闭资源,因为使用了try-with-resources语句 使用try-with-resources语句可以自动关闭资源,这是Java 7及以上版本提供的功能,可以自动管理资源的关闭。statement接口常用方法以下是 JDBC 中 Statement 接口常用的方法及其功能的详细解释:方法描述execute(String sql)在数据库中执行给定的 SQL 语句,可以是任何类型的 SQL 语句(例如,SELECT、INSERT、UPDATE、DELETE),返回一个 boolean 值,指示第一个结果是一个 ResultSet 对象还是更新计数或没有结果。executeQuery(String sql)在数据库中执行给定的 SELECT 语句,返回一个 ResultSet 对象,它包含满足查询条件的结果集。executeUpdate(String sql)在数据库中执行给定的 INSERT、UPDATE 或 DELETE 语句,或者是 SQL 数据定义语言(DDL)语句,例如 CREATE TABLE、ALTER TABLE、DROP TABLE 等。返回一个整数,表示受影响的行数。addBatch(String sql)将 SQL 语句添加到批处理中,以便一次性执行多个 SQL 语句。clearBatch()清除当前的批处理命令列表。executeBatch()执行当前的批处理中的所有 SQL 语句。close()关闭该 Statement 对象。getResultSet()获取当前结果集(如果有)。getUpdateCount()获取受上一条 SQL 语句影响的行数。getMoreResults()将当前结果集关闭,并将游标移动到下一个结果集(如果有)。getGeneratedKeys()获取由数据库自动生成的键,如果上一条 SQL 语句执行的是插入语句,并且指定了自动生成键的字段,则返回包含生成键的 ResultSet 对象。setFetchSize(int rows)设置获取的行数。setMaxRows(int max)设置最大的结果集行数限制。setQueryTimeout(int seconds)设置查询的超时时间(以秒为单位)。getFetchSize()获取获取的行数。getMaxRows()获取结果集的最大行数限制。getQueryTimeout()获取查询的超时时间(以秒为单位)。
    • 2个月前
    • 70
    • 0
    • 1
  • JAVA 的多线程编程 java的多线程编程下图展示了 java 线程的生命周期当我们只调用 run()方法时,线程并不会被启动,只会执行 run();只有当调用 start()方法时,线程才会被启动,并且调用 run()方法;我们常用的 public static void main(String[] args) main 其实是 java 中的主线程。java创建线程的三种方式通过实现 Runnable 接口 创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下:public void run()你可以重写该方法,重要的是理解的 run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。在创建一个实现 Runnable 接口的类之后,你可以在类中实例化一个线程对象。Thread 定义了几个构造方法,下面的这个是我们经常使用的: 教程参考菜鸟教程 Thread(Runnable threadOb,String threadName);这里,threadOb 是一个实现 Runnable 接口的类的实例,并且 threadName 指定新线程的名字。新线程创建之后,你调用它的 start() 方法它才会运行。 通过继承 Thread 类本身创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。class ThreadDemo extends Thread { private Thread t; private String threadName; ThreadDemo( String name) { threadName = name; System.out.println("Creating " + threadName ); } public void run() { System.out.println("Running " + threadName ); try { for(int i = 4; i > 0; i--) { System.out.println("Thread: " + threadName + ", " + i); // 让线程睡眠一会 Thread.sleep(50); } }catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); } public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class TestThread { public static void main(String args[]) { ThreadDemo T1 = new ThreadDemo( "Thread-1"); T1.start(); ThreadDemo T2 = new ThreadDemo( "Thread-2"); T2.start(); } }下表列出了Thread类的一些重要方法:序号方法描述1.使该线程开始执行;Java 虚拟机调用该线程的 run 方法public void start();2.如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回public void run();3.改变线程名称,使之与参数 name 相同。public final void setName(String name);4.更改线程的优先级。public final void setPriority(int priority);5.将该线程标记为守护线程或用户线程。public final void setDaemon(boolean on);6.等待该线程终止的时间最长为 millis 毫秒。public final void join(long millisec);7.中断线程。public void interrupt();8.测试线程是否处于活动状态。public final boolean isAlive();上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。序号方法描述1.暂停当前正在执行的线程对象,并执行其他线程。public static void yield()2.在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。public static void sleep(long millisec)3.当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。public static boolean holdsLock(Object x)4.返回对当前正在执行的线程对象的引用。public static Thread currentThread()5.将当前线程的堆栈跟踪打印至标准错误流。public static void dumpStack()方法演示// 文件名 : DisplayMessage.java // 通过实现 Runnable 接口创建线程 public class DisplayMessage implements Runnable { private String message; public DisplayMessage(String message) { this.message = message; } public void run() { while(true) { System.out.println(message); } } }// 文件名 : GuessANumber.java // 通过继承 Thread 类创建线程 public class GuessANumber extends Thread { private int number; public GuessANumber(int number) { this.number = number; } public void run() { int counter = 0; int guess = 0; do { guess = (int) (Math.random() * 100 + 1); System.out.println(this.getName() + " guesses " + guess); counter++; } while(guess != number); System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**"); } }// 文件名 : ThreadClassDemo.java public class ThreadClassDemo { public static void main(String [] args) { Runnable hello = new DisplayMessage("Hello"); Thread thread1 = new Thread(hello); thread1.setDaemon(true); thread1.setName("hello"); System.out.println("Starting hello thread..."); thread1.start(); Runnable bye = new DisplayMessage("Goodbye"); Thread thread2 = new Thread(bye); thread2.setPriority(Thread.MIN_PRIORITY); thread2.setDaemon(true); System.out.println("Starting goodbye thread..."); thread2.start(); System.out.println("Starting thread3..."); Thread thread3 = new GuessANumber(27); thread3.start(); try { thread3.join(); }catch(InterruptedException e) { System.out.println("Thread interrupted."); } System.out.println("Starting thread4..."); Thread thread4 = new GuessANumber(75); thread4.start(); System.out.println("main() is ending..."); } }通过 Callable 和 Future 创建线程创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。public class CallableThreadTest implements Callable<Integer> { public static void main(String[] args) { CallableThreadTest ctt = new CallableThreadTest(); FutureTask<Integer> ft = new FutureTask<>(ctt); for(int i = 0;i < 100;i++) { System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i); if(i==20) { new Thread(ft,"有返回值的线程").start(); } } try { System.out.println("子线程的返回值:"+ft.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } @Override public Integer call() throws Exception { int i = 0; for(;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); } return i; } }
    • 2个月前
    • 78
    • 0
    • 1
  • 软件测试省赛功能测试答案
    软件测试省赛功能测试答案 import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.By; import org.openqa.selenium.Alert; @SuppressWarnings("unused") public class Example { // Mooctest Selenium Example // <!> Check if selenium-standalone.jar is added to build path. public static void test(WebDriver driver) { // TODO Test script // eg:driver.get("https://www.baidu.com/") // eg:driver.findElement(By.id("wd")); try { driver.get("https://www.ifeng.com/"); driver.manage().window().maximize(); Thread.sleep(20000); driver.findElement(By.linkText("资讯")).click();//1咨询 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[1].toString()); Thread.sleep(1500); driver.findElement(By.linkText("新时代")).click();//2新时代 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[2].toString()); Thread.sleep(1500); driver.findElement(By.linkText("+ 更多新闻")).click();//3更多新闻 Thread.sleep(1500); driver.findElement(By.className("index_go_to_top_A0C-y")).click();//4置顶 Thread.sleep(1500); driver.findElement(By.linkText("凤凰资讯")).click();//5选择凤凰资讯 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[3].toString()); Thread.sleep(1500); // driver.findElement(By.className("index_checked_2L1JS")).click();//6站内框 // Thread.sleep(1500); // driver.findElement(By.linkText("站内")).click();//7站内 // Thread.sleep(2500); driver.findElement(By.xpath("/html/body/div[1]/div[3]/div[3]/div[2]/input")).sendKeys("科技");//6搜索框 Thread.sleep(1500); driver.findElement(By.className("index_btn_S-5T7")).click();//7点击 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[4].toString()); Thread.sleep(1500); // driver.switchTo().window(driver.getWindowHandles().toArray()[2].toString());//速度过题 // Thread.sleep(1500); driver.findElement(By.xpath("/html/body/div/div[2]/div[3]/div[2]/ul/li[1]/div/h2/a")).click();//8 2023慕尼黑国际车展 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[5].toString()); Thread.sleep(1500); // driver.switchTo().window(driver.getWindowHandles().toArray()[3].toString());//速度过题 // Thread.sleep(1500); driver.findElement(By.className("index_item_box_t--L6")).click();//9 现场直击 Thread.sleep(1500); driver.findElement(By.linkText("2023慕尼黑车展:大众全新Tiguan亮相,预计2024年上市")).click();//10 2023慕尼黑车展:大众全新Tiguan亮相,预计2024年上市 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[6].toString()); Thread.sleep(1500); // driver.switchTo().window(driver.getWindowHandles().toArray()[4].toString());//速度过题 // Thread.sleep(1500); driver.findElement(By.className("text-2sXTFgZW")).click();//11 人参与 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[7].toString()); Thread.sleep(1500); // driver.switchTo().window(driver.getWindowHandles().toArray()[5].toString());//速度过题 // Thread.sleep(1500); driver.findElement(By.xpath("/html/body/div/div[3]/div[2]/div[1]/div[2]/div[5]/div[2]/div[1]/div/div[2]/span[1]/a[2]")).click();//12 最新处 回复 Thread.sleep(1500); driver.findElement(By.className("w-submitBtn")).click();//13 发表 Thread.sleep(2500); Alert b = driver.switchTo().alert(); b.accept(); Thread.sleep(2500); driver.findElement(By.className("w-commentArea")).sendKeys("优秀");//14输入 Thread.sleep(1500); driver.findElement(By.className("icon-faceTrigArr")).click();//15表情 Thread.sleep(2500); driver.findElement(By.xpath("/html/body/div/div[3]/div[2]/div[1]/div[2]/div[5]/div[2]/div[1]/div/div[3]/div[1]/form/div[2]/div/div/div[2]/div/div[2]/ul/li[20]/img")).click();//18拜拜表情 Thread.sleep(1500); // driver.findElement(By.linkText("取消")).click();//15取消 // Thread.sleep(1500); driver.findElement(By.id("js_toTop")).click();//16 置顶 Thread.sleep(1500); driver.findElement(By.linkText("凤凰网首页")).click();//17凤凰网首页 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[8].toString()); Thread.sleep(1500); driver.findElement(By.linkText("视频")).click();//18 视频 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[9].toString()); Thread.sleep(1500); driver.findElement(By.className("index_more_T32Gd")).click();//19更多 Thread.sleep(1500); driver.findElement(By.linkText("美食")).click();//20 美食 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[10].toString()); Thread.sleep(1500); driver.findElement(By.xpath("/html/body/div/div[4]/div[1]/div[2]/a/div/img")).click();//21 第二个视频 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[11].toString()); Thread.sleep(1500); driver.findElement(By.className("index_vSelect_1csYP")).click();//22更多 Thread.sleep(3000); // WebElement e = driver.findElement(By.className("index_vSelect_1csYP"));//频道 // Actions c = new Actions(driver); // c.moveToElement(e).perform(); // Thread.sleep(2500); driver.findElement(By.linkText("凤凰首页")).click();//23 凤凰首页 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[12].toString()); Thread.sleep(1500); driver.findElement(By.className("index_login_name_2x_UU-Kq")).click();//24 名字 Thread.sleep(1500); driver.findElement(By.linkText("进入个人中心")).click();//25 个人中心 Thread.sleep(1500); driver.switchTo().window(driver.getWindowHandles().toArray()[13].toString()); Thread.sleep(1500); driver.findElement(By.linkText("注销")).click();//26注销 Thread.sleep(1500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { // Run main function to test your script. WebDriver driver = new ChromeDriver(); try { test(driver); } catch(Exception e) { e.printStackTrace(); } finally { driver.quit(); } } }import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.By; import java.util.List; import org.openqa.selenium.Alert; @SuppressWarnings("unused") public class Example { // Mooctest Selenium Example // <!> Check if selenium-standalone.jar is added to build path. public static void test(WebDriver driver) { // TODO Test script // eg:driver.get("https://www.baidu.com/") // eg:driver.findElement(By.id("wd")); try { driver.get("http://121.43.149.85/"); driver.manage().window().maximize(); Thread.sleep(10000); driver.findElement(By.id("username")).clear(); Thread.sleep(2000); driver.findElement(By.id("password")).clear(); Thread.sleep(2000); driver.findElement(By.id("username")).sendKeys("sunkang@mooctest.com");//1账号 Thread.sleep(2000); driver.findElement(By.id("password")).sendKeys("123456");//2密码 Thread.sleep(2000); driver.findElement(By.id("loginbutton")).click();//3登录 Thread.sleep(10000); driver.findElement(By.xpath("/html/body/div[1]/div/div[1]/div[2]/div[1]/div/ul/div[2]/li/div")).click();//4商品管理 Thread.sleep(5000); driver.findElement(By.xpath("/html/body/div[1]/div/div[1]/div[2]/div[1]/div/ul/div[2]/li/ul/div[1]/a/li")).click();//5商品分类 Thread.sleep(5000); driver.findElement(By.xpath("/html/body/div/div/div[2]/section/div[1]/div[1]/div[2]/span/button[1]/span")).click();//6新增 Thread.sleep(5000); driver.findElement(By.xpath("/html/body/div[2]/div/div[2]/form/div[1]/div/div/input")).sendKeys("测试");//7商品名称 Thread.sleep(5000); driver.findElement(By.xpath("/html/body/div[2]/div/div[2]/form/div[2]/div/div/div[1]/i")).click();//8 加好 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[3]/div/div[2]/section/main/div/div[2]/div/div[1]/div/div[3]/div/div/div[2]/label/span[1]/span")).click();//9选择第三个 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[3]/div/div[3]/span/button[2]")).click();//10确定 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[2]/div/div[2]/form/div[3]/div/div/label[2]/span[2]")).click();//11隐藏 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[2]/div/div[3]/div/button[2]")).click();//12确定 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[1]/div/div[2]/section/div[1]/div[1]/div[1]/div/input")).sendKeys("测试");//13 搜索测试 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[1]/div/div[2]/section/div[1]/div[1]/div[1]/span/button[1]")).click();//14搜索确定 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[1]/div/div[2]/section/div[1]/div[2]/div[4]/div[2]/table/tbody/tr/td[5]/div/div/span/span/button")).click();//15删除 Thread.sleep(5000); driver.findElement(By.xpath("/html/body/div[4]/div[1]/button[2]")).click();//16确定删除 Thread.sleep(5000); driver.findElement(By.xpath("/html/body/div/div/div[1]/div[2]/div[1]/div/ul/div[4]/li/div")).click();//17选择订单管理 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div/div/div[1]/div[2]/div[1]/div/ul/div[4]/li/ul/div[3]/a/li/span")).click();//18物流快递 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div/div/div[2]/section/div[1]/div[1]/div/button/span")).click();//19物流快递新增 Thread.sleep(2000); List<WebElement> inputs = driver.findElements(By.className("el-input__inner")); inputs.get(2).sendKeys("Test01"); Thread.sleep(2000); inputs = driver.findElements(By.className("el-input__inner")); inputs.get(3).sendKeys("Test01"); Thread.sleep(3000); driver.findElement(By.xpath("/html/body/div[2]/div/div[3]/div/button[2]")).click();; Thread.sleep(3000); // driver.findElement(By.xpath("/html/body/div[4]/div/div[2]/form/div[1]/div/div/input")).sendKeys("test01");//19物流快递新增 // Thread.sleep(2000); // driver.findElement(By.xpath("/html/body/div[4]/div/div[2]/form/div[2]/div/div/input")).sendKeys("test01");//19物流快递新增 // Thread.sleep(2000); // driver.findElement(By.xpath("/html/body/div[4]/div/div[3]/div/button[2]")).click();//19物流快递新增 // Thread.sleep(2000); // driver.findElement(By.xpath("/html/body/div[1]/div/div[2]/section/div[1]/div[2]/div[3]/table/tbody/tr[1]/td[4]/div/span/span/button")).click();//20物流快递删除 Thread.sleep(2000); driver.findElement(By.xpath("/html/body/div[3]/div[1]/button[2]")).click();//20物流快递删除 Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { // Run main function to test your script. WebDriver driver = new ChromeDriver(); try { test(driver); } catch(Exception e) { e.printStackTrace(); } finally { driver.quit(); } } }
    • 5个月前
    • 185
    • 0
    • 0
  • Vue 3 和 Element Plus 实现商品管理系统 - 表单校验部分解析 介绍在本博客中,我们将深入探讨如何使用 Vue 3 和 Element Plus 构建一个简单的商品管理系统,并重点关注表单校验的部分。这个系统允许用户添加、编辑和删除商品,以及对商品进行搜索。技术栈在这个项目中,我们使用了以下技术:Vue 3:一个流行的 JavaScript 框架,用于构建用户界面。Element Plus:一套基于 Vue 3 的组件库,用于创建漂亮的用户界面。Axios:一个用于处理 HTTP 请求的 JavaScript 库。表单校验在这个项目中,我们使用 Element Plus 的表单组件来实现商品信息的输入和校验。以下是与表单校验相关的关键知识点和注意事项:1. 引入 Element Plus在项目中首先要确保已正确引入 Element Plus,以便使用它的表单组件和验证规则。import { ref, reactive } from "vue"; import { ElForm, ElFormItem, ElInput, ElSelect, ElOption } from "element-plus";2. 创建表单数据和校验规则我们使用 ref 来创建表单数据,并使用 ref 来创建校验规则。校验规则通常包括字段的必填性、数据类型和自定义校验方法。const insertForm = ref({ sellerID: "", name: "", description: "", price: "", category: "", condition: "", quantity: "", // status: "", }); const insertFormRules = ref({ name: [ { required: true, message: "商品名称不能为空", trigger: "blur", }, ], description: [ { required: true, message: "商品描述不能为空", trigger: "blur", }, ], price: [ { required: true, validator: validatePrice, trigger: "blur", }, ], category: [ { required: true, message: "请选择商品类别", trigger: "change", }, ], condition: [ { required: true, message: "请选择商品成色", trigger: "change", }, ], quantity: [ { required: true, message: "商品数量不能为空", trigger: "blur", }, { type: "number", message: "商品数量必须为数字值", }, ], });3. 表单校验在提交表单之前,我们使用 el-form 的 validate 方法来进行表单校验。校验成功后才允许提交数据。<el-dialog v-model="dialogInsertFormVisible" title="上架商品"> <el-form ref="insertFormRulesRef" :model="insertForm" :rules="insertFormRules" > <el-form-item label="商品名称" label-width="80px" prop="name"> <el-input v-model="insertForm.name" autocomplete="off" /> </el-form-item> <el-form-item label="描述" label-width="80px" prop="description"> <el-input v-model="insertForm.description" autocomplete="off" /> </el-form-item> <el-form-item label="价格" label-width="80px" prop="price"> <el-input v-model="insertForm.price" autocomplete="off" /> </el-form-item> <el-form-item label="类别" label-width="80px" prop="category"> <el-select v-model="insertForm.category" placeholder="请选择类别"> <el-option label="服饰鞋帽" value="服饰鞋帽" /> <el-option label="家居用品" value="家居用品" /> <el-option label="电子数码" value="电子数码" /> <el-option label="美妆护肤" value="美妆护肤" /> <el-option label="食品生鲜" value="食品生鲜" /> <el-option label="图书音像" value="图书音像" /> <el-option label="儿童玩具" value="儿童玩具" /> <el-option label="运动户外" value="运动户外" /> <el-option label="汽车用品" value="汽车用品" /> <el-option label="医疗保健" value="医疗保健" /> <el-option label="工艺礼品" value="工艺礼品" /> <el-option label="虚拟物品" value="虚拟物品" /> </el-select> </el-form-item> <el-form-item label="成色" label-width="80px" prop="condition"> <el-select v-model="insertForm.condition" placeholder="请选择成色"> <el-option label="全新" value="全新" /> <el-option label="99新" value="99新" /> <el-option label="95新" value="95新" /> <el-option label="9成新" value="9成新" /> <el-option label="8成新" value="8成新" /> <el-option label="6成新" value="6成新" /> </el-select> </el-form-item> <el-form-item label="数量" label-width="80px" prop="quantity"> <el-input v-model.number="insertForm.quantity" autocomplete="off" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogInsertFormVisible = false">取消</el-button> <el-button type="primary" @click="submitItemInform(insertFormRulesRef)" > 提交 </el-button> <el-button type="primary" @click="test"> 提交 </el-button> </span> </template> </el-dialog>ref[0].validate(async (valid) => { if (valid) { // 表单校验通过,可以提交数据 try { const res = await axios.post( "http://localhost:8080/userInsertItem", insertForm.value ); // 处理提交结果... } catch (err) { // 处理请求错误... } } else { // 表单校验不通过,不执行提交操作 console.log("表单校验不通过!"); } });4. 自定义校验规则在校验规则中,我们可以使用自定义校验方法来实现特定的验证逻辑。例如,我们可以编写一个验证价格是否为数字的自定义校验方法:const validatePrice = (rule, value, callback) => { if (!value) return callback(new Error("请输入金额")); if (!Number(value)) return callback(new Error("请输入数字值")); let reg = /((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/; if (!reg.test(value)) return callback(new Error("请输入正确价格")); callback(); };然后,在校验规则中应用该自定义校验方法:price: [ { required: true, validator: validatePrice, trigger: "blur", }, ],5. 提示用户在校验不通过时,使用 Element Plus 的消息提示功能来通知用户错误信息:if (!valid) { // 表单校验不通过,显示错误消息 this.$message.error("表单校验不通过,请检查输入!"); }6. 表单重置在提交成功后,你可以选择重置表单,以便用户继续添加新的商品信息:ref[0].resetFields(); // 重置表单总结在这篇博客中,我们深入探讨了如何使用 Vue 3 和 Element Plus 构建商品管理系统的表单校验部分。我们学习了如何创建表单数据、定义校验规则、进行表单校验以及处理校验结果。此外,我们还介绍了如何使用自定义校验方法和提示用户错误信息的方法。这个项目只是一个简单的示例,你可以根据实际需求扩展和定制更多功能,以满足你的项目要求。希望这篇博客对你有所帮助,如果有任何问题或建议,请随时留言。
    • 5个月前
    • 259
    • 1
    • 1
  • 人生倒计时
    舔狗日记