HowToDoInJava-其它教程-2-二-
HowToDoInJava 其它教程 2(二)
Java 核心面试问题 – 第 2 部分
原文: https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-2/
在 Java 面试问题系列:第 1 部分中,我们讨论了面试官通常问的一些重要问题。 现在是推进该讨论的时候了。 在这篇文章中,我将在下面给出的问题列表中进行讨论。
Why finalize() method should be avoided?
Why HashMap should not be used in multithreaded environment? Can it cause infinite loop as well?
Explain abstraction and encapsulation? How are they related?
Difference between interfaces and abstract classes?
How StringBuffer save the memory?
Why wait and notify is declared in Object class instead of Thread ?
Write Java program to create deadlock in Java and fix it ?
What happens if your Serializable class contains a member which is not serializable? How do you fix it?
Explain transient and volatile keywords in java?
Difference between Iterator and ListIterator?
为什么要避免使用finalize()
方法?
我们都知道,在回收分配给对象的内存之前,垃圾收集器线程会调用finalize()
方法的基本声明。 请参阅这篇文章,证明根本不能保证finalize()
调用。 其他原因可能是:
-
finalize()
方法无法像构造器一样在链接中工作。 这意味着就像您调用构造器时一样,所有超类的构造器都将被隐式调用。 但是,在使用finalize
方法的情况下,则不遵循此方法。 超类的finalize()
应该显式调用。 -
由
finalize
方法引发的任何异常都将被 GC 线程忽略,并且不会进一步传播,实际上不会记录在日志文件中。 真糟糕,不是吗? -
另外,当您的类中包含
finalize()
时,也会影响性能。 Joshua bloch 在《Effective Java》(第 2 版)中说,“哦,还有一件事:使用终结器会严重影响性能。 在我的机器上,创建和销毁简单对象的时间约为 5.6 ns。 添加终结器会将时间增加到 2,400 ns。 换句话说,使用终结器创建和销毁对象要慢 430 倍。”
为什么不应该在多线程环境中使用HashMap
? 它也会引起无限循环吗?
我们知道HashMap
是非同步集合,因为它的同步计数器是HashTable
。 因此,当您在多线程环境中访问集合时,所有线程都在访问集合的单个实例时,出于各种明显的原因,例如HashTable
,使用HashTable
更安全。 以避免脏读并保持数据一致性。 在最坏的情况下,这种多线程环境也可能导致无限循环。
是的,它是真实的。 HashMap.get()
可能导致无限循环。 让我们看看如何?
如果查看HashMap.get(Object key)
方法的源代码,则如下所示:
public Object get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
Entry e = table[i];
while (true) {
if (e == null)
return e;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}
在多线程环境中,while(true){...}
始终是运行时无限循环的受害者,因此e.next
可以指向自身。 这将导致无限循环。 但是,e.next
将如何指向自身(即)。
这可能在void transfer(Entry[] newTable)
方法中发生,该方法在HashMap
调整大小时调用。
do {
Entry next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
如果调整大小并且同时其他线程试图修改映射实例,则这段代码很容易产生上述条件。
避免这种情况的唯一方法是在代码中使用同步,或者更好的方法是使用同步集合。
解释抽象和封装? 它们有什么关系?
抽象
抽象仅捕获与当前视角有关的那些对象的详细信息。
在面向对象编程理论中,抽象涉及定义定义代表抽象“角色”的对象的功能,这些抽象“角色”可以执行工作,报告和更改其状态,并与系统中的其他对象“通信”。
任何编程语言中的抽象都可以通过多种方式工作。 从创建子例程到定义用于进行低级语言调用的接口可以看出。 一些抽象试图通过完全隐藏它们依次建立在其上的抽象,来限制程序员所需概念的广度。 例如设计模式。
通常,可以通过两种方式查看抽象:
数据抽象是创建复杂数据类型并仅公开有意义的操作以与数据类型进行交互的方法,其中隐藏了外部工作中的所有实现细节。
控制抽象是识别所有此类语句并将其作为工作单元公开的过程。 我们通常在创建函数来执行任何工作时使用此功能。
封装
将类中的数据和方法与实现隐藏(通过访问控制)结合起来通常称为封装。 结果是具有特征和行为的数据类型。 封装本质上既具有信息隐藏又具有实现隐藏。
“无论进行任何更改,都封装它”。 它被引用为著名的设计原则。 因此,在任何类中,运行时中的数据都可能发生更改,将来的发行版中可能会更改实现。 因此,封装既适用于数据也适用于实现。
因此,它们可以像下面这样关联:
- 抽象更多是关于“类可以做什么”。(想法)
- 封装更多地是关于“如何”实现该功能。(实现)
接口和抽象类之间的区别?
接口和抽象类之间的基本区别可以算作如下:
- 接口不能有任何方法,而抽象类可以(在 Java8 默认方法之后不正确)
- 一个类可以实现许多接口,但只能有一个超类(是否抽象)
- 接口不属于类层次结构。 不相关的类可以实现相同的接口
您应该记住:“当您可以用做什么充分描述该概念时,而无需指定任何它是如何工作的,那么您应该使用一个接口。 如果您需要包括一些实现细节,那么您将需要在抽象类中表示您的概念。”
另外,如果我说的不同:是否可以将许多分组在一起并用一个名词描述的类? 如果是这样,请以该名词的名称创建一个抽象类,并从其继承这些类。 例如,Cat
和Dog
都可以从抽象类Animal
继承,并且此抽象基类将实现方法void breathe()
,所有动物都将以完全相同的方式执行该方法。
什么样的动词可以应用于我的类,通常也可以应用于其他动词? 为每个动词创建一个接口。 例如,所有动物都可以喂食,因此我将创建一个名为IFeedable
的接口,并让Animal
实现该接口。 尽管Dog
和Horse
足以实现ILikeable
,但有些还不够。
正如某人所说:主要区别在于您想要实现的地方。 通过创建接口,可以将实现移动到实现接口的任何类。 通过创建一个抽象类,您可以在一个中央位置共享所有派生类的实现,并且避免了很多不好的事情,例如代码重复。
StringBuffer
如何节省内存?
字符串被实现为不变对象; 也就是说,当您最初决定将某些内容放入String
对象时,JVM 会分配一个与初始值大小正好相等的固定宽度数组。 然后将其视为 JVM 内部的常量,在不更改String
值的情况下,可以大大节省性能。 但是,如果您决定以任何方式更改String
的内容,那么 JVM 实质上要做的就是将原始String
的内容复制到一个临时空间中,进行更改,然后将这些更改保存到一个全新的内存阵列中。 因此,在初始化后更改String
的值是一项相当昂贵的操作。
StringBuffer
在 JVM 内部被实现为可动态增长的数组,这意味着任何更改操作都可以在现有内存位置上进行,而新内存仅按需分配。 但是,JVM 没有机会围绕StringBuffer
进行优化,因为假定其内容在任何情况下都是可更改的。
为什么在对象类而不是线程中声明了wait
和notify
?
wait
,notify
,notifyAll
方法仅在您希望线程访问共享资源并且共享资源可以是堆上的任何 Java 对象时才需要。 因此,这些方法是在核心Object
类上定义的,因此每个对象都可以控制允许线程在其监视器上等待。 Java 没有用于共享公共资源的任何特殊对象。 没有定义这样的数据结构。因此,在Object
类上有责任成为共享资源,条件是它可以使用wait()
,notify()
和notifyAll()
之类的辅助方法。
Java 基于 Hoare 的监视器概念。 在 Java 中,所有对象都有一个监视器。 线程在监视器上等待,因此要执行等待,我们需要 2 个参数:
– 线程
– 监视器(任何对象)
在 Java 设计中,无法指定线程,它始终是当前运行代码的线程。 但是,我们可以指定监视器(这是我们称为wait
的对象)。 这是一个很好的设计,因为如果我们可以让任何其他线程在所需的监视器上等待,则会导致“入侵”,给设计/编程并发程序带来了困难。 请记住,在 Java 中,不推荐使用会干扰另一个线程执行的所有操作(例如stop()
)。
编写 Java 程序以在 Java 中创建死锁并修复死锁?
在 Java 中,死锁是指至少有两个线程在某个不同的资源上持有锁,并且都在等待其他资源来完成其任务的情况。 而且,没有人能够锁定它所拥有的资源。
阅读更多:编写死锁并使用 Java 解决
如果您的Serializable
类包含一个不可序列化的成员,该怎么办? 您如何解决?
在这种情况下,将在运行时引发NotSerializableException
。 要解决此问题,一个非常简单的解决方案是将此类字段标记为瞬态。 这意味着这些字段将不会被序列化。 如果还要保存这些字段的状态,则应考虑已经实现Serializable
接口的引用变量。
您可能还需要使用readResolve()
和writeResolve()
方法。 让我们总结一下:
- 首先,设置您的不可序列化字段
transient
。 - 在
writeObject()
中,首先在流上调用defaultWriteObject()
来存储所有非瞬态字段,然后调用其他方法来序列化不可序列化对象的各个属性。 - 在
readObject()
中,首先在流上调用defaultReadObject()
以读回所有非瞬态字段,然后调用其他方法(与您添加到writeObject
的方法相对应)来反序列化不可序列化的对象。
另外,我强烈建议阅读关于 Java 中序列化的完整指南。
解释 Java 中的transient
和volatile
关键字?
transient
“Java 中的transient
关键字用于指示不应序列化字段。”根据语言规范:可以将变量标记为transient
,以指示它们不是对象持久状态的一部分。 例如,您可能具有从其他字段派生的字段,并且仅应以编程方式进行操作,而不要通过序列化来保持状态。
例如,在BankPayment.java
类中,可以对principal
和rate
之类的字段进行序列化,而即使在反序列化之后也可以随时计算interest
。
回想一下,java 中的每个线程也都有自己的本地内存空间,并且它在本地内存中执行所有读/写操作。 完成所有操作后,它将所有线程访问该变量的位置写回主存储器中变量的修改状态。 通常,这是 JVM 内部的默认流程。 但是,volatile
修饰符告诉 JVM,访问该变量的线程必须始终将其自身的变量私有副本与内存中的主副本进行协调。 这意味着每次线程想要读取变量的状态时,它都必须刷新其本地内存状态并从主内存中更新变量。
volatile
volatile
在无锁算法中最有用。 当您不使用锁定来访问该变量并且希望一个线程所做的更改在另一个线程中可见时,或者您要创建“后接”关系以确保计算无需重新排序,以确保更改在适当的时间可见。
volatile
应该用于在多线程环境中安全发布不可变对象。 声明诸如public volatile ImmutableObject foo
之类的字段可确保所有线程始终看到当前可用的实例引用。
Iterator
和ListIterator
之间的区别?
我们可以使用Iterator
遍历Set
或List
或Map
。 但是ListIterator
仅可用于遍历List
。 其他差异如下所示。
您可以:
- 向后迭代。
- 随时获取索引。
- 随时添加新值。
- 在这个时间设置一个新值。
例如:
List<String> names = new ArrayList<String>();
names.add("Alex");
names.add("Bob");
names.add("Charles");
System.out.println(names);
ListIterator<String> listIterator = names.listIterator();
//Add a value at any place using ListIterator
while(listIterator.hasNext()){
listIterator.next();
listIterator.add("Lokesh");
}
System.out.println(names);
listIterator = names.listIterator();
//Set a value at any place using ListIterator
while(listIterator.hasNext()){
listIterator.next();
listIterator.set("John");
}
System.out.println(names);
Output:
[Alex, Bob, Charles]
[Alex, Lokesh, Bob, Lokesh, Charles, Lokesh]
[John, John, John, John, John, John]
显然,我可以在列表中的任意位置添加元素,同时对其进行迭代 – 同样,我也可以更改任何元素。 使用Iterator
不可能。
学习愉快!
Java 核心面试问题 – 第 3 部分
原文: https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-3/
在 面试问题系列中:第 1 部分和第 2 部分,我们讨论了面试官通常会问的一些重要问题。 现在是推进该讨论的时候了。 在这篇文章中,我将在下面给出的问题列表中进行讨论。
Deep copy and shallow copy?
What is synchronization? Class level locking and object level locking?
Difference between sleep() and wait()?
Can you assign null to this reference variable?
What if the difference between && and &??
How to override equals and hashCode() methods?
Explain all access modifiers?
What is garbage collection? Can we enforce it?
What is native keyword?
What is serialization? Explain the catches?
深拷贝和浅拷贝?
克隆是原始副本的精确副本。 在 Java 中,它实质上意味着能够创建状态与原始对象相似的对象。clone()
方法提供了此功能。
浅拷贝应尽可能少地重复。 默认情况下,Java 克隆是浅表复制或“逐字段复制”,即,由于Object
类不了解将在其上调用clone()
方法的类的结构。 因此,JVM 被要求克隆时,请执行以下操作:
1)如果该类只有原始数据类型成员,则将创建该对象的全新副本,并返回对该新对象副本的引用。
2)如果该类包含任何类类型的成员,则仅复制对那些成员的对象引用,因此原始对象和克隆对象中的成员引用都引用同一对象。
深层副本会复制所有内容。 集合的深层副本是两个集合,原始集合中的所有元素都重复了。 在这里,我们想要一个独立于原始版本的克隆,对克隆进行更改不应影响原始版本。
深度克隆要求满足以下规则。
- 无需单独复制原始类型。
- 原始类中的所有成员类都应支持克隆,而上下文中原始类的
clone
方法应在所有成员类上调用super.clone()
。 - 如果任何成员类不支持克隆,则必须在克隆方法中创建该成员类的新实例,并将其所有属性一一复制到新的成员类对象中。 这个新的成员类对象将在克隆对象中设置。
什么是同步? 对象级锁定和类级锁定?
同步是指多线程。 同步的代码块一次只能由一个线程执行。 Java 支持执行多个线程。 这可能会导致两个或多个线程访问相同的字段或对象。 同步是使所有并发线程在执行中保持同步的过程。 同步避免了由于共享内存视图不一致而导致的内存一致性错误。 当方法声明为已同步时; 该线程持有该方法对象的监视器。如果另一个线程正在执行同步方法,则该线程将被阻塞,直到该线程释放监视器。
Java 中的同步是使用syncronized
关键字实现的。 您可以在类中的已定义方法或块上使用syncronized
关键字。 关键字不能与类定义中的变量或属性一起使用。
对象级别锁定是一种机制,当您要同步非静态方法或非静态代码块,以便仅一个线程将能够在给定实例的代码上执行代码块时, 类。 应该始终这样做以确保实例级数据线程安全。
类级别锁定可防止多个线程在运行时进入所有可用实例中的任何同步块。 这意味着,如果在运行时有 100 个DemoClass
实例,则一次只能在一个实例中的任何一个线程上执行demoMethod()
,而所有其他实例将被其他线程锁定。 为了确保静态数据线程的安全,应该始终这样做。
sleep()
和wait()
之间的区别?
sleep()
是一种用于将进程保留几秒钟或所需时间的方法,但是如果使用wait()
方法,线程将进入等待状态,直到我们调用notify()
或notifyAll()
。
主要区别在于,wait()
释放锁定或监视器,而sleep()
不在等待期间释放任何锁或监视器。 通常,“等待”用于线程间通信,而“睡眠”用于引入执行暂停。
Thread.sleep()
在一段时间内将当前线程发送到“不可运行”状态。 该线程将保留其已获取的监视器 - 即,如果该线程当前处于同步块或方法中,则其他线程无法进入该块或方法。 如果另一个线程调用t.interrupt()
,它将唤醒睡眠线程。 请注意,sleep
是一种静态方法,这意味着它始终会影响当前线程(正在执行sleep
方法的线程)。 一个常见的错误是调用t.sleep()
,其中t
是一个不同的线程。 即使这样,当前线程仍将睡眠,而不是t
线程。
object.wait()
将当前线程发送到“不可运行”状态,就像sleep()
一样,但要稍加调整。 Wait
是在对象而不是线程上调用的; 我们将此对象称为“锁定对象”。 在调用lock.wait()
之前,当前线程必须在锁对象上进行同步。 然后,wait()
释放此锁定,并将线程添加到与该锁定关联的“等待列表”。 稍后,另一个线程可以在同一个锁对象上同步并调用lock.notify()
。 这将唤醒原始的等待线程。 基本上,wait()
/notify()
就像sleep()
/interrupt()
一样,仅活动线程不需要直接指针指向睡眠线程,而仅需要指向共享锁对象的指针。
可以为this
引用变量分配null
吗?
没有。 你不能。在 Java 中,赋值语句的左侧必须是变量。 “this
”是一个特殊的关键字,始终代表当前实例。 这不是任何变量。
同样,不能将null
分配给“super
”或任何此类关键字。
&&
和&
之间是否有区别?
&
是按位的,&&
是逻辑的。
&
求值操作的双方。&&
求值操作的左侧,如果为真,则继续并求值右侧。
如何覆盖equals
和hashCode()
方法?
hashCode()
和equals()
方法已在Object
类中定义,Object
类是 Java 对象的父类。 因此,所有 java 对象都继承这些方法的默认实现。
hashCode()
方法用于获取给定对象的唯一整数。 当此对象需要存储在类似数据结构的HashTable
中时,此整数用于确定存储桶位置。 默认情况下,对象的hashCode()
方法返回存储对象的内存地址的整数表示形式。
顾名思义,equals()
方法用于简单地验证两个对象的相等性。 默认实现只是检查两个对象的对象引用以验证它们的相等性。
以下是在覆盖这些函数时要记住的要点。
- 始终使用对象的相同属性来生成
hashCode()
和equals()
两者。 在本例中,我们使用了员工 ID。 equals(
)必须一致(如果未修改对象,则必须保持返回相同的值)。- 只要
a.equals(b)
,则a.hashCode()
必须与b.hashCode()
相同。 - 如果覆盖一个,则应覆盖另一个。
解释所有访问修饰符?
Java 类,字段,构造器和方法可以具有四种不同的访问修饰符之一:
private
如果将方法或变量标记为私有,则只有同一类内的代码才能访问该变量或调用该方法。 子类中的代码无法访问变量或方法,也不能从任何外部类中进行代码。
如果将一个类标记为私有,则没有外部类可以访问该类。 不过,对于类来说,这实际上没有多大意义。 因此,访问修饰符private
主要用于字段,构造器和方法。
默认
通过根本不编写任何访问修饰符来声明默认访问级别。 默认访问级别意味着与类相同的包中的类本身内的代码+类内的代码可以访问类,字段,构造器或方法。 因此,默认访问修饰符有时也称为包访问修饰符。
如果子类声明了默认的可访问性,则子类不能访问父类中的方法和成员变量,除非子类与父类位于同一包中。
protected
protected
访问修饰符的作用与默认访问权限相同,除了子类还可以访问超类的受保护方法和成员变量。 即使子类与超类不在同一个包中,也是如此。
public
公开访问修饰符意味着所有代码都可以访问类,字段,构造器或方法,无论访问代码位于何处。
| 修饰符 | 相同的类 | 相同的包 | 子类 | 其他包 |
| --- | --- | --- |
| public
| Y | Y | Y | Y |
| protected
| Y | Y | Y | N |
| 默认 | Y | Y | N | N |
| private
| Y | N | N | N |
什么是垃圾回收? 我们可以执行吗?
垃圾回收是许多现代编程语言(例如 Java 和 .NET 框架中的语言)中的自动内存管理功能。 使用垃圾回收的语言通常在 JVM 之类的虚拟机中解释或运行。 在每种情况下,运行代码的环境还负责垃圾回收。 GC 具有两个目标:应释放所有未使用的内存,并且除非程序不再使用它,否则不应释放任何内存。
你能强迫垃圾收集吗? 不,System.gc()
尽可能接近。 最好的选择是调用System.gc()
,这只是向垃圾收集器提示您要它进行收集。 由于垃圾收集器是不确定的,因此无法强制立即收集。 另外,在OutOfMemoryError
文档下,它声明除非 VM 在完全垃圾回收后未能回收内存,否则不会抛出该错误。 因此,如果在出现错误之前一直分配内存,那么您将已经强制执行完整的垃圾回收。
什么是`native关键字? 详细解释?
将native
关键字应用于方法,以指示该方法是使用 JNI 在本地代码中实现的。 它标记了一种方法,它将以其他语言而不是 Java 来实现。
过去曾使用本机方法来编写对性能至关重要的部分,但随着 Java 变得越来越快,这种方法现在已不那么普遍了。 当前需要本机方法
- 您需要从 Java 调用用其他语言编写的库。
- 您需要访问只能从其他语言(通常为 C)访问的系统或硬件资源。 实际上,许多与真实计算机交互的系统功能(例如磁盘和网络 IO)只能执行此操作,因为它们调用了本机代码。
使用本机代码库的缺点也很重要:
- JNI/JNA 倾向于破坏 JVM 的稳定性,尤其是当您尝试做一些复杂的事情时。 如果您的本机代码错误地执行了本机代码内存管理,则很有可能会使 JVM 崩溃。 如果您的本机代码是不可重入的,并且从多个 Java 线程中调用,则坏事……会偶尔发生。 等等。
- 带有本机代码的 Java 比纯 Java 或纯 C/C++ 更难调试。
- 本机代码可能为其他平台无关的 Java 应用引入重要的平台依赖项/问题。
- 本机代码需要一个单独的构建框架,并且也可能存在平台/可移植性问题。
什么是序列化? 解释渔获物?
在计算机科学中,在数据存储和传输的上下文中,序列化是将数据结构或对象状态转换为一种格式的过程,该格式可以稍后在相同或另一台计算机环境中存储和恢复。 当根据序列化格式重新读取生成的一系列位时,可以使用它来创建原始对象的语义相同的克隆。
Java 提供了自动序列化,该序列化要求通过实现java.io.Serializable
接口来标记对象。 实现该接口会将类标记为“可以序列化”,然后 Java 将在内部处理序列化。 在Serializable
接口上没有定义任何序列化方法,但是可序列化类可以选择定义具有某些特殊名称和签名的方法,如果定义了这些特殊名称和签名,这些方法将在序列化/反序列化过程中被调用。
对象序列化后,其类中的更改会破坏反序列化过程。 要确定您的类中将来的变化,这些变化将是兼容的,而其他变化将被证明是不兼容的,请在此处阅读完整的指南。 简而言之,我在这里列出:
不兼容的更改
- 删除字段
- 将类上移或下移
- 将非静态字段更改为静态或将非瞬态字段更改为瞬态
- 更改原始字段的声明类型
- 更改
writeObject
或readObject
方法,使其不再写入或读取默认字段数据 - 将类从可序列化更改为可外部化,反之亦然
- 将类从非枚举类型更改为枚举类型,反之亦然
- 删除
Serializable
或Externalizable
- 将
writeReplace
或readResolve
方法添加到类
兼容的更改
- 新增字段
- 添加/删除类
- 添加
writeObject
/readObject
方法(首先应调用defaultReadObject
或defaultWriteObject
) - 删除
writeObject
/readObject
方法 - 添加
java.io.Serializable
- 更改对字段的访问
- 将字段从静态更改为非静态或将瞬态更改为非瞬态
学习愉快!
Java 面试的 40 个热门问答集
原文: https://howtodoinjava.com/interview-questions/useful-java-collection-interview-questions/
毫无疑问,java 集合是最重要的领域之一,无论您是初级还是高级,您都可以在任何位置对其进行测试。 范围如此之广,几乎不可能涵盖所有问题。 但是,根据我以前的面试,我尝试提出您必须知道的尽可能多的优秀的 java 集合面试问题。
我的目标是初学者和高级问题,所以如果您发现一些基本问题,请多多包涵,因为它们对某些初级开发人员可能有用。
Java collection interview questions
General questions
1) What is the Java Collections API? List down its advantages?
2) Explain Collections hierarchy?
3) Why Collection interface does not extend Cloneable and Serializable interface?
4) Why Map interface does not extend Collection interface?
List interface related
5) Why we use List interface? What are main classes implementing List interface?
6) How to convert an array of String to ArrayList?
7) How to reverse the list?
Set interface related
8) Why we use Set interface? What are main classes implementing Set interface?
9) How HashSet store elements?
10) Can a null element added to a TreeSet or HashSet?
Map interface related
11) Why we use Map interface? What are main classes implementing Map interface?
12) What are IdentityHashMap and WeakHashMap?
13) Explain ConcurrentHashMap? How it works?
14) How hashmap works?
15) How to design a good key for hashmap?
16) What are different Collection views provided by Map interface?
17) When to use HashMap or TreeMap?
Tell the difference questions
18) Difference between Set and List?
19) Difference between List and Map?
20) Difference between HashMap and HashTable?
21) Difference between Vector and ArrayList?
22) Difference between Iterator and Enumeration?
23) Difference between HashMap and HashSet?
24) Difference between Iterator and ListIterator?
25) Difference between TreeSet and SortedSet?
26) Difference between ArrayList and LinkedList?
More questions
27) How to make a collection read only?
28) How to make a collection thread safe?
29) Why there is not method like Iterator.add() to add elements to the collection?
30) What are different ways to iterate over a list?
31) What do you understand by iterator fail-fast property?
32) What is difference between fail-fast and fail-safe?
33) How to avoid ConcurrentModificationException while iterating a collection?
34) What is UnsupportedOperationException?
35) Which collection classes provide random access of it’s elements?
36) What is BlockingQueue?
37) What is Queue and Stack, list their differences?
38) What is Comparable and Comparator interface?
39) What are Collections and Arrays class?
40) Recommended resources
不要浪费时间,让我们深入研究 Java 集合的概念。
Java 集合面试一般问题
1)什么是 Java 集合框架? 列出其优势?
根据定义,集合是代表一组对象的对象。 像集合论一样,集合是一组元素。 很简单!
在 JDK 1.2 之前,JDK 具有一些工具类,例如Vector
和HashTable
,但是没有集合框架的概念。 从 JDK 1.2 以后,JDK 感到需要对可重用数据结构提供一致的支持。 最后,集合框架主要由 Joshua Bloch 设计和开发,并在 JDK 1.2 中引入。
Java 集合的最明显的优点可以列出为:
- 随时可用的代码,减少了编程工作
- 由于数据结构和算法的高性能实现而提高了性能
- 通过建立公共语言来回传递集合,从而在不相关的 API 之间提供互操作性
- 通过仅学习一些顶级接口和受支持的操作,易于学习的 API
2)解释集合的层次结构?
Java 集合的层次结构
如上图所示,集合框架顶部有一个接口,即集合。 通过集,列表和队列接口对其进行了扩展。 然后在这 3 个分支中还有其他类别的负载,我们将在以下问题中学习。
记住Collection
接口的签名。 它会在很多问题上帮助您。
public interface Collection extends Iterable {
//method definitions
}
框架还包含Map
接口,它是集合框架的一部分。 但它不会扩展Collection
接口。 我们将在此问题库中的第四个问题中看到原因。
3)为什么Collection
接口没有扩展Cloneable
和Serializable
接口?
好吧,最简单的答案是“不需要这样做”。 扩展接口仅表示您正在创建接口的子类型,换句话说,不希望使用更专门的行为和Collection
接口来实现Cloneable
和Serializable
接口。
另一个原因是并非每个人都有理由拥有Cloneable
集合,因为如果它具有非常大的数据,那么每个不必要的克隆操作都将消耗大量内存。 初学者可能在不知道后果的情况下使用它。
另一个原因是Cloneable
和Serializable
是非常专门的行为,因此仅在需要时才应实现。 例如,集合中的许多具体类都实现了这些接口。 因此,如果您想要此功能。 使用这些集合类,否则使用其替代类。
4)为什么Map
接口没有扩展Collection
接口?
这个面试问题的一个很好的答案是“因为它们不兼容”。 集合具有方法add(Object o)
。 Map 无法使用这种方法,因为它需要键值对。 还有其他原因,例如Map
支持keySet
,valueSet
等。Collection
类没有此类视图。
由于存在如此大的差异,因此在Map
接口中未使用Collection
接口,而是在单独的层次结构中构建。
Java 集合面试 – 列出接口问题
5)为什么要使用List
接口? 什么是实现List
接口的主要类?
Java 列表是元素的“有序”集合。 该排序是基于零的索引。 它不关心重复项。 除了在Collection
接口中定义的方法外,它确实有自己的方法,它们在很大程度上也要根据元素的索引位置来操作集合。 这些方法可以分为搜索,获取,迭代和范围视图。 以上所有操作均支持索引位置。
实现List
接口的主要类为: Stack
,Vector
,ArrayList
和LinkedList
。 在 Java 文档中阅读有关它们的更多信息。
6)如何将String
数组转换为arraylist
?
这更多是一个程序性问题,在初学者水平上可以看到。 目的是检查集合工具类中申请人的知识。 现在,让我们了解Collection
框架中有两个工具类,它们大多数在面试中看到,即Collections
和Arrays
。
集合类提供了一些静态函数来对集合类型执行特定操作。 数组提供了要在数组类型上执行的工具函数。
//String array
String[] words = {"ace", "boom", "crew", "dog", "eon"};
//Use Arrays utility class
List wordList = Arrays.asList(words);
//Now you can iterate over the list
请注意,此函数并非特定于String
类,它将返回数组属于任何类型的元素的List
。 例如:
//String array
Integer[] nums = {1,2,3,4};
//Use Arrays utility class
List numsList = Arrays.asList(nums);
7)如何反转列表?
这个问题就像上面的测试您对集合工具类的了解。 使用它的reverse()
方法可以反转列表。
Collections.reverse(list);
Java 集合面试 – `Set``接口问题
8)为什么要使用Set
接口? 什么是实现Set
接口的主要类?
它对集合论中的数学集合进行建模。 Set
接口类似于List
接口,但有一些区别。 首先,它是未排序的集合。 因此,添加或删除元素时不会保留任何顺序。 它提供的主要功能是“元素的唯一性”。 它不支持重复元素。
Set
还对equals
和hashCode
操作的行为增加了更强的约定,从而即使它们的实现类型不同,也可以有意义地比较Set
实例。 如果两个Set
实例包含相同的元素,则它们相等。
基于上述原因,它没有基于列表之类的元素的索引进行的操作。 它只有由Collection
接口继承的方法。
实现Set
接口的主要类为:EnumSet
,HashSet
,LinkedHashSet
,TreeSet
。 阅读更多有关 Java 文档的信息。
9)HashSet
如何存储元素?
您必须知道HashMap
存储具有一个条件的键值对,即键将是唯一的。 HashSet
使用映射的此功能来确保元素的唯一性。 在HashSet
类中,映射声明如下:
private transient HashMap<E,Object> map;
//This is added as value for each key
private static final Object PRESENT = new Object();
因此,将元素存储在HashSet
中时,会将元素存储为映射中的键,将“PRESENT
”对象存储为值。 (请参见上面的声明)。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
我强烈建议您阅读这篇文章:HashMap
如何在 Java 中工作?这篇文章将帮助您轻松地回答所有与HashMap
相关的问题。
10)是否可以将null
元素添加到TreeSet
或 HashSet 中?
如您所见,上一个问题的add()
方法中没有null
检查。 并且HashMap
还允许一个null
键,因此在HashSet
中允许一个“null
”。
TreeSet
使用与HashSet
相同的概念进行内部逻辑,但是使用NavigableMap
来存储元素。
private transient NavigableMap<E,Object> m;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
NavigableMap
是SortedMap
的子类型,不允许使用null
键。 因此,本质上,TreeSet
也不支持空键。 如果您尝试在TreeSet
中添加null
元素,它将抛出NullPointerException
。
Java 集合面试 – Map
接口问题
11)为什么要使用Map
接口? 什么是实现Map
接口的主要类?
Map
接口是一种特殊的集合类型,它用于存储键值对。 因此,它不会扩展Collection
接口。 该接口提供了在映射的各种视图上添加,删除,搜索或迭代的方法。
实现Map
接口的主要类有:HashMap
,Hashtable
,EnumMap
,IdentityHashMap
,LinkedHashMap
和Properties
。
12)什么是 IdentityHashMap
和WeakHashMap
?
IdentityHashMap
与HashMap
相似,不同之处在于在比较元素时使用引用相等性。 IdentityHashMap
类不是一种广泛使用的Map
实现。 尽管此类实现了Map
接口,但它有意违反Map
的一般协定,该协定要求在比较对象时必须使用equals()
方法。 IdentityHashMap
设计为仅在少数情况下使用,其中需要引用相等语义。
WeakHashMap
是Map
接口的实现,该接口仅存储对其键的弱引用。 当不再在WeakHashMap
外部引用键值对时,仅存储弱引用将允许对键值对进行垃圾回收。 该类主要用于与equals
方法使用==
运算符测试对象标识的键对象一起使用。 一旦丢弃了这样的键,就永远无法重新创建它,因此以后不可能在WeakHashMap
中对该键进行查找,并且会惊讶地发现它的项目已被删除。
13)解释ConcurrentHashMap
吗? 怎么运行的?
来自 Java 文档:
支持检索的完全并发和用于更新的可调整预期并发的哈希表。 此类遵循与Hashtable
相同的功能规范,并且包括与Hashtable
的每个方法相对应的方法的版本。 但是,即使所有操作都是线程安全的,检索操作也不需要进行锁定,并且不支持以阻止所有访问的方式锁定整个表。 在依赖于其线程安全性但不依赖于其同步详细信息的程序中,此类可与Hashtable
完全互操作。
阅读有关ConcurrentHashMap
面试问题的更多信息。
14)HashMap
如何工作?
最重要的问题在每个工作面试中最有可能出现。 您必须在这个主题上非常清楚。不仅因为它是最常被问到的问题,而且会让您对与集合 API 相关的其他问题打开思路。
这个问题的答案非常大,您应该阅读我的文章:HashMap
如何工作? 现在,让我们记住HashMap
在哈希原理上工作。 根据定义,映射是:“将键映射到值的对象”。 为了存储这种结构,使用了内部类Entry
:
static class Entry implements Map.Entry
{
final K key;
V value;
Entry next;
final int hash;
...//More code goes here
}
此处,键和值变量用于存储键值对。 整个项目对象存储在数组中。
/**
* The table, re-sized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;
数组的索引是根据Key
对象的哈希码计算的。 阅读更多链接主题。
15)如何为哈希表设计一个好的键?
在回答HashMap
如何工作后,通常会跟进另一个好问题。 好吧,最重要的约束是,您将来必须能够取回值对象。 否则,没有使用这种数据结构。 如果您了解hashmap
的工作原理,将会发现它很大程度上取决于Key
对象的hashCode()
和equals()
方法。
因此,好的键对象必须一次又一次提供相同的hashCode()
,无论它被获取了多少次。 同样,与equals()
方法比较时,相同的键必须返回true
,而不同的键必须返回false
。
因此,不变类被认为是HashMap
键的最佳候选者。
阅读更多:如何为HashMap
设计一个好的键?
16)Map
接口提供哪些不同的集合视图?
Map
接口提供了 3 个存储在其中的键值对的视图:
- 键集视图
- 值集视图
- 项集视图
可以使用迭代器浏览所有视图。
17)什么时候使用HashMap
或TreeMap
?
HashMap
是众所周知的类,我们所有人都知道。 因此,我将离开这部分,说它用于存储键值对,并允许对这样的对集合执行许多操作。
TreeMap
是HashMap
的特殊形式。 它维护HashMap
类中缺少的键的顺序。 默认情况下,此排序为“自然排序”。 通过提供Comparator
类的实例,可以覆盖默认顺序,该类的compare
方法将用于维护键的顺序。
请注意,所有插入映射的键都必须实现Comparable
接口(这是确定顺序的必要条件)。 此外,所有这些键必须相互可比较:k1.compareTo(k2)
不得为映射中的任何键k1
和k2
抛出ClassCastException
。 如果用户尝试将键放入违反此约束的映射中(例如,用户尝试将字符串键放入其键为整数的映射中),则put(Object key, Object value)
调用将引发ClassCastException
。
Java 集合面试 – 讲述差异问题
18)Set
和List
之间的区别?
最明显的区别是:
Set
是无序集合,其中List
是基于零索引的有序集合。- 列表允许重复元素,但
Set
不允许重复。 List
不会阻止插入空元素(随您喜欢),但是Set
将只允许一个空元素。
19)列表和映射之间的区别?
也许是最简单的问题。 列表是元素的集合,而映射是键值对的集合。 实际上,有很多差异源自第一个陈述。 它们具有单独的顶层接口,单独的一组通用方法,不同的受支持方法和不同的集合视图。
我会花很多时间来回答这个问题,仅作为第一个区别就足够了。
20)HashMap
和HashTable
之间的区别?
Java 中的HashMap
和Hashtable
之间有一些区别:
Hashtable
是同步的,而HashMap
不是同步的。- 哈希表不允许使用空键或空值。
HashMap
允许一个空键和任意数量的空值。 HashMap
与Hashtable
之间的第三个重要区别是HashMap
中的Iterator
是快速失败的迭代器,而Hashtable
的枚举器则不是。
21)Vector
和ArrayList
之间的区别?
让我们记下差异:
Vector
的所有方法都是同步的。 但是,ArrayList
的方法不同步。Vector
是在 JDK 的第一个版本中添加的旧类。 当在 Java 中引入集合框架时,ArrayList
是 JDK 1.2 的一部分。- 默认情况下,
Vector
在内部调整大小时会将其数组的大小加倍。 但是,重新调整大小时,ArrayList
的大小增加一半。
22)迭代器和枚举器之间的区别?
迭代器与枚举在以下三个方面有所不同:
- 迭代器允许调用方使用其
remove()
方法在迭代过程中从基础集合中删除元素。 使用枚举器时,不能从集合中添加/删除元素。 - 枚举器在旧类(例如
Vector
/Stack
等)中可用,而Iterator
在所有现代集合类中可用。 - 另一个小的区别是
Iterator
改进了方法名称,例如Enumeration.hasMoreElement()
变为Iterator.hasNext()
,Enumeration.nextElement()
变为Iterator.next()
等。
23)HashMap
和HashSet
之间的区别?
HashMap
是键值对的集合,而HashSet
是唯一元素的无序集合。 而已。 无需进一步描述。
24)Iterator
和ListIterator
之间的区别?
有三个区别:
- 我们可以使用
Iterator
遍历Set
和List
以及Map
的Object
类型。 但是列表迭代器可用于遍历列表类型的对象,但不能遍历对象的集合类型。 - 通过使用
Iterator
,我们只能从正向检索Collection
对象中的元素,而List Iterator
则允许您使用hasPrevious()
和previous()
方法在任一方向上遍历。 ListIterator
允许您使用add() remove()
方法修改列表。 使用Iterator
不能添加,只能删除元素。
25)TreeSet
和SortedSet
之间的区别?
SortedSet
是TreeSet
实现的接口。 就是这样!
26)ArrayList
和LinkedList
之间的区别?
LinkedList
将元素存储在双链列表数据结构中。ArrayList
将元素存储在动态调整大小的数组中。LinkedList
允许进行固定时间的插入或删除,但只允许顺序访问元素。 换句话说,您可以向前或向后浏览列表,但是在中间抓取一个元素所花费的时间与列表的大小成正比。 另一方面,ArrayList
允许随机访问,因此您可以在固定时间内抓取任何元素。 但是,从末端开始的任何地方添加或删除,都需要将后面的所有元素移开,以形成开口或填补空白。LinkedList
比ArrayList
具有更多的内存开销,因为在ArrayList
中,每个索引仅保存实际的对象(数据),但是在LinkedList
的情况下,每个节点都保存下一个和上一个节点的数据以及地址。
更多面试面试问题
27)如何使集合只读?
使用以下方法:
Collections.unmodifiableList(list);
Collections.unmodifiableSet(set);
Collections.unmodifiableMap(map);
这些方法采用集合参数,并返回一个具有与原始集合中相同的元素的新的只读集合。
28)如何使集合线程安全?
使用以下方法:
Collections.synchronizedList(list);
Collections.synchronizedSet(set);
Collections.synchronizedMap(map);
上面的方法将集合作为参数并返回相同类型的集合,这些类型是同步的且线程安全的。
29)为什么没有像Iterator.add()
这样的方法将元素添加到集合中?
迭代器的唯一目的是通过集合进行枚举。 所有集合都包含add()
方法以实现您的目的。 添加Iterator
毫无意义,因为集合可能有序,也可能没有排序。 而且add()
方法对于有序和无序集合不能具有相同的实现。
30)有哪些不同的方法可以遍历列表?
您可以使用以下方式遍历列表:
- 迭代器循环
for
循环for
循环(高级)While
循环
阅读更多: http://www.mkyong.com/java/how-do-loop-iterate-a-list-in-java/
31)通过迭代器快速失败属性您了解什么?
快速失败迭代器一旦意识到自迭代开始以来就已更改集合的结构,便会失败。 结构更改意味着在一个线程迭代该集合时,从集合中添加,删除或更新任何元素。
通过保留修改计数来实现快速失败行为,如果迭代线程实现了修改计数的更改,则会引发ConcurrentModificationException
。
32)快速失败和故障安全之间有什么区别?
您已经在上一个问题中理解了快速失败。 故障安全迭代器与快速失败相反。 如果您修改要在其上进行迭代的基础集合,它们将永远不会失败,因为它们在集合的克隆而不是原始集合上起作用,这就是为什么将它们称为故障保护迭代器。
CopyOnWriteArrayList
的迭代器是故障安全迭代器的示例,而且ConcurrentHashMap keySet
编写的迭代器也是故障安全迭代器,并且永远不会抛出ConcurrentModificationException
。
33)如何在迭代集合时避免ConcurrentModificationException
?
您应该首先尝试查找故障安全的另一个替代迭代器。 例如,如果您正在使用List
,则可以使用ListIterator
。 如果它是旧式集合,则可以使用枚举。
如果上述选项不可行,则可以使用以下三种更改之一:
- 如果使用的是 JDK1.5 或更高版本,则可以使用
ConcurrentHashMap
和CopyOnWriteArrayList
类。 这是推荐的方法。 - 您可以将列表转换为数组,然后在数组上进行迭代。
- 您可以通过将列表放在同步块中来在迭代时锁定列表。
请注意,最后两种方法会导致性能下降。
34)什么是UnsupportedOperationException
?
实际的集合类型不支持的被调用方法抛出的异常。
例如,如果您使用“Collections.unmodifiableList(list)
”创建一个只读列表列表,然后调用add()
或remove()
方法,那将会发生什么。 它应该明确抛出UnsupportedOperationException
。
35)哪些集合类可随机访问其元素?
ArrayList
,HashMap
,TreeMap
,Hashtable
类提供对其元素的随机访问。
36)什么是BlockingQueue
?
一个队列,它另外支持以下操作:在检索元素时等待队列变为非空,并在存储元素时等待队列中的空间变为可用。
BlockingQueue
方法有四种形式:一种抛出异常,第二种返回一个特殊值(根据操作的不同,返回null
或false
),第三种无限期地阻塞当前线程,直到操作成功为止;第四种仅在放弃之前给出最大时间限制。
阅读文章中的阻塞队列示例用法: 如何使用阻塞队列?
37)什么是队列和栈,列出它们之间的差异?
设计用于在处理之前保存元素的集合。 除了基本的集合操作之外,队列还提供其他插入,提取和检查操作。
通常但不一定以 FIFO(先进先出)的方式对元素进行排序。
栈也是队列的一种形式,但有一个区别,那就是 LIFO(后进先出)。
无论使用哪种顺序,队列的开头都是该元素,可以通过调用remove()
或poll()
将其删除。 另请注意,栈和向量都已同步。
用法:如果要按接收顺序处理传入流,请使用队列。适用于工作列表和处理请求。
如果只想从栈顶部推动并弹出,请使用栈。 适用于递归算法。
38)什么是Comparable
和Comparator
接口?
在 Java 中。 所有具有自动排序功能的集合都使用比较方法来确保元素的正确排序。 例如,使用排序的类为TreeSet
,TreeMap
等。
为了对一个类的数据元素进行排序,需要实现Comparator
或Comparable
接口。 这就是所有包装器类(例如Integer
,Double
和String
类)都实现Comparable
接口的原因。
Comparable
帮助保留默认的自然排序,而Comparator
帮助以某些特殊的必需排序模式对元素进行排序。 比较器的实例,通常在支持集合时作为集合的构造器参数传递。
39)什么是Collections
和Arrays
类?
Collections
和Arrays
类是支持集合框架核心类的特殊工具类。 它们提供工具函数以获取只读/同步集合,以各种方式对集合进行排序等。
数组还帮助对象数组转换为集合对象。 数组还具有一些函数,有助于复制或处理部分数组对象。
40)推荐资源
好吧,这不是面试的问题.. 😃。 这只是为了好玩。 但是您应该真正阅读我的博客,以获取有关集合框架知识的更多帖子。
希望这些 Java 集合面试问题对您的下一次面试有所帮助。 此外,除了本文之外,我建议您阅读更多有关上述问题的信息。 更多的知识只会帮助您。
学习愉快!
中级开发人员的 Java 面试问题
原文: https://howtodoinjava.com/interview-questions/java-interview-questions-for-mid-level-developers/
实际上,这个面试问题最初是由我们的读者之一尼基尔提出的。 他的问题是:“我的问题是,我有 6 年的 java/j2ee 开发人员经验,并且我打算更换公司。 您能否建议我准备面试所需的所有主题,以及参加面试和公司对我的经验的期望……对于基于产品/服务的公司..”
中级 Java 面试准备
为了回答这个问题,我回答了以下答案。
- 您提出的问题的答案范围非常广。 我建议集中精力于简历中的内容……显然。
- 接下来,关注设计模式。 完美准备 3-4 种模式。 准备给现实生活中的示例,以及如何在以前的项目中使用它们。 他们一定会问这个问题。
- 接下来,了解有关当前项目的每个细节。 系统设计,模块设计,数据库结构..以及它们提供的总体好处。 一切都放在指尖上。
- 学习和练习多线程(特别是执行器和线程池)。 在纸上创建一些程序。 练习一下。
- 尝试编写一些棘手的 SQL 查询等。了解联接,索引及其语法。
- 您也应该期待 OOP 概念。 准备自己的定义并记住。
- 我认为,其余的都是您将在简历中提及的技术。
祝您学习愉快!
针对 Oracle 企业管理器项目的实际 Java 面试问题
Oracle 企业管理器可帮助私有和公共云服务提供商在释放管理资源的同时,将云服务的速度提高十倍。 这是来自 Oracle 的非常受欢迎的产品。
HowToDoInJava 的读者之一,Sreenath Ravva,出现在上述产品(即 oracle 企业管理器)职位的采访中。 他与我分享了以下列出的问题,以便我可以与大家分享,希望在任何美好的一天中对我们中的几个人都没有好处。
注意:我已尝试在网页上放置链接,以供您参考以下面试问题的答案。 它们可能不足以涵盖该主题,但是它们可以帮助您入门。
第一轮(电话)java 面试题
1)您可以开始讲述自己和您的项目吗?
https://www.youtube.com/embed/CumOvDWnUDY?feature=oembed
2)什么是 Java 中的抽象和封装?
– https://howtodoinjava.com/object-oriented/understanding-abstraction-in-java/
– https://howtodoinjava.com/object-oriented/encapsulation-in-java-and-its-relation-with-abstraction/
3)方法重载规则? 我们可以在子类中重载超类方法吗? 该示例进行了讨论。
- https://howtodoinjava.com/2013/07/15/what-is-polymorphism-in-java
- http://stackoverflow.com/questions/10901259/java-overloading-rules
4)方法覆盖规则?
http://docs.oracle.com/javase/tutorial/java/IandI/override.html
5)Java 中的扩大和缩小? 讨论发生在例子上吗?
http://stackoverflow.com/questions/16781649/real-world-application-of-widening-narrowing-conversion
6)我在代码中可以只有try
块吗?
不。您至少需要catch
块或finally
块以及try
块。(直到 Java 6)
如“Ievgen”在评论中提到的,从 JDK 7 开始,您可以使用try-with-resources
带有“可选的”catch
或finally
块。
try (FileInputStream f = new FileInputStream("ttt"))
{
System.out.println("t");
}
7)线程:生产者和消费者的问题?
- http://en.wikipedia.org/wiki/Producer-consumer_problem
- http://howtodoinjava.com/java-5/how-to-use-blockingqueue-and-threadpoolexecutor-in-java/
8)为什么在Object
类中定义了wait()
,notify()
和notifyAll()
?
- http://howtodoinjava.com/2013/03/04/core-java-interview-questions-series-part-2/
- http://stackoverflow.com/questions/17840397/concept-behind-putting-wait-notify-methods-in-object-class
9)我们可以覆盖wait()
或notify()
方法吗?
在Object.java
中,方法getClass()
,notify()
,notifyAll()
和三个wait()
方法是最终的,因此您无法覆盖它们。
10)wait()
,sleep()
和yield()
之间的区别?
11)解释线程类中的join()
方法
http://stackoverflow.com/questions/18479771/java-multithreading-concept-and-join-method
第二轮(面对面)java 面试题
1) 您可以开始讲述自己和您的项目吗?
请参阅上面列表中的第一个问题。
2)您是否遇到内存不足错误? 如果是,您如何解决? 告诉不同的情况为什么会这样?
3)数据库连接泄漏?
4)编写一个程序,使用第三个变量将两个数字互换?
import java.io.*;
public class SwappingNumberWithoutThirdVariable
{
public static void main(String[] args)throws IOException
{
int a = 0 ,b = 1;
System.out.println("a = "+a);
System.out.println("b = "+b);
//Beginning of Swapping
a = a + b;
b = a - b;
a = a - b;
//End of Swapping
System.out.println("The numbers after swapping are");
System.out.println("a = "+a);
System.out.println("b = "+b);
}
}
5)编写程序以对数组进行排序并删除重复项?
http://stackoverflow.com/questions/17967114/how-to-remove-dumoments-from-an-array-in-java
6)在单例上编写程序?
https://howtodoinjava.com/design-patterns/singleton-design-pattern-in-java/
7)我有两个包含整数的数组。 编写一个程序来合并这两个数组并删除重复的元素? 最后,我需要一个应该具有唯一元素的数组?
http://stackoverflow.com/questions/5057156/merging-lists-into-a-single-array-with-unique-elements
8)编写程序以使用 JDBC 和结果集从表中获取数据?
https://howtodoinjava.com/2013/11/24/jdbc-select-query-example/
9)如何从HashMap
获取数据?
https://howtodoinjava.com/java/interviews-questions/how-hashmap-works-in-java/
10)Vector
和ArrayList
之间的区别?
https://howtodoinjava.com/java/collections/useful-java-collection-interview-questions/
11)睡眠和等待之间的区别?
https://howtodoinjava.com/2013/03/08/difference-between-sleep-and-wait/
12)还问了一些 sql 查询。
练习一下。
13)编写程序来打印斐波那契数列?
public class FibonacciSampleCode
{
public static void main(String[] args)
{
FibonacciSampleCode fs = new FibonacciSampleCode();
fs.fibonacci();
}
public void fibonacci()
{
int numb1 = 1;
int numb2 = 1;
int temp = 0;
Scanner input=new Scanner(System.in);
System.out.println("How Many Terms? (Up To 45)");
int x=input.nextInt();
x=x-2;
System.out.println(numb1);
System.out.println(numb2);
for (int i = 0; i < x; i++)
{
System.out.println(numb1 + numb2 + " ");
temp = numb1;
numb1 = numb2;
numb2 = temp + numb2;
}
}
}
14)我们可以像下面的代码一样编写try catch
块吗?
try
{
try
{
}
}
catch()
{
}
https://howtodoinjava.com/2012/12/why-try-catch-finally-blocks-require-braces/
15)finally
块有什么用?
16)final
关键字有什么用?
http://en.wikipedia.org/wiki/Final_%28Java%29
17)我可以将类声明为静态吗?
http://stackoverflow.com/questions/2376938/why-cant-a-java-class-be-de-clared-as-static
18)什么是静态方法和静态变量?
http://stackoverflow.com/questions/7815664/static-method-and-static-variable-java
19)我可以将一个类声明为私有类吗?
http://docs.oracle.com/javase/tutorial/java/javaOO/classdecl.html
20)如果我在try
块中写return
会发生什么? finally
会执行吗? 如果写入system.exit()
,finally
块会怎样?
http://stackoverflow.com/questions/65035/does-finally-always-execute-in-java
21)为什么要更改公司?
http://www.linkedin.com/groups/How-do-you-answer-Why-1792709.S.54631120
没有人期望你说实话...🙂
这是他在写给我有关此问题的邮件时回想的所有面试问题。 我们希望这会对计划下一次与 oracle 进行面试的我们某些人有所帮助。
祝您学习愉快!
HashMap
和ConcurrentHashMap
面试问题
原文: https://howtodoinjava.com/interview-questions/hashmap-concurrenthashmap-interview-questions/
关于“HashMap
如何在 Java 中工作”,我解释了HashMap
或ConcurrentHashMap
类的内部结构以及它们如何适合整个概念。 但是,当面试官向您询问有关HashMap
相关概念时,他不仅会停留在核心概念上。 讨论通常会朝多个方向进行,以了解您是否真正了解该概念。
在这篇文章中,我将尝试在HashMap
和 ConcurrentHashMap
上涵盖一些相关的面试问题。
HashMap
和ConcurrentHashMap
面试问题
- 您将如何为
HashMap
设计一个好的键? HashMap
和ConcurrentHashMap
之间的区别?HashMap
和Collections.synchronizedMap(HashMap)
之间的区别吗?ConcurrentHashMap
和Collections.synchronizedMap(HashMap)
之间的区别?HashMap
和HashTable
之间的区别?HashTable
和Collections.synchronized(HashMap)
之间的区别?- 键的随机/固定
hashCode()
值的影响? - 在多线程应用的非同步代码中使用
HashMap
吗?
1.如何为HashMap
设计一个好的键
设计一个好的键的最基本的需求是“我们应该能够从映射中检索到值对象而不会失败”,对吗? 否则,无论您如何构建精美的数据结构,它都将毫无用处。 要确定我们已经创建了一个好的键,我们必须知道“HashMap
如何工作?。 我将介绍哈希表的工作原理,让您从链接的文章中阅读内容,但总而言之,它是基于哈希原理的。
键的哈希码主要与equals()
方法结合使用,用于将键放入映射,然后从映射中搜索回来。 因此,如果在将键值对放入映射后,键对象的哈希码发生变化,则几乎不可能从映射取回值对象。 这是内存泄漏的情况。 为了避免这种情况,映射键应该是不可变的。 这些是创建类不变的东西。
这就是为什么不可变类(例如String
,Integer
或其他包装器类)是好的关键对象候选对象的主要原因。
但是请记住,建议不可变,而不是强制性。 如果要将可变对象作为HashMap
中的键,则必须确保键对象的状态更改不会更改对象的哈希码。 这可以通过覆盖hashCode()
方法来完成。 同样,键类必须遵守hashCode()
和equals()
方法协定,以避免在运行时出现不良行为。 在链接的文章中阅读有关此约定的更多信息。
更详细的信息可在在此处找到。
2. HashMap
和ConcurrentHashMap
之间的区别
为了更好地可视化ConcurrentHashMap
,请将其视为一组HashMap
。 要从HashMap
中获取和放置键值对,您必须计算哈希码并在Collection.Entry
数组中查找正确的存储桶位置。 其余的,您已阅读了以前有关哈希表如何工作的相关文章。
在currentHashMap
中,的不同之处在于内部结构来存储这些键值对。 ConcurrentHashMap
具有段的附加概念。 当您想到一个段等于一个HashMap
时,概念上会更容易理解。 初始化时,并发HashMap
的段数默认为 16。 ConcurrentHashMap
允许相似数量(16)的线程同时访问这些段,以便在高并发期间每个线程都在特定的段上工作。
这样,如果您的键值对存储在第 10 段中; 代码不需要另外阻塞其他 15 个段。 这种结构提供了很高的并发性。
ConcurrentHashMap
内部结构
换句话说,ConcurrentHashMap
使用多个锁,每个锁控制映射的一个段。 在特定段中设置数据时,将获得该段的锁。 因此,基本上更新操作是同步的。
获取数据时,将使用易失性读取,而不会进行任何同步。 如果易失性读取导致未命中,则将获得该段的锁定,并在同步块中再次搜索项目。
3. HashMap
和Collections.synchronizedMap(HashMap)
之间的区别
这个问题很简单,对! HashMap
是不同步的,并且Collections.synchronizedMap()
返回HashMap
的包装实例,该实例具有同步的所有get
,put
方法。
本质上,Collections.synchronizedMap()
返回内部创建的内部类“SynchronizedMap
”的引用,该类包含作为参数传递的输入HashMap
的键值对。
内部类的此实例与原始参数HashMap
实例无关,并且是完全独立的。
4. ConcurrentHashMap
和Collections.synchronizedMap(HashMap)
之间的区别
这一点要难一些。 两者都是HashMap
的同步版本,其核心功能和内部结构有所不同。
如上所述,ConcurrentHashMap
由内部段组成,从概念上讲,这些内部段可以视为独立的HashMap
。 所有这样的段可以在高并发执行中被单独的线程锁定。 这样,多个线程可以从ConcurrentHashMap
获取/放置键值对,而不会互相阻塞/等待。
在Collections.synchronizedMap()
中,我们获得了HashMap
的同步版本,并且以阻塞方式进行访问。 这意味着如果多个线程尝试同时访问synchronizedMap
,将允许它们一次以同步方式获取/放置键值对。
5. HashMap
和HashTable
之间的区别
这也是一个很简单的问题。 主要区别在于HashTable
是同步的,而HashMap
不是。
如果由于其他原因而被告知,请告诉他们,HashTable
是旧类(JDK 1.0 的一部分),该类稍后通过实现Map
接口而被提升为集合框架。 它仍然具有一些附加功能,例如HashMap
缺少的Enumerator
。
另一个较小的原因可能是:HashMap
支持空键(映射到零桶),HashTable
不支持空键,并且在这种尝试时抛出NullPointerException
。
6. HashTable
和Collections.synchronized(HashMap)
之间的区别
到目前为止,您必须已经了解了它们之间相似性的核心思想。 两者都是集合的同步版本。 两者都在类内部具有同步方法。 两者本质上都是阻塞的,即在将实例中的任何内容放进去之前,多个线程将需要等待获取实例上的锁。
那么区别是什么呢。 好吧,由于上述原因,没有重大差异。 两个集合的性能也相同。
唯一将它们分开的是事实,HashTable
是提升为集合框架的旧版类。 它具有自己的额外功能,例如枚举器。
7.键的随机/固定hashcode()
值的影响
两种情况(键的固定哈希码或键的随机哈希码)的影响将产生相同的结果,即“意外行为”。 HashMap
中哈希码最基本的需求是确定存储桶的位置,以将键值对放置在哪里,以及必须从哪里检索它。
如果键对象的哈希码每次都更改,则键值对的确切位置每次都将计算为不同。 这样,存储在HashMap
中的一个对象将永远丢失,并且将其从映射取回的可能性极小。
出于同样的原因,建议键是不可变的,以便每次在同一键对象上请求时,它们都返回唯一且相同的哈希码。
8.在多线程应用中的非同步代码中使用HashMap
在正常情况下,它可使HashMap
处于不一致状态,在该状态下添加和检索的键值对可能不同。 除此之外,还会出现其他令人惊讶的行为,例如NullPointerException
。
在最坏的情况下,会导致无限循环。 是。 你答对了。 它可能导致无限循环。 你问什么,如何? 好吧,这就是原因。
当HashMap
达到其大小上限时,它具有重新哈希的概念。 重新哈希处理是创建新的内存区域,并在新的内存中复制所有已经存在的键值对的过程。 可以说,线程 A 尝试将键值对放入映射中,然后开始重新哈希。 同时,线程 B 来了,并开始使用put
操作来操作存储桶。
在进行重新哈希处理时,有机会生成循环依赖关系,其中链表中的任何元素(在任何存储桶中)都可以指向同一存储桶中的任何先前节点。 这将导致无限循环,因为重新哈希处理的代码包含一个“while(true){//获取下一个节点;}
”块,并且在循环依赖项下它将无限运行。
要仔细观察,请查看用于重新哈希处理的传输方法的艺术源代码:
public Object get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
Entry e = table[i];
//While true is always a bad practice and cause infinite loops
while (true) {
if (e == null)
return e;
if (e.hash == hash & eq(k, e.key))
return e.value;
e = e.next;
}
}
以后我会写一篇更详细的文章。
希望我能够为HashMap
面试问题和ConcurrentHashMap
面试问题投入更多知识。 如果您认为本文有帮助,请考虑与您的朋友分享。
学习愉快!
参考文献:
Java 版本和新特性
原文: https://howtodoinjava.com/java-version-wise-features-history/
Java 版本 7 或 8 中的新 Java 特性是什么? 这些是 Java 面试中经常被问到的问题。
在此页面中,我依次列出了所有 JDK 从 JDK 1.x 到 Java SE 12 的更改。 尽管我已尽力涵盖了我所能收集的全部信息,但是,如果您知道我在下面遗漏的内容,请告诉我,我将添加该信息。
Java 12 特性
Java 12 (于 2019 年 3 月 19 日发布)是 JDK 的最新版本。 让我们看看它为开发人员和架构师带来的新特性和改进。
- 流 API 中的
Collectors.teeing()
- 字符串 API 的更改
Files.mismatch(Path, Path)
- 紧凑数字格式
- 支持 Unicode 11
switch
表达式(预览)
Java 11 特性
Java 11 (于 2018 年 9 月发布)包含许多重要且有用的更新。 让我们看看它为开发人员和架构师带来的新特性和改进。
- HTTP 客户端 API
- 启动不编译的单文件程序
- 字符串 API 的更改
Collection.toArray(IntFunction)
Files.readString()
和Files.writeString()
Optional.isEmpty()
Java 10 特性
Java 9 发布后,Java 10 很快问世。 与以前的版本不同,Java 10 没有那么多令人兴奋的特性,但它仍然很少有重要更新,它们会改变您的编码方式以及其他将来的 Java 版本。
- JEP 286:局部变量类型推断
- JEP 322:基于时间的发行版本控制
- JEP 304:垃圾收集器接口
- JEP 307:用于 G1 的并行全 GC
- JEP 316:备用存储设备上的堆分配
- JEP 296:将 JDK 森林整合到单个仓库中
- JEP 310:应用类 - 数据共享
- JEP 314:其他 Unicode 语言标签扩展
- JEP 319:根证书
- JEP 317:基于 Java 的实验性 JIT 编译器
- JEP 312:线程本地握手
- JEP 313:删除本机头生成工具
- 新增的 API 和选项
- 删除的 API 和选项
Java 9 特性
Java 9 在 2017 年九月可用。 最大的变化是模块化,即 Java 模块。
- Java 平台模块系统
- 接口专用方法
- HTTP 2 客户端
- JShell – REPL 工具
- 平台和 JVM 日志记录
- 进程 API 更新
- 集合 API 更新
- 流 API 的改进
- 多版本 JAR 文件
@Deprecated
标签更改- 栈遍历
- Java 文档更新
- 其他特性
Java8 特性
发行日期:2014.3.18
代号文化被删除。 包括的特性包括:
- API 中的 Lambda 表达式支持
- 流 API
- 函数式接口和默认方法
Optional
- Nashorn – JavaScript 运行时,允许开发人员将 JavaScript 代码嵌入应用中
- Java 类型注解
- 无符号整数运算
- 重复注解
- 新日期和时间 API
- 静态链接的 JNI 库
- 从 jar 文件启动 JavaFX 应用
- 从 GC 中删除永久代
Java SE 7 特性
发行日期:2011.7.28
此版本称为“海豚”。 包括的特性包括:
- JVM 对动态语言的支持
- 压缩的 64 位指针
switch
中的字符串try
语句中的自动资源管理- 菱形运算符
- 简化的可变参数方法声明
- 二进制整数字面值
- 数字字面值下划线
- 改进的异常处理
- ForkJoin 框架
- NIO 2.0 具有对多个文件系统,文件元数据和符号链接的支持
WatchService
- Timsort 用于对对象的集合和数组进行排序,而不是归并排序
- 图形特性的 API
- 支持新的网络协议,包括 SCTP 和套接字直接协议
Java SE 6 特性
发行日期:2006.12.11
此版本称为“野马”。 Sun 从版本号中删除了“.0
”,版本变为 Java SE6。所包含的特性包括:
- 脚本语言支持
- 性能提升
- JAX-WS
- JDBC 4.0
- Java 编译器 API
- JAXB 2.0 和 StAX 解析器
- 可插拔注解
- 新的 GC 算法
J2SE 5.0 特性
发行日期:2004.9.30
此版本称为“老虎”。 此发行版中添加了 Java 面试中要求的大多数特性。
版本也称为 5.0,而不是 1.5。 包括的特性在下面列出:
J2SE 1.4 特性
发行日期:2002.2.6
此版本称为“Merlin”。 包括的特性包括:
assert
关键字- 正则表达式
- 异常链
- 互联网协议版本 6(IPv6)支持
- 新的 I/O;
Future
- 日志 API
- 图像 I/O API
- 集成的 XML 解析器和 XSLT 处理器(JAXP)
- 集成的安全性和加密扩展(JCE,JSSE,JAAS)
- Java Web Start
- 首选项 API(
java.util.prefs
)
J2SE 1.3 特性
发行日期:2000.5.8
该版本称为“Kestrel”。 包括的特性包括:
- Hotspot JVM
- Java 命名和目录接口(JNDI)
- Java 平台调试器架构(JPDA)
- JavaSound
- 复合代理类
J2SE 1.2 特性
发行日期:1008.12.8
此版本称为“游乐场”。 就添加的类数而言,这是一个主要版本(几乎是其大小的三倍)。 引入“J2SE”一词是为了区分代码平台与 J2EE 和 J2ME。 包括的特性包括:
strictfp
关键字- Swing 图形 API
- Sun 的 JVM 首次配备了 JIT 编译器
- Java 插件
- 集合框架
JDK 1 特性
发行日期:1996.1.23
这是初始版本,最初称为 Oak 。 它具有非常不稳定的 API 和一个名为WebRunner
的 Java Web 浏览器。
第一个稳定版本 JDK 1.0.2 被称为 Java 1。
1997 年 2 月 19 日,发布了 JDK 1.1,其中列出了一些主要特性,例如:
- AWT 事件模型
- 内部类
- JavaBeans
- JDBC
- RMI
- 反射仅支持自省,无法在运行时进行修改。
- Windows 的 JIT(即时)编译器
同样,随时建议我在上面的列表中错过的任何 Java 版本中的 Java 特性。
学习愉快!
Gson – 排除或忽略字段
原文: https://howtodoinjava.com/gson/gson-exclude-or-ignore-fields/
Gson 允许我们从 Java 类中排除或忽略字段,这些字段不希望包含在序列化和反序列化中。 Gson 支持许多内置机制,用于排除顶级类,字段和字段类型。
1. Gson @Expose
注解
@Expose
标记要排除的对象的某些字段,默认为标记为,以考虑将序列化和反序列化为 JSON。 这意味着 Gson 将排除类中没有用@Expose
注解标记的所有字段。
@Expose
注解在一种编程风格中很有用,在该编程风格中,您要显式指定应考虑进行序列化或反序列化的所有字段。
1.1 如何使用@Expose
@Expose
是可选的,并提供两个配置参数:
serialize
– 如果为真,则在序列化时会在 JSON 中写出带有此注解的字段。deserialize
– 如果为真,则从 JSON 反序列化带有此注解的字段。
@Expose(serialize = false)
private String lastName;
@Expose (serialize = false, deserialize = false)
private String emailAddress;
1.2 创建 Gson 实例
如果我们使用new Gson()
创建 Gson 并执行toJson()
和fromJson()
方法,则@Expose
将不会对序列化和反序列化产生任何影响。
要使用此注解,我们必须使用GsonBuilder
类及其excludeFieldsWithoutExposeAnnotation()
方法创建Gson
实例。
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
2.排除带有修饰符的字段
2.1 瞬态字段
默认情况下,如果我们仅将字段标记为瞬态,则 Gson 会将字段从序列化和反序列化中排除。 请记住,它无法阻止单向转换。 它同时阻止了两者。
transient
将具有与@Expose (serialize = false, deserialize = false)
相同的效果。
@Expose(serialize = false)
private String lastName;
private transient String emailAddress;
2.2 其他修饰符
通过使用GsonBuilder
的excludeFieldsWithModifiers()
方法,我们可以排除具有某些公开修饰符的字段。
例如,我们要排除一个类的所有static
成员,我们可以这样创建 Gson 对象:
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.STATIC)
.create();
我们可以在“excludeFieldsWithModifiers
”方法中使用任意数量的Modifier
常量。 例如:
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.STATIC,
Modifier.TRANSIENT,
Modifier.VOLATILE)
.create();
3.排除策略
如果以上任何一种技术都不适合我们,那么我们可以创建自己的策略。 ExclusionStrategy
用于确定是否应序列化或反序列化字段或顶级类作为 JSON 输出/输入的一部分。
- 对于序列化,如果
shouldSkipClass(Class)
或shouldSkipField(fieldAttributes)
方法返回true
,则该类或字段类型将不属于 JSON。 输出。 - 对于反序列化,如果
shouldSkipClass(Class)
或shouldSkipField(fieldAttributes)
方法返回true
,则不会将其设置为 Java 对象结构的一部分 。
例如,在ExclusionStrategy
定义下方将排除所有带有@Hidden
注解的字段。
//public @interface Hidden {
// some implementation here
//}
// Excludes any field (or class) that is tagged with an "@Hidden"
public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy
{
public boolean shouldSkipClass(Class<?> clazz) {
return clazz.getAnnotation(Hidden.class) != null;
}
public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(Hidden.class) != null;
}
}
要使用该排除策略,请在GsonBuilder
对象中进行设置。
GsonBuilder builder = new GsonBuilder();
builder.setExclusionStrategies( new HiddenAnnotationExclusionStrategy() );
Gson gson = builder.create();
如果上述机制都不能满足我们的需求,那么我们始终可以使用自定义序列化器和反序列化器。
学习愉快!
Gson - JsonReader
原文: https://howtodoinjava.com/gson/jsonreader-streaming-json-parser/
了解如何使用 Gson JsonReader
类,该类是基于请求的流式 JSON 解析器。 它有助于将 JSON 作为令牌流读取。
1. JsonReader
JsonReader
是流 JSON 解析器,并且是拉式解析器的示例。 推送解析器解析 JSON 令牌并将其推送到事件处理器中。- 它有助于读取 JSON(RFC 7159)编码的值作为令牌流。
- 它读取字面值(字符串,数字,布尔值和
null
)以及对象和数组的开始和结束定界符。 - 令牌以深度优先顺序遍历,与 JSON 文档中出现的顺序相同。
阅读更多: XML 的流解析器
2.令牌
在流模式下,每个 JSON 数据都被视为一个单独的令牌。 当我们使用JsonReader
处理它时,每个令牌将被顺序处理。 例如,
{
"name":"Lokesh"
}
在使用JsonReader
进行解析时,上述 JSON 将生成 4 个令牌:
- 令牌 1 =
{
- 令牌 2 =
name
- 令牌 3 =
Lokesh
- 令牌 4 =
}
3.如何创建 GSON JsonReader
我们可以使用它的简单构造器创建一个JsonReader
实例,该实例接受java.io.Reader
类型的输入流。
String json = "{}";
JsonReader jsonReader = new JsonReader( new StringReader(json) );
我们可以根据 JSON 流的来源使用以下阅读器之一:
BufferedReader
LineNumberReader
CharArrayReader
InputStreamReader
FileReader
FilterReader
PushbackReader
PipedReader
StringReader
4.读取 JSON 流
在创建包装了有效 JSON 源的JsonReader
之后,我们可以开始对流令牌进行迭代并查看令牌值。
以下是在令牌上使用JsonReader
读取简单 JSON 的示例。
import java.io.IOException;
import java.io.StringReader;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
public class Main
{
public static void main(String[] args) throws Exception
{
String json = "{'id': 1001,'firstName': 'Lokesh','lastName': 'Gupta','email': null}";
JsonReader jsonReader = new JsonReader(new StringReader(json));
jsonReader.setLenient(true);
try
{
while (jsonReader.hasNext())
{
JsonToken nextToken = jsonReader.peek();
if (JsonToken.BEGIN_OBJECT.equals(nextToken)) {
jsonReader.beginObject();
} else if (JsonToken.NAME.equals(nextToken)) {
String name = jsonReader.nextName();
System.out.println("Token KEY >>>> " + name);
} else if (JsonToken.STRING.equals(nextToken)) {
String value = jsonReader.nextString();
System.out.println("Token Value >>>> " + value);
} else if (JsonToken.NUMBER.equals(nextToken)) {
long value = jsonReader.nextLong();
System.out.println("Token Value >>>> " + value);
} else if (JsonToken.NULL.equals(nextToken)) {
jsonReader.nextNull();
System.out.println("Token Value >>>> null");
} else if (JsonToken.END_OBJECT.equals(nextToken)) {
jsonReader.endObject();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
jsonReader.close();
}
}
}
Token KEY >>>> id
Token Value >>>> 1001
Token KEY >>>> firstName
Token Value >>>> Lokesh
Token KEY >>>> lastName
Token Value >>>> Gupta
Token KEY >>>> email
Token Value >>>> null
在上面的示例中:
JsonReader
的hasNext()
方法如果有更多令牌,则返回true
。peek()
方法返回下一个 JSON 令牌,但不移至下一个。- 随后,多次调用
peek()
将返回相同的 JSON 令牌。 - 可以使用
JsonToken
类的常量检查返回令牌的类型。 - 使用
beginArray()
和endArray()
方法检查数组的左括号'['
和']'
。 - 使用
beginObject()
和endObject()
方法检查对象的左括号'{'
和'}'
。
令牌的密钥的类型为JsonToken.NAME
。 使用nextName()
方法获取密钥名称。
- 确定令牌类型后,使用
nextLong()
,nextString()
和nextInt()
等方法获取令牌的值。 - 可以使用
nextNull()
或skipValue()
使用空字面值。 - 所有
next....()
方法都返回当前令牌的值,并将内部指针移到下一个。 - 当遇到未知名称时,严格的解析器应该失败,并带有异常。 宽松解析器应调用
skipValue()
来递归地跳过该值的嵌套令牌,否则可能会发生冲突。
将有关 Gson JsonReader
的问题交给我。
学习愉快!
参考:
Gson - JsonParser
Gson JsonParser
用于将 Json 数据解析为JsonElement
并因此解析为JsonObject
的解析树。 JsonObject
可用于使用 JSON 字符串中的相应键来访问值。
1.创建JsonParser
JsonParser
类只有一个默认的构造器,不需要任何参数或配置。
JsonParser parser = new JsonParser();
2.解析 JSON
JsonParser
类提供 3 种方法来提供 JSON 作为源并将其解析为JsonElement
的树。
JsonElement parse(JsonReader json)
– 使用JsonReader
将 JSON 作为令牌流读取,并从 JSON 流中返回下一个值作为分析树。JsonElement parse(java.io.Reader json)
– 使用指定的读取器读取 JSON,并将 JSON 字符串解析为解析树。JsonElement parse(java.lang.String json)
- 将指定的 JSON 字符串解析为解析树。
如果指定的文本不是有效的 JSON,则这三种方法都将抛出JsonParseException
和JsonSyntaxException
。
3. JsonElement
,JsonObject
和JsonArray
在JsonElement
树中解析了 JSON 字符串后,我们就可以使用它的各种方法来访问 JSON 数据元素。
例如,使用一种类型检查方法找出它代表什么类型的 JSON 元素:
jsonElement.isJsonObject();
jsonElement.isJsonArray();
jsonElement.isJsonNull();
jsonElement.isJsonPrimitive();
我们可以使用相应的方法将JsonElement
转换为 JsonObject
和JsonArray
:
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonArray jsonArray = jsonElement.getAsJsonArray();
一旦有了JsonObject
或JsonArray
实例,就可以使用其 get()
方法从中提取字段。
4. Gson JsonParser
示例
使用JsonParser
的 Java 程序将 JSON 解析为 JsonElement
(和JsonObject
),并使用键获取 JSON 值。
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class Main
{
public static void main(String[] args) throws Exception
{
String json = "{'id': 1001, "
+ "'firstName': 'Lokesh',"
+ "'lastName': 'Gupta',"
+ "'email': 'howtodoinjava@gmail.com'}";
JsonElement jsonElement = new JsonParser().parse(json);
JsonObject jsonObject = jsonElement.getAsJsonObject();
System.out.println( jsonObject.get("id") );
System.out.println( jsonObject.get("firstName") );
System.out.println( jsonObject.get("lastName") );
System.out.println( jsonObject.get("email") );
}
}
程序输出。
1001
"Lokesh"
"Gupta"
"howtodoinjava@gmail.com"
5.使用fromJson()
获得JsonObject
我们可以使用Gson
实例和来自Json()
方法的实例来达到相同的结果。
String json = "{'id': 1001, "
+ "'firstName': 'Lokesh',"
+ "'lastName': 'Gupta',"
+ "'email': 'howtodoinjava@gmail.com'}";
JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
System.out.println(jsonObject.get("id"));
System.out.println(jsonObject.get("firstName"));
System.out.println(jsonObject.get("lastName"));
System.out.println(jsonObject.get("email"));
程序输出:
1001
"Lokesh"
"Gupta"
"howtodoinjava@gmail.com"
将有关使用Jsonparser
从 Java 的 json 字符串中获取值的问题交给我。
学习愉快!
Gson – 自定义序列化和反序列化
原文: https://howtodoinjava.com/gson/custom-serialization-deserialization/
Gson 在默认序列化和反序列化方面提供了非常出色的功能。 不过,我们可能会遇到默认和内置自定义选项无法解决我们问题的情况。
在这种情况下,我们可以使用两个接口JsonSerializer
和JsonDeserializer
使用自定义序列化和反序列化。
1.自定义序列化
1.1 JsonSerializer
接口
JsonSerializer
接口看起来像这样:
public interface JsonSerializer<T>
{
public JsonElement serialize(T value, Type type,
JsonSerializationContext jsonSerializationContext) {
}
}
为 Json 创建自定义序列化器之后,我们还需要通过GsonBuilder.registerTypeAdapter(Type, Object)
注册该序列化器。
Gson 在遇到指定类型的字段时,会在序列化过程中调用其回调方法serialize()
。
1.2 Gson JsonSerializer
示例
假设我们进入一种情况,我们必须将 Java 对象序列化为 json,以便将所有布尔值都写入1 or 0
,而不是打印true or false
。
让我们为该要求编写自定义序列化程序。
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class BooleanSerializer implements JsonSerializer<Boolean> {
public JsonElement serialize(Boolean aBoolean, Type type,
JsonSerializationContext jsonSerializationContext)
{
if(aBoolean){
return new JsonPrimitive(1);
}
return new JsonPrimitive(0);
}
}
让我们编写一个程序,使用registerTypeAdapter()
注册JsonSerializer
实例,然后使用它将 Java 对象序列化为 json。
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class Main
{
public static void main(String[] args) throws Exception
{
Employee emp = new Employee(1, "Lokesh", "Gupta", "howtodoinjava@gmail.com", true);
Gson gson = new GsonBuilder()
.registerTypeAdapter(Boolean.class, new BooleanSerializer())
.setPrettyPrinting()
.create();
String json = gson.toJson(emp);
System.out.println(json);
}
}
注意程序输出,键“active
”的值被序列化为 1。
{
"id": 1,
"firstName": "Lokesh",
"lastName": "Gupta",
"email": "howtodoinjava@gmail.com",
"active": 1
}
2.自定义反序列化
2.1 JsonDeserializer
接口
自定义反序列化器必须实现JsonDeserializer
接口。 JsonDeserializer
接口如下所示:
public interface JsonDeserializer<T>
{
public Boolean deserialize(JsonElement jsonElement,
Type type, JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException;
}
为 Json 创建自定义反序列化器之后,我们还需要通过GsonBuilder.registerTypeAdapter(Type, Object)
注册此反序列化器。
Gson 在遇到指定类型的字段时,会在序列化过程中调用其回调方法deserialize()
。
2.2 Gson JsonDeserializer
示例
假设某些服务将日期字段分别分为天,月和年等部分分别返回给我们。 在 JSON 字符串中,它们可能有意义,但在 Java 中,它们只有作为单个java.time.LocalDate
对象的一部分时才有意义。
{
"id": 1,
"firstName": "Lokesh",
"lastName": "Gupta",
"email": "howtodoinjava@gmail.com",
"day": 11,
"month": 8,
"year": 2019
}
我们要自定义反序列化并将最后三个字段组合为LocalDate
对象。
我们的Employee
看起来像这样。 包括必要的获取器和设置器以及构造器。
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private String email;
private LocalDate dob;
}
自定义反序列化器类如下所示:
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
public class EmployeeDeserializer implements JsonDeserializer<Employee>
{
@Override
public Employee deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException
{
JsonObject jsonObject = json.getAsJsonObject();
LocalDate localDate = LocalDate.of(
jsonObject.get("year").getAsInt(),
jsonObject.get("month").getAsInt(),
jsonObject.get("day").getAsInt()
);
return new Employee(
jsonObject.get("id").getAsInt(),
jsonObject.get("firstName").getAsString(),
jsonObject.get("lastName").getAsString(),
jsonObject.get("email").getAsString(),
localDate);
}
}
让我们注册反序列化器,然后将给定的 JSON 解析为 java 对象。
public class Main
{
public static void main(String[] args) throws Exception
{
String json = "{'id': 1001,"
+ "'firstName': 'Lokesh',"
+ "'lastName': 'Gupta',"
+ "'email': 'howtodoinjava@gmail.com', "
+ "'day': 11, "
+ "'month': 8, "
+ "'year': 2019}";
Gson gson = new GsonBuilder()
.registerTypeAdapter(Employee.class, new EmployeeDeserializer())
.create();
Employee employee = gson.fromJson(json, Employee.class);
System.out.println(employee);
}
}
注意程序输出如何将 3 个单独的字段组合成单个LocalDate
对象。
Employee [id=1001,
firstName=Lokesh,
lastName=Gupta,
email=howtodoinjava@gmail.com,
dob=2019-08-11]
根据提供的 json 输入的保证,我们可能想用has()
来检查JsonObject
中是否存在模型属性。 否则,如果我们正在访问属性,然后尝试获取该属性的值,则可能会遇到NullPointerException
。
向我提供有关 Java 中使用 Gson 的自定义序列化和反序列化的问题。
学习愉快!
Gson – 快速指南
Gson(由 Google 提供)是可用于将 Java 对象转换为 JSON 字符串的 Java 库。 此外,它还可以用于将 JSON 字符串转换为等效的 Java 对象。
还有其他一些 Java 库也可以执行此转换,但是 Gson 处于极少数情况,不需要任何预先注解的 Java 类或 Java 类的源代码。
Gson 还支持旧的 Java 类,这些类中不支持泛型来提供类型信息。 它只是与这些旧式类一起正常工作。
在这个 gson 教程中,我仅给出一些示例,这些示例可以用 Gson 执行。
Table of Contents
1\. Prerequisites and dependency
2\. Create Gson object
3\. Convert Java objects to JSON format
4\. Convert JSON to Java Objects
5\. Writing an Instance Creator
6\. Custom Serialization and De-serialization
7\. Pretty Printing for JSON Output Format
8\. Versioning Support
9\. More Gson Tutorials
1.先决条件和依赖项
1.1 POJO 类
在介绍示例之前,让我们先准备一个 POJO 类,该类将在给定的示例中使用。
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private List<String> roles;
public Employee(){
}
public Employee(Integer id, String firstName, String lastName, Date birthDate){
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
//Getters and setters
@Override
public String toString()
{
return "Employee [id=" + id + ", firstName=" + firstName + ", " +
"lastName=" + lastName + ", roles=" + roles + "]";
}
}
1.2 Maven 依赖
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
在 gradle 中,请使用以下依赖项。
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
2.创建 Gson 对象
Gson 对象可以通过两种方式创建。 第一种方法为您准备了快速的 Gson 对象,可以进行更快的编码,而第二种方法使用GsonBuilder
来构建更复杂的 Gson 对象。
//1\. Default constructor
Gson gson = new Gson();
//2\. Using GsonBuilder
Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.setPrettyPrinting()
.serializeNulls()
.create();
使用GsonBuilder
时,可以为Gson
对象提供许多其他有用选项。 继续检查一下。
3. Gson toJson()
– 将 Java 对象转换为 JSON 字符串
要将将对象转换为 json,请使用toJson()
方法。
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("Lokesh");
employee.setLastName("Gupta");
employee.setRoles(Arrays.asList("ADMIN", "MANAGER"));
Gson gson = new Gson();
System.out.println(gson.toJson(employee));
程序输出。
{"id":1,"firstName":"Lokesh","lastName":"Gupta","roles":["ADMIN","MANAGER"]}
4. 3. Gson fromJson()
– 将 JSON 字符串转换为对象
要将 json 解析为对象,请使用 fromJson()
方法。
Gson gson = new Gson();
System.out.println(
gson.fromJson("{'id':1,'firstName':'Lokesh','lastName':'Gupta','roles':['ADMIN','MANAGER']}",
Employee.class));
程序输出:
Employee [id=1, firstName=Lokesh, lastName=Gupta, roles=[ADMIN, MANAGER]]
5. Gson InstanceCreator
– 给定对象中不存在无参构造器时
在大多数情况下,即使任何类都不提供默认的无参数构造器, Gson 库也足以创建实例。 但是,如果使用无参数构造器的类发现任何问题,则可以使用InstanceCreator
支持。 使用它之前,您需要先向 Gson 注册 Java 类类型的InstanceCreator
。
例如,Department
没有任何默认构造器。
public class Department
{
public Department(String deptName)
{
this.deptName = deptName;
}
private String deptName;
public String getDeptName()
{
return deptName;
}
public void setDeptName(String deptName)
{
this.deptName = deptName;
}
@Override
public String toString()
{
return "Department [deptName="+deptName+"]";
}
}
我们的Employee
类引用了Department
:
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private List<String> roles;
private Department department; //Department reference
//Other setters and getters
}
要正确使用Department
类,我们需要为Department
注册一个InstanceCreator
,如下所示:
class DepartmentInstanceCreator implements InstanceCreator<Department> {
public Department createInstance(Type type)
{
return new Department("None");
}
}
现在,如下使用上述InstanceCreator
。
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Department.class, new DepartmentInstanceCreator());
Gson gson = gsonBuilder.create();
System.out.println(
gson.fromJson("{'id':1,'firstName':'Lokesh','lastName':'Gupta',
'roles':['ADMIN','MANAGER'],'department':{'deptName':'Finance'}}",
Employee.class));
程序输出:
Employee [id=1, firstName=Lokesh, lastName=Gupta, roles=[ADMIN, MANAGER], department=Department [deptName=Finance]]
6. Gson 自定义序列化和反序列化
很多时候,我们需要写入/读取不是 Java 对象默认表示形式的 JSON 值。 在这种情况下,我们需要编写该 Java 类型的自定义序列化器和反序列化器。
在我们的示例中,我正在为java.util.Date
类编写序列化器和反序列化器,这将有助于以“dd/MM/yyyy
”格式编写日期格式。
6.1 Gson 自定义序列化器
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class DateSerializer implements JsonSerializer<Date>
{
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
public JsonElement serialize(Date date, Type typeOfSrc, JsonSerializationContext context)
{
return new JsonPrimitive(dateFormat.format(date));
}
}
6.2 Gson 自定义反序列化器
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
public class DateDeserializer implements JsonDeserializer<Date>
{
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
public Date deserialize(JsonElement dateStr, Type typeOfSrc, JsonDeserializationContext context)
{
try
{
return dateFormat.parse(dateStr.getAsString());
}
catch (ParseException e)
{
e.printStackTrace();
}
return null;
}
}
6.3 注册自定义序列化器和反序列化器
现在,您可以在GsonBuilder
中注册这些串行器和反序列化器,如下所示:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class, new DateSerializer());
gsonBuilder.registerTypeAdapter(Date.class, new DateDeserializer());
6.4 Gson 自定义序列化器和反序列化器示例
串行器和反序列化器的完整示例如下。
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("Lokesh");
employee.setLastName("Gupta");
employee.setRoles(Arrays.asList("ADMIN", "MANAGER"));
employee.setBirthDate(new Date());
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class, new DateSerializer());
gsonBuilder.registerTypeAdapter(Date.class, new DateDeserializer());
Gson gson = gsonBuilder.create();
//Convert to JSON
System.out.println(gson.toJson(employee));
//Convert to java objects
System.out.println(gson.fromJson("{'id':1,'firstName':'Lokesh','lastName':'Gupta',
'roles':['ADMIN','MANAGER'],'birthDate':'17/06/2014'}"
, Employee.class));
程序输出:
{"id":1,"firstName":"Lokesh","lastName":"Gupta","roles":["ADMIN","MANAGER"],"birthDate":"17/06/2014"}
Employee [id=1, firstName=Lokesh, lastName=Gupta, roles=[ADMIN, MANAGER], birthDate=Tue Jun 17 00:00:00 IST 2014]
7. Gson setPrettyPrinting()
– 精美打印 JSON 输出
Gson 提供的默认 JSON 输出是紧凑的 JSON 格式。 这意味着在输出 JSON 结构中将没有任何空格。 要生成更具可读性和美观的 JSON,请使用GsonBuilder
中的 setPrettyPrinting()
。
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(employee);
程序输出:
{
"id": 1,
"firstName": "Lokesh",
"lastName": "Gupta",
"roles": [
"ADMIN",
"MANAGER"
],
"birthDate": "17/06/2014"
}
8. Gson setVersion()
- 版本支持
如果您正在使用的类文件已在不同版本中进行了修改,并且使用@Since
注解了字段,则可以使用此功能。 您需要做的就是使用GsonBuilder
的setVersion()
方法。
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class, new DateSerializer());
gsonBuilder.registerTypeAdapter(Date.class, new DateDeserializer());
//Specify the version like this
gsonBuilder.setVersion(1.0);
Gson gson = gsonBuilder.create();
8.1 Employee.java
中以各种版本添加的字段
public class Employee
{
@Since(1.0)
private Integer id;
private String firstName;
private String lastName;
@Since(1.1)
private List<String> roles;
@Since(1.2)
private Date birthDate;
//Setters and Getters
}
Gson @Since
示例
//Using version 1.0 fields
gsonBuilder.setVersion(1.0);
Output:
{"id":1,"firstName":"Lokesh","lastName":"Gupta"}
/////////////////////////////////////////////////////////////
//Using version 1.1 fields
gsonBuilder.setVersion(1.1);
Output:
{"id":1,"firstName":"Lokesh","lastName":"Gupta","roles":["ADMIN","MANAGER"]}
/////////////////////////////////////////////////////////////
//Using version 1.2 fields
gsonBuilder.setVersion(1.2);
Output:
{"id":1,"firstName":"Lokesh","lastName":"Gupta","roles":["ADMIN","MANAGER"],"birthDate":"17/06/2014"}
9.更多的 Gson 教程
- Gson -
GsonBuilder
教程 - Gson – 序列化和反序列化 JSON
- Gson – 序列化和反序列化映射
- Gson – 序列化和反序列化集合
- Gson – 序列化和反序列化数组
- Gson -
@SerializedName
注解示例 - Gson- Jersey + Gson 示例
这就是这个非常有用的 java gson 库的全部内容,可以将对象转换为 JSON 。 如果您有任何疑问或反馈,请发表评论。
学习愉快!
参考
Jackson 教程
JAXB 教程
JAXB 注解
详细了解 JAXB 注解及其在编组和解组操作期间的用法。
1)JAXB 注解列表
注解 | 范围 | 描述 |
---|---|---|
@XmlRootElement |
类,枚举 | 定义 XML 根元素。 根 Java 类在创建时需要在 JAXB 上下文中注册。 |
@XmlAccessorType |
包,类 | 定义 JAXB 引擎用于绑定的 Java 类的字段和属性。 它具有四个值:PUBLIC_MEMBER ,FIELD ,PROPERTY 和NONE 。 |
@XmlAccessorOrder |
包,类 | 定义子项的顺序。 |
@XmlType |
类,枚举 | 将 Java 类映射到架构类型。 它定义了其子类型的名称和顺序。 |
@XmlElement |
字段 | 将字段或属性映射到 XML 元素 |
@XmlAttribute |
字段 | 将字段或属性映射到 XML 属性 |
@XmlTransient |
字段 | 防止将字段或属性映射到 XML 模式 |
@XmlValue |
字段 | 将字段或属性映射到 XML 标记上的文本值。 |
@XmlList |
字段,参数 | 将集合映射到以空格分隔的值列表。 |
@XmlElementWrapper |
字段 | 将 Java 集合映射到 XML 包的集合 |
阅读更多:将 Java 对象转换为 XML
1.1)@XmlRootElement
这将类或枚举类型映射到 XML 根元素。 当使用@XmlRootElement
注解对顶级类或枚举类型进行注解时,则其值将表示为 XML 文档中的 XML 元素。
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Employee implements Serializable
{
//More code
}
以上将导致:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
//....
</employee>
1.2)@XmlAccessorType
它定义 JAXB 引擎用来包含到生成的 XML 中的 Java 类的字段或属性。 它有四个可能的值。
FIELD
– 绑定到 JAXB 的类中的每个非静态,非瞬态字段都将自动绑定到 XML,除非由XmlTransient
注解。NONE
– 没有任何字段或属性绑定到 XML,除非使用某些 JAXB 注解专门对其进行注解。PROPERTY
– 绑定到 JAXB 的类中的每个获取器/设置器对将自动绑定到 XML,除非由XmlTransient
注解。PUBLIC_MEMBER
– 每个公开获取/设置对和每个公开字段都将自动绑定到 XML,除非由XmlTransient
注解。- 默认值为
PUBLIC_MEMBER
。
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable
{
private Integer id;
private String firstName;
private String lastName;
}
以上将产生:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
1.3)@XmlAccessorOrder
控制类中字段和属性的顺序。 您可以具有预定义的值ALPHABETICAL
或UNDEFINED
。
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable
{
private Integer id;
private String firstName;
private String lastName;
private Department department;
}
以上将产生:
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
1.4)@XmlType
它将 Java 类或枚举类型映射到架构类型。 它定义了其子代的类型名称,命名空间和顺序。 它用于将架构中的元素与模型中的元素进行匹配。
@XmlRootElement(name = "employee")
@XmlType(propOrder={"id", "firstName" , "lastName", "department" })
public class Employee implements Serializable
{
private Integer id;
private String firstName;
private String lastName;
private Department department;
}
1.5)@XmlElement
将 JavaBean 属性映射到从属性名称派生的 XML 元素。
@XmlRootElement(name = "employee")
public class Employee implements Serializable
{
@XmlElement(name=employeeId)
private Integer id;
@XmlElement
private String firstName;
private String lastName;
private Department department;
}
以上将产生:
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<employeeId>1</employeeId>
<firstName>Lokesh</firstName>
</employee>
1.6)@XmlAttribute
将 JavaBean 属性映射到 XML 属性。
@XmlRootElement(name = "employee")
public class Employee implements Serializable
{
@XmlAttribute
private Integer id;
private String firstName;
private String lastName;
private Department department;
}
以上将产生:
<?xml version="1.0" encoding="UTF-8"?>
<employee id="1">
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
</employee>
1.7)@XmlTransient
防止将 JavaBean 属性/类型映射到 XML 表示形式。 当放置在一个类上时,它指示该类不应单独映射到 XML。 此类的属性将与其派生类一起映射到 XML,就好像该类是内联的一样。
@XmlTransient
与所有其他 JAXB 定义的注解互斥。
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable
{
@XmlTransient
private Integer id;
private String firstName;
private String lastName;
private Department department;
}
以上将产生:
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<department>
<id>101</id>
<name>IT</name>
</department>
</employee>
1.8)@XmlValue
允许将类映射到具有simpleContent
或 XML Schema 简单类型的 XML Schema 复杂类型。 它与架构映射到模型映射的关系更大。
1.9)@XmlList
用于将属性映射到列表简单类型。 它允许将多个值表示为单个元素中的由空格分隔的标记。
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable
{
private List<String> hobbies;
}
//
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<hobbies>Swimming</hobbies>
<hobbies>Playing</hobbies>
<hobbies>Karate</hobbies>
</employee>
使用@XmlList
之后,观察输出。
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable
{
@XmlList
private List<String> hobbies;
}
//
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<hobbies>Swimming Playing Karate</hobbies>
</employee>
]
1.10)@XmlElementWrapper
围绕 XML 表示生成包器元素。 它主要用于在集合周围产生包 XML 元素。 因此,它必须与collection
属性一起使用。
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable
{
@XmlElementWrapper(name="hobbies")
@XmlElement(name="hobby")
private List<String> hobbies;
}
以上将产生:
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<hobbies>
<hobby>Swimming</hobby>
<hobby>Playing</hobby>
<hobby>Karate</hobby>
</hobbies>
</employee>
2)JAXB 注解示例
学习在模型类上应用 JAXB 注解,然后将对象编组到 XML 文件中。
package com.howtodoinjava.demo.model;
import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
@XmlElementWrapper(name="hobbies")
@XmlElement(name="hobby")
private List<String> hobbies;
public Employee() {
super();
}
public Employee(int id, String fName, String lName, Department department) {
super();
this.id = id;
this.firstName = fName;
this.lastName = lName;
this.department = department;
}
//Setters and Getters
}
package com.howtodoinjava.demo;
import java.io.File;
import java.util.Arrays;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
employee.setHobbies(Arrays.asList("Swimming","Playing", "Karate"));
jaxbObjectToXML(employee);
}
private static void jaxbObjectToXML(Employee employee)
{
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // To format XML
//Print XML String to Console
jaxbMarshaller.marshal(employee, new File("employee.xml"));
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<department>
<id>101</id>
<name>IT</name>
</department>
<hobbies>
<hobby>Swimming</hobby>
<hobby>Playing</hobby>
<hobby>Karate</hobby>
</hobbies>
</employee>
将我的问题放在评论部分。
学习愉快!
参考: JAXB 注解 Java 文档
JMS 教程 – Java 消息服务教程
原文: https://howtodoinjava.com/jms/jms-java-message-service-tutorial/
Java 消息服务是一种 API,支持网络上计算机之间称为消息传递的正式通信。 它为标准消息协议和消息服务提供了通用接口,以支持 Java 程序。 它提供了创建,发送和阅读消息的功能。 JMS API 减少了程序员必须学习使用消息传递服务/产品的概念,并且还提供了支持消息传递应用的功能。
JMS 是一种技术,在 J2EE 技术中用于使应用以松散耦合的方式与其他应用通信。 这意味着必须通信的应用没有直接连接,而是通过一个公共目标连接。 我们将在本 jms 教程中详细介绍。
Table of Contents
1\. Need of JMS
2\. Benefits of JMS
3\. Messaging Domains
4\. Message Consumption
5\. JMS participating objects
6\. JMS Message Components
1. JMS 教程 - JMS 的必要性
在 Java 中,如果一个人想要以一种方式将消息从一个应用发送到另一个应用,使得这两个应用彼此之间一无所知,那么即使它们可以完全不依赖地部署在单独的大陆上。 例如,一个应用 A 在印度运行,另一个应用在美国运行,而 B 则有兴趣从 A 获得一些更新/消息 - 每当 A 上发生独特的事情。可能有 N 个这样的应用对 来自 A 的此类更新。
在这种情况下,java 提供了 JMS 形式的最佳解决方案 - 解决了上面讨论的完全相同的问题。
当我们编写任何基于事件的应用(例如聊天服务器)时,JMS 也是有用的,在该应用中,它需要一种发布事件机制来在服务器之间向与服务器连接的客户端之间发送消息。 由于 JMS 与 RMI 不同,因此在将消息从客户端发送到服务器时,不需要使目标对象联机可用。 服务器发布消息并忘记它,每当客户端联机时,它将获取消息。 它是当今世界上非常常见的问题的强大解决方案。
2. JMS 教程 - JMS 的好处
-
异步
默认情况下,JMS 是异步的。 因此,要接收消息,不需要客户端发送请求。 消息将在可用时自动到达客户端。
-
可靠
JMS 提供了保证消息将只传递一次的功能。 您知道重复的消息会造成问题。 JMS 帮助您避免此类问题。
3. JMS 消息传递域
在 JMS API 出现之前,大多数消息传递产品都支持点对点或发布/订阅消息传递方法。 JMS 为每种方法提供一个单独的域,并定义每个域的合规性。 任何 JMS 提供商都可以实现这两个域或一个域,这是他自己的选择。 JMS 提供了公共接口,使我们能够使用 JMS API,而不是特定于任何一个域。
让我们更详细地了解两种消息传递域,以了解 JMS 的工作原理。
3.1 点对点消息传递域
在点对点消息传递域中,该应用是基于消息队列,发送者和接收者构建的。 每个消息都寻址到特定的队列。 队列保留发送给他们的所有消息,直到消息被消耗或过期。 PTP 消息传递具有一些特征:
- 每个消息只有一个客户端。
- 消息的发送者和接收者没有时间依赖项。
- 当发送方发送消息时,接收方可以获取消息是否正在运行。
- 接收者在收到消息后发送确认。
点对点 JMS 消息传递
3.2 发布/订阅消息域
在发布/订阅消息传递域中,仅发布一条消息,该消息通过充当公告板的主题传递给所有客户端。 发布者和订阅者通常是匿名的,可以动态发布或订阅主题。 主题负责保存和传递消息。 只要分发到当前客户端,该主题就会保留消息。
一些特征是:
- 一条消息可以有多个订阅者。
- 发布者和订阅具有时间依赖项。 订阅主题的客户端只能使用在客户端创建订阅后发布的消息,并且订阅者必须继续处于活动状态才能使用消息。
发布订阅 JMS 消息传递
阅读更多:HornetQ 基本示例
4.消息使用
在 JMS 中,可以通过两种方式使用消息:
4.1 同步
在同步消息使用中,订阅者/接收者通过调用receive()
方法从目标请求消息。 在receive()
中,方法将阻塞直到消息到达或超时(如果消息在给定时间内未到达)。 就像普通的 java 方法调用一样,它带有一些返回值。
4.2 异步
在异步消息消费中,订阅者可以向消费者注册(或订阅)为消息监听器。 消息监听器与事件监听器相同,每当消息到达目标时,JMS 提供者都会通过调用监听器的onMessage()
方法来传递消息,该方法将对消息的内容起作用。
5. JMS 参与对象
JMS 应用具有一些基本构建块,它们是:
- 受管对象 – 连接工厂和目标
- 连接
- 会话
- 消息生产者
- 消息消费者
- 消息监听器
JMS API 编程模型
5.1 JMS 管理对象
JMS 应用提供两种类型的管理对象:
- 连接工厂
- 目标
这两个受管理对象由 JMS 系统管理员在 JMS 生产者中通过使用应用服务管理控制台创建。 这两个对象都存储在应用服务器 JNDI 目录或 JNDI 注册表中。
5.2 连接工厂
客户端使用的对象是连接工厂,用于创建与供应器的连接。 它在 JMS 生产者和 JMS 客户端之间创建连接。 当诸如发送者或接收者之类的 JMS 客户端在 JNDI 注册表中搜索该对象时,则 JMS 客户端会收到一个连接对象,这不仅仅是 JMS 生产者和 JMS 客户端之间的物理连接。 使用此连接,客户端可以与目标对象进行通信,以将消息发送或接收到队列或主题中。 让我们举一个例子来理解它发送消息:
QueueConnectionFactory queueConnFactory = (QueueConnectionFactory) initialCtx.lookup ("primaryQCF");
Queue purchaseQueue = (Queue) initialCtx.lookup ("Purchase_Queue");
Queue returnQueue = (Queue) initialCtx.lookup ("Return_Queue");
5.3 目标
客户端使用称为目标的对象,该对象用于指定其生成的消息的目标以及使用它的消息的源。 JMS 应用使用两种类型的目标队列或主题。 该代码指定队列和主题。
创建队列会话
QueueSession ses = con.createQueueSession (false, Session.AUTO_ACKNOWLEDGE); //get the Queue object
Queue t = (Queue) ctx.lookup ("myQueue"); //create QueueReceiver
QueueReceiver receiver = ses.createReceiver(t);
创建主题会话
TopicSession ses = con.createTopicSession (false, Session.AUTO_ACKNOWLEDGE); // get the Topic object
Topic t = (Topic) ctx.lookup ("myTopic"); //create TopicSubscriber
TopicSubscriber receiver = ses.createSubscriber(t);
5.4 JMS 连接
该连接封装了与 JMS 供应器的虚拟连接。 该连接实现了Connection
接口,当它具有ConnectionFactory
对象时,我们可以使用它来创建连接。
Connection connection = connectionFactory.createConnection();
创建任何连接后,应在使用以下方法完成应用之前关闭它们:
connection.close();
5.5 JMS 会话
会话是用于生成和使用消息的单线程上下文。 这些会话用于创建以下内容:
- 消息生产者
- 消息消费者
会话实现了Session
接口,并且在创建Connection
对象之后,我们使用它来创建Session
。
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
5.6 JMS 消息生产者
消息生产者是由会话创建的对象,用于将消息发送到目标。 这实现了MessageProducer
接口。 我们使用Session
为目标,队列或主题对象创建一个MessageProducer
。
MessageProducer producer = session.createProducer(dest);
MessageProducer producer = session.createProducer(queue);
MessageProducer producer = session.createProducer(topic);
创建消息后,将使用生成器来使用send
方法发送消息。
producer.send(message);
5.7 JMS 消息使用者
消息使用者是一个由会话创建的对象,用于接收在目标发送的消息。 它将实现MessageConsumer
接口。 我们使用会话为目标,队列或主题对象创建MessageConsumer
。
MessageConsumer consumer = session.createConsumer(dest);
MessageConsumer consumer = session.createConsumer(queue);
MessageConsumer consumer = session.createConsumer(topic);
5.8 JMS 消息监听器
消息监听器是一个对象,充当消息的异步事件处理器。 消息监听器实现MessageListener
接口,其中包含一个方法onMessage()
。 在这种方法中,我们定义了消息到达时要执行的动作。 通过使用setMessageListener()
,我们使用特定的MessageConsumer
定义消息监听器。
Listener myListener = new Listener();
consumer.setMessageListener(myListener);
6. JMS 消息组件
JMS 客户端使用 JMS 消息在系统之间进行通信。 JMS 消息具有简单的格式,但具有高度的灵活性,它允许创建与格式匹配的消息。 JMS 消息分为三个部分。 他们是:
-
消息标题
JMS 消息头包含许多预定义字段,这些字段包含客户机和提供者用来标识和发送消息的那些值。 预定义的标头是:
JMSDestination
JMSDeliveryMode
JMSMessageID
JMSTimestamp
JMSCorrelationID
JMSReplyTo
JMSRelivered
JMSType
JMSExpiration
-
消息属性
在消息属性中,我们可以创建和设置消息的属性。 消息属性是由应用设置或读取的自定义名称值对。 消息属性对于支持过滤消息很有用。 JMS API 提供了供应器可以支持的一些预定义属性。 消息属性是可选的。
-
消息正文
在消息正文中,JMS API 定义了五种消息正文格式,也称为消息类型,它们使我们能够以许多不同的形式发送和接收数据,并提供与现有消息传递格式的兼容性。 它基本上由从 JMS 发送方发送到接收方的实际消息组成。 不同的消息类型是:
文本消息:由
javax.jms.TextMessage
表示。 它用于表示文本块。
对象消息:由javax.jms.ObjectMessage
表示。 它用来表示一个 Java 对象。
字节消息:由javax.jms.BytesMessage
表示。 它用来表示二进制数据。
流消息:由javax.jms.StreamMessage
表示。 它用于表示 Java 基本值的列表。
映射消息:由javax.jms.MapMessage
表示。 它用于表示一组关键字或值对。
JMS 入门教程及其相关术语就这些了。 在下一组帖子中。 我将举一些 JMS 的例子。
学习愉快!
参考文献:
JAXB @XmlRootElement
注解示例
原文: https://howtodoinjava.com/jaxb/xmlrootelement-annotation/
JAXB @XmlRootElement
注解的 Java 示例及其在编组和解组操作期间的用法详细说明。
1. JAXB @XmlRootElement
注解类型
@XmlRootElement
将类或枚举类型映射到 XML 元素。 当使用@XmlRootElement
注解来注解顶级类或枚举类型时,则其值在 XML 文档中表示为 XML 元素。
@XmlRootElement
注解可以与以下注解一起使用:XmlType
,XmlEnum
,XmlAccessorType
,XmlAccessorOrder
。
1.1 语法
//Without name attribute
@XmlRootElement //1
//With name attribute
@XmlRootElement(name = "employee") //2
2. JAXB @XmlRootElement
示例
现在来看几个使用@XmlRootElement
更改 XML 表示形式的示例。
2.1 具有name
属性的@XmlRootElement
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeData implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
}
以上转换为:
<employee>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
</employee>
2.2 不带name
属性的@XmlRootElement
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeData implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
}
以上转换为:
<EmployeeData>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
</EmployeeData>
将我的问题放在评论部分。
学习愉快!
JAXB @XmlElementWrapper
注解示例
原文: https://howtodoinjava.com/jaxb/xmlelementwrapper-annotation/
JAXB @XmlElementWrapper
注解的 Java 示例及其在编组和编组操作期间的用法详细说明。
1. @XmlElementWrapper
类型
- 该注解生成围绕 XML 表示的包装器元素。
- 它主要用于在集合周围产生包装 XML 元素。
- 该注解可以与以下注解一起使用:
XmlElement
,XmlElements
,XmlElementRef
,XmlElementRefs
,XmlJavaTypeAdapter
。 @XmlElementWrapper
注解可以与以下程序元素一起使用:- JavaBean 属性
- 非静态,非瞬态字段
2. JAXB @XmlElementWrapper
示例
现在来看几个有关如何将@XmlElementWrapper
与@XmlElement
一起使用来更改 XML 表示形式的示例。
2.1 使用@XmlElementWrapper
和@XmlElement
(包装的集合)
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@XmlElementWrapper(name="hobbies")
@XmlElement(name="hobby")
private List<String> hobbies;
private Integer id;
private String firstName;
private String lastName;
}
以上转换为:
<employee>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<hobbies>
<hobby>Swimming</hobby>
<hobby>Playing</hobby>
<hobby>Karate</hobby>
</hobbies>
</employee>
2.2 仅使用@XmlElementWrapper
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@XmlElementWrapper(name="hobbies")
//@XmlElement(name="hobby") //Comment it out
private List<String> hobbies;
private Integer id;
private String firstName;
private String lastName;
}
以上转换为:
<employee>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<hobbies>
<hobbies>Swimming</hobbies>
<hobbies>Playing</hobbies>
<hobbies>Karate</hobbies>
</hobbies>
</employee>
2.3 不使用@XmlElementWrapper
(未包装的集合)
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
//@XmlElementWrapper(name="hobbies") //Comment it out
@XmlElement(name="hobby")
private List<String> hobbies;
private Integer id;
private String firstName;
private String lastName;
}
以上转换为:
<employee>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<hobby>Swimming</hobby>
<hobby>Playing</hobby>
<hobby>Karate</hobby>
</employee>>
将我的问题放在评论部分。
学习愉快!
JAXB Marshaller
(编组器)示例
JAXB Marshaller
接口负责管理将 Java 内容树即 Java 对象转换为 XML 数据的过程。 可以将 XML 编组到各种输出目标。
1. JAXB 编组对象到 XML
1.1 创建编组器
通常,要创建编组器,可以重用此代码。
JAXBContext jaxbContext = JAXBContext.newInstance( Employee.class );
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
Employee employeeObj = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
//Overloaded methods to marshal to different outputs
jaxbMarshaller.marshal(employeeObj);
1.2 编组 XML 文件
OutputStream os = new FileOutputStream( "employee.xml" );
jaxbMarshaller.marshal( employeeObj, os );
1.3 编组至 SAX ContentHandler
假设MyContentHandler
是 org.xml.sax.ContentHandler
的实例。
jaxbMarshaller.marshal( employeeObj, new MyContentHandler() );
1.4 编组 DOM 文件
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
jaxbMarshaller.marshal( employeeObj, doc );
1.5 编组并打印到控制台
m.marshal( employeeObj, new PrintWriter( System.out ) );
2. JAXB Marshaller
属性
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//or
jaxbMarshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
所有 JAXB 供应器都必须支持以下属性集。 一些供应器可能支持其他属性。
jaxb.encoding
- 编组 XML 数据时使用的输出编码。 如果未指定此属性,则默认情况下Marshaller
将使用“UTF-8
”。jaxb.formatted.output
- 值可以是true
或false
。Marshaller
是否将使用换行符和缩进来格式化所得的 XML 数据。 默认值为false
。jaxb.schemaLocation
– 允许客户端应用在生成的 XML 数据中指定xsi:schemaLocation
属性。jaxb.noNamespaceSchemaLocation
– 它允许客户端应用在生成的 XML 数据中指定xsi:noNamespaceSchemaLocation
属性。jaxb.fragment
– 它确定Marshaller
是否将生成文档级事件。 值可以是true
或false
。
3.Marshaller
回调方法
您可以通过 JAXB 注解类中的自定义编组操作,例如 Employee.java
。 您需要定义两个方法,这些方法将在编组程序处理该类之前和之后进行监听。 在这些方法中,您可以执行诸如设置额外字段之类的操作。
package com.howtodoinjava.demo.model;
import java.io.Serializable;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
//Setters and Getters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", department="
+ department + "]";
}
// Invoked by Marshaller after it has created an instance of this object.
boolean beforeMarshal(Marshaller marshaller) {
System.out.println("Before Marshaller Callback");
return true;
}
// Invoked by Marshaller after it has marshalled all properties of this object.
void afterMarshal(Marshaller marshaller) {
System.out.println("After Marshaller Callback");
}
}
4. JAXB 编组示例
将 Java 对象编组为 XML 字符串的示例。
package com.howtodoinjava.demo;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
jaxbObjectToXML(employee);
}
private static void jaxbObjectToXML(Employee employee)
{
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // To format XML
//Print XML String to Console
jaxbMarshaller.marshal(employee, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
程序输出。
Before Marshaller Callback
After Marshaller Callback
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
将我的问题放在评论部分。
学习愉快!
JAXB Unmarshaller
(解组器)示例
原文: https://howtodoinjava.com/jaxb/jaxb-unmarshaller-example/
JAXB Unmarshaller
接口负责管理将 XML 数据反序列化为 Java 对象的过程。 可以将对象解组到各种输入源。
1.如何将 XML 解组到对象
1.1 创建解组器
通常,要创建Unmarshaller
,可以重用此代码。
JAXBContext jaxbContext = JAXBContext.newInstance( Employee.class );
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
//Overloaded methods to unmarshal from different xml sources
Employee employee = (Employee) jaxbUnmarshaller.unmarshal( xmlSource );
1.2 从InputStream
解组
InputStream inStream = new FileInputStream( "employee.xml" );
Employee employee = (Employee) jaxbUnmarshaller.unmarshal( inStream );
1.3 从 URL 解组
URL url = new URL( "http://localhost:8080/employee.xml" );
Employee employee = (Employee) jaxbUnmarshaller.unmarshal( url );
1.4 解组字符串内容
String xmlString = "...";
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(new StringReader(xmlString));
1.5 从org.w3c.dom.Node
解组
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(new File( "employee.xml")); //Node
Employee employee = (Employee) jaxbUnmarshaller.unmarshal( document );
2. JAXB 解组器属性
当前,Unmarshaller
上的所有 JAXB 供应器都不需要所有属性。 但是,某些供应器可能支持它们自己的一组供应器特定属性。
3.解组事件回调
您可以通过在 JAXB 注解的类中添加这些回调方法来自定义解组操作,例如Employee.java
。 您需要定义两个方法,这些方法将在Unmarshaller
处理该类之前和之后监听。
void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) {}
void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {}
package com.howtodoinjava.demo.model;
import java.io.Serializable;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
//Setters and Getters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", department="
+ department + "]";
}
// It is called immediately after the object is created and before the unmarshalling begins.
// The callback provides an opportunity to initialize JavaBean properties prior to unmarshalling.
void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) {
System.out.println("Before Unmarshaller Callback");
}
// It is called after all the properties are unmarshalled for this object,
// but before this object is set to the parent object.
void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
System.out.println("After Unmarshaller Callback");
}
}
4. JAXB 解组器示例
将 XML 文件解组到 Java 对象的示例。
package com.howtodoinjava.demo;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
String fileName = "employee.xml";
jaxbXmlFileToObject(fileName);
}
private static void jaxbXmlFileToObject(String fileName) {
File xmlFile = new File(fileName);
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(xmlFile);
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出。
Before Unmarshaller Callback
After Unmarshaller Callback
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
其中employee.xml
文件是:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
向我提出您的有关使用 JAXB 注解在 Java 中解组的问题。
学习愉快!
JAXB 读取 XML 到 Java 对象的示例
读取 XML 到对象的 Java 示例。 可以通过某些.xml
文件或仅通过字符串表示形式提供 XML。 然后,可以在应用中使用填充的 Java 对象进行进一步处理或工作流。
1)JAXB vs SAX vs DOM
Java 提供了许多读取 XML 文件并使用 XML 内容打印,在应用中使用或在 Java 对象中填充数据以进一步在应用生命周期中使用的方法。 用于此目的的三个主要 API 是 XML 的简单 API(SAX
),文档对象模型(DOM
)和 XML 绑定的 Java 架构(JAXB
)。
SAX
或DOM
解析器使用 JAXP API 来解析 XML 文档。 两者都扫描文档并在逻辑上将其分解为离散的片段(例如,节点,文本和注释等)。SAX
解析器从文档的开头开始,并将文档的每个片段按找到它的顺序传递给应用。 内存中没有保存任何内容,因此无法进行任何内存中的操作。DOM
解析器创建一个对象树,该树表示内存中Document
对象中数据的内容和组织。 然后,应用可以在此处浏览树以访问所需的数据,并在适当时对其进行操作。- 当
JAXB
将文档解组为 Java 内容对象时。 Java 内容对象代表 XML 文档的内容和组织,可直接用于您的程序。
2)将 XML 字符串转换为 Java 对象
要读取 XML,请首先获取JAXBContext
。 它是 JAXB API 的入口点,并提供了解组,组组和验证操作的方法。
现在从JAXBContext
获取Unmarshaller
实例。 unmarshal()
方法从指定的 XML 解组 XML 数据,然后返回结果树。
String xmlString = "<employee>" +
" <department>" +
" <id>101</id>" +
" <name>IT</name>" +
" </department>" +
" <firstName>Lokesh</firstName>" +
" <id>1</id>" +
" <lastName>Gupta</lastName>" +
"</employee>";
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(new StringReader(xmlString));
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
Output:
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
3)将 XML 文件转换为 Java 对象
从文件读取 XML 与上面的示例非常相似。 您只需要传递File
对象代替StringReader
对象。 File
将参考要在文件系统中读取的'.xml'
文件。
File xmlFile = new File("employee.xml");
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(xmlFile);
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
Output:
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
public Employee(int id, String fName, String lName, Department department) {
super();
this.id = id;
this.firstName = fName;
this.lastName = lName;
this.department = department;
}
//Setters and Getters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ",
lastName=" + lastName + ", department="+ department + "]";
}
}
@XmlRootElement(name = "department")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
Integer id;
String name;
public Department() {
super();
}
public Department(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
//Setters and Getters
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
xml 文件的内容与第一个示例相同。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
将我的问题放在评论部分。
学习愉快!
使用 Moxy 和 Jaxb 将 JSON 转换为 Java 对象的示例
原文: https://howtodoinjava.com/jaxb/convert-json-to-java-object-moxy/
Java 示例将 JSON 转换为 Java 对象。 您可以将 JSON 字符串解组到对象或将 JSON 文件解组到对象。 此示例将 MOXy 与 JAXB 一起使用,以将 JSON 解组到 Java 对象。 MOXy 实现 JAXB,使开发人员可以通过注解提供其映射信息,并提供 JAXB 默认不提供的许多丰富功能。
1. MOXy 依赖
包括 MOXy 到项目运行时。
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.5.2</version>
</dependency>
2.将 JSON 文件转换为 Java 对象
2.1 添加 JAXB 注解
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
//Setters and Getters
}
@XmlRootElement(name = "department")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
Integer id;
String name;
public Department() {
super();
}
//Setters and Getters
}
2.2 添加jaxb.properties
当您获得JAXBContext
的实例时,JAXB 将检查jaxb.properties
文件并构造上下文。 在这里,您从 MOXy 库中注入了JAXBContextFactory
。
将
jaxb.properties
文件放在放置 JAXB 注解类的同一包中。
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
3.将 JSON 文件转换为对象
现在使用javax.xml.bind.UnMarshaller
类将 json 转换为对象。
package com.howtodoinjava.demo;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
String fileName = "employee.json";
jaxbJsonToObject(fileName);
}
private static void jaxbJsonToObject(String fileName) {
File xmlFile = new File(fileName);
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
//Set JSON type
jaxbUnmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
jaxbUnmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, true);
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(xmlFile);
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出:
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
读取的 JSON 文件为:
{
"employee" : {
"department" : {
"id" : 101,
"name" : "IT"
},
"firstName" : "Lokesh",
"id" : 1,
"lastName" : "Gupta"
}
}
4.将 JSON 字符串转换为 Java 对象
您可以获取字符串形式的 JSON,然后直接填充到 Java 对象。
package com.howtodoinjava.demo;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
String jsonString = "{\"employee\":{\"department\":{\"id\":101,\"name\":\"IT\"},
\"firstName\":\"Lokesh\",\"id\":1,\"lastName\":\"Gupta\"}}";
jaxbJsonStringToObject(jsonString);
}
private static void jaxbJsonStringToObject(String jsonString)
{
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
//Set JSON type
jaxbUnmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
jaxbUnmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, true);
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(new StringReader(jsonString));
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出:
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
5.将 Java 对象转换为 JSON
将 Java 对象转换为 JSON 的示例。
package com.howtodoinjava.demo;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
jaxbObjectToJSON(employee);
}
private static void jaxbObjectToJSON(Employee employee)
{
try
{
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// To format JSON
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//Set JSON type
jaxbMarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
jaxbMarshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
//Print JSON String to Console
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(employee, sw);
System.out.println(sw.toString());
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出:
{
"employee" : {
"department" : {
"id" : 101,
"name" : "IT"
},
"firstName" : "Lokesh",
"id" : 1,
"lastName" : "Gupta"
}
}
阅读更多:将 Java 对象转换为 XML
在评论部分中,向我发送您与编组和解组 json 有关的问题。
学习愉快!
JAXB 将 Java 对象写入 XML 的示例
将 Java 对象写入 XML 的 Java 示例。 Java 对象字段中存储的信息可以写入 XML 文件,也可以写入 XML 字符串。
1)将 Java 对象转换为 XML 字符串
要将 Java 对象写入 XML String
,请首先获取JAXBContext
。 它是 JAXB API 的入口点,并提供了解组,组组和验证操作的方法。
现在从JAXBContext
获取Marshaller
实例。 marshal()
方法将 Java 对象编组为 XML。 现在可以将此 XML 写入不同的输出,例如,字符串,文件或流。
package com.howtodoinjava.demo;
import java.io.File;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JaxbExample
{
public static void main(String[] args)
{
//Java object. We will convert it to XML.
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
//Method which uses JAXB to convert object to XML
jaxbObjectToXML(employee);
}
private static void jaxbObjectToXML(Employee employee)
{
try
{
//Create JAXB Context
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
//Create Marshaller
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
//Required formatting??
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//Print XML String to Console
StringWriter sw = new StringWriter();
//Write XML to StringWriter
jaxbMarshaller.marshal(employee, sw);
//Verify XML Content
String xmlContent = sw.toString();
System.out.println( xmlContent );
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
程序输出。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
2)将 Java 对象转换为 XML 文件
将 XML 写入文件与上面的示例非常相似。 您只需要提供要在其中写入文件的 XML 文件位置即可。
package com.howtodoinjava.demo;
import java.io.File;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JaxbExample
{
public static void main(String[] args)
{
//Java object. We will convert it to XML.
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
//Method which uses JAXB to convert object to XML
jaxbObjectToXML(employee);
}
private static void jaxbObjectToXML(Employee employee)
{
try
{
//Create JAXB Context
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
//Create Marshaller
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
//Required formatting??
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//Store XML to File
File file = new File("employee.xml");
//Writes XML file to file-system
jaxbMarshaller.marshal(employee, file);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
3)读取 XML 的示例
如果要再次从文件读取 XML 到 Java 对象,请使用此方法。
String fileName = "employee.xml";
//Call method which read the XML file above
jaxbXmlFileToObject(fileName);
private static void jaxbXmlFileToObject(String fileName) {
File xmlFile = new File(fileName);
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(xmlFile);
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
程序输出:
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
将我的问题放在评论部分。
学习愉快!
JAXB 将对象转换为 JSON 的示例
原文: https://howtodoinjava.com/jaxb/convert-object-to-json-moxy/
Java 示例将 Java 对象转换为 JSON 字符串或将 JSON 写入文件。 本示例将 MOXy 与 JAXB 一起使用,以将 Java 对象编组为 JSON。 MOXy 实现 JAXB,使开发人员可以通过注解提供其映射信息,并提供 JAXB 默认不提供的许多丰富功能。
1. MOXy 依赖
包括 MOXy 到项目运行时。
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.5.2</version>
</dependency>
2. Java 对象到 JSON 字符串
2.1 添加 JAXB 注解
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
//Setters and Getters
}
@XmlRootElement(name = "department")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
Integer id;
String name;
public Department() {
super();
}
//Setters and Getters
}
2.2 添加jaxb.properties
当您获得JAXBContext
的实例时,JAXB 将检查jaxb.properties
文件并构造上下文。 在这里,您从 MOXy 库中注入了JAXBContextFactory
。
将
jaxb.properties
文件放在放置 JAXB 注解类的同一包中。
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
2.3 将对象转换为 JSON
现在使用javax.xml.bind.Marshaller
类将对象转换为 json。
package com.howtodoinjava.demo;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
jaxbObjectToJSON(employee);
}
private static void jaxbObjectToJSON(Employee employee)
{
try
{
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// To format JSON
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//Set JSON type
jaxbMarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
jaxbMarshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
//Print JSON String to Console
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(employee, sw);
System.out.println(sw.toString());
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出:
{
"employee" : {
"department" : {
"id" : 101,
"name" : "IT"
},
"firstName" : "Lokesh",
"id" : 1,
"lastName" : "Gupta"
}
}
阅读更多:将 Java 对象转换为 XML
3. Java 对象到 JSON 文件
使用上面的代码,现在输出到 json 文件。
package com.howtodoinjava.demo;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
jaxbObjectToJSON(employee);
}
private static void jaxbObjectToJSON(Employee employee)
{
try
{
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// To format JSON
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//Set JSON type
jaxbMarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
jaxbMarshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
//Store JSON to File
File file = new File("employee.json");
jaxbMarshaller.marshal(employee, file);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出:
{
"employee" : {
"department" : {
"id" : 101,
"name" : "IT"
},
"firstName" : "Lokesh",
"id" : 1,
"lastName" : "Gupta"
}
}
请在评论部分将该 json 转换示例相关的问题发送给我。
学习愉快!
JAXB – 在 Java 中编组和解组HashMap
原文: https://howtodoinjava.com/jaxb/jaxb-example-marshalling-and-unmarshalling-hashmap-in-java/
我们知道 JAXB(用于 XML 绑定的 Java 架构)允许 Java 开发人员将 Java 类映射到 XML 表示形式。 JAXB 提供了两个主要功能:将 Java 对象编组为 XML 的能力和相反的功能,即将 XML 解组为 Java 对象的能力。 JAXB 主要用于实现 Web 服务或任何其他此类客户端接口的应用,在该应用中,数据需要以 XML 格式(而不是 HTML 格式)传输,而对于可视客户端(如 Web 浏览器)来说,HTML 格式是默认格式。
一个很好的例子是 facebook API。 Facebook 已通过 RESTful Web 服务的形式通过一些开放的端点公开了其服务,您在其中单击 URL 并发布了一些参数,而 API 以 xml 格式返回数据。 现在由您决定如何使用这些数据。
在本文中,我将举一个编组和解组Map
对象的示例,例如 HashMap
。 这些映射对象通常表示一些简单键与复杂数据之间的映射。
1)JAXB Maven 依赖关系
要运行 JAXB 示例,我们需要添加运行时依赖项,如下所示。
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.8-b01</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2-promoted-b65</version>
</dependency>
2)映射模型类
我创建了一个模型类“Employee.java
”,它具有一些公开字段。 我想构建可以解析对象映射的代码,其中键是序列码,值是Employee
对象本身。
@XmlRootElement(name = "employee")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private double income;
//Getters and Setters
}
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement (name="employees")
@XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeMap {
private Map<Integer, Employee> employeeMap = new HashMap<Integer, Employee>();
public Map<Integer, Employee> getEmployeeMap() {
return employeeMap;
}
public void setEmployeeMap(Map<Integer, Employee> employeeMap) {
this.employeeMap = employeeMap;
}
}
3)编组映射到 XML 的示例
将 Java 映射编组或转换为 xml 表示形式的 Java 示例。 在下面的示例代码中,我首先在控制台中编写员工映射,然后在文件中编写。
public static void main(String[] args) throws JAXBException
{
HashMap<Integer, Employee> map = new HashMap<Integer, Employee>();
Employee emp1 = new Employee();
emp1.setId(1);
emp1.setFirstName("Lokesh");
emp1.setLastName("Gupta");
emp1.setIncome(100.0);
Employee emp2 = new Employee();
emp2.setId(2);
emp2.setFirstName("John");
emp2.setLastName("Mclane");
emp2.setIncome(200.0);
map.put( 1 , emp1);
map.put( 2 , emp2);
//Add employees in map
EmployeeMap employeeMap = new EmployeeMap();
employeeMap.setEmployeeMap(map);
/******************** Marshalling example *****************************/
JAXBContext jaxbContext = JAXBContext.newInstance(EmployeeMap.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(employeeMap, System.out);
jaxbMarshaller.marshal(employeeMap, new File("c:/temp/employees.xml"));
}
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
<employeeMap>
<entry>
<key>1</key>
<value>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<income>100.0</income>
</value>
</entry>
<entry>
<key>2</key>
<value>
<id>2</id>
<firstName>John</firstName>
<lastName>Mclane</lastName>
<income>200.0</income>
</value>
</entry>
</employeeMap>
</employees>
4)解组 XML 到映射的示例
Java 示例将 xml 转换为 Java 映射对象。 让我们看一下EmployeeMap
类的示例。
private static void unMarshalingExample() throws JAXBException
{
JAXBContext jaxbContext = JAXBContext.newInstance(EmployeeMap.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
EmployeeMap empMap = (EmployeeMap) jaxbUnmarshaller.unmarshal( new File("c:/temp/employees.xml") );
for(Integer empId : empMap.getEmployeeMap().keySet())
{
System.out.println(empMap.getEmployeeMap().get(empId).getFirstName());
System.out.println(empMap.getEmployeeMap().get(empId).getLastName());
}
}
Output:
Lokesh
Gupta
John
Mclane
5)源代码下载
要下载以上示例的源代码,请点击以下链接。
学习愉快!
JAXB – 编组和解组对象列表或集合
原文: https://howtodoinjava.com/jaxb/jaxb-exmaple-marshalling-and-unmarshalling-list-or-set-of-objects/
我们知道 JAXB(用于 XML 绑定的 Java 架构)允许 Java 开发人员将 Java 类映射到 XML 表示形式。 JAXB 提供了两个主要功能:将 Java 对象编组为 XML 的能力和相反的功能,即将 XML 解组为 Java 对象的能力。 JAXB 主要用于实现 Web 服务或任何其他此类客户端接口的应用,在该应用中,数据需要以 XML 格式(而不是 HTML 格式)传输,而对于可视客户端(如 Web 浏览器)来说,HTML 格式是默认格式。
一个很好的例子是 facebook API。 Facebook 已通过 RESTful Web 服务的形式通过一些开放的端点公开了其服务,您在其中单击 URL 并发布了一些参数,而 API 以 xml 格式返回数据。 现在由您决定如何使用这些数据。
在本文中,我以编组和解组对象的集合为例。 Java 中的这些集合可以是:List
和Set
实现,例如 ArrayList
或HashSet
。
1)JAXB Maven 依赖关系
要运行 JAXB 示例,我们需要添加运行时 maven 依赖项,如下所示:
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.8-b01</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2-promoted-b65</version>
</dependency>
2)模型类
我创建了一个模型类“Employee
”,它具有一些公开字段。 我想构建可以解析一组employees
的代码。 请注意,JAXB 在最重要的类上需要 @XmlRootElement
注解,我们将对其进行编组或解组。
ArrayList
类是集合框架的一部分,它没有任何 JAXB 注解。 因此,我们需要另外一个类别“Employees
”,该类别将代表一组雇员。 现在,在该类中,我们可以添加任何我们喜欢的注解。
@XmlRootElement(name = "employee")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private double income;
//Getters and Setters
}
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "employees")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employees
{
@XmlElement(name = "employee")
private List<Employee> employees = null;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
3)将列表编组为 XML 的示例
编组是“将 Java 对象转换为 xml 表示形式”。 在下面的示例代码中,我首先在控制台中写入employees
列表,然后在文件中写入。
//Initialize the employees list
static Employees employees = new Employees();
static
{
employees.setEmployees(new ArrayList<Employee>());
//Create two employees
Employee emp1 = new Employee();
emp1.setId(1);
emp1.setFirstName("Lokesh");
emp1.setLastName("Gupta");
emp1.setIncome(100.0);
Employee emp2 = new Employee();
emp2.setId(2);
emp2.setFirstName("John");
emp2.setLastName("Mclane");
emp2.setIncome(200.0);
//Add the employees in list
employees.getEmployees().add(emp1);
employees.getEmployees().add(emp2);
}
private static void marshalingExample() throws JAXBException
{
JAXBContext jaxbContext = JAXBContext.newInstance(Employees.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//Marshal the employees list in console
jaxbMarshaller.marshal(employees, System.out);
//Marshal the employees list in file
jaxbMarshaller.marshal(employees, new File("c:/temp/employees.xml"));
}
上面代码的输出是:
JAXB 编组示例输出
4)解组 XML 到列表的示例
解组是将 xml 转换回 Java 对象的过程。 让我们看一下Employees
类的示例。
private static void unMarshalingExample() throws JAXBException
{
JAXBContext jaxbContext = JAXBContext.newInstance(Employees.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
//We had written this file in marshalling example
Employees emps = (Employees) jaxbUnmarshaller.unmarshal( new File("c:/temp/employees.xml") );
for(Employee emp : emps.getEmployees())
{
System.out.println(emp.getId());
System.out.println(emp.getFirstName());
}
}
Output:
1
Lokesh
2
John
5. 源代码下载
要下载以上示例的源代码,请点击以下链接。
学习愉快!
JMS 点对点消息示例
原文: https://howtodoinjava.com/jms/jms-point-to-point-message-example/
在 JMS 教程中,您了解了 JMS 消息传递域点对点域和发送订阅域。 在此示例中,我们将通过点对点消息传递域进行示例。 在点对点消息中,发送方将消息传递到队列,单个接收方从队列中取出消息。 接收者在发送消息时不需要监听队列。
点对点 JMS 消息传递
点对点消息发布者应用流程
下面给出了发送方应用的典型点对点消息传递示例。 该应用的以下步骤是:
- 首先,我们将获取 JMS 服务器的
InitialContext
对象。 - 之后,使用初始上下文对象查找队列对象。
- 同样,我们将使用初始上下文对象来查找队列连接工厂。
- 然后,使用队列连接工厂来创建队列连接,因为它表示 JMS 服务器的物理连接。
- 创建队列连接工厂后,我们将创建队列会话,其中第一个参数将决定会话是否被事务处理。 但是,我们将使用非事务会话。
- 此后,为队列创建一个队列发送者,然后创建一条消息。
- 然后将诸如“
Hello World
”之类的消息发送到队列对象。 - 关闭队列连接后,关闭队列连接后,它将自动关闭会话和队列发送者。
让我们看下面的例子:
package pointToPoint;
import javax.naming.InitialContext;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.QueueSender;
import javax.jms.DeliveryMode;
import javax.jms.QueueSession;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
public class Sender
{
public static void main(String[] args) throws Exception
{
// get the initial context
InitialContext context = new InitialContext();
// lookup the queue object
Queue queue = (Queue) context.lookup("queue/queue0");
// lookup the queue connection factory
QueueConnectionFactory conFactory = (QueueConnectionFactory) context.lookup ("queue/connectionFactory");
// create a queue connection
QueueConnection queConn = conFactory.createQueueConnection();
// create a queue session
QueueSession queSession = queConn.createQueueSession(false, Session.DUPS_OK_ACKNOWLEDGE);
// create a queue sender
QueueSender queSender = queSession.createSender(queue);
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// create a simple message to say "Hello World"
TextMessage message = queSession.createTextMessage("Hello World");
// send the message
queSender.send(message);
// print what we did
System.out.println("Message Sent: " + message.getText());
// close the queue connection
queConn.close();
}
}
点对点消息传递订阅者应用流程
接收方的大多数步骤与发送方应用相同 – 除了它将监听消息而不是发送 JMS 消息外。
package pointToPoint;
import javax.naming.InitialContext;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.QueueSession;
import javax.jms.QueueReceiver;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
public class Receiver
{
public static void main(String[] args) throws Exception
{
// get the initial context
InitialContext context = new InitialContext();
// lookup the queue object
Queue queue = (Queue) context.lookup("queue/queue0");
// lookup the queue connection factory
QueueConnectionFactory conFactory = (QueueConnectionFactory) context.lookup ("queue/connectionFactory");
// create a queue connection
QueueConnection queConn = conFactory.createQueueConnection();
// create a queue session
QueueSession queSession = queConn.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
// create a queue receiver
QueueReceiver queReceiver = queSession.createReceiver(queue);
// start the connection
queConn.start();
// receive a message
TextMessage message = (TextMessage) queueReceiver.receive();
// print the message
System.out.println("Message Received: " + message.getText());
// close the queue connection
queConn.close();
}
}
在上面的代码中,接收方将接收来自发送方的消息并进行打印,即 HelloWorld。 但是,如果未启动连接,则方法接收器将被阻塞,直到其他任何线程启动连接为止。
学习愉快!
使用 Eclipse 从 JAXB Java 类生成 XSD
原文: https://howtodoinjava.com/jaxb/java-class-to-xsd-eclipse/
学习使用 Eclipse IDE 从带有 JAXB 注解的 Java 类创建 XML 模式文档(xsd)。
1)将 JAXB 注解添加到 Java 类
第一步是向 Java 类添加@XmlRootElement
,@XmlAccessorType
和@XmlElement
等注解。
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
//Setters and Getters
}
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "department")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
Integer id;
String name;
public Department() {
super();
}
//Setters and Getters
}
2)从 JAXB 类生成 XSD
2.1)导航到 Eclipse 选项
File -> New -> JAXB -> Schema from JAXB Classes
JAXB 类选项的模式
2.2)选择生成的模式文件的位置
生成的模式文件的位置
2.3)选择 JAXB 类
选择 JAXB 类
2.4)生成 xsd 文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="department" type="department"/>
<xs:element name="employee" type="employee"/>
<xs:complexType name="employee">
<xs:sequence>
<xs:element ref="department" minOccurs="0"/>
<xs:element name="firstName" type="xs:string" minOccurs="0"/>
<xs:element name="id" type="xs:int" minOccurs="0"/>
<xs:element name="lastName" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="department">
<xs:sequence>
<xs:element name="id" type="xs:int" minOccurs="0"/>
<xs:element name="name" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
XSd 文件已生成,现在您可以将其用于各种应用用例。
学习愉快!
JAXB 模式验证
了解根据架构(xsd)验证 XML,然后将 XML 解组到 Java 对象。 如果验证失败,还请学习在 xml 模式验证期间检查验证错误。
阅读更多:如何从 JAXB 类生成模式
1.在 XSD 验证后将 XML 转换为 Java 对象
我们已经看到了将 XML 文件读取到 Java 对象的示例。 现在让我们修改该示例,以在填充Employee
对象之前针对 XSD 验证 XML。
package com.howtodoinjava.demo;
import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.SAXException;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
String xmlFile = "employee.xml";
String xsdFile = "employee.xsd";
jaxbXmlFileToObject(xmlFile, xsdFile);
}
private static void jaxbXmlFileToObject(String xmlFile, String xsdFile) {
JAXBContext jaxbContext;
try
{
//Get JAXBContext
jaxbContext = JAXBContext.newInstance(Employee.class);
//Create Unmarshaller
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
//Setup schema validator
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema employeeSchema = sf.newSchema(new File(xsdFile));
jaxbUnmarshaller.setSchema(employeeSchema);
//Unmarshal xml file
Employee employee = (Employee) jaxbUnmarshaller.unmarshal(new File(xmlFile));
System.out.println(employee);
}
catch (JAXBException | SAXException e)
{
e.printStackTrace();
}
}
}
程序输出。
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
下面给出employee.xml
和employee.xsd
的含量。
<employees>
<employee id="101">
<name>Lokesh Gupta</name>
<title>Author</title>
</employee>
<employee id="102">
<name>Brian Lara</name>
<title>Cricketer</title>
</employee>
</employees>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="department" type="department"/>
<xs:element name="employee" type="employee"/>
<xs:complexType name="employee">
<xs:sequence>
<xs:element ref="department" minOccurs="0"/>
<xs:element name="firstName" type="xs:string" minOccurs="0"/>
<xs:element name="id" type="xs:int" minOccurs="0"/>
<xs:element name="lastName" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="department">
<xs:sequence>
<xs:element name="id" type="xs:int" minOccurs="0"/>
<xs:element name="name" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
2.模式验证错误
针对 XML 的 XSD 验证不会总是成功。 很多时候,您会收到验证错误。 这些错误将作为SAXException
抛出。 因此捕获此异常,它将具有验证失败的上下文。
例如,我已通过此更改更新了架构文件。
<xs:element name="firstName" type="xs:string" minOccurs="0"/>
//to
<xs:element name="firstName" type="xs:int" minOccurs="0"/>
现在来看验证错误。
javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; systemId: file:/C:/Users/lokesh/workspace/App/employee.xml; lineNumber: 7; columnNumber: 34;
cvc-datatype-valid.1.2.1: 'Lokesh' is not a valid value for 'integer'.]
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:162)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:171)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:189)
at com.howtodoinjava.demo.JaxbExample.jaxbXmlFileToObject(JaxbExample.java:45)
at com.howtodoinjava.demo.JaxbExample.main(JaxbExample.java:23)
Caused by: org.xml.sax.SAXParseException; systemId: file:/C:/Users/lokesh/workspace/App/employee.xml; lineNumber: 7; columnNumber: 34;
cvc-datatype-valid.1.2.1: 'Lokesh' is not a valid value for 'integer'.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:325)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:458)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3237)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(XMLSchemaValidator.java:3152)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(XMLSchemaValidator.java:3062)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(XMLSchemaValidator.java:2140)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(XMLSchemaValidator.java:859)
at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.endElement(ValidatorHandlerImpl.java:584)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.endElement(ValidatingUnmarshaller.java:91)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:165)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:609)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1782)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2973)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
... 7 more
将我的问题放在评论部分。
学习愉快!
[已解决]:javax.xml.bind.JAXBException
:java.util.ArrayList
或其任何超类不是此上下文的已知类
当您使用 JAXB 将 Java 对象(集合类型)编组为 xml 格式时,会发生此异常。 栈跟踪如下所示:
Exception in thread "main" javax.xml.bind.JAXBException: class java.util.ArrayList nor any of its super class is known to this context.
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getBeanInfo(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(Unknown Source)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(Unknown Source)
at com.howtodoinjava.jaxb.examples.list.TestEmployeeMarshing.main(TestEmployeeMarshing.java:58)
随机异常
原因
发生上述异常是因为 JAXB 总是期望实体上有一个@XmlRootElement
注解,它会编组。 这是强制性的,不能跳过。 需要@XmlRootElement
注解才能从 Java 对象编组的 XML 根元素中获取元数据。
ArrayList
类或任何 Java 集合类都没有任何 JAXB 注解。 由于这个原因,JAXB 无法解析任何此类 java 对象,并引发此错误。
解决方案:创建包装器类
建议您使用此方法,因为它可以让您灵活地在将来(例如)添加/删除字段大小属性。
@XmlRootElement(name = "employees")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employees
{
@XmlElement(name = "employee")
private List<Employee> employees = null;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
现在,您可以按以下方式使用此类:
static Employees employees = new Employees();
static
{
employees.setEmployees(new ArrayList<Employee>());
Employee emp1 = new Employee();
emp1.setId(1);
emp1.setFirstName("Lokesh");
emp1.setLastName("Gupta");
emp1.setIncome(100.0);
Employee emp2 = new Employee();
emp2.setId(2);
emp2.setFirstName("John");
emp2.setLastName("Mclane");
emp2.setIncome(200.0);
employees.getEmployees().add(emp1);
employees.getEmployees().add(emp2);
}
private static void marshalingExample() throws JAXBException
{
JAXBContext jaxbContext = JAXBContext.newInstance(Employees.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(employees, System.out);
}
Output:
<employees>
<employee>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<income>100.0</income>
</employee>
<employee>
<id>2</id>
<firstName>John</firstName>
<lastName>Mclane</lastName>
<income>200.0</income>
</employee>
</employees>
请参阅此帖子中的完整示例: java ArrayList
或Set
编组示例
祝您学习愉快!
[已解决]:线程“main
”com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException
中的异常:3 个IllegalAnnotationExceptions
计数
当您使用 JAXB 将 Java 对象(集合类型)编组为 xml 格式时,会发生此异常。 栈跟踪如下所示:
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "employees"
this problem is related to the following location:
at public java.util.List com.howtodoinjava.jaxb.examples.list.Employees.getEmployees()
at com.howtodoinjava.jaxb.examples.list.Employees
this problem is related to the following location:
at private java.util.List com.howtodoinjava.jaxb.examples.list.Employees.employees
at com.howtodoinjava.jaxb.examples.list.Employees
at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(Unknown Source)
..... more
或者
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 3 counts of IllegalAnnotationExceptions
java.util.Map is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at java.util.Map
at private java.util.Map com.howtodoinjava.jaxb.examples.map.EmployeeMap.employeeMap
at com.howtodoinjava.jaxb.examples.map.EmployeeMap
java.util.Map does not have a no-arg default constructor.
this problem is related to the following location:
at java.util.Map
at private java.util.Map com.howtodoinjava.jaxb.examples.map.EmployeeMap.employeeMap
at com.howtodoinjava.jaxb.examples.map.EmployeeMap
Class has two properties of the same name "employeeMap"
this problem is related to the following location:
at public java.util.Map com.howtodoinjava.jaxb.examples.map.EmployeeMap.getEmployeeMap()
at com.howtodoinjava.jaxb.examples.map.EmployeeMap
this problem is related to the following location:
at private java.util.Map com.howtodoinjava.jaxb.examples.map.EmployeeMap.employeeMap
at com.howtodoinjava.jaxb.examples.map.EmployeeMap
......more
随机异常
原因
发生上述异常的主要原因是缺少@XmlAccessType
注解或对@XmlAccessType
和@XxmlElement
注解的无效使用。 正确的用法是,一个 Java 字段应只包含一个表示其元数据的有效 JAXB 注解。
默认情况下,JAXB 包含所有公开字段和用于整理的获取器。 因此,如果您有一个字段及其获取器,那么它将包含两次。 这是错误,需要通过正确使用注解来解决。
解决方案:使用@XmlAccessType
注解
1)@XmlAccessorType(XmlAccessType.FIELD)
如果您使用的是XmlAccessType.FIELD;
那么只有所有公开字段(非静态)将被自动包括在内以进行编组。 不会考虑吸气剂。 因此,如果将消除重复的问题。 例如,在下面的代码中,将同时包含employee
和size
字段。
请注意,“@XmlElement(name="employee")
”是可选的; 我用它来重命名输出 xml 中的 xml 节点。 如果删除它; 不会出现任何编组错误或异常。
@XmlRootElement(name = "employees")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employees
{
@XmlElement(name="employee")
private List<Employee> employees = null;
private Integer size;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
}
2)@XmlAccessorType(XmlAccessType.NONE)
如果使用“XmlAccessType.NONE
”,则意味着必须在输出 XML 中注解所有要编组的字段。 剩下的任何字段都不会包含在 JAXB 上下文中。 因此,本质上,employee
和size
字段都需要@XmlElement
注解。 如果这两个字段中的任何一个都未使用@XmlElement
注解,则不会将其编组。
@XmlRootElement(name = "employees")
@XmlAccessorType (XmlAccessType.NONE)
public class Employees
{
@XmlElement(name="employee")
private List<Employee> employees = null;
@XmlElement(name="size")
private Integer size;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
}
祝您学习愉快!
没有@XmlRootElement
的 JAXB 编组 – 缺少@XmlRootElement
错误
原文: https://howtodoinjava.com/jaxb/marshal-without-xmlrootelement/
很多时候,我们将需要编组 Java 对象,而不使用 JAXB 注解,例如@XmlRootElement
,并且我们不允许在源代码中进行任何更改。 当我们使用遗留代码或某些我们没有源代码的客户端 jar 时,可能会发生这种情况。
可能还有许多其他情况,但是想法是我们无法使用 JAXB 注解修改模型类。 这可能是将 Java 对象转换为 xml 而没有 jaxb 的示例。
1.不带@XmlRootElement
的编组问题
在这种情况下,如果我们尝试将将 Java 对象直接编组为 XML,则将得到类似的错误。
javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: unable to marshal type "com.howtodoinjava.demo.model.Employee"
as an element because it is missing an @XmlRootElement annotation]
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:311)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at com.howtodoinjava.demo.JaxbExample.jaxbObjectToXML(JaxbExample.java:45)
at com.howtodoinjava.demo.JaxbExample.main(JaxbExample.java:17)
Caused by: com.sun.istack.internal.SAXException2: unable to marshal type "com.howtodoinjava.demo.model.Employee"
as an element because it is missing an @XmlRootElement annotation
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:234)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:323)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:479)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308)
... 4 more
其中Employee.java
类如下。 它没有任何@XmlRootElement
这样的 JAXB 注解。
package com.howtodoinjava.demo.model;
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
public Employee(int id, String fName, String lName, Department department) {
super();
this.id = id;
this.firstName = fName;
this.lastName = lName;
this.department = department;
}
//Getters and Setters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ",
lastName=" + lastName + ", department=" + department + "]";
}
}
2.不带@XmlRootElement
注解的编组的解决方案
缺少@XmlRootElement
注解时,JAXB 无法为Employee
对象构建JAXBElement
实例。 这就是我们必须帮助 JAXB 手动构建它的地方。
2.1 语法
/**
* @param name Java binding of xml element tag name
* @param declaredType Java binding of xml element declaration's type
* @param value Java instance representing xml element's value
*/
JAXBElement<T> elem = new JAXBElement(QName name, Class<T> declaredType, T value );
例如:
JAXBElement<Employee> jaxbElement
= new JAXBElement<Employee>( new QName("", "employee"), Employee.class, employeeObj );
2.2 不带@XmlRootElement
的 JAXB 编组示例
现在,让我们看看该编组代码的工作原理。
package com.howtodoinjava.demo;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
jaxbObjectToXML( employee );
}
private static void jaxbObjectToXML(Employee employeeObj)
{
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// To format XML
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//If we DO NOT have JAXB annotated class
JAXBElement<Employee> jaxbElement =
new JAXBElement<Employee>( new QName("", "employee"),
Employee.class,
employeeObj);
jaxbMarshaller.marshal(jaxbElement, System.out);
//If we have JAXB annotated class
//jaxbMarshaller.marshal(employeeObj, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
程序输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
请向我提供关于没有@XmlRootElement
的 JAXB 编组示例的问题。
学习愉快!
不带 jaxb 注解的解组
原文: https://howtodoinjava.com/jaxb/unmarshal-without-xmlrootelement/
很多时候,您将需要解组不具有诸如@XmlRootElement
之类的 JAXB 注解的 Java 对象,并且不允许您对源代码进行任何更改。 当您使用旧代码或某些您没有源代码的客户端 jar 时,可能会发生这种情况。
1.不带 JAXB 注解的解组问题
在这种情况下,如果您尝试直接将 Java 对象解组为 XML ,则将出现类似的错误。
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"employee"). Expected elements are (none)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1131)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:379)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:605)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3138)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:880)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:162)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:171)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:189)
at com.howtodoinjava.demo.JaxbExample.jaxbXmlFileToObject(JaxbExample.java:63)
at com.howtodoinjava.demo.JaxbExample.main(JaxbExample.java:21)
其中Employee.java
类如下。 它没有任何@XmlRootElement
这样的 JAXB 注解。
package com.howtodoinjava.demo.model;
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
public Employee(int id, String fName, String lName, Department department) {
super();
this.id = id;
this.firstName = fName;
this.lastName = lName;
this.department = department;
}
//Getters and Setters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", department="
+ department + "]";
}
}
2.不带 JAXB 注解的解组解决方案
缺少@XmlRootElement
注解时,JAXB 无法为Employee
对象构建JAXBElement
实例。 因此,您必须在此帮助 JAXB 手动构建它。
2.1 语法
/**
* Unmarshal XML data from the specified XML Source by <tt>declaredType</tt> and return the
* resulting content tree.
* @param source source the XML Source to unmarshal XML data from (providers are
* only required to support SAXSource, DOMSource, and StreamSource)
*
* @param declaredType appropriate JAXB mapped class to hold <tt>source</tt>'s xml root element
*
* @return value Java content rooted by JAXB Element
*/
public <T> JAXBElement<T> unmarshal( javax.xml.transform.Source source, Class<T> declaredType )
throws JAXBException;
例如:
JAXBElement<Employee> jaxbElement = (JAXBElement<Employee>) jaxbUnmarshaller
.unmarshal(new StreamSource(xmlFile), Employee.class);
2.2 解组
现在,让我们看看该解组代码的工作方式。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
package com.howtodoinjava.demo;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
String fileName = "employee.xml";
jaxbXmlFileToObject(fileName);
}
private static void jaxbXmlFileToObject(String fileName)
{
File xmlFile = new File(fileName);
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<Employee> jaxbElement = (JAXBElement<Employee>) jaxbUnmarshaller
.unmarshal(new StreamSource(xmlFile), Employee.class);
Employee employee = jaxbElement.getValue();
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
程序输出:
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
将我的问题放在评论部分。
学习愉快!
Jackson2 – 将 Java 对象转换为 JSON,并将 JSON 字符串转换为对象
原文: https://howtodoinjava.com/jackson/jackson-2-convert-json-to-from-java-object/
在本教程中,我们将学习使用 Jackson2 库将 JSON 转换为 Java 对象 – 和将 Java 对象转换为 JSON。
Table of Contents
Jackson2 maven dependency
Convert Java object to JSON
Convert JSON to Java object
1.Jackson2 Maven 依赖
要将 Jackson2 库包含在您的项目中,请在pom.xml
中包含以下依赖项。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.4</version>
</dependency>
您可以从 maven 站点找到可下载的 jar 文件。
2.将 Java 对象转换为 JSON 的示例
在简单的 pojo 对象之间进行转换时,Jackson 非常直接。 通常只涉及两个步骤,
- 创建
com.fasterxml.jackson.databind.ObjectMapper
的实例 - 使用
objectMapper.writeValueAsString()
方法将 pojo 转换为 JSON
//Simple POJO
Employee emp = new Employee(1, "Lokesh Gupta", 34, "India");
//Object mapper instance
ObjectMapper mapper = new ObjectMapper();
//Convert POJO to JSON
String json = mapper.writeValueAsString(emp);
2.1 将 Java 对象转换为 JSON 的 Java 程序
package com.howtodoinjava.jackson2.example;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.howtodoinjava.jackson2.example.pojo.Employee;
public class FromJavaPojoToJSON
{
public static void main(String[] args)
{
Employee emp = new Employee(1, "Lokesh Gupta", 34, "India");
ObjectMapper mapper = new ObjectMapper();
try
{
String json = mapper.writeValueAsString(emp);
System.out.println(json);
//Use pretty print for printing the output
String beutifulJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(emp);
System.out.println(beutifulJson);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output:
{"id":1,"name":"Lokesh Gupta","age":34,"location":"India"}
{
"id" : 1,
"name" : "Lokesh Gupta",
"age" : 34,
"location" : "India"
}
这里使用的 POJO 对象是:
package com.howtodoinjava.jackson2.example.pojo;
public class Employee
{
private Integer id;
private String name;
private Integer age;
private String location;
public Employee(Integer id, String name, Integer age, String location) {
super();
this.id = id;
this.name = name;
this.age = age;
this.location = location;
}
//Setters and Getters will be added here
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" + age
+ ", location=" + location + "]";
}
}
3.将 JSON 转换为 Java 对象的示例
就像上面的示例一样,从 JSON 到 POJO 的转换也仅涉及两个步骤,
- 创建
com.fasterxml.jackson.databind.ObjectMapper
的实例 - 使用
objectMapper.readValue()
方法将 JSON 转换为 POJO
例如:
//JSON input
String json = "{\"id\":1,\"name\":\"Lokesh Gupta\",\"age\":34,\"location\":\"India\"}";
//Object mapper instance
ObjectMapper mapper = new ObjectMapper();
//Convert JSON to POJO
Employee emp = mapper.readValue(json, Employee.class);
我们可以在 Java 中读取 json 文件,并将其传递给 jackson 库。
3.1 将 JSON 转换为 Java 对象的 Java 程序
package com.howtodoinjava.jackson2.example;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.howtodoinjava.jackson2.example.pojo.Employee;
public class FromJSONToPOJO {
public static void main(String[] args) {
String json = "{\"id\":1,\"name\":\"Lokesh Gupta\",\"age\":34,\"location\":\"India\"}";
ObjectMapper mapper = new ObjectMapper();
try
{
Employee emp = mapper.readValue(json, Employee.class);
System.out.println(emp);
}
catch (JsonGenerationException e)
{
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序输出。
Employee [id=1, name=Lokesh Gupta, age=34, location=India]
请不要忘记在 POJO 类中添加默认的构造器,否则会出现此错误:
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.howtodoinjava.jackson2.example.pojo.Employee]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: {"id":1,"name":"Lokesh Gupta","age":34,"location":"India"}; line: 1, column: 2]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1106)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:296)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:133)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3736)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2726)
at com.howtodoinjava.jackson2.example.FromJSONToPOJO.main(FromJSONToPOJO.java:18)
以上就是使用 Jackson2 库将 Java 对象转换为 JSON 并将 JSON 字符串转换为 Java 对象的所有示例。
让我知道您是否对如何将 json 对象转换为 java 对象有任何疑问。
学习愉快!
Jackson 将对象转换为 json 并将 json 转换为对象
原文: https://howtodoinjava.com/jackson/jackson-convert-object-to-from-json/
Jackson 将对象转换为 JSON 示例,将 json 转换为对象示例。 学习使用 jackson objectmapper
从 json 字符串填充 Java 对象,并从 java 对象写入 json 字符串。
Jackson 用于将 Java 对象转换为 json ,而则将 json 转换为 Java 对象。 在这个快速的 jackson 教程中,我给出了将 Java 对象以编程方式转换为 json 的示例。
Table of Contents
1\. Jackson maven dependency
2\. Convert Java object to JSON
3\. Pretty print JSON
4\. Convert JSON to Java object
在进入代码示例之前,让我们定义一个简单的 pojo 类,我们将在此示例中使用该类进行转换。
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
public Employee(){
}
public Employee(Integer id, String firstName, String lastName, Date birthDate){
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
//Getters and setters
@Override
public String toString()
{
return "Employee [id=" + id + ", firstName=" + firstName + ", " +
"lastName=" + lastName + "]";
}
}
1.Jackson 依赖
您可以通过两种方式添加 Jackson 依赖项,具体取决于您的项目类型。
1.1 基于 Maven 的项目
在pom.xml
文件中添加以下依赖项。
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.6</version>
</dependency>
</dependencies>
1.2 对于 ANT 或其他项目类型
对于非 Maven 用例,可以从 Maven 中央仓库下载 jar。
2.Jackson ObjectMapper
ObjectMapper
是用于数据绑定的主要 API。 它带有几种读取器/写入器方法,以执行从 Java 到 JSON 的转换。 它将使用JsonParser
和JsonGenerator
的实例来实现 JSON 的实际读取/写入。
2.1 将 json 转换为对象的语法
使用以下示例语法读取 JSON 并填充 Java 对象。
ObjectMapper mapper = new ObjectMapper();
Object value = mapper.readValue(jsonSource , javaObject);
jsonSource
– 将获取 json 字符串的输入源。javaObject
– 需要填充的目标 Java 对象。
2.2 将对象转换为 json 的语法
使用以下示例语法将 Java 对象写入 json 字符串。
ObjectMapper mapper = new ObjectMapper();
Object value = mapper.writeValue(jsonTarget, javaObject);
jsonTarget
– 将写入 json 字符串的输出目标。javaObject
– 需要转换为 json 的源 Java 对象。
3. Jackson 将对象转换为 JSON
要转换雇员对象并将其写入某个文件,可以使用以下代码。
package test.jackson;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
public class JavaToJSONExample
{
public static void main(String[] args)
{
@SuppressWarnings("deprecation")
Employee employee = new Employee(1, "Lokesh", "Gupta", new Date(1981,8,18));
ObjectMapper mapper = new ObjectMapper();
try
{
mapper.writeValue(new File("c://temp/employee.json"), employee);
} catch (JsonGenerationException e)
{
e.printStackTrace();
} catch (JsonMappingException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
程序输出。
{"id":1,"firstName":"Lokesh","lastName":"Gupta"}
4. Jackson 精美打印 JSON 输出
如果看上面的输出,那么写在文本文件中的输出是非常原始的并且没有格式化。 您可以使用writerWithDefaultPrettyPrinter
而不是defaultPrettyPrintingWriter()
实例编写格式化的 JSON 内容,如下所示:
package test.jackson;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
public class JavaToPrettyJSONExample
{
public static void main(String[] args)
{
@SuppressWarnings("deprecation")
Employee employee = new Employee(1, "Lokesh", "Gupta", new Date(1981,8,18));
ObjectMapper mapper = new ObjectMapper();
try
{
mapper.defaultPrettyPrintingWriter().writeValue(new File("c://temp/employee.json"), employee);
} catch (JsonGenerationException e)
{
e.printStackTrace();
} catch (JsonMappingException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
程序输出:
{
"id" : 1,
"firstName" : "Lokesh",
"lastName" : "Gupta"
}
5. Jackson 将 JSON 转换为 Java 对象
要将 json 字符串转换为 java 对象(例如Employee
对象),请使用以下代码:
package test.jackson;
import java.io.File;
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
public class JSONToJavaExample
{
public static void main(String[] args)
{
Employee employee = null;
ObjectMapper mapper = new ObjectMapper();
try
{
employee = mapper.readValue(new File("c://temp/employee.json"), Employee.class);
} catch (JsonGenerationException e)
{
e.printStackTrace();
} catch (JsonMappingException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
System.out.println(employee);
}
}
程序输出:
Employee [id=1, firstName=Lokesh, lastName=Gupta]
确保在 POJO 类中定义了默认的构造器(例如,本例中为Employee.java
)。 Jackson 使用默认构造器通过反射来创建 Java 类的实例。 如果没有提供默认的构造器,那么您将在运行时得到JsonMappingException
。
学习愉快!
Jackson – 将 JSON 转换为Map
并将Map
转换为 JSON
原文: https://howtodoinjava.com/jackson/jackson-json-to-from-hashmap/
在 Jackson json 映射示例示例中,我们将学习将 json 转换为映射对象,然后我们将学习将 java 映射转换为 json。
1. Jackson 依赖项
在您的应用项目中包括 Jackson2 依赖项。 不要忘记在 maven 站点检查最新依赖项。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
2. Jackson 将Map
转换为 JSON
将Map
转换为 JSON 的 Java 程序如下。 我在这里使用HashMap
。
package com.howtodoinjava.jackson2.example;
import java.io.IOException;
import java.util.HashMap;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class MapToJSON
{
public static void main(String[] args)
{
HashMap<String, Object> hashmap = new HashMap<String, Object>();
hashmap.put("id", 11);
hashmap.put("firstName", "Lokesh");
hashmap.put("lastName", "Gupta");
ObjectMapper mapper = new ObjectMapper();
try
{
//Convert Map to JSON
String json = mapper.writeValueAsString(hashmap);
//Print JSON output
System.out.println(json);
}
catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序输出。
{"id":11,"lastName":"Gupta","firstName":"Lokesh"}
3. Jackson 将 JSON 转换为Map
将 JSON 转换为Map
的 Java 程序如下。 我在这里使用HashMap
。
package com.howtodoinjava.jackson2.example;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONToMap
{
public static void main(String[] args)
{
String json = "{\"id\":1,\"name\":\"Lokesh Gupta\",\"age\":34,\"location\":\"India\"}";
HashMap<String, Object> map = new HashMap<String, Object>();
ObjectMapper mapper = new ObjectMapper();
try
{
//Convert Map to JSON
map = mapper.readValue(json, new TypeReference<Map<String, Object>>(){});
//Print JSON output
System.out.println(map);
}
catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序输出:
{id=1, name=Lokesh Gupta, age=34, location=India}
学习愉快!
Java XML 教程
JMS 发布/订阅消息示例
原文: https://howtodoinjava.com/jms/jms-publish-subscribe-message-example/
在 JMS 教程中,您将了解有关 JMS 消息传递域“点对点域”和“发布订阅域”的信息。 在此示例中,我们将通过发布/订阅消息传递域这样的示例。 发布/订阅消息传递域是一对多模型,其中一个发布者通过topic
向所有活动的订阅者发送消息,并且他们通过主题接收消息。
发布订阅 JMS 消息传递
发布/订阅消息发布者应用流程
下面给出了发送方应用的典型发布/订阅消息传递示例。 该应用的以下步骤是:
- 首先,我们将获取 JMS 服务器的
InitialContext
对象。 - 之后,使用初始上下文对象查找主题对象。
- 同样,我们将使用初始上下文对象查找主题连接工厂。
- 然后,使用主题连接工厂来创建主题连接,因为它表示 JMS 服务器的物理连接。
- 创建主题连接工厂后,我们将创建主题会话,在该会话中,第一个参数将决定该会话是否被处理。 但是,我们将使用非事务会话,而第二个参数确定传递模式。
- 之后,我们将为主题对象创建一个主题发布者,然后创建一条消息。
- 然后将诸如“
Hello
”之类的消息发送到主题对象。 - 关闭主题连接后,关闭主题连接后,它将自动关闭会话和主题发布者。
让我们看下面的例子:
package pubSub;
import javax.naming.InitialContext;
import javax.jms.Topic;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.TopicPublisher;
import javax.jms.DeliveryMode;
import javax.jms.TopicSession;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
public class Publisher
{
public static void main(String[] args) throws Exception
{
// get the initial context
InitialContext ctx = new InitialContext();
// lookup the topic object
Topic topic = (Topic) ctx.lookup("topic/topic0");
// lookup the topic connection factory
TopicConnectionFactory connFactory = (TopicConnectionFactory) ctx.
lookup("topic/connectionFactory");
// create a topic connection
TopicConnection topicConn = connFactory.createTopicConnection();
// create a topic session
TopicSession topicSession = topicConn.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
// create a topic publisher
TopicPublisher topicPublisher = topicSession.createPublisher(topic);
topicPublisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// create the "Hello World" message
TextMessage message = topicSession.createTextMessage();
message.setText("Hello World");
// publish the messages
topicPublisher.publish(message);
// print what we did
System.out.println("Message published: " + message.getText());
// close the topic connection
topicConn.close();
}
}
发布/订阅消息订阅者应用流程
接收方的大多数步骤与发送方应用相同 – 除了它将监听消息而不是发送 JMS 消息外。
package pubSub;
import javax.naming.InitialContext;
import javax.jms.Topic;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
public class Subscriber
{
public static void main(String[] args) throws Exception
{
// get the initial context
InitialContext ctx = new InitialContext();
// lookup the topic object
Topic topic = (Topic) ctx.lookup("topic/topic0");
// lookup the topic connection factory
TopicConnectionFactory connFactory = (TopicConnectionFactory) ctx.
lookup("topic/connectionFactory");
// create a topic connection
TopicConnection topicConn = connFactory.createTopicConnection();
// create a topic session
TopicSession topicSession = topicConn.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
// create a topic subscriber
TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
// start the connection
topicConn.start();
// receive the message
TextMessage message = (TextMessage) topicSubscriber.receive();
// print the message
System.out.println("Message received: " + message.getText());
// close the topic connection
topicConn.close();
}
}
在上面的代码中,接收方将接收来自发送方的消息并进行打印,即 HelloWorld。
学习愉快!
Java 读取 XML – Java DOM 解析器示例
原文: https://howtodoinjava.com/xml/read-xml-dom-parser-example/
在此 Java xml 解析器教程中,学习用 Java 中的 DOM 解析器读取 xml。 DOM 解析器旨在将 XML 作为内存中的对象图(树状结构)使用 – 称为“文档对象模型(DOM)”。
首先,解析器遍历输入的 XML 文件并创建与 XML 文件中的节点相对应的 DOM 对象。 这些 DOM 对象以树状结构链接在一起。 一旦解析器完成了解析过程,我们就会从中获得这种树状 DOM 对象结构。 现在,我们可以根据需要来回遍历 DOM 结构 - 从中获取/更新/删除数据。
Table of Contents
1\. DOM Parser API
-Import XML-related packages
-Create a DocumentBuilder
-Create a Document from a file or stream
-Validate Document structure
-Extract the root element
-Examine attributes
-Examine sub-elements
2\. Read XML with DOM parser
3\. Read data to POJO objects
4\. Parse "unknown" xml with DOM parser
阅读更多: DOM 解析器和 SAX 解析器之间的区别
出于示例目的,我们将在所有代码示例中解析 xml 内容。
<employees>
<employee id="111">
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<location>India</location>
</employee>
<employee id="222">
<firstName>Alex</firstName>
<lastName>Gussin</lastName>
<location>Russia</location>
</employee>
<employee id="333">
<firstName>David</firstName>
<lastName>Feezor</lastName>
<location>USA</location>
</employee>
</employees>
1. DOM 解析器 API
让我们记下一些主要步骤,以创建并使用 DOM 解析器来解析 Java 中的 XML 文件。
DOM 解析器的实际应用
1.1 导入 dom 解析器包
我们将需要首先在我们的应用中导入 dom 解析器包。
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
1.2 创建DocumentBuilder
下一步是创建DocumentBuilder
对象。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
1.3 从 xml 文件创建Document
对象
将 XML 文件读取到Document
对象。
Document document = builder.parse(new File( file ));
1.4 验证文件结构
XML 验证是可选的,但最好在开始解析之前进行验证。
Schema schema = null;
try {
String language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
SchemaFactory factory = SchemaFactory.newInstance(language);
schema = factory.newSchema(new File(name));
} catch (Exception e) {
e.printStackStrace();
}
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
1.5 提取根元素
我们可以使用以下代码从 XML 文档中获取根元素。
Element root = document.getDocumentElement();
1.6 检查属性
我们可以使用以下方法检查 xml 元素属性。
element.getAttribute("attributeName") ; //returns specific attribute
element.getAttributes(); //returns a Map (table) of names/values
1.7 检查子元素
子元素可以以下方式查询。
node.getElementsByTagName("subElementName") //returns a list of sub-elements of specified name
node.getChildNodes() //returns a list of all child nodes
2.使用 DOM 解析器读取 XML
在下面的示例代码中,我假设用户已经知道employees.xml
文件的结构(它的节点和属性); 因此,示例直接开始获取信息并开始在控制台中打印信息。 在现实生活中的应用中,我们将这些信息用于某些实际目的,而不是在控制台上打印并离开。
//Get Document Builder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
//Build Document
Document document = builder.parse(new File("employees.xml"));
//Normalize the XML Structure; It's just too important !!
document.getDocumentElement().normalize();
//Here comes the root node
Element root = document.getDocumentElement();
System.out.println(root.getNodeName());
//Get all employees
NodeList nList = document.getElementsByTagName("employee");
System.out.println("============================");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node node = nList.item(temp);
System.out.println(""); //Just a separator
if (node.getNodeType() == Node.ELEMENT_NODE)
{
//Print each employee's detail
Element eElement = (Element) node;
System.out.println("Employee id : " + eElement.getAttribute("id"));
System.out.println("First Name : " + eElement.getElementsByTagName("firstName").item(0).getTextContent());
System.out.println("Last Name : " + eElement.getElementsByTagName("lastName").item(0).getTextContent());
System.out.println("Location : " + eElement.getElementsByTagName("location").item(0).getTextContent());
}
}
程序输出:
employees
============================
Employee id : 111
First Name : Lokesh
Last Name : Gupta
Location : India
Employee id : 222
First Name : Alex
Last Name : Gussin
Location : Russia
Employee id : 333
First Name : David
Last Name : Feezor
Location : USA
3.将数据读取到 POJO 对象
现实生活中另一个应用的要求可能是使用上面示例代码中提取的信息填充 DTO 对象。 我写了一个简单的程序来帮助您了解如何轻松完成它。
假设我们必须填充Employee
对象,其定义如下。
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private String location;
//Setters and Getters
@Override
public String toString()
{
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", location=" + location + "]";
}
}
现在查看示例代码以填充员工对象列表。 就像在代码之间插入几行,然后将值复制到 DTO 而不是控制台中一样简单。
Java 程序,用于使用 DOM 解析器读取 XML 文件。
public class PopulateDTOExamplesWithParsedXML
{
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException
{
List<Employee> employees = parseEmployeesXML();
System.out.println(employees);
}
private static List<Employee> parseEmployeesXML() throws ParserConfigurationException, SAXException, IOException
{
//Initialize a list of employees
List<Employee> employees = new ArrayList<Employee>();
Employee employee = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("employees.xml"));
document.getDocumentElement().normalize();
NodeList nList = document.getElementsByTagName("employee");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node node = nList.item(temp);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
Element eElement = (Element) node;
//Create new Employee Object
employee = new Employee();
employee.setId(Integer.parseInt(eElement.getAttribute("id")));
employee.setFirstName(eElement.getElementsByTagName("firstName").item(0).getTextContent());
employee.setLastName(eElement.getElementsByTagName("lastName").item(0).getTextContent());
employee.setLocation(eElement.getElementsByTagName("location").item(0).getTextContent());
//Add Employee to list
employees.add(employee);
}
}
return employees;
}
}
程序输出。
[Employee [id=111, firstName=Lokesh, lastName=Gupta, location=India],
Employee [id=222, firstName=Alex, lastName=Gussin, location=Russia],
Employee [id=333, firstName=David, lastName=Feezor, location=USA]]
4.使用 DOM 解析器解析“未知” xml
上一个示例显示了在编写代码时,我们如何遍历具有已知或几乎不知道的结构的 XML 文档。 在某些情况下,我们可能必须以某种方式编写代码,以便即使在编码时假定的 XML 结构存在某些差异,程序也必须能够正常运行。
在这里,我们遍历 XML 文档树中存在的所有元素。 我们可以添加我们的知识并修改代码,以便在遍历树时只要获得所需信息,我们就可以使用它。
public class ParseUnknownXMLStructure
{
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException
{
//Get Document Builder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
//Build Document
Document document = builder.parse(new File("employees.xml"));
//Normalize the XML Structure; It's just too important !!
document.getDocumentElement().normalize();
//Here comes the root node
Element root = document.getDocumentElement();
System.out.println(root.getNodeName());
//Get all employees
NodeList nList = document.getElementsByTagName("employee");
System.out.println("============================");
visitChildNodes(nList);
}
//This function is called recursively
private static void visitChildNodes(NodeList nList)
{
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node node = nList.item(temp);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
System.out.println("Node Name = " + node.getNodeName() + "; Value = " + node.getTextContent());
//Check all attributes
if (node.hasAttributes()) {
// get attributes names and values
NamedNodeMap nodeMap = node.getAttributes();
for (int i = 0; i < nodeMap.getLength(); i++)
{
Node tempNode = nodeMap.item(i);
System.out.println("Attr name : " + tempNode.getNodeName()+ "; Value = " + tempNode.getNodeValue());
}
if (node.hasChildNodes()) {
//We got more childs; Let's visit them as well
visitChildNodes(node.getChildNodes());
}
}
}
}
}
}
程序输出:
employees
============================
Node Name = employee; Value =
Lokesh
Gupta
India
Attr name : id; Value = 111
Node Name = firstName; Value = Lokesh
Node Name = lastName; Value = Gupta
Node Name = location; Value = India
Node Name = employee; Value =
Alex
Gussin
Russia
Attr name : id; Value = 222
Node Name = firstName; Value = Alex
Node Name = lastName; Value = Gussin
Node Name = location; Value = Russia
Node Name = employee; Value =
David
Feezor
USA
Attr name : id; Value = 333
Node Name = firstName; Value = David
Node Name = lastName; Value = Feezor
Node Name = location; Value = USA
这就是 Java XML DOM 解析器的概念。 如果不清楚或需要更多说明,请给我评论。
学习愉快!
参考:
Java SAX 解析器 – XML 读取示例
原文: https://howtodoinjava.com/xml/sax-parser-read-xml-example/
SAX 解析器或 XML 的简单 API 已经存在很多年了,最初由 David Megginson 领导开发。 那时,您不得不从 David 的个人网站下载 Java 版本的 SAX。 在最终添加到 Java 标准版 1.4 中之前,它已发展为 SAX 项目 。
SAX 是 XML 的流接口,这意味着使用 SAX 的应用从文档的顶部开始,以顺序的时间接收到有关 XML 文档正在处理元素和属性的事件通知,并以根元素的关闭而结束。 这意味着它在线性时间内处理 XML 的效率非常高,而不会对系统内存提出过多要求。
让我们创建一个演示程序,以便使用 SAX 解析器读取 xml 文件以全面理解。
1.准备要解析的 xml 文件
该 xml 文件包含 xml 属性以及 xml 元素。
<users>
<user id="100">
<firstname>Tom</firstname>
<lastname>Hanks</lastname>
</user>
<user id="101">
<firstname>Lokesh</firstname>
<lastname>Gupta</lastname>
</user>
<user id="102">
<firstname>HowToDo</firstname>
<lastname>InJava</lastname>
</user>
</users>
2.创建模型类
package com.howtodoinjava.xml.sax;
/**
* Model class. Its instances will be populated using SAX parser.
* */
public class User
{
//XML attribute id
private int id;
//XML element fisrtName
private String firstName;
//XML element lastName
private String lastName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return this.id + ":" + this.firstName + ":" +this.lastName ;
}
}
3.通过扩展DefaultParser
构建处理器
下面的代码为解析处理器。 我在代码注释中添加了其他信息。 不过,您有任何疑问吗,请给我留言。
package com.howtodoinjava.xml.sax;
import java.util.ArrayList;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class UserParserHandler extends DefaultHandler
{
//This is the list which shall be populated while parsing the XML.
private ArrayList userList = new ArrayList();
//As we read any XML element we will push that in this stack
private Stack elementStack = new Stack();
//As we complete one user block in XML, we will push the User instance in userList
private Stack objectStack = new Stack();
public void startDocument() throws SAXException
{
//System.out.println("start of the document : ");
}
public void endDocument() throws SAXException
{
//System.out.println("end of the document document : ");
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
//Push it in element stack
this.elementStack.push(qName);
//If this is start of 'user' element then prepare a new User instance and push it in object stack
if ("user".equals(qName))
{
//New User instance
User user = new User();
//Set all required attributes in any XML element here itself
if(attributes != null && attributes.getLength() == 1)
{
user.setId(Integer.parseInt(attributes.getValue(0)));
}
this.objectStack.push(user);
}
}
public void endElement(String uri, String localName, String qName) throws SAXException
{
//Remove last added element
this.elementStack.pop();
//User instance has been constructed so pop it from object stack and push in userList
if ("user".equals(qName))
{
User object = this.objectStack.pop();
this.userList.add(object);
}
}
/**
* This will be called everytime parser encounter a value node
* */
public void characters(char[] ch, int start, int length) throws SAXException
{
String value = new String(ch, start, length).trim();
if (value.length() == 0)
{
return; // ignore white space
}
//handle the value based on to which element it belongs
if ("firstName".equals(currentElement()))
{
User user = (User) this.objectStack.peek();
user.setFirstName(value);
}
else if ("lastName".equals(currentElement()))
{
User user = (User) this.objectStack.peek();
user.setLastName(value);
}
}
/**
* Utility method for getting the current element in processing
* */
private String currentElement()
{
return this.elementStack.peek();
}
//Accessor for userList object
public ArrayList getUsers()
{
return userList;
}
}
4. SAX 解析器读取 XML 文件
package com.howtodoinjava.xml.sax;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class UsersXmlParser
{
public ArrayList parseXml(InputStream in)
{
//Create a empty link of users initially
ArrayList<user> users = new ArrayList</user><user>();
try
{
//Create default handler instance
UserParserHandler handler = new UserParserHandler();
//Create parser from factory
XMLReader parser = XMLReaderFactory.createXMLReader();
//Register handler with parser
parser.setContentHandler(handler);
//Create an input source from the XML input stream
InputSource source = new InputSource(in);
//parse the document
parser.parse(source);
//populate the parsed users list in above created empty list; You can return from here also.
users = handler.getUsers();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
return users;
}
}
5)测试 SAX 解析器
让我们编写一些代码来测试我们的处理器是否真正起作用。
package com.howtodoinjava.xml.sax;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
public class TestSaxParser
{
public static void main(String[] args) throws FileNotFoundException
{
//Locate the file
File xmlFile = new File("D:/temp/sample.xml");
//Create the parser instance
UsersXmlParser parser = new UsersXmlParser();
//Parse the file
ArrayList users = parser.parseXml(new FileInputStream(xmlFile));
//Verify the result
System.out.println(users);
}
}
Output:
[100:Tom:Hanks, 101:Lokesh:Gupta, 102:HowToDo:InJava]
学习愉快!
Java JDOM2 – XML 读取示例
原文: https://howtodoinjava.com/xml/jdom2-read-parse-xml-examples/
JDOM 解析器可用于在更新 XML 内容后用于读取 XML,解析 XML 和写入 XML 文件。 它将 JDOM2 文档存储在内存中,以读取和修改其值。
将 XML 文档加载到内存中后,JDOM2 维护严格的父子类型关系。 父类型的 JDOM 实例(父)具有访问其内容的方法,子类型的 JDOM 实例(内容)具有访问其父对象的方法。
Table of Contents
Project Structure
JDOM2 Maven Dependency
Create JDOM2 Document
Read and filter XML content
Read XML Content with XPath
Complete Example
源码下载
项目结构
请创建此文件夹结构以执行示例。 这是在 Eclipse 中创建的简单 Maven 项目。
项目结构
请注意,我已经使用了 lambda 表达式和方法引用,因此您需要配置为使用 JDK 1.8。
JDOM2 Maven 依赖关系
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
</dependency>
要执行 XPath,您还需要 jaxen。
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
创建 JDOM2 文档
您可以使用下面列出的任何解析器创建org.jdom2.Document
实例。 它们都解析 XML 并返回内存中的 JDOM 文档。
-
使用 DOM 解析器
private static Document getDOMParsedDocument(final String fileName) { Document document = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //If want to make namespace aware. //factory.setNamespaceAware(true); DocumentBuilder documentBuilder = factory.newDocumentBuilder(); org.w3c.dom.Document w3cDocument = documentBuilder.parse(fileName); document = new DOMBuilder().build(w3cDocument); } catch (IOException | SAXException | ParserConfigurationException e) { e.printStackTrace(); } return document; }
-
使用 SAX 解析器
private static Document getSAXParsedDocument(final String fileName) { SAXBuilder builder = new SAXBuilder(); Document document = null; try { document = builder.build(fileName); } catch (JDOMException | IOException e) { e.printStackTrace(); } return document; }
-
使用 StAX 解析器
private static Document getStAXParsedDocument(final String fileName) { Document document = null; try { XMLInputFactory factory = XMLInputFactory.newFactory(); XMLEventReader reader = factory.createXMLEventReader(new FileReader(fileName)); StAXEventBuilder builder = new StAXEventBuilder(); document = builder.build(reader); } catch (JDOMException | IOException | XMLStreamException e) { e.printStackTrace(); } return document; }
读取和过滤 XML 内容
我将读取employees.xml
文件。
<employees>
<employee id="101">
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<country>India</country>
<department id="25">
<name>ITS</name>
</department>
</employee>
<employee id="102">
<firstName>Brian</firstName>
<lastName>Schultz</lastName>
<country>USA</country>
<department id="26">
<name>DEV</name>
</department>
</employee>
</employees>
读取根节点
使用document.getRootElement()
方法。
public static void main(String[] args)
{
String xmlFile = "employees.xml";
Document document = getSAXParsedDocument(xmlFile);
Element rootNode = document.getRootElement();
System.out.println("Root Element :: " + rootNode.getName());
}
输出:
Root Element :: employees
读取属性值
使用Element.getAttributeValue()
方法。
public static void main(String[] args)
{
String xmlFile = "employees.xml";
Document document = getSAXParsedDocument(xmlFile);
Element rootNode = document.getRootElement();
rootNode.getChildren("employee").forEach( ReadXMLDemo::readEmployeeNode );
}
private static void readEmployeeNode(Element employeeNode)
{
//Employee Id
System.out.println("Id : " + employeeNode.getAttributeValue("id"));
}
输出:
Id : 101
Id : 102
读取元素值
使用Element.getChildText()
或Element.getText()
方法。
public static void main(String[] args)
{
String xmlFile = "employees.xml";
Document document = getSAXParsedDocument(xmlFile);
Element rootNode = document.getRootElement();
rootNode.getChildren("employee").forEach( ReadXMLDemo::readEmployeeNode );
}
private static void readEmployeeNode(Element employeeNode)
{
//Employee Id
System.out.println("Id : " + employeeNode.getAttributeValue("id"));
//First Name
System.out.println("FirstName : " + employeeNode.getChildText("firstName"));
//Last Name
System.out.println("LastName : " + employeeNode.getChildText("lastName"));
//Country
System.out.println("country : " + employeeNode.getChild("country").getText());
/**Read Department Content*/
employeeNode.getChildren("department").forEach( ReadXMLDemo::readDepartmentNode );
}
private static void readDepartmentNode(Element deptNode)
{
//Department Id
System.out.println("Department Id : " + deptNode.getAttributeValue("id"));
//Department Name
System.out.println("Department Name : " + deptNode.getChildText("name"));
}
Output:
FirstName : Lokesh
LastName : Gupta
country : India
Department Id : 25
Department Name : ITS
FirstName : Brian
LastName : Schultz
country : USA
Department Id : 26
Department Name : DEV
使用 XPath 读取 XML 内容
要使用 xpath 读取任何元素的值集,您需要编译XPathExpression
并使用其evaluate()
方法。
String xmlFile = "employees.xml";
Document document = getSAXParsedDocument(xmlFile);
XPathFactory xpfac = XPathFactory.instance();
//Read employee ids
XPathExpression<Attribute> xPathA = xpfac.compile("//employees/employee/@id", Filters.attribute());
for (Attribute att : xPathA.evaluate(document))
{
System.out.println("Employee Ids :: " + att.getValue());
}
//Read employee first names
XPathExpression<Element> xPathN = xpfac.compile("//employees/employee/firstName", Filters.element());
for (Element element : xPathN.evaluate(document))
{
System.out.println("Employee First Name :: " + element.getValue());
}
输出:
Employee Ids :: 101
Employee Ids :: 102
Employee First Name :: Lokesh
Employee First Name :: Brian
完整的 JDOM2 XML 读取示例
这是在 Java 中使用 JDOM2 读取 xml 的完整代码。
package com.howtodoinjava.demo.jdom2;
import java.io.FileReader;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.Filters;
import org.jdom2.input.DOMBuilder;
import org.jdom2.input.SAXBuilder;
import org.jdom2.input.StAXEventBuilder;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import org.xml.sax.SAXException;
@SuppressWarnings("unused")
public class ReadXMLDemo
{
public static void main(String[] args)
{
String xmlFile = "employees.xml";
Document document = getSAXParsedDocument(xmlFile);
/**Read Document Content*/
Element rootNode = document.getRootElement();
System.out.println("Root Element :: " + rootNode.getName());
System.out.println("\n=================================\n");
/**Read Employee Content*/
rootNode.getChildren("employee").forEach( ReadXMLDemo::readEmployeeNode );
System.out.println("\n=================================\n");
readByXPath(document);
}
private static void readEmployeeNode(Element employeeNode)
{
//Employee Id
System.out.println("Id : " + employeeNode.getAttributeValue("id"));
//First Name
System.out.println("FirstName : " + employeeNode.getChildText("firstName"));
//Last Name
System.out.println("LastName : " + employeeNode.getChildText("lastName"));
//Country
System.out.println("country : " + employeeNode.getChild("country").getText());
/**Read Department Content*/
employeeNode.getChildren("department").forEach( ReadXMLDemo::readDepartmentNode );
}
private static void readDepartmentNode(Element deptNode)
{
//Department Id
System.out.println("Department Id : " + deptNode.getAttributeValue("id"));
//Department Name
System.out.println("Department Name : " + deptNode.getChildText("name"));
}
private static void readByXPath(Document document)
{
//Read employee ids
XPathFactory xpfac = XPathFactory.instance();
XPathExpression<Attribute> xPathA = xpfac.compile("//employees/employee/@id", Filters.attribute());
for (Attribute att : xPathA.evaluate(document))
{
System.out.println("Employee Ids :: " + att.getValue());
}
XPathExpression<Element> xPathN = xpfac.compile("//employees/employee/firstName", Filters.element());
for (Element element : xPathN.evaluate(document))
{
System.out.println("Employee First Name :: " + element.getValue());
}
}
private static Document getSAXParsedDocument(final String fileName)
{
SAXBuilder builder = new SAXBuilder();
Document document = null;
try
{
document = builder.build(fileName);
}
catch (JDOMException | IOException e)
{
e.printStackTrace();
}
return document;
}
private static Document getStAXParsedDocument(final String fileName)
{
Document document = null;
try
{
XMLInputFactory factory = XMLInputFactory.newFactory();
XMLEventReader reader = factory.createXMLEventReader(new FileReader(fileName));
StAXEventBuilder builder = new StAXEventBuilder();
document = builder.build(reader);
}
catch (JDOMException | IOException | XMLStreamException e)
{
e.printStackTrace();
}
return document;
}
private static Document getDOMParsedDocument(final String fileName)
{
Document document = null;
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//If want to make namespace aware.
//factory.setNamespaceAware(true);
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
org.w3c.dom.Document w3cDocument = documentBuilder.parse(fileName);
document = new DOMBuilder().build(w3cDocument);
}
catch (IOException | SAXException | ParserConfigurationException e)
{
e.printStackTrace();
}
return document;
}
/*private static String readFileContent(String filePath)
{
StringBuilder contentBuilder = new StringBuilder();
try (Stream<String> stream = Files.lines( Paths.get(filePath), StandardCharsets.UTF_8))
{
stream.forEach(s -> contentBuilder.append(s).append("\n"));
}
catch (IOException e)
{
e.printStackTrace();
}
return contentBuilder.toString();
}*/
}
输出:
Root Element :: employees
=================================
Id : 101
FirstName : Lokesh
LastName : Gupta
country : India
Department Id : 25
Department Name : ITS
Id : 102
FirstName : Brian
LastName : Schultz
country : USA
Department Id : 26
Department Name : DEV
=================================
Employee Ids :: 101
Employee Ids :: 102
Employee First Name :: Lokesh
Employee First Name :: Brian
源代码下载
学习愉快!
参考文献:
使用 Java StAX 解析器读取 XML – 游标和迭代器 API
原文: https://howtodoinjava.com/xml/read-xml-stax-parser-cursor-iterator/
学习使用 Java StAX 解析器解析和读取 XML 文件。 StAX(用于 XML 的流 API)提供了两种解析 XML 的方法,即基于游标的 API 和基于迭代器的 API 。
1)StAX 解析器
就像 SAX 解析器一样, StAX API 设计用于解析 XML 流。 区别在于:
- StAX 是“
pull
” API。 SAX 是“push
” API。 - StAX 可以进行 XML 读取和写入。 SAX 只能读取 XML。
StAX 是拉取风格 API 。 这意味着您必须自己将 StAX 解析器从 XML 文件中的一个项目移动到另一个项目,就像使用标准Iterator
或 JDBC ResultSet
一样。 然后,您可以通过 StAX 解析器访问 XML 文件中遇到的每个此类“项目”的 XML 信息。
游标与迭代器
-
在读取 XML 文档时,迭代器读取器从其
nextEvent()
调用中返回 XML 事件对象。 此事件提供有关您遇到的 XML 标签类型(元素,文本,注释等)的信息。 收到的事件是不可变的,因此您可以传递应用以安全地对其进行处理。XMLEventReader reader = ...; while(reader.hasNext()){ XMLEvent event = reader.nextEvent(); if(event.getEventType() == XMLEvent.START_ELEMENT){ //process data } //... more event types handled here... }
-
与迭代器不同,游标的工作方式类似于 JDBC 中的
Resultset
。 如果将游标移动到 XML 文档中的下一个元素。 然后,您可以直接在游标上调用方法以获得有关当前事件的更多信息。XMLStreamReader streamReader = ...; while(streamReader.hasNext()){ int eventType = streamReader.next(); if(eventType == XMLStreamReader.START_ELEMENT){ System.out.println(streamReader.getLocalName()); } //... more event types handled here... }
2)StAX 迭代器 API 示例
下面给出的 XML 文档演示如何使用基于 StAX 迭代器的 API 读取对象。
XML 文件
<employees>
<employee id="101">
<name>Lokesh Gupta</name>
<title>Author</title>
</employee>
<employee id="102">
<name>Brian Lara</name>
<title>Cricketer</title>
</employee>
</employees>
使用 StAX 迭代器读取 XML
要读取文件,我已按照以下步骤编写了程序:
- 创建迭代器并开始接收事件。
- 一旦获得打开的
'employee'
标签,请创建一个新的Employee
对象。 - 从员工标签读取
id
属性,并将其设置为当前的Employee
对象。 - 循环到下一个开始标签事件。 这些是
employee
标记内的 XML 元素。 读取这些标签内的数据。 将读取的数据设置为当前的Employee
对象。 - 继续迭代事件。 当找到
'employee'
标签的结束元素事件时,可以说您已经读取了当前employee
的数据,因此将当前employee
对象添加到employeeList
集合中。 - 最后,通过打印
employeeList
验证读取的数据。
package com.howtodoinjava.demo.stax;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
public class ReadXMLExample
{
public static void main(String[] args) throws FileNotFoundException, XMLStreamException
{
File file = new File("employees.xml");
// Instance of the class which helps on reading tags
XMLInputFactory factory = XMLInputFactory.newInstance();
// Initializing the handler to access the tags in the XML file
XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(file));
//All read employees objects will be added to this list
List<Employee> employeeList = new ArrayList<>();
//Create Employee object. It will get all the data using setter methods.
//And at last, it will stored in above 'employeeList'
Employee employee = null;
// Checking the availability of the next tag
while (eventReader.hasNext())
{
XMLEvent xmlEvent = eventReader.nextEvent();
if (xmlEvent.isStartElement())
{
StartElement startElement = xmlEvent.asStartElement();
//As soo as employee tag is opened, create new Employee object
if("employee".equalsIgnoreCase(startElement.getName().getLocalPart())) {
employee = new Employee();
}
//Read all attributes when start tag is being read
@SuppressWarnings("unchecked")
Iterator<Attribute> iterator = startElement.getAttributes();
while (iterator.hasNext())
{
Attribute attribute = iterator.next();
QName name = attribute.getName();
if("id".equalsIgnoreCase(name.getLocalPart())) {
employee.setId(Integer.valueOf(attribute.getValue()));
}
}
//Now everytime content tags are found;
//Move the iterator and read data
switch (startElement.getName().getLocalPart())
{
case "name":
Characters nameDataEvent = (Characters) eventReader.nextEvent();
employee.setName(nameDataEvent.getData());
break;
case "title":
Characters titleDataEvent = (Characters) eventReader.nextEvent();
employee.setTitle(titleDataEvent.getData());
break;
}
}
if (xmlEvent.isEndElement())
{
EndElement endElement = xmlEvent.asEndElement();
//If employee tag is closed then add the employee object to list;
//and be ready to read next employee data
if("employee".equalsIgnoreCase(endElement.getName().getLocalPart())) {
employeeList.add(employee);
}
}
}
System.out.println(employeeList); //Verify read data
}
}
//Output:
[Employee [id=101, name=Lokesh Gupta, title=Author],
Employee [id=102, name=Brian Lara, title=Cricketer]]
3)StAX 游标 API 示例
我将使用基于游标的 API 读取相同的employees.xml
文件。
package com.howtodoinjava.demo.stax;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class ReadXMLExample
{
public static void main(String[] args) throws FileNotFoundException, XMLStreamException
{
//All read employees objects will be added to this list
List<Employee> employeeList = new ArrayList<>();
//Create Employee object. It will get all the data using setter methods.
//And at last, it will stored in above 'employeeList'
Employee employee = null;
File file = new File("employees.xml");
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader streamReader = factory.createXMLStreamReader(new FileReader(file));
while(streamReader.hasNext())
{
//Move to next event
streamReader.next();
//Check if its 'START_ELEMENT'
if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT)
{
//employee tag - opened
if(streamReader.getLocalName().equalsIgnoreCase("employee")) {
//Create new employee object asap tag is open
employee = new Employee();
//Read attributes within employee tag
if(streamReader.getAttributeCount() > 0) {
String id = streamReader.getAttributeValue(null,"id");
employee.setId(Integer.valueOf(id));
}
}
//Read name data
if(streamReader.getLocalName().equalsIgnoreCase("name")) {
employee.setName(streamReader.getElementText());
}
//Read title data
if(streamReader.getLocalName().equalsIgnoreCase("title")) {
employee.setTitle(streamReader.getElementText());
}
}
//If employee tag is closed then add the employee object to list
if(streamReader.getEventType() == XMLStreamReader.END_ELEMENT)
{
if(streamReader.getLocalName().equalsIgnoreCase("employee")) {
employeeList.add(employee);
}
}
}
//Verify read data
System.out.println(employeeList);
}
}
//Output:
[Employee [id=101, name=Lokesh Gupta, title=Author],
Employee [id=102, name=Brian Lara, title=Cricketer]]
4)总结
因此,在此 StAX 解析器教程中,我们学习了以下内容:
- 什么是基于 XML 流 API 的 StAX 解析器。
- StAX 与 SAX 解析器之间的差异。
- 如何通过示例使用 StAX 迭代器 API 来读取 XML。
- 如何通过示例使用 StAX 游标 API 来读取 XML。
两种 API 都能够解析任何类型的 XML 文档,但是游标 API 比迭代器 API 具有更高的内存效率。 因此,如果您的应用需要更好的性能,请考虑使用基于游标的 API。
将我的问题放在评论部分。
学习愉快!
DOM 与 Java 中的 SAX 解析器
原文: https://howtodoinjava.com/xml/dom-vs-sax-parser-in-java/
DOM 与 SAX 解析器之间的区别是非常流行 Java 面试问题 ,当在 Java 和 XML 上进行面试时经常被问到。 DOM 和 SAX 解析器都广泛用于在 Java 应用中读取和解析 XML 文件,它们都有各自的优缺点。 在这篇文章中,我列出了两个解析器之间的一些明显的差异。
1. Java 中的 DOM XML 解析器
DOM 解析器是基于树的 API 。 基于树的 API 以树结构为中心,因此在树的组件(是 DOM 文档)上提供接口,例如Document
接口,Node
接口, NodeList
接口,Element
接口,Attrubute
接口等等。
DOM 解析器根据输入文档在内存中创建树结构,然后等待来自客户端的请求。 DOM 解析器始终将整个文档提供给客户端应用,无论客户端实际需要多少。 使用 DOM 解析器,客户端应用中的方法调用必须是显式的,并形成一种链式方法调用。
2. Java 中的 SAX XML 解析器
SAX 解析器是基于事件的 API 。 通常,基于事件的 API 在处理器上提供接口。 有四个处理器接口,ContentHandler
接口, DTDHandler
接口,EntityResolver
接口和ErrorHandler
接口。
SAX 解析器不会创建任何内部结构。 取而代之的是,它将输入文档中组件的出现视为事件,并告诉客户端在读取输入文档时所读取的内容。 SAX 解析器始终在任何给定时间始终仅将文档的片段提供给客户端应用。 使用 SAX 解析器,当在 xml 文档上解析期间发生某些特定事件时,某些自定义方法称为“回调”方法。 尽管我们可以显式调用它们,但客户端不必显式调用这些方法。
3. Java 中的 DOM 和 SAX XML 解析器之间的区别
让我们列出一个容易记住的差异简短列表。
DOM(文档对象模型)
- 解析整个文档
- 将结果表示为树
- 让您搜索树
- 让您修改树
- 适合读取数据/配置文件
SAX
- 解析直到您告诉它停止
- 为每个事件触发事件处理器:
- 开始标签
- 标签正文
- 结束标签
- 低级 API
- 适用于非常大的文档,特别是如果您只关心文档的一小部分。
4.如何在 DOM 和 SAX 解析器之间进行选择?
理想情况下,一个好的解析器应该是快速的(省时的),节省空间的,功能丰富的并且易于使用的。 但是实际上,没有一个主要的解析器同时具有所有这些功能。 例如,DOM 解析器功能丰富(因为它在内存中创建了 DOM 树,并允许您重复访问文档的任何部分,并允许您修改 DOM 树),但是当文档很大时,空间效率低下 ,并且需要花费一些时间来学习如何使用它。
但是,在输入文档较大的情况下,SAX 解析器的空间效率要高得多(因为它不创建内部结构)。 而且,由于它的 API 非常简单,因此与 DOM 分析器相比,它运行更快且更易于学习。 但是从功能的角度来看,它提供的功能较少,这意味着用户自己必须承担更多的责任,例如创建自己的数据结构。
我认为答案确实取决于您的应用的特性和当前的要求。
5.可以同时使用 SAX 和 DOM 解析器吗?
是,当然,因为 DOM 解析器和 SAX 解析器的使用是独立的。 例如,如果您的应用需要处理两个 XML 文档,并且对每个文档执行不同的操作,则可以对一个文档使用 DOM 解析器,对另一个文档使用 SAX 解析器,然后合并结果或使处理与每个文档配合 其他。
学习愉快!
Java 将 XML 转换为属性 – 从 XML 文件读取属性
原文: https://howtodoinjava.com/xml/convert-xml-to-properties/
Java 示例从 XML 文件创建.properties
文件。 此代码可用于从 XML 文件读取属性键值,以在应用代码中使用。
XML 示例的属性
要将 XML 文件转换为属性文件,最好的方法是使用java.util.Properties
类。 流程是:
- 使用
Properties.loadFromXML()
方法将 XML 文件加载到java.util.Properties
类对象中。 - 使用
Properties.store()
方法将内容写为属性。
package com.howtodoinjava.demo;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
public class XMLToProperties
{
public static void main(String[] args) throws InvalidPropertiesFormatException, IOException
{
String outPropertiesFile = "application.properties";
String inXmlFile = "applicationProperties.xml";
InputStream inStream = new FileInputStream(inXmlFile); //Input XML File
OutputStream outStream = new FileOutputStream(outPropertiesFile); //Output properties File
Properties props = new Properties();
//Load XML file
props.loadFromXML(inStream);
//Store to properties file
props.store(outStream, "Converted from applicationProperties.xml");
//Use properties in code
System.out.println(props.get("input.dir")); //Prints 'c:/temp/input'
}
}
输入 XML 文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>application.properties</comment>
<entry key="input.dir">c:/temp/input</entry>
<entry key="spring.batch.job.enabled">false</entry>
<entry key="spring.main.banner-mode">off</entry>
</properties>
输出属性文件
#Converted from applicationProperties.xml
#Mon Jul 23 18:15:00 IST 2018
spring.batch.job.enabled=false
input.dir=c\:/temp/input
spring.main.banner-mode=off
将我的问题放在评论部分。
学习愉快!
Java 将属性文件转换为 XML 文件
原文: https://howtodoinjava.com/xml/convert-properties-to-xml/
从Properties
对象或任何现有.properties
文件创建 XML 文件的 Java 示例。
从属性文件创建 XML 文件
要将属性文件转换为 XML 文件,最好的方法是使用java.util.Properties
类。 流程是:
- 将属性文件加载到
java.util.java.util.Properties
类对象中。 - 使用
Properties.storeToXML()
方法将内容写为 XML。
package com.howtodoinjava.demo.xml;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
import javax.xml.stream.XMLStreamException;
public class PropertiesToXML
{
public static void main(String[] args) throws XMLStreamException,
InvalidPropertiesFormatException, IOException
{
String inPropertiesFile = "application.properties";
String outXmlFile = "applicationProperties.xml";
InputStream is = new FileInputStream(inPropertiesFile); //Input file
OutputStream os = new FileOutputStream(outXmlFile); //Output file
Properties props = new Properties();
props.load(is);
props.storeToXML(os, "application.properties","UTF-8");
}
}
输入属性文件
#Disable batch job's auto start
spring.batch.job.enabled=false
spring.main.banner-mode=off
#batch input files location
input.dir=c:/temp/input
输出 XML 文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>application.properties</comment>
<entry key="input.dir">c:/temp/input</entry>
<entry key="spring.batch.job.enabled">false</entry>
<entry key="spring.main.banner-mode">off</entry>
</properties>
将我的问题放在评论部分。
学习愉快!
Java 字符串到 XML – 将字符串解析为 XML DOM 的示例
在 Java 中,XML 用org.w3c.dom.Document
对象表示。 在本 XML 教程中,我们将学习:
- 将 XML 字符串转换为 XML 文档
- 将 XML 文件内容转换为 XML 文档
1)将字符串转换为 XML 文档
要将将 XML 字符串转换为 XML Dom,我们需要以下类:
javax.xml.parsers.DocumentBuilder
:定义 API,以从来自各种输入源的 XML 内容中获取 XML DOM 文档实例。 这些输入源是InputStreams
,文件,URL 和 SAXInputSources
。javax.xml.parsers.DocumentBuilderFactory
:定义一种工厂 API,使应用能够获取解析器(DocumentBuilder
),该解析器从 XML 内容生成 DOM 对象树。org.w3c.dom.Document
:它表示整个 XML DOM。 从概念上讲,它是文档树的根,并通过工厂方法提供对文档数据的访问,甚至深入到树中。java.io.StringReader
:根据字符串内容创建流。DocumentBuilder
使用此流读取 XML 内容进行解析。
package com.howtodoinjava.demo;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
public class StringtoXMLExample
{
public static void main(String[] args)
{
final String xmlStr = "<employees>" +
" <employee id=\"101\">" +
" <name>Lokesh Gupta</name>" +
" <title>Author</title>" +
" </employee>" +
" <employee id=\"102\">" +
" <name>Brian Lara</name>" +
" <title>Cricketer</title>" +
" </employee>" +
"</employees>";
//Use method to convert XML string content to XML Document object
Document doc = convertStringToXMLDocument( xmlStr );
//Verify XML document is build correctly
System.out.println(doc.getFirstChild().getNodeName());
}
private static Document convertStringToXMLDocument(String xmlString)
{
//Parser that produces DOM object trees from XML content
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//API to obtain DOM Document instance
DocumentBuilder builder = null;
try
{
//Create DocumentBuilder with default configuration
builder = factory.newDocumentBuilder();
//Parse the content to Document object
Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
return doc;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
//Output:
employees
2)将 XML 文件转换为 XML 文档
要使从 XML 文件获取 XML dom,而不是将 XML 字符串传递给DocumentBuilder
,请传递文件路径以使解析器直接读取文件内容。
我们有包含 XML 内容的employees.xml
文件,我们将阅读以获取 XML 文档。
<employees>
<employee id="101">
<name>Lokesh Gupta</name>
<title>Author</title>
</employee>
<employee id="102">
<name>Brian Lara</name>
<title>Cricketer</title>
</employee>
</employees>
package com.howtodoinjava.demo;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
public class StringtoXMLExample
{
public static void main(String[] args)
{
final String xmlFilePath = "employees.xml";
//Use method to convert XML string content to XML Document object
Document doc = convertXMLFileToXMLDocument( xmlFilePath );
//Verify XML document is build correctly
System.out.println(doc.getFirstChild().getNodeName());
}
private static Document convertXMLFileToXMLDocument(String filePath)
{
//Parser that produces DOM object trees from XML content
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//API to obtain DOM Document instance
DocumentBuilder builder = null;
try
{
//Create DocumentBuilder with default configuration
builder = factory.newDocumentBuilder();
//Parse the content to Document object
Document doc = builder.parse(new File(filePath));
return doc;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
//Output:
employees
将我的问题放在评论部分。
学习愉快!
Java XML 转换为字符串 – 将 XML 对象写入文件的示例
原文: https://howtodoinjava.com/xml/xml-to-string-write-xml-file/
Java 示例读取 XML 文件,打印 XML 字符串进行控制台,或将 XML 写入文件。
1)将 XML 转换为字符串
要将 XML 对象(即org.w3c.dom.Document
)转换为字符串,您需要以下类:
javax.xml.transform.Transformer
:此类的实例可以使用其transform()
方法将源树转换为结果树。javax.xml.transform.TransformerFactory
:创建Transformer
实例的工厂。javax.xml.transform.dom.DOMSource
:文档树(DOM)树形式的源树。javax.xml.transform.stream.StreamResult
:转换结果树的持有人,可以是 XML,纯文本,HTML 或其他某种形式的标记。
1.1)将 XML 打印到控制台或日志文件
private static void writeXmlDocumentToXmlFile(Document xmlDocument)
{
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer;
try {
transformer = tf.newTransformer();
// Uncomment if you do not require XML declaration
// transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//A character stream that collects its output in a string buffer,
//which can then be used to construct a string.
StringWriter writer = new StringWriter();
//transform document to string
transformer.transform(new DOMSource(xmlDocument), new StreamResult(writer));
String xmlString = writer.getBuffer().toString();
System.out.println(xmlString); //Print to console or logs
}
catch (TransformerException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
1.2)将 XML 写入文件
private static void writeXmlDocumentToXmlFile(Document xmlDocument, String fileName)
{
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer;
try {
transformer = tf.newTransformer();
//Uncomment if you do not require XML declaration
//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//Write XML to file
FileOutputStream outStream = new FileOutputStream(new File(fileName));
transformer.transform(new DOMSource(xmlDocument), new StreamResult(outStream));
}
catch (TransformerException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
2)从文件读取 XML
将 XML 从.xml
文件读取到Document
对象的示例。
private static Document convertXMLFileToXMLDocument(String filePath)
{
//Parser that produces DOM object trees from XML content
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//API to obtain DOM Document instance
DocumentBuilder builder = null;
try
{
//Create DocumentBuilder with default configuration
builder = factory.newDocumentBuilder();
//Parse the content to Document object
Document xmlDocument = builder.parse(new File(filePath));
return xmlDocument;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
3)完整的例子
用于运行示例的完整代码。
package com.howtodoinjava.demo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public class XmlToStringExample
{
public static void main(String[] args)
{
final String xmlFilePath = "employees.xml";
//Use method to convert XML string content to XML Document object
Document xmlDocument = convertXMLFileToXMLDocument( xmlFilePath );
//Write to file or print XML
writeXmlDocumentToXmlFile(xmlDocument, "newEmployees.xml");
}
private static Document convertXMLFileToXMLDocument(String filePath)
{
//Parser that produces DOM object trees from XML content
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//API to obtain DOM Document instance
DocumentBuilder builder = null;
try
{
//Create DocumentBuilder with default configuration
builder = factory.newDocumentBuilder();
//Parse the content to Document object
Document xmlDocument = builder.parse(new File(filePath));
return xmlDocument;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
private static void writeXmlDocumentToXmlFile(Document xmlDocument, String fileName)
{
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer;
try {
transformer = tf.newTransformer();
// Uncomment if you do not require XML declaration
// transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//Print XML or Logs or Console
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(xmlDocument), new StreamResult(writer));
String xmlString = writer.getBuffer().toString();
System.out.println(xmlString);
//Write XML to file
FileOutputStream outStream = new FileOutputStream(new File(fileName));
transformer.transform(new DOMSource(xmlDocument), new StreamResult(outStream));
}
catch (TransformerException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
输入文件。
<employees>
<employee id="101">
<name>Lokesh Gupta</name>
<title>Author</title>
</employee>
<employee id="102">
<name>Brian Lara</name>
<title>Cricketer</title>
</employee>
</employees>
输出文件。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<employees>
<employee id="101">
<name>Lokesh Gupta</name>
<title>Author</title>
</employee>
<employee id="102">
<name>Brian Lara</name>
<title>Cricketer</title>
</employee>
</employees>
将我的问题放在评论部分。
学习愉快!
Java XPath 示例 – XPath 教程
原文: https://howtodoinjava.com/xml/java-xpath-tutorial-example/
在此 Java XPath 教程中,我们将学习什么是 XPath 库,什么是 XPath 数据类型,并学习创建 XPath 表达式语法以从 XML 文件或文档中检索信息。 此信息可以是 XML 节点或 XML 属性,甚至可以是注释。
Table of Contents
1\. What is XPath?
2\. XPath Data Model
3\. XPath Data Types
4\. XPath Syntax
5\. XPath Expressions
6\. Recommended reading
在本教程中,我们将在运行各种 XPath 示例时使用此 XML。
<?xml version="1.0" encoding="utf-8" ?>
<inventory>
<!--Test is test comment-->
<book year="2000">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553380958</isbn>
<price>14.95</price>
</book>
<book year="2005">
<title>Burning Tower</title>
<author>Larry Niven</author>
<author>Jerry Pournelle</author>
<publisher>Pocket</publisher>
<isbn>0743416910</isbn>
<price>5.99</price>
</book>
<book year="1995">
<title>Zodiac</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553573862</isbn>
<price>7.50</price>
</book>
</inventory>
1.什么是 XPath
XPath 是一种语法,用于描述 XML 文档的各个部分。 使用 XPath,您可以引用第一个元素,元素的任何属性,包含某些文本的所有特定元素以及许多其他变体。 XSLT 样式表在匹配项中使用 XPath 表达式,并选择各种元素的属性来指示应如何转换文档。
在使用 XML 发送请求和接收响应来测试 Web 服务时,XPath 有时会很有用。
XPath 使用的语言语法与我们已经知道的非常相似。 语法是基本编程语言表达式(例如$x*6
的通配符)和类 Unix 路径表达式(例如/inventory/author
)的混合。
除了基本语法外,XPath 还提供了一组有用的函数(例如count()
或contains()
,与工具函数调用非常相似),这些函数使您可以搜索文档中的各种数据片段。
2. XPath 数据模型
XPath 将 XML 文档视为节点的树。 该树与文档对象模型(即 DOM 树)非常相似,因此,如果您熟悉 DOM,则可以轻松了解如何构建基本的 XPath 表达式。
XPath 数据模型中有七种节点:
- 根节点(每个文档仅一个)
- 元素节点
- 属性节点
- 文本节点
- 注释节点
- 处理指令节点
- 命名空间节点
2.1 根节点
根节点是包含整个文档的 XPath 节点。 在我们的示例中,根节点包含<inventory>
元素。 在 XPath 表达式中,用单斜杠('/'
)指定根节点。
2.2 元素节点
原始 XML 文档中的每个元素都由一个 XPath 元素节点表示。
例如,在下面的示例 XML 中,是元素节点。
book
title
author
publisher
isbn
price
2.3 属性节点
元素节点至少是 XML 源文档中每个属性的一个属性节点的父级。 这些节点用于定义有关特定元素节点的特征。
例如,在我们的 XML 片段“year
”中是一个属性节点。
2.4 文本节点
文本节点非常简单。 它们包含来自元素的文本。 如果 XML 文档中的原始文本包含实体或字符引用,则在创建 XPath 文本节点之前将其解析。
文本节点是纯净的文本。 文本节点需要包含尽可能多的文本。 请记住,文本节点的下一个或上一个节点不能是另一个文本节点。
例如,我们 XML 片段中的所有值都是文本节点,例如 “Snow Crash
”和“Neal Stephenson
”。
2.5 注释节点
注释节点也非常简单 - 它包含一些文本。 源文档中的每个注释都将成为注释节点。 注释节点的文本包含注释中的所有内容,除了<!--
开头和-->
结尾。
例如:
<!--Test is test comment-->
2.6 处理指令节点
处理指令节点具有两个部分,名称(由name()
函数返回)和字符串值。 字符串值是名称<?xml
之后的所有内容,包括空格,但不包括关闭处理指令的?>
。
例如:
<?xml version="1.0" encoding="utf-8"?>
2.7 命名空间节点
XSLT 样式表几乎从未使用过命名空间节点。 它们的存在主要是为了 XSLT 处理器的利益。
请记住,即使从技术上来说,命名空间的声明(例如
xmlns:auth="http://www.authors.net"
)在 XML 源中仍是一个属性,但它成为命名空间节点,而不是属性节点。
3. XPath 数据类型
在 Java 中,XPath 表达式可能返回以下数据类型之一:
- 节点集 – 表示一组节点。 该集合可以为空,也可以包含任意数量的节点。
- 节点 (Java 支持)– 表示单个节点。 它可以为空,也可以包含任意数量的子节点。
- 布尔值 – 表示值
true
或false
。 请注意,在 XPath 中,true
或false
字符串没有特殊含义或值。 有关布尔值的更详细讨论,请参见第 4 章的 4.2.1.2 节。 - 数字 – 表示浮点数。 XPath 和 XSLT 中的所有数字均实现为浮点数; XPath 和 XSLT 中不存在整数(或
int
)数据类型。 具体来说,所有数字都实现为 IEEE 754 浮点数,与 Javafloat
和double
原始类型使用的标准相同。 除普通数字外,数字还有五个特殊值:正负无穷大,正负零和NaN
(非数字的特殊符号)。 - 字符串 – 表示零个或多个字符,如 XML 规范中所定义。
这些数据类型通常很简单,并且除了节点集之外,类型之间的转换通常很简单。 我们将不在这里更详细地讨论这些数据类型。 相反,我们将讨论数据类型和转换,因为我们需要它们来执行特定的任务。
4. XPath 语法
XPath 使用 UNIX 和正则表达式这种语法。
4.1 选择具有 xpath 的节点
表达式 | 描述 |
---|---|
nodename |
选择所有名称为“nodename ”的节点 |
/ |
从根节点选择 |
// |
从当前节点中选择匹配选择的节点,无论它们在何处 |
. |
选择当前节点 |
.. |
选择当前节点的父节点 |
@ |
选择属性 |
4.2 将谓词与 xpath 一起使用
谓词用于查找特定节点或包含特定值的节点。 谓词始终嵌入在方括号中。
我们将在下一节中学习如何使用它们。
4.3 使用 xpath 访问未知节点
XPath 通配符可用于选择未知的 XML 元素。
通配符 | 描述 |
---|---|
* |
匹配任何元素节点 |
@* |
匹配任何属性节点 |
node() |
匹配任何种类的任何节点 |
4.4 XPath 轴
轴定义相对于当前节点的节点集。 以下是默认定义的轴。
轴名 | 结果 |
---|---|
ancestor |
选择当前节点的所有祖先(父,祖父等) |
ancestor-or-self |
选择当前节点的所有祖先(父,祖父等)和当前节点本身 |
attribute |
选择当前节点的所有属性 |
child |
选择当前节点的所有子节点 |
descendant |
选择当前节点的所有后代(子代,孙代等) |
descendant-or-self |
选择当前节点的所有后代(子代,孙代等)和当前节点本身 |
following |
选择当前节点的结束标记之后的文档中的所有内容 |
following-sibling |
选择当前节点之后的所有同级 |
namespace |
选择当前节点的所有命名空间节点 |
parent |
选择当前节点的父节点 |
preceding |
选择出现在文档中当前节点之前的所有节点,但祖先,属性节点和命名空间节点除外 |
preceding-sibling |
选择当前节点之前的所有同级 |
self |
选择当前节点 |
4.5 XPath 运算符
以下是可在 XPath 表达式中使用的 xpath 运算符的列表:
运算符 | 描述 | 例 | 返回值 |
---|---|---|---|
| |
计算两个节点集 | //book | //cd |
返回包含所有book 和cd 元素的节点集 |
+ |
加法 | 6 + 4 |
10 |
- |
减法 | 6 – 4 |
2 |
* |
乘法 | 6 * 4 |
24 |
div |
除法 | 8 div 4 |
2 |
= |
等于 | price = 9.80 |
如果价格为 9.80,则为true ,如果价格为 9.90,则为false |
!= |
不等于 | price != 9.80 |
如果价格为 9.90,则为true ,如果价格为 9.80,则为false |
< |
小于 | price < 9.80 |
如果价格为 9.00,则为true ,如果价格为 9.80,则为false |
< = |
小于或等于 | price <= 9.80 |
如果价格为 9.00,则为true ,如果价格为 9.90,则为false |
> |
大于 | prcie > 9.80 |
如果价格为 9.90,则为true ,如果价格为 9.80,则为false |
>= |
大于或等于 | price >= 9.80 |
如果价格为 9.90,则为true ,如果价格为 9.70,则为false |
or |
或 | price = 9.80 or price = 9.70 |
如果价格为 9.80,则为true ,如果价格为 9.50,则为false |
and |
且 | price > 9.00 and price < 9.90 |
如果价格为 9.80,则为true ,如果价格为 8.50,则为false |
mod |
模数(除法余数) | 5 mod 2 |
1 |
5. XPath 表达式
让我们尝试使用 XPath 表达式和给定的数据类型来检索 XML 的不同部分。
package xml;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XPathTest
{
public static void main(String[] args) throws Exception
{
//Build DOM
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("inventory.xml");
//Create XPath
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
System.out.println("n//1) Get book titles written after 2001");
// 1) Get book titles written after 2001
XPathExpression expr = xpath.compile("//book[@year>2001]/title/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//2) Get book titles written before 2001");
// 2) Get book titles written before 2001
expr = xpath.compile("//book[@year<2001]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//3) Get book titles cheaper than 8 dollars");
// 3) Get book titles cheaper than 8 dollars
expr = xpath.compile("//book[price<8]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//4) Get book titles costlier than 8 dollars");
// 4) Get book titles costlier than 8 dollars
expr = xpath.compile("//book[price>8]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//5) Get book titles added in first node");
// 5) Get book titles added in first node
expr = xpath.compile("//book[1]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//6) Get book title added in last node");
// 6) Get book title added in last node
expr = xpath.compile("//book[last()]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//7) Get all writers");
// 7) Get all writers
expr = xpath.compile("//book/author/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//8) Count all books titles ");
// 8) Count all books titles
expr = xpath.compile("count(//book/title)");
result = expr.evaluate(doc, XPathConstants.NUMBER);
Double count = (Double) result;
System.out.println(count.intValue());
System.out.println("n//9) Get book titles with writer name start with Neal");
// 9) Get book titles with writer name start with Neal
expr = xpath.compile("//book[starts-with(author,'Neal')]");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i)
.getChildNodes()
.item(1) //node <title> is on first index
.getTextContent());
}
System.out.println("n//10) Get book titles with writer name containing Niven");
// 10) Get book titles with writer name containing Niven
expr = xpath.compile("//book[contains(author,'Niven')]");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i)
.getChildNodes()
.item(1) //node <title> is on first index
.getTextContent());
}
System.out.println("//11) Get book titles written by Neal Stephenson");
// 11) Get book titles written by Neal Stephenson
expr = xpath.compile("//book[author='Neal Stephenson']/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//12) Get count of book titles written by Neal Stephenson");
// 12) Get count of book titles written by Neal Stephenson
expr = xpath.compile("count(//book[author='Neal Stephenson'])");
result = expr.evaluate(doc, XPathConstants.NUMBER);
count = (Double) result;
System.out.println(count.intValue());
System.out.println("n//13) Reading comment node ");
// 13) Reading comment node
expr = xpath.compile("//inventory/comment()");
result = expr.evaluate(doc, XPathConstants.STRING);
String comment = (String) result;
System.out.println(comment);
}
}
程序输出:
//1) Get book titles written after 2001
Burning Tower
//2) Get book titles written before 2001
Snow Crash
Zodiac
//3) Get book titles cheaper than 8 dollars
Burning Tower
Zodiac
//4) Get book titles costlier than 8 dollars
Snow Crash
//5) Get book titles added in the first node
Snow Crash
//6) Get book title added in last node
Zodiac
//7) Get all writers
Neal Stephenson
Larry Niven
Jerry Pournelle
Neal Stephenson
//8) Count all books titles
3
//9) Get book titles with writer name start with Neal
Snow Crash
Zodiac
//10) Get book titles with writer name containing Niven
Burning Tower
//11) Get book titles written by Neal Stephenson
Snow Crash
Zodiac
//12) Get count of book titles written by Neal Stephenson
2
//13) Reading comment node
Test is test comment
希望本 xpath 教程对您有所帮助。 它将帮助您使用 Java 执行 xpath。 字符串的 Java xpath 示例也将在 Java8 中成功运行。
如果您有任何建议,请发表评论。
学习愉快!
推荐阅读:
http://www.w3.org/TR/xpath-full-text-10-use-cases
http://en.wikipedia.org/wiki/XPath
http://oreilly.com/catalog/xmlnut/chapter/ch09.html
HornetQ 教程
Java xpath 示例 – 在 xml 文件上求值 xpath
Java xpath 示例读取 XML 文件并解析为 DOM 对象,然后求值org.w3c.dom.Document
对象上的 xpath 并以String
或NodeList
的形式获取结果。
1. Java 求值 xml 文件上的 xpath
- 创建
Document
DOM 对象javax.xml.parsers.DocumentBuilder
对象。 - 从
XPathFactory
创建XPath
。 - 使用
xpath.evaluate('expression', dom, resultType)
获取结果 HTML。
package com.howtodoinjava.demo;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XPathExample
{
public static void main(String[] args) throws Exception
{
String xmlFile = "employees.xml";
//Get DOM
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document xml = db.parse(xmlFile);
//Get XPath
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
//Get first match
String name = (String) xpath.evaluate("/employees/employee/firstName", xml, XPathConstants.STRING);
System.out.println(name); //Lokesh
//Get all matches
NodeList nodes = (NodeList) xpath.evaluate("/employees/employee/@id", xml, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue()); //1 2
}
}
}
程序输出:
Lokesh
1
2
2. XML 文件
输入的 xml 文件为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
<employee id="1">
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<department>
<id>101</id>
<name>IT</name>
</department>
</employee>
<employee id="2">
<firstName>Brian</firstName>
<lastName>Schultz</lastName>
<department>
<id>102</id>
<name>HR</name>
</department>
</employee>
</employees>
学习愉快!
阅读更多:
如何在 Java 中使用 xpath 获取 xml 中的属性值
Java8 xpath 示例 – 在字符串上求值 xpath
原文: https://howtodoinjava.com/xml/evaluate-xpath-on-xml-string/
Java 示例求值字符串上的 xpath 并返回字符串本身的结果 XML。
1. XPath 示例 – 在 xml 字符串上求值 xpath
- 创建包含
StringReader
并引用 XML 字符串的org.xml.sax.InputSource
。 - 从
XPathFactory
创建XPath
。 - 使用
xpath.evaluate('expression', inputSource)
获取结果 HTML。
package com.howtodoinjava.demo;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class XPathExample
{
public static void main(String[] args) throws Exception
{
String xml = "<employees>"
+ "<employee id=\"1\">"
+ "<firstName>Lokesh</firstName>"
+ "<lastName>Gupta</lastName>"
+ "<department><id>101</id><name>IT</name></department>"
+ "</employee>"
+ "</employees>";
InputSource inputXML = new InputSource( new StringReader( xml ) );
XPath xPath = XPathFactory.newInstance().newXPath();
String result = xPath.evaluate("/employees/employee/firstName", inputXML);
System.out.println(result);
}
}
程序输出:
Lokesh
2. XPath 示例 – 在 xml 文件上求值 xpath
package com.howtodoinjava.demo;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XPathExample
{
public static void main(String[] args) throws Exception
{
String xmlFile = "employees.xml";
//Get DOM
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document xml = db.parse(xmlFile);
//Get XPath
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
//Get first match
String name = (String) xpath.evaluate("/employees/employee/firstName", xml, XPathConstants.STRING);
System.out.println(name); //Lokesh
//Get all matches
NodeList nodes = (NodeList) xpath.evaluate("/employees/employee/@id", xml, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue()); //1 2
}
}
}
程序输出:
Lokesh
1
2
输入的 xml 文件为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
<employee id="1">
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<department>
<id>101</id>
<name>IT</name>
</department>
</employee>
<employee id="2">
<firstName>Brian</firstName>
<lastName>Schultz</lastName>
<department>
<id>102</id>
<name>HR</name>
</department>
</employee>
</employees>
在上面的 Xpath 教程中,我们学习了使用示例求值字符串上的 xpath 的方法。
学习愉快!
阅读更多:
如何在 Java 中使用 xpath 获取 xml 中的属性值
Java XPath 表达式示例
原文: https://howtodoinjava.com/xml/java-xpath-expression-examples/
Java xpath 表达式示例,通过求值这些表达式从 XML 文档中提取信息。 我们将学习获取有关匹配属性值,匹配字段值,contains()
表达式等的信息。
1. XPath 查询示例
1.1 输入 XML 文件
首先查看我们将读取的 XML 文件,然后使用 xpath 查询从中获取信息。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
<employee id="1">
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<department>
<id>101</id>
<name>IT</name>
</department>
</employee>
<employee id="2">
<firstName>Brian</firstName>
<lastName>Schultz</lastName>
<department>
<id>102</id>
<name>HR</name>
</department>
</employee>
<employee id="3">
<firstName>Alex</firstName>
<lastName>Kolenchisky</lastName>
<department>
<id>103</id>
<name>FINANCE</name>
</department>
</employee>
<employee id="4">
<firstName>Amit</firstName>
<lastName>Jain</lastName>
<department>
<id>104</id>
<name>HR</name>
</department>
</employee>
<employee id="5">
<firstName>David</firstName>
<lastName>Beckham</lastName>
<department>
<id>105</id>
<name>DEVOPS</name>
</department>
</employee>
<employee id="6">
<firstName>Virat</firstName>
<lastName>Kohli</lastName>
<department>
<id>106</id>
<name>DEVOPS</name>
</department>
</employee>
<employee id="7">
<firstName>John</firstName>
<lastName>Wick</lastName>
<department>
<id>107</id>
<name>IT</name>
</department>
</employee>
<employee id="8">
<firstName>Mike</firstName>
<lastName>Anderson</lastName>
<department>
<id>108</id>
<name>HR</name>
</department>
</employee>
<employee id="9">
<firstName>Bob</firstName>
<lastName>Sponge</lastName>
<department>
<id>109</id>
<name>FINANCE</name>
</department>
</employee>
<employee id="10">
<firstName>Gary</firstName>
<lastName>Kasporov</lastName>
<department>
<id>110</id>
<name>IT</name>
</department>
</employee>
</employees>
1.2 XPath 表达式
现在来看几个有关如何构建 xpath 以便基于字段和属性的各种条件获取信息的示例。
描述 | XPath | 结果 |
---|---|---|
获取所有员工姓名 | /employees/employee/firstName/text() |
[Lokesh, Brian, Alex, Amit, David, Virat, John, Mike, Bob, Gary] |
获取所有部门名称 | /employees/employee/department/name/text() |
[IT, HR, FINANCE, HR, DEVOPS, DEVOPS, IT, HR, FINANCE, IT] |
获取所有 IT 员工 | /employees/employee[department/name='IT']/firstName/text() |
[Lokesh, John, Gary] |
按编号获取员工 | /employees/employee[@id=4]/firstName/text() |
[Amit] |
取得 ID 大于 6 的员工 | /employees/employee[@id>6]/firstName/text() |
[John, Mike, Bob, Gary] |
获取大卫的部门 | /employees/employee[firstName = 'David']/department/name/text() |
[DEVOPS] |
获取所有员工 ID | /employees/employee/@id |
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
获取人力资源部门的所有员工 ID | /employees/employee[department/name='HR']/@id |
[2, 4, 8] |
获取员工“Alex ”编号 |
/employees/employee[firstName='Alex']/@id |
[3] |
获取大于 5 的员工 ID | /employees/employee/@id[. > 5] |
[6, 7, 8, 9, 10] |
获取其 ID 包含“1”的员工 | /employees/employee[contains(@id,'1')]/firstName/text() |
[Lokesh, Gary] |
获取其 ID 包含 1 的员工 | descendant-or-self::*[contains(@id,'1')]/firstName/text() |
[Lokesh, Gary] |
2.求值 xpath 表达式的 Java 示例
让我们看一下用于求值以上 xpath 表达式的代码。
package com.howtodoinjava.demo;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XPathExample
{
public static void main(String[] args) throws Exception
{
//Get DOM Node for XML
String fileName= "employees.xml";
Document document = getDocument(fileName);
String xpathExpression = "";
/*******Get attribute values using xpath******/
//Get all employee ids
xpathExpression = "/employees/employee/@id";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get all employee ids in HR department
xpathExpression = "/employees/employee[department/name='HR']/@id";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee id of 'Alex'
xpathExpression = "/employees/employee[firstName='Alex']/@id";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee ids greater than 5
xpathExpression = "/employees/employee/@id[. > 5]";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee whose id contains 1
xpathExpression = "/employees/employee[contains(@id,'1')]/firstName/text()";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee whose id contains 1
xpathExpression = "descendant-or-self::*[contains(@id,'1')]/firstName/text()";
System.out.println( evaluateXPath(document, xpathExpression) );
}
private static List<String> evaluateXPath(Document document, String xpathExpression) throws Exception
{
// Create XPathFactory object
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
List<String> values = new ArrayList<>();
try
{
// Create XPathExpression object
XPathExpression expr = xpath.compile(xpathExpression);
// Evaluate expression result on XML document
NodeList nodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
values.add(nodes.item(i).getNodeValue());
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return values;
}
private static Document getDocument(String fileName) throws Exception
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fileName);
return doc;
}
}
程序输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[2, 4, 8]
[3]
[6, 7, 8, 9, 10]
[Lokesh, Gary]
[Lokesh, Gary]
XPath 表达式不是线程安全的。 确保在任何给定时间不从多个线程使用一个
XPathExpression
对象是应用的责任,并且在调用求值方法时,应用可能不会递归调用求值方法。
3.模型类
@XmlRootElement(name="employees")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employees implements Serializable
{
private static final long serialVersionUID = 1L;
@XmlElement(name="employee")
private List<Employee> employees;
public List<Employee> getEmployees() {
if(employees == null) {
employees = new ArrayList<Employee>();
}
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Employees [employees=" + employees + "]";
}
}
@XmlRootElement(name="employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@XmlAttribute
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
public Employee(int id, String fName, String lName, Department department) {
super();
this.id = id;
this.firstName = fName;
this.lastName = lName;
this.department = department;
}
//Setters and Getters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", department=" + department + "]";
}
}
@XmlRootElement(name="department")
@XmlAccessorType(XmlAccessType.FIELD)
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
Integer id;
String name;
public Department() {
super();
}
public Department(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
//Setters and Getters
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
将我的问题放在评论部分。
学习愉快!
参考文献:
Java XPath NamespaceContext
– 命名空间解析示例
原文: https://howtodoinjava.com/xml/xpath-namespace-resolution-example/
在此 Java 示例中,我们将使用NamespaceContext
将 XPath 命名空间解析学习为 XML 文件,该文件具有命名空间声明和各自的用法。
添加了 XML 文件的命名空间
我已经创建了sample.xml
文件并将其放在类路径中。
<ns2:bookStore xmlns:ns2="http://bookstore.com/schemes">
<ns2:book id="1">
<ns2:name>Data Structure</ns2:name>
</ns2:book>
<ns2:book id="2">
<ns2:name>Java Core</ns2:name>
</ns2:book>
</ns2:bookStore>
实现NamespaceContext
以创建命名空间解析器
该命名空间解析器可以与使用了命名空间定义的任何 XML 文件一起使用。 它搜索 XML 文档本身内任何给定命名空间前缀(作为参数传递)的命名空间声明。 因此无需单独创建命名空间映射。
public class NamespaceResolver implements NamespaceContext
{
//Store the source document to search the namespaces
private Document sourceDocument;
public NamespaceResolver(Document document) {
sourceDocument = document;
}
//The lookup for the namespace uris is delegated to the stored document.
public String getNamespaceURI(String prefix) {
if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return sourceDocument.lookupNamespaceURI(null);
} else {
return sourceDocument.lookupNamespaceURI(prefix);
}
}
public String getPrefix(String namespaceURI) {
return sourceDocument.lookupPrefix(namespaceURI);
}
@SuppressWarnings("rawtypes")
public Iterator getPrefixes(String namespaceURI) {
return null;
}
}
使用NamespaceResolver
并应用 XPath
现在,我们准备在 XML 文件上应用 xpath 表达式。
//Want to read all book names from XML
ArrayList<String> bookNames = new ArrayList<String>();
//Parse XML file
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new FileInputStream(new File("sample.xml")));
//Get XPath expression
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
xpath.setNamespaceContext(new NamespaceResolver(doc));
XPathExpression expr = xpath.compile("//ns2:bookStore/ns2:book/ns2:name/text()");
//Search XPath expression
Object result = expr.evaluate(doc, XPathConstants.NODESET);
//Iterate over results and fetch book names
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
bookNames.add(nodes.item(i).getNodeValue());
}
//Verify book names
System.out.println(bookNames);
上面程序的输出是:
[Data Structure, Java Core]
XPath 命名空间解析的完整源代码
这是上面示例的完整源代码。
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class Main
{
public static void main(String[] args) throws Exception
{
//Want to read all book names from XML
ArrayList<String> bookNames = new ArrayList<String>();
//Parse XML file
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new FileInputStream(new File("sample.xml")));
//Get XPath expression
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
xpath.setNamespaceContext(new NamespaceResolver(doc));
XPathExpression expr = xpath.compile("//ns2:bookStore/ns2:book/ns2:name/text()");
//Search XPath expression
Object result = expr.evaluate(doc, XPathConstants.NODESET);
//Iterate over results and fetch book names
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
bookNames.add(nodes.item(i).getNodeValue());
}
//Verify book names
System.out.println(bookNames);
}
}
class NamespaceResolver implements NamespaceContext
{
//Store the source document to search the namespaces
private Document sourceDocument;
public NamespaceResolver(Document document) {
sourceDocument = document;
}
//The lookup for the namespace uris is delegated to the stored document.
public String getNamespaceURI(String prefix) {
if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return sourceDocument.lookupNamespaceURI(null);
} else {
return sourceDocument.lookupNamespaceURI(prefix);
}
}
public String getPrefix(String namespaceURI) {
return sourceDocument.lookupPrefix(namespaceURI);
}
@SuppressWarnings("rawtypes")
public Iterator getPrefixes(String namespaceURI) {
return null;
}
}
在评论部分让我知道您的问题。
学习愉快!
参考: http://www.ibm.com/developerworks/library/x-nmspccontext/
Java XPath 从 XML 获取属性值
原文: https://howtodoinjava.com/xml/xpath-get-attribute-value-xml/
很多时候,我们需要解析 XML 文件并从中提取信息。 例如,使用 xpath 读取 XML 元素的属性值。 在此 Java XPath 教程中,学习从 XML 字符串获取属性值。
我正在使用 jdom 和 jaxen。 这些也是可用的其他大量开源 API,但是想法保持不变。
使用 XPath 从 Java 中获得值的 Java 程序
在给定的 Java 程序下面,从提供的 XML 字符串创建 DOM 对象。 然后,它使用XPath.selectNodes()
方法应用 XPATH 表达式。
方法返回Element
实例的列表,这些实例是求值 XPath 表达式的结果。 您可以迭代列表并使用结果。
package com.howtodoinjava.xml;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;
public class XmlAttributesUsingXPathExample
{
@SuppressWarnings("unchecked")
public static void main(String[] args) throws JDOMException, IOException
{
Document doc = new SAXBuilder(false).build(new StringReader(new String(
<users> " +
<user id='13423'>" +
<firstname>Andre</firstname>" +
</user>" +
<user id='32424'>" +
<firstname>Peter</firstname>" +
</user> " +
<user id='543534'>" +
<firstname>Sandra</firstname>" +
</user>" +
</users>")));
//Build the xpath expression
XPath xpathExpression = XPath.newInstance("//*[@id]");
//Apply xpath and fetch all matching nodes
ArrayList<Element> userIds = (ArrayList<Element>) xpathExpression.selectNodes(doc);
//Iterate over naodes and print the value
for (int i = 0; i < userIds.size(); i++)
{
System.out.println((userIds.get(i)).getAttributeValue("id").trim());
}
}
}
程序输出。
13423
32424
543534
请包括正确的类文件。 无效的导入会导致以下错误或类似的错误。
java.lang.ClassCastException: org.jdom.Document cannot be cast to org.w3c.dom.Node
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.eval(XPathExpressionImpl.java:116)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.eval(XPathExpressionImpl.java:98)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.evaluate(XPathExpressionImpl.java:180)
学习愉快!
在 Java 中使用 xpath 查找具有属性值的 xml 元素
如何使用 Java 中的 xpath 获取 xml 中的属性值的简单示例。 我们将学习获取信息以匹配属性值,属性值在范围内,xpath 属性contains()
等。
1. XPath 属性表达式
1.1 输入 XML 文件
首先查看我们将读取的 XML 文件,然后使用 xpath 查询从中获取信息。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
<employee id="1">
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<department>
<id>101</id>
<name>IT</name>
</department>
</employee>
<employee id="2">
<firstName>Brian</firstName>
<lastName>Schultz</lastName>
<department>
<id>102</id>
<name>HR</name>
</department>
</employee>
<employee id="3">
<firstName>Alex</firstName>
<lastName>Kolenchisky</lastName>
<department>
<id>103</id>
<name>FINANCE</name>
</department>
</employee>
<employee id="4">
<firstName>Amit</firstName>
<lastName>Jain</lastName>
<department>
<id>104</id>
<name>HR</name>
</department>
</employee>
<employee id="5">
<firstName>David</firstName>
<lastName>Beckham</lastName>
<department>
<id>105</id>
<name>DEVOPS</name>
</department>
</employee>
<employee id="6">
<firstName>Virat</firstName>
<lastName>Kohli</lastName>
<department>
<id>106</id>
<name>DEVOPS</name>
</department>
</employee>
<employee id="7">
<firstName>John</firstName>
<lastName>Wick</lastName>
<department>
<id>107</id>
<name>IT</name>
</department>
</employee>
<employee id="8">
<firstName>Mike</firstName>
<lastName>Anderson</lastName>
<department>
<id>108</id>
<name>HR</name>
</department>
</employee>
<employee id="9">
<firstName>Bob</firstName>
<lastName>Sponge</lastName>
<department>
<id>109</id>
<name>FINANCE</name>
</department>
</employee>
<employee id="10">
<firstName>Gary</firstName>
<lastName>Kasporov</lastName>
<department>
<id>110</id>
<name>IT</name>
</department>
</employee>
</employees>
1.2 XPath 属性表达式示例
现在来看几个有关如何构建 xpath 以便基于属性获取信息的示例。
描述 | XPath | 结果 |
---|---|---|
获取所有员工 ID | /employees/employee/@id |
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
获取人力资源部门的所有员工 ID | /employees/employee[department/name='HR']/@id |
[2, 4, 8] |
获取员工编号“ Alex” | /employees/employee[firstName='Alex']/@id |
[3] |
获取大于 5 的员工 ID | /employees/employee/@id[. > 5] |
[6, 7, 8, 9, 10] |
获取其 ID 包含“1”的员工 | /employees/employee[contains(@id,'1')]/firstName/text() |
[Lokesh, Gary] |
获取其 ID 包含 1 的员工 | descendant-or-self::*[contains(@id,'1')]/firstName/text() |
[Lokesh, Gary] |
2. 使用 xpath 查找具有属性值的 xml 元素的 Java 示例
我们来看一下用于求值以上 xpath 表达式以选择具有特定属性值的节点的代码。
2.1 XPath 求值示例
要在 Java 中求值 xpath,您需要执行以下步骤:
- 将 XML 文件读取到
org.w3c.dom.Document
中。 - 使用其
newInstance()
静态方法创建XPathFactory
。 - 从
XPathFactory
获取XPath
实例。 该对象提供对 xpath 求值环境和表达式的访问。 - 创建 xpath 表达式字符串。 使用
xpath.compile()
方法将 xpath 字符串转换为XPathExpression
对象。 - 针对第一步中创建的文档实例求值 xpath。 它将返回文档中的 DOM 节点列表。
- 使用
getNodeValue()
方法迭代节点并获得测试值。
XPath 表达式不是线程安全的。 确保在任何给定时间不从多个线程使用一个
XPathExpression
对象是应用的责任,并且在调用求值方法时,应用可能不会递归调用求值方法。
package com.howtodoinjava.demo;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XPathExample
{
public static void main(String[] args) throws Exception
{
//Get DOM Node for XML
String fileName= "employees.xml";
Document document = getDocument(fileName);
String xpathExpression = "";
/*******Get attribute values using xpath******/
//Get all employee ids
xpathExpression = "/employees/employee/@id";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get all employee ids in HR department
xpathExpression = "/employees/employee[department/name='HR']/@id";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee id of 'Alex'
xpathExpression = "/employees/employee[firstName='Alex']/@id";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee ids greater than 5
xpathExpression = "/employees/employee/@id[. > 5]";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee whose id contains 1
xpathExpression = "/employees/employee[contains(@id,'1')]/firstName/text()";
System.out.println( evaluateXPath(document, xpathExpression) );
//Get employee whose id contains 1
xpathExpression = "descendant-or-self::*[contains(@id,'1')]/firstName/text()";
System.out.println( evaluateXPath(document, xpathExpression) );
}
private static List<String> evaluateXPath(Document document, String xpathExpression) throws Exception
{
// Create XPathFactory object
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
List<String> values = new ArrayList<>();
try
{
// Create XPathExpression object
XPathExpression expr = xpath.compile(xpathExpression);
// Evaluate expression result on XML document
NodeList nodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
values.add(nodes.item(i).getNodeValue());
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return values;
}
private static Document getDocument(String fileName) throws Exception
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fileName);
return doc;
}
}
程序输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[2, 4, 8]
[3]
[6, 7, 8, 9, 10]
[Lokesh, Gary]
[Lokesh, Gary]
2.2 模型类
@XmlRootElement(name="employees")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employees implements Serializable
{
private static final long serialVersionUID = 1L;
@XmlElement(name="employee")
private List<Employee> employees;
public List<Employee> getEmployees() {
if(employees == null) {
employees = new ArrayList<Employee>();
}
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Employees [employees=" + employees + "]";
}
}
@XmlRootElement(name="employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@XmlAttribute
private Integer id;
private String firstName;
private String lastName;
private Department department;
public Employee() {
super();
}
public Employee(int id, String fName, String lName, Department department) {
super();
this.id = id;
this.firstName = fName;
this.lastName = lName;
this.department = department;
}
//Setters and Getters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", department="
+ department + "]";
}
}
@XmlRootElement(name="department")
@XmlAccessorType(XmlAccessType.FIELD)
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
Integer id;
String name;
public Department() {
super();
}
public Department(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
//Setters and Getters
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
向我提供有关如何使用 xpath 查找具有属性值的 xml 元素的问题。
学习愉快!
Java XPath – 检查节点或属性是否存在?
原文: https://howtodoinjava.com/xml/xpath-check-if-xml-tag-exists/
Java 示例使用 XPath 检查给定 XML 内容中的节点是否存在或检查 XML 中的属性是否存在。
1.如何检查 xml 节点是否存在?
要验证 XML 内容中是否存在节点或标记,您可以针对该 XML 的 DOM 文档执行 xpath 表达式,并计算匹配的节点。
matching nodes > zero
– XML 标记/属性存在。matching nodes <= zero
– XML 标记/属性不存在。
1.1 XML 文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
<employee id="1">
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<department>
<id>101</id>
<name>IT</name>
</department>
</employee>
<employee id="2">
<firstName>Brian</firstName>
<lastName>Schultz</lastName>
<department>
<id>102</id>
<name>HR</name>
</department>
</employee>
</employees>
1.2 使用 XPath 计数 XML 标签以检查是否存在
package com.howtodoinjava.demo;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XPathExample {
public static void main(String[] args) throws Exception {
// Get DOM Node for XML
String fileName = "employees.xml";
Document document = getDocument(fileName);
String xpathExpression = "";
// Get all employee names
xpathExpression = "/employees/employee/firstName";
System.out.println(checkIfNodeExists(document, xpathExpression)); //true
// Get all employee ids
xpathExpression = "/employees/employee/@id";
System.out.println(checkIfNodeExists(document, xpathExpression)); //true
// Get all employee age
xpathExpression = "/employees/employee/@age";
System.out.println(checkIfNodeExists(document, xpathExpression)); //false
// Get all department names
xpathExpression = "/employees/employee/department/name";
System.out.println(checkIfNodeExists(document, xpathExpression)); //true
// Get department locations
xpathExpression = "/employees/employee/department/location";
System.out.println(checkIfNodeExists(document, xpathExpression)); //false
}
private static boolean checkIfNodeExists(Document document, String xpathExpression) throws Exception
{
boolean matches = false;
// Create XPathFactory object
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
try {
// Create XPathExpression object
XPathExpression expr = xpath.compile(xpathExpression);
// Evaluate expression result on XML document
NodeList nodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
if(nodes != null && nodes.getLength() > 0) {
matches = true;
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return matches;
}
private static Document getDocument(String fileName) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fileName);
return doc;
}
}
程序输出:
true
true
false
true
false
阅读更多: Xpath 示例
学习愉快!
Eclipse 教程
在 Eclipse 中导入 Maven 远程原型目录
原文: https://howtodoinjava.com/eclipse/how-to-import-maven-remote-archetype-catalogs-in-eclipse/
本教程为在 Eclipse 中导入 Maven 远程原型目录提供了简单的说明,以使您在配置项目时获得领先。 使用原型自动导入所有基本的运行时依赖项,并使用最基本的配置来配置项目,您可以在数分钟内直接将其直接用于构建 helloworld 应用。
第 1 步:在 Eclipse 中打开 Maven 首选项
转到“Windows -> Preferences -> Maven -> Archetypes”。
Eclipse 中的 Maven 原型选项
步骤 2:添加远程目录文件
单击添加远程目录按钮。 将目录文件填写为“http://repo1.maven.org/maven2/archetype-catalog.xml
”和一些自定义描述。
填写原型网址和名称
单击确定按钮。 大功告成
步骤 3:验证远程原型
为了验证您现在可以访问所有原型,请创建一个新的 maven 项目。
选择您创建的新的自定义目录。
Jersey 远程原型
第一次,将花费一些时间来收集所有原型。 您可以在 IDE 的右下角看到进度。 完成后,您应该可以看到原型
填写项目的组 ID 和工件 ID。
填写组 ID 和工件 ID
单击确定以创建项目。 您将在工作区上看到已完成所有依赖关系和基本配置的新项目创建。
具有自动配置的新 Maven 项目
如果您在任何步骤中遇到任何问题,请随时向我提问。
祝您学习愉快!
使用 Eclipse 快速搜索插件进行更快的文本搜索
原文: https://howtodoinjava.com/eclipse/use-eclipse-quick-search-plugin-for-faster-text-searches/
昨天,我遇到了很好的 eclipse 插件,用于在 Eclipse 工作区中进行文本搜索。 你们中的一些人可能已经意识到了这一点,但是对于那些尚不了解的人,请继续安装此插件,并提高您的开发技能的速度。
eclipse 快速搜索插件是 Spring 工具套件(STS)的一部分。 因此,如果您在 Eclipse 中安装了 STS,那么很可能已经安装了它。
安装 Eclipse 快速搜索
1)要安装 eclipse 快速搜索,请转到您拥有的 Eclipse 版本的 STS 版本。 快速的 Google 搜索可以将您定向到那里。 例如,我的开发机器上已经使用了 Eclipse Luna,所以我通过此链接使用 STS。
http://marketplace.eclipse.org/content/spring-tool-suite-sts-eclipse-luna-44
2)现在,将安装按钮拖到 Eclipse 工作区,它将打开一个窗口,以帮助您进行进一步的安装。 (在某些版本中,安装可能从后端开始)。
3)现在,从可用功能列表中选择快速搜索功能并安装它。
4)您可能需要重新启动 Eclipse。 重新启动。 现在按命令 CTRL + SHIFT + L
打开快速搜索编辑器。
祝您学习愉快!
HornetQ 单体 – 基本的 JMS 消息传递示例
原文: https://howtodoinjava.com/hornetq/basic-jms-messaging-example-using-hornetq-stand-alone-server/
HornetQ 是一个开放源代码项目,旨在构建多协议,可嵌入,非常高性能的集群异步消息传递系统。 HornetQ 支持 JMS 1.1 API,并且还定义了自己的消息传递 API,以实现最佳性能和灵活性。 HornetQ 一流的高性能日志以非持久消息传递通常看到的速度提供持久消息传递性能。 HornetQ 提供服务器复制和自动客户端故障转移功能,以消除服务器故障时丢失或重复的消息。
在上一篇文章中,我们了解了有关配置独立 hornetq 服务器和基本配置的信息。 让我们继续举例。
在本文中,我们将学习将 JMS 消息发送到 hornetq 服务器上的队列的机制,然后检索这些消息。
步骤 1)使用以下命令创建一个 maven 项目并将其转换为 Eclipse Java 项目
mvn archetype:generate -DgroupId=com.howtodoinjava -DartifactId=HornetQHelloWorld
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
cd HornetQHelloWorld
mvn eclipse:eclipse
步骤 2)更新pom.xml
文件并更新项目依赖项
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.howtodoinjava</groupId>
<artifactId>HornetQHelloWorld</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>HornetQHelloWorld</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-core</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-logging</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-transports</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
<version>3.1.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.javaee</groupId>
<artifactId>jboss-jms-api</artifactId>
<version>1.1.0.GA</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
步骤 3)将基本的 hornetq 配置文件放在类路径中。
hornetq-configuration.xml
<?xml version="1.0"?>
<configuration xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hornetq">
<connectors>
<connector name="netty-connector">
<factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory
</factory-class>
</connector>
</connectors>
<acceptors>
<acceptor name="netty-acceptor">
<factory-class>org.hornetq.integration.transports.netty.NettyAcceptorFactory
</factory-class>
</acceptor>
</acceptors>
<security-enabled>false</security-enabled>
</configuration>
步骤 4)配置连接器工厂,并将配置文件放置在classpath
中。
hornetq-jms.xml
<?xml version="1.0"?>
<configuration xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hornetq">
<!--the connection factory used by the example -->
<connection-factory name="ConnectionFactory">
<connectors>
<connector-ref connector-name="netty-connector" />
</connectors>
<entries>
<entry name="ConnectionFactory" />
</entries>
</connection-factory>
<queue name="exampleQueue">
<entry name="exampleQueue" />
</queue>
</configuration>
步骤 5)启动服务器并测试消息传递代码
HornetQMessageQueueDemo.java
package com.howtodoinjava;
import java.util.HashMap;
import java.util.Map;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.hornetq.api.core.TransportConfiguration;
import org.hornetq.api.jms.HornetQJMSClient;
import org.hornetq.core.config.impl.FileConfiguration;
import org.hornetq.core.server.HornetQServer;
import org.hornetq.core.server.HornetQServers;
import org.hornetq.integration.transports.netty.NettyConnectorFactory;
import org.hornetq.integration.transports.netty.TransportConstants;
import org.hornetq.jms.server.JMSServerManager;
import org.hornetq.jms.server.impl.JMSServerManagerImpl;
public class HornetQMessageQueueDemo {
static void startServer()
{
try
{
FileConfiguration configuration = new FileConfiguration();
configuration.setConfigurationUrl("hornetq-configuration.xml");
configuration.start();
HornetQServer server = HornetQServers.newHornetQServer(configuration);
JMSServerManager jmsServerManager = new JMSServerManagerImpl(server, "hornetq-jms.xml");
//if you want to use JNDI, simple inject a context here or don't call this method and make sure the JNDI parameters are set.
jmsServerManager.setContext(null);
jmsServerManager.start();
System.out.println("Server started !!");
}
catch (Throwable e)
{
System.out.println("Damn it !!");
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception
{
//Start the server
startServer();
Connection connection = null;
try
{
// Step 1\. Directly instantiate the JMS Queue object.
Queue queue = HornetQJMSClient.createQueue("exampleQueue");
// Step 2\. Instantiate the TransportConfiguration object which
// contains the knowledge of what transport to use,
// The server port etc.
Map<String, Object> connectionParams = new HashMap<String, Object>();
connectionParams.put(TransportConstants.PORT_PROP_NAME, 5445);
TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), connectionParams);
// Step 3 Directly instantiate the JMS ConnectionFactory object
// using that TransportConfiguration
ConnectionFactory cf = HornetQJMSClient.createConnectionFactory(transportConfiguration);
// Step 4.Create a JMS Connection
connection = cf.createConnection();
// Step 5\. Create a JMS Session
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
// Step 6\. Create a JMS Message Producer
MessageProducer producer = session.createProducer(queue);
// Step 7\. Create a Text Message
TextMessage message = session.createTextMessage("How to do in java dot com");
System.out.println("Sent message: " + message.getText());
// Step 8\. Send the Message
producer.send(message);
// Step 9\. Create a JMS Message Consumer
MessageConsumer messageConsumer = session.createConsumer(queue);
// Step 10\. Start the Connection
connection.start();
// Step 11\. Receive the message
TextMessage messageReceived = (TextMessage) messageConsumer.receive(5000);
System.out.println("Received message: " + messageReceived.getText());
}
finally
{
if (connection != null) {
connection.close();
}
}
}
}
Output in console:
22 Mar, 2013 2:23:36 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: live server is starting..
22 Mar, 2013 2:23:36 PM org.hornetq.core.logging.impl.JULLogDelegate warn
WARNING: AIO wasn't located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO to enable the AIO journal
22 Mar, 2013 2:23:36 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: Using NIO Journal
22 Mar, 2013 2:23:36 PM org.hornetq.core.logging.impl.JULLogDelegate warn
WARNING: Security risk! It has been detected that the cluster admin user and password have not been changed from the installation default. Please see the HornetQ user guide, cluster chapter, for instructions on how to do this.
22 Mar, 2013 2:23:36 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: Started Netty Acceptor version 3.1.5.GA-r1772
Server started !!
22 Mar, 2013 2:23:36 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: HornetQ Server version 2.0.0.GA (Hornet Queen, 113) started
Sent message: How to do in java dot com
Received message: How to do in java dot com
祝您学习愉快!
如何在 Eclipse 中显示非英文 unicode(例如中文)字符
如果您不是讲英语的国家/地区的原住民,并且正在针对您的语言环境测试应用,则可能会难以通过 Eclipse 控制台测试应用。 默认情况下,Eclipse 会将非英语字符转换为问号(?
)或一些奇怪的字符,因为默认情况下 eclipse 的控制台编码为 CP1252 或 ASCII,它们无法显示其他非英语单词。
通过设置以下选项,您可以轻松地将默认编码更改为 UTF-8,即 Unicode。
将 Eclipse 默认编码更改为 unicode
现在,当您在 IDE 中使用任何非英语字符甚至在控制台中进行打印时,它都可以完美工作。
成功的 Eclipse Unicode 转换
在这里,如果不添加 Unicode 支持,则上述程序将如下所示。
不正确的 Eclipse Unicode 转换
如果要一直将 Unicode UTF-8 应用到所有项目,则应在eclipse.ini
文件中进行设置。
-Dfile.encoding=UTF-8
如果有不清楚的地方,请给我留言。
祝您学习愉快!
如何在 Eclipse 中增加控制台输出限制
原文: https://howtodoinjava.com/eclipse/how-to-increase-console-output-limit-in-eclipse/
通常,当我们尝试使用 Eclipse 调试器调试关键问题时,我们需要查看控制台输出。 但是,如果您将日志记录级别设置为“调试”,则应用会将大量日志语句转储到控制台中。 很多时候,日志语句只是在此日志语句转储中丢失了。
您可以通过在控制台中通过增加日志语句的限制来简单地解决此问题,或者简单地将所有限制都一起删除。 可以在 Eclipse 中进行以下设置来完成此设置:
1)转到“窗口 -> 首选项 -> 运行/调试 -> 控制台”
2)增加控制台缓冲区的大小
2)或直接取消选中“限制控制台输出”
增加 Eclipse 中的控制台输出限制
就这样。 您将有更多的垃圾箱来调查您的问题。
祝您学习愉快!
创建 Eclipse 模板以加快 Java 编程
原文: https://howtodoinjava.com/eclipse/create-eclipse-templates-for-faster-java-coding/
我们大多数使用 Eclipse IDE 编写代码的人,都必须使用main
或sysout
之类的快捷方式,然后点击CTRL+SPACE
,它将快捷方式转换为public static void main(String[] args){…}
和System.out.println()
。 这是一项非常有用的功能,每当我为项目或教程编写代码时,我就一直使用它。
好消息是,您也可以在此列表中添加自己的模板,并利用此功能。 例如,解析作为参数传递的 XML 字符串是非常普遍的要求。 解析此类 XML 字符串的代码始终几乎相同。 我们可以为其创建模板,然后在需要时使用其快捷方式。
如何创建新的 Eclipse 模板
要创建 XML 字符串解析的快捷方式,请按照以下步骤操作:
1)通过转到“Windows -> 首选项”打开“首选项”对话框
2)在左侧导航树上,转到“Java -> 编辑器 -> 模板”
3)预定义模板
Eclipse 预定义模板
4)按下“New…”按钮添加新模板。
5)填写以下模板信息并保存
建立新模板
6)使用CTRL + SPACE
在任何 Java 源文件中使用模板
使用模板快捷方式
7)按下Enter
,它将生成下面的代码。 请享用 !!
代替快捷方式的插入代码
您会看到它很有用。 现在,让我们记下一些可以直接使用的代码模板。
有用的 Eclipse 模板示例
1)IO 模板文件
以下模板对于读取或写入文件很有用。 他们使用 Java7 功能(如try-with-resources
)自动关闭文件。 他们还使用 NIO2.0 中的方法来获取缓冲的读取器并读取文件。
a)从文件中读取文本
${:import(java.nio.file.Files,
java.nio.file.Paths,
java.nio.charset.Charset,
java.io.IOException,
java.io.BufferedReader)}
try (BufferedReader in = Files.newBufferedReader(Paths.get(${fileName:var(String)}),
Charset.forName("UTF-8"))) {
String line = null;
while ((line = in.readLine()) != null) {
${cursor}
}
} catch (IOException e) {
// ${todo}: handle exception
}
b)从列表中的文件中读取所有行
${:import(java.nio.file.Files,
java.nio.file.Paths,
java.nio.charset.Charset,
java.util.List,
java.util.ArrayList)}
Lis<String> lines = new ArrayList<>();
try{
lines = Files.readAllLines(Paths.get(${fileName:var(String)}),
Charset.forName("UTF-8"));
}catch (IOException e) {
// ${todo}: handle exception
}
${cursor}
c)写入文件
${:import(java.nio.file.Files,
java.nio.file.Paths,
java.nio.Charset,
java.io.IOException,
java.io.BufferedWriter)}
try (BufferedWriter out = Files.newBufferedWriter(Paths.get(${fileName:var(String)}),
Charset.forName("UTF-8"))) {
out.write(${string:var(String)});
out.newLine();
${cursor}
} catch (IOException e) {
// ${todo}: handle exception
}
2)XML I/O 模板
以下模板用于读取 xml 文件或字符串并返回 DOM。
a)将 XML 文件解析为文档
${:import(org.w3c.dom.Document,
javax.xml.parsers.DocumentBuilderFactory,
java.io.File,
java.io.IOException,
javax.xml.parsers.ParserConfigurationException,
org.xml.sax.SAXException)}
Document doc = null;
try {
doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new File(${filename:var(String)}));
} catch (SAXException | IOException | ParserConfigurationException e) {
// ${todo}: handle exception
}
${cursor}
b)将 XML 字符串解析为文档
${:import(org.w3c.dom.Document,
javax.xml.parsers.DocumentBuilderFactory,
org.xml.sax.InputSource,
java.io.StringReader,
java.io.IOException,
javax.xml.parsers.ParserConfigurationException,
org.xml.sax.SAXException)}
Document doc = null;
try {
doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new InputSource(new StringReader(${str:var(String)})));
} catch (SAXException | IOException | ParserConfigurationException e) {
// ${todo}: handle exception
}
${cursor}
3)日志模板
以下模板对于创建记录器和记录消息很有用。 我使用的是 SLF4J,但是可以很容易地对其进行调整,以使用任何其他日志记录框架。
a)创建一个新的记录器
${:import(org.slf4j.Logger,
org.slf4j.LoggerFactory)}
private static final Logger LOGGER = LoggerFactory.getLogger(${enclosing_type}.class);
b)在放置调试日志之前检查调试范围
if(LOGGER.isDebugEnabled())
LOGGER.debug(${word_selection}${});
${cursor}
c)日志信息级别声明
LOGGER.info(${word_selection}${});
${cursor}
d)记录错误
LOGGER.error(${word_selection}${}, ${exception_variable_name});
e)记录错误并引发异常
LOGGER.error(${word_selection}${}, ${exception_variable_name});
throw ${exception_variable_name};
${cursor}
4)JUNIT 模板
a)Junit 的之前方法
${:import (org.junit.Before)}
@Before
public void setUp() {
${cursor}
}
b)Junit 的之后方法
${:import (org.junit.After)}
@After
public void tearDown() {
${cursor}
}
c)Junit 的之前类
${:import (org.junit.BeforeClass)}
@BeforeClass
public static void oneTimeSetUp() {
// one-time initialization code
${cursor}
}
d)Junit 的之后类
${:import (org.junit.AfterClass)}
@AfterClass
public static void oneTimeTearDown() {
// one-time cleanup code
${cursor}
}
请注意,可以为其他文件类型(例如 XML,JSP 等)定义这些模板。在给定的链接中可以找到更多模板:
http://stackoverflow.com/questions/1028858/useful-eclipse-java-code-templates
http://eclipse.dzone.com/news/effective-eclipse-custom-templ
祝您学习愉快!
在 5 分钟内使 Eclipse 更快
原文: https://howtodoinjava.com/eclipse/how-to-quickly-make-eclipse-faster/
一旦我们开始进行 Eclipse 工作,它就会逐渐变慢。 为了提高性能并加快食蚀的速度,可以使用某些方法来查看明显的差异。 这些有效的方法如下:
1) Clean up history and indexes
2) Remove structured text validation
3) Do not use subclipse plugin
4) Configure appropriate start-up arguments
让我们一一详细了解它们:
1)清理历史和索引
清理历史记录和索引可以减少 RAM 上的负载以及整体 HDD 的使用。 这会对性能产生很大的影响。 要删除索引和历史记录文件夹,请清除以下两个文件夹中的所有文件/文件夹:
用于清理索引
{workspace path}\.metadata\.plugins\org.eclipse.jdt.core
用于清除历史记录
{workspace path}\.metadata\.plugins\org.eclipse.core.resources\.history
这里{workspace path}
是您在其中创建所有项目的 Eclipse 工作区的路径。
请注意,从两个文件夹上方删除文件不会以任何方式影响您的任何项目源代码。
2)删除结构化文本验证
这也产生了很大的影响。 这里的验证必定意味着 eclipse 在后台会对源代码文件执行多项操作以检查其有效性。 这些有时有时也不必要并且令人讨厌。 我参与了一些由许多 XML/XSLT 和 WSDL 文件组成的项目,并且其中一些文件总是显示一些危险信号。 但是他们实际上在大多数情况下在运行时都产生了问题,即使这实际上也是正确的处理方式。
您可以关闭这些验证(对于您认为不必要的所有类型),并享受 Eclipse。
要关闭这些文本验证,请打开“Windows -> 首选项”,然后在搜索栏中键入“验证”。 它将列出所有文件类型并对其进行验证。 禁用任何您认为不必要的东西。 然后单击“确定”。
3)不要使用 subclipse 插件
该技术确实有效,但难以遵循。 它说您应该只在 eclipse 中使用代码来编写/修改和执行。 与 SVN/perforce 或任何代码仓库相关的所有其他事情都应在 eclipse 之外完成。 这可以来自命令行工具或任何可视客户端。
Subversion 插件占用了过多的系统资源,严重影响了 Eclipse 的性能。
即使您确实想使用它,也可以通过子剪辑仅检出部分代码,并将其余代码导入为外部项目。 它也将为您提供帮助。
4)配置适当的启动参数
在您的eclipse.ini
文件(位于 Eclipse 安装文件夹中)中,根据需要更改默认的-Xms40m -Xmx256m
参数。 此选项定义传递给 Java 虚拟内存以管理 Eclipse 应用的内存分配容限的最小和最大内存使用范围。 您不应将它们设置为最大可用,因为您需要并行运行其他软件。
您应该尝试使用-Xms
和-Xmx
选项的不同组合,然后确定哪一种最适合您,并使 Eclipse 最快。
示例配置如下所示:
-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20120522-1813
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Dhelp.lucene.tokenizer=standard
-Xms256m
-Xmx1024m
温馨提示:在eclipse.ini
中使用-Xverify:none
,-Xquickstart
和 -server
或-client
-Xquickstart
您可以使用-Xquickstart
进行初始编译,而优化级别要比默认模式低。 以后,根据采样结果,您可以在默认模式下重新编译为初始编译的级别。 对于早期中等速度比长期吞吐量更重要的应用,请使用-Xquickstart
。 在某些调试方案,测试工具和短期运行的工具中,您可以将启动时间缩短 15% 至 20%。
-Xverify:none
如果要在类加载期间跳过类验证阶段,可以使用-Xverify:none
。 使用-Xverify:none
将禁用 Java 类验证,这可以将启动时间缩短 10-15%。 但是,指定此选项时,不会检测到损坏或无效的类数据。 如果加载了损坏的类数据,则 Java 虚拟机(JVM)可能会以意外的方式运行,或者 JVM 可能会失败。 但这只有在您自己修改字节码时才会发生。
-server
或-client
基于 Sun 的 Java 开发工具包(JDK)1.4.2 版中的 Java HotSpot 技术引入了一种自适应 JVM,其中包含用于随着时间的推移优化字节代码执行的算法。 JVM 以两种模式运行-server
和-client
。 如果使用默认的-client
模式,将有更快的启动时间和较小的内存占用,但扩展性能较低。 如果允许 HotSpot JVM 通过连续执行字节代码来预热足够的时间,则可以使用-server
模式来提高性能。 在大多数情况下,请使用-server
模式,该模式可在更长的时间内产生更有效的运行时执行。 您可以监视进程大小和服务器启动时间,以检查-client
和-server
之间的差异。
现在就这样。 如果您知道除上述技术以外的任何其他技术,请与我们分享。
祝您学习愉快!
如何在印地语中编译和运行 Java 程序
原文: https://howtodoinjava.com/eclipse/how-to-compile-and-run-java-program-written-in-another-language/
我们都知道如何编写 Java 程序。 我们也使用英语来做到这一点。 今天,我尝试使用 eclipse 用印地语编写 Java 程序,然后执行它。
印地语中的 Java 程序
让我们看看如何做到这一点。 以下是可以使用任何语言翻译器轻松编写的代码示例。
package runtime;
public class DemoHindiProgram {
public static void main(String... s) {
java.util.Locale हिन्दी = new java.util.Locale("hi", "IN");
int लंबाई = 20;
int चौड़ाई = 10;
int क्षेत्रफल;
क्षेत्रफल = लंबाई * चौड़ाई;
System.out.printf(हिन्दी, "%dn", क्षेत्रफल);
}
}
2.问题
实际问题始于在 eclipse 插件中复制以上代码时。 一旦您在 eclipse 中复制了以上代码,它就会开始报错各种编译问题。
这些问题基本上是由于 Eclipse 中的默认字符编码为“CP1252”。 我们需要改变这一点。
3.解决方案 – 更改 Eclipse 默认编码
可以从以下位置更改此默认编码:“File -> Properties”。 将其更改为 UTF-8。
现在创建一个名为“DemoHindiProgram.java
”的类。
该文件不会有编译问题,如果您通过“右键单击 -> 以 Java 程序运行”来执行上述程序,您将能够在控制台输出中看到输出为“200” 。
有趣的事实是,控制台输出也使用印地语字母。
学习愉快!
Java 覆盖最终静态方法 – 方法是覆盖还是隐藏?
我们可以覆盖 Java 中的静态方法吗? 好吧,我们所有人都知道方法覆盖和方法隐藏。 您是否尝试过覆盖静态方法,特别是在父类中方法为final
时。
覆盖最终静态方法的 Java 程序
下面是我编写的用于测试各种关键字组合的程序。 因此,请参考该程序进行进一步的讨论。
package staticTest;
class SuperClass {
static void display() {
System.out.println("Super");
}
}
class SubClass extends SuperClass {
static void display() {
System.out.println("Sub");
}
}
public class Test {
public static void main(String[] args) {
// Prints "Super" in console
SuperClass sup = new SubClass();
sup.display();
// Prints "Sub" in console
SubClass sub = new SubClass();
sub.display();
}
}
是方法覆盖还是方法隐藏?
-
上面的代码将成功编译,而不会发出警告或错误。 方法隐藏就是这种情况,子类的静态方法从超类隐藏了静态方法。
-
如果我们从子类的显示方法中删除
static
关键字,则编译器会报错您无法覆盖超类的静态方法。众所周知,静态方法不能被覆盖。 它们只能从子类中隐藏。 因此,这种情况下的编译器消息应被认为是错误的。 正确消息应该为“实例方法无法从超类“隐藏”静态方法”。
现在在上面的代码示例中,将final
添加到超类的显示方法中。 再次,编译器开始报错“无法从超类覆盖最终方法”。
由于上述原因,这也会产生误导。 在这里,正确的消息也应该是“无法隐藏超类的最终方法”
总结
为什么在 Java 中不能覆盖静态方法? 以我的观点,方法覆盖仅在我们使用实例方法进行讨论时才有效。 一旦我们开始谈论静态方法,就应该使用隐藏的方法。
幸运的是,以上术语已在大多数 Java 文献中使用(甚至在 Java 语言规范中也是如此),但我想仍然必须对其进行更新。
请让我知道您对 Java 覆盖最终静态方法的想法,为什么在 Java 中不能覆盖静态方法,而在 Java 中我们可以覆盖非静态方法呢?
学习愉快!
[已解决] 在 Eclipse 的 Java 构建路径中找不到超类“javax.servlet.http.HttpServlet
”
如果将现有的 maven 项目导入 eclipse IDE 后遇到此错误,则表明该项目的类路径中没有http-servlet
,因此必须将其包括在内。
错误看起来像这样。
Java 构建路径错误
解决方案
要将http-servlet
包含到类路径中,您有两个选择:
1)添加目标运行时
在此解决方案中,您可以将所需的服务器运行时作为项目构面添加到您的应用中。 由于运行时服务器已经具有 servlet 运行时相关性,因此它们已包含在您的项目中,因此错误消失了。
2)添加 Maven 依赖
另一个选择是通过 maven 本身包括 servlet 依赖关系。 这也将修复错误。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
祝您学习愉快!
版本控制系统教程
分布式版本控制系统如何工作?
原文: https://howtodoinjava.com/vcs/how-distributed-version-control-system-works/
在上一篇文章中,我们对集中式版本控制系统进行了介绍。 在这篇文章中,我将向您介绍“分布式版本控制系统”。
与集中式 VCS 不同,在集中式 VCS 中,所有繁重的工作都在服务器端完成,并作为所有操作的单点操作,而客户端仅拥有代码库的工作副本。 在分布式 VCS 中,每个客户端(称为协作者)都有自己的本地仓库,大部分将在其本地仓库上工作。
分布式版本控制系统如何工作?
颠倒中央 VCS 的整个方法,每个协作者将在其本地计算机上拥有完整的仓库,即完整的修订历史记录,所有分支,标签,提交信息都存在于本地计算机上。 我们没有中央服务器的概念,但是我们可以将任何仓库配置为中央仓库,以将其视为真相来源并与 Jenkins,Chef 之类的构建和部署工具集成。
下面是不同协作者如何与分布式版本控制系统一起工作的框图。
分布式 VCS
从上图可以看出,与传统的 VCS 不同,在分布式 VCS 中,我们的协作者在分散式系统中与其他协作者一起工作。
在分布式 VCS 中,客户不仅仅签出文件的最新快照,还需要查看文件的最新快照。 而是完全镜像仓库。 因此,如果有任何服务器故障,并且这些系统通过它进行协作,则可以将任何客户端存储库复制回服务器以恢复该服务器。 每个克隆实际上都是所有数据的完整备份。
另请注意,分布式 VCS 中使用的术语不同于集中式 VCS。 我们在中央 VCS 中使用“检出”和“提交”的地方; 在分布式 VCS 中,我们使用“推”和“拉”。
- 推送:将更改发送到另一个仓库(可能需要许可)
- 拉取:从仓库中获取更改
有很多分布式版本控制系统,例如 Git , Mercurial 等。在即将发布的系列文章中,我将介绍 Git 并将 每当提到“分布式版本控制系统”时,都指的是 Git。
分布式版本控制系统的优点
让我们看看这种方法相对于传统/集中版本控制系统的优势。
快速
每个协作者都将代码库签出到其本地仓库中并在本地仓库上工作。 因此,由于不会有网络呼叫任何服务器,因此所有操作将很快进行。
低成本的分支和合并
由于代码库位于本地硬盘上,因此创建分支和合并非常简单容易。 这是强大的功能之一,因为如果使用集中式仓库,则使用分支和合并太复杂了。
本地分支
开发人员可以创建尽可能多的本地分支并在分支上工作,然后将其合并回主分支。 合并完成后,可以安全地删除本地分支。 此处最大的优势是,与集中式 VCS 不同,该分支对其他人将不可见,在集中式 VCS 中,所有分支都驻留在一台服务器上,并且在处理大型项目时会造成很多混乱。
快照而不是差异
这是主要好处之一。 我们可以为执行的每个提交获取完整的代码仓库。 因此,与中央 VCS 一样,我们可以轻松地恢复到任何提交,而无需手动应用来自基本版本的更改。
简单而高效的工具
一旦开发人员对核心概念和功能了如指掌,开发人员将变得更有生产力。 开发人员还可以采用模块化方式提交代码,并与其他开发人员进行协作,而不会影响其他开发人员的工作区。
可扩展
与“集中式 VCS”相比,“分布式 VCS”具有高度可扩展性,尤其是在开源项目中,该项目中数百万开发人员做出了贡献,而传统的版本控制系统无法完成这项任务。
开源
Git 是开源的,免费的。 此外,开发人员可以在各种平台(如 Github)上从事开源项目。
分布式版本控制系统的缺点
现在,让我们看看分布式版本控制系统的一些缺点。
陡峭的学习曲线
学习 Git 将经历一些陡峭的学习过程,并且对于来自其他传统 VCS 工具的开发人员而言,通常会感到困惑和沮丧。 但是,一旦理解了核心概念,就可以与之合作。
支持工具和 IDE
尽管有很多工具和插件可以与 IDE 集成,但与 SVN 或 perforce 相比,它们并不多。 虽然 git bash 是一种流行的工具,如果它来自 unix 背景,可以利用。
在下一篇文章中,让我们进一步了解 Git 基础知识。
关于作者:
以上文章由该博客的其中一位读者 Pradeep Kumar(@pradeepkumarl)提供。 他是一位拥有 10 多年经验的软件开发人员,并且曾使用过各种版本控制工具,例如 SVN,Perforce,ClearCase 和 Git。 他对技术充满热情,并热爱教技术。 您可以在 Git – 新手到专家上查看他的在线课程之一。
祝您学习愉快!
版本控制系统(VCS)如何工作?
原文: https://howtodoinjava.com/vcs/how-version-control-system-vcs-works/
如果您是开发人员或正在测试,则必须使用源代码仓库(也称为版本控制系统)。 您可能使用过 CVS,SVN 和 Perforce 等。在本文中,我将带您了解版本控制系统的基础,这将有助于我们了解传统版本控制系统的主要优缺点。
传统 VCS 的工作原理
传统的 VCS 具有集中式服务器,该服务器充当源代码仓库。 除了存储代码外,这些工具还维护每次提交的修订历史记录。
在下图中,我们有 3 个文件 A,B 和 C。 项目更改以四个方面提交,即初始提交,第二,第三和第四次提交。
当在第二次提交中对文件 A 和 C 进行更改时,仅差异或增量更改将应用于初始文件并存储。 类似地,当在第三次提交中对 B 和 C 文件的顶部执行另一次更改时,仅将 B 和 C 的增量更改存储为提交的一部分。
请注意,在任何给定的时间点,如果我们要获取整个代码库的当前状态,将无法获得,因为对于给定的提交,我们只能获得与上次文件更改相比的增量变化。 承诺。
例如,当我们比较两个提交时,我们仅获得具有更改的文件,并且可以看到对文件所做的实际更改,我们将其称为增量。
您绝对可以要求一个文件的某些先前版本,但是您不能要求整个工作区在几次提交之前是什么。 如果要查看工作区如何查看给定的提交,则必须采用基本版本和路径,其中所有提交都已完成,直到达到所需的提交为止。 因此,您将只能获得最新版本。 或基本修订。 因此,VCS 仅存储差异。
传统 VCS 的优势
- 所有源代码都安全地存储在中央服务器上的安全位置。
- 如果由于系统或硬盘崩溃而导致本地计算机上的源代码丢失,那么从 VCS 中获取代码可以还原该源代码。
- 可以在 VCS 上进行认证和授权。
- VCS 负责管理版本控制,并且如果存在任何冲突,将不允许提交。
- 维护提交日志以获取开发人员的提交信息。
让我们也介绍一下这种方法的一些缺点。
传统 VCS 的缺点
由于 VCS 驻留在服务器上,并且在托管代码,对文件进行版本控制,维护提交日志信息方面承担了所有繁重的工作,因此客户端仅被限制为获取代码的最新副本并工作,最后将所做的更改提交给客户端。 VCS。 客户端计算机上的代码仅仅是工作副本,而不是整个仓库本身。 现在让我们看看这种方法的主要缺点。 让我借助示例进行解释。
- 假设有 5 个开发人员正在使用 VCS,并且他们都使用功能并将更改提交到仓库。 不幸的是,VCS 崩溃,并且没有备份。 我们剩下的是使用最后一次稳定的提交来还原 VCS。 现在,由于修订历史记录和提交日志都保存在 VCS 服务器上,并且开发人员计算机上存在的代码库只是普通的工作副本,因此我们无法自信地将 VCS 置于上一个提交状态。
- 这是我们遇到的常见情况。 我们执行的几乎所有操作(如检查文件差异,提交,合并等)都只能在 VCS 启动时执行。 由于某些原因,如果 VCS 暂时关闭,例如网络中断,服务器维护,则将阻止所有访问 VCS 的用户。 即使简单的操作(如将文件与以前的版本进行比较)也无法完成。
- 这种集中式仓库的另一个缺点是与分支有关。 当我们在进行项目时,我们有主干或主分支,它们被认为是事实的来源,将被用于与诸如 Jenkins 之类的构建工具集成。 为了进行开发,我们从主干创建一个分支,在该分支上工作,然后在该分支上进行测试,最后将所做的更改合并回创建标记的主干,并最终将其推送进行部署。 请注意,分支是在服务器上创建的。 另外,如果两个开发人员希望使用某个功能并希望彼此合作而不影响其他人的代码,那么他们将不得不求助于分支机构,该分支机构又将位于服务器上。 因此,在一段时间内,服务器将充满许多分支。
- VCS 的另一个缺点是可伸缩性。 想象一下在一个开源项目中工作,在该项目中成千上万的开发人员需要工作,并且创建了成千上万的分支机构。 合并更改和管理分支机构是一场噩梦,而传统的版本控制系统是无法实现的。
集中版本控制工具在软件开发中扮演着重要的角色,并将继续发挥作用,但是当项目发展壮大时,对于高可用性和关键项目,这可能不是最佳解决方案,因为还有其他更好的选择。 了解集中式 VCS 的弊端有助于我们确定促使我们探索其他选项的因素,例如分布式版本控制系统,例如 Git , Mercurial 等 。
关于作者:
以上文章由该博客的其中一位读者 Pradeep Kumar(@pradeepkumarl)提供。 他是一位拥有 10 多年经验的软件开发人员,并且曾使用过各种版本控制工具,例如 SVN,Perforce,ClearCase 和 Git。 他对技术充满热情,并热爱教技术。 您可以在 Git – 新手到专家上查看他的在线课程之一。
祝您学习愉快!
使用 Maven 的 HornetQ 独立服务器示例
原文: https://howtodoinjava.com/hornetq/hornetq-stand-alone-server-example-using-maven/
HornetQ 是一个开放源代码项目,旨在构建多协议,可嵌入,非常高性能的集群异步消息传递系统。 HornetQ 支持 JMS 1.1 API,并且还定义了自己的消息传递 API,以实现最佳性能和灵活性。 HornetQ 一流的高性能日志以非持久消息传递通常看到的速度提供持久消息传递性能。 HornetQ 提供服务器复制和自动客户端故障转移功能,以消除服务器故障时丢失或重复的消息。
在这篇文章中,我们将学习将 hornetq 服务器作为独立服务器运行的最基本配置,即在诸如 jboss 之类的任何容器之外运行。
步骤 1)使用以下命令创建一个 maven 项目并将其转换为 Eclipse Java 项目
mvn archetype:generate -DgroupId=com.howtodoinjava -DartifactId=HornetQHelloWorld
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
cd HornetQHelloWorld
mvn eclipse:eclipse
步骤 2)更新pom.xml
文件并更新项目依赖项
pom.xml
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelversion>4.0.0</modelversion>
<groupid>com.howtodoinjava</groupid>
<artifactid>HornetQHelloWorld</artifactid>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>HornetQHelloWorld</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupid>org.hornetq</groupid>
<artifactid>hornetq-core</artifactid>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupid>org.hornetq</groupid>
<artifactid>hornetq-jms</artifactid>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupid>org.hornetq</groupid>
<artifactid>hornetq-logging</artifactid>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupid>org.hornetq</groupid>
<artifactid>hornetq-transports</artifactid>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupid>org.jboss.netty</groupid>
<artifactid>netty</artifactid>
<version>3.1.0.GA</version>
</dependency>
<dependency>
<groupid>org.jboss.javaee</groupid>
<artifactid>jboss-jms-api</artifactid>
<version>1.1.0.GA</version>
<scope>compile</scope>
</dependency>
</dependencies>
步骤 3)将基本的 hornetq 配置文件放在类路径中。
hornetq-configuration.xml
< ?xml version="1.0"?>
xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hornetq">
<connectors>
<connector name="netty-connector">
<factory -class>org.hornetq.integration.transports.netty.NettyConnectorFactory
</factory>
</connector>
</connectors>
<acceptors>
<acceptor name="netty-acceptor">
<factory -class>org.hornetq.integration.transports.netty.NettyAcceptorFactory
</factory>
</acceptor>
</acceptors>
<security -enabled>false</security>
步骤 4)配置连接器工厂,并将配置文件放置在 classpath 中。
hornetq-jms.xml
< ?xml version="1.0"?>
xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hornetq">
<!--the connection factory used by the example -->
<connection -factory name="ConnectionFactory">
<connectors>
<connector -ref connector-name="netty-connector"></connector>
</connectors>
<entries>
<entry name="ConnectionFactory"></entry>
</entries>
</connection>
<queue name="exampleQueue">
<entry name="exampleQueue"></entry>
</queue>
步骤 5)启动服务器
EmbeddedServerDemo.java
package com.howtodoinjava;
import org.hornetq.core.config.impl.FileConfiguration;
import org.hornetq.core.server.HornetQServer;
import org.hornetq.core.server.HornetQServers;
import org.hornetq.jms.server.JMSServerManager;
import org.hornetq.jms.server.impl.JMSServerManagerImpl;
public class EmbeddedServerDemo
{
public static void main(String[] args) throws Exception {
try
{
//Load the file configuration first of all
FileConfiguration configuration = new FileConfiguration();
configuration.setConfigurationUrl("hornetq-configuration.xml");
configuration.start();
//Create a new instance of hornetq server
HornetQServer server = HornetQServers.newHornetQServer(configuration);
//Wrap inside a JMS server
JMSServerManager jmsServerManager = new JMSServerManagerImpl(
server, "hornetq-jms.xml");
// if you want to use JNDI, simple inject a context here or don't
// call this method and make sure the JNDI parameters are set.
jmsServerManager.setContext(null);
//Start the server
jmsServerManager.start();
//WOO HOO
System.out.println("HornetQ server started successfully !!");
}
catch (Throwable e)
{
System.out.println("Well, you seems to doing something wrong. Please check if config files are in your classes folder.");
e.printStackTrace();
}
}
}
Output in console:
22 Mar, 2013 2:09:33 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: live server is starting..
22 Mar, 2013 2:09:33 PM org.hornetq.core.logging.impl.JULLogDelegate warn
WARNING: AIO wasn't located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO to enable the AIO journal
22 Mar, 2013 2:09:33 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: Using NIO Journal
22 Mar, 2013 2:09:33 PM org.hornetq.core.logging.impl.JULLogDelegate warn
WARNING: Security risk! It has been detected that the cluster admin user and password have not been changed from the installation default. Please see the HornetQ user guide, cluster chapter, for instructions on how to do this.
22 Mar, 2013 2:09:33 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: Started Netty Acceptor version 3.1.5.GA-r1772
22 Mar, 2013 2:09:33 PM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: HornetQ Server version 2.0.0.GA (Hornet Queen, 113) started
HornetQ server started successfully !!
祝您学习愉快!
如何从 Google Code 项目中签出源代码
原文: https://howtodoinjava.com/vcs/checkout-sourcecode-from-google-code-projects/
如果您转到 Github 项目,它们会为您提供一个链接,以 zip 文件的形式下载源代码(如果您不想配置任何 git 客户端)。 但是在 Google 代码项目中,某些项目没有为您提供此选项,而是向您显示 SVN URL 来检出。 在本教程中,我提供了一个示例,该示例使用 Tortoise SVN 客户端从code.google.com
检出源代码到本地计算机。
1)下载任何 SVN 客户端的安装文件(例如 Tortoise)
转到 http://tortoisesvn.net/downloads.html 并将其最新版本安装在开发计算机中。
Tortoise svn 下载页面
2)在文件系统中创建一个空白文件夹并签出源代码
现在在您的工作区中创建一个空文件夹。 然后右键单击。 单击“SVN Checkout…”选项。
SVN 检出截图
现在,将 google 代码项目中的 SVN 检出 URL 复制直到trunk
。
复制源代码检出 URL 直到trunk
在工作区的签出对话框中复制路径,然后单击“确定”。
在检出对话框中复制 URL
现在,所有文件将从 Google Code 项目下载到本地工作区。 在合适的编辑器中导入代码并开始进行处理。
祝您学习愉快!
Tomcat 教程
Tomcat – 架构和server.xml
配置
原文: https://howtodoinjava.com/tomcat/tomcats-architecture-and-server-xml-configuration-tutorial/
我们已经学习了,当您在服务器上部署 Web 应用并通过浏览器进行访问时,Web 服务器通常是如何工作的。 现在,让我们学习一下服务器内部可能无法在日常工作中使用的东西,但是当您初次配置应用时,它们肯定会为您提供帮助。 我长期以来一直在使用 tomcat 服务器,因此我将其用作教程。 将来,只要时间允许,我将尝试在其他服务器上分享我的经验。
Apache Tomcat 是由 Apache 软件基金会(ASF)开发的开源 Web 服务器和 Servlet 容器。 Tomcat 实现了几种 Java EE 规范,包括 Java Servlet,JavaServer Pages(JSP),Java EL 和 WebSocket,并提供了运行 Java 代码的“纯 Java” HTTP Web 服务器环境(Wiki)。
Tomcat 的架构
Tomcat 的架构由一系列功能组件组成,可以根据明确定义的规则进行组合。
Tomcat 架构
每个服务器安装的结构(通过这些功能组件)在文件server.xml
中定义,该文件位于 Tomcat 的安装文件夹的/conf
子目录中。 让我们详细讨论这些组件。
server.xml
组件
默认情况下,server.xml
文件随附此配置,我们将详细研究其元素。
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
让我们从内到外讨论 tomcat 配置文件的功能组件,以更好地关联事物。
上下文
上下文是一组称为容器的 Tomcat 组件的最里面的元素,它代表单个 Web 应用。 Tomcat 在加载应用时自动实例化并配置标准上下文。 作为配置的一部分,Tomcat 还处理应用文件夹的\WEB-INF\web.xml
文件中定义的属性,并使这些属性可用于应用。
连接器(第 16-19 行)
连接器处理与客户端的通信。 Tomcat 提供了多个连接器,例如 HTTP 连接器用于大多数 HTTP 通信,AJP 连接器实现将 Tomcat 连接到另一个 Web 服务器(例如 Apache HTTPD 服务器)时使用的 AJP 协议。
Tomcat 的默认配置包括一个用于处理 HTTP 通信的连接器。 默认情况下,此连接器等待通过端口 8080 发出的请求。 这就是我们示例的 URL 始终以http://localhost:8080/
开头的原因。 请注意,对所有应用的请求都通过此连接器的单个实例。 每个新请求都会导致实例化一个新线程,该新线程在请求期间将保持活动状态。 互联网上有关 Tomcat 的文章通常将此连接器称为“Coyote
”。
connectionTimeout
属性设置为 20,000 表示会话在闲置 5 小时,33 分钟和 20 秒后终止,而redirectPort="8443"
表示需要安全套接字层(SSL)传输的传入请求将重定向到端口 8443。
AJP 连接器使 Tomcat 只处理动态网页,而让纯 HTML 服务器(例如 Apache Web 服务器)处理对静态页面的请求。 这样可以最大程度地处理请求。 您可能可以注释掉此连接器,因为 tomcat 本身今天已经非常快,或者只是如果您不打算将 Web 服务器与 Tomcat 一起使用,则可以将其注释掉。
主机(第 25-30 行)
主机是网络名称的关联,例如www.yourdomain.com
,访问 Tomcat 服务器。 主机可以包含任意数量的上下文(即应用)。 您可以在同一服务器上定义多个主机。 例如,如果您已注册域yourdomain.com
,则可以定义主机名,例如w1.yourdomain.com
和w2.yourdomain.com
。 请记住,只有当域名服务器将其名称映射到计算机的 IP 地址时,才可以从互联网访问它。
Tomcat 的默认配置包括名为 localhost 的主机。 可以通过在文件C:\Windows\System32\drivers\etc\hosts
中写入一个项目来完成 localhost 与您的计算机之间的关联。
主机属性“appBase
”定义了 Tomcat 安装文件夹中的应用目录。 然后,每个应用通过该目录中的路径进行标识。 唯一的例外是根路径,该路径已映射到空字符串。 本地主机的应用基本目录是webapps
。 这意味着目录“C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\ROOT\
”中的应用由空字符串标识。 因此,其 URL 为“http://localhost:8080/
”。 对于驻留在根以外的目录中的其他应用,如“C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\myapp\
”,URL 类似于“http://localhost:8080/myapp/
”。
属性unpackWARs="true"
表示,如果将 WAR 文件拖放到appBase
目录中,Tomcat 将自动将其扩展到普通文件夹中。 如果将此属性设置为false
,则应用将直接从 WAR 文件运行。 这显然意味着应用的执行速度较慢,因为 Tomcat 需要在执行时解压缩 WAR 文件。
属性autoDeploy="true"
表示,如果在 Tomcat 运行时将应用放置在appBase
目录中,它将被自动部署。
引擎(第 20 行)
引擎代表特定服务的请求处理管道。 由于服务可能具有多个连接器,因此引擎从这些连接器接收并处理所有请求,将响应传递回适当的连接器以传输到客户端。
引擎必须包含一个或多个主机,其中之一被指定为默认主机。 Tomcat 的默认配置包括引擎 Catalina,该引擎包含主机 localhost(显然是默认主机,因为它是唯一的主机)。 Catalina 引擎处理通过 HTTP 连接器收到的所有传入请求,并发回相应的响应。 它根据请求头中包含的信息将每个请求转发到正确的主机和上下文。
服务(第 15 行)
服务是驻留在服务器内部的一个中间组件,并且将一个或多个连接器与一个引擎完全绑定在一起。 Tomcat 的默认配置包括服务 Catalina,该服务将 HTTP 和 AJP 连接器关联到 Catalina 引擎。 因此,连接器和引擎是 Service 元素的子元素。
用户很少自定义 Service 元素,因为默认实现很简单并且足够。
服务器(第 2 行)
服务器是最重要的组件,代表 Tomcat 的一个实例。 它可以包含一个或多个服务,每个服务都有自己的引擎和连接器。
现在,让我们讨论以上server.xml
中使用的其他一些概念。
监听器(第 3-7 行)
监听器是一个 Java 对象,通过实现org.apache.catalina.LifecycleListener
接口,它可以响应特定的事件。
AprLifecycleListener
:启用 Apache 可移植运行时(APR)库。 该库为 tomcat 提供了操作系统级别的支持。JasperListener
:启用 Jasper,它是 JSP 引擎。 该监听器使重新编译已更新的 JSP 文档成为可能。JreMemoryLeakPreventionListener
:处理可能导致内存泄漏的各种已知情况。GlobalResourcesLifecycleListener
:负责实例化与全局 Java 命名和目录接口(JNDI)相关联的托管 Bean。ThreadLocalLeakPreventionListener
:还处理可能导致内存泄漏的各种已知情况。
全局命名资源
GlobalNamingResources
元素只能在服务器组件内部定义。 它定义了整个服务器都可以访问的 JNDI 资源。 默认server.xml
中定义的唯一资源是通过文件conf/tomcat-users.xml
定义的基于用户和密码存储的数据库。
领域(第 21-24 行)
领域组件可以出现在任何容器组件(引擎,主机和上下门)内。 它代表用户,密码和用户角色的数据库。 其目的是支持基于容器的认证。
除了UserDatabaseRealm
之外,还提供以下领域类:JDBCRealm
(用于通过其 JDBC 驱动程序连接到关系数据库),DataSourceRealm
(用于连接到通过 JNDI 命名的 JDBC 数据源),JNDIRealm
(用于连接 到轻型目录访问协议目录)和MemoryRealm
(将 XML 文件加载到内存中)。
阀门(行 27-29)
阀门是类似于拦截器的元素,当插入到容器(上下文,主机或引擎)中时,会在所有传入的 HTTP 请求到达应用之前拦截它们。 这使您能够预处理针对特定应用的请求。 虚拟主机中运行的应用或引擎中运行的所有应用。
阀门可以有多种用途,例如:
通过RemoteAddrValve
阀,您可以根据源 IP 地址有选择地允许或阻止请求。 它支持两个属性 – allow
和block
。
<Valve className="org.apache.catalina.valves.RemoteAddrValve" block="192\.168.*"/>
RemoteHostValve
阀的操作类似于远程地址过滤器,但在客户端主机名而不是客户端 IP 地址上。
<Valve className="org.apache.catalina.valves.RemoteHostValve" deny=".*badweb\.com"/>
RequestDumperValve
记录传入请求的详细信息,因此对于调试目的很有用。
<Valve className="org.apache.catalina.valves.RequestDumperValve"/>
当single sign on valve
包含在主机容器中时,其作用是仅对该主机的所有应用进行一次认证。 如果没有此阀,则用户必须在使用每个单独的应用之前输入其 ID 和密码。
<Valve className="org.apache.catalina.valves.SingleSignOn"/>
仅限于server.xml
内部元素的介绍。 将来我将介绍与 tomcat 服务器有关的更多任务/概念。
祝您学习愉快!
参考: http://tomcat.apache.org/tomcat-7.0-doc/architecture/overview.html
如何在默认的 HTTP 端口 80 中运行 tomcat
原文: https://howtodoinjava.com/tomcat/run-tomcat-in-default-http-port-80/
默认情况下,tomcat 配置为在端口 8080 上运行。这就是为什么可以通过http://localhost:8080/yourapp
之类的 URL 访问所有已部署的 Web 应用的原因。 如果要在http://localhost/yourapp
之类的 URL 上运行应用,则需要将默认端口 8080 更改为 80,这是 HTTP 连接器的默认端口。
要更改此端口,请打开server.xml
并找到以下项目:
<Connector port="8080" //Change this
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
/>
并将其更改为以下项目:
<Connector port="80" //Changed
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
/>
您都可以使用根路径“http://localhost/
”访问您的应用。
祝您学习愉快!
Tomcat – 启用/禁用目录列表
原文: https://howtodoinjava.com/tomcat/tomcat-enabledisable-directory-listing/
当您的应用部署在 tomcat Web 服务器中,并且您请求指向目录而不是文件的 URL(例如http://host:port/helloWorldApp/
)时,您可以将 Tomcat 配置为提供目录列表或欢迎文件,或发出错误“404 页面未找到”。 让我们看看如何启用或禁用 tomcat 服务器中的目录列表。
Table of Contents
Enabling Directory Listing for ALL Webapps
Enabling Directory Listing for any particular Webapp
为所有 Webapp 启用目录列表
要为所有 Web 应用启用目录列表,您可以通过将“default
” servlet 的“listings
”从“false
”更改为“true
”来修改<CATALINA_HOME>\conf\web.xml
,如下所示:
<!-- The default servlet for all web applications, that serves static -->
<!-- resources. It processes all requests that are not mapped to other -->
<!-- servlets with servlet mappings. -->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- The mapping for the default servlet -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- ==================== Default Welcome File List ===================== -->
<!-- When a request URI refers to a directory, the default servlet looks -->
<!-- for a "welcome file" within that directory and, if present, -->
<!-- to the corresponding resource URI for display. If no welcome file -->
<!-- is present, the default servlet either serves a directory listing, -->
<!-- or returns a 404 status, depending on how it is configured. -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
上面的配置将 URL “/
”(Web 上下文的根目录)映射到 Java 类DefaultServlet
。 我们通过将 Servlet 的初始化参数listings
更改为true
来启用目录列表。
如果用户请求目录,并且目录列表已启用并且包含<welcome-file>
列表中的文件之一,则将提供欢迎文件; 否则,将提供目录列表。 另一方面,如果接收到目录请求且未启用目录列表,则服务器将返回错误“404 页面未找到”。
为任何特定的 Webapp 启用目录列表
如果只希望允许特定 Web 应用的目录列表,则可以全局禁用“<CATALINA_HOME>\conf\web.xml
”中的目录列表,并在特定于应用的WEB-INF\web.xml
中定义以下<servlet>
和<servlet-mapping>
,如下所示 :
<servlet>
<servlet-name>DirectoryListing</servlet-name>
<servlet-class>com.package.MyServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DirectoryListing</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
请注意,启用目录列表对于测试服务器很方便,但对于生产服务器则不希望。
祝您学习愉快!
Tomcat SSL 或 HTTPS 配置示例
原文: https://howtodoinjava.com/tomcat/how-to-configure-tomcat-with-ssl-or-https/
安全套接字层(SSL) 是用于使用加密方法在互联网上进行通信的安全传输协议。 SSL 协议的主要目的是确保不会有人篡改浏览器与部署 Web 应用的服务器之间的通信。 安全通信的另一个目的是根据 SSL 信息对服务器及其所有者进行认证的能力 – 这样,用户就可以确定它正在访问的服务器。 在常见的 SSL 方案中,当用户首次访问 Web 服务器时,服务器会将其 SSL 证书或公共密钥发送给客户端。 SSL 证书包含有关服务器,其所有者,公司及其有效期的信息。 如果用户不信任证书的真实性,则可以拒绝该证书,从而有效地终止连接。 如果用户接受证书,则证书本身存储在浏览器中,并用于启动与发行服务器的安全连接。
通过 HTTP 协议进行的 SSL 协议通信称为 HTTPS (安全 HTTP)。 使用 SSL 加密连接的网站在浏览器的地址栏中显示 https 作为协议名称,例如。 名为证书颁发机构(CA)的组织可以对 SSL 证书的详细信息进行认证,因此,如果用户信任 CA,则可以确保安全网站及其证书已通过认证。 细节是正确的。 有许多可以颁发认证的 SSL 证书的 CA。 现代浏览器会自动识别最大和最知名的 CA,并允许自动连接到提供由这些组织认证的 SSL 证书的站点。 如果 SSL 证书未通过 CA 认证,或未通过 CA 认证但未被用户的浏览器识别,则将向用户显示警告屏幕,用户可以在该屏幕上决定是否信任该证书。
Configuring tomcat with SSL is three step process.
1) Generating Keystore
2) Updating Connector in server.xml
3) Updating application's web.xml with secured URLs
1)生成密钥库
SSL 证书是 JKS 文件。 JKS 格式代表 JavaKeyStore,这是 Java 特定的 keystore 格式。 可以使用 Keytool 工具应用创建和操作 JKS 密钥库,该应用作为 1.4 版 Java SDK 的一部分分发。 我们将用于创建自签名 SSL 证书的 Keytool 位于JAVA_HOME/bin/
目录中。
//GOTO JAVA HOME
c:\ > cd %JAVA_HOME%/bin
//TYPE GENKEY COMMAND
C:\BAML\DFCCUI\installs\jdk1.6\bin>keytool -genkey -alias tomcat -keyalg RSA
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: lokesh
What is the name of your organizational unit?
[Unknown]: boa
What is the name of your organization?
[Unknown]: boa
What is the name of your City or Locality?
[Unknown]: delhi
What is the name of your State or Province?
[Unknown]: delhi
What is the two-letter country code for this unit?
[Unknown]: 91
Is CN=lokesh, OU=boa, O=boa, L=delhi, ST=delhi, C=91 correct?
[no]: yes
Enter key password for <tomcat>
(RETURN if same as keystore password):
Re-enter new password:
C:\installs\jdk1.6\bin>
它将在您的用户主目录中创建一个.keystore
文件。 在 Windows 7 上,其C:\Users\lokesh
下。
一个 IP 地址只能拥有一个 SSL 证书。 如果您在同一 IP 上托管多个域,则这些主机名中只有一个可以具有与其域名匹配的有效 SSL 证书。 如果您尝试对同一 IP 上的任何其他域名使用 SSL,浏览器将显示警告,提示该域名与证书不匹配。 这是 SSL 的已知限制,因为必须在从 HTTP 请求中提取主机名之前进行 SSL 协议握手。
2)更新server.xml
中的连接器
打开您的 Tomcat 安装目录,然后打开conf
文件夹。 在此文件夹中,您将找到server.xml
文件。 打开它并找到以下声明:
<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
-->
并使用此信息进行更改。 不要忘记使用您的密码和密钥库路径。
<Connector SSLEnabled="true" acceptCount="100" clientAuth="false"
disableUploadTimeout="true" enableLookups="false" maxThreads="25"
port="8443" keystoreFile="C:/Users/lokesh/.keystore" keystorePass="password"
protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
secure="true" sslProtocol="TLS" />
大功告成,现在查看应用更改。
3)使用安全的网址更新应用的web.xml
现在,使用以下更新您的应用的web.xml
文件。
<security-constraint>
<web-resource-collection>
<web-resource-name>application-one</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
url 模式设置为/*
,因此来自应用的任何页面/资源都是安全的(只能使用 https 访问)。 transport-guarantee
标签设置为CONFIDENTIAL
,以确保您的应用可以在 SSL 上运行。
现在尝试使用https://localhost:8443/application-one/
访问该应用。 这将在浏览器中显示证书信息。
仅在您接受证书后,它才会显示页面。
如果您没有将web.xml
中的安全约束置于上方,则可以使用http://localhost:8080/application-one/
直接访问您的应用。
这就是在 Tomcat 服务器中实现 SSL 支持这一简单而重要的概念。
学习愉快!
通过单个服务器安装运行 Tomcat 的多个实例
很多时候,我们遇到需要修改服务器配置以使其特定于应用的情况。 而且,如果我们有多个这样的应用,并且希望每个应用都具有自己定义的配置选项,那么它就需要某种配置。 在本教程中,我将讨论为每个应用使用不同的 tomcat 实例而应进行的更改。
配置 Tomcat 服务器的多个实例的步骤
我正在使用 Windows 机器,您将使用 Windows 格式的路径。 但是创建所有实例的过程在所有其他操作系统中都是相同的。 另外,我假设您要创建 2 个新的 tomcat 实例。 现在开始阅读完成目标的完整步骤。
步骤 1)安装 Tomcat 服务器
这是非常明显的第一步。 假设我们的 tomcat 安装目录为“C:/tomcatServer
”。
步骤 2)在不同位置创建 2 个新的不同文件夹
这些文件夹用于存储实例特定的配置和其他数据,例如日志,临时数据。
假设新文件夹为“C:/tomcatInstanceOne
”和“C:/tomcatInstanceTwo
”。
步骤 3)将“conf
”文件夹从服务器文件夹复制到实例文件夹
为了使每个实例具有不同的配置,必须执行此步骤。 任何与实例特定的配置相关的更改应仅在相关实例文件夹中进行。
步骤 4)创建实例特定的startup.bat
和shutdown.bat
启动和关闭特定实例将需要这些文件。 文件内容如下:
startup.bat
set CATALINA_HOME=C:\tomcatServer
set CATALINA_BASE=C:\tomcatInstanceOne
C:\tomcatServer\bin\startup.bat
shutdown.bat
set CATALINA_HOME=C:\tomcatServer
set CATALINA_BASE=C:\tomcatInstanceOne
C:\tomcatServer\bin\shutdown.bat
将两个文件都放在两个实例特定文件夹内的“bin
”文件夹中。 例如,创建文件夹C:/tomcatInstanceOne/bin
并复制两个文件。
第一个属性(CATALINA_HOME
)指向所有正在运行的实例之间可共享的公共信息的位置,而其他属性(CATALINA_BASE
)指向所有实例特定信息的存储目录。
步骤 5)创建setenv.bat
以设置实例特定的环境配置
在“C:\tomcatInstanceOne\bin
”(以及第二个实例文件夹)目录中创建一个名为setenv.bat
的文件,以设置C:\tomcatServer\bin\catalina.bat
中提到的任何环境变量。 在这里设置系统属性,JPDA 地址等。
步骤 6)为日志,临时文件等创建更多文件夹
现在是时候创建更多文件夹了,这些文件夹将在您的应用实际运行时使用。 这些文件夹类似于日志,临时文件,Web 应用和工作文件夹。 在两个实例文件夹中分别创建它们。
只需确保编辑conf\server.xml
文件,以使关闭端口和 HTTP 连接器端口不会干扰其他可能正在运行的 tomcat 实例。
例如,更改 tomcat 将要运行/调试的端口。
First server.xml file
<connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<server port="8005" shutdown="SHUTDOWN"/>
<connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<connector port="8100" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
Second server.xml file
<connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<server port="8006" shutdown="SHUTDOWN"/>
<connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
<connector port="8101" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
完成上述更改后,您应该能够在计算机中启动同一 tomcat 服务器的多个实例。 如果您被打中,请告诉我。
祝您学习愉快!
Tomcat Maven 插件示例
原文: https://howtodoinjava.com/maven/tomcat-maven-plugin-example/
在本 maven 教程中,学习将 tomcat 插件添加并配置到pom.xml
并使用它部署 Web 应用,而无需在机器上安装任何 tomcat。
当您想在由于某些原因无法安装实际 tomcat 的开发人员的机器上测试应用时,此功能非常有用。
插件的最新版本是“2.2”。 它具有 Apache Tomcat7 支持。
如何添加 tomcat Maven 插件
编辑项目的pom.xml
文件和build
标签内的插件项目。
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Tomcat plugin-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>9000</port> //Configure port number
<path>/spring5-webmvc-demo</path> //Configure application root URL
</configuration>
</plugin>
</plugins>
</build>
Tomcat Maven 插件配置
您可以在configuration
标签内以各种方式添加 tomcat 插件。 一些有用的配置选项是:
address
– 此 IP 地址将在所有端口上使用contextFile
– Tomcat 上下文 XML 文件的路径。hostName
– 配置主机名httpsPort
– 用于运行 Tomcat 服务器的 https 端口。keystoreFile
– 覆盖 HTTPS 连接器的默认密钥库文件(如果启用)keystorePass
– 覆盖 HTTPS 连接器的默认 keystorePass(如果启用)mainClass
– 用于启动独立 jar 的主类。systemProperties
– 要传递给 Tomcat 服务器的系统属性的列表。port
– 自定义端口号path
– 用于 Web 应用的 WebApp 上下文路径warFile
– 要部署的 WAR 文件的路径。
使用 tomcat 插件运行应用
要使用 tomcat maven 插件运行该应用,请将 maven 目标用作:
mvn tomcat7:run
当您运行在 Maven 目标之上时,您会看到 tomcat 在控制台日志中使用默认端口8080
启动。
[INFO] >>> tomcat7-maven-plugin:2.2:run (default-cli) > process-classes @ spring5-webmvc-demo >>>
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ spring5-webmvc-demo ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ spring5-webmvc-demo ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] <<< tomcat7-maven-plugin:2.2:run (default-cli) < process-classes @ spring5-webmvc-demo <<<
[INFO]
[INFO] --- tomcat7-maven-plugin:2.2:run (default-cli) @ spring5-webmvc-demo ---
[INFO] Running war on http://localhost:8080/spring5-webmvc-demo
[INFO] Using existing Tomcat server configuration at D:\java9\workspace\spring5-webmvc-demo\target\tomcat
[INFO] create webapp with contextPath: /spring5-webmvc-demo
---
---
INFO: Starting ProtocolHandler ["http-bio-8080"]
将我的问题放在评论部分。
学习愉快!
Spring,Tomcat – 获取负载均衡器后面的真实 IP
原文: https://howtodoinjava.com/tomcat/tomcat-get-real-ip-behind-load-balancer/
通常,出于日志记录和安全目的,我们需要传入请求的 IP 地址信息。 在任何 Java Web 应用中,都可以使用getRemoteAddr()
方法获取 IP 地址。
String httpServletAddress = request.getRemoteAddr();
但是,如果您的应用在负载均衡器代理后面运行,并且您希望转换用户使用的真实请求 IP 而不是我们的应用实例收到请求时来自代理的 IP,那么上述语句即可获取 IP 仅均衡器代理的地址。
使用 Tomcat 的RemoteIpFilter
在上述情况下,可以使用 tomcat 提供的RemoteIpFilter
servlet 过滤器。
要进行配置,请使用 Java 配置RemoteIpFilter
– 在 spring boot 应用中,使用@Configuration
注解注册 bean。
@Configuration
public class WebConfiguration {
@Bean
public RemoteIpFilter remoteIpFilter() {
return new RemoteIpFilter();
}
}
或使用 XML 配置,例如web.xml
– 使用filter
标签。
<filter>
<filter-name>RemoteIpFilter</filter-name>
<filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RemoteIpFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
注册上述过滤器后,启动应用。
现在,当您使用request.remoteAddr()
方法时,您将获得呼叫客户端的正确 IP 地址。
阅读更多:RemoteIpFilter
RemoteIpFilter
在内部集成了X-Forwarded-For
和X-Forwarded-Proto
HTTP 标头。
该 Servlet 过滤器的另一个功能是通过请求标头(例如“X-Forwarded-Proto
”),用代理或负载均衡器提供的方案替换表观方案(http / https)和服务器端口。
学习愉快!
Web 服务器如何工作?
原文: https://howtodoinjava.com/tomcat/a-birds-eye-view-on-how-web-servers-work/
许多时候,我们想知道 Web 容器 / Web 服务器(例如 tomcat 或 jboss)如何工作? 他们如何处理来自世界各地的传入 HTTP 请求? 幕后发生的原因是什么? Java Servlet API(例如ServletContext
,ServletRequest
,ServletResponse
和Session
之类的类)如何适应图片? 这些是非常重要的问题/概念,如果您是 Web 应用开发人员或渴望成为,则必须知道。 在这篇文章中,我将尝试找出上述问题的答案,即使不是全部。 从这里保持集中。
Table of Contents:
What are web server, application server and web container?
What are Servlets? How they help?
What is ServletContext? Who creates it?
Where ServletRequest and ServletResponse fits into life cycle?
How Session is managed? Know the cookie?
How thread safety should be ensured?
什么是 Web 服务器,应用服务器和 Web 容器?
我将首先讨论 Web 服务器和应用服务器。 我说一句
“从历史上看,它们是不同的,但是这两个以前截然不同的类别逐渐合并,现在在大多数情况和用途中应被视为一个实体。”
在 Mosaic 浏览器(通常被称为第一个图形化 Web 浏览器)和超链接内容的早期,出现了一种新概念“Web 服务器”,用于服务静态网页内容和 HTTP 协议上的图像。 很简单。 如今,大多数内容都是静态的,HTTP 1.0 协议只是一种随身携带文件的方式。 但是很快,Web 服务器就发展为具有 CGI 功能。 这意味着在每个 Web 请求上有效启动一个流程以生成动态内容。 到那时,HTTP 协议也已经成熟,Web 服务器变得更加复杂,并具有诸如缓存,安全性和会话管理之类的附加功能。 随着技术的进一步成熟,我们从 Kiva 和 NetDynamics 中获得了基于公司的基于 Java 的服务器端技术,最终它们全部合并为 JSP(java 服务器页面), 在当今大多数应用开发中使用。
这是关于网络服务器的。 现在,我们来讨论应用服务器。
在并行类别中,应用服务器已经发展并存在了很长时间。 一些公司为 Unix 提供了诸如 Tuxedo(面向事务的中间件),TopEnd,Encina 等产品,这些产品从大型机应用管理中衍生而来 和监视环境,例如 IMS 和 CICS。 这些产品大多数都指定了“封闭式”产品特定的通信协议,以将“胖”客户端互连到服务器。 在 90 年代,这些传统的应用服务器产品首先通过网关开始嵌入基本的 HTTP 通信功能。 很快,这两类之间的界限开始模糊。
到那时,Web 服务器在处理更高的负载,更多的并发和更好的功能方面变得越来越成熟。 应用服务器开始提供越来越多的基于 HTTP 的通信功能。 所有这些都导致 Web 服务器和应用服务器之间的界限很窄。
在这一点上,“应用服务器”和“网络服务器”之间的界线是模糊的。 但是,作为重点,人们继续使用不同的术语。
当有人说“Web 服务器”时,您通常会想到以 HTTP 为中心,面向 Web UI 的应用。 当有人说“应用服务器”时,您可能会认为“负载较重,企业功能,事务和排队,多通道通信(HTTP 及其他)”。 但是大多数情况下,这是同一款产品,如今可以同时满足这两种要求。
这就是有关 Web 服务器和应用服务器的一切。 现在进入第三个术语,即网络容器。
Web 容器,尤其是 java 中的,应引用 servlet 容器。 Servlet 容器是与 Java Servlet 交互的 Web 服务器的组件。 Web 容器负责管理 Servlet 的生命周期,将 URL 映射到特定的 Servlet,并确保 URL 请求者具有正确的访问权限以及更多此类服务。 基本上,综合以上所有事实, Servlet 容器是 Servlet 运行并维持其生命周期的运行时环境。
什么是 Servlet? 他们如何提供帮助?
在 Java 中,servlet 使您可以编写服务器端组件,以根据请求帮助生成动态内容。 实际上,Servlet 是在javax.servlet
包中定义的接口。 它声明了 Servlet 生命周期的三种基本方法 - init()
,service()
和destroy()
。 它们由每个 servlet(在 SDK 中定义或由用户定义)实现,并在服务器的生命周期中由服务器在特定时间调用。
Servlet 类由其类加载器通过延迟加载或急切加载动态地加载到容器中。 每个请求都在其自己的线程中,并且 servlet 对象可以同时服务多个线程。 当不再使用它时,它将被 JVM 垃圾回收。
延迟加载 servlet
立即加载 Servlet
什么是ServletContext
? 谁创造的?
当 Servlet 容器启动时,它将部署并加载所有 Web 应用。 加载 Web 应用后,Servlet 容器将为每个应用创建一次 ServletContext
,并将其保留在服务器的内存中。 该 Web 应用的web.xml
将被解析,并且在web.xml
中找到的每个 Servlet,过滤器和监听器都将被创建一次并保存在服务器的内存中。 当 Servlet 容器关闭时,它将卸载所有 Web 应用,并且ServletContext
以及所有 Servlet,过滤器和监听器实例都将被丢弃。
根据 Java 文档, ServletContext
定义了 Servlet 用于与其 Servlet 容器通信的一组方法,例如,获取文件的 MIME 类型,调度请求或写入日志文件。 对于 Web 应用在其部署描述符中标记为“已分发”的情况,每个虚拟机都有一个上下文实例。 在这种情况下,上下文不能用作共享全局信息的位置(因为该信息不是真正的全局信息)。 请改用外部资源,例如数据库。
ServletRequest
和ServletResponse
适合生命周期的地方?
Servlet 容器连接到 Web 服务器,该服务器在特定端口号(通常为 80)上监听 HTTP 请求。当客户端(具有 Web 浏览器的用户)发送 HTTP 请求时, Servlet 容器将创建新的HttpServletRequest
和HttpServletResponse
对象将其传递给 URL 样式与请求 URL 匹配的已创建过滤器和 Servlet 实例的方法,所有这些都在同一线程中。
请求对象提供对 HTTP 请求的所有信息的访问,例如请求标头和请求正文。 响应对象提供了以所需方式控制和发送 HTTP 响应的功能,例如设置标头和正文(通常带有 JSP 文件中的 HTML 内容)。 提交并完成 HTTP 响应后,请求和响应对象都将被丢弃。
如何管理会话? 知道 cookie 吗?
当客户端首次访问 Web 应用和/或要通过request.getSession()
首次获取HttpSession
时,则 Servlet 容器将创建它,并生成一个长而唯一的 ID(您可以通过session.getId()
获取并存储在服务器的内存中。 servlet 容器还将在 HTTP 响应中设置 Cookie,其中JSESSIONID
为 cookie 名称,唯一会话 ID 为 cookie 值。
根据 HTTP cookie 规范(体面的 Web 浏览器和 Web 服务器必须遵守的约定),要求客户端(Web 浏览器)在后续请求中将该 Cookie 发送回 只要 Cookie 有效即可。 Servlet 容器将确定每个传入的 HTTP 请求标头中是否存在名为JSESSIONID
的 cookie,并使用其值从服务器的内存中获取关联的HttpSession
。
HttpSession
会一直存在,直到没有被使用为止,您可以在web.xml
中指定该设置,该设置默认为 30 分钟。 因此,如果客户端超过 30 分钟不再访问该 Web 应用,则 Servlet 容器将破坏该会话。 即使指定了 cookie,每个后续请求都将无法再访问同一会话。 servlet 容器将创建一个新的。
现有会话
新会话
另一方面,客户端上的会话 cookie 具有默认生存期,该生存期只要浏览器实例正在运行即可。 因此,当客户端关闭浏览器实例(所有选项卡/窗口)时,会话将在客户端被丢弃。 在新的浏览器实例中,与该会话关联的 cookie 将不再发送。 一个新的request.getSession()
将返回一个全新的HttpSession
并设置一个具有全新会话 ID 的 cookie。
应如何确保线程安全?
您现在应该已经了解到,Servlet 和过滤器在所有请求之间共享。 这是 Java 的优点,因为它是多线程,并且不同的线程(即 HTTP 请求)可以使用同一实例。 否则,在每个请求上重新创建它会太昂贵。
但是,您还应该意识到,永远不要将任何请求或会话范围的数据分配为 Servlet 或过滤器的实例变量。 它将在其他会话中的所有其他请求之间共享。 那是线程不安全的! 下面的示例说明:
public class MyServlet extends HttpServlet
{
private Object thisIsNOTThreadSafe; //Don't to this
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Object thisIsThreadSafe;
thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
}
}
不要这样做。 这将导致软件错误。
以上就是这个主题。 请继续关注更多此类帖子。 最好订阅电子邮件新闻信,以在收件箱中获得通知。
祝您学习愉快!
推荐链接:
http://www.invir.com/int-prog-cgi.html
Spring3 Hornetq 独立集成示例
原文: https://howtodoinjava.com/hornetq/spring-3-hornetq-standalone-integration-example/
HornetQ 是一个开放源代码项目,旨在构建多协议,可嵌入,非常高性能的集群异步消息传递系统。 到目前为止,我们已经了解了配置 hornetq 独立服务器和设置基本消息传递功能的示例。 HornetQ 具有很大的灵活性,可以通过一些现有的应用框架进行配置。 在此序列中,我将展示 HornetQ 在 Spring3 中的用法。
让我们逐步进行所有设置。
步骤 1)创建一个 Maven 项目并将其转换为 Eclipse Java 项目。
步骤 2)使用 Spring3 和 hornetq 依赖项更新 maven 仓库。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.howtodoinjava.app</groupId>
<artifactId>Spring3HornetQStandaloneIntegration</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Spring3HornetQStandaloneIntegration</name>
<url>http://maven.apache.org</url>
<properties>
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
</properties>
<dependencies>
<!-- User Application Lib -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<!-- HornetQ Embedded Server -->
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-core</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-logging</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-transports</artifactId>
<version>2.0.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
<version>3.1.0.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.javaee</groupId>
<artifactId>jboss-jms-api</artifactId>
<version>1.1.0.GA</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jboss-common-core</artifactId>
<version>2.2.10.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-spi</artifactId>
<version>2.0.5.GA</version>
</dependency>
<!--
Core utilities used by other modules.
Define this if you use Spring Utility APIs (org.springframework.core.*/org.springframework.util.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Expression Language (depends on spring-core)
Define this if you use Spring Expression APIs (org.springframework.expression.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Bean Factory and JavaBeans utilities (depends on spring-core)
Define this if you use Spring Bean APIs (org.springframework.beans.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Aspect Oriented Programming (AOP) Framework (depends on spring-core, spring-beans)
Define this if you use Spring AOP APIs (org.springframework.aop.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Application Context (depends on spring-core, spring-expression, spring-aop, spring-beans)
This is the central artifact for Spring's Dependency Injection Container and is generally always defined
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Various Application Context utilities, including EhCache, JavaMail, Quartz, and Freemarker integration
Define this if you need any of these integrations
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Transaction Management Abstraction (depends on spring-core, spring-beans, spring-aop, spring-context)
Define this if you use Spring Transactions or DAO Exception Hierarchy
(org.springframework.transaction.*/org.springframework.dao.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
JDBC Data Access Library (depends on spring-core, spring-beans, spring-context, spring-tx)
Define this if you use Spring's JdbcTemplate API (org.springframework.jdbc.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Object-to-Relation-Mapping (ORM) integration with Hibernate, JPA, and iBatis.
(depends on spring-core, spring-beans, spring-context, spring-tx)
Define this if you need ORM (org.springframework.orm.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Object-to-XML Mapping (OXM) abstraction and integration with JAXB, JiBX, Castor, XStream, and XML Beans.
(depends on spring-core, spring-beans, spring-context)
Define this if you need OXM (org.springframework.oxm.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Web application development utilities applicable to both Servlet and Portlet Environments
(depends on spring-core, spring-beans, spring-context)
Define this if you use Spring MVC, or wish to use Struts, JSF, or another web framework with Spring (org.springframework.web.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Spring MVC for Servlet Environments (depends on spring-core, spring-beans, spring-context, spring-web)
Define this if you use Spring MVC with a Servlet Container such as Apache Tomcat (org.springframework.web.servlet.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Spring MVC for Portlet Environments (depends on spring-core, spring-beans, spring-context, spring-web)
Define this if you use Spring MVC with a Portlet Container (org.springframework.web.portlet.*)
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!--
Support for testing Spring applications with tools such as JUnit and TestNG
This artifact is generally always defined with a 'test' scope for the integration testing framework and unit testing stubs
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
步骤 3)在lib
文件夹中添加两个其他 jar。 如果时间允许,请找到它们的 Maven 依赖项并添加pom.xml
。
jnpserver-5.0.3.GA.jar
org.springframework.jms-3.0.5.RELEASE.jar
步骤 4)从 jboss 发行版复制以下文件,并将其放在类路径中。 或者,只需复制下面给出的文件。
hornetq-configuration.xml
<configuration xmlns="urn:hornetq"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd">
<connectors>
<connector name="netty">
<factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory</factory-class>
<param key="host" value="${hornetq.remoting.netty.host:localhost}"/>
<param key="port" value="${hornetq.remoting.netty.port:5445}"/>
</connector>
</connectors>
<acceptors>
<acceptor name="netty">
<factory-class>org.hornetq.integration.transports.netty.NettyAcceptorFactory</factory-class>
<param key="host" value="${hornetq.remoting.netty.host:localhost}"/>
<param key="port" value="${hornetq.remoting.netty.port:5445}"/>
</acceptor>
</acceptors>
<security-settings>
<security-setting match="#">
<permission type="createTempQueue" roles="guest"/>
<permission type="deleteTempQueue" roles="guest"/>
<permission type="consume" roles="guest"/>
<permission type="send" roles="guest"/>
</security-setting>
</security-settings>
<address-settings>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>jms.queue.DLQ</dead-letter-address>
<expiry-address>jms.queue.ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-size-bytes>-1</max-size-bytes>
<page-size-bytes>10485760</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>
</address-settings>
<paging-directory>${hornetq.data.dir}/paging</paging-directory>
<bindings-directory>${hornetq.data.dir}/bindings</bindings-directory>
<journal-directory>${hornetq.data.dir}/journal</journal-directory>
<large-messages-directory>${hornetq.data.dir}/large-messages</large-messages-directory>
</configuration>
hornetq-jms.xml
<configuration xmlns="urn:hornetq"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd">
<connection-factory name="NettyConnectionFactory">
<connectors>
<connector-ref connector-name="netty"/>
</connectors>
<entries>
<entry name="/ConnectionFactory"/>
<entry name="/XAConnectionFactory"/>
</entries>
</connection-factory>
<queue name="ExampleQueue">
<entry name="/queue/ExampleQueue"/>
</queue>
<topic name="ExampleTopic">
<entry name="/topic/ExampleTopic"/>
</topic>
</configuration>
hornetq-users.xml
<configuration xmlns="urn:hornetq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:hornetq /schema/hornetq-users.xsd">
<!-- the default user. this is used where username is null-->
<defaultuser name="guest" password="guest">
<role name="guest"/>
</defaultuser>
</configuration>
步骤 5)在类路径中复制jndi.properties
。
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
步骤 6)配置记录器,以更好地捕获信息。
# Create a STDOUT appender
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.ConversionPattern=%05p | %m%n
# Default everything to WARN
log4j.rootCategory=WARN, STDOUT
# Enable this application log level to the lowest.
log4j.category.com.howtodoinjava=TRACE
log4j.category.org.jnp.server=INFO
log4j.category.org.hornetq=INFO
log4j.category.org.springframework=INFO
步骤 7)到目前为止,已经配置了 hornetq 服务器和 jndi。 现在,将它们插入spring.xml
和spring.properties
中的 spring 框架。
spring.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:property-placeholder location="classpath:config/server/spring.properties" />
<bean name ="namingServerImpl" class="org.jnp.server.NamingBeanImpl" init-method="start" destroy-method="stop">
</bean>
<!-- JNDI server. Disable this if you don't want JNDI -->
<bean name="namingServer" class="org.jnp.server.Main" init-method="start" destroy-method="stop">
<property name="namingInfo" ref="namingServerImpl"></property>
<property name="port" value="1099"></property>
<property name="bindAddress" value="localhost"></property>
<property name="rmiPort" value="1098"></property>
<property name="rmiBindAddress" value="localhost"></property>
</bean>
<!-- MBean server -->
<bean name="mbeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer">
</bean>
<!-- The core configuration -->
<bean name="fileConfiguration" class="org.hornetq.core.config.impl.FileConfiguration" init-method="start" destroy-method="stop">
</bean>
<!-- The security manager -->
<bean name="hornetQSecurityManagerImpl" class="org.hornetq.spi.core.security.HornetQSecurityManagerImpl">
</bean>
<!-- The core server -->
<bean name="hornetQServerImpl" class="org.hornetq.core.server.impl.HornetQServerImpl">
<constructor-arg ref="fileConfiguration" />
<constructor-arg ref="mbeanServer" />
<constructor-arg ref="hornetQSecurityManagerImpl" />
</bean>
<!-- The JMS server -->
<bean name="jmsServerManagerImpl" class="org.hornetq.jms.server.impl.JMSServerManagerImpl" init-method="start" destroy-method="stop">
<constructor-arg ref="hornetQServerImpl" />
</bean>
<bean name="connectionFactory" class="org.hornetq.jms.client.HornetQConnectionFactory" >
<constructor-arg>
<bean class="org.hornetq.api.core.TransportConfiguration">
<constructor-arg value="org.hornetq.integration.transports.netty.NettyConnectorFactory" />
<constructor-arg>
<map key-type="java.lang.String" value-type="java.lang.Object">
<entry key="port" value="5445"></entry>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean name="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"></property>
</bean>
<bean name="messageProducerClient" class="com.howtodoinjava.hornetq.demo.MessageProducerClient">
<property name="jmsTemplate" ref="jmsTemplate"></property>
</bean>
<bean name="messageConsumerClient" class="com.howtodoinjava.hornetq.demo.MessageConsumerClient">
<property name="jmsTemplate" ref="jmsTemplate"></property>
</bean>
</beans>
spring.properties
hornetq.data.dir=${hornetq.spring.examples.home}/hornetq-data
org.hornetq.logger-delegate-factory-class-name=org.hornetq.integration.logging.Log4jLogDelegateFactory
步骤 8)首先加载 Spring 容器。 它还将验证我们所有的配置文件。
SpringContainerLoader.java
package com.howtodoinjava.hornetq.demo;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringContainerLoader
{
public static FileSystemXmlApplicationContext loadEnvironment()
{
final FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("classpath:config/server/spring.xml");
context.registerShutdownHook();
context.start();
return context;
}
}
步骤 8)现在,我将编写消息生产者和消息使用者客户端。
MessageProducerClient.java
package com.howtodoinjava.hornetq.demo;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.ProducerCallback;
public class MessageProducerClient implements Runnable {
private static Log log = LogFactory.getLog(MessageProducerClient.class);
private static int counter = 1;
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
@Override
public void run() {
jmsTemplate.execute("ExampleQueue", new ProducerCallback<Object>() {
@Override
public Object doInJms(Session session, MessageProducer producer)
throws JMSException {
while (true) {
TextMessage msg = session.createTextMessage("Message number : " + counter++);
log.trace("Sending msg: " + msg);
producer.send(msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}
MessageConsumerClient.java
package com.howtodoinjava.hornetq.demo;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.SessionCallback;
public class MessageConsumerClient implements Runnable {
private static Log log = LogFactory.getLog(MessageConsumerClient.class);
private JmsTemplate jmsTemplate;
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
@Override
public void run()
{
log.info("Message Consumer is just started !!");
boolean startConn = true;
jmsTemplate.execute(new SessionCallback<Object>() {
@Override
public Object doInJms(Session session) throws JMSException {
Queue queue = session.createQueue("ExampleQueue");
MessageConsumer consumer = session.createConsumer(queue);
while (true) {
Message msg = consumer.receive();
log.trace("Received msg: " + msg);
}
}
}, startConn);
}
}
步骤 9)现在该测试整个代码和消息传递功能了。
HornetQMessagingTest.java
package com.howtodoinjava.hornetq.demo;
import org.springframework.context.ApplicationContext;
public class HornetQMessagingTest
{
public static void main(String[] args) throws InterruptedException
{
//Load configurations
ApplicationContext context = SpringContainerLoader.loadEnvironment();
//Start the message producer
new Thread((Runnable)context.getBean("messageProducerClient")).start();
//Start the message consumer
new Thread((Runnable)context.getBean("messageConsumerClient")).start();
}
}
在测试类之上运行会在下面生成日志,以验证 Spring3 和 hornetq 集成成功。
INFO | Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@aa9835: startup date [Mon Mar 25 09:23:26 IST 2013]; root of context hierarchy
INFO | Loading XML bean definitions from class path resource [config/server/spring.xml]
INFO | Loading properties file from class path resource [config/server/spring.properties]
INFO | Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1b4fad5: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,namingServerImpl,namingServer,mbeanServer,fileConfiguration,hornetQSecurityManagerImpl,hornetQServerImpl,jmsServerManagerImpl,connectionFactory,jmsTemplate,messageProducerClient,messageConsumerClient]; root of factory hierarchy
25 Mar, 2013 9:23:28 AM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: live server is starting..
25 Mar, 2013 9:23:28 AM org.hornetq.core.logging.impl.JULLogDelegate warn
WARNING: AIO wasn't located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO to enable the AIO journal
25 Mar, 2013 9:23:28 AM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: Using NIO Journal
25 Mar, 2013 9:23:28 AM org.hornetq.core.logging.impl.JULLogDelegate warn
WARNING: Security risk! It has been detected that the cluster admin user and password have not been changed from the installation default. Please see the HornetQ user guide, cluster chapter, for instructions on how to do this.
25 Mar, 2013 9:23:30 AM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: Started Netty Acceptor version 3.1.5.GA-r1772
25 Mar, 2013 9:23:30 AM org.hornetq.core.logging.impl.JULLogDelegate info
INFO: HornetQ Server version 2.0.0.GA (Hornet Queen, 113) started
INFO | Message Consumer is just started !!
TRACE | Sending msg: HornetQMessage[null]:PERSISTENT
TRACE | Received msg: HornetQMessage[ID:8e74da0e-94ff-11e2-bbba-002564ac1704:0000000000000000]:PERSISTENT
TRACE | Sending msg: HornetQMessage[null]:PERSISTENT
TRACE | Received msg: HornetQMessage[ID:8e74da0e-94ff-11e2-bbba-002564ac1704:1000000000000000]:PERSISTENT
TRACE | Sending msg: HornetQMessage[null]:PERSISTENT
TRACE | Received msg: HornetQMessage[ID:8e74da0e-94ff-11e2-bbba-002564ac1704:2000000000000000]:PERSISTENT
TRACE | Sending msg: HornetQMessage[null]:PERSISTENT
TRACE | Received msg: HornetQMessage[ID:8e74da0e-94ff-11e2-bbba-002564ac1704:3000000000000000]:PERSISTENT
如有任何问题,请先确认以下几点:
- 所有配置文件都在类路径中。
- lib 文件夹中存在的两个 jar 文件包含在类路径中。
作为参考,我给出了目录结构的快照。
祝您学习愉快!
Linux 教程
JStack 线程转储分析器
原文: https://howtodoinjava.com/linux/how-to-get-thread-dump-in-linux-using-jstack/
线程转储是 Java 虚拟机(JVM)中当前活动的所有 Java 线程的列表。 有几种方法可以从 JVM 提取线程转储。 强烈建议在分析任何问题(例如死锁或资源使用情况分析)时采取多个线程转储。 最好在多个线程转储中进行确认,然后单次尝试得出结论。
1.获取 Java 进程的 PID
获得线程转储所需的第一条信息是 Java 进程的 PID。
Java JDK 附带jps
命令,该命令列出了所有 Java 进程 ID。 您可以这样运行此命令:
$ jps -l
记住 – 您可能必须以$ sudo -u jps -l
运行此命令,其中“user
”是正在运行的 Java 进程用户的用户名。
即使现在,如果您仍无法找到进程 ID,请使用以下命令:
$ ps -aef | grep java
2.从 JVM 请求线程转储
如果已安装/可用,我们建议使用 jstack 工具。 它将线程转储打印到命令行控制台。
要使用 jstack 获得线程转储,请运行以下命令:
$ jstack
您可以使用控制台输出redirect/append
伪指令将连续的线程转储输出到文件中:
$ jstack >> threaddumps.log
要点
- 从 JDK 1.5 开始,可以使用 jstack 工具。
- 即使启用了
-Xrs jvm
参数,jstack 也可以工作。 - 无法使用 JDK 1.6 中的 jstack 工具从运行在 JDK 1.5 上的进程中进行线程转储。
3.使用 jstack 脚本以固定的时间间隔进行线程转储采样
这个简单的 Shell 脚本以固定的时间间隔拍摄了几个 jstack 快照(参考文档):
#!/bin/bash
if [ $# -eq 0 ]; then
echo >= 2 "Usage: jstackSeries [ count [ delay ] ]"
echo >= 2 " Defaults: count = 10, delay = 1 (seconds)"
exit 1
fi
pid=$1 # required
count=${2:-10} # defaults to 10 times
delay=${3:-1} # defaults to 1 second
while [ $count -gt 0 ]
do
jstack $pid >jstack.$pid.$(date +%H%M%S.%N)
sleep $delay
let count--
echo -n "."
done
像这样使用上面的脚本:
$ jstackSeries 10 5
4.如何比较两个 JStack 线程转储
要比较线程转储,您可以使用交互式差异查看器,例如:
$ vimdiff file1 file2 file3 file4 # up to 4 files
查看 jstack 跟踪的哪些部分随时间变化的另一种方法是使用$ context diff
(-c 选项)比较相邻的 jstack 跟踪:
d_old=""
for d in jstack.13585.12171*
do
if [ -n "$d_old" ]
then
diff -c "$d_old" "$d"
fi
d_old="$d"
done
在这里,结果仅显示 JStack 线程转储在文件之间更改的位置。
学习愉快!
使用 Java 在 Linux 中管理系统日志文件不超过 N GB
原文: https://howtodoinjava.com/linux/manage-system-log-files-in-linux-using-java/
如今,大多数应用都需要管理自己的日志文件,包括在达到特定大小限制时将其删除。 在本文中,我将尝试为这种日志文件管理提出一种解决方案。 我还将建议捕获 linux 进程的输出并将其记录到一些单独的日志文件中的方法。
本文是我上一篇文章的延续:自动重载配置,其中我讨论了只要有人在文件系统中更改配置文件,应用如何无需重新启动应用即可完成其配置重载的工作。 。
这篇文章中的部分:
- 确定方法
- 编写 bash 脚本
- 编写脚本执行器
- 添加
StreamEater
- 查看全部
确定方法
我相信,要把工作做好,我们肯定需要一个 bash 脚本。 Linux 具有一些非常有用的内置命令,这些命令在通过命令窗口执行时可以立即执行此工作。 bash 脚本的优势包括将实际应用的文件处理器代码解耦,如果需要任何特定于平台的更改,可以对其进行修改。
编写 bash 脚本
我已经编写了一个演示脚本。 您可以根据需要使用它:
#!/bin/bash
###############################################################################
#
# discCleanUp.sh
#
################################################################################
DIR_PATH=$1
NUM_OF_DAYS=$2
DIR_SIZE=$3
SIZE=1024
DIR_SIZE=$(($DIR_SIZE * $SIZE * $SIZE))
# Command to find the File older then NUM_OF_DAYS and removing them from directory DIR_PATH
find $DIR_PATH -mtime +$NUM_OF_DAYS -exec rm {} ;
#Go to specified directory
cd $DIR_PATH
# Command to get the current directory size.
CURR_DIR_SIZE=`du -sk | cut -f1`
while [[ $CURR_DIR_SIZE -gt DIR_SIZE ]];
do
echo $CURR_DIR_SIZE
FILE=`ls -1tra | head -1`
rm -rf $FILE
# Command to get the current directory size.
CURR_DIR_SIZE=`du -sk | cut -f1`
done
exit 0
在上面的脚本中,DIR_PATH
,NUM_OF_DAYS
和DIR_SIZE
是命令行参数。 而SIZE
是用于计算目的的常数。 在上面的脚本中,行号 16 将删除 n 天之前的日志文件。
在行号 22 中,脚本使用du
命令检查目录的当前大小。 如果大小超过DIR_SIZE
(以 GB 为单位),脚本将开始使用ls -1tra | head -1
命令并开始将它们一个一个地删除。 它将继续直到目录大小未达到所需的限制。
编写脚本执行器
至于本文,核心组件将保留在 bash 脚本之上,但仍然需要一种从应用运行*.sh
文件的方法。 最好的方法是使用线程(如果需要,可以使用执行器)。 该线程将以可配置的速率定期执行以上 bash 脚本。 我不会写那部分代码。 如果执行代码时遇到任何问题,请写下评论。
让我给你一个示例代码::
package corejava.dischandler;
import java.io.IOException;
/**
* Title: DiskFileManager.java
* Description :- This class provides API to check file size and file time threshold and
* if threshold is crossed then deletes file to come within threshold.
*/
public final class DiskFileManager
{
private static DiskFileManager diskFileManager=new DiskFileManager();
private DiskFileManager()
{
}
/**
* <pre>
* <b>checkAndDeleteFiles</b>
* <b>Description:This method is called to clean the files from the file system.</b>
* </pre>
* @throws InterruptedException
* @throws IOException
* @throws InstantiationException
*/
public void checkAndDeleteFiles() throws InterruptedException, IOException, InstantiationException
{
try
{
StringBuffer outStr = new StringBuffer();
StringBuffer errStr = new StringBuffer();
String scriptFileName = "./discfilehandler.sh";
String command = scriptFileName + "/logs 1 1";
System.out.println("Command to be executed :- " + command);
Process output = Runtime.getRuntime().exec(command);
StreamEater errorEater = new StreamEater(output.getErrorStream(),errStr);
StreamEater outputEater = new StreamEater(output.getInputStream(),outStr);
errorEater.start();
outputEater.start();
try
{
int ret = output.waitFor();
errorEater.join();
outputEater.join();
System.out.println();
//logger.info("execute(): Error Stream:" + errStr + " ; execute(): Output Stream:" + outStr + " ; execute(): ExitValue:" + ret);
} catch (InterruptedException e)
{
throw e;
}
} catch (IOException e)
{
throw e;
}
}
/**
* <pre>
* <b>getInstance</b>
* <b>Description:This method is used to get the instance of Disk File Manager.</b>
* </pre>
* @return
*/
public static DiskFileManager getInstance()
{
return diskFileManager;
}
}
上面的代码将在类路径中找到脚本文件,并传递所需的参数。 在我们的例子中,“/logs 1 1
”是 3 个参数,这意味着
- 要监视的目录是
/logs
, - 删除一天的日志文件,然后
- 请勿在任何时候存储超过 1 GB 的日志文件。
添加StreamEater
因此,我们已经添加了一个 bash 脚本和一个用于运行脚本的执行器代码。 您必须编写自己的线程才能在执行器上方定期运行。
现在,我们将研究StreamEater
,它实际上收集命令输出并提供给您的应用代码,因此应用可以记录它或执行所需的任何操作。
我们已经在上面的执行器中使用过StreamEater
,现在我给出其代码:
package corejava.dischandler;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class StreamEater extends Thread
{
/**
* Stream Eater thread to eat up every thing that is the output to the
* execute command
*/
private InputStream iStream;
public InputStream getiStream() {
return iStream;
}
public void setiStream(InputStream iStream) {
this.iStream = iStream;
}
private StringBuffer stringBuffer;
public StringBuffer getStringBuffer() {
return stringBuffer;
}
public void setStringBuffer(StringBuffer stringBuffer) {
this.stringBuffer = stringBuffer;
}
/**
* This is the constructor.
*
* @param is - It is the input stream
* @param type - type of input stream
* @param redirect - string buffer to contain the output.
* @throws InstantiationException
*/
public StreamEater(InputStream is, StringBuffer redirect) throws InstantiationException
{
this.iStream = is;
if (redirect == null)
{
throw new InstantiationException("String Buffer Reference , second param can not be null");
}
this.stringBuffer = redirect;
}
/**
* This is method called when the thread is started. It captures the stream
* output and and store it into the buffer.
*/
public void run()
{
InputStreamReader isr = null;
BufferedReader br = null;
try
{
isr = new InputStreamReader(iStream);
br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null)
{
stringBuffer.append(line).append(System.getProperty("line.separator"));
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
if (isr != null)
{
try
{
isr.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
if (br != null)
{
try
{
br.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
}
如您所见,这些都是等待收集进程输出的小线程。
查看全部
使用上述类和给定的 bash 脚本,您可以轻松开发一些应用组件,以确保日志文件的大小不超过某些预定义的数目。 当您的应用负责删除实际的日志文件时,可以在任何级别对其进行自定义。
希望您在这篇文章中得到一些有用的信息。 如果需要任何帮助或有任何疑问,请给我写信。
学习愉快!
Swagger – Spring REST 示例
原文: https://howtodoinjava.com/swagger2/swagger-spring-mvc-rest-example/
如今, REST 和微服务势头强劲。 同时,实际的 REST 规范并未建议任何标准方法来记录我们将要公开的 REST API(例如 WSDL for SOAP)。 结果,每个人都以自己的方式记录自己的 API,从而导致通用结构中的空白,所有这些都可以轻松地遵循,理解和使用。 我们需要一个通用的模式和工具。
Swagger(得到了 Google,IBM,Microsoft 等公司的支持)完成了相同工作,以填补常见文档样式的空白。 在本教程中,我们将学习使用 Swagger 来使用 swagger2 注解来生成 REST API 文档。
Table of Contents
What is Swagger
Project Structure and Technology Stack
Create REST APIs
Swagger2 Configuration
Swagger2 Annotations
Demo
Swagger
Swagger(现为“Open API Initiative”)是一种规范和框架,用于使用所有人都可以理解的通用语言来描述 REST API。 还有其他一些流行的框架,例如 RAML,Summation 等。但是,考虑到它的功能和在开发者社区中的接受程度,Swagger 在这一点上最受欢迎。
它提供了人类可读和机器可读的文档格式。 它同时提供 JSON 和 UI 支持。 JSON 可以用作机器可读格式,Swagger-UI
用于可视化显示,人类只需浏览 api 文档即可轻松理解。
项目结构与技术栈
项目的文件夹结构为:
Swagger2 项目结构
在本演示中,我们将使用以下技术。
- Eclipse 作为 IDE
- Maven 作为构建工具
- Spring Boot 作为应用框架
- Spring Rest 作为 REST API 框架
- Swagger2 作为 REST 文档框架
- Java 1.8
创建 REST API
我们将首先创建一些 REST API,这些 API 将用于展示 Swagger 文档功能。 我们将使用 Spring 引导样式公开剩余的 API,以缩短开发时间。
-
从具有 Web,Rest Repositories,Actuator 依赖项的 Spring Boot 初始化器门户创建一个 Spring Boot 项目。 给出其他 Maven GAV 坐标并下载项目。 该屏幕如下所示:
Spring Boot REST 项目生成
将项目解压缩并将其作为现有的 maven 项目导入 Eclipse。 在此步骤中,将从 maven 仓库下载所有必需的依赖项。 在此步骤中执行全新的
mvn clean install
,以便正确下载所有与 Spring Boot 相关的工件。 -
打开
application.properties
并添加以下属性。 这将在/swagger2-demo
上下文路径中启动应用。server.contextPath=/swagger2-demo
-
添加一个 REST 控制器“
Swagger2DemoRestController
”,该控制器将在“Student
”实体上提供基于 REST 的基本功能。Swagger2DemoRestController.java
package com.example.springbootswagger2.controller; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.example.springbootswagger2.model.Student; @RestController public class Swagger2DemoRestController { List<Student> students = new ArrayList<Student>(); { students.add(new Student("Sajal", "IV", "India")); students.add(new Student("Lokesh", "V", "India")); students.add(new Student("Kajal", "III", "USA")); students.add(new Student("Sukesh", "VI", "USA")); } @RequestMapping(value = "/getStudents") public List<Student> getStudents() { return students; } @RequestMapping(value = "/getStudent/{name}") public Student getStudent(@PathVariable(value = "name") String name) { return students.stream().filter(x -> x.getName().equalsIgnoreCase(name)).collect(Collectors.toList()).get(0); } @RequestMapping(value = "/getStudentByCountry/{country}") public List<Student> getStudentByCountry(@PathVariable(value = "country") String country) { System.out.println("Searching Student in country : " + country); List<Student> studentsByCountry = students.stream().filter(x -> x.getCountry().equalsIgnoreCase(country)) .collect(Collectors.toList()); System.out.println(studentsByCountry); return studentsByCountry; } @RequestMapping(value = "/getStudentByClass/{cls}") public List<Student> getStudentByClass(@PathVariable(value = "cls") String cls) { return students.stream().filter(x -> x.getCls().equalsIgnoreCase(cls)).collect(Collectors.toList()); } }
Student.java
package com.example.springbootswagger2.model; public class Student { private String name; private String cls; private String country; public Student(String name, String cls, String country) { super(); this.name = name; this.cls = cls; this.country = country; } public String getName() { return name; } public String getCls() { return cls; } public String getCountry() { return country; } @Override public String toString() { return "Student [name=" + name + ", cls=" + cls + ", country=" + country + "]"; } }
-
作为 Spring Boot 应用启动该应用。 测试几个 REST 端点,以检查它们是否工作正常:
http://localhost:8080/swagger2-demo/getStudents
http://localhost:8080/swagger2-demo/getStudent/sajal
http://localhost:8080/swagger2-demo/getStudentByCountry/india
http://localhost:8080/swagger2-demo/getStudentByClass/v
Swagger2 配置
我们的 REST API 已准备就绪。 现在将 swagger2 支持添加到project.ff
添加 Swagger2 Maven 依赖项
打开spring-boot-swagger2
项目的pom.xml
文件,并在下面添加两个与 swagger 相关的依赖项,即springfox-swagger2
和springfox-swagger-ui
。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
实际上,swagger
API 具有多种变体,并且维护在不同的工件中。 今天,我们将使用springfox
,因为该版本可以很好地适应任何基于 spring 的配置。 我们还可以轻松地尝试其他配置,并且应该提供相同的功能-无需更改/只需稍作更改即可。
添加 Swagger2 配置
在代码库中添加以下配置。 为了帮助您理解配置,我添加了嵌入式注解。
package com.example.springbootswagger2.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.google.common.base.Predicates;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2UiConfiguration extends WebMvcConfigurerAdapter
{
@Bean
public Docket api() {
// @formatter:off
//Register the controllers to swagger
//Also it is configuring the Swagger Docket
return new Docket(DocumentationType.SWAGGER_2).select()
// .apis(RequestHandlerSelectors.any())
.apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.boot")))
// .paths(PathSelectors.any())
// .paths(PathSelectors.ant("/swagger2-demo"))
.build();
// @formatter:on
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
//enabling swagger-ui part for visual documentation
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
验证 Swagger2 JSON 格式文档
执行 maven 并启动服务器。 打开链接http://localhost:8080/swagger2-demo/v2/api-docs
,它应该以JSON
格式提供整个文档。 这并不是那么容易阅读和理解,实际上 Swagger 已经提供了将其用于其他系统中的功能,例如如今流行的 API 管理工具,它提供了 API 网关,API 缓存,API 文档等功能。
JSON 文档
验证 Swagger2 UI 文档
打开http://localhost:8080/swagger2-demo/swagger-ui.html
在浏览器中查看 Swagger UI 文档。
Swagger2 UI 文档(无注解)
Swagger2 注解
默认生成的 API 文档很好,但是缺少详细的 API 级别信息。 Swagger 提供了一些注解,可以将这些详细信息添加到 API。 例如:
-
@Api
– 我们可以将此注解添加到控制器,以添加有关控制器的基本信息。@Api(value = "Swagger2DemoRestController", description = "REST APIs related to Student Entity!!!!") @RestController public class Swagger2DemoRestController { ... }
-
@ApiOperation
和@ApiResponses
– 我们可以将这些注解添加到控制器中的任何 rest 方法,以添加与该方法有关的基本信息。 例如:@ApiOperation(value = "Get list of Students in the System ", response = Iterable.class, tags = "getStudents") @ApiResponses(value = { @ApiResponse(code = 200, message = "Success|OK"), @ApiResponse(code = 401, message = "not authorized!"), @ApiResponse(code = 403, message = "forbidden!!!"), @ApiResponse(code = 404, message = "not found!!!") }) @RequestMapping(value = "/getStudents") public List<Student> getStudents() { return students; }
在这里,我们可以将
tags
添加到方法中,以在swagger-ui
中添加一些分组。 -
@ApiModelProperty
– 在 Model 属性中使用此注解可为该 Model 属性的 Swagger 输出添加一些描述。 例如:@ApiModelProperty(notes = "Name of the Student",name="name",required=true,value="test name") private String name;
添加 swagger2 注解后的控制器和模型类代码。
Swagger2DemoRestController.java
package com.example.springbootswagger2.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.springbootswagger2.model.Student;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
@Api(value = "Swagger2DemoRestController", description = "REST Apis related to Student Entity!!!!")
@RestController
public class Swagger2DemoRestController {
List<Student> students = new ArrayList<Student>();
{
students.add(new Student("Sajal", "IV", "India"));
students.add(new Student("Lokesh", "V", "India"));
students.add(new Student("Kajal", "III", "USA"));
students.add(new Student("Sukesh", "VI", "USA"));
}
@ApiOperation(value = "Get list of Students in the System ", response = Iterable.class, tags = "getStudents")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Suceess|OK"),
@ApiResponse(code = 401, message = "not authorized!"),
@ApiResponse(code = 403, message = "forbidden!!!"),
@ApiResponse(code = 404, message = "not found!!!") })
@RequestMapping(value = "/getStudents")
public List<Student> getStudents() {
return students;
}
@ApiOperation(value = "Get specific Student in the System ", response = Student.class, tags = "getStudent")
@RequestMapping(value = "/getStudent/{name}")
public Student getStudent(@PathVariable(value = "name") String name) {
return students.stream().filter(x -> x.getName().equalsIgnoreCase(name)).collect(Collectors.toList()).get(0);
}
@ApiOperation(value = "Get specific Student By Country in the System ", response = Student.class, tags = "getStudentByCountry")
@RequestMapping(value = "/getStudentByCountry/{country}")
public List<Student> getStudentByCountry(@PathVariable(value = "country") String country) {
System.out.println("Searching Student in country : " + country);
List<Student> studentsByCountry = students.stream().filter(x -> x.getCountry().equalsIgnoreCase(country))
.collect(Collectors.toList());
System.out.println(studentsByCountry);
return studentsByCountry;
}
// @ApiOperation(value = "Get specific Student By Class in the System ",response = Student.class,tags="getStudentByClass")
@RequestMapping(value = "/getStudentByClass/{cls}")
public List<Student> getStudentByClass(@PathVariable(value = "cls") String cls) {
return students.stream().filter(x -> x.getCls().equalsIgnoreCase(cls)).collect(Collectors.toList());
}
}
Student.java
package com.example.springbootswagger2.model;
import io.swagger.annotations.ApiModelProperty;
public class Student
{
@ApiModelProperty(notes = "Name of the Student",name="name",required=true,value="test name")
private String name;
@ApiModelProperty(notes = "Class of the Student",name="cls",required=true,value="test class")
private String cls;
@ApiModelProperty(notes = "Country of the Student",name="country",required=true,value="test country")
private String country;
public Student(String name, String cls, String country) {
super();
this.name = name;
this.cls = cls;
this.country = country;
}
public String getName() {
return name;
}
public String getCls() {
return cls;
}
public String getCountry() {
return country;
}
@Override
public String toString() {
return "Student [name=" + name + ", cls=" + cls + ", country=" + country + "]";
}
}
演示
现在,在正确注解我们的 REST API 之后,我们来看一下最终输出。 打开http://localhost:8080/swagger2-demo/swagger-ui.html
在浏览器中查看 Swagger ui 文档。
Swagger2 REST API 最终输出
这一切都将通过 Spring Boot 应用 swagger2 创建 REST API 文档。 将我的问题放在评论部分。
学习愉快!
GoF 设计模式
设计模式
原文: https://howtodoinjava.com/gang-of-four-java-design-patterns/
顾名思义,设计模式是设计软件时最常见(和最常见)的问题的解决方案。 这些模式大多是“进化的”而不是“发现的”。 这些设计模式总结了许多专业人士的大量学习成果。 这些模式都没有强迫您执行任何东西。 它们只是在特定情况下以特定方式解决特定问题的指南。 代码实现是您的责任。
非常重要,让我们更详细地学习这些设计模式(在 Java 上下文中)。
1.创建型设计模式
创建型模式通常用于代替构造器的直接实例化。 它们使创建过程更具适应性和动态性。 特别是,它们可以为创建哪些对象,如何创建这些对象以及如何对其进行初始化提供很大的灵活性。
设计模式名称 | 目的 |
---|---|
构建器 | 构建器设计模式是构建复杂对象的另一种方法,仅当我们希望使用相同的对象构建过程构建不同类型的不可变对象时,才应使用构建器设计模式。 |
原型 | 原型设计模式用于应用需要创建大量类的实例的情况,这些实例的状态几乎相同或相差很小。 |
工厂 | 当涉及复杂的对象创建步骤时,工厂设计模式最合适。 为了确保这些步骤是集中的,并且不暴露于组成类。 |
抽象工厂 | 每当我们需要对使用工厂模式创建的一组工厂进行另一个抽象级别时,就会使用抽象工厂模式。 |
单例 | 单例使应用每个 JVM 具有一个类的一个实例。 |
2.结构型设计模式
结构型设计模式向我们展示了如何以灵活和可扩展的方式将系统的不同部分粘合在一起。 这些模式帮助我们确保当其中一部分发生更改时,整个应用结构都不需要更改。
设计模式名称 | 目的 |
---|---|
适配器 | 适配器将类的接口转换为客户端期望的另一个接口。 它可以让类因接口不兼容而无法一起工作。 |
桥接 | 桥接器设计模式用于将一个类分解为两部分 - 抽象和实现 – 以便将来可以相互进化而不会相互影响。 它增加了类抽象与其实现之间的松散耦合。 |
组合 | 组合设计模式有助于将对象组合成树形结构,以表示整个部分的层次结构。 组合可以使客户统一对待单个对象和对象组成。 |
装饰器 | 装饰器设计模式用于向类的特定实例添加其他功能或行为,而不会修改同一类的其他实例。 |
外观 | 外观设计模式为子系统中的一组接口提供了统一的接口。 外观定义了一个更高级别的接口,使子系统更易于使用。 |
享元 | 享元设计模式允许使用对象共享,以有效支持大量细粒度的对象。 享元是一个共享对象,可以同时在多个上下文中使用。 享元在每种情况下都充当独立对象。 |
代理 | 在代理设计模式中,代理对象为另一个对象提供代理或占位符,以控制对其的访问。 代理大量用于实现与延迟加载相关的用例,在这种情况下,我们直到真正需要时才创建完整的对象。 |
3.行为型设计模式
行为型模式抽象了我们要对采取该操作的对象或类采取的操作。 通过更改对象或类,我们可以更改所使用的算法,受影响的对象或行为,同时仍为客户端类保留相同的基本接口。
设计模式名称 | 目的 |
---|---|
责任链 | 责任链设计模式通过以链的形式将接收对象链接在一起,为多个对象提供了处理请求的机会。 |
命令 | 命令设计模式对于将业务逻辑抽象为离散的动作(我们称为命令)很有用。 这些命令对象有助于两个类之间的松散耦合,其中一个类(调用者)应调用另一类(接收者)上的方法来执行业务操作。 |
解释器 | 解释器模式指定如何以编程方式求值一种语言的句子。 它有助于为一种简单的语言建立语法,以便可以解释该语言中的句子。 |
迭代器 | 迭代器模式提供了一种在不暴露其基础表示的情况下顺序访问聚合对象的元素的方法。 |
中介者 | 中介者模式定义了一个对象,该对象封装了一组对象之间的交互方式。 中介者通过防止对象之间显式地相互引用来促进松散耦合,并且它使我们可以独立地更改其交互。 |
备忘录 | 备忘录模式用于将对象的状态恢复到先前的状态。 也称为快照模式。 |
观察者 | 观察者模式定义了对象之间的一对多依赖关系,因此当一个对象改变状态时,其所有依赖关系都会得到通知并自动更新。 它也称为发布 - 订阅模式。 |
状态 | 在状态模式下,对象可以在其内部状态更改时更改其行为。 该对象似乎将更改其类。 每个对象的可能状态应有一个单独的具体类。 |
策略 | 当我们在运行时从算法的多个其他实现中选择特定的算法或任务实现时,将使用策略模式。 |
模板方法 | 模板方法模式定义了执行多步算法的顺序步骤,并且还可以选择提供默认实现(基于需求)。 |
访问者 | 当我们希望对象的层次结构修改其行为但不修改其源代码时,将使用访问者模式。 |
学习愉快!
创建型设计模式
在软件工程中,创建型设计模式是处理对象创建机制的设计模式,试图以适合情况的方式创建对象。 创造型设计模式由两个主要思想组成。 一种是封装有关系统使用哪些具体类的知识。 另一个是隐藏如何创建和组合这些具体类的实例。
创建型模式旨在将系统与对象的创建,组成和表示方式分开。 它们在创建对象的内容,对象,方式和时间方面增加了系统的灵活性。
在以下情况下,请考虑应用创建型模式:
- 系统应独立于其对象和产品的创建方式。
- 一组相关的对象设计为可以一起使用。
- 隐藏类库或产品的实现,仅显示其接口。
- 构造独立复杂对象的不同表示形式。
- 类希望其子类实现其创建的对象。
- 类实例是在运行时指定的。
- 必须有一个实例,客户端可以随时访问该实例。
- 实例应该是可扩展的,无需进行修改。
Java 单例模式介绍
原文: https://howtodoinjava.com/design-patterns/creational/singleton-design-pattern-in-java/
单例模式是一种设计解决方案,其中应用希望在所有可能的情况下都具有一个且只有一个任何类的实例,而没有任何特殊情况。 在 Java 社区中,关于使任何类单例化的可能方法已经争论了很长时间。 不过,您会发现人们对您提供的任何解决方案都不满意。 它们也不能被否决。 在这篇文章中,我们将讨论一些好的方法,并将尽我们最大的努力。
Table of Contents:
1\. Singleton with eager initialization
2\. Singleton with lazy initialization
3\. Singleton with static block initialization
4\. Singleton with bill pugh solution
5\. Singleton using Enum
6\. Add readResolve() to singleton objects
7\. Add serialVersionUID to singleton objects
8\. Conclusion
单例术语是从其数学对应术语中得出的。 如上所述,它希望我们每个上下文只有一个实例。 在 Java 中,每个 JVM 一个实例。
让我们看一下在 Java 中创建单例对象的可能解决方案。
1.立即初始化的单例
这是一种设计模式,其中的类实例实际上是在实际需要之前创建的。 通常,它是在系统启动时完成的。 在热切的初始化单例模式中,无论是否有其他类实际请求其实例,都将创建该单例实例。
public class EagerSingleton {
private static volatile EagerSingleton instance = new EagerSingleton();
// private constructor
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
上面的方法很好用,但是有一个缺点。 不论是否在运行时都需要创建实例。 如果此实例不是大对象,并且您可以在不使用它的情况下生存下去,那么这是最好的方法。
让我们用下一种方法解决上述问题。
2.延迟初始化的单例
在计算机编程中,延迟初始化是将对象的创建,值的计算或其他昂贵的过程推迟到第一次使用时的策略。 在单例模式中,它将限制实例的创建,直到首次请求该实例为止。 让我们在代码中看到这一点:
public final class LazySingleton {
private static volatile LazySingleton instance = null;
// private constructor
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
instance = new LazySingleton();
}
}
return instance;
}
}
第一次调用时,上述方法将检查是否已使用instance
变量创建了实例。 如果没有实例,即实例为null
,它将创建一个实例并返回其引用。 如果实例已经创建,它将仅返回实例的引用。
但是,这种方法也有其自身的缺点。 让我们看看如何。 假设有两个线程 T1 和 T2。 两者都来创建实例并检查是否“instance==null”
。 现在,两个线程都将实例变量标识为 null,因此它们都假定必须创建一个实例。 他们依次进入同步块并创建实例。 最后,我们的应用中有两个实例。
可以使用双检锁解决此错误。 该原理告诉我们在同步块中再次重新检查实例变量,如下所示:
public class LazySingleton {
private static volatile LazySingleton instance = null;
// private constructor
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
// Double check
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
上面的代码是单例模式的正确实现。
请确保对实例变量使用volatile
关键字,否则您可能会遇到乱码的错误情况,在实例实际构造对象之前返回实例的引用,即 JVM 仅分配了内存,而构造器代码仍未执行。 在这种情况下,引用未初始化对象的其他线程可能会引发空指针异常,甚至可能使整个应用崩溃。
3.使用静态块初始化的单例
如果您对类的加载顺序有所了解,则可以使用以下事实:即使在调用构造器之前,也要在类的加载期间执行静态块。 我们可以在单例模式中使用此功能,如下所示:
public class StaticBlockSingleton {
private static final StaticBlockSingleton INSTANCE;
static {
try {
INSTANCE = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException("Uffff, i was not expecting this!", e);
}
}
public static StaticBlockSingleton getInstance() {
return INSTANCE;
}
private StaticBlockSingleton() {
// ...
}
}
上面的代码有一个缺点。 假设一个类中有 5 个静态字段,并且应用代码只需要访问 2 或 3,那么根本不需要创建实例。 因此,如果我们使用此静态初始化,尽管没有要求,我们将创建一个实例。
下一节将克服此问题。
4. 单例与 Bill Pugh 解决方案
Bill Pugh 是 java 内存模型更改背后的主要力量。 他的原则“按需初始化持有人惯例”也使用了静态块的想法,但方式有所不同。 建议使用静态内部类。
public class BillPughSingleton {
private BillPughSingleton() {
}
private static class LazyHolder {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return LazyHolder.INSTANCE;
}
}
如您所见,在需要实例之前,LazyHolder
类直到需要时才会初始化,您仍然可以使用BillPughSingleton
类的其他静态成员。 这是解决方案,我建议使用。 我在所有项目中都使用了它。
5.使用枚举的单例
这种类型的实现使用枚举。 枚举(如 java 文档中所写)为线程安全提供了隐式支持,并且仅保证了一个实例。 Java 枚举单例也是使单例花费最少的好方法。
public enum EnumSingleton {
INSTANCE;
public void someMethod(String param) {
// some class member
}
}
6.将readResolve()
添加到单例对象
到目前为止,您必须已经决定如何实现单例。 现在,让我们看看即使在面试中也可能出现的其他问题。
假设您的应用是分布式的,并且经常将对象序列化到文件系统中,直到以后需要时才读取它们。 请注意,反序列化总是创建一个新实例。 我们来看一个例子:
我们的单例类是:
public class DemoSingleton implements Serializable {
private volatile static DemoSingleton instance = null;
public static DemoSingleton getInstance() {
if (instance == null) {
instance = new DemoSingleton();
}
return instance;
}
private int i = 10;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
让我们对该类进行序列化,并在进行一些更改后对其进行反序列化:
public class SerializationTest {
static DemoSingleton instanceOne = DemoSingleton.getInstance();
public static void main(String[] args) {
try {
// Serialize to a file
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
"filename.ser"));
out.writeObject(instanceOne);
out.close();
instanceOne.setI(20);
// Serialize to a file
ObjectInput in = new ObjectInputStream(new FileInputStream(
"filename.ser"));
DemoSingleton instanceTwo = (DemoSingleton) in.readObject();
in.close();
System.out.println(instanceOne.getI());
System.out.println(instanceTwo.getI());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Output:
20
10
不幸的是,两个变量的变量“i
”的值不同。 显然,该类有两个实例。 因此,我们再次遇到应用中多个实例的相同问题。
要解决此问题,我们需要在DemoSingleton
类中包含readResolve()
方法。 当您反序列化对象时,将调用此方法。 在此方法的内部,必须返回现有实例以确保整个实例应用范围。
public class DemoSingleton implements Serializable {
private volatile static DemoSingleton instance = null;
public static DemoSingleton getInstance() {
if (instance == null) {
instance = new DemoSingleton();
}
return instance;
}
protected Object readResolve() {
return instance;
}
private int i = 10;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
现在,当您执行类SerializationTest
时,它将为您提供正确的输出。
20
20
7.将serialVersionUId
添加到单例对象
到目前为止,一切都很好。 到目前为止,我们已经解决了同步和序列化这两个问题。 现在,我们距正确而完整的实现仅一步之遥。 唯一缺少的部分是序列号。
在您的类结构在序列化和反序列化之间更改的情况下,这是必需的。 更改的类结构将导致 JVM 在反序列化过程中给出异常。
java.io.InvalidClassException: singleton.DemoSingleton; local class incompatible: stream classdesc serialVersionUID = 5026910492258526905, local class serialVersionUID = 3597984220566440782
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at singleton.SerializationTest.main(SerializationTest.java:24)
仅通过向类添加唯一的串行版本 ID 即可解决此问题。 通过告诉两个类相同,这将防止编译器引发异常,并且仅加载可用的实例变量。
8.结论
在讨论了许多可能的方法和其他可能的错误情况之后,我将向您推荐以下代码模板,以设计您的单例类,该类应确保在上述所有情况下,整个应用中仅一个类的实例。
public class DemoSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private DemoSingleton() {
// private constructor
}
private static class DemoSingletonHolder {
public static final DemoSingleton INSTANCE = new DemoSingleton();
}
public static DemoSingleton getInstance() {
return DemoSingletonHolder.INSTANCE;
}
protected Object readResolve() {
return getInstance();
}
}
我希望这篇文章有足够的信息来帮助您了解单例模式和单例最佳实践的最常用方法。 让我知道你的想法。
学习愉快!
实时单例示例 – 我只是想添加一些示例,以供进一步研究和在面试中提及:
Java 中的构建器设计模式
原文: https://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/
顾名思义, 构建器模式是构建复杂对象的替代方法。 仅当您要使用相同的对象构建过程构建不同的不可变对象时,才应使用此方法。
在开始讨论之前,我想弄清楚我将在本文中讨论的构建器模式与 GOF“设计模式”书中提到的稍有不同。 这本书说:
构建器模式是一种设计模式,它允许使用正确的操作顺序逐步创建复杂的对象。 构造由导向对象控制,该导向对象仅需要知道要创建的对象的类型。
本书给出如下示例:
我真的很难在现实生活中的编程和应用中利用以上示例。 上面的过程与抽象工厂模式非常相似(并非完全相似),在该模式中,您找到了特定类型对象的工厂(或构建器),然后工厂为您提供了具体的 该对象的实例。 这个构建器模式与抽象工厂模式之间唯一的不同之处在于,构建器为您提供了对对象创建过程的更多控制,仅此而已。 除此之外,没有重大差异。
一句话,抽象工厂模式是对“WHAT
”的回答,而构建器模式是对“HOW
”的回答。
对我来说,构建器模式更像流利的接口 。 通常使用方法级联(或方法链接)来实现流利的接口。
现在,从这里开始,我将以我认为在实际情况下特别有用的方式来讨论构建器模式。 我也希望说服你们。
Sections in this post:
Definition of Builder Pattern
Where we need Builder Pattern
A sample implementation using Builder Pattern
Existing implementations in JDK
Benefits and Advantages
Costs and Disadvantages
Conclusion
构建器模式的定义
首先,给构建器模式一个定义:
构建器模式的目标是“将复杂对象的构造与其表示分开,以便同一构造过程可以创建不同的表示。”
我们需要构建器模式的地方
我们已经知道不可变和不可变实例在应用中的好处。 如果对此有任何疑问,请让我想起 Java 中的String
类。 正如我已经说过的那样,构建器模式可以帮助我们创建具有大量状态属性的不可变类。
让我们讨论一下我们应用中的一个常见问题。 假设在任何用户管理模块中,主要实体都是User
。 理想情况下,实际上,一旦完全创建了用户对象,您就不想更改其状态。 根本没有道理,对吧? 现在,假设我们的User
对象具有以下 5 个属性,即firstName
,lastName
,age
,phone
和address
。
在通常的实践中,如果要创建不可变的User
类,则必须将所有五个信息作为参数传递给构造器。 它看起来像这样:
public User (String firstName, String lastName, int age, String phone, String address){
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.phone = phone;
this.address = address;
}
很好。 现在,如果只有firstName
和lastName
是必不可少的,剩下的 3 个字段是可选的,该怎么办。 问题! 我们需要更多的构造器。
public User (String firstName, String lastName, int age, String phone){ ... }
public User (String firstName, String lastName, String phone, String address){ ... }
public User (String firstName, String lastName, int age){ ... }
public User (String firstName, String lastName){ ... }
我们将需要更多类似上面的内容。 还能管理吗? 现在,让我们介绍我们的第六个属性,即薪水。 现在是问题。
一种创建更多构造器的方法,另一种方法是放松不变性并引入设置器方法。 您选择这两个选项中的任何一个,就松了点,对吧?
在这里,构建器模式将帮助您使用其他属性,同时保留 Use 类的不变性。
使用构建器模式的示例实现
下面是我们上面讨论的问题的编码解决方案。 这使用附加的类UserBuilder
,该类可帮助我们构建具有所有必需属性和可选属性组合的所需User
对象,而不会失去不变性。
public class User
{
//All final attributes
private final String firstName; // required
private final String lastName; // required
private final int age; // optional
private final String phone; // optional
private final String address; // optional
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
//All getter, and NO setter to provde immutability
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return "User: "+this.firstName+", "+this.lastName+", "+this.age+", "+this.phone+", "+this.address;
}
public static class UserBuilder
{
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address;
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
//Return the finally consrcuted User object
public User build() {
User user = new User(this);
validateUserObject(user);
return user;
}
private void validateUserObject(User user) {
//Do some basic validations to check
//if user object does not break any assumption of system
}
}
}
下面是方法,我们将在代码中使用UserBuilder
:
public static void main(String[] args) {
User user1 = new User.UserBuilder("Lokesh", "Gupta")
.age(30)
.phone("1234567")
.address("Fake address 1234")
.build();
System.out.println(user1);
User user2 = new User.UserBuilder("Jack", "Reacher")
.age(40)
.phone("5655")
//no address
.build();
System.out.println(user2);
User user3 = new User.UserBuilder("Super", "Man")
//No age
//No phone
//no address
.build();
System.out.println(user3);
}
Output:
User: Lokesh, Gupta, 30, 1234567, Fake address 1234
User: Jack, Reacher, 40, 5655, null
User: Super, Man, 0, null, null
请注意,上面创建的用户对象没有任何设置方法,因此一旦建立,便无法更改其状态。 这提供了所需的不变性。
有时,开发人员将属性添加到User
类时,可能会忘记为构建器添加对新属性的支持。 为了最大程度地减少这种情况,我们应该将构建器封装在它们所构建的类中(如上例所示),以使开发人员更清楚地知道也需要更新一个相关的构建器。
有时,我认为应该有一个驱逐舰模式(与构建器相对),该模式应该以系统的方式从复杂对象中拆除某些属性。 你怎么看?
JDK 中的现有实现
java.lang.Appendable
的所有实现实际上都是在 Java 中使用 Builder 模式的良好示例。 例如:
java.lang.StringBuilder#append()
[未同步的类]
java.lang.StringBuffer#append()
[同步类]
java.nio.ByteBuffer#put()
(也在 CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer 和 DoubleBuffer 上)
另一种用法可以在javax.swing.GroupLayout.Group#addComponent()
中找到。
看看这些实现与我们上面讨论的相似。
StringBuilder builder = new StringBuilder("Temp");
String data = builder.append(1)
.append(true)
.append("friend")
.toString();
System.out.println(data);
Output:
Temp1truefriend
构建器模式的优点和好处
毫无疑问,在构建器模式中,代码行数增加了至少增加了一倍,但是在设计灵活性和更多可读代码方面,努力得到了回报 。 构造器的参数被简化,并在高可读性方法调用中提供。
构建器模式还有助于最大程度地减少构造器中的参数数量,因此不需要将可选参数的null
传递给构造器。 真的吸引了我
另一个好处是,对象总是以complete
状态实例化,而不是处于不完整的状态,直到开发人员调用(如果曾经调用)适当的设置器方法来设置其他字段。
最后,我可以在对象构建过程中构建不可变对象,而无需太多复杂的逻辑。
构建器模式的成本与缺点
尽管构建器模式减少了一些代码行,从而消除了使用设置器方法的需要,但仍然通过引入构建器对象使总行数翻了一番。 此外,尽管客户代码更具可读性,但客户代码也更为冗长。 虽然对我而言,可读性比代码行更重要。
我能想到的唯一缺点。
仅此而已。 如果您也分享您的想法,我会很高兴。
祝您学习愉快!
参考文献
http://en.wikipedia.org/wiki/Builder_pattern
http://www.javaspecialists.eu/archive/Issue163.html
http://en.wikipedia.org/wiki/Fluent_interface
http://martinfowler.com/bliki/FluentInterface.html
Java 工厂模式说明
原文: https://howtodoinjava.com/design-patterns/creational/implementing-factory-design-pattern-in-java/
在 Java 中创建类实例的最常用方法是什么? 大多数人会回答这个问题:“使用new
新关键字”。 好吧,它现在被认为是老式的。 让我们看看如何?
如果对象创建代码散布在整个应用中,并且如果您需要更改对象创建过程,则需要在每个地方进行必要的更改。 在完成本文之后,在编写应用时,请考虑使用 Java 工厂模式。
在我以前的文章“ Java 中的 单例设计模式”中,我们讨论了创建类实例的各种方法,以使同一 JVM 中不存在同一类的另一个实例。
在这篇文章中,我将演示另一个创建型模式,即工厂模式,用于为您的类创建实例。 顾名思义,工厂是一个创建一些不同产品的地方,这些产品在功能上有些相似,但又分为几类。
在 Java 中,工厂模式用于创建相同类型的不同类的实例。
Table of Contents
1\. When to implement factory pattern?
2\. Factory Pattern Implementation
3\. Advantages of factory pattern
4\. Final notes
1.什么时候使用工厂模式?
工厂模式引入了类之间的松散耦合,这是在设计应用架构时应考虑并应用的最重要的原则。 通过针对抽象实体(而不是具体的实现)进行编程,可以在应用架构中引入松耦合。 这不仅使我们的架构更加灵活,而且不那么脆弱。
一张图片胜过千言万语。 让我们看看工厂实现的样子。
上图以汽车工厂为例描述了一种常见情况,该工厂能够制造 3 种类型的汽车,即小型,轿车和豪华型汽车。 制造汽车需要从分配配件到最终化妆的许多步骤。 这些步骤可以作为方法编写在程序中,并在创建特定汽车类型的实例时调用。
如果很不幸,那么我们将在我们的应用类中创建汽车类型的实例(例如SmallCar
),因此我们会将汽车制造逻辑暴露给外界,这当然不好。 这也阻止了我们对汽车制造过程的更改,因为代码不是集中的,并且在所有组成类中进行更改似乎都不可行。
2. Java 工厂模式示例
到目前为止,我们已经设计了用于制造CarFactory
的类。 现在创建它们。
2.1 对象类型
CarType
将保留汽车类型,并将为所有其他类别提供汽车类型。
package designPatterns.creational.factory;
public enum CarType {
SMALL, SEDAN, LUXURY
}
2.2 对象实现
Car
是所有汽车实例的父类,并且还将包含适用于所有类型汽车的通用逻辑。
package designPatterns.creational.factory;
public abstract class Car {
public Car(CarType model) {
this.model = model;
arrangeParts();
}
private void arrangeParts() {
// Do one time processing here
}
// Do subclass level processing in this method
protected abstract void construct();
private CarType model = null;
public CarType getModel() {
return model;
}
public void setModel(CarType model) {
this.model = model;
}
}
LuxuryCar
是LUXURY
型汽车的具体实现。
package designPatterns.creational.factory;
public class LuxuryCar extends Car {
LuxuryCar() {
super(CarType.LUXURY);
construct();
}
@Override
protected void construct() {
System.out.println("Building luxury car");
// add accessories
}
}
SmallCar
是SMALL
型汽车的具体实现。
package designPatterns.creational.factory;
public class SmallCar extends Car {
SmallCar() {
super(CarType.SMALL);
construct();
}
@Override
protected void construct() {
System.out.println("Building small car");
// add accessories
}
}
SedanCar
是SEDAN
型汽车的具体实现。
package designPatterns.creational.factory;
public class SedanCar extends Car {
SedanCar() {
super(CarType.SEDAN);
construct();
}
@Override
protected void construct() {
System.out.println("Building sedan car");
// add accessories
}
}
2.3 创建对象的工厂
CarFactory.java
是我们使用工厂模式实现的主要类。 仅在确定实例类型之后,才会实例化实例。
package designPatterns.creational.factory;
public class CarFactory {
public static Car buildCar(CarType model) {
Car car = null;
switch (model) {
case SMALL:
car = new SmallCar();
break;
case SEDAN:
car = new SedanCar();
break;
case LUXURY:
car = new LuxuryCar();
break;
default:
// throw some exception
break;
}
return car;
}
}
2.4 测试工厂模式
在TestFactoryPattern
中,我们将测试我们的工厂代码。 让我们运行这个类。
package designPatterns.creational.factory;
public class TestFactoryPattern {
public static void main(String[] args) {
System.out.println(CarFactory.buildCar(CarType.SMALL));
System.out.println(CarFactory.buildCar(CarType.SEDAN));
System.out.println(CarFactory.buildCar(CarType.LUXURY));
}
}
程序输出。
Building small car
designPatterns.creational.factory.SmallCar@7c230be4
Building sedan car
designPatterns.creational.factory.SedanCar@60e1e567
Building luxury car
designPatterns.creational.factory.LuxuryCar@e9bfee2
如您所见,工厂可以退回所要求的任何类型的汽车实例。 这将帮助我们在汽车制造过程中进行任何形式的更改,甚至无需触及组成类,即使用CarFactory
的类。
3.工厂模式的好处
到目前为止,您应该能够算出使用工厂模式的主要优势。 让我们记下:
- 对象的创建可避免其重用,而无需大量重复代码。
- 创建对象需要访问不应包含在组成类中的信息或资源。
- 必须集中管理所生成对象的生命周期管理,以确保应用内行为的一致性。
4.最后的笔记
工厂模式最适合涉及一些复杂的对象创建步骤的地方。 为确保这些步骤集中进行,并且不暴露于编写类中,应使用工厂模式。 我们可以在 JDK 本身中看到许多实时的工厂模式示例,例如:
java.sql.DriverManager#getConnection()
java.net.URL#openConnection()
java.lang.Class#newInstance()
java.lang.Class#forName()
希望我在此 Java 工厂模式示例中包含了足够的信息,以使该帖子内容丰富。
如果您对 Java 中的抽象工厂设计模式仍有疑问,请发表评论。 我很乐意与您讨论。
学习愉快!