-
ThreadPoolExecutor有5种状态,分别是:RUNNING:线程池正在运行中,即有任务正在执行或者等待执行。SHUTDOWN:线程池已经关闭,不再接受新任务,但是会继续执行已提交的任务。STOP:线程池已经停止,不再执行任何任务。TIDYING:线程池正在整理,即将进入TERMINATED状态。TERMINATED:线程池已经终止,所有任务都已经执行完毕。线程池的状态切换关系如下:初始状态为RUNNING。当调用shutdown()方法时,线程池会进入SHUTDOWN状态。此时线程池不再接受新任务,但是会继续执行已提交的任务。如果所有已提交的任务都执行完毕,线程池会进入STOP状态。此时线程池不再执行任何任务。如果线程池在SHUTDOWN状态下超时(通过awaitTermination(long timeout, TimeUnit unit)方法设置),或者在执行过程中抛出未捕获的异常,线程池会进入TIDYING状态。此时线程池会尝试结束所有正在执行的任务,并返回尚未开始执行的任务。当所有任务都执行完毕后,线程池会进入TERMINATED状态。此时线程池已经完全终止。
-
ThreadPoolExecutor中的无界队列指的是当线程池中的任务数量超过线程池的最大容量时,新提交的任务会被放入一个无界的阻塞队列中等待执行。这种队列可以容纳任意数量的任务,因此称为无界队列。在Java中,可以使用LinkedBlockingQueue作为ThreadPoolExecutor的无界队列实现。以下是一个简单的示例:import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) { int corePoolSize = 2; int maximumPoolSize = 4; long keepAliveTime = 10; TimeUnit unit = TimeUnit.SECONDS; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10); ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); for (int i = 0; i < 20; i++) { final int taskIndex = i; executor.execute(() -> { System.out.println("Task " + taskIndex + " is running by " + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }); } executor.shutdown(); } }在这个示例中,我们创建了一个ThreadPoolExecutor实例,并设置了核心线程数、最大线程数、空闲线程存活时间等参数。同时,我们使用LinkedBlockingQueue作为工作队列,其初始容量为10。这样,当线程池中的任务数量超过10个时,新提交的任务会被放入这个无界队列中等待执行。
-
要判断ThreadPoolExecutor中的所有任务是否已结束,可以使用isTerminated()方法。这个方法会返回一个布尔值,表示线程池中的所有任务是否都已完成执行。示例代码:import java.util.concurrent.*; public class Main { public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { executor.submit(() -> { try { System.out.println("任务开始执行:" + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(2); System.out.println("任务执行完毕:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } }); } // 等待所有任务完成 while (!executor.isTerminated()) { System.out.println("等待所有任务完成..."); Thread.sleep(1000); } System.out.println("所有任务已完成"); executor.shutdown(); } }在这个示例中,我们创建了一个固定大小的线程池,并提交了10个任务。然后使用isTerminated()方法检查线程池中的任务是否都已完成。如果所有任务都已完成,isTerminated()方法将返回true,否则返回false。
-
在Java中,可以使用ExecutorService的awaitTermination方法来判断线程池中所有任务是否已结束。这个方法会阻塞当前线程,直到所有任务完成执行或者超时。示例代码:import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class ThreadPoolExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { executorService.submit(() -> { try { System.out.println("任务开始执行:" + Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(2); System.out.println("任务执行完毕:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } }); } executorService.shutdown(); try { if (!executorService.awaitTermination(1, TimeUnit.HOURS)) { System.out.println("线程池未在指定时间内关闭"); } else { System.out.println("线程池已关闭"); } } catch (InterruptedException e) { e.printStackTrace(); } } }在这个示例中,我们创建了一个固定大小的线程池,提交了10个任务。然后调用executorService.shutdown()来关闭线程池。接下来,我们使用executorService.awaitTermination(1, TimeUnit.HOURS)来等待线程池中的所有任务完成执行或者超时。如果线程池在指定的时间内关闭,那么awaitTermination方法返回true,否则返回false。
-
Java中的ThreadPoolExecutor线程池的生命周期主要包括以下几个阶段:创建线程池:通过ThreadPoolExecutor类的构造方法创建一个线程池实例。在创建过程中,可以设置线程池的核心线程数、最大线程数、空闲线程存活时间等参数。import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) { int corePoolSize = 5; // 核心线程数 int maximumPoolSize = 10; // 最大线程数 long keepAliveTime = 60L; // 空闲线程存活时间(秒) TimeUnit unit = TimeUnit.SECONDS; // 时间单位 BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(25); // 任务队列 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } }提交任务:通过线程池的submit()方法提交一个任务到线程池中执行。submit()方法会返回一个Future对象,可以通过该对象获取任务的执行结果或者取消任务。import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) { // ...创建线程池的代码... Runnable task = () -> { System.out.println("任务执行中:" + Thread.currentThread().getName()); }; Future<?> future = threadPoolExecutor.submit(task); } }关闭线程池:当所有任务都执行完毕后,需要调用线程池的shutdown()方法来关闭线程池。此时,线程池不再接受新的任务,但会继续执行已提交的任务。如果需要在关闭线程池之前等待所有任务完成,可以使用awaitTermination()方法。import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) { // ...创建线程池和提交任务的代码... threadPoolExecutor.shutdown(); // 关闭线程池 try { if (!threadPoolExecutor.awaitTermination(60, TimeUnit.SECONDS)) { threadPoolExecutor.shutdownNow(); // 超时后强制关闭线程池 } } catch (InterruptedException e) { threadPoolExecutor.shutdownNow(); // 发生异常时强制关闭线程池 } } }处理任务结果:如果任务有返回值,可以通过Future对象的get()方法获取任务的执行结果。如果任务执行过程中发生异常,可以通过get()方法的重载版本获取异常信息。import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) { // ...创建线程池和提交任务的代码... Future<String> future = threadPoolExecutor.submit(() -> { System.out.println("任务执行中:" + Thread.currentThread().getName()); return "任务执行结果"; }); try { String result = future.get(); // 获取任务执行结果 System.out.println("任务执行结果:" + result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
-
在多线程编程中,锁是一种用于保护共享资源的重要机制。当多个线程需要访问同一个共享资源时,可以使用锁来确保在任何时刻只有一个线程能够访问该资源,从而避免数据竞争和不一致的问题。然而,当一个线程结束执行并释放其占用的锁时,其他等待的线程是否能够立即获得锁并继续执行呢?本文将介绍在线程结束后锁是否会自动释放的情况。 首先,我们需要了解锁的释放方式。在大多数编程语言中,锁的释放是由程序员显式完成的。当一个线程完成了对共享资源的访问后,它需要调用相应的方法来释放锁,以便其他线程可以获取锁并继续执行。这种方式被称为“显式释放”。 然而,在某些情况下,程序员可能会忘记显式释放锁,或者由于程序逻辑错误导致锁无法被释放。在这种情况下,锁将一直被占用,其他线程将无法获得锁并继续执行。这种情况可能会导致死锁或程序无响应等问题。 为了避免这种情况的发生,一些编程语言提供了自动释放锁的机制。当一个线程结束时,它会自动释放其占用的锁,以便其他线程可以立即获得锁并继续执行。这种机制被称为“自动释放”。 以Java语言为例,当一个线程结束时,它会自动释放其占用的所有锁。这是因为Java虚拟机(JVM)在垃圾回收器回收线程对象时,会检查该线程是否持有任何锁。如果该线程持有锁,垃圾回收器将等待直到锁被释放,然后再回收线程对象。这样可以避免死锁和其他与锁相关的问题。 需要注意的是,自动释放锁的机制并不是所有编程语言都支持的。在一些编程语言中,程序员仍然需要显式地释放锁,否则可能导致程序出现问题。因此,在使用多线程编程时,程序员应该仔细考虑如何正确地管理锁,以避免出现潜在的问题。
-
Java中的浅拷贝和深拷贝是两种不同的对象复制方式。它们的主要区别在于对对象内部成员的处理方式。下面我们来详细介绍一下这两种拷贝方式。浅拷贝浅拷贝是指对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,新旧对象还是共享同一个内存空间。简单来说,浅拷贝只是复制了对象的引用,而不是对象本身。因此,原始对象和新对象的成员变量指向的是同一个内存地址。在Java中,可以使用Object类的clone()方法实现浅拷贝。需要注意的是,clone()方法的默认实现是浅拷贝。以下是一个简单的示例:class Person implements Cloneable { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class ShallowCopyDemo { public static void main(String[] args) { try { Person p1 = new Person("张三", 20); Person p2 = (Person) p1.clone(); System.out.println("p1: " + p1.name + ", " + p1.age); System.out.println("p2: " + p2.name + ", " + p2.age); p1.name = "李四"; p1.age = 30; System.out.println("修改后的p1: " + p1.name + ", " + p1.age); System.out.println("修改后的p2: " + p2.name + ", " + p2.age); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }输出结果:p1: 张三, 20 p2: 张三, 20 修改后的p1: 李四, 30 修改后的p2: 张三, 20从输出结果可以看出,修改p1的name和age属性后,p2的对应属性并没有发生改变,说明它们是浅拷贝。深拷贝深拷贝是对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容。简单来说,深拷贝会创建一个新的对象,并将原对象的内容复制到新对象中。因此,原始对象和新对象的成员变量指向的是两个不同的内存地址。在Java中,可以通过实现Cloneable接口并重写clone()方法来实现深拷贝。需要注意的是,需要对引用数据类型进行递归拷贝。以下是一个简单的示例:class Person implements Cloneable { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); person.name = new String(this.name); // 对引用数据类型进行递归拷贝 return person; } } public class DeepCopyDemo { public static void main(String[] args) { try { Person p1 = new Person("张三", 20); Person p2 = (Person) p1.clone(); System.out.println("p1: " + p1.name + ", " + p1.age); System.out.println("p2: " + p2.name + ", " + p2.age); p1.name = "李四"; p1.age = 30; System.out.println("修改后的p1: " + p1.name + ", " + p1.age); System.out.println("修改后的p2: " + p2.name + ", " + p2.age); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }输出结果:p1: 张三, 20 p2: 张三, 20 修改后的p1: 李四, 30 修改后的p2: 张三, 20从输出结果可以看出,修改p1的name和age属性后,p2的对应属性并没有发生改变,说明它们是深拷贝。
-
Java中的List数组是一种常用的数据结构,它允许我们存储和操作一系列的对象。而Stream API是Java 8中引入的一个新特性,它提供了一种高效且简洁的方式来处理List数组中的数据。本文将介绍一些常用的Stream操作。创建Stream要使用Stream API处理List数组,首先需要创建一个Stream对象。可以通过以下几种方式创建Stream:使用list.stream()方法从List数组中创建一个Stream。使用Arrays.stream(array)方法从数组中创建一个Stream。使用Stream.of(elements)方法从多个元素中创建一个Stream。List<String> list = Arrays.asList("A", "B", "C"); Stream<String> stream = list.stream();过滤(Filter)过滤操作可以根据给定的条件筛选出符合条件的元素。可以使用filter()方法实现过滤操作。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0);映射(Map)映射操作可以将一个类型的元素转换为另一个类型的元素。可以使用map()方法实现映射操作。List<String> names = Arrays.asList("张三", "李四", "王五"); Stream<Integer> nameLengths = names.stream().map(String::length);排序(Sort)排序操作可以对Stream中的元素进行排序。可以使用sorted()方法实现排序操作。默认情况下,排序是基于元素的自然顺序进行的。如果需要自定义排序规则,可以提供一个比较器(Comparator)。List<String> words = Arrays.asList("apple", "banana", "orange"); Stream<String> sortedWords = words.stream().sorted();去重(Distinct)去重操作可以去除Stream中重复的元素。可以使用distinct()方法实现去重操作。List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5); Stream<Integer> distinctNumbers = numbers.stream().distinct();限制(Limit)限制操作可以获取Stream中的前n个元素。可以使用limit()方法实现限制操作。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> firstThreeNumbers = numbers.stream().limit(3);跳过(Skip)跳过操作可以跳过Stream中的前n个元素。可以使用skip()方法实现跳过操作。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> numbersAfterTwo = numbers.stream().skip(2);收集(Collect)收集操作可以将Stream中的元素收集到一个新的数据结构中,例如List、Set或Map。可以使用collect()方法实现收集操作。需要提供一个Collector,用于指定如何将元素收集到目标数据结构中。例如,可以使用Collectors.toList()将元素收集到一个List中。List<String> words = Arrays.asList("apple", "banana", "orange"); List<String> wordList = words.stream().collect(Collectors.toList());
-
问题描述:公司最近使用使用华为kafka,通过DRS获取ORACLE数据库日志文件并且使用ARVO格式序列化到kafka里的topic里,最后通过工具插入目标数据库中。问题点:现要通过java获取topic里的数据,并且反序列化ARVO格式成JSON可识别语句。目前已经获取到topic数据,但是反序列化出错,(使用的是官网给的反序列化demo和schem)kafka 消费者获取数据代码:出错代码行:报错信息:烦请大佬帮忙!!!
-
Java线程池是一种管理线程的工具,它可以在需要时创建新的线程,也可以在不需要时回收和重用已经存在的线程。使用线程池可以有效地减少线程的创建和销毁开销,提高系统性能。然而,如果不正确使用线程池,可能会导致资源浪费、系统崩溃等问题。因此,如何安全地使用Java线程池是非常重要的。 以下是一些关于如何最安全地使用Java线程池的建议: 1. 合理设置线程池大小:线程池的大小应该根据系统的硬件资源、并发任务的数量和任务的处理时间来设置。如果线程池太小,可能会导致任务排队等待处理,影响系统性能;如果线程池太大,可能会消耗过多的系统资源,导致系统崩溃。 2. 使用有界队列:有界队列可以防止任务过多而无法处理的情况。当队列满时,线程池会根据设定的策略拒绝新任务或者丢弃旧任务。这样可以保证系统的稳定性。 3. 避免长时间执行的任务:线程池中的线程是复用的,如果某个任务长时间执行,可能会导致其他任务无法得到及时处理。因此,对于长时间执行的任务,应该单独启动一个线程来处理。 4. 使用合适的拒绝策略:当线程池和队列都无法处理新任务时,线程池会调用设定的拒绝策略。常见的拒绝策略有抛出异常、丢弃任务、在队列中等待等。应该根据实际需求选择合适的拒绝策略。 5. 定期检查和调整线程池:应该定期检查线程池的状态,如线程数量、队列大小等,并根据实际需求进行调整。例如,如果发现队列经常满,可能需要增加线程池的大小或者增大队列的容量。 6. 使用线程池监控工具:有许多第三方库提供了线程池的监控工具,如VisualVM、JConsole等。这些工具可以帮助我们更好地了解线程池的状态,及时发现和解决问题。 7. 注意线程安全:在多线程环境下,需要注意线程安全问题。例如,多个线程同时访问共享资源时,可能会导致数据不一致的问题。可以使用synchronized关键字、Lock接口等机制来保证线程安全。 8. 及时关闭线程池:当不再需要线程池时,应该及时关闭它,以释放资源。可以通过调用ThreadPoolExecutor的shutdown()方法来关闭线程池。
-
什么是反射Java 中的反射(Reflection)是一种强大的编程特性,它允许程序在运行时动态地获取类的信息,包括类名、属性、方法等,并且可以对这些信息进行操作,如创建对象、调用方法和访问属性。反射机制使得程序在运行时能够更加灵活地处理不同类型的对象和情况,提高了程序的扩展性和灵活性。反射的作用反射主要提供以下功能:在运行时判断任意一个对象所属的类。在运行时构造任意一个类的对象。在运行时判断任意一个类所具有的成员变量和方法。在运行时调用任意一个对象的方法。Java为什么要支持反射Java 支持反射机制的原因主要有以下几点:灵活性:反射机制使得 Java 程序在运行时能够动态地获取类的信息,包括类名、属性、方法等。这使得程序在运行时能够更加灵活地处理不同类型的对象和情况。解耦:反射机制有助于实现程序组件之间的解耦。通过反射,可以在运行时动态地加载类、创建对象、调用方法等,这使得程序之间的依赖关系变得更加松散。扩展性:反射机制为 Java 程序提供了强大的扩展能力。通过反射,可以在运行时动态地加载和调用自定义的类和方法,这为程序的扩展和定制提供了便利。高效性:反射机制可以实现程序的优化。在某些场景下,通过反射创建对象、调用方法等操作可能会比使用静态语句更加高效。反射可以在运行时直接调用指定的方法,避免了额外的类型检查和绑定过程。安全性:反射机制可以提高 Java 程序的安全性。通过反射,可以对程序的运行状态进行动态监控和调试,有助于及时发现和修复潜在的安全隐患。框架基础:反射机制是许多 Java 框架(如 Hibernate、Struts 等)的基础。这些框架利用反射实现对对象、方法和属性的操作,从而简化了开发者的任务,提高了开发效率。反射机制为 Java 程序带来了更高的灵活性、扩展性、高效性和安全性,同时还是许多重要框架和技术的基础。反射的应用场景反射机制在 Java 中的应用场景包括:动态地加载类和对象。实现多态性,即在运行时动态地确定对象类型。序列化库(如 Jackson)和 Web 框架(如 Spring MVC、Jersey)中,利用反射和注解实现通用的序列化/反序列化机制以及请求参数和内容的转换。 通过灵活掌握反射机制,开发者可以更好地定制和优化程序,提高代码的灵活性和扩展性。同时,反射机制也是许多 Java 框架和高级技术的基础。代码示例以下是一个简单的 Java 反射应用示例,通过代码演示了如何使用反射创建对象、访问属性和方法:首先,定义一个简单的类 Person:public class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }然后,使用反射创建 Person 对象、访问属性和方法:import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectionExample { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { // 1. 获取 Class 对象 Class<?> personClass = Class.forName("Person"); // 2. 创建对象 Constructor<?> constructor = personClass.getConstructor(String.class, int.class); Person person = (Person) constructor.newInstance("张三", 25); // 3. 访问属性 Field nameField = personClass.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(person, "李四"); Field ageField = personClass.getDeclaredField("age"); ageField.setAccessible(true); ageField.set(person, 26); // 4. 访问方法 Method getNameMethod = personClass.getMethod("getName"); String name = (String) getNameMethod.invoke(person); System.out.println("Name: " + name); Method setNameMethod = personClass.getMethod("setName", String.class); setNameMethod.invoke(person, "王五"); Method getAgeMethod = personClass.getMethod("getAge"); int age = (int) getAgeMethod.invoke(person); System.out.println("Age: " + age); Method setAgeMethod = personClass.getMethod("setAge", int.class); setAgeMethod.invoke(person, 27); } }在这个示例中,我们首先使用 Class.forName() 方法获取 Person 类的 Class 对象。然后,通过 getConstructor() 方法获取构造方法,创建新的 Person 对象。接下来,使用 getDeclaredField() 方法获取类的属性,并通过 setAccessible() 方法访问私有属性。最后,使用 getMethod() 方法获取类的方法,并调用这些方法。
-
JAVA简单制作excel文件 需求:查询的业务数据根据指定的样式下载 比如这个模板包含了行合并和表头字体颜色和内容字体和下面的小计的颜色的行合并 怎么去做呢? 其实使用excel有很多种做法,要么你对自己的手法很自信那就直接手撸代码写样式,如果你想偷懒那就按照我说这种方式也许能给你提供一些想法。 1.创建一个excel文件制作两个sheet页 第一个sheet页制作: 我们可以根据模板将一些固定不变的模板画在这个sheet页,就像现在这个,我就可以直接去填充数据 第二个sheet页制作: 第二个sheet页你就放只有一条数据的一个简单的完整样式,用于下面的取样式 2.核心代码 //将你创建好的excel文件放到静态文件夹下面然后引用 ClassPathResource classPathResource = new ClassPathResource("static/zlfxb.xlsx"); InputStream inputStream = classPathResource.getStream(); XSSFWorkbook workBook = new XSSFWorkbook(inputStream); //引用完成 //接下来一个一个来获取业务数据的样式 //解读:正文样式:第2个sheet页第三行第一列的样式 XSSFCellStyle ptzt = workBook.getSheetAt(1).getRow(2).getCell(0).getCellStyle(); //这里可能会有多个样式,这就按照你的需求来,像上面一样创建多个样式.... XSSFSheet sheet1 = workBook.getSheetAt(0);//获取第一个sheet页,也就是正常填充业务数据的sheet页 XSSFRow row = null; Cell cell = null; //现在是循环填充数据 //这个mapList就是你的数据有多少行就是for多少个 for (int i = 0; i < mapList.size(); i++) { //我们是从第三行开始填充 row = sheet1.createRow(i + 2); //现在是要看你有多少列也是需要循环的 for(int x = 0; x < 11;x++){ //你有11列那就赋值下去咯,这里不是统一的,看你的数据格式 //这里是第i行创建第x列 cell = row.createCell(x); //使用的是上面我们创建的正文格式 cell.setCellStyle(ptzt); //给这个列表赋值,但是一定要是string不然会报错 cell.setCellValue(String.valueOf(map.get("orgNo"))); } } //赋值完数据后然后就把第二个样式sheet页删除掉就ok了 workBook.removeSheetAt(1); FileOutputStream fos = null; File file = File.createTempFile("分析表", ".xlsx"); fos = new FileOutputStream(file, false); workBook.write(fos); //弄成文件输出就行 核心代码就是这样的,上面的代码是提供的一些思路 3.一些常用java制作excel操作: 1.合并列: sheet.addMergedRegion(new CellRangeAddress(firstRow,lastRow ,firstCol, lastCol)); //例子解读:从第三行开始到第三行结束,第一列到第五列合并 sheet.addMergedRegion(new CellRangeAddress(2,2, 0, 4)); 2.删除行: //其实java是没有删除excel这一说法的,只是说从第几行开始,下面的行要往上移几行,这一行代码最好写在需要删除行的下面,及时删除是最好的 sheet.shiftRows(5,sheet1.getLastRowNum(),-2); ———————————————— 原文链接:https://blog.csdn.net/weixin_42235875/article/details/132497421
-
public synchronized static int writeExcel(JSONArray jsonArray,int k) { //创建Excel文件薄 HSSFWorkbook workbook=new HSSFWorkbook(); //创建工作表sheeet HSSFSheet sheet=workbook.createSheet(); //创建第一行 HSSFRow row=sheet.createRow(0); String[] title={"货号","中文名","英文名","CAS","分子式","分子量","图片网址","svg网址"}; HSSFCell cell_title = null; for (int i=0;i<title.length;i++){ cell_title=row.createCell(i); cell_title.setCellValue(title[i]); } //追加数据 for (int i=0;i<jsonArray.size();i++){ JSONObject jsonObject =(JSONObject) jsonArray.get(i); HSSFRow nextrow=sheet.createRow(i+1); HSSFCell cell_value=nextrow.createCell(0); cell_value.setCellValue(""); cell_value=nextrow.createCell(1); cell_value.setCellValue(TransApi.EN_to_ZH(jsonObject.get("name").toString())); cell_value=nextrow.createCell(2); cell_value.setCellValue(jsonObject.get("name").toString()); cell_value=nextrow.createCell(3); cell_value.setCellValue(jsonObject.get("CAS").toString()); cell_value=nextrow.createCell(4); cell_value.setCellValue(jsonObject.get("FCS").toString()); cell_value=nextrow.createCell(5); cell_value.setCellValue(jsonObject.get("MW").toString()); cell_value=nextrow.createCell(6); cell_value.setCellValue(jsonObject.get("img").toString()); cell_value=nextrow.createCell(7); cell_value.setCellValue(jsonObject.get("svg").toString()); } //创建一个文件 try { File file=new File("D:/pacong/poi_test_"+k+".xls"); file.createNewFile(); FileOutputStream stream= FileUtils.openOutputStream(file); workbook.write(stream); stream.close(); }catch (Exception e){ e.printStackTrace(); }finally { return 1; } }原文链接:https://blog.csdn.net/qq_31122833/article/details/123449030
-
在很多项目中,都需要我们把数据库查询出来的数据导出成excel表格,导出就算了,还给我弄个模板,大标题要写在合并表格里还要居中,标题要有底色,还要加粗,等等,下面我就来讲一下我用到的表格操作: 首先要进行表格操作,要添加相关依赖 这里我重点说明一下,我用4.3及以上版本就不行,可能是方法有升级 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.0.1</version> </dependency> 创建excel文件 如果想生成.xls文件: Workbook workbook = new HSSFWorkbook(); 如果想生成.xlsx文件 Workbook workbook = new XSSFWorkbook(); 创建工作簿 也就是我们说的Sheet页,sheet页是根据Workbook对象生成的,也就是sheet页依赖excel文件而存在。 Sheet sheet = workbook.createSheet("Sheet1"); // Sheet1为要生成的sheet页的名称 写入操作 完成以上操作,在不考虑样式的前提下,我们就可以写数据了。写数据的话是按行进行写入的。 首先声明行变量 行是根据sheet声明的,参数为该行的位置(从0开始算) Row titleRow = sheet.createRow(0); 写入数据 有了行对象,那么我们就可以对该行的某列进行操作了 首先要创建该行某列对象,然后用getCell方法获取单元格,参数为单元格索引位置(从0开始算),然后用setCellValue方法进行内容写入,参数为内容 titleRow.createCell(0); titleRow.getCell(0).setCellValue("序号"); 写完之后,返回workbook对象就可以了。 按这样操作,一份没有样式的表格文件就生成好了。 样式操作 首先要声明样式对象 因为创建的workbook对象方式不同,样式对象的类型也不一样,不过方法是类似的 XSSFCellStyle cellStyle = workbook.createCellStyle(); 背景颜色 这里修改只需要改new java.awt.Color里的参数值即可,也支持输入0xff000000(默认值)16进制数 需要与设置填充格式一起使用才生效,使用无先后顺序 cellStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(89, 214, 255),new DefaultIndexedColorMap())); 字体居中 cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中 cellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中 设置边框 BorderStyle.THIN为宽度属性 cellStyle.setBorderBottom(BorderStyle.THIN); // 下边框 cellStyle.setBorderRight(BorderStyle.THIN); // 右边框 cellStyle.setBorderLeft(BorderStyle.THIN); // 左边框 cellStyle.setBorderTop(BorderStyle.THIN); // 上边框 设置填充格式 cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); 自动换行 cellStyle.setWrapText(true); 字体设置 Font titleFont = workbook.createFont(); // 声明字体对象 titleFont.setBold(true); // 字体加粗 titleFont.setFontName("华文彩云"); // 字体类型 titleFont.setFontHeightInPoints((short) 20); // 字体大小 cellStyle.setFont(titleFont); // 赋值样式对象 设置列宽 sheet.setColumnWidth(0, 4200); // 第0列列宽设置为4200 合并单元格 sheet.addMergedRegion(new CellRangeAddress(1, 3, 1, 3)); // 参数分别为起始行,结束行,起始列,结束列 1 返回前端的话,写法是这样的,方法是没有返回的,也就是void public void index(HttpServletResponse response) { XSSFWorkbook workbook = service.test(); if (workbook!=null){ String fileName = "1.xlsx"; try { fileName = URLEncoder.encode(fileName, "UTF-8"); //设置ContentType请求信息格式 response.setContentType("application/vnd.ms-excel;charset=utf-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName); OutputStream outputStream = response.getOutputStream(); workbook.write(outputStream); outputStream.flush(); outputStream.close(); } catch (Exception e) { System.out.println(e); } } } 我这边用到的基本是这些,如果有其他的操作可以评论我或者私信我,我这边在做补充 ———————————————— 原文链接:https://blog.csdn.net/weixin_45494557/article/details/132088533
上滑加载中
推荐直播
-
华为云码道Skill实战与极速交付,智能开发全链路实战2026/07/22 周三 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;姜浩-华为云HCDG核心组成员
直播深度解读华为云码道6月产品新特性,从Skill市场安装专家技能,带你零距离体验从需求,开发,审查,重构全链路闭环的开发过程。从零构建并交付一个完整项目,让您体验从代码提交到服务上线的“极速”之旅。
回顾中 -
聚开发者之力,创具身新未来2026/07/23 周四 15:00-17:00
张豪杰/程文/王军/刘新春/黄钦开 /张晓天
本次华为云具身智能开发平台CloudRobo培训面向具身智能开发者,带您全流程体验机器人本体R2C小时级接入、环境重建与轨迹生成仿真数据生产、PB级数据管理、数据评测、模型训推、强化学习和Benchmark一键评测等功能,并体验业界主流具身模型应用。
回顾中
热门标签