Mkyong-中文博客翻译-六-
Mkyong 中文博客翻译(六)
原文:Mkyong
JSF 2 数据表示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-datatable-example/
在 JSF 中,“ h:dataTable ”标签用于以 HTML 表格格式显示数据。下面的 JSF 2.0 示例向您展示了如何使用“ h:dataTable ”标记来循环遍历“订单”对象的数组,并以 HTML 表格格式显示它。
1.项目文件夹
本例的项目文件夹结构。
2.受管 bean
一个名为“order”的受管 bean 初始化了数组对象供以后使用。
OrderBean.java
package com.mkyong;
import java.io.Serializable;
import java.math.BigDecimal;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="order")
@SessionScoped
public class OrderBean implements Serializable{
private static final long serialVersionUID = 1L;
private static final Order[] orderList = new Order[] {
new Order("A0001", "Intel CPU",
new BigDecimal("700.00"), 1),
new Order("A0002", "Harddisk 10TB",
new BigDecimal("500.00"), 2),
new Order("A0003", "Dell Laptop",
new BigDecimal("11600.00"), 8),
new Order("A0004", "Samsung LCD",
new BigDecimal("5200.00"), 3),
new Order("A0005", "A4Tech Mouse",
new BigDecimal("100.00"), 10)
};
public Order[] getOrderList() {
return orderList;
}
public static class Order{
String orderNo;
String productName;
BigDecimal price;
int qty;
public Order(String orderNo, String productName,
BigDecimal price, int qty) {
this.orderNo = orderNo;
this.productName = productName;
this.price = price;
this.qty = qty;
}
//getter and setter methods
}
}
3.半铸钢ˌ钢性铸铁(Cast Semi-Steel)
创建一个 CSS 文件来设置表格布局的样式。
table-style.css
.order-table{
border-collapse:collapse;
}
.order-table-header{
text-align:center;
background:none repeat scroll 0 0 #E5E5E5;
border-bottom:1px solid #BBBBBB;
padding:16px;
}
.order-table-odd-row{
text-align:center;
background:none repeat scroll 0 0 #FFFFFFF;
border-top:1px solid #BBBBBB;
}
.order-table-even-row{
text-align:center;
background:none repeat scroll 0 0 #F9F9F9;
border-top:1px solid #BBBBBB;
}
4.h:数据表
一个 JSF 2.0 xhtml 页面,展示了如何使用" h:dataTable "标签来循环访问" order "对象的数组。这个例子应该是不言自明的。
default.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:head>
<h:outputStylesheet library="css" name="table-style.css" />
</h:head>
<h:body>
<h1>JSF 2 dataTable example</h1>
<h:dataTable value="#{order.orderList}" var="o"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row"
>
<h:column>
<!-- column header -->
<f:facet name="header">Order No</f:facet>
<!-- row record -->
#{o.orderNo}
</h:column>
<h:column>
<f:facet name="header">Product Name</f:facet>
#{o.productName}
</h:column>
<h:column>
<f:facet name="header">Price</f:facet>
#{o.price}
</h:column>
<h:column>
<f:facet name="header">Quantity</f:facet>
#{o.qty}
</h:column>
</h:dataTable>
</h:body>
</html>
生成这个 HTML 输出
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >
<head>
<link type="text/css" rel="stylesheet"
href="/JavaServerFaces/faces/javax.faces.resource/table-style.css?ln=css" />
</head>
<body>
<h1>JSF 2 dataTable example</h1>
<table class="order-table">
<thead>
<tr>
<th class="order-table-header" scope="col">Order No</th>
<th class="order-table-header" scope="col">Product Name</th>
<th class="order-table-header" scope="col">Price</th>
<th class="order-table-header" scope="col">Quantity</th>
</tr>
</thead>
<tbody>
<tr class="order-table-odd-row">
<td>A0001</td>
<td>Intel CPU</td>
<td>700.00</td>
<td>1</td>
</tr>
<tr class="order-table-even-row">
<td>A0002</td>
<td>Harddisk 10TB</td>
<td>500.00</td>
<td>2</td>
</tr>
<tr class="order-table-odd-row">
<td>A0003</td>
<td>Dell Laptop</td>
<td>11600.00</td>
<td>8</td>
</tr>
<tr class="order-table-even-row">
<td>A0004</td>
<td>Samsung LCD</td>
<td>5200.00</td>
<td>3</td>
</tr>
<tr class="order-table-odd-row">
<td>A0005</td>
<td>A4Tech Mouse</td>
<td>100.00</td>
<td>10</td>
</tr>
</tbody>
</table>
</body>
</html>
6.演示
URL:http://localhost:8080/Java server faces/default . XHTML
Download It – JSF-2-DataTable-Example.zip (11KB)
参考
datatable jsf2 (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190705140941/https://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
JSF 2 数据表排序示例–数据模型
在前面的 JSF 2 的数据表排序示例中,展示了最简单的方法,一个自定义的比较器来排序一个列表并显示在数据表中。
数据模型装饰器
在这个例子中,展示了另一种对 dataTable 中的列表进行排序的方式,在“ Core JavaServer Faces(第三版)”中提到了这种方式,称为 DataModel Decorator。
1.数据模型
创建一个 decorator 类来扩展 javax.faces.model.DataModel 类,并添加一个额外的排序行为。嗯,解释起来有点复杂,详细请参考书中:)
package com.mkyong;
import java.util.Arrays;
import java.util.Comparator;
import javax.faces.model.DataModel;
public class SortableDataModel<E> extends DataModel<E>{
DataModel<E> model;
private Integer[] rows;
SortableDataModel(DataModel<E> model){
this.model = model;
initRows();
}
public void initRows(){
int rowCount = model.getRowCount();
if(rowCount != -1){
this.rows = new Integer[rowCount];
for(int i = 0; i < rowCount; ++i){
rows[i] = i;
}
}
}
public void sortBy(final Comparator<E> comparator){
Comparator<Integer> rowComp = new Comparator<Integer>() {
public int compare(Integer i1, Integer i2){
E o1 = getData(i1);
E o2 = getData(i2);
return comparator.compare(o1, o2);
}
};
Arrays.sort(rows, rowComp);
}
private E getData(int row){
int originalRowIndex = model.getRowIndex();
model.setRowIndex(row);
E newRowData = model.getRowData();
model.setRowIndex(originalRowIndex);
return newRowData;
}
@Override
public void setRowIndex(int rowIndex) {
if(0 <= rowIndex && rowIndex < rows.length){
model.setRowIndex(rows[rowIndex]);
}else{
model.setRowIndex(rowIndex);
}
}
@Override
public boolean isRowAvailable() {
return model.isRowAvailable();
}
@Override
public int getRowCount() {
return model.getRowCount();
}
@Override
public E getRowData() {
return model.getRowData();
}
@Override
public int getRowIndex() {
return model.getRowIndex();
}
@Override
public Object getWrappedData() {
return model.getWrappedData();
}
@Override
public void setWrappedData(Object data) {
model.setWrappedData(data);
initRows();
}
}
2.受管 Bean
一个托管 bean 为测试提供一个虚拟列表,并展示了使用自定义数据模型对数据表列表进行排序。
package com.mkyong;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Comparator;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.model.ArrayDataModel;
import javax.faces.model.DataModel;
@ManagedBean(name="order")
@SessionScoped
public class OrderBean implements Serializable{
private static final long serialVersionUID = 1L;
private SortableDataModel<Order> sotableDataModel;
private boolean sortAscending = true;
private static final Order[] orderList = {
new Order("A0002", "Harddisk 100TB",
new BigDecimal("500.00"), 3),
new Order("A0001", "Intel CPU",
new BigDecimal("4200.00"), 6),
new Order("A0004", "Samsung LCD",
new BigDecimal("5200.00"), 10),
new Order("A0003", "Dell Laptop",
new BigDecimal("11600.00"), 9),
new Order("A0005", "A4Tech Mouse",
new BigDecimal("200.00"), 20)
};
public OrderBean(){
sotableDataModel = new SortableDataModel<Order>(
new ArrayDataModel<Order>(orderList));
}
public DataModel<Order> getOrderList() {
return sotableDataModel;
}
//sort by order no
public String sortByOrderNo() {
if(sortAscending){
sotableDataModel.sortBy(new Comparator<Order>() {
@Override
public int compare(Order o1, Order o2) {
return o1.getOrderNo().compareTo(o2.getOrderNo());
}
});
sortAscending = false;
}else{
//descending order
sotableDataModel.sortBy(new Comparator<Order>() {
@Override
public int compare(Order o1, Order o2) {
return o2.getOrderNo().compareTo(o1.getOrderNo());
}
});
sortAscending = true;
}
return null;
}
public static class Order{
String orderNo;
String productName;
BigDecimal price;
int qty;
public Order(String orderNo, String productName,
BigDecimal price, int qty) {
this.orderNo = orderNo;
this.productName = productName;
this.price = price;
this.qty = qty;
}
//getter and setter methods
}
}
2.数据表标签
一个 JSF 页面,在“订单号”列标题放一个 commandLink 标签,如果点击,对数据表列表进行排序。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
>
<h:head>
<h:outputStylesheet library="css" name="table-style.css" />
</h:head>
<h:body>
<h1>JSF 2 dataTable sorting example</h1>
<h:form>
<h:dataTable value="#{order.orderList}" var="o"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row"
>
<h:column>
<f:facet name="header">
<h:commandLink action="#{order.sortByOrderNo}">
Order No
</h:commandLink>
</f:facet>
#{o.orderNo}
</h:column>
<h:column>
<f:facet name="header">
Product Name
</f:facet>
#{o.productName}
</h:column>
<h:column>
<f:facet name="header">Price</f:facet>
#{o.price}
</h:column>
<h:column>
<f:facet name="header">Quantity</f:facet>
#{o.qty}
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
3.演示
从上到下,显示按升序和降序排序的数据表列表。
下载源代码
Download It - JSF-2-DataTable-Sorting-DataModel-Example.zip (11KB)
参考
JSF 2 数据表排序示例
对 JSF 数据表列表进行排序的想法如下:
1.列标题
在列标题中放置一个 commandLink,如果这个链接被点击,对数据表列表进行排序。
<h:column>
<f:facet name="header">
<h:commandLink action="#{order.sortByOrderNo}">
Order No
</h:commandLink>
</f:facet>
#{o.orderNo}
</h:column>
2.履行
在受管 bean 中,使用 Collections.sort() 和自定义比较器对列表进行排序。
@ManagedBean(name="order")
@SessionScoped
public class OrderBean implements Serializable{
//sort by order no
public String sortByOrderNo() {
Collections.sort(orderArrayList, new Comparator<Order>() {
@Override
public int compare(Order o1, Order o2) {
return o1.getOrderNo().compareTo(o2.getOrderNo());
}
});
}
//...
}
数据表排序示例
一个在数据表中实现排序特性的 JSF 2.0 例子。点击"订单号"列标题使列表按"订单号"升序排序;再次点击,按“订单号”降序排列列表。
1.受管 Bean
一个托管 bean,为测试提供一个虚拟列表,并展示了如何使用 Collections.sort()对数据表列表进行排序。
package com.mkyong;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="order")
@SessionScoped
public class OrderBean implements Serializable{
private static final long serialVersionUID = 1L;
private List<Order> orderArrayList;
private boolean sortAscending = true;
private static final Order[] orderList = {
new Order("A0002", "Harddisk 100TB",
new BigDecimal("500.00"), 3),
new Order("A0001", "Intel CPU",
new BigDecimal("4200.00"), 6),
new Order("A0004", "Samsung LCD",
new BigDecimal("5200.00"), 10),
new Order("A0003", "Dell Laptop",
new BigDecimal("11600.00"), 9),
new Order("A0005", "A4Tech Mouse",
new BigDecimal("200.00"), 20)
};
public OrderBean(){
orderArrayList = new ArrayList<Order>(Arrays.asList(orderList));
}
public List<Order> getOrderList() {
return orderArrayList;
}
//sort by order no
public String sortByOrderNo() {
if(sortAscending){
//ascending order
Collections.sort(orderArrayList, new Comparator<Order>() {
@Override
public int compare(Order o1, Order o2) {
return o1.getOrderNo().compareTo(o2.getOrderNo());
}
});
sortAscending = false;
}else{
//descending order
Collections.sort(orderArrayList, new Comparator<Order>() {
@Override
public int compare(Order o1, Order o2) {
return o2.getOrderNo().compareTo(o1.getOrderNo());
}
});
sortAscending = true;
}
return null;
}
public static class Order{
String orderNo;
String productName;
BigDecimal price;
int qty;
public Order(String orderNo, String productName,
BigDecimal price, int qty) {
this.orderNo = orderNo;
this.productName = productName;
this.price = price;
this.qty = qty;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
}
}
2.数据表标签
一个 JSF 页面,在“订单号”列标题放一个 commandLink 标签,如果点击,对数据表列表进行排序。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
>
<h:head>
<h:outputStylesheet library="css" name="table-style.css" />
</h:head>
<h:body>
<h1>JSF 2 dataTable sorting example</h1>
<h:form>
<h:dataTable value="#{order.orderList}" var="o"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row"
>
<h:column>
<f:facet name="header">
<h:commandLink action="#{order.sortByOrderNo}">
Order No
</h:commandLink>
</f:facet>
#{o.orderNo}
</h:column>
<h:column>
<f:facet name="header">
Product Name
</f:facet>
#{o.productName}
</h:column>
<h:column>
<f:facet name="header">Price</f:facet>
#{o.price}
</h:column>
<h:column>
<f:facet name="header">Quantity</f:facet>
#{o.qty}
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
3.演示
从上到下,显示按升序和降序排序的数据表列表。
下载源代码
Download It – JSF-2-DataTable-Sorting-Example.zip (10KB)
参考
- 使用数据库对数据表列表进行排序
- JSF h:数据表 JavaDoc
- JSF 2 链接、命令链接和输出链接示例
- Java 对象排序示例
JSF 2 下拉框示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-dropdown-box-example/
在 JSF, < h:selectOneMenu / > 标签用于呈现一个下拉框——HTML 选择元素,属性为“ size=1 ”。
//JSF...
<h:selectOneMenu value="#{user.favCoffee1}">
<f:selectItem itemValue="Cream Latte" itemLabel="Coffee3 - Cream Latte" />
<f:selectItem itemValue="Extreme Mocha" itemLabel="Coffee3 - Extreme Mocha" />
<f:selectItem itemValue="Buena Vista" itemLabel="Coffee3 - Buena Vista" />
</h:selectOneMenu>
//HTML output...
<select name="j_idt6:j_idt8" size="1">
<option value="Cream Latte">Coffee3 - Cream Latte</option>
<option value="Extreme Mocha">Coffee3 - Extreme Mocha</option>
<option value="Buena Vista">Coffee3 - Buena Vista</option>
</select>
h:选择一个菜单示例
一个 JSF 2.0 的例子,展示了使用" h:selectOneMenu "标签来呈现一个下拉框,并以 3 种不同的方式填充数据:
- “f:selecti item标签中的硬核值。
- 用 Map 生成值,并将其放入“f:selecti items标签中。
- 用一个对象数组生成值,放入“ f:selectItems ”标签,然后用“ var 属性表示值。
1.支撑豆
用于保存和生成下拉框值数据的后备 bean。
package com.mkyong;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
public String favCoffee1;
public String favCoffee2;
public String favCoffee3;
public String getFavCoffee1() {
return favCoffee1;
}
public void setFavCoffee1(String favCoffee1) {
this.favCoffee1 = favCoffee1;
}
public String getFavCoffee2() {
return favCoffee2;
}
public void setFavCoffee2(String favCoffee2) {
this.favCoffee2 = favCoffee2;
}
public String getFavCoffee3() {
return favCoffee3;
}
public void setFavCoffee3(String favCoffee3) {
this.favCoffee3 = favCoffee3;
}
//Generated by Map
private static Map<String,Object> coffee2Value;
static{
coffee2Value = new LinkedHashMap<String,Object>();
coffee2Value.put("Coffee2 - Cream Latte", "Cream Latte"); //label, value
coffee2Value.put("Coffee2 - Extreme Mocha", "Extreme Mocha");
coffee2Value.put("Coffee2 - Buena Vista", "Buena Vista");
}
public Map<String,Object> getFavCoffee2Value() {
return coffee2Value;
}
//Generated by Object array
public static class Coffee{
public String coffeeLabel;
public String coffeeValue;
public Coffee(String coffeeLabel, String coffeeValue){
this.coffeeLabel = coffeeLabel;
this.coffeeValue = coffeeValue;
}
public String getCoffeeLabel(){
return coffeeLabel;
}
public String getCoffeeValue(){
return coffeeValue;
}
}
public Coffee[] coffee3List;
public Coffee[] getFavCoffee3Value() {
coffee3List = new Coffee[3];
coffee3List[0] = new Coffee("Coffee3 - Cream Latte", "Cream Latte");
coffee3List[1] = new Coffee("Coffee3 - Extreme Mocha", "Extreme Mocha");
coffee3List[2] = new Coffee("Coffee3 - Buena Vista", "Buena Vista");
return coffee3List;
}
}
2.JSF·佩奇
演示“ h:selectOneMenu ”标签使用的 JSF 页面。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 dropdown box example</h1>
<h:form>
1\. Hard-coded with "f:selectItem" :
<h:selectOneMenu value="#{user.favCoffee1}">
<f:selectItem itemValue="Cream Latte" itemLabel="Coffee3 - Cream Latte" />
<f:selectItem itemValue="Extreme Mocha" itemLabel="Coffee3 - Extreme Mocha" />
<f:selectItem itemValue="Buena Vista" itemLabel="Coffee3 - Buena Vista" />
</h:selectOneMenu>
<br /><br />
2\. Generated by Map :
<h:selectOneMenu value="#{user.favCoffee2}">
<f:selectItems value="#{user.favCoffee2Value}" />
</h:selectOneMenu>
<br /><br />
3\. Generated by Object array and iterate with var :
<h:selectOneMenu value="#{user.favCoffee3}">
<f:selectItems value="#{user.favCoffee3Value}" var="c"
itemLabel="#{c.coffeeLabel}" itemValue="#{c.coffeeValue}" />
</h:selectOneMenu>
<br /><br />
<h:commandButton value="Submit" action="result" />
<h:commandButton value="Reset" type="reset" />
</h:form>
</h:body>
</html>
result.xhtml…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h1>JSF 2 dropdown box example</h1>
<h2>result.xhtml</h2>
<ol>
<li>user.favCoffee1 : #{user.favCoffee1}</li>
<li>user.favCoffee2 : #{user.favCoffee2}</li>
<li>user.favCoffee3 : #{user.favCoffee3}</li>
</ol>
</h:body>
</html>
3.演示
单击“提交”按钮时,链接到“result.xhtml”页面并显示已提交的下拉框值。
如何预选下拉框值?
如果“f:selecti items”标签的值与“ h:selectOneMenu 标签的“值”匹配,则选择该标签的值。在上面的示例中,如果您将“favCoffee1”属性设置为“Extreme Mocha”:
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String favCoffee1 = "Extreme Mocha";
//...
“favCoffee1”下拉框,值“极端摩卡”被默认选中。
下载源代码
Download It – JSF-2-Dropdown-Box-Example.zip (10KB)
参考
JSF 2 图形图像示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-graphicimage-example/
在 JSF,你可以使用 < h:graphicImage / > 标签来呈现一个 HTML“img”元素。例如,资源文件夹中一个名为“sofa.png”的图片,见下图:
1.JSF 1.x 图形图像
在 JSF 1.x 中你可以直接在“值”属性中硬编码上面的图片 URL:
JSF…
<h:graphicImage value="resourcimg/sofa.png" />
HTML 输出…
<img src="resourcimg/sofa.png;" alt="" />
2.JSF 2.x 图形图像
在 JSF 2.0 中,你可以通过“资源库”的概念来渲染上面的图像:
JSF…
<h:graphicImage library="images" name="sofa.png" />
HTML 输出…
<img src="/JavaServerFaces/faces/javax.faces.resource/sofa.png?ln=images" alt="" />
Note
For more detail, please read this JSF 2.0 resource library example. ## 下载源代码
Download It – JSF-2-GraphicImage-Example.zip (14KB)
参考
JSF 2 隐藏价值示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-hidden-value-example/
在 JSF,你可以使用 < h:inputHidden / > 标签来呈现一个 HTML 隐藏值字段。举个例子,
JSF 标签…
<h:inputHidden value="some text" />
呈现此 HTML 代码…
<input type="hidden" name="random value" value="some text" />
JSF 隐藏字段示例
一个 JSF 2 的例子,通过 < h:inputHidden / > 标签呈现一个隐藏字段,并在 JavaScript 中访问隐藏值。
1.受管 Bean
一个简单的托管 bean,声明为“user”。
package com.mkyong.form;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable {
String answer = "I'm Hidden value!";
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
}
2.查看页面
通过“h:inputHidden”标签呈现一个隐藏值,如果按钮被点击,通过 JavaScript 打印隐藏值。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<script type="text/javascript">
function printHiddenValue(){
alert(document.getElementById('myform:hiddenId').value);
}
</script>
</h:head>
<h:body>
<h1>JSF 2 hidden value example</h1>
<h:form id="myform">
<h:inputHidden value="#{user.answer}" id="hiddenId" />
<h:commandButton type="button" value="ClickMe" onclick="printHiddenValue()" />
</h:form>
</h:body>
</html>
3.演示
URL:http://localhost:8080/Java server faces/
下载源代码
Download It – JSF-2-HiddenValue-Example.zip (9KB)Note
You may interest to know how to pass new hidden value to backing bean in JSF.
参考
相关文章
-
[How to pass the new hidden value to the backing bean 【T1] in JS](/web/20201212022659/https://www.mkyong.com/jsf2/how-to-pass-new-hidden-value-to-backing-bean-in-jsf/)
-
How to get the hidden field value in JavaScript
-
[ Spring MVC Hidden Value Example
JSF 新协议国际化范例
在 JSF 应用程序中,您可以像这样以编程方式更改应用程序区域设置:
//this example change locale to france
FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale('fr');
这使得 JSF 很容易支持国际化或多语言。
完整的 JSF 国际化范例
在本教程中,我们将向您展示一个 JSF 2.0 web 应用程序,它显示一个欢迎页面,从属性文件中检索欢迎消息,并根据所选语言动态更改欢迎消息。
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
1.项目文件夹
本例的目录结构。
2.属性文件
这里有两个属性文件来存储英文和中文信息。
welcome.properties
welcome.jsf = Happy learning JSF 2.0
welcome_zh_CN.properties
welcome.jsf = \u5feb\u4e50\u5b66\u4e60 JSF 2.0
Note
For UTF-8 or non-English characters, for example Chinese , you should encode it with native2ascii tool.
3.faces-config.xml
包括到您的 JSF 应用程序中,并声明“en”作为您的默认应用程序区域设置。
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<application>
<locale-config>
<default-locale>en</default-locale>
</locale-config>
<resource-bundle>
<base-name>com.mkyong.welcome</base-name>
<var>msg</var>
</resource-bundle>
</application>
</faces-config>
4.受管 Bean
一个受管 bean,它提供语言选择列表和一个值更改事件侦听器,以编程方式更改区域设置。
LanguageBean。java
package com.mkyong;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
@ManagedBean(name="language")
@SessionScoped
public class LanguageBean implements Serializable{
private static final long serialVersionUID = 1L;
private String localeCode;
private static Map<String,Object> countries;
static{
countries = new LinkedHashMap<String,Object>();
countries.put("English", Locale.ENGLISH); //label, value
countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}
public Map<String, Object> getCountriesInMap() {
return countries;
}
public String getLocaleCode() {
return localeCode;
}
public void setLocaleCode(String localeCode) {
this.localeCode = localeCode;
}
//value change event listener
public void countryLocaleCodeChanged(ValueChangeEvent e){
String newLocaleValue = e.getNewValue().toString();
//loop country map to compare the locale code
for (Map.Entry<String, Object> entry : countries.entrySet()) {
if(entry.getValue().toString().equals(newLocaleValue)){
FacesContext.getCurrentInstance()
.getViewRoot().setLocale((Locale)entry.getValue());
}
}
}
}
5.JSF·佩奇
一个 JSF 页面,显示来自属性文件的欢迎消息,并将值更改事件侦听器附加到下拉框。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<h1>JSF 2 internationalization example</h1>
<h:form>
<h2>
<h:outputText value="#{msg['welcome.jsf']}" />
</h2>
<h:panelGrid columns="2">
Language :
<h:selectOneMenu value="#{language.localeCode}" onchange="submit()"
valueChangeListener="#{language.countryLocaleCodeChanged}">
<f:selectItems value="#{language.countriesInMap}" />
</h:selectOneMenu>
</h:panelGrid>
</h:form>
</h:body>
</html>
6.演示
URL:http://localhost:8080/Java server faces/faces/default . XHTML
默认情况下,显示区域英语。
如果用户更改下拉框语言,它将触发一个值更改事件监听器,并相应地更改应用程序的区域设置。
下载源代码
Download It – JSF-2-Internationalization-Example.zip (11KB)
参考
Tags : jsf2 multiple languagesfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 2 链接、命令链接和输出链接示例
在 JSF 中, < h:link / > 、 < h:commandLink / > 和 < h:outputLink / > 标签被用来渲染一个 HTML“a”锚元素,请看下面的例子来了解其中的不同。
Note
In below examples, assume “/JavaServerFaces/” is the root of your project context URL.
1.JSF h:链接示例
“ h:link ”标签是 JSF 2.0 中的新标签,“ value 属性呈现为锚文本,“ outcome ”属性确定为 HTML 的目标 URL“href属性。参见示例:
1.链接+“结果”
//JSF
<h:link value="Login page" outcome="login" />
//HTML output
<a href="/JavaServerFaces/faces/login.xhtml">Login page</a>
2.链接+“结果”+参数
//JSF
<h:link value="Login page + Param " outcome="login" >
<f:param name="username" value="mkyong" />
</h:link>
//HTML output
<a href="/JavaServerFaces/faces/login.xhtml?username=mkyong">Login page + Param</a>
3.链接+“结果”+图像
//JSF
<h:link outcome="login" >
<h:graphicImage library="images" name="sofa.png" />
</h:link>
//HTML output
<a href="/JavaServerFaces/faces/login.xhtml">
<img src="/JavaServerFaces/faces/javax.faces.resource/sofa.png?ln=images" />
</a>
2.JSF h:命令链接示例
“ h:commandLink ”标签是从 JSF 1.x 开始发布的,它生成一个链接,当点击时就像一个提交按钮。“值属性呈现为锚文本,“动作”属性确定为 HTML“href属性的目标 URL。此外,“h:commandLink”将在页面中包含一个“ jsf.js ”文件,并将一个“onclick”事件附加到生成的链接上,参见示例:
Note
The “j_idtx” is a random value generated by JSF.
1.commandLink
//JSF
<h:commandLink value="Login page" />
//HTML output
<script type="text/javascript"
src="/JavaServerFaces/faces/javax.faces.resource/jsf.js?ln=javax.faces&stage=Development">
</script>
<a href="#"
onclick="mojarra.jsfcljs(document.getElementById('j_idt6'),
{'j_idt6:j_idt16':'j_idt6:j_idt16'},'');
return false">
Login page
</a>
P.S 如果省略了“动作属性,那么当点击按钮时,将重新加载当前页面。
2.commandLink +操作
//JSF
<h:commandLink action="#{user.goLoginPage}" value="Login page" />
//HTML output
<script type="text/javascript"
src="/JavaServerFaces/faces/javax.faces.resource/jsf.js?ln=javax.faces&stage=Development">
</script>
<a href="#"
onclick="mojarra.jsfcljs(document.getElementById('j_idt6'),
{'j_idt6:j_idt18':'j_idt6:j_idt18'},'');
return false">
Login page
</a>
你甚至不能在 HTML 输出中找到动作值,只有 JSF 知道它去了哪里。
3.命令链接+操作+参数
//JSF
<h:commandLink action="#{user.goLoginPage}" value="Login page + Param ">
<f:param name="username" value="mkyong" />
</h:commandLink>
//HTML output
<script type="text/javascript"
src="/JavaServerFaces/faces/javax.faces.resource/jsf.js?ln=javax.faces&stage=Development">
</script>
<a href="#"
onclick="mojarra.jsfcljs(document.getElementById('j_idt6'),
{'j_idt6:j_idt20':'j_idt6:j_idt20','username':'mkyong'},'');
return false">
Login page + Param
</a>
4.命令链接+动作+图像
//JSF
<h:commandLink action="#{user.goLoginPage}">
<h:graphicImage library="images" name="sofa.png" />
</h:commandLink>
//HTML output
<script type="text/javascript"
src="/JavaServerFaces/faces/javax.faces.resource/jsf.js?ln=javax.faces&stage=Development">
</script>
<a href="#"
onclick="mojarra.jsfcljs(document.getElementById('j_idt6'),
{'j_idt6:j_idt23':'j_idt6:j_idt23'},'');
return false">
<img src="/JavaServerFaces/faces/javax.faces.resource/sofa.png?ln=images" />
</a>
3.JSF h:输出链接示例
在 JSF 1.x 中发布了“ h:outputLink ”标签,标签体被渲染为锚文本,“ value ”属性被直接渲染为 HTML“href”属性的值,参见示例:
1. outputLink
//JSF
<h:outputLink>Login page</h:outputLink>
//HTML output
<a href="currentpage.xhtml">Login page</a>
P.S 如果“ value 属性被省略,它会把当前页面的 URL 作为“href”属性的值。
2.outputLink +"值"
//JSF
<h:outputLink value="login.xhtml" >
Login page
</h:outputLink>
//HTML output
<a href="login.xhtml">
Login page
</a>
3.outputLink + "value" + outputText +参数
//JSF
<h:outputLink value="login.xhtml">
<h:outputText value="Login page" />
<f:param name="username" value="mkyong" />
</h:outputLink>
//HTML output
<a href="login.xhtml?username=mkyong">Login page</a>
4.outputLink +"值'+ outputText + image
//JSF
<h:outputLink value="login.xhtml">
<h:graphicImage library="images" name="sofa.png" />
</h:outputLink>
//HTML output
<a href="login.xhtml">
<img src="/JavaServerFaces/faces/javax.faces.resource/sofa.png?ln=images" />
</a>
我的想法…
以上三个链接标签的一些回顾:
- “ h:link ”标签对于生成需要与 JSF“结果”交互的链接是有用的,但是缺乏“动作”支持使得很难生成动态结果。
- “ h:commandLink ”标签很烂,生成的 JavaScript 真的很吓人!不建议使用这个标签,除非你有充分的理由支持。但它支持“动作属性,这正是“ h:link 所缺少的。
- “ h:outputLink ”对于生成不需要与 JSF 程序本身交互的链接是有用的。
最后,如果在“ h:link ”中加入“ action 属性就更完美了。
下载源代码
Download It – JSF-2-link-commandLink-outputLink-Example.zip (15KB)
参考
- JSF < h:link/ > JavaDoc
- JSF < h:命令链接/ > JavaDoc
- JSF < h:输出链接/ > JavaDoc
JSF 2 列表框示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-listbox-example/
在 JSF,<h:selectone listbox/>标签用于呈现单个选择列表框——HTML 选择元素,具有“大小属性。
//JSF...
<h:selectOneListbox value="#{user.favYear1}">
<f:selectItem itemValue="2000" itemLabel="Year1 - 2000" />
<f:selectItem itemValue="2010" itemLabel="Year1 - 2010" />
<f:selectItem itemValue="2020" itemLabel="Year1 - 2020" />
</h:selectOneListbox>
//HTML output...
<select name="j_idt6:j_idt8" size="3">
<option value="2000">Year1 - 2000</option>
<option value="2010">Year1 - 2010</option>
<option value="2020">Year1 - 2020</option>
</select>
h:selectOneListbox 示例
一个 JSF 2.0 示例,展示了如何使用" h:selectOneListbox "标记来呈现单个选择列表框,并以 3 种不同的方式填充数据:
- “f:selecti item标签中的硬核值。
- 用 Map 生成值,并将其放入“f:selecti items标签中。
- 用一个对象数组生成值,放入“ f:selectItems ”标签,然后用“ var 属性表示值。
1.支撑豆
为列表框值保存和生成数据的后备 bean。
package com.mkyong;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
public String favYear1;
public String favYear2;
public String favYear3;
//getter and setter methods
//Generated by Map
private static Map<String,Object> year2Value;
static{
year2Value = new LinkedHashMap<String,Object>();
year2Value.put("Year2 - 2000", "2000"); //label, value
year2Value.put("Year2 - 2010", "2010");
year2Value.put("Year2 - 2020", "2020");
}
public Map<String,Object> getFavYear2Value() {
return year2Value;
}
//Generated by Object array
public static class Year{
public String yearLabel;
public String yearValue;
public Year(String yearLabel, String yearValue){
this.yearLabel = yearLabel;
this.yearValue = yearValue;
}
public String getYearLabel(){
return yearLabel;
}
public String getYearValue(){
return yearValue;
}
}
public Year[] year3List;
public Year[] getFavYear3Value() {
year3List = new Year[3];
year3List[0] = new Year("Year3 - 2000", "2000");
year3List[1] = new Year("Year3 - 2010", "2010");
year3List[2] = new Year("Year3 - 2020", "2020");
return year3List;
}
}
2.JSF·佩奇
演示“ h:selectOneListbox ”标签使用的 JSF 页面。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 listbox example</h1>
<h:form>
1\. Hard-coded with "f:selectItem" :
<h:selectOneListbox value="#{user.favYear1}">
<f:selectItem itemValue="2000" itemLabel="Year1 - 2000" />
<f:selectItem itemValue="2010" itemLabel="Year1 - 2010" />
<f:selectItem itemValue="2020" itemLabel="Year1 - 2020" />
</h:selectOneListbox>
<br />
2\. Generated by Map :
<h:selectOneListbox value="#{user.favYear2}">
<f:selectItems value="#{user.favYear2Value}" />
</h:selectOneListbox>
<br />
3\. Generated by Object array and iterate with var :
<h:selectOneListbox value="#{user.favYear3}">
<f:selectItems value="#{user.favYear3Value}" var="y"
itemLabel="#{y.yearLabel}" itemValue="#{y.yearValue}" />
</h:selectOneListbox>
<br />
<h:commandButton value="Submit" action="result" />
<h:commandButton value="Reset" type="reset" />
</h:form>
</h:body>
</html>
result.xhtml…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h1>JSF 2 listbox example</h1>
<h2>result.xhtml</h2>
<ol>
<li>user.favYear1 : #{user.favYear1}</li>
<li>user.favYear2 : #{user.favYear2}</li>
<li>user.favYear3 : #{user.favYear3}</li>
</ol>
</h:body>
</html>
3.演示
单击“提交”按钮时,链接到“result.xhtml”页面并显示提交的列表框值。
如何预先选择列表框值?
如果与“ h:selectOneListbox ”标记的“值”匹配,则选择“ f:selectItems ”标记的值。在上面的示例中,如果您将 favYear1 属性设置为“2010”:
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String favYear1 = "2010";
//...
默认情况下,“favYear1”列表框值“2010”处于选中状态。
下载源代码
Download It – JSF-2-Listbox-Example.zip (10KB)
参考
JSF 2 + Log4j 集成示例
在本教程中,我们将向您展示如何将 log4j 框架与 JSF 2.x web 应用程序集成。JSF 正在使用java.util.logging
,您需要额外的工作来将日志从 JSF 的java.util.logging
重定向到log4j
,这会带来严重的性能损失,请确保仅在本地开发或调试环境中使用此技巧。
检查项目环境:
- SLF4j 1.7.7
- Log4j 1.2.17
- JSF 2.2.7
- maven3
- tomcat6
- 日食开普勒 4.3
简而言之,集成 JSF 和 log4j 的步骤。
- 在
logging.properties
上打开 JSF 日志,因为这个项目是在 Eclipse 环境中运行的,所以将使用 Eclipse 的JRE/lib/logging.properties
。 - 创建一个
log4j.properties
并把它放在类路径上。 - 创建一个 Servlet 的监听器,安装
slf4j bridge handler
将日志从 java.util.logging 重定向到 log4j。
Note
Refer to this SLF4j Bridging legacy APIs
1.项目目录
审查最终的项目结构。
2.项目相关性
你需要 slf4j-log4j12 和 jul-to-slf4j。
pom.xml
<properties>
<jdk.version>1.7</jdk.version>
<jsf.version>2.2.7</jsf.version>
<slf4j.version>1.7.7</slf4j.version>
</properties>
<dependencies>
<!-- from java.util.logging to log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- it help to get slf4j and log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- JSF -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>${jsf.version}</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>${jsf.version}</version>
</dependency>
<!-- you need this in web -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
4.JSF 伐木公司
因为这个项目是在 Eclipse 的环境中运行的,所以将使用 Eclipse 的 JRE。打开logging.properties
,将等级改为最细,打开javax.faces
和com.sun.faces
上的测井:
${JRE_PATH}/lib/logging.properties
# Default is INFO, change it to FINNEST
#java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
#Add these two lines to enable JSF logging
javax.faces.level = FINEST
com.sun.faces.level = FINEST
Note
If this project is deployed on Tomcat directly, update this ${Tomcat}\conf\logging.properties
5.Log4j 记录
创建一个 log4j 属性文件,放入resources
文件夹,参考步骤#1。
log4j.properties
# Root logger option
log4j.rootLogger=WARN, console, file
#enable JSF logging
log4j.logger.javax.faces=DEBUG
log4j.logger.com.sun.faces=DEBUG
# Redirect log messages to console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# Redirect log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=${catalina.home}/logs/jsfapp.log
log4j.appender.file.MaxFileSize=5KB
log4j.appender.file.MaxBackupIndex=5
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
6.ServletContextListener
创建一个 Servlet 监听器来安装桥处理器,以便将 JSF 的日志从java.util.properties
重定向到log4j
。
MyListener
package com.mkyong.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.slf4j.bridge.SLF4JBridgeHandler;
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent arg) {
System.out.println("contextInitialized....");
//remove the jsf root logger, avoid duplicated logging
//try comment out this and see the different on the console
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
@Override
public void contextDestroyed(ServletContextEvent arg) {
System.out.println("contextDestroyed....");
}
}
包括侦听器类以及其他标准 JSF 设置。
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:web="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>JavaServerFacesAndLog4j</display-name>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
<!-- Install slf4j bridge handler -->
<listener>
<listener-class>
com.mkyong.listener.MyListener
</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
7.应用程序日志
一个简单的例子向你展示如何做 log4j 的日志。
WelcomeAction.java
package com.mkyong.controller;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.apache.log4j.Logger;
@ManagedBean
@SessionScoped
public class PageController implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(PageController.class);
public String process() {
// logs debug
if (logger.isDebugEnabled()) {
logger.debug("PageController.process()");
}
// logs exception
logger.error("This is Error message", new Exception("Testing"));
return "success";
}
}
一个简单的 JSF 视图资源。
pages/welcome.jsp
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2.0 + Log4j</h1>
<h:form>
<h:commandButton action="#{pageController.process}" value="Click Me" />
</h:form>
</h:body>
</html>
8.演示
运行 JSF web 应用程序,并访问默认页面,然后单击按钮。
网址:http://localhost:8080/Java server facesandlog 4j/
8.1JSF 和应用程序记录都将显示在控制台中。
图:Eclipse 控制台
8.2JSF 和应用程序日志都将记录在${tomcat}\logs\jsfapp.log
中。
图:D:\ Apache-Tomcat-6 . 0 . 37 \ logs \ JSF app . log
下载源代码
Download it – JSFAndLog4j.zip (12 KB)
参考
- Stackover:为什么水平。未显示详细日志记录消息?
- Stackover : JSF2 日志与 tomcat
- 将 java.util.logging 桥接到 SLF4J
- log4j 1.2 官方页面
- log4j hello world 示例
- Slf4j:桥接遗留 API
- JavaDoc:Java . util . logging
JSF 新协议消息和消息示例
在 JSF,您可以通过以下两个消息标签输出消息:
- h:消息–为特定组件输出一条消息。
- h:消息–输出当前页面的所有消息。
参见下面的 JSF 2.0 示例,展示如何使用“ h:message ”和“ h:messages ”标签来显示验证错误消息。
JSF 页……
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 message + messages example</h1>
<h:form>
<h:messages style="color:red;margin:8px;" />
<br />
<h:panelGrid columns="3">
Enter your username :
<h:inputText id="username" value="#{user.username}"
size="20" required="true"
label="UserName" >
<f:validateLength minimum="5" maximum="10" />
</h:inputText>
<h:message for="username" style="color:red" />
Enter your age :
<h:inputText id="age" value="#{user.age}"
size="20" required="true"
label="Age" >
<f:validateLongRange for="age" minimum="1" maximum="200" />
</h:inputText>
<h:message for="age" style="color:red" />
</h:panelGrid>
<h:commandButton value="Submit" action="result" />
</h:form>
</h:body>
</html>
这是输出…
下载源代码
Download It – JSF-2-Message-Example.zip (10KB)
参考
- JSF h:消息 JavaDoc
- JSF h:消息 JavaDoc
Tags : jsf2freestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
相关文章
JSF 2 多选下拉框示例
在 JSF,<h:selectmany menu/>标签用于呈现一个多选下拉框——HTML select 元素,带有“ multiple ”和“ size=1 ”属性。
//JSF...
<h:selectManyMenu value="#{user.favCoffee1}">
<f:selectItem itemValue="Cream Latte" itemLabel="Coffee3 - Cream Latte" />
<f:selectItem itemValue="Extreme Mocha" itemLabel="Coffee3 - Extreme Mocha" />
<f:selectItem itemValue="Buena Vista" itemLabel="Coffee3 - Buena Vista" />
</h:selectManyMenu>
//HTML output...
<select name="j_idt6:j_idt8" multiple="multiple" size="1">
<option value="Cream Latte">Coffee3 - Cream Latte</option>
<option value="Extreme Mocha">Coffee3 - Extreme Mocha</option>
<option value="Buena Vista">Coffee3 - Buena Vista</option>
</select>
然而, h:selectManyMenu 标签的使用极不推荐,因为它们在不同的互联网浏览器中显示不一致,见图:
1.Internet Explorer 8
一个小滚动条来操作下拉框的值。
2.火狐 3.6.10
没有滚动条,看起来像一个普通的“文本框”,但你可以点击“文本框”和“上下拖动”或“上下键”来操纵值。
3.谷歌浏览器
在 Google Chrome 中,无论是<< select element with "multiple" and size="1" attribute - " h:selectManyMenu "标签> >还是< <带有" multiple "和 size="total of records "属性的 select 元素- " h:selectManyListbox "标签> >都是显示精确的布局。
结论
忘了“ h:selectManyMenu ”标签吧,真的没有理由用它。“ h:selectManyListbox ”标签是一个很好的选择。
参考
相关文章
-
Set the drop-down box value in
-
[How to use Struts 2 【T1]](/web/20201226142747/https://mkyong.com/struts2/how-to-auto-select-drop-down-box-value-in-struts-2/)
-
Automatically select the value struts 2 < s from the drop-down box : select the drop-down box > as an example
JSF 2 多重选择列表框示例
在 JSF 中,<h:selectmany listbox/>标签用于呈现一个多选 listbox-HTML 选择元素,具有“多个”和“大小属性。
//JSF...
<h:selectManyListbox value="#{user.favFood1}">
<f:selectItem itemValue="Fry Checken" itemLabel="Food1 - Fry Checken" />
<f:selectItem itemValue="Tomyam Soup" itemLabel="Food1 - Tomyam Soup" />
<f:selectItem itemValue="Mixed Rice" itemLabel="Food1 - Mixed Rice" />
</h:selectManyListbox>
//HTML output...
<select name="j_idt6:j_idt8" multiple="multiple" size="3">
<option value="Fry Checken">Food1 - Fry Checken</option>
<option value="Tomyam Soup">Food1 - Tomyam Soup</option>
<option value="Mixed Rice">Food1 - Mixed Rice</option>
</select>
h:selectManyListbox example
一个 JSF 2.0 示例,展示了如何使用“ h:selectManyListbox ”标记来呈现多个选择列表框,并以 3 种不同的方式填充数据:
- “f:selecti item标签中的硬核值。
- 用 Map 生成值,并将其放入“f:selecti items标签中。
- 用一个对象数组生成值,放入“ f:selectItems ”标签,然后用“ var 属性表示值。
1.支撑豆
用于保存和生成多选列表框值的数据的后备 bean。保存多选列表框值的属性必须是集合类型或数组类型;否则将会出现以下错误信息
WARNING: Target model Type is no a Collection or Array
javax.faces.FacesException: Target model Type is no a Collection or Array
package com.mkyong;
import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
public String[] favFood1;
public String[] favFood2;
public String[] favFood3;
//getter and setter methods...
public String getFavFood1InString() {
return Arrays.toString(favFood1);
}
public String getFavFood2InString() {
return Arrays.toString(favFood2);
}
public String getFavFood3InString() {
return Arrays.toString(favFood3);
}
//Generated by Map
private static Map<String,Object> food2Value;
static{
food2Value = new LinkedHashMap<String,Object>();
food2Value.put("Food2 - Fry Checken", "Fry Checken"); //label, value
food2Value.put("Food2 - Tomyam Soup", "Tomyam Soup");
food2Value.put("Food2 - Mixed Rice", "Mixed Rice");
}
public Map<String,Object> getFavFood2Value() {
return food2Value;
}
//Generated by Object array
public static class Food{
public String foodLabel;
public String foodValue;
public Food(String foodLabel, String foodValue){
this.foodLabel = foodLabel;
this.foodValue = foodValue;
}
public String getFoodLabel(){
return foodLabel;
}
public String getFoodValue(){
return foodValue;
}
}
public Food[] food3List;
public Food[] getFavFood3Value() {
food3List = new Food[3];
food3List[0] = new Food("Food3 - Fry Checken", "Fry Checken");
food3List[1] = new Food("Food3 - Tomyam Soup", "Tomyam Soup");
food3List[2] = new Food("Food3 - Mixed Rice", "Mixed Rice");
return food3List;
}
}
2.JSF·佩奇
演示“ h:selectManyListbox ”标签使用的 JSF 页面。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 multi-select listbox example</h1>
<h:form>
1\. Hard-coded with "f:selectItem" :
<h:selectManyListbox value="#{user.favFood1}">
<f:selectItem itemValue="Fry Checken" itemLabel="Food1 - Fry Checken" />
<f:selectItem itemValue="Tomyam Soup" itemLabel="Food1 - Tomyam Soup" />
<f:selectItem itemValue="Mixed Rice" itemLabel="Food1 - Mixed Rice" />
</h:selectManyListbox>
<br /><br />
2\. Generated by Map :
<h:selectManyListbox value="#{user.favFood2}">
<f:selectItems value="#{user.favFood2Value}" />
</h:selectManyListbox>
<br /><br />
3\. Generated by Object array and iterate with var :
<h:selectManyListbox value="#{user.favFood3}">
<f:selectItems value="#{user.favFood3Value}" var="f"
itemLabel="#{f.foodLabel}" itemValue="#{f.foodValue}" />
</h:selectManyListbox>
<br /><br />
<h:commandButton value="Submit" action="result" />
<h:commandButton value="Reset" type="reset" />
</h:form>
</h:body>
</html>
result.xhtml…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h1>JSF 2 multi-select listbox example</h1>
<h2>result.xhtml</h2>
<ol>
<li>user.favFood1 : #{user.favFood1InString}</li>
<li>user.favFood2 : #{user.favFood2InString}</li>
<li>user.favFood3 : #{user.favFood3InString}</li>
</ol>
</h:body>
</html>
3.演示
单击“提交”按钮时,链接到“result.xhtml”页面并显示提交的多选列表框值。
如何预先选择多个列表框值?
如果“f:selecti items”标签的值与“ h:selectManyListbox ”标签的“值”匹配,则选择该标签的值。在上面的示例中,如果您将 favFood1 属性设置为“Fry Checken”和“Tomyam Soup”:
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String[] favFood1 = {"Fry Checken", "Tomyam Soup"};
//...
默认情况下,“favFood1”列表框值、“Fry Checken”和“Tomyam Soup”被选中。
下载源代码
Download It – JSF-2-Multi-Select-Listbox-Example.zip (10KB)
参考
相关文章
- JSF 2 列表框 103
- 检票口列表选择示例
- 检票口列表多选示例 JSF 2 link、commandLink 和输出链接示例
- JSF 新协议数据表示例
- Example of JSF2 radio button
- Warning: JSF1063: Warning! Set unseriable
JSF 2 输出格式示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-outputformat-example/
在 JSF web 应用中,“ h:outputFormat ”标签与“ h:outputText ”标签类似,但是具有额外的功能来呈现参数化的消息。举个例子,
<h:outputFormat value="param0 : {0}, param1 : {1}" >
<f:param value="Number 1" />
<f:param value="Number 2" />
</h:outputFormat>
它将输出以下结果
param0 : Number 1, param1 : Number 2
- {0}匹配到
- {1}与匹配
OutputFormat 示例
查看 JSF 2.0 web 应用中编码的“ h:outputFormat ”标签的几个用例。
1.受管 Bean
一个受管 bean,提供一些文本用于演示。
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String text = "Hello {0}";
public String htmlInput = "<input type=\"{0}\" {1} />";
//getter and setter methods...
}
2.查看页面
带有几个“ h:outputFormat ”标签的页面示例。
JSF…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2.0 h:outputFormat Example</h1>
<ol>
<li>
<h:outputFormat value="this is param 0 : {0}, param 1 : {1}" >
<f:param value="Number 1" />
<f:param value="Number 2" />
</h:outputFormat>
</li>
<li>
<h:outputFormat value="#{user.text}" >
<f:param value="mkyong" />
</h:outputFormat>
</li>
<li>
<h:outputFormat value="#{user.htmlInput}" >
<f:param value="text" />
<f:param value="size='30'" />
</h:outputFormat>
</li>
<li>
<h:outputFormat value="#{user.htmlInput}" escape="false" >
<f:param value="text" />
<f:param value="size='30'" />
</h:outputFormat>
</li>
<li>
<h:outputFormat value="#{user.htmlInput}" escape="false" >
<f:param value="button" />
<f:param value="value='Click Me'" />
</h:outputFormat>
</li>
</ol>
</h:body>
</html>
生成以下 HTML 代码…
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >
<body>
<h1>JSF 2.0 h:outputFormat Example</h1>
<ol>
<li>
this is param 0 : Number 1, param 1 : Number 2
</li>
<li>
Hello mkyong
</li>
<li>
<input type="text" size='30' />
</li>
<li>
<input type="text" size='30' />
</li>
<li>
<input type="button" value='Click Me' />
</li>
</ol>
</body>
</html>
3.演示
URL:http://localhost:8080/Java server faces/
下载源代码
Download It – JSF-2-OutputFormat-Example.zip (9KB)
参考
JSF 2 输出文本示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-outputtext-example/
在 JSF 2.0 web 应用程序中,“ h:outputText 标签是显示纯文本最常用的标签,它不会生成任何额外的 HTML 元素。参见示例…
1.受管 Bean
一个受管 bean,提供一些文本用于演示。
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String text = "This is Text!";
public String htmlInput = "<input type='text' size='20' />";
//getter and setter methods...
}
2.查看页面
带有几个“ h:outputText ”标签的页面示例。
JSF…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2.0 h:outputText Example</h1>
<ol>
<li>#{user.text}</li>
<li><h:outputText value="#{user.text}" /></li>
<li><h:outputText value="#{user.text}" styleClass="abc" /></li>
<li><h:outputText value="#{user.htmlInput}" /></li>
<li><h:outputText value="#{user.htmlInput}" escape="false" /></li>
</ol>
</h:body>
</html>
生成以下 HTML 代码…
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >
<body>
<h1>JSF 2.0 h:outputText Example</h1>
<ol>
<li>This is Text!</li>
<li>This is Text!</li>
<li><span class="abc">This is Text!</span></li>
<li><input type='text' size='20' /></li>
<li><input type='text' size='20' /></li>
</ol>
</body>
</html>
-
对于 JSF 2.0 中的案例 1 和案例 2
,你其实并不需要使用“h:outputText”标签,因为你可以用直接的值表达式“#{user.text}”来实现同样的事情。 -
对于案例 3
如果存在“styleClass”、“style”、“dir”或“lang”属性中的任何一个,则呈现文本并用“ span 元素将其换行。 -
For case 4 and 5
The “escape” attribute in “h:outputText” tag, is used to convert sensitive HTML and XML markup to the corresponds valid HTML character.
For example,-
转换为>
- &转换为&
默认情况下,“转义属性设置为 true。
-
Note
See complete list of sensitive HTML and XML markup here…
http://www.ascii.cl/htmlcodes.htm
3.演示
URL:http://localhost:8080/Java server faces/
下载源代码
Download It – JSF-2-OutputText-Example.zip (9KB)
参考
标签:JSF 2
相关文章
-
[ JSF 2.0 tutorial
-
[ JSF 2.0 [Examples of commandLink and outputLink of Multi-component Verifier
JSF 2 面板网格示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-panelgrid-example/
在 JSF 中,“ h:panelGrid ”标签用于生成 HTML 表格标签,以将 JSF 组件放置在行和列布局中,从左到右,从上到下。
例如,您曾经使用 HTML 表格标签对 JSF 组件进行分组,如下所示:
HTML
<table>
<tbody>
<tr>
<td>
Enter a number :
</td>
<td>
<h:inputText id="number" value="#{dummy.number}"
size="20" required="true"
label="Number" >
<f:convertNumber />
</h:inputText>
</td>
<td>
<h:message for="number" style="color:red" />
</td>
</tr>
</tbody>
</table>
使用“ h:panelGrid ”标记,您可以获得上面相同的表格布局,而无需键入任何 HTML 表格标记:
【t0 h:嵌板网格】T1
<h:panelGrid columns="3">
Enter a number :
<h:inputText id="number" value="#{dummy.number}"
size="20" required="true"
label="Number" >
<f:convertNumber />
</h:inputText>
<h:message for="number" style="color:red" />
</h:panelGrid>
Note
The “column” attribute is optional, which define the number of columns are required to lay out the JSF component, defaults to 1.
h:panelGrid 示例
一个 JSF 2.0 的例子向你展示了如何使用" h:panelGrid "标签来正确地布局组件。
1.受管 Bean
用于演示的虚拟 bean。
package com.mkyong;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="dummy")
@SessionScoped
public class DummyBean implements Serializable{
int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
2.JSF·佩奇
一个 JSF XHTML 页面使用“ h:panelGrid ”标签将 JSF 组件放置在 3 列布局中。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
>
<h:body>
<h1>JSF 2 panelGrid example</h1>
<h:form>
<h:panelGrid columns="3">
Enter a number :
<h:inputText id="number" value="#{dummy.number}"
size="20" required="true"
label="Number" >
<f:convertNumber />
</h:inputText>
<h:message for="number" style="color:red" />
</h:panelGrid>
<h:commandButton value="Submit" action="result" />
</h:form>
</h:body>
</html>
输出以下 HTML 结果:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html >
<body>
<h1>JSF 2 panelGrid example</h1>
<form id="j_idt6" name="j_idt6" method="post"
action="/JavaServerFaces/faces/default.xhtml"
enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_idt6" value="j_idt6" />
<table>
<tbody>
<tr>
<td>
Enter a number :
</td>
<td>
<input id="j_idt6:number" type="text"
name="j_idt6:number" value="0" size="20" />
</td>
<td></td>
</tr>
</tbody>
</table>
<input type="submit" name="j_idt6:j_idt10" value="Submit" />
<input type="hidden" .... />
</form>
</body>
</html>
3.演示
此示例的屏幕截图。
下载源代码
Download It – JSF-2-PanelGrid-Example.zip (9KB)
参考
JSF 2 参数示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-param-example/
在 JSF 中,“ f:param ”标签允许你传递一个参数给一个组件,但是它的行为是不同的,取决于它附加的组件的类型。举个例子,
1. f:param + h:输出格式
如果将一个“ f:param ”标记附加到“ h:outputFormat ”上,该参数就指定了占位符。
<h:outputFormat value="Hello,{0}. You are from {1}.">
<f:param value="JSF User" />
<f:param value="China" />
</h:outputFormat>
下面是输出结果——“你好,JSF 用户。你来自中国”。
2.f:参数+其他组件
如果您将一个“ f:param ”标签附加到其他组件上,如“ h:commandButton ”,该参数将被转换为请求参数。
<h:commandButton id="submitButton"
value="Submit - US" action="#{user.outcome}">
<f:param name="country" value="China" />
</h:commandButton>
在用户 bean 中,您可以像这样取回参数值:
Map<String,String> params =
FacesContext.getExternalContext().getRequestParameterMap();
String countrry = params.get("country");
JSF f:参数示例
下面是一个 JSF 2.0 应用程序,展示了在“ h:commandButton 和“ h:outputFormat 组件中使用 f:param 标记。
1.受管 Bean
简单的托管 bean。
UserBean.java
package com.mkyong;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String name;
public String country;
public String outcome(){
FacesContext fc = FacesContext.getCurrentInstance();
this.country = getCountryParam(fc);
return "result";
}
//get value from "f:param"
public String getCountryParam(FacesContext fc){
Map<String,String> params = fc.getExternalContext().getRequestParameterMap();
return params.get("country");
}
//getter and setter methods
}
2.JSF·佩奇
两个 JSF 页面用于演示。
default.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 param example</h1>
<h:form id="form">
Enter your name :
<h:inputText size="10" value="#{user.name}" />
<br /><br />
<h:commandButton id="submitButton"
value="Submit - US" action="#{user.outcome}">
<f:param name="country" value="United States" />
</h:commandButton>
</h:form>
</h:body>
</html>
result.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 param example</h1>
<h2>
<h:outputFormat value="Hello,{0}. You are from {1}.">
<f:param value="#{user.name}" />
<f:param value="#{user.country}" />
</h:outputFormat>
</h2>
</h:body>
</html>
3.演示
输入您的姓名,例如“mkyong”,然后点击按钮。
显示格式化的消息,“姓名”来自用户输入,“国家”来自按钮参数。
下载源代码
Download It – JSF-2-Param-Example.zip (10KB)
参考
- JSF f:帕拉姆贾瓦德克
JSF 新协议密码示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-password-example/
在 JSF,您可以使用 < h:inputSecret / > 标签来呈现一个 HTML 输入的 type="password" ,密码字段。举个例子,
JSF 标签…
<h:inputSecret />
呈现此 HTML 代码…
<input type="password" name="j_idt6:j_idt7" />
P.S 名称属性值由 JSF 随机生成。
JSF 密码示例
一个完整的 JSF 2 示例,通过 < h:inputSecret / > 标签呈现密码输入字段。
1.受管 Bean
一个简单的托管 bean,具有“密码”属性。
package com.mkyong.form;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;
@ManagedBean
@SessionScoped
public class UserBean implements Serializable {
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
2.查看页面
演示用了两页。
demo . XHTML——通过“h:inputSecret”呈现一个密码字段,通过“h:commandButton”呈现按钮,如果点击按钮,密码值将通过 setPassword()方法提交给“userBean.password”属性,并转发给“user.xhtml”。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2 password example</h1>
<h:form>
Password : <h:inputSecret value="#{userBean.password}" />
<h:commandButton value="Submit" action="user" />
</h:form>
</h:body>
</html>
user . XHTML–通过“h:outputText”显示提交的密码值
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2 password example</h1>
Password : <h:outputText value="#{userBean.password}" />
</h:body>
</html>
3.演示
URL:http://localhost:8080/Java server faces/
显示“demo.xhtml”页面
如果单击该按钮,将显示“user.xhtml”页面,以及提交的密码值。
下载源代码
Download It – JSF-2-Password-Example.zip (9KB)
参考
相关文章
- Top 5 passwords
- Wicket password field example
- Java regex verification password example
- JSF 2 2。0 教程 JSF 2 预渲染事件示例
- [ JSF multi-component verifier 2.0
- JSF2 multiple-choice listbox example
- JSF 2 链接、commandLink 和输出链接示例
JSF 2 post constructapplicationevent 和 PreDestroyApplicationEvent 示例
从 JSF 2.0 开始,你可以注册javax.faces.event.PostConstructApplicationEvent
和javax.faces.event.PreDestroyApplicationEvent
系统事件来操纵 JSF 应用的生命周期。
1.post constructapplicationevent–在应用程序启动后执行自定义后配置。
2。predestroyaplicationevent–在应用程序即将关闭之前执行自定义清理任务。
Note
In JSF, you can’t depends on the standard ServletContextListeners
to perform above task, because the ServletContextListeners
may be run before JSF application is started.
以下示例向您展示了如何在 JSF 2.0 中创建一个PostConstructApplicationEvent
和PreDestroyApplicationEvent
系统事件。
1.实现 SystemEventListener
创建一个实现javax.faces.event.SystemEventListener
的类,并为您的定制后配置和清理任务覆盖processEvent()
和isListenerForSource()
方法。
package com.mkyong;
import javax.faces.application.Application;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.PostConstructApplicationEvent;
import javax.faces.event.PreDestroyApplicationEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
public class FacesAppListener implements SystemEventListener{
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
if(event instanceof PostConstructApplicationEvent){
System.out.println("PostConstructApplicationEvent is Called");
}
if(event instanceof PreDestroyApplicationEvent){
System.out.println("PreDestroyApplicationEvent is Called");
}
}
@Override
public boolean isListenerForSource(Object source) {
//only for Application
return (source instanceof Application);
}
}
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
2.注册系统事件
在 faces-config.xml 文件中注册PostConstructApplicationEvent
和PreDestroyApplicationEvent
系统事件,如下所示:
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<application>
<!-- Application is started -->
<system-event-listener>
<system-event-listener-class>
com.mkyong.FacesAppListener
</system-event-listener-class>
<system-event-class>
javax.faces.event.PostConstructApplicationEvent
</system-event-class>
</system-event-listener>
<!-- Before Application is shut down -->
<system-event-listener>
<system-event-listener-class>
com.mkyong.FacesAppListener
</system-event-listener-class>
<system-event-class>
javax.faces.event.PreDestroyApplicationEvent
</system-event-class>
</system-event-listener>
</application>
</faces-config>
3.演示
运行您的 JSF 应用程序。processEvent()
方法在您的 JSF 应用程序启动后执行,见下图:
Note
However, the PreDestroyApplicationEvent
is not really reliable, because JSF will not run it if it’s shut down abnormally. For example, Java process killed by system administrator, it’s always happened 😃. So, please use this system event wisely.
下载源代码
Download It – JSF-2-PostConstructApplicationEvent-Example.zip (9KB)
参考
Tags : jsf2freestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 2 预渲染事件示例
在 JSF 2.0 中,您可以在显示视图根(JSF 页面)之前附加一个javax.faces.event.PreRenderViewEvent
系统事件来执行定制任务。
让我们看下面一个完整的PreRenderViewEvent
例子:
1.受管 Bean
创建一个普通 bean,包含一个方法签名"public void method-name(ComponentSystemEvent event)",稍后你会要求监听器调用这个方法。
在此方法中,它验证当前会话中的“角色,如果角色不等于“管理员,则导航到结果“拒绝访问”。
package com.mkyong;
import javax.faces.application.ConfigurableNavigationHandler;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public void isAdmin(ComponentSystemEvent event){
FacesContext fc = FacesContext.getCurrentInstance();
if (!"admin".equals(fc.getExternalContext().getSessionMap().get("role"))){
ConfigurableNavigationHandler nav
= (ConfigurableNavigationHandler)
fc.getApplication().getNavigationHandler();
nav.performNavigation("access-denied");
}
}
}
2.JSF·佩奇
现在,您使用f:event
标记将“preRenderView
”系统事件附加到“default.xhtml”页面。
default.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<f:event listener="#{user.isAdmin}" type="preRenderView" />
<h:body>
<h1>JSF 2 protected page example</h1>
</h:body>
</html>
拒绝访问. xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h1>Access Denied!</h1>
</h:body>
</html>
3.演示
访问这个页面“ default.xhtml ”,由于 session 对象中没有“角色”值,所以 JSF 会导航到另一个页面“ access-denied.xhtml ”。
下载源代码
Download It – JSF-2-PreRenderViewEvent-Example.zip (10KB)
参考
Tags : jsf2
JSF 2 +石英 2 示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/jsf2/jsf-2-quartz-2-example/
在本教程中,我们将向您展示如何通过 Quartz 库中的QuartzInitializerListener
监听器类在 JSF web 应用程序中运行 Quartz 作业。这个解决方案不仅适用于 JSF 2,这个概念也适用于几乎所有的标准 Java web 应用程序。
使用的工具:
- JSF 2.1.11
- 石英
- maven3
- Eclipse 4.2
- Tomcat 7
之前的 JSF 2.0 hello world 示例被重用,我们将通过QuartzInitializerListener
监听器类增强它以支持 Quartz 作业。
本教程仅关注石英集成,对于 JSF,请阅读以上 JSF hello world 示例。
1.项目文件夹
检查最终的项目目录结构。
## 2.属国
要在 Tomcat 上部署,您需要许多 JSF 依赖项。有关详细信息,请阅读 XML 注释。
文件:pom.xml
<dependencies>
...
<!-- JSF 2 libraries -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.1.11</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.1.11</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
<!-- Tomcat 6 need this -->
<dependency>
<groupId>com.sun.el</groupId>
<artifactId>el-ri</artifactId>
<version>1.0</version>
</dependency>
<!-- Quartz scheduler framework -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.1.5</version>
</dependency>
<!-- Quartz need transaction -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
...
3.石英工作
创建一个 Quartz 作业类。该课程将在以后安排和运行。
文件:SchedulerJob.java
package com.mkyong.scheduler;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class SchedulerJob implements Job {
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("JSF 2 + Quartz 2 example");
}
}
4.石英结构
创建quartz.properties
和quartz-config.xml
,将其放在 resources“文件夹”(Maven 结构)中,对于非 Maven 项目,确保它可以位于项目类路径中。
文件:quartz . properties–配置 Quartz 实例并从quartz-config.xml
读取设置
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
文件:quartz-config . XML–配置触发器运行com.mkyong.scheduler.SchedulerJob
<?xml version="1.0" encoding="UTF-8"?>
<job-scheduling-data
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData
http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"
version="1.8">
<schedule>
<job>
<name>AJob</name>
<group>AGroup</group>
<description>Print a welcome message</description>
<job-class>com.mkyong.scheduler.SchedulerJob</job-class>
</job>
<trigger>
<cron>
<name>dummyTriggerName</name>
<job-name>AJob</job-name>
<job-group>AGroup</job-group>
<!-- It will run every 5 seconds -->
<cron-expression>0/5 * * * * ?</cron-expression>
</cron>
</trigger>
</schedule>
</job-scheduling-data>
Note
For detail explanation, please read this Quartz configuration reference article.
5.集成石英
这是整合发生的地方。在web.xml
文件中将org.quartz.ee.servlet.QuartzInitializerListener
声明为监听器类。
文件:web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
<listener>
<listener-class>
org.quartz.ee.servlet.QuartzInitializerListener
</listener-class>
</listener>
</web-app>
6.演示
在项目启动期间,Quartz 启动并每隔 5 秒运行一次计划的作业。
Jul 26, 2012 3:32:18 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Jul 26, 2012 3:32:18 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Jul 26, 2012 3:32:18 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 3591 ms
JSF 2 + Quartz 2 example
JSF 2 + Quartz 2 example
JSF 2 + Quartz 2 example
下载源代码
Download it – JSF-Quartz-Example.zip (25 kb)
参考
JSF 2 单选按钮示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-radio-buttons-example/
在 JSF 中,“ h:selectOneRadio 标签用于呈现一组“ radio 类型的 HTML 输入元素,并使用 HTML table 和 label 标签对其进行格式化。
//JSF...
<h:selectOneRadio value="#{user.favColor1}">
<f:selectItem itemValue="Red" itemLabel="Color1 - Red" />
<f:selectItem itemValue="Green" itemLabel="Color1 - Green" />
<f:selectItem itemValue="Blue" itemLabel="Color1 - Blue" />
</h:selectOneRadio>
//HTML output...
<table>
<tr>
<td>
<input type="radio" name="j_idt6:j_idt8" id="j_idt6:j_idt8:0" value="Red" />
<label for="j_idt6:j_idt8:0"> Color1 - Red</label></td>
<td>
<input type="radio" name="j_idt6:j_idt8" id="j_idt6:j_idt8:1" value="Green" />
<label for="j_idt6:j_idt8:1"> Color1 - Green</label></td>
<td>
<input type="radio" name="j_idt6:j_idt8" id="j_idt6:j_idt8:2" value="Blue" />
<label for="j_idt6:j_idt8:2"> Color1 - Blue</label>
</td>
</tr>
</table>
JSF 2.0“h:selectone radio”示例
一个 JSF 2.0 示例,展示了如何使用" h:selectOneRadio "标记来呈现单选按钮,并以 3 种不同的方式填充数据:
- “f:selecti item标签中的硬核值。
- 用 Map 生成值,并将其放入“f:selecti items标签中。
- 用一个对象数组生成值,放入“ f:selectItems ”标签,然后用一个“ var 属性表示该值。
1.支撑豆
用于保存提交数据的后备 bean。
package com.mkyong;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String favColor1;
public String favColor2;
public String favColor3;
//getter and setter methods
//Generated by Map
private static Map<String,Object> color2Value;
static{
color2Value = new LinkedHashMap<String,Object>();
color2Value.put("Color2 - Red", "Red"); //label, value
color2Value.put("Color2 - Green", "Green");
color2Value.put("Color3 - Blue", "Blue");
}
public Map<String,Object> getFavColor2Value() {
return color2Value;
}
//Generated by Object array
public static class Color{
public String colorLabel;
public String colorValue;
public Color(String colorLabel, String colorValue){
this.colorLabel = colorLabel;
this.colorValue = colorValue;
}
public String getColorLabel(){
return colorLabel;
}
public String getColorValue(){
return colorValue;
}
}
public Color[] color3List;
public Color[] getFavColor3Value() {
color3List = new Color[3];
color3List[0] = new Color("Color3 - Red", "Red");
color3List[1] = new Color("Color3 - Green", "Green");
color3List[2] = new Color("Color3 - Blue", "Blue");
return color3List;
}
}
2.JSF·佩奇
演示“ h:selectOneRadio ”标签使用的 JSF 页面。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 radio button example</h1>
<h:form>
1\. Hard-coded with "f:selectItem" :
<h:selectOneRadio value="#{user.favColor1}">
<f:selectItem itemValue="Red" itemLabel="Color1 - Red" />
<f:selectItem itemValue="Green" itemLabel="Color1 - Green" />
<f:selectItem itemValue="Blue" itemLabel="Color1 - Blue" />
</h:selectOneRadio>
<br />
2\. Generated by Map :
<h:selectOneRadio value="#{user.favColor2}">
<f:selectItems value="#{user.favColor2Value}" />
</h:selectOneRadio>
<br />
3\. Generated by Object array and iterate with var :
<h:selectOneRadio value="#{user.favColor3}">
<f:selectItems value="#{user.favColor3Value}" var="c"
itemLabel="#{c.colorLabel}" itemValue="#{c.colorValue}" />
</h:selectOneRadio>
<br />
<h:commandButton value="Submit" action="result" />
<h:commandButton value="Reset" type="reset" />
</h:form>
</h:body>
</html>
result.xhtml…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h1>JSF 2 radio button example</h1>
<h2>result.xhtml</h2>
<ol>
<li>user.favColor1 : #{user.favColor1}</li>
<li>user.favColor2 : #{user.favColor2}</li>
<li>user.favColor3 : #{user.favColor3}</li>
</ol>
</h:body>
</html>
3.演示
单击“提交”按钮时,链接到“result.xhtml”并显示提交的单选按钮值。
如何默认选择单选按钮值?
在 JSF 中,如果与“ h:selectOneRadio ”标签的“值”匹配,则选择“ f:selectItems ”标签的单选按钮值。在上面的例子中,如果你设置 favColor2 为“红色”:
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String[] favColor = "Red";
//...
“favColor2”单选按钮,“红色”选项默认选中。
下载源代码
Download It – JSF-2-RadioButtons-Example.zip (10KB)
参考
JSF 2 重复标签示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-repeat-tag-example/
ui:repeat
总是作为h:dataTable
的替代,循环数组或列表,以 HTML 表格格式显示数据。请参见以下示例:
1.h:数据表
在数据表中,JSF 帮助你生成所有的 HTML 表格标签。
<h:dataTable value="#{order.orderList}" var="o">
<h:column>
#{o.orderNo}
</h:column>
<h:column>
#{o.productName}
</h:column>
<h:column>
#{o.price}
</h:column>
<h:column>
#{o.qty}
</h:column>
</h:dataTable>
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
2.ui:重复
在重复标签中,你必须手工放置所有的 HTML 表格标签。
<table>
<ui:repeat var="o" value="#{order.orderList}" varStatus="status">
<tr>
<td>#{o.orderNo}</td>
<td>#{o.productName}</td>
<td>#{o.price}</td>
<td>#{o.qty}</td>
</tr>
</ui:repeat>
</table>
ui:重复示例
这里有一个 JSF 2.0 ui:重复示例来渲染完全相同的 HTML 输出,就像这样 h:dataTable 示例。比较两者,找出不同之处。
JSF…
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
>
<h:head>
<h:outputStylesheet library="css" name="table-style.css" />
</h:head>
<h:body>
<h1>JSF 2 ui:repeat tag example</h1>
<table class="order-table">
<tr>
<th class="order-table-header">Order No</th>
<th class="order-table-header">Product Name</th>
<th class="order-table-header">Price</th>
<th class="order-table-header">Quantity</th>
</tr>
<tbody>
<ui:repeat var="o" value="#{order.orderList}" varStatus="status">
<h:panelGroup rendered="#{status.even}">
<tr>
<td class="order-table-even-row">#{o.orderNo}</td>
<td class="order-table-even-row">#{o.productName}</td>
<td class="order-table-even-row">#{o.price}</td>
<td class="order-table-even-row">#{o.qty}</td>
</tr>
</h:panelGroup>
<h:panelGroup rendered="#{status.odd}">
<tr>
<td class="order-table-odd-row">#{o.orderNo}</td>
<td class="order-table-odd-row">#{o.productName}</td>
<td class="order-table-odd-row">#{o.price}</td>
<td class="order-table-odd-row">#{o.qty}</td>
</tr>
</h:panelGroup>
</ui:repeat>
</tbody>
</table>
</h:body>
</html>
Note
You can find the “order” managed bean source code in this h:dataTable example.
“ ui:repeat ”标签带有许多有用的属性,如偏移量、大小、状态等。确保您检查了这个 JSF 用户界面:重复 javadoc 。
输出
下载源代码
Download It – JSF-2-Repeat-Tag-Example.zip (10KB)
参考
- JSF ui:重复 JavaDoc
- JSF h:数据表 JavaDoc
- JSF h:panelGroup JavaDoc
Tags : jsf2freestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 2 setPropertyActionListener 示例
在 JSF,“f:setPropertyActionListener”标签允许你直接设置一个值到你的后台 bean 的属性中。举个例子,
<h:commandButton action="#{user.outcome}" value="Submit">
<f:setPropertyActionListener target="#{user.username}" value="mkyong" />
</h:commandButton>
在上面的 JSF 代码片段中,如果单击按钮,它会通过 setUsername() 方法将“ mkyong ”值设置为“用户名”属性。
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String username;
public void setUsername(String username) {
this.username = username;
}
}
JSF f:setPropertyActionListener 示例
好了,让我们来看一个 JSF 2.0 的完整例子。
1.受管 Bean
一个名为“user”的超级简单的托管 bean。
package com.mkyong;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean{
public String username;
public String outcome(){
return "result";
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
2.JSF·佩奇
JSF 页面展示了如何使用"f:setPropertyActionListener"将一个值" mkyong "直接设置到您的后台 bean 的属性" username "中。
default.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 setPropertyActionListener example</h1>
<h:form id="form">
<h:commandButton action="#{user.outcome}" value="Click Me">
<f:setPropertyActionListener target="#{user.username}" value="mkyong" />
</h:commandButton>
</h:form>
</h:body>
</html>
result.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
>
<h:body>
<h1>JSF 2 setPropertyActionListener example</h1>
#{user.username}
</h:body>
</html>
3.演示
这是点击按钮后的结果。
下载源代码
Download It – JSF-2-setPropertyActionListener-Example.zip (9KB)
参考
使用 Facelets 的 JSF 2 模板示例
在 web 应用程序中,大多数页面都遵循相似 web 界面布局和样式,例如,相同的页眉和页脚。在 JSF 2.0 中,你可以很容易地使用 Facelets 标签来提供一个标准的 web 界面布局,事实上,它看起来与 Apache Tiles 框架很相似。
在本例中,它展示了使用 4 个 Facelets 标记从模板构建页面:
- ui:插入–用于模板文件,定义加载模板的文件将要替换的内容。内容可以替换为“ui:define”标签。
- ui:define–用匹配的“ui:insert”标签定义插入模板的内容。
- ui:include——类似于 JSP 的“jsp:include”,包含来自另一个 XHTML 页面的内容。
- ui:composition–如果与“template”属性一起使用,则加载指定的模板,该标签的子标签定义模板布局;否则,它就是一组元素,可以插入到某个地方。此外,JSF 删除了“ui:composition”标签之外的所有标签。
1.型板布置
在 JSF 2.0 中,模板文件只是一个普通的 XHTML 文件,很少有 JSF facelets 标签来定义模板布局。
文件:commonLayout.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:head>
<h:outputStylesheet name="common-style.css" library="css" />
</h:head>
<h:body>
<div id="page">
<div id="header">
<ui:insert name="header" >
<ui:include src="/template/common/commonHeader.xhtml" />
</ui:insert>
</div>
<div id="content">
<ui:insert name="content" >
<ui:include src="/template/common/commonContent.xhtml" />
</ui:insert>
</div>
<div id="footer">
<ui:insert name="footer" >
<ui:include src="/template/common/commonFooter.xhtml" />
</ui:insert>
</div>
</div>
</h:body>
</html>
在这个模板中,它定义了一个标准的 web 布局:
- 使用" h:outputStylesheet "标记在 head 中包含一个 CSS 文件,以设计整个页面布局的样式。
- 使用“ ui:insert 标签定义三个可替换的部分:页眉、内容和页脚。
- 使用模板时,如果没有指定替换,则使用“ ui:include 标签提供默认内容。
2.页眉、内容和页脚
三个默认页面内容。
文件:commonHeader.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<body>
<ui:composition>
<h1>This is default header</h1>
</ui:composition>
</body>
</html>
文件:commonContent.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<body>
<ui:composition>
<h1>This is default content</h1>
</ui:composition>
</body>
</html>
文件:commonFooter.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<body>
<ui:composition>
<h1>This is default footer</h1>
</ui:composition>
</body>
</html>
当这些页面被插入到模板文件中时,所有在“ui:composition
”之外的标签都将被删除。举个例子,
文件:commonHeader.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<body>
ALL TAGS ABOVE THIS LINE WILL BE REMOVED BY JSF
<ui:composition>
<h1>This is default header</h1>
</ui:composition>
ALL TAGS BELOW THIS LINE WILL BE REMOVED BY JSF
</body>
</html>
JSF 只取下列元素并插入到模板文件中
<ui:composition>
<h1>This is default header</h1>
</ui:composition>
当插入到“commonLayout”模板中时,它变成了…
文件:commonLayout.xhtml
...
<h:body>
<div id="page">
<div id="header">
<h1>This is default header</h1>
</div>
...
3.使用模板
要使用现有的模板,例如"commonLayout.xhtml
",您可以使用带有" template "属性的"ui:composition
"标记。参见以下两个例子:
文件:default.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<ui:composition template="template/common/commonLayout.xhtml">
</ui:composition>
</h:body>
</html>
这个 JSF 页面加载“commonLayout.xhtml”模板并显示所有默认页面内容。
文件:page1.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<ui:composition template="/template/common/commonLayout.xhtml">
<ui:define name="content">
<h2>This is page1 content</h2>
</ui:define>
<ui:define name="footer">
<h2>This is page1 Footer</h2>
</ui:define>
</ui:composition>
</h:body>
</html>
这个 JSF 页面加载一个“commonLayout.xhtml”模板,并使用“ui:define”标记来覆盖模板文件中定义的“ui:insert”标记。
Note
As long as the name of the “ui:define” tag is matched to the name of the “ui:insert” tag, which defined in template, the “ui:insert” content is replaced.
下载源代码
Download It – JSF-2-Facelets-Template-Example.zip (12KB)
引用
JSF 2 文本区示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-textarea-example/
在 JSF,你可以使用 < h:inputTextarea / > 标签来呈现一个 HTML 文本区域字段。举个例子,
JSF 标签…
<h:inputTextarea cols="30" rows="10" />
呈现此 HTML 代码…
<textarea name="random value" cols="30" rows="10"></textarea>
JSF 文本区示例
一个完整的 JSF 2 示例,通过 < h:inputTextarea / > 标签呈现一个 textarea 字段。
1.受管 Bean
一个被管理的 bean,被声明为名称“user”。
package com.mkyong.form;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2.查看页面
演示用了两页。
demo . XHTML–通过“h:inputTextarea”呈现一个 Textarea 字段,通过“h:commandButton”呈现按钮,如果点击按钮,textarea 值将通过 setAddress()方法提交给“userBean.address”属性,并转发给“user.xhtml”。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2 textarea example</h1>
<h:form>
<table>
<tr>
<td valign="top">Address :</td>
<td><h:inputTextarea value="#{user.address}" cols="30" rows="10" /></td>
</tr>
</table>
<h:commandButton value="Submit" action="user" />
</h:form>
</h:body>
</html>
user . XHTML–通过“h:outputText”显示提交的 textarea 值
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2 textarea example</h1>
Address : <h:outputText value="#{user.address}" />
</h:body>
</html>
3.演示
URL:http://localhost:8080/Java server faces/
显示“demo.xhtml”页面
如果单击该按钮,将显示“user.xhtml”页面,以及提交的 textarea 值。
下载源代码
Download It – JSF-2-TextArea-Example.zip (9KB)
参考
相关文章
- 在文本区域上添加 maxlength 使用 jQuery
- Wicket textArea 示例
- JSF 2.0 tutorial
- JSF 2 PreRenderViewEvent 示例
- JSF 多组件验证器 2.0
- JSF 2 多选列表框示例
- JSF 2 链接、commandLink 和输出链接示例
JSF 2 文本框示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-textbox-example/
在 JSF,你可以使用 < h:inputText / > 标签来呈现一个 HTML 输入的 type="text" ,文本框。举个例子,
JSF 标签…
<h:inputText />
呈现此 HTML 代码…
<input type="text" name="j_idt6:j_idt7" />
P.S 名称属性值由 JSF 随机生成。
JSF 文本框示例
一个完整的 JSF 2 示例,通过 < h:inputText / > 标签呈现一个文本框输入字段。
1.受管 Bean
一个简单的托管 bean,具有“用户名”属性。
package com.mkyong.form;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;
@ManagedBean
@SessionScoped
public class UserBean implements Serializable {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
2.查看页面
演示用了两页。
demo . XHTML–通过“h:inputText”呈现 textbox,通过“h:commandButton”呈现 button,如果点击按钮,textbox 的值将通过 setUserName()方法提交给“userBean.userName”属性,并转发给“user.xhtml”。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2 textbox example</h1>
<h:form>
<h:inputText value="#{userBean.userName}" />
<h:commandButton value="Submit" action="user" />
</h:form>
</h:body>
</html>
user . XHTML–通过“h:outputText”显示提交的文本框值
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h1>JSF 2 textbox example</h1>
Submitted value : <h:outputText value="#{userBean.userName}" />
</h:body>
</html>
3.演示
URL:http://localhost:8080/Java server faces/
显示“demo.xhtml”页面
如果单击按钮,显示“user.xhtml”页面和提交的文本框值
下载源代码
Download It – JSF-2-TextBox-Example.zip (9KB)
参考
相关文章
-
How to get textbox value with jQuery
-
[How to add/remove textbox 【T1] dynamically with jQuer](/web/20201212022629/https://www.mkyong.com/jquery/how-to-add-remove-textbox-dynamically-with-jquery/)
JSF 2 有效双程示例
" f:validateDoubleRange "是一个 JSF 范围验证器标签,用于验证浮点值的范围。举个例子,
<h:inputText id="salary" value="#{user.salary}">
<f:validateDoubleRange minimum="10.11" maximum="10000.11" />
</h:inputText>
提交该表单时,验证器将确保“薪金”值在“10.11”到“10000.11”的范围内。
“f:validateDoubleRange”示例
一个 JSF 2.0 的例子展示了如何使用" f:validateDoubleRange "标签来验证" salary "输入字段的范围,当验证器失败时,通过" h:message "标签显示错误消息。
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
1.受管 Bean
用户管理的 bean,具有“薪金”属性。
package com.mkyong;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
double salary;
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
2.JSF·佩奇
JSF XHTML 页面,展示了如何使用" f:validateDoubleRange "标记来确保" salary "输入值在" 10.11 "到" 10000.11 "的范围内。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 validateDoubleRange example</h1>
<h:form>
<h:panelGrid columns="3">
Enter your salary :
<h:inputText id="salary" value="#{user.salary}"
size="10" required="true"
label="Salary" >
<f:validateDoubleRange minimum="10.11" maximum="10000.11" />
</h:inputText>
<h:message for="salary" style="color:red" />
</h:panelGrid>
<h:commandButton value="Submit" action="result" />
</h:form>
</h:body>
</html>
3.演示
最小范围验证失败。
下载源代码
Download It – JSF-2-ValidateDoubleRange-Example.zip (9KB)
参考
Tags : jsf2 validationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 2 有效长度示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-validatelength-example/
" f:validateLength "是一个 JSF 字符串长度验证器标签,用于检查字符串的长度。举个例子,
<h:inputText id="username" value="#{user.username}">
<f:validateLength minimum="5" maximum="10" />
</h:inputText>
提交表单时,验证器将确保“用户名”文本字段包含的最小长度为 5,最大长度为 10。
“f:validateLength”示例
一个 JSF 2.0 的例子,展示了使用" f:validateLength "标签来验证"用户名"文本字段的长度,当验证器失败时,通过" h:message "标签显示错误消息。
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
1.受管 Bean
仅保存“用户名”属性的虚拟受管 bean。
package com.mkyong;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
2.JSF·佩奇
JSF XHTML 页面,展示了如何使用" f:validateLength "标记来确保表单的输入" username "包含的最小长度为 5,最大长度为 10。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
>
<h:body>
<h1>JSF 2 validateLength example</h1>
<h:form>
<h:panelGrid columns="3">
Enter UserName :
<h:inputText id="username" value="#{user.username}"
size="20" required="true"
label="UserName" >
<f:validateLength minimum="5" maximum="10" />
</h:inputText>
<h:message for="username" style="color:red" />
</h:panelGrid>
<h:commandButton value="Submit" action="result" />
</h:form>
</h:body>
</html>
3.演示
最小长度验证失败。
最大长度验证失败。
下载源代码
Download It – JSF-2-ValidateLength-Example.zip (9KB)
参考
Tags : jsf2 validatationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 2 有效范围示例
" f:validateLongRange "是一个 JSF 范围验证器标签,用于检查数值的范围。举个例子,
<h:inputText id="age" value="#{user.age}">
<f:validateLongRange minimum="1" maximum="150" />
</h:inputText>
提交表单时,验证器将确保“年龄”值在 1 到 150 的范围内。
“f:validateLongRange”示例
一个 JSF 2.0 的例子,展示了如何使用" f:validateLongRange "标签来验证" age "输入域的范围,当验证器失败时,通过" h:message "标签显示错误消息。
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
1.受管 Bean
用户管理的 bean,具有“年龄”属性。
package com.mkyong;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.JSF·佩奇
JSF XHTML 页面,展示了如何使用“ f:validateLongRange ”标签来确保“年龄”输入值在 1 到 150 的范围内。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 validateLongRange example</h1>
<h:form>
<h:panelGrid columns="3">
Enter your age :
<h:inputText id="age" value="#{user.age}"
size="10" required="true"
label="Age" >
<f:validateLongRange maximum="150" minimum="1" />
</h:inputText>
<h:message for="age" style="color:red" />
</h:panelGrid>
<h:commandButton value="Submit" action="result" />
</h:form>
</h:body>
</html>
3.演示
最大范围验证失败。
下载源代码
Download It – JSF-2-ValidateLongRange-Example.zip (9KB)
参考
Tags : jsf2 validationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 新协议有效性示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-validateregex-example/
" f:validateRegex "是 JSF 2.0 中一个新的验证器标签,用于验证具有给定正则表达式模式的 JSF 组件。举个例子,
<h:inputSecret id="password" value="#{user.password}">
<f:validateRegex pattern="((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})" />
</h:inputSecret>
上述 regex 模式需要 6 到 20 个字符的字符串,至少包含一个数字、一个大写字母、一个小写字母和一个特殊符号(" @#$% ")。这对于密码验证来说足够强大和复杂,参见这个带正则表达式的密码验证。
“f:validateRegex”示例
一个 JSF 2.0 的例子,展示了如何使用" f:validateRegex "标签来创建一个强密码验证器。
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
1.受管 Bean
用户管理的 bean。
package com.mkyong;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
2.JSF·佩奇
JSF XHTML 页面,展示了如何使用“ f:validateRegex ”标签来确保“密码”字段匹配给定的正则表达式模式。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 validateRegex example</h1>
<h:form>
<h:panelGrid columns="3">
Enter your password :
<h:inputSecret id="password" value="#{user.password}"
size="20" required="true"
label="Password">
<f:validateRegex
pattern="((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})" />
</h:inputSecret>
<h:message for="password" style="color:red" />
</h:panelGrid>
<h:commandButton value="Submit" action="result" />
</h:form>
</h:body>
</html>
3.演示
如果“密码”与 regex 模式不匹配,则显示错误消息。
下载源代码
Download It – JSF-2-ValidateRegex-Example.zip (9KB)
参考
Tags : jsf2 regex validationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 新协议验证必需的示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/jsf-2-validaterequired-example/
" f:validateRequired "是 JSF 2.0 中一个新的验证器标签,用来确保输入字段不为空。举个例子,
<h:inputSecret id="password" value="#{user.password}">
<f:validateRequired />
</h:inputSecret>
或者,您也可以使用“required”属性,两者都执行相同的空值验证。
<h:inputSecret id="password" value="#{user.password}" required="true" />
“f:validateRequired”示例
一个 JSF 2.0 的例子,展示了如何使用“ f:validateRequired ”标签来确保“密码”字段不为空。
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
1.受管 Bean
用户管理的 bean。
package com.mkyong;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="user")
@SessionScoped
public class UserBean implements Serializable{
String password;
String confPassword;
//getter and setter methods
}
2.JSF·佩奇
JSF XHTML 页面,展示了如何使用“ f:validateRequired ”标签来确保“密码”和“确认密码”字段不为空。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:body>
<h1>JSF 2 validateRequired example</h1>
<h:form>
<h:panelGrid columns="3">
Enter your password :
<h:inputSecret id="password" value="#{user.password}"
size="20" required="true"
label="Password" />
<h:message for="password" style="color:red" />
Enter your password again :
<h:inputSecret id="confPassword" value="#{user.confPassword}"
size="20" label="Confirm Password">
<f:validateRequired />
</h:inputSecret>
<h:message for="confPassword" style="color:red" />
</h:panelGrid>
<h:commandButton value="Submit" action="result" />
</h:form>
</h:body>
</html>
3.演示
如果“密码”或“确认密码”字段为空,则显示错误消息。
下载源代码
Download It – JSF-2-ValidateRequired-Example.zip (9KB)
参考
Tags : jsf2 validationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF 2 值更改监听程序示例
当用户对输入组件进行更改时,如 h:inputText 或 h:selectOneMenu ,将触发 JSF“值更改事件。
实现它的两种方法:
1。方法绑定–在输入组件中,直接在“ valueChangeListener ”属性中指定了 bean 的方法。
JSF……
<h:selectOneMenu value="#{bean.value}" onchange="submit()"
valueChangeListener="#{bean.valueChangeMethod}">
<f:selectItems value="#{bean.values}" />
</h:selectOneMenu>
Java…
与值变化事件交互的方法应该接受一个 ValueChangeEvent 参数。
@ManagedBean(name="bean")
@SessionScoped
public class BeanBean{
public void valueChangeMethod(ValueChangeEvent e){
//...
}
}
2。valueChangeListener 接口——在输入组件中,内部添加了一个“ f:valueChangeListener 标签,并指定了 ValueChangeListener 接口的一个实现类。
JSF……
<h:selectOneMenu value="#{bean.value}" onchange="submit()">
<f:valueChangeListener type="ValueListenerXXX" />
<f:selectItems value="#{bean.values}" />
</h:selectOneMenu>
Java…
实现 ValueChangeListener 接口并覆盖 processValueChange() 方法。
public class ValueListenerXXX implements ValueChangeListener{
@Override
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException {
//...
}
}
Note
To make it work, you have to attach a onchange=”submit()” JavaScript to the input component; Otherwise, no event will be fired.
完整的 valueChangeListener 示例
这是一个 JSF 2.0 应用程序,有一个下拉框( h:selectOneMenu )和一个文本框( h:inputText ),当用户在下拉框中进行更改时,它会触发“值更改事件”并用新选择的下拉框值更新文本框。
这个例子以“方法绑定和“ ValueChangeListener ”两种方式进行了演示。
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
1.方法绑定
一个 country bean,为演示提供国家和地区代码列表。您可以通过输入组件中的" valueChangeListener "属性绑定 bean 的方法。见下文:
CountryBean.java 的缩写形式
package com.mkyong;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ValueChangeEvent;
@ManagedBean(name="country")
@SessionScoped
public class CountryBean implements Serializable{
private static final long serialVersionUID = 1L;
private static Map<String,String> countries;
private String localeCode = "en"; //default value
static{
countries = new LinkedHashMap<String,String>();
countries.put("United Kingdom", "en"); //label, value
countries.put("French", "fr");
countries.put("German", "de");
countries.put("China", "zh_CN");
}
public void countryLocaleCodeChanged(ValueChangeEvent e){
//assign new value to localeCode
localeCode = e.getNewValue().toString();
}
public Map<String,String> getCountryInMap() {
return this.countries;
}
public String getLocaleCode() {
return localeCode;
}
public void setLocaleCode(String localeCode) {
this.localeCode = localeCode;
}
}
JSF 页面
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<h1>JSF 2 valueChangeListener example</h1>
<h:form>
<h:panelGrid columns="2">
Selected country :
<h:inputText id="country" value="#{country.localeCode}" size="20" />
Select a country {method binding}:
<h:selectOneMenu value="#{country.localeCode}" onchange="submit()"
valueChangeListener="#{country.countryLocaleCodeChanged}">
<f:selectItems value="#{country.countryInMap}" />
</h:selectOneMenu>
</h:panelGrid>
</h:form>
</h:body>
</html>
2.ValueChangeListener 接口
重用 above country bean 来提供国家和地区代码的列表。实现 ValueChangeListener 接口,并通过“ f:valueChangeListener 标签绑定。见下文:
CountryValueListener.java
package com.mkyong;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;
public class CountryValueListener implements ValueChangeListener{
@Override
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException {
//access country bean directly
CountryBean country = (CountryBean) FacesContext.getCurrentInstance().
getExternalContext().getSessionMap().get("country");
country.setLocaleCode(event.getNewValue().toString());
}
}
JSF 页面
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:body>
<h1>JSF 2 valueChangeListener example</h1>
<h:form>
<h:panelGrid columns="2">
Selected country :
<h:inputText id="country" value="#{country.localeCode}" size="20" />
Select a country {ValueChangeListener class}:
<h:selectOneMenu value="#{country.localeCode}" onchange="submit()">
<f:valueChangeListener type="com.mkyong.CountryValueListener" />
<f:selectItems value="#{country.countryInMap}" />
</h:selectOneMenu>
</h:panelGrid>
</h:form>
</h:body>
</html>
演示
默认情况下,选择国家“英国”。
如果国家/地区下拉框值被更改,则触发 valueChangeListener ,并用新选择的 dropdrow 框值更新 textbox 值。
下载源代码
Download It – JSF-2-ValueChangeListener-Example.zip (10KB)
参考
Tags : jsf2freestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
JSF“从活动”导航规则示例
在 JSF 导航规则中,您可能会遇到这样的情况:两个单独的操作在一个页面中返回相同的“结果”。在这种情况下,您可以使用“ from-action ”元素来区分这两种导航情况。请参见以下示例:
1.受管 Bean
一个受管 bean,有两个操作返回相同的结果——“成功”。
PageController.java
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.Serializable;
@ManagedBean
@SessionScoped
public class PageController implements Serializable {
private static final long serialVersionUID = 1L;
public String processPage1(){
return "success";
}
public String processPage2(){
return "success";
}
}
2.JSF·佩奇
一个 JSF 页面,有两个按钮链接到上面的PageController
的方法。
start.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h2>This is start.xhtml</h2>
<h:form>
<h:commandButton action="#{pageController.processPage1}" value="Page1" />
<h:commandButton action="#{pageController.processPage2}" value="Page2" />
</h:form>
</h:body>
</html>
两种行动都将返回同样的“成功”结局,JSF 如何决定何去何从?
3.导航规则
为了解决这个问题,在“faces-config.xml
”中定义了以下导航规则,并使用“ from-action ”元素来区分相同的“结果”导航案例。
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<navigation-rule>
<from-view-id>start.xhtml</from-view-id>
<navigation-case>
<from-action>#{pageController.processPage1}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>page1.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{pageController.processPage2}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>page2.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
4.演示
在上面的例子中,按钮是这样工作的:
- 当点击带有action = " # { page controller . process page 1 } "的按钮时,将返回“成功”结果,并移动到 page1.xhtml
- 当点击带有action = " # { page controller . process page 2 } "的按钮时,将返回“成功”结果,并移动到 page2.xhtml
下载源代码
Download it – JSF-2-From-Action-Navigation-Example.zip (11KB)Tags : jsf2 navigation rule
相关文章
JSF:页面转发 vs 页面重定向
默认情况下,JSF 将在导航到另一个页面时向前执行一个服务器页面。请参见下面的示例来区分页面转发和页面重定向。
一个“start.xhtml
”页面,带有一个导航到“page1.xhtml
”页面的按钮。
1.向前翻页
下面是向前翻页的工作方式:
- 浏览器发送一个“ GET 请求到 URL:http://localhost:8080/Java server faces/faces/start . XHTML。
- JSF 收到请求并返回“ start.xhtml ”。
- 浏览器显示“ start.xhtml 的内容。
- 用户点击按钮。
- JSF 收到动作,在服务器端执行一个内部页面转发到“ page1.xhtml ”。
- JSF 返回了" page1.xhtml "。
- 浏览器显示" page1.xhtml 的内容。
在页面转发中,浏览器的 URL 不更新。
2.页面重定向
页面重定向的工作原理如下:
- 浏览器发送一个“ GET 请求到 URL:http://localhost:8080/Java server faces/faces/start . XHTML。
- JSF 收到请求并返回“ start.xhtml ”。
- 浏览器显示“ start.xhtml 的内容。
- 用户点击按钮。
- JSF 收到这个动作,并向浏览器发回一个“重定向到“ page1.xhtml ”的响应。
- 浏览器收到响应后,向 URL 发送另一个“ GET ”请求:http://localhost:8080/Java server faces/faces/page 1 . XHTML。
- JSF 收到请求并返回" page1.xhtml "。
- 浏览器显示“ page1.xhtml 的内容,浏览器的网址更新。
要在 JSF 2.0 中启用页面重定向,可以在结果字符串的末尾附加“faces-redirect=true
”。
向前翻页。
<h:form>
<h:commandButton action="page1" value="Page1" />
</h:form>
页面重定向。
<h:form>
<h:commandButton action="page1?faces-redirect=true" value="Page1" />
</h:form>
在导航规则中,您可以通过在<navigation-case />
中添加一个<redirect />
元素来启用页面重定向。
<navigation-rule>
<from-view-id>start.xhtml</from-view-id>
<navigation-case>
<from-outcome>page1</from-outcome>
<to-view-id>page1.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
结论
与页面重定向相比,默认页面转发机制更快,因为页面重定向向服务器添加了额外的 HTTP 请求。所以,只在必要的时候启用页面重定向,比如使用 Post/Redirect/Get 设计模式来解决经典的重复表单提交问题。
下载源代码
Download it – JSF-2-Page-Redirection-Example.zip (9KB)
JSON . simple——读写 JSON
JSON.simple 是一个简单的 Java 库,用于 JSON 处理、读写 JSON 数据,完全符合 JSON 规范(RFC4627)
Warning
This article is using the old JSON.simple 1.x
,which is deprecated and no longer maintained by the author. Please visit this upgraded article – JSON.simple 3.x – How to parse JSONWhy not Jackson or Gson?
You may have interest to read this article – How to parse JSON with Jackson or Gson
1.下载 JSON.simple
pom.xml
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
2.将 JSON 写入文件
JsonSimpleWriteExample.java
package com.mkyong;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.io.FileWriter;
import java.io.IOException;
public class JsonSimpleWriteExample {
public static void main(String[] args) {
JSONObject obj = new JSONObject();
obj.put("name", "mkyong.com");
obj.put("age", 100);
JSONArray list = new JSONArray();
list.add("msg 1");
list.add("msg 2");
list.add("msg 3");
obj.put("messages", list);
try (FileWriter file = new FileWriter("c:\\projects\\test.json")) {
file.write(obj.toJSONString());
} catch (IOException e) {
e.printStackTrace();
}
System.out.print(obj);
}
}
输出
Terminal
{"name":"mkyong.com","messages":["msg 1","msg 2","msg 3"],"age":100}
c:\projects\test.json
{"name":"mkyong.com","messages":["msg 1","msg 2","msg 3"],"age":100}
3.将 JSON 读取到文件
JsonSimpleReadExample.java
package com.mkyong;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Iterator;
public class JsonSimpleReadExample {
public static void main(String[] args) {
JSONParser parser = new JSONParser();
try (Reader reader = new FileReader("c:\\projects\\test.json")) {
JSONObject jsonObject = (JSONObject) parser.parse(reader);
System.out.println(jsonObject);
String name = (String) jsonObject.get("name");
System.out.println(name);
long age = (Long) jsonObject.get("age");
System.out.println(age);
// loop array
JSONArray msg = (JSONArray) jsonObject.get("messages");
Iterator<String> iterator = msg.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
输出
Terminal
{"name":"mkyong.com","messages":["msg 1","msg 2","msg 3"],"age":100}
mkyong.com
100
msg 1
msg 2
msg 3
参考
- JSON.simple 3.x 首页
- JSON.simple 1.x 首页
- JSON.simple 1.x 谷歌主页
- JSON.simple 1.x 编码示例
- JSON . simple 1 . x decoding 示例
- Gson–如何处理 JSON
- Jackson–如何解析 JSON
- JSON . simple 3 . x–如何解析 JSON
简单——如何解析 JSON
原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/java/json-simple-how-to-parse-json/
在本教程中,我们将向您展示如何用 JSON.simple 解析 JSON
Note
You may have interest to read – How to parse JSON with Jackson or GsonJSON.simple short history
This project was formerly JSON.simple 1.x from a Google code project by Yidong, now maintaining by Clifton Labs, read this JSON.simple history
用 json-simple 3.1.0 测试的 PS
1.下载 JSON.simple
pom.xml
<dependency>
<groupId>com.github.cliftonlabs</groupId>
<artifactId>json-simple</artifactId>
<version>3.1.0</version>
</dependency>
2.POJO+jsn able
2.1 为了将 Java 对象与 JSON 相互转换,JSON.simple 需要 POJO 实现Jsonable
,并覆盖toJson()
Staff.java
package com.mkyong;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsonable;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class Staff implements Jsonable {
private String name;
private int age;
private String[] position;
private List<String> skills;
private Map<String, BigDecimal> salary;
//..getters setters
@Override
public String toJson() {
final StringWriter writable = new StringWriter();
try {
this.toJson(writable);
} catch (final IOException e) {
}
return writable.toString();
}
@Override
public void toJson(Writer writer) throws IOException {
final JsonObject json = new JsonObject();
json.put("name", this.getName());
json.put("age", this.getAge());
json.put("position", this.getPosition());
json.put("skills", this.getSkills());
json.put("salary", this.getSalary());
json.toJson(writer);
}
}
3.JSON 的 Java 对象
3.1 将 Java 对象转换为 JSON 字符串并保存为.json
文件。
JsonSimple1.java
package com.mkyong;
import com.github.cliftonlabs.json_simple.Jsoner;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class JsonSimple1 {
public static void main(String[] args) throws IOException {
Staff staff = createStaff();
// Java objects to JSON String
String json = Jsoner.serialize(staff);
// pretty print
json = Jsoner.prettyPrint(json);
System.out.println(json);
// Java objects to JSON file
try (FileWriter fileWriter = new FileWriter("C:\\projects\\user3.json")) {
Jsoner.serialize(staff, fileWriter);
}
}
private static Staff createStaff() {
Staff staff = new Staff();
staff.setName("mkyong");
staff.setAge(38);
staff.setPosition(new String[]{"Founder", "CTO", "Writer"});
Map<String, BigDecimal> salary = new HashMap() {{
put("2010", new BigDecimal(10000));
put("2012", new BigDecimal(12000));
put("2018", new BigDecimal(14000));
}};
staff.setSalary(salary);
staff.setSkills(Arrays.asList("java", "python", "node", "kotlin"));
return staff;
}
}
输出
Terminal
{
"skills":[
"java",
"python",
"node",
"kotlin"
],
"name":"mkyong",
"position":[
"Founder",
"CTO",
"Writer"
],
"salary":{
"2018":14000,
"2012":12000,
"2010":10000
},
"age":38
}
C:\projects\user3.json
{"skills":["java","python","node","kotlin"],"name":"mkyong","position":["Founder","CTO","Writer"],"salary":{"2018":14000,"2012":12000,"2010":10000},"age":38}
3.2 将对象列表转换为 JSON 数组并保存为.json
文件。
Staff staff = createStaff();
List<Staff> list = Arrays.asList(createStaff(), createStaff());
// list of Java objects to JSON file
try (FileWriter fileWriter = new FileWriter("C:\\projects\\user4.json")) {
Jsoner.serialize(list, fileWriter);
}
输出
C:\projects\user4.json
[
{"skills":["java","python","node","kotlin"],"name":"mkyong","position":["Founder","CTO","Writer"],"salary":{"2018":14000,"2012":12000,"2010":10000},"age":38},
{"skills":["java","python","node","kotlin"],"name":"mkyong","position":["Founder","CTO","Writer"],"salary":{"2018":14000,"2012":12000,"2010":10000},"age":38}
]
4.JSON 到 Java 对象
4.1 要将 JSON 转换回 Java 对象,我们需要来自dozer
第三方库的帮助来复制对象属性。
pom.xml
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
4.2 JSON 字符串到 Java 对象。
JsonSimple2.java
package com.mkyong;
import com.github.cliftonlabs.json_simple.JsonException;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsoner;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import java.io.FileReader;
import java.io.IOException;
public class JsonSimple2 {
public static void main(String[] args) throws IOException, JsonException {
// The file `user3.json` is generated from above example 3.1
try (FileReader fileReader = new FileReader(("C:\\projects\\user3.json"))) {
JsonObject deserialize = (JsonObject) Jsoner.deserialize(fileReader);
// need dozer to copy object to staff, json_simple no api for this?
Mapper mapper = new DozerBeanMapper();
// JSON to object
Staff staff = mapper.map(deserialize, Staff.class);
System.out.println(staff);
}
}
}
输出
Staff{name='mkyong', age=38, position=[Founder, CTO, Writer],
skills=[java, python, node, kotlin], salary={2018=14000, 2012=12000, 2010=10000}}
4.3 JSON 数组到 Java 对象。
JsonSimple3.java
package com.mkyong;
import com.github.cliftonlabs.json_simple.JsonArray;
import com.github.cliftonlabs.json_simple.JsonException;
import com.github.cliftonlabs.json_simple.Jsoner;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
public class JsonSimple3 {
public static void main(String[] args) throws IOException, JsonException {
// The file `user4.json` is generated from above example 3.2
try (FileReader fileReader = new FileReader(("C:\\projects\\user4.json"))) {
JsonArray objects = Jsoner.deserializeMany(fileReader);
Mapper mapper = new DozerBeanMapper();
JsonArray o = (JsonArray) objects.get(0);
List<Staff> collect = o.stream()
.map(x -> mapper.map(x, Staff.class)).collect(Collectors.toList());
collect.forEach(x -> System.out.println(x));
}
}
}
输出
Staff{name='mkyong', age=38, position=[Founder, CTO, Writer], skills=[java, python, node, kotlin], salary={2018=14000, 2012=12000, 2010=10000}}
Staff{name='mkyong', age=38, position=[Founder, CTO, Writer], skills=[java, python, node, kotlin], salary={2018=14000, 2012=12000, 2010=10000}}
参考
JSONAssert——如何对 JSON 数据进行单元测试
在 Java 中,我们可以使用JSONAssert
轻松地对 JSON 数据进行单元测试。
1.专家
pom.xml
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.5.0</version>
</dependency>
2.JSON 对象
为了测试 JSON 对象,无论严格与否,字段顺序都无关紧要。如果扩展字段很重要,则启用严格模式。
2.1 当strictMode
关闭时。
JSONObject actual = new JSONObject();
actual.put("id", 1);
actual.put("name", "mkyong");
actual.put("age", 37);
JSONAssert.assertEquals("{id:1}", actual, false); //Pass, extended fields doesn't matter
JSONAssert.assertEquals("{name:\"mkyong\"}", actual, false); //Pass
JSONAssert.assertEquals("{name:\"mkyong\", age:37}", actual, false);//Pass
JSONAssert.assertEquals("{name:mkyong, id:1}", actual, false); //Pass
JSONAssert.assertEquals("{id:1, age:37}", actual, false); //Pass
2.2 当strictMode
开启时。
String actual = "{\"name\":\"mkyong\",\"id\":1,\"age\":37}";
JSONAssert.assertEquals("{id:1, name:\"mkyong\", age:37}", actual, true); //Pass, fields order doesn't matter
JSONAssert.assertEquals("{age:37, id:1, name:\"mkyong\"}", actual, true); //Pass
JSONAssert.assertEquals("{name:\"mkyong\"}", actual, true); // Fail, extended fields must match
JSONAssert.assertEquals("{name:\"mkyong\", age:37}", actual, true); // Fail, extended fields must match
3.JSON 数组
为了测试 JSON 数组,无论严格与否,扩展字段必须匹配。如果字段顺序很重要,则启用严格模式。
3.1 当strictMode
关闭时。
String result = "[1,2,3,4,5]";
JSONAssert.assertEquals("[1,2,3,4,5]", result, false); // Pass
JSONAssert.assertEquals("[5,3,2,1,4]", result, false); // Pass, fields order doesn't matter
JSONAssert.assertEquals("[1,2,3,4]", result, false); // Fail, extended fields must match
3.2 当strictMode
开启时。
String result = "[1,2,3,4,5]";
JSONAssert.assertEquals("[1,2,3,4,5]", result, true); // Pass
JSONAssert.assertEquals("[5,3,2,1,4]", result, true); // Fail, fields order must match.
JSONAssert.assertEquals("[1,2,3,4]", result, true); // Fail, extended fields must match
4.Spring Boot + JSONAssert
4.1 对于 Spring Boot,JSONAssert
捆绑在spring-boot-starter-test
中
+- org.springframework.boot:spring-boot-starter-test:jar:2.1.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test:jar:2.1.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.1.2.RELEASE:test
[INFO] | +- com.jayway.jsonpath:json-path:jar:2.4.0:test
[INFO] | | \- net.minidev:json-smart:jar:2.3:test
[INFO] | | \- net.minidev:accessors-smart:jar:1.2:test
[INFO] | | \- org.ow2.asm:asm:jar:5.0.4:test
[INFO] | +- junit:junit:jar:4.12:test
[INFO] | +- org.assertj:assertj-core:jar:3.11.1:test
[INFO] | +- org.mockito:mockito-core:jar:2.23.4:test
[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.9.7:test
[INFO] | | \- org.objenesis:objenesis:jar:2.6:test
[INFO] | +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] | +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.0:test <<-------- JSONAssert
[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] | \- org.xmlunit:xmlunit-core:jar:2.6.2:test
4.2 用JSONAssert
进行简单的弹簧靴集成测试
package com.mkyong;
import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // for restTemplate
@ActiveProfiles("test")
public class BookControllerRestTemplateTest {
private static final ObjectMapper om = new ObjectMapper();
@Autowired
private TestRestTemplate restTemplate;
@MockBean
private BookRepository mockRepository;
/*
{
"timestamp":"2019-03-05T09:34:13.207+0000",
"status":400,
"errors":["Author is not allowed."]
}
*/
@Test
public void save_invalidAuthor_400() throws JSONException {
String bookInJson = "{\"name\":\" Spring REST tutorials\", \"author\":\"abc\",\"price\":\"9.99\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(bookInJson, headers);
//Try exchange
ResponseEntity<String> response = restTemplate.exchange("/books", HttpMethod.POST, entity, String.class);
String expectedJson = "{\"status\":400,\"errors\":[\"Author is not allowed.\"]}";
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
JSONAssert.assertEquals(expectedJson, response.getBody(), false);
verify(mockRepository, times(0)).save(any(Book.class));
}
}
用 Spring Boot 2 号进行了测试
参考
Tags : json spring test unit test
JUnit–基本注释示例
这里有一些您应该了解的基本 JUnit 注释:
- @ before class–在类中的任何测试方法之前运行一次,
public static void
- @ after class–在运行完该类中的所有测试后运行一次,
public static void
- @ Before–在@Test 之前运行,
public void
- @ After–在@Test,
public void
之后运行 - @ Test–这是要运行的测试方法,
public void
P.S .用 JUnit 4.12 测试
BasicAnnotationTest.java
package com.mkyong;
import org.junit.*;
public class BasicAnnotationTest {
// Run once, e.g. Database connection, connection pool
@BeforeClass
public static void runOnceBeforeClass() {
System.out.println("@BeforeClass - runOnceBeforeClass");
}
// Run once, e.g close connection, cleanup
@AfterClass
public static void runOnceAfterClass() {
System.out.println("@AfterClass - runOnceAfterClass");
}
// Should rename to @BeforeTestMethod
// e.g. Creating an similar object and share for all @Test
@Before
public void runBeforeTestMethod() {
System.out.println("@Before - runBeforeTestMethod");
}
// Should rename to @AfterTestMethod
@After
public void runAfterTestMethod() {
System.out.println("@After - runAfterTestMethod");
}
@Test
public void test_method_1() {
System.out.println("@Test - test_method_1");
}
@Test
public void test_method_2() {
System.out.println("@Test - test_method_2");
}
}
输出
@BeforeClass - runOnceBeforeClass
@Before - runBeforeTestMethod
@Test - test_method_1
@After - runAfterTestMethod
@Before - runBeforeTestMethod
@Test - test_method_2
@After - runAfterTestMethod
@AfterClass - runOnceAfterClass
参考
JUnit–预期异常测试
在 JUnit 中,有 3 种方法可以测试预期的异常:
@Test
,可选的‘预期’属性- 尝试-捕捉并总是
fail()
@Rule
预期异常
P.S .用 JUnit 4.12 测试
1.@Test 预期属性
如果您只想测试异常类型,请使用此选项,请参考以下内容:
Exception1Test.java
package com.mkyong;
import org.junit.Test;
import java.util.ArrayList;
public class Exception1Test {
@Test(expected = ArithmeticException.class)
public void testDivisionWithException() {
int i = 1 / 0;
}
@Test(expected = IndexOutOfBoundsException.class)
public void testEmptyList() {
new ArrayList<>().get(0);
}
}
2.Try-catch 并且总是失败()
这是一个有点老的学校,在 JUnit 3 中广泛使用。测试异常类型和异常详细信息。参考下文:
Exception2Test.java
package com.mkyong;
import org.junit.Test;
import java.util.ArrayList;
import static junit.framework.TestCase.fail;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
public class Exception2Test {
@Test
public void testDivisionWithException() {
try {
int i = 1 / 0;
fail(); //remember this line, else 'may' false positive
} catch (ArithmeticException e) {
assertThat(e.getMessage(), is("/ by zero"));
//assert others
}
}
@Test
public void testEmptyList() {
try {
new ArrayList<>().get(0);
fail();
} catch (IndexOutOfBoundsException e) {
assertThat(e.getMessage(), is("Index: 0, Size: 0"));
}
}
}
Always remember the fail()!
If the line you want to test didn’t throw any exception, and you forgot to put the fail()
, the test will be passed (false positive). ## 3.@Rule 需要异常
这个ExpectedException
规则(从 JUnit 4.7 开始)允许您测试异常类型和异常细节,类似于" 2。“试-赶和总是失败()”的方法,但用了一种更优雅的方式:
Exception3Test.java
package com.mkyong;
import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;
public class Exception3Test {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testDivisionWithException() {
thrown.expect(ArithmeticException.class);
thrown.expectMessage(containsString("/ by zero"));
int i = 1 / 0;
}
@Test
public void testNameNotFoundException() throws NameNotFoundException {
//test type
thrown.expect(NameNotFoundException.class);
//test message
thrown.expectMessage(is("Name is empty!"));
//test detail
thrown.expect(hasProperty("errCode")); //make sure getters n setters are defined.
thrown.expect(hasProperty("errCode", is(666)));
CustomerService cust = new CustomerService();
cust.findByName("");
}
}
NameNotFoundException.java
package com.mkyong.examples.exception;
public class NameNotFoundException extends Exception {
private int errCode;
public NameNotFoundException(int errCode, String message) {
super(message);
this.errCode = errCode;
}
public int getErrCode() {
return errCode;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
}
CustomerService.java
package com.mkyong.examples;
import com.mkyong.examples.exception.NameNotFoundException;
public class CustomerService {
public Customer findByName(String name) throws NameNotFoundException {
if ("".equals(name)) {
throw new NameNotFoundException(666, "Name is empty!");
}
return new Customer(name);
}
}
参考
JUnit–忽略测试
在 JUnit 中,要忽略一个测试,只需在@Test
方法之前或之后添加一个@Ignore
注释。
P.S .用 JUnit 4.12 测试
IgnoreTest.java
package com.mkyong;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class IgnoreTest {
@Test
public void testMath1() {
assertThat(1 + 1, is(2));
}
@Ignore
@Test
public void testMath2() {
assertThat(1 + 2, is(5));
}
@Ignore("some one please create a test for Math3!")
@Test
public void testMath3() {
//...
}
}
在上面的例子中,testMath2()
和testMath3()
都将被忽略。
常见问题(frequently asked questions)
1.要忽略一个测试,为什么不只是注释测试方法或者@Test
注释呢?
答:测试运行人员不会报告测试。在 IDE 中,测试运行程序会用不同的图标或颜色显示被忽略的测试,并突出显示,这样您就知道哪些测试被忽略了。
2.为什么要做一个不测试的测试?
答:对于大型项目,许多开发人员在处理不同的模块,失败的测试可能是由其他团队造成的,您可以在测试方法上添加@Ignore
来避免测试中断整个构建过程。
答:或者您希望有人帮助创建测试,像@Ignore ("help for this method!")
一样,可选参数(字符串)将显示在测试运行器中。
参考
junit unit test (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190225092958/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
JUnit–超时测试
如果测试花费的时间超过定义的“超时”时间,将抛出TestTimedOutException
并标记测试失败。请参见以下示例:
P.S .用 JUnit 4.12 测试
1.超时示例
这个timeout
例子只适用于单个测试方法。超时值以毫秒为单位。
TimeoutTest.java
package com.mkyong;
import org.junit.Test;
public class TimeoutTest {
//This test will always failed :)
@Test(timeout = 1000)
public void infinity() {
while (true) ;
}
//This test can't run more than 5 seconds, else failed
@Test(timeout = 5000)
public void testSlowMethod() {
//...
}
}
这个超时测试对于测试方法性能很有用。
2.全局超时规则示例
这个例子向你展示了如何创建一个全局超时规则,这个规则将应用于一个类中的所有测试方法。
TimeoutTest.java
package com.mkyong;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import java.util.concurrent.TimeUnit;
public class TimeoutRuleTest {
//global timeout rule
@Rule
public Timeout globalTimeout = Timeout.seconds(1);
//This test will be failed, because it will take more than 1 second to finish!
@Test
public void testSlowMethod1() throws InterruptedException {
//...
TimeUnit.SECONDS.sleep(5000);
}
//passed
@Test
public void testSlowMethod2() {
//...
}
}
在上面的例子中,声明了一个全局Timeout
规则,testSlowMethod1()
和testSlowMethod2()
必须在 1 秒内完成测试,否则测试将失败。
这个规则也适用于@Before
和@After
方法。
Note
All unit test should be fast, and this global timeout rule should be your best helper. ## 参考
JUnit–套件测试,运行多个测试用例
在 JUnit 中,您可以使用@RunWith
和@Suite
注释运行多个测试用例。参考下面的例子:
SuiteAbcTest.java
package com.mkyong;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
Exception1Test.class, //test case 1
TimeoutTest.class //test case 2
})
public class SuiteAbcTest {
//normally, this is an empty class
}
P.S .用 JUnit 4.12 测试
参考
junit (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190225100645/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
JUnit–参数化测试
在 JUnit 中,您可以通过以下方法将参数传递给单元测试方法:
- 构造器
- 通过
@Parameter
注入磁场
P.S .用 JUnit 4.12 测试
1.match utils–多参数测试
简单的加法运算。
MathUtils.java
package com.mkyong.examples;
public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
}
1.2 match utils–通过构造函数参数化
参数通过构造函数传递给测试方法。
ParameterizedTest.java
package com.mkyong;
import com.mkyong.examples.MathUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@RunWith(value = Parameterized.class)
public class ParameterizedTest {
private int numberA;
private int numberB;
private int expected;
// Inject via constructor
// for {8, 2, 10}, numberA = 8, numberB = 2, expected = 10
public ParameterizedTest(int numberA, int numberB, int expected) {
this.numberA = numberA;
this.numberB = numberB;
this.expected = expected;
}
// name attribute is optional, provide an unique name for test
// multiple parameters, uses Collection<Object[]>
@Parameters(name = "{index}: testAdd({0}+{1}) = {2}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{1, 1, 2},
{2, 2, 4},
{8, 2, 10},
{4, 5, 9},
{5, 5, 10}
});
}
@Test
public void test_addTwoNumbes() {
assertThat(MathUtils.add(numberA, numberB), is(expected));
}
}
1.3 匹配-通过现场注入参数化
参数通过现场注入传递到测试方法中。
ParameterizedTest.java
package com.mkyong;
import com.mkyong.examples.MathUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.Parameter;
import java.util.Arrays;
import java.util.Collection;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@RunWith(value = Parameterized.class)
public class ParameterizedTest {
//default value = 0
@Parameter(value = 0)
public int numberA;
@Parameter(value = 1)
public int numberB;
@Parameter(value = 2)
public int expected;
@Parameters(name = "{index}: testAdd({0}+{1}) = {2}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{1, 1, 2},
{2, 2, 4},
{8, 2, 10},
{4, 5, 9},
{5, 5, 10}
});
}
@Test
public void test_addTwoNumbes() {
assertThat(MathUtils.add(numberA, numberB), is(expected));
}
}
Note
For @Parameters
, the “name” attribute is optional, it helps you to identify individual test cases by providing a unique name.
什么是{0}、{1}和{2}?
如果参数为“{ 3,4,7 }”,则{0} = 3,{1} = 4,{2} = 7。
输出
2.域名–单参数测试
另一个简单的类,验证域名。
DomainUtils.java
package com.mkyong.examples;
import java.util.regex.Pattern;
public class DomainUtils {
private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$";
private static Pattern pDomainName = Pattern.compile(DOMAIN_NAME_PATTERN);
public static boolean isValid(String domainName) {
return pDomainName.matcher(domainName).find();
}
}
2.1 域名参数化测试
参数通过现场注入传递到测试方法中。
ParameterizedTest.java
package com.mkyong;
import com.mkyong.examples.DomainUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@RunWith(value = Parameterized.class)
public class Parameterized2Test {
//default value = 0
@Parameter
public String domainName;
//Single parameter, use Object[]
@Parameters(name = "{index}: testDomain - {0}")
public static Object[] data() {
return new Object[]{
"google.com",
"mkyong.com",
"twitter.com"
};
}
@Test
public void test_valid_domain() {
assertThat(DomainUtils.isValid(domainName), is(true));
}
}
输出
Note
TestNG is more flexible in the way of passing the parameters into unit tests, read this TestNG parameter test.
参考
JUnit 4 与 TestNG–比较
JUnit 4 和 TestNG 都是 Java 中非常流行的单元测试框架。这两个框架在功能上看起来非常相似。哪个更好?Java 项目中应该使用哪个单元测试框架?
这里我做了一个 JUnit 4 和 TestNG 的特性比较。
1.注释支持
JUnit 4 和 TestNG 中实现的注释支持看起来很相似。
| 特征 | 6 月 4 日 | 测试 |
| 测试注释 | @测试 | @测试 |
| 在此套件中的所有测试运行之前运行 | — | @ BeforeSuite 套件 |
| 在此套件中的所有测试运行后运行 | — | @AfterSuite |
| 测试前运行 | — | @测试前 |
| 测试后运行 | — | @事后测试 |
| 在调用属于任何这些组的第一个测试方法之前运行 | — | @ BeforeGroups |
| 在属于这些组的最后一个测试方法被调用后运行 | — | @AfterGroups |
| 在调用当前类中的第一个测试方法之前运行 | @BeforeClass | @BeforeClass |
| 在运行完当前类中的所有测试方法后运行 | @课后 | @课后 |
| 在每个测试方法之前运行 | @以前 | @ before 方法 |
| 在每个测试方法后运行 | @之后 | @AfterMethod |
| 忽略测试 | @忽略 | @Test(enbale=false) |
| 预期异常 | @Test(应为= ArithmeticException.class) | @ Test(expected exceptions = arithmetic exception . class) |
| 超时 | @Test(超时= 1000) | @Test(超时= 1000) |
JUnit4 和 TestNG 之间的主要注释差异是
1.在 JUnit 4 中,我们必须将“@BeforeClass”和“@AfterClass”方法声明为静态方法。TestNG 在方法声明方面更加灵活,它没有这种限制。
2.3 附加设置/拆卸级别:套件和组(@Before/AfterSuite,@Before/AfterTest,@Before/AfterGroup)。点击此处查看更多详情。
JUnit 4
@BeforeClass
public static void oneTimeSetUp() {
// one-time initialization code
System.out.println("@BeforeClass - oneTimeSetUp");
}
测试
@BeforeClass
public void oneTimeSetUp() {
// one-time initialization code
System.out.println("@BeforeClass - oneTimeSetUp");
}
在 JUnit 4 中,注释命名约定有点混乱,例如“Before”、“After”和“Expected”,我们并不真正理解“Before”和“After”做了什么,以及我们从测试方法中“期望”了什么?测试更容易理解,它用“BeforeMethod”、“AfterMethod”和“ExpectedException”来代替。
2.异常测试
“异常测试”意味着单元测试会抛出什么异常,这个特性在 JUnit 4 和 TestNG 中都实现了。
JUnit 4
@Test(expected = ArithmeticException.class)
public void divisionWithException() {
int i = 1/0;
}
测试
@Test(expectedExceptions = ArithmeticException.class)
public void divisionWithException() {
int i = 1/0;
}
3.忽略测试
“忽略”意味着它是否应该忽略单元测试,这个特性在 JUnit 4 和 TestNG 中都实现了。
JUnit 4
@Ignore("Not Ready to Run")
@Test
public void divisionWithException() {
System.out.println("Method is not ready yet");
}
测试
@Test(enabled=false)
public void divisionWithException() {
System.out.println("Method is not ready yet");
}
4.时间测验
“时间测试”意味着如果一个单元测试运行的时间超过了指定的毫秒数,测试将被终止并标记为失败,这个特性在 JUnit 4 和 TestNG 中都实现了。
JUnit 4
@Test(timeout = 1000)
public void infinity() {
while (true);
}
测试
@Test(timeOut = 1000)
public void infinity() {
while (true);
}
5.套件测试
“套件测试”意味着捆绑几个单元测试并一起运行。这个特性在 JUnit 4 和 TestNG 中都实现了。然而,两者都使用非常不同的方法来实现它。
JUnit 4
“@RunWith”和“@Suite”用于运行套件测试。下面的类意味着单元测试“JunitTest1”和“JunitTest2”在 JunitTest5 执行后一起运行。所有的声明都是在类内部定义的。
@RunWith(Suite.class)
@Suite.SuiteClasses({
JunitTest1.class,
JunitTest2.class
})
public class JunitTest5 {
}
测试
XML 文件用于运行套件测试。下面的 XML 文件意味着单元测试“TestNGTest1”和“TestNGTest2”将一起运行它。
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
<test name="testing">
<classes>
<class name="com.fsecure.demo.testng.TestNGTest1" />
<class name="com.fsecure.demo.testng.TestNGTest2" />
</classes>
</test>
</suite>
TestNG 不仅可以捆绑类测试,还可以捆绑方法测试。由于 TestNG 独特的“分组”概念,每个方法都被绑定到一个组,它可以根据特性对测试进行分类。举个例子,
这里有一个包含四个方法的类,分为三组(方法 1、方法 2 和方法 3)
@Test(groups="method1")
public void testingMethod1() {
System.out.println("Method - testingMethod1()");
}
@Test(groups="method2")
public void testingMethod2() {
System.out.println("Method - testingMethod2()");
}
@Test(groups="method1")
public void testingMethod1_1() {
System.out.println("Method - testingMethod1_1()");
}
@Test(groups="method4")
public void testingMethod4() {
System.out.println("Method - testingMethod4()");
}
使用下面的 XML 文件,我们可以只使用组“method1”来执行单元测试。
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
<test name="testing">
<groups>
<run>
<include name="method1"/>
</run>
</groups>
<classes>
<class name="com.fsecure.demo.testng.TestNGTest5_2_0" />
</classes>
</test>
</suite>
有了“分组”测试概念,集成测试的可能性是无限的。例如,我们只能从所有的单元测试类中测试“DatabaseFuntion”组。
6.参数化测试
“参数化测试”是指改变单元测试的参数值。这个特性在 JUnit 4 和 TestNG 中都实现了。然而,两者都使用非常不同的方法来实现它。
JUnit 4
“@RunWith”和“@Parameter”用于为单元测试提供参数值,@Parameters 必须返回 List[],参数将作为实参传入类构造函数。
@RunWith(value = Parameterized.class)
public class JunitTest6 {
private int number;
public JunitTest6(int number) {
this.number = number;
}
@Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } };
return Arrays.asList(data);
}
@Test
public void pushTest() {
System.out.println("Parameterized Number is : " + number);
}
}
它在这里有许多限制;我们必须遵循“JUnit”的方式来声明参数,并且参数必须传递到构造函数中,以便将类成员初始化为用于测试的参数值。参数类的返回类型为“List []”,数据已被限制为字符串或一个用于测试的原始值。
测试
XML 文件或“@DataProvider”用于为测试提供不同参数。
用于参数化测试的 XML 文件。
只有“@Parameters”在需要参数进行测试的方法中声明,参数化数据会在 TestNG 的 XML 配置文件中提供。通过这样做,我们可以用不同的数据集重用单个测试用例,甚至得到不同的结果。此外,即使是最终用户、QA 或 QE 也可以用 XML 文件提供他们自己数据进行测试。
单元测试
public class TestNGTest6_1_0 {
@Test
@Parameters(value="number")
public void parameterIntTest(int number) {
System.out.println("Parameterized Number is : " + number);
}
}
XML 文件
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
<test name="testing">
<parameter name="number" value="2"/>
<classes>
<class name="com.fsecure.demo.testng.TestNGTest6_0" />
</classes>
</test>
</suite>
@DataProvider 进行参数化测试。
虽然将数据值放入 XML 文件非常方便,但是测试有时需要复杂的类型,这些类型不能表示为字符串或原始值。TestNG 用它的@DataProvider 注释来处理这个场景,这有助于将复杂的参数类型映射到测试方法。
@DataProvider for Vector,String 或 Integer 作为参数
@Test(dataProvider = "Data-Provider-Function")
public void parameterIntTest(Class clzz, String[] number) {
System.out.println("Parameterized Number is : " + number[0]);
System.out.println("Parameterized Number is : " + number[1]);
}
//This function will provide the patameter data
@DataProvider(name = "Data-Provider-Function")
public Object[][] parameterIntTestProvider() {
return new Object[][]{
{Vector.class, new String[] {"java.util.AbstractList",
"java.util.AbstractCollection"}},
{String.class, new String[] {"1", "2"}},
{Integer.class, new String[] {"1", "2"}}
};
}
@ data provider for object as parameter
P . S " testngtest 6 _ 3 _ 0 "是一个简单的对象,只带有 get set 方法用于演示。
@Test(dataProvider = "Data-Provider-Function")
public void parameterIntTest(TestNGTest6_3_0 clzz) {
System.out.println("Parameterized Number is : " + clzz.getMsg());
System.out.println("Parameterized Number is : " + clzz.getNumber());
}
//This function will provide the patameter data
@DataProvider(name = "Data-Provider-Function")
public Object[][] parameterIntTestProvider() {
TestNGTest6_3_0 obj = new TestNGTest6_3_0();
obj.setMsg("Hello");
obj.setNumber(123);
return new Object[][]{
{obj}
};
}
TestNG 的参数化测试非常用户友好和灵活(无论是在 XML 文件中还是在类内部)。它可以支持许多复杂的数据类型作为参数值,并且可能性是无限的。如上例,我们甚至可以传入我们自己的对象(TestNGTest6_3_0)进行参数化测试
7.依赖性测试
“参数化测试”意味着方法是基于依赖的测试,它将在期望的方法之前执行。如果依赖方法失败,那么所有后续测试将被跳过,而不是被标记为失败。
JUnit 4
JUnit 框架专注于测试隔离;它目前不支持这个特性。
测试
它使用“依赖方法”来实现依赖测试,如下所示
@Test
public void method1() {
System.out.println("This is method 1");
}
@Test(dependsOnMethods={"method1"})
public void method2() {
System.out.println("This is method 2");
}
只有当“方法 1()”成功运行时,“方法 2()”才会执行,否则“方法 2()”将跳过测试。
结论
经过对所有特性的比较,我建议使用 TestNG 作为 Java 项目的核心单元测试框架,因为 TestNG 在参数化测试、依赖测试和套件测试(分组概念)方面更先进。TestNG 是针对高级测试和复杂集成测试的。它的灵活性对于大型测试套件尤其有用。此外,TestNG 还涵盖了 JUnit4 的全部核心功能。我再也没有理由使用 JUnit 了。
参考
TestNG
————
http://en.wikipedia.org/wiki/TestNG
http://www.ibm.com/developerworks/java/library/j-testng/
http://testng.org/doc/index.html
http://beust.com/weblog/
JUnit
————
http://en.wikipedia.org/wiki/JUnit
http://www . IBM . com/developer works/Java/library/j-JUnit 4 . html
http://junit.sourceforge.net/doc/faq/faq.htm
http://www.devx.com/Java/Article/31983/0/page/3
http://our craft . WordPress . com/2008/08/27/writing-a-parameterized-JUnit-test/
TestNG VS JUnit
——————
http://docs . codehaus . org/display/XPR/Migration+to+JUnit 4+or+TestNG
http://www . IBM . com/developer works/Java/library/j-CQ 08296/index . html
http://www.cavdar.net/2008/07/21/junit-4-in-60-seconds/
JUnit 5 + AssertJ 示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-assertj-examples/
在本文中,我们将向您展示如何用 AssertJ 编写测试断言。
P.S 使用 JUnit 5.5.2 和 AssertJ 3.14.0 测试
pom.xml
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.14.0</version>
<scope>test</scope>
</dependency>
1.JUnit 5 对 AssertJ 的断言
将 JUnit 5 断言转换为 AssetJ 很容易,请参见以下语法:
JUnit 5
assertEquals(expected, actual);
assertEquals(expected, actual, "assertion desc");
AssertJ
assertThat(actual).isEqualTo(expected);
assertThat(actual).as("assertion desc").isEqualTo(expected);
2.AssertJ
2.1 一些带有 AssertJ 的典型测试断言—String
、List
、Map
和Exception
。
AssertjTest.java
package com.mkyong.assertions.assertj;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.assertj.core.data.Index;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
public class AssertjTest {
// assert string
@Test
void test_string_ok() {
String name = "I am Mkyong!";
assertThat(name)
.as("if failed display this msg!")
.isEqualTo("I am Mkyong!")
.isEqualToIgnoringCase("I AM mkyong!")
.startsWith("I")
.endsWith("!")
.containsIgnoringCase("mkyong");
}
// assert list
@Test
void test_list_ok() {
List<String> list = Arrays.asList("Java", "Rust", "Clojure");
assertThat(list)
.hasSize(3)
.contains("Java", "Clojure")
.contains("Java", Index.atIndex(0))
.contains("Rust", Index.atIndex(1))
.contains("Clojure", Index.atIndex(2))
.doesNotContain("Node JS");
}
// assert map
@Test
void test_map_ok() {
Map<String, Object> map = new HashMap<>();
map.put("name", "mkyong");
assertThat(map)
.hasSize(1)
.extractingByKey("name", as(InstanceOfAssertFactories.STRING))
.isEqualToIgnoringCase("mkyong")
.startsWith("mkyong");
assertThat(map).extracting("name")
.isEqualTo("mkyong");
Map<String, Object> map2 = new HashMap<>();
map2.put("number", 999);
assertThat(map2)
.hasSize(1)
.extractingByKey("number", as(InstanceOfAssertFactories.INTEGER))
.isEqualTo(999);
}
// assert exception
@Test
void test_exception_ok() {
assertThatThrownBy(() -> divide(1, 0))
.isInstanceOf(ArithmeticException.class)
.hasMessageContaining("zero")
.hasMessage("/ by zero");
assertThatThrownBy(() -> {
List<String> list = Arrays.asList("one", "two");
list.get(2);
})
.isInstanceOf(IndexOutOfBoundsException.class)
.hasMessageContaining("Index 2 out of bounds");
}
int divide(int input, int divide) {
return input / divide;
}
}
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/assertions/assertj/*.java
参考
JUnit 5 假设示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-assumptions-examples/
本文向您展示了如何使用 JUnit 5 假设来执行条件测试。
使用的技术:
- Maven 3.6
- Java 8
- JUnit 5.5.2
1.假设
1.1 如果assumeTrue()
条件为真,则运行测试,否则中止测试。
1.2assumingThat()
更加灵活,它允许部分代码作为条件测试运行。
AssumptionsTest.java
package com.mkyong;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.junit.jupiter.api.Assumptions.assumingThat;
public class AssumptionsTest {
// Output: org.opentest4j.TestAbortedException: Assumption failed: assumption is not true
@DisplayName("Run this if `assumeTrue` condition is true, else aborting this test")
@Test
void testOnlyOnDevEnvElseAbort() {
assumeTrue("DEV".equals(System.getenv("APP_MODE")));
assertEquals(2, 1 + 1);
}
// Output: org.opentest4j.TestAbortedException: Assumption failed: Aborting test: not on developer environment
@DisplayName("Run this if `assumeTrue` condition is true, else aborting this test (Custom Message)")
@Test
void testOnlyOnDevEnvElseAbortWithCustomMsg() {
assumeTrue("DEV".equals(System.getenv("APP_MODE")), () -> "Aborting test: not on developer environment");
assertEquals(2, 1 + 1);
}
@Test
void testAssumingThat() {
// run these assertions always, just like normal test
assertEquals(2, 1 + 1);
assumingThat("DEV".equals(System.getenv("APP_MODE")),
() -> {
// run this only if assumingThat condition is true
assertEquals(2, 1 + 1);
});
// run these assertions always, just like normal test
assertEquals(2, 1 + 1);
}
}
输出
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/AssumptionsTest.java
参考
JUnit 5 条件测试示例
本文向您展示了如何使用 JUnit 5 来基于条件启用或禁用测试。
用 JUnit 5.5.2 测试的 PS
1.操作系统
1.1 通过@EnabledOnOs
和@DisabledOnOs
注释基于特定操作系统启用或禁用测试。
OperatingSystemTest.java
package com.mkyong.conditional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
public class OperatingSystemTest {
@Test
@EnabledOnOs({OS.LINUX, OS.WINDOWS})
void onLinuxOrWindows() {
System.out.println("Run this on Linux or Windows!");
}
@Test
@EnabledOnOs({OS.WINDOWS})
void onWindows() {
System.out.println("Run this on Windows!");
}
@Test
@DisabledOnOs(OS.WINDOWS)
void notOnWindows() {
System.out.println("Do not run this on Windows!");
}
@Test
@DisabledOnOs({OS.WINDOWS, OS.AIX, OS.SOLARIS, OS.MAC})
void notOnWindowsOrAixOrSolarisOrMac() {
System.out.println("Do not run this on Windows, AIX, Solaris or MAC!");
}
}
输出–使用 Windows 操作系统进行测试。
2.Java 运行时环境
2.1 通过@EnabledOnJre
和@DisabledOnJre
注释基于特定的 Java 运行时环境(JRE)启用或禁用测试。
JreTest.java
package com.mkyong.conditional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnJre;
import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE;
public class JreTest {
@Test
@EnabledOnJre(JRE.JAVA_9)
void onJava9() {
System.out.println("Run this on Java 9");
}
@Test
@EnabledOnJre({JRE.JAVA_12, JRE.JAVA_13})
void onJava12OrJava13() {
System.out.println("Run this on Java 12 or Java 13");
}
@Test
@DisabledOnJre(JRE.JAVA_9)
void notOnJava9() {
System.out.println("Do not run this on Java 9");
}
}
输出–用 Java 13 测试
3.系统属性
3.1 通过@EnabledIfSystemProperty
和@DisabledIfSystemProperty
注释,根据 JVM 系统属性中named
的值启用或禁用测试。
SystemPropertyTest.java
package com.mkyong.conditional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import java.util.Properties;
public class SystemPropertyTest {
@Test
@EnabledIfSystemProperty(named = "java.vm.name", matches = ".*OpenJDK.*")
void onOpenJDK() {
System.out.println("Run this on OpenJDK!");
}
@Test
@DisabledIfSystemProperty(named = "user.country", matches = "MY")
void notOnCountryMalaysia() {
System.out.println("Do not run this on country code MY");
}
@Test
void printSystemProperties() {
Properties properties = System.getProperties();
properties.forEach((k, v) -> System.out.println(k + ":" + v));
}
}
4.环境变量
4.1 通过@EnabledIfEnvironmentVariable
和@DisabledIfEnvironmentVariable
注释,根据环境属性中named
的值启用或禁用测试。
EnvVariableTest.java
package com.mkyong.conditional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import java.util.Map;
public class EnvVariableTest {
@Test
@EnabledIfEnvironmentVariable(named = "PROCESSOR_IDENTIFIER", matches = ".*Intel64 Family 6.*")
void onIntel64() {
System.out.println("Run this on Intel6 Family 6 only.");
}
@Test
@EnabledIfEnvironmentVariable(named = "NUMBER_OF_PROCESSORS", matches = "8")
void onProcessor8() {
System.out.println("Run this if it has 8 processors.");
}
@Test
@DisabledIfEnvironmentVariable(named = "CURRENT_ENV", matches = ".*development.*")
void notOnDeveloperPC() {
System.out.println("Do not run this if env variables 'CURRENT_ENV' matches .*development.* ");
}
@Test
void printEnvironmentProperties() {
Map<String, String> env = System.getenv();
env.forEach((k, v) -> System.out.println(k + ":" + v));
}
}
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/conditional/*.java
参考
JUnit 5 控制台启动器示例
本文向您展示了如何使用 JUnit 5 ConsoleLauncher
从命令行运行测试。
测试对象
- JUnit 5.5.2
- JUnit-平台-控制台-独立版 1.5.2
1.下载 JAR
要从命令行运行测试,我们可以手动从 Maven central repository 下载JUnit-platform-console-standalone . jar。
这个例子使用的是版本1.5.2
。
https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.5.2/
2.习惯
通常,测试类位于以下类路径中:
build/classes/java/test
target/test-classes
2.1 从此类路径运行所有测试build/classes/java/test
Terminal
$ java -jar junit-platform-console-standalone-1.5.2.jar --classpath build/classes/java/test --scan-classpath
$ java -jar junit-platform-console-standalone-1.5.2.jar -cp build/classes/java/test --scan-classpath
2.2 使用类名运行指定的测试。
Terminal
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp 'build/classes/java/test'
-c com.mkyong.order.MethodOrderTest
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp 'build/classes/java/test'
--select-class com.mkyong.order.MethodOrderTest
2.3 运行包中的所有测试。
Terminal
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp 'build/classes/java/test'
--select-package com.mkyong.order
2.4 运行包中的所有测试,通过正则表达式模式过滤测试的类名。
Terminal
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp 'build/classes/java/test'
--select-package com.mkyong.order
--include-classname='.*Count.*'
2.5 输出样本。
Terminal
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp 'build/classes/java/test'
--select-package com.mkyong.order
--include-classname='.*'
Thanks for using JUnit! Support its development at https://junit.org/sponsoring
+-- JUnit Jupiter [OK]
| +-- MethodRandomTest [OK]
| | +-- testA() [OK]
| | +-- testZ() [OK]
| | +-- testY() [OK]
| | +-- testE() [OK]
| | '-- testB() [OK]
| +-- MethodParameterCountTest [OK]
| | +-- Parameter Count : 3 [OK]
| | | +-- 1 ==> fruit='apple', qty=1, price=1.99 [OK]
| | | '-- 2 ==> fruit='banana', qty=2, price=2.99 [OK]
| | +-- Parameter Count : 2 [OK]
| | | +-- 1 ==> fruit='apple', qty=1 [OK]
| | | '-- 2 ==> fruit='banana', qty=2 [OK]
| | '-- Parameter Count : 1 [OK]
| | +-- 1 ==> ints=1 [OK]
| | +-- 2 ==> ints=2 [OK]
| | '-- 3 ==> ints=3 [OK]
| +-- MethodAlphanumericTest [OK]
| | +-- testA() [OK]
| | +-- testB() [OK]
| | +-- testE() [OK]
| | +-- testY() [OK]
| | '-- testZ() [OK]
| '-- MethodOrderTest [OK]
| +-- test2() [OK]
| +-- test3() [OK]
| +-- test1() [OK]
| +-- test0() [OK]
| '-- test4() [OK]
'-- JUnit Vintage [OK]
Test run finished after 109 ms
[ 9 containers found ]
[ 0 containers skipped ]
[ 9 containers started ]
[ 0 containers aborted ]
[ 9 containers successful ]
[ 0 containers failed ]
[ 22 tests found ]
[ 0 tests skipped ]
[ 22 tests started ]
[ 0 tests aborted ]
[ 22 tests successful ]
[ 0 tests failed ]
附:请参考 JUnit 5 官方指南,了解所有控制台启动器选项
3.Windows 操作系统
3.1 如果我们想在经典命令提示符下运行上述命令,请用双引号替换单引号,例如:
Command Prompt – Windows
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp "build/classes/java/test"
-c com.mkyong.order.MethodOrderTest
3.2 传递一个--disable-ansi-colors
选项来禁用输出中的 ANSI 颜色。命令提示符不支持此功能。
Command Prompt – Windows
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp "build/classes/java/test"
-c com.mkyong.order.MethodOrderTest
--disable-ansi-colors
下载源代码
$ git clone https://github.com/mkyong/junit-examples
参考
JUnit 5 显示名称
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-display-names/
在 JUnit 5 中,我们可以使用@DisplayName
来声明测试类和测试方法的定制显示名称。
用 JUnit 5.5.2 测试的 PS
1.@DisplayName
1.1 测试类和方法的默认名称。
DisplayNameTest.java
package com.mkyong.display;
import org.junit.jupiter.api.Test;
public class DisplayNameTest {
@Test
void test_spaces_ok() {
}
@Test
void test_spaces_fail() {
}
}
输出
+-- JUnit Jupiter [OK]
| '-- DisplayNameTest [OK]
| +-- test_spaces_ok() [OK]
| '-- test_spaces_fail() [OK]
1.2 @DisplayName
DisplayNameCustomTest.java
package com.mkyong.display;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("I'm a Test Class")
public class DisplayNameCustomTest {
@Test
@DisplayName("Test with spaces, expected ok")
void test_spaces_ok() {
}
@DisplayName("Test with spaces, expected failed")
@Test
void test_spaces_fail() {
}
}
输出
+-- JUnit Jupiter [OK]
| '-- I'm a Test Class [OK]
| +-- Test with spaces, expected ok [OK]
| '-- Test with spaces, expected failed [OK]
2.显示名称生成器
2.1 我们还可以创建一个自定义显示名称生成器,并通过@DisplayNameGeneration
进行配置。
2.2 这个例子使用 JUnit ReplaceUnderscores
生成器将下划线替换为空格。
DisplayNameGenerator1Test.java
package com.mkyong.display;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
public class DisplayNameGenerator1Test {
@Test
void test_spaces_ok() {
}
@Test
void test_spaces_fail() {
}
}
输出
2.3 我们可以扩展 JUnit DisplayNameGenerator
来创建我们的自定义显示名称生成器。
DisplayNameGenerator2Test.java
package com.mkyong.display;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;
@DisplayNameGeneration(DisplayNameGenerator2Test.CustomDisplayNameGenerator.class)
public class DisplayNameGenerator2Test {
@Test
void test_spaces_ok() {
}
@Test
void test_spaces_fail() {
}
static class CustomDisplayNameGenerator extends DisplayNameGenerator.Standard {
@Override
public String generateDisplayNameForClass(Class<?> testClass) {
return "New Name for test class";
}
@Override
public String generateDisplayNameForNestedClass(Class<?> nestedClass) {
return super.generateDisplayNameForNestedClass(nestedClass);
}
@Override
public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {
String name = testMethod.getName();
return Arrays.stream(name.split("_")).collect(Collectors.joining(" | "));
}
}
}
输出
3.参数化测试
3.1 对于参数化测试,我们可以通过@ParameterizedTest
的 name 属性来声明自定义显示名称,参见下面的例子:
DisplayNameParamTest.java
package com.mkyong.display;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static org.junit.jupiter.params.provider.Arguments.arguments;
public class DisplayNameParamTest {
@ParameterizedTest(name = "#{index} - Test with TimeUnit: {0}")
@EnumSource(value = TimeUnit.class, names = {"MINUTES", "SECONDS"})
void test_timeunit_ok(TimeUnit time) {
}
@ParameterizedTest(name = "#{index} - Test with {0} and {1}")
@MethodSource("argumentProvider")
void test_method_multi(String str, int length) {
}
static Stream<Arguments> argumentProvider() {
return Stream.of(
arguments("abc", 3),
arguments("lemon", 2)
);
}
}
输出
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/display/*.java
参考
JUnit 5 预期异常
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-expected-exception/
在 JUnit 5 中,我们可以使用assertThrows
来断言抛出了异常。
用 JUnit 5.5.2 测试的 PS
1.未检查的异常
1.1 捕捉运行时异常的 JUnit 示例。
ExceptionExample1.java
package com.mkyong.assertions;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ExceptionExample1 {
@Test
void test_exception() {
Exception exception = assertThrows(
ArithmeticException.class,
() -> divide(1, 0));
assertEquals("/ by zero", exception.getMessage());
assertTrue(exception.getMessage().contains("zero"));
}
int divide(int input, int divide) {
return input / divide;
}
}
2.检查异常
2.1 捕捉自定义/编译时异常的 JUnit 示例。
NameNotFoundException.java
package com.mkyong.assertions;
public class NameNotFoundException extends Exception {
public NameNotFoundException(String message) {
super(message);
}
}
ExceptionExample2.java
package com.mkyong.assertions;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ExceptionExample2 {
@Test
void test_exception_custom() {
Exception exception = assertThrows(
NameNotFoundException.class,
() -> findByName("mkyong"));
assertTrue(exception.getMessage().contains("not found"));
}
String findByName(String name) throws NameNotFoundException{
throw new NameNotFoundException( name + " not found!");
}
}
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/assertions/*.java
参考
JUnit 5 + Gradle 示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/gradle/junit-5-gradle-examples/
本文向您展示了如何在 Gradle 项目中添加 JUnit 5。
使用的技术:
- Gradle 5.4.1
- Java 8
- JUnit 5.5.2
1.Gradle + JUnit 5
1.添加 JUni 5 jupiter 引擎,并如下定义useJUnitPlatform()
:
gradle.build
plugins {
id 'java'
id 'eclipse' // optional, for Eclipse project
id 'idea' // optional, for IntelliJ IDEA project
}
repositories {
mavenCentral()
}
dependencies {
testImplementation('org.junit.jupiter:junit-jupiter:5.5.2')
}
test {
useJUnitPlatform()
}
2.Gradle 项目
标准的 Java 项目结构。
3.JUnit 5
3.1 一个简单的单元测试例子。
MessageService.java
package com.mkyong.core;
public class MessageService {
public static String get() {
return "Hello JUnit 5";
}
}
3.2 JUnit 5 简单Assertions
测试。
MessageServiceTest.java
package com.mkyong.core;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MessageServiceTest {
@DisplayName("Test MessageService.get()")
@Test
void testGet() {
assertEquals("Hello JUnit 5", MessageService.get());
}
}
4 .测试等级
4.1 在 Gradle 中运行测试。
Terminal
$ cd project
$ gradle test
BUILD SUCCESSFUL in 0s
3 actionable tasks: 3 up-to-date
4.2 如果测试失败,它将显示如下内容:
Terminal
$ gradle test
> Task :test FAILED
com.mkyong.core.MessageServiceTest > testGet() FAILED
org.opentest4j.AssertionFailedError at MessageServiceTest.java:13
1 test completed, 1 failed
4.3 gradle test
默认生成如下 HTML 测试报告:
{project}\build\reports\tests\test\index.html
完成了。
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-gradle
$ gradle test
参考
- JUnit 5 官方网站
- Spring Boot +朱尼特 5 +莫奇托
- Java 测试& JVM 项目
JUnit 5–如何禁用测试?
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-how-to-disable-tests/
JUnit 5 @Disabled
示例禁用对整个测试类或单个测试方法的测试。
用 JUnit 5.5.2 测试的 PS
Note
You can also disable tests based on conditions.
1.@在方法上禁用
1.1 测试方法testCustomerServiceGet
被禁用。
DisabledMethodTest.java
package com.mkyong.disable;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class DisabledMethodTest {
@Disabled("Disabled until CustomerService is up!")
@Test
void testCustomerServiceGet() {
assertEquals(2, 1 + 1);
}
@Test
void test3Plus3() {
assertEquals(6, 3 + 3);
}
}
输出–使用 Intellij IDE 运行。
2.@在课堂上被禁用
2.1 整个测试类将被禁用。
DisabledClassTest.java
package com.mkyong.disable;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@Disabled("Disabled until bug #2019 has been fixed!")
public class DisabledClassTest {
@Test
void test1Plus1() {
assertEquals(2, 1 + 1);
}
@Test
void test2Plus2() {
assertEquals(4, 2 + 2);
}
}
经过测试,它在 Maven 或 Gradle 构建工具中运行正常。
Note
However, run the above test under Intellij IDE, the @Disabled
on class level is NOT working as expected, no idea why?
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/disable/*.java
参考
JUnit 5 + Maven 示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-maven-examples/
这篇文章向你展示了如何在一个 Maven 项目中添加 JUnit 5,没什么特别的,只是添加 JUnit 5 junit-jupiter-engine
库并确保maven-surefire-plugin
至少是版本2.22.0
使用的技术:
- Maven 3.6
- Java 8
- JUnit 5.5.2
1.腹部+6 月 5 日
1.添加 JUni 5 jupiter 引擎。
pom.xml
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
2.要在 Maven 中运行测试,maven-surefire-plugin
必须至少是版本2.22.0
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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.mkyong.core</groupId>
<artifactId>junit5-maven</artifactId>
<version>1.0</version>
<properties>
<java.version>1.8</java.version>
<junit-jupiter.version>5.5.2</junit-jupiter.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- junit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Need at least 2.22.0 to support JUnit 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.Maven 项目
一个简单的 Maven 项目结构。
3.JUnit 5
3.1 一个简单的单元测试例子。
MessageService.java
package com.mkyong.core;
public class MessageService {
public static String get() {
return "Hello JUnit 5";
}
}
3.2 JUnit 5 简单Assertions
测试。
MessageServiceTest.java
package com.mkyong.core;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MessageServiceTest {
@DisplayName("Test MessageService.get()")
@Test
void testGet() {
assertEquals("Hello JUnit 5", MessageService.get());
}
}
3.3 在 IntelliJ IDEA 中运行,输出:
4.mvn 试验
4.1Maven Surefire Plugin
将扫描并运行以下测试类:
**/Test*.java
**/*Test.java
**/*Tests.java
**/*TestCase.java
Terminal
$ cd project
$ mvn test
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.mkyong.core.MessageServiceTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0,
Time elapsed: 0.02 s - in com.mkyong.core.MessageServiceTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.488 s
[INFO] Finished at: 2019-09-14T10:27:01+08:00
[INFO] ------------------------------------------------------------------------
测试结果将在project\target\surefire-reports
以.txt
和.xml
两种格式生成。
5.mvn 站点
5.1 最好生成一个项目站点,以 HTML 格式查看单元测试结果。要将 surefire 单元测试报告添加到站点中,请添加以下reporting
部分。
pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.8.2</version>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
</plugin>
</plugins>
</reporting>
Terminal
$ cd project
$ mvn site
项目网站将在project\target\site
生成,点击index.html
点击project reports
->-surefire report
完成了。
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-maven
$ mvn test
参考
JUnit 5 嵌套测试
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-nested-test-examples/
本文向您展示了如何使用 JUnit 5 @Nested
注释将测试分组在一起。
用 JUnit 5.5.2 测试的 PS
为什么是嵌套测试?
创建嵌套测试是可选的。尽管如此,创建层次化的上下文来将相关的单元测试组织在一起还是有帮助的;简而言之,它有助于保持测试的整洁和可读性。
让我们看看下面的例子——对一个CustomerService
的测试。
1.单一测试类别
1.1 默认情况下,我们可以在一个类中创建所有的测试,如下所示:
CustomerServiceMethodTest.java
package com.mkyong.nested.samples;
import com.mkyong.customer.service.CustomerService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("Test Customer Service")
public class CustomerServiceMethodTest {
CustomerService customerService;
@BeforeEach
void createNewObjectForAll() {
System.out.println("New CustomerService()");
//customerService = new CustomerServiceJDBC();
}
@Test
void findOne_with_id() {
//customerService.findOneById(2L);
}
@Test
void findOne_with_name() {
//customerService.findOneByName(2L);
}
@Test
void findOne_with_name_regex() {
//customerService.findOneByNameRegex("%s");
}
@Test
void findAll_with_ids() {
//customerService.findAllByIds(Arrays.asList(2, 3, 4));
}
@Test
void findAll_with_name_like() {
//customerService.findAllByName("mkyong");
}
@Test
void update_with_new() {
//customerService.update(new Customer());
}
@Test
void update_with_existing() {
//customerService.update(new Customer());
}
}
IDE 中的输出。
如果CustomerService
增加了更多的特性,那么这个测试类将很容易被数百个测试方法所超载。最后,我们创建了一个混乱的、有意义的、无组织的单一测试类。
2.分类测试
2.1 一些开发人员开始按照类名对相关测试进行分组,如下所示:
CustomerServiceFindOneTest.java
package com.mkyong.nested.samples;
import com.mkyong.customer.service.CustomerService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class CustomerServiceFindOneTest {
CustomerService customerService;
@BeforeEach
void createNewObjectForAll() {
System.out.println("New CustomerService()");
//customerService = new CustomerServiceJDBC();
}
@Test
void findOne_with_id() {
//customerService.findOneById(2L);
}
@Test
void findOne_with_name() {
//customerService.findOneByName(2L);
}
@Test
void findOne_with_name_regex() {
//customerService.findOneByNameRegex("%s");
}
}
CustomerServiceFindAllTest.java
package com.mkyong.nested.samples;
import com.mkyong.customer.service.CustomerService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class CustomerServiceFindAllTest {
CustomerService customerService;
@BeforeEach
void createNewObjectForAll() {
System.out.println("New CustomerService()");
//customerService = new CustomerServiceJDBC();
}
@Test
void findAll_with_ids() {
//customerService.findAllByIds(Arrays.asList(2, 3, 4));
}
@Test
void findAll_with_name_likeY() {
//customerService.findAllByName("mkyong");
}
}
CustomerServiceUpdateTest.java
package com.mkyong.nested.samples;
import com.mkyong.customer.service.CustomerService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class CustomerServiceUpdateTest {
CustomerService customerService;
@BeforeEach
void createNewObjectForAll() {
System.out.println("New CustomerService()");
//customerService = new CustomerServiceJDBC();
}
@Test
void update_with_new() {
//customerService.update(new Customer());
}
@Test
void update_with_existing() {
//customerService.update(new Customer());
}
}
如果CustomerService
增加了更多的特性,例如,新的 30 多个方法,我们会为CustomerService
创建 30 多个测试类吗?如何运行 30 多个测试类,通过模式还是创建一个新的测试套件?
3.嵌套测试
3.1 对于大类,我们应该考虑@Nested
测试,单个测试类中的所有测试(在一个层次结构中),IDE 中的层次输出使测试更具可读性。
此外,我们还可以初始化一个对象,并对所有嵌套的测试进行重用。
CustomerServiceNestedTest.java
package com.mkyong.nested;
import com.mkyong.customer.service.CustomerService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@DisplayName("Test Customer Service")
public class CustomerServiceNestedTest {
CustomerService customerService;
// Create one customerService object and reuse for all the nested tests
@Test
@DisplayName("new CustomerService() for all the nested methods.")
void createNewObjectForAll() {
System.out.println("New CustomerService()");
//customerService = new CustomerServiceJDBC();
}
@Nested
@DisplayName("findOne methods")
class FindOne {
@Test
void findOne_with_id() {
//customerService.findOneById(2L);
}
@Test
void findWith_with_name() {
//customerService.findOneByName(2L);
}
@Test
void findWith_with_name_regex() {
//customerService.findOneByNameRegex("%s");
}
}
@Nested
@DisplayName("findAll methods")
class FindAll {
@Test
void findAll_with_ids() {
//customerService.findAllByIds(Arrays.asList(2, 3, 4));
}
@Test
void findAll_with_name_likeY() {
//customerService.findAllByName("mkyong");
}
}
@Nested
@DisplayName("update methods")
class Update {
@Test
void update_with_new() {
//customerService.update(new Customer());
}
@Test
void update_with_existing() {
//customerService.update(new Customer());
}
}
}
IDE 中的输出。
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/nested/*.java
参考
JUnit 5 参数化测试
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-parameterized-tests/
本文向您展示了如何使用不同的参数多次运行一个测试,即所谓的“参数化测试”,让我们来看看以下为测试提供参数的方法:
@ValueSource
@EnumSource
@MethodSource
@CsvSource
@CsvFileSource
@ArgumentsSource
我们需要junit-jupiter-params
来支持参数化测试。
pom.xml
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<!-- Parameterized Tests -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
用 JUnit 5.5.2 测试的 PS
1.@ValueSource
1.1 为单参数测试。
ValueSourceTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ValueSourceTest {
// This test will run 3 times with different arguments
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void test_int_arrays(int arg) {
assertTrue(arg > 0);
}
@ParameterizedTest(name = "#{index} - Run test with args={0}")
@ValueSource(ints = {1, 2, 3})
void test_int_arrays_custom_name(int arg) {
assertTrue(arg > 0);
}
@ParameterizedTest(name = "#{index} - Run test with args={0}")
@ValueSource(strings = {"apple", "banana", "orange"})
void test_string_arrays_custom_name(String arg) {
assertTrue(arg.length() > 1);
}
}
输出
1.2 我们可以通过@EmptySource
、@NullSource
或@NullAndEmptySource
将空值或 null 值传递到测试中(从 JUnit 5.4 开始)。让我们看下面的例子来测试一个isEmpty()
方法。
ValueSourceEmptyTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ValueSourceEmptyTest {
boolean isEmpty(String input) {
return (input == null || input.length() == 0);
}
// run 3 times, 1 for empty, 1 for null, 1 for ""
@ParameterizedTest(name = "#{index} - isEmpty()? {0}")
@EmptySource
@NullSource
//@NullAndEmptySource
@ValueSource(strings = {""})
void test_is_empty_true(String arg) {
assertTrue(isEmpty(arg));
}
@ParameterizedTest(name = "#{index} - isEmpty()? {0}")
@ValueSource(strings = {" ", "\n", "a", "\t"})
void test_is_empty_false(String arg) {
assertFalse(isEmpty(arg));
}
}
输出
2.@EnumSource
2.1 运行以Enum
为参数的测试。
EnumSourceTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import java.util.EnumSet;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.params.provider.EnumSource.Mode.EXCLUDE;
public class EnumSourceTest {
enum Size {
XXS, XS, S, M, L, XL, XXL, XXXL;
}
@ParameterizedTest
@EnumSource(Size.class)
void test_enum(Size size) {
assertNotNull(size);
}
@ParameterizedTest(name = "#{index} - Is size contains {0}?")
@EnumSource(value = Size.class, names = {"L", "XL", "XXL", "XXXL"})
void test_enum_include(Size size) {
assertTrue(EnumSet.allOf(Size.class).contains(size));
}
// Size = M, L, XL, XXL, XXXL
@ParameterizedTest
@EnumSource(value = Size.class, mode = EXCLUDE, names = {"XXS", "XS", "S"})
void test_enum_exclude(Size size) {
EnumSet<Size> excludeSmallSize = EnumSet.range(Size.M, Size.XXXL);
assertTrue(excludeSmallSize.contains(size));
}
}
输出。
$ java -jar junit-platform-console-standalone-1.5.2.jar
-cp "target/test-classes/"
--select-class com.mkyong.params.EnumSourceTest
--disable-ansi-colors
+-- JUnit Jupiter [OK]
| '-- EnumSourceTest [OK]
| +-- test_enum_include(Size) [OK]
| | +-- #1 - Is size contains L? [OK]
| | +-- #2 - Is size contains XL? [OK]
| | +-- #3 - Is size contains XXL? [OK]
| | '-- #4 - Is size contains XXXL? [OK]
| +-- test_enum(Size) [OK]
| | +-- [1] XXS [OK]
| | +-- [2] XS [OK]
| | +-- [3] S [OK]
| | +-- [4] M [OK]
| | +-- [5] L [OK]
| | +-- [6] XL [OK]
| | +-- [7] XXL [OK]
| | '-- [8] XXXL [OK]
| '-- test_enum_exclude(Size) [OK]
| +-- [1] M [OK]
| +-- [2] L [OK]
| +-- [3] XL [OK]
| +-- [4] XXL [OK]
| '-- [5] XXXL [OK]
'-- JUnit Vintage [OK]
3.@MethodSource
3.1 运行使用静态method
生成参数的测试。
MethodSourceTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class MethodSourceTest {
@ParameterizedTest(name = "#{index} - Test with String : {0}")
@MethodSource("stringProvider")
void test_method_string(String arg) {
assertNotNull(arg);
}
// this need static
static Stream<String> stringProvider() {
return Stream.of("java", "rust");
}
@ParameterizedTest(name = "#{index} - Test with Int : {0}")
@MethodSource("rangeProvider")
void test_method_int(int arg) {
assertTrue(arg < 10);
}
// this need static
static IntStream rangeProvider() {
return IntStream.range(0, 10);
}
}
输出
+-- JUnit Jupiter [OK]
| '-- MethodSourceTest [OK]
| +-- test_method_int(int) [OK]
| | +-- #1 - Test with Int : 0 [OK]
| | +-- #2 - Test with Int : 1 [OK]
| | +-- #3 - Test with Int : 2 [OK]
| | +-- #4 - Test with Int : 3 [OK]
| | +-- #5 - Test with Int : 4 [OK]
| | +-- #6 - Test with Int : 5 [OK]
| | +-- #7 - Test with Int : 6 [OK]
| | +-- #8 - Test with Int : 7 [OK]
| | +-- #9 - Test with Int : 8 [OK]
| | '-- #10 - Test with Int : 9 [OK]
| '-- test_method_string(String) [OK]
| +-- #1 - Test with String : java [OK]
| '-- #2 - Test with String : rust [OK]
'-- JUnit Vintage [OK]
3.2 多重论证
MethodSourceMultiTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.params.provider.Arguments.arguments;
public class MethodSourceMultiTest {
@ParameterizedTest
@MethodSource("stringIntAndListProvider")
void testWithMultiArgMethodSource(String str, int length, List<String> list) {
assertTrue(str.length() > 0);
assertEquals(length, list.size());
}
static Stream<Arguments> stringIntAndListProvider() {
return Stream.of(
arguments("abc", 3, Arrays.asList("a", "b", "c")),
arguments("lemon", 2, Arrays.asList("x", "y"))
);
}
}
输出
+-- JUnit Jupiter [OK]
| '-- MethodSourceMultiTest [OK]
| '-- test_method_multi(String, int, List) [OK]
| +-- [1] abc, 3, [a, b, c] [OK]
| '-- [2] lemon, 2, [x, y] [OK]
'-- JUnit Vintage [OK]
4.@CsvSource
4.1 运行以逗号分隔值(csv)作为参数的测试。
CsvSourceTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CsvSourceTest {
@ParameterizedTest
@CsvSource({
"java, 4",
"clojure, 7",
"python, 6"
})
void test_csv(String str, int length) {
assertEquals(length, str.length());
}
}
5.@CsvFileSource
5.1 从文件中导入逗号分隔值(csv)作为参数。
src/test/resources/simple.csv
java, 4
clojure, 7
python, 6
CsvFileSourceTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CsvFileSourceTest {
// Skip the first line
@ParameterizedTest
@CsvFileSource(resources = "/simple.csv", numLinesToSkip = 1)
void test_csv_file(String str, int length) {
assertEquals(length, str.length());
}
}
输出
+-- JUnit Jupiter [OK]
| '-- CsvFileSourceTest [OK]
| '-- test_csv_file(String, int) [OK]
| +-- [1] clojure, 7 [OK]
| '-- [2] python, 6 [OK]
'-- JUnit Vintage [OK]
6.@ArgumentsSource
6.1 创建可重用的参数提供程序。
CustomArgumentsProvider.java
package com.mkyong.params;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import java.util.stream.Stream;
public class CustomArgumentsProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments>
provideArguments(ExtensionContext extensionContext) throws Exception {
return Stream.of("java", "rust", "kotlin").map(Arguments::of);
}
}
ArgumentsSourceTest.java
package com.mkyong.params;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class ArgumentsSourceTest {
@ParameterizedTest
@ArgumentsSource(CustomArgumentsProvider.class)
void test_argument_custom(String arg) {
assertNotNull(arg);
}
}
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/params/*.java
参考
JUnit 5 重复测试
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-repeated-tests/
本文向您展示了如何使用 JUnit 5 @RepeatedTest
来重复测试指定的次数。
用 JUnit 5.5.2 测试的 PS
1.@重复测试
1.1@RepeatedTest
测试方法就像常规的@Test
方法一样,相同的生命周期。
RepeatedSample1Test.java
package com.mkyong.repeated;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class RepeatedSample1Test {
@BeforeAll
static void beforeAll() {
System.out.println("beforeAll");
}
@AfterAll
static void afterAll() {
System.out.println("afterAll");
}
@BeforeEach
void beforeEach() {
System.out.println("beforeEach");
}
@AfterEach
void afterEach() {
System.out.println("afterEach");
}
// Repeat this test 3 times
@RepeatedTest(3)
void math_add_1() {
System.out.println("Run math_add_1()");
assertEquals(2, 1 + 1);
}
@RepeatedTest(3)
void math_add_2() {
System.out.println("Run math_add_2()");
assertEquals(2, 1 + 1);
}
}
IDE 中的输出。
控制台中的输出。
beforeAll
beforeEach
Run math_add_1()
afterEach
beforeEach
Run math_add_1()
afterEach
beforeEach
Run math_add_1()
afterEach
beforeEach
Run math_add_2()
afterEach
beforeEach
Run math_add_2()
afterEach
beforeEach
Run math_add_2()
afterEach
afterAll
2.自定义测试名称
2.1 我们可以配置@RepeatedTest
方法的名称。
RepeatedSample2Test.java
package com.mkyong.repeated;
import org.junit.jupiter.api.RepeatedTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class RepeatedSample2Test {
@RepeatedTest(3)
void math_add_1() {
System.out.println("Run math_add_1()");
assertEquals(2, 1 + 1);
}
@RepeatedTest(value = 3, name = RepeatedTest.LONG_DISPLAY_NAME)
void math_add_2() {
System.out.println("Run math_add_2()");
assertEquals(2, 1 + 1);
}
@RepeatedTest(value = 3, name = "{displayName} - ABC - {currentRepetition}/{totalRepetitions}")
void math_add_3() {
System.out.println("Run math_add_3()");
assertEquals(2, 1 + 1);
}
}
IDE 中的输出。
注意
{displayName}
:测试方法的名称。{currentRepetition}
:当前重复次数。{totalRepetitions}
:总重复次数。
3.重复信息
3.1 我们也可以将RepetitionInfo
作为参数注入,并访问@RepeatedTest
的元数据。
@RepeatedTest.java
package com.mkyong.repeated;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class RepeatedSample3Test {
@RepeatedTest(3)
void math_add_4(RepetitionInfo repetitionInfo) {
System.out.println("Repetition #" + repetitionInfo.getCurrentRepetition());
assertEquals(3, repetitionInfo.getTotalRepetitions());
}
}
控制台中的输出。
Repetition #1
Repetition #2
Repetition #3
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/repeated/*.java
参考
JUnit 5 标签和过滤,@标签示例
本文向您展示了如何通过@Tag
注释使用 JUnit 5 标记和过滤。
测试对象
- JUnit 5.5.2
- Maven 3.6.0
- Gradle 5.6.2
1.@标签
一个简单的标签演示。
TagMethodTest.java
package com.mkyong.tags;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@Tag("branch-20")
public class TagMethodTest {
@Test
@Tag("feature-168")
void test1Plus1() {
assertEquals(2, 1 + 1);
}
@Test
@Tag("integration")
@Tag("fast")
void testFastAndIntegration() {
assertEquals(2, 1 + 1);
}
@Test
@Tag("slow")
void testSlow() {
assertEquals(2, 1 + 1);
}
}
2.Maven 过滤测试
2.1 在 Maven 中,我们可以通过maven-surefire-plugin
的配置参数运行基于标签的测试
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<!-- include tags -->
<groups>integration, feature-168</groups>
<!-- exclude tags -->
<excludedGroups>slow</excludedGroups>
</configuration>
</plugin>
2.2 在控制台中,使用-D
选项。
Terminal
# Run tests which tagged with `integration, slow, feature-168`
$ mvn -Dgroups="integration, fast, feature-168"
# Exclude tests which tagged with 'slow'
$ mvn -DexcludedGroups="slow"
3.梯度过滤试验
3.1 在 Gradle 中,我们可以像这样过滤标签:
build.gradle
test {
useJUnitPlatform{
includeTags 'integration', 'feature-168'
excludeTags 'slow'
}
}
运行标记有integration' and
feature-168`的测试
Terminal
$ gradle clean test
> Task :test
com.mkyong.tags.TagMethodTest > testFastAndIntegration() PASSED
com.mkyong.tags.TagMethodTest > test1Plus1() PASSED
3.2 不知道如何在控制台中传递includeTags
参数,而是创建一个新的测试任务。
build.gradle
task slowTest(type: Test) {
useJUnitPlatform {
includeTags 'slow'
}
}
运行标记为“慢”的测试
Terminal
$ gradle clean slowtest
> Task :slowTest
com.mkyong.tags.TagMethodTest > testSlow() PASSED
Note
JUnit 5 supports Tag Expressions.
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/tag/*.java
$ check pom.xml, uncomment tags stuff
$ mvn test
$ check build.gradle, uncomment tags stuff
$ gradle test
参考
JUnit 5 测试执行顺序
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-test-execution-order/
本文向您展示了如何通过下面的MethodOrderer
类来控制 JUnit 5 测试的执行顺序:
- 含字母和数字的
- 订单注释
- 随意
- 定制订单
用 JUnit 5.5.2 测试的 PS
1.含字母和数字的
1.1 它按字母数字顺序对测试方法进行分类。
MethodAlphanumericTest.java
package com.mkyong.order;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestMethodOrder(MethodOrderer.Alphanumeric.class)
public class MethodAlphanumericTest {
@Test
void testZ() {
assertEquals(2, 1 + 1);
}
@Test
void testA() {
assertEquals(2, 1 + 1);
}
@Test
void testY() {
assertEquals(2, 1 + 1);
}
@Test
void testE() {
assertEquals(2, 1 + 1);
}
@Test
void testB() {
assertEquals(2, 1 + 1);
}
}
输出
testA()
testB()
testE()
testY()
testZ()
2.订单注释
2.1 根据@Order
值对测试方法进行分类。
MethodOrderTest.java
package com.mkyong.order;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MethodOrderTest {
@Test
void test0() {
assertEquals(2, 1 + 1);
}
@Test
@Order(3)
void test1() {
assertEquals(2, 1 + 1);
}
@Test
@Order(1)
void test2() {
assertEquals(2, 1 + 1);
}
@Test
@Order(2)
void test3() {
assertEquals(2, 1 + 1);
}
@Test
void test4() {
assertEquals(2, 1 + 1);
}
}
输出
test2()
test3()
test1()
test0()
test4()
3.随意
3.1 它对测试方法进行伪随机排序,并支持自定义种子的配置:
junit.jupiter.execution.order.random.seed
MethodRandomTest.java
package com.mkyong.order;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestMethodOrder(MethodOrderer.Random.class)
public class MethodRandomTest {
@Test
void testZ() {
assertEquals(2, 1 + 1);
}
@Test
void testA() {
assertEquals(2, 1 + 1);
}
@Test
void testY() {
assertEquals(2, 1 + 1);
}
@Test
void testE() {
assertEquals(2, 1 + 1);
}
@Test
void testB() {
assertEquals(2, 1 + 1);
}
}
输出,随机。
# Run 1
testA()
testZ()
testE()
testY()
testB()
# Run 2
testY()
testE()
testZ()
testA()
testB()
# Run 3
testA()
testB()
testY()
testE()
testZ()
3.2 配置一个定制种子junit.jupiter.execution.order.random.seed
来创建一个可重复的测试构建
在属性文件中。
junit-platform.properties
junit.jupiter.execution.order.random.seed=99
在 Maven 中,配置参数
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<properties>
<configurationParameters>
junit.jupiter.execution.order.random.seed=99
</configurationParameters>
</properties>
</configuration>
</plugin>
在 Gradle 中,配置参数
build.gradle
test {
useJUnitPlatform()
systemProperties = [
'junit.jupiter.execution.order.random.seed': 99
]
}
使用自定义种子再次运行它。
# Run 1 - seed 99
testA()
testZ()
testE()
testY()
testB()
# Run 2 - seed 99
testA()
testZ()
testE()
testY()
testB()
# Run 3 - seed 99
testA()
testZ()
testE()
testY()
testB()
4.定制订单
4.1 执行MethodOrderer
创建自定义测试订单。
4.2 以下示例是按参数计数排序的。
ParameterCountOrder.java
package com.mkyong.order;
import org.junit.jupiter.api.MethodDescriptor;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.MethodOrdererContext;
import java.util.Comparator;
public class ParameterCountOrder implements MethodOrderer {
private Comparator<MethodDescriptor> comparator =
Comparator.comparingInt(md1 -> md1.getMethod().getParameterCount());
@Override
public void orderMethods(MethodOrdererContext context) {
context.getMethodDescriptors().sort(comparator.reversed());
}
}
4.3 用@ParameterizedTest
测试上述定制订单
MethodParameterCountTest.java
package com.mkyong.order;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestMethodOrder(ParameterCountOrder.class)
public class MethodParameterCountTest {
@DisplayName("Parameter Count : 2")
@ParameterizedTest(name = "{index} ==> fruit=''{0}'', qty={1}")
@CsvSource({
"apple, 1",
"banana, 2"
})
void test2(String fruit, int qty) {
assertTrue(true);
}
@DisplayName("Parameter Count : 1")
@ParameterizedTest(name = "{index} ==> ints={0}")
@ValueSource(ints = {1, 2, 3})
void test1(int num1) {
assertTrue(num1 < 4);
}
@DisplayName("Parameter Count : 3")
@ParameterizedTest(name = "{index} ==> fruit=''{0}'', qty={1}, price={2}")
@CsvSource({
"apple, 1, 1.99",
"banana, 2, 2.99"
})
void test3(String fruit, int qty, BigDecimal price) {
assertTrue(true);
}
}
输出
4.4 拆卸comparator.reversed()
public class ParameterCountOrder implements MethodOrderer {
//...
@Override
public void orderMethods(MethodOrdererContext context) {
//context.getMethodDescriptors().sort(comparator.reversed());
context.getMethodDescriptors().sort(comparator);
}
}
输出
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/order/*.java
参考
- JUnit 5 测试执行顺序
- 方法订购者。随机
JUnit 5 超时示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-timeouts-examples/
在 JUnit 5 中,如果执行时间超过给定的持续时间,我们可以使用@Timeout
使测试失败。
用 JUnit 5.5.2 测试的 PS
1.@超时
TimeOutExample1.java
package com.mkyong.timeout;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.util.concurrent.TimeUnit;
public class TimeOutExample1 {
// timed out after 5 seconds
@BeforeEach
@Timeout(5)
void setUpDB() throws InterruptedException {
//TimeUnit.SECONDS.sleep(10);
}
// timed out after 500 miliseconds
@Test
@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
void test_this() {
}
}
2.assertTimeout
2.1 我们也可以使用assertTimeout
让测试超时。
TimeOutExample2.java
package com.mkyong.timeout;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertTimeout;
public class TimeOutExample2 {
// timed out after 5 seconds
@Test
void test_timeout_fail() {
// assertTimeout(Duration.ofSeconds(5), () -> delaySecond(10)); // this will fail
assertTimeout(Duration.ofSeconds(5), () -> delaySecond(1)); // pass
}
void delaySecond(int second) {
try {
TimeUnit.SECONDS.sleep(second);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
下载源代码
$ git clone https://github.com/mkyong/junit-examples
$ cd junit5-examples
$ check src/test/java/com/mkyong/timeout/*.java
参考
JUnit 5 教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/junit5/junit-5-tutorials/
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
P.S JUnit 5 在运行时需要 Java 8(或更高版本)
1.6 月 5 日+胃
参见这个完整的 JUnit 5 + Maven 示例。
pom.xml
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
</plugins>
</build>
附言maven-surefire-plugin
必须至少是版本2.22.0
2.JUnit 5 + Gradle
查看完整的 JUnit 5 + Gradle 示例。
gradle.build
plugins {
id 'java'
id 'eclipse' // optional, for Eclipse project
id 'idea' // optional, for IntelliJ IDEA project
}
repositories {
mavenCentral()
}
dependencies {
testImplementation('org.junit.jupiter:junit-jupiter:5.5.2')
}
test {
useJUnitPlatform()
}
3.JUnit 5 测试
- 六月五日@DisplayName
- JUnit 5 假设
- JUnit 5 @禁用
- JUnit 5 条件测试示例
- JUnit 5 标签和过滤,@Tag
- JUnit 5 测试执行顺序,@TestMethodOrder
- JUnit 5 嵌套测试
- JUnit 5 重复测试
- JUnit 5 从控制台运行测试
- JUnit 5 参数化测试
- JUnit 5 超时
- JUnit 5 预期异常
- JUnit 5 断言
4.第三方断言库
- JUnit 5 + AssertJ
- JUnit 5 + Hamcrest
- JUnit 5 +真相
5.综合
- JUnit 5 + JUnit 4 一起
- JUnit 5 + Mockito
- 朱尼特 5 + Spring Boot
- JUnit 5+https://cucumber.io/
下载源代码
$ git 克隆https://github.com/mkyong/junit-examples
参考
- JUnit 5 官网
- JUnit 5 用户指南
- JUnit 5 样本库
- JUnit 5 指南
- Java 测试& JVM 项目
JUnit–断言一个属性是否存在于一个类中
包括hamcrest-library
并用hasProperty()
测试类属性及其值:
用 JUnit 4.12 和 hamcrest-library 1.3 测试的 PS
ClassPropertyTest.java
package com.mkyong;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasProperty;
import static org.junit.Assert.assertThat;
public class ClassPropertyTest {
//Single Object
@Test
public void testClassProperty() {
Book obj = new Book("Mkyong in Action");
assertThat(obj, hasProperty("name"));
assertThat(obj, hasProperty("name", is("Mkyong in Action")));
}
// List Objects
@Test
public void testClassPropertyInList() {
List<Book> list = Arrays.asList(
new Book("Java in Action"),
new Book("Spring in Action")
);
assertThat(list, containsInAnyOrder(
hasProperty("name", is("Spring in Action")),
hasProperty("name", is("Java in Action"))
));
}
public class Book {
public Book(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
下面是包含hamcrest-library
的 Maven pom 文件
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- This will get hamcrest-core automatically -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
参考
assert hamcrest junit (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190210095034/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
JUnit–类别测试
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/unittest/junit-categories-test/
在 JUnit 中,您可以将测试用例组织成不同的类别,并使用@Categories.ExcludeCategory
或@Categories.IncludeCategory
运行这些分类的测试用例
Note
This @Categories
annotation is available since JUnit 4.12
1.类别=标记界面
在 JUnit 中,您需要创建标记接口来表示类别:
PerformanceTests.java
package com.mkyong.category;
//category marker interface
public interface PerformanceTests {
}
RegressionTests.java
package com.mkyong.category;
public interface RegressionTests {
}
2.@类别示例
将测试用例组织成不同的类别。
2.1 方法级别的@Category
。
ClassA.java
package com.mkyong.category;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class ClassA {
@Category(PerformanceTests.class)
@Test
public void test_a_1() {
assertThat(1 == 1, is(true));
}
@Test
public void test_a_2() {
assertThat(1 == 1, is(true));
}
}
2.2 @Category
在班级层面。
ClassB.java
package com.mkyong.category;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@Category({PerformanceTests.class, RegressionTests.class})
public class ClassB {
@Test
public void test_b_1() {
assertThat(1 == 1, is(true));
}
}
2.3 多个@Category
例子。
ClassC.java
package com.mkyong.category;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class ClassC {
@Category({PerformanceTests.class, RegressionTests.class})
@Test
public void test_c_1() {
assertThat(1 == 1, is(true));
}
@Category(RegressionTests.class)
@Test
public void test_c_2() {
assertThat(1 == 1, is(true));
}
}
3.套件测试
运行分类测试用例的例子。
3.1 包含类别示例,运行PerformanceTests
类别。
PerformanceTestSuite.java
package com.mkyong.category;
import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Categories.class)
@Categories.IncludeCategory(PerformanceTests.class)
//Include multiple categories
//@Categories.IncludeCategory({PerformanceTests.class, RegressionTests.class})
@Suite.SuiteClasses({ClassA.class, ClassB.class, ClassC.class})
public class PerformanceTestSuite {
}
输出
ClassA.test_a_1()
ClassB.test_b_1()
ClassC.test_c_1()
3.2 包含类别示例,运行RegressionTestSuite
类别。
RegressionTestSuite.java
package com.mkyong.category;
import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Categories.class)
@Categories.IncludeCategory(RegressionTests.class)
@Suite.SuiteClasses({ClassA.class, ClassB.class, ClassC.class})
public class RegressionTestSuite {
}
输出
ClassB.test_b_1()
ClassC.test_c_1()
ClassC.test_c_2()
3.3 排除类别示例。
ExcludePerformanceTestSuite.java
package com.mkyong.category;
import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Categories.class)
@Categories.ExcludeCategory(PerformanceTests.class)
@Suite.SuiteClasses({ClassA.class, ClassB.class, ClassC.class})
public class ExcludePerformanceTestSuite {
}
输出
ClassA.test_a_2()
ClassC.test_c_2()
Note
This is similar with the TestNG group test.
参考
category test group test junit
JUnit——如何测试列表
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/unittest/junit-how-to-test-a-list/
首先,排除掉hamcrest-core
的 JUnit 捆绑副本,包含有用的hamcrest-library
,它包含了很多测试List
数据类型的有用方法。
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- This will get hamcrest-core automatically -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
1.断言列表字符串
检查包org.hamcrest.collection
,它包含许多有用的方法来测试一个Collection
或List
ListTest.java
package com.mkyong;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hamcrest.collection.IsEmptyCollection;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.hamcrest.MatcherAssert.assertThat;
public class ListTest {
@Test
public void testAssertList() {
List<String> actual = Arrays.asList("a", "b", "c");
List<String> expected = Arrays.asList("a", "b", "c");
//All passed / true
//1\. Test equal.
assertThat(actual, is(expected));
//2\. If List has this value?
assertThat(actual, hasItems("b"));
//3\. Check List Size
assertThat(actual, hasSize(3));
assertThat(actual.size(), is(3));
//4\. List order
// Ensure Correct order
assertThat(actual, contains("a", "b", "c"));
// Can be any order
assertThat(actual, containsInAnyOrder("c", "b", "a"));
//5\. check empty list
assertThat(actual, not(IsEmptyCollection.empty()));
assertThat(new ArrayList<>(), IsEmptyCollection.empty());
}
}
2.断言列表整数
检查包org.hamcrest.number
,它有断言数字的方法。
ListTest.java
package com.mkyong;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hamcrest.collection.IsEmptyCollection;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;
import static org.hamcrest.number.OrderingComparison.lessThan;
import static org.hamcrest.MatcherAssert.assertThat;
public class ListTest {
@Test
public void testAssertList() {
List<Integer> actual = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5);
//All passed / true
//1\. Test equal.
assertThat(actual, is(expected));
//2\. Check List has this value
assertThat(actual, hasItems(2));
//3\. Check List Size
assertThat(actual, hasSize(4));
assertThat(actual.size(), is(5));
//4\. List order
// Ensure Correct order
assertThat(actual, contains(1, 2, 3, 4, 5));
// Can be any order
assertThat(actual, containsInAnyOrder(5, 4, 3, 2, 1));
//5\. check empty list
assertThat(actual, not(IsEmptyCollection.empty()));
assertThat(new ArrayList<>(), IsEmptyCollection.empty());
//6\. Test numeric comparisons
assertThat(actual, everyItem(greaterThanOrEqualTo(1)));
assertThat(actual, everyItem(lessThan(10)));
}
}
Note
Both org.hamcrest.collection
and org.hamcrest.number
are belong to hamcrest-library
3.断言列表对象
ListTest.java
package com.mkyong;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.junit.Assert.assertThat;
public class ListTest {
@Test
public void testAssertList() {
List<Fruit> list = Arrays.asList(
new Fruit("Banana", 99),
new Fruit("Apple", 20)
);
//Test equals
assertThat(list, hasItems(
new Fruit("Banana", 99),
new Fruit("Apple", 20)
));
assertThat(list, containsInAnyOrder(
new Fruit("Apple", 20),
new Fruit("Banana", 99)
));
//Test class property, and its value
assertThat(list, containsInAnyOrder(
hasProperty("name", is("Apple")),
hasProperty("name", is("Banana"))
));
}
public class Fruit {
public Fruit(String name, int qty) {
this.name = name;
this.qty = qty;
}
private String name;
private int qty;
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//Test equal, override equals() and hashCode()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Fruit fruit = (Fruit) o;
return qty == fruit.qty &&
Objects.equals(name, fruit.name);
}
@Override
public int hashCode() {
return Objects.hash(name, qty);
}
}
}
请在下面分享您的测试示例列表🙂
参考
- Hamcrest 官方网站
- 数组和集合的匹配器——org . ham crest . collection
- 执行数字比较的匹配器–org . ham crest . number
- Maven 和 JUnit 示例
- JUnit–如何测试地图
- Java–如何覆盖 equals 和 hashCode
- JUnit–断言一个属性是否存在于一个类中
JUnit——如何测试地图
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/unittest/junit-how-to-test-a-map/
忘掉 JUnit assertEquals()
,为了测试一个Map
,使用了来自hamcrest-library.jar
的更有表现力的IsMapContaining
类
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- This will get hamcrest-core automatically -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
1.包含示例的 ismap
以下所有assertThat
检查都将通过。
MapTest.java
package com.mkyong;
import org.hamcrest.collection.IsMapContaining;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
public class MapTest {
@Test
public void testAssertMap() {
Map<String, String> map = new HashMap<>();
map.put("j", "java");
map.put("c", "c++");
map.put("p", "python");
map.put("n", "node");
Map<String, String> expected = new HashMap<>();
expected.put("n", "node");
expected.put("c", "c++");
expected.put("j", "java");
expected.put("p", "python");
//All passed / true
//1\. Test equal, ignore order
assertThat(map, is(expected));
//2\. Test size
assertThat(map.size(), is(4));
//3\. Test map entry, best!
assertThat(map, IsMapContaining.hasEntry("n", "node"));
assertThat(map, not(IsMapContaining.hasEntry("r", "ruby")));
//4\. Test map key
assertThat(map, IsMapContaining.hasKey("j"));
//5\. Test map value
assertThat(map, IsMapContaining.hasValue("node"));
}
}
Note
Try IsMapContaining
, before you create your own methods to test a Map. ## 参考
hamcrest junit map (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190214234119/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
JUnit——以特定的顺序运行测试
在 JUnit 中,您可以使用@FixMethodOrder(MethodSorters.NAME_ASCENDING)
按照方法名,按字典顺序运行测试方法。
P.S .用 JUnit 4.12 测试
ExecutionOrderTest.java
package com.mkyong;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
//Sorts by method name
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ExecutionOrderTest {
@Test
public void testB() {
assertThat(1 + 1, is(2));
}
@Test
public void test1() {
assertThat(1 + 1, is(2));
}
@Test
public void testA() {
assertThat(1 + 1, is(2));
}
@Test
public void test2() {
assertThat(1 + 1, is(2));
}
@Test
public void testC() {
assertThat(1 + 1, is(2));
}
}
输出,上述测试方法将按以下顺序运行:
test1
test2
testA
testB
testC
Note
JUnit only provides the method name as the execution order, and I think the JUnit team has no plan to develop other features to support the test execution order, because, unit test should run isolated and in ANY execution order.
如果你真的需要测试执行顺序,试试 TestNG 依赖测试
参考
junit (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190224205421/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
JUnit + Spring 集成示例
在本教程中,我们将向您展示如何使用 JUnit 框架测试 Spring DI 组件。
使用的技术:
- JUnit 4.12
- 哈姆克雷斯特 1.3
- 弹簧 4.3.0 .释放
- 专家
1.项目相关性
要集成 Spring 和 JUnit,您需要spring-test.jar
pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.0.RELEASE</version>
<scope>test</scope>
</dependency>
2.弹簧组件
一个简单的弹簧组件,稍后进行测试。
2.1 一个接口。
DataModelService.java
package com.mkyong.examples.spring;
public interface DataModelService {
boolean isValid(String input);
}
2.2 上述接口的实现。
MachineLearningService.java
package com.mkyong.examples.spring;
import org.springframework.stereotype.Service;
@Service("ml")
public class MachineLearningService implements DataModelService {
@Override
public boolean isValid(String input) {
return true;
}
}
2.2 一个 Spring 配置文件,组件扫描。
AppConfig.java
package com.mkyong.examples.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.mkyong.examples.spring"})
public class AppConfig {
}
3.JUnit + Spring 集成示例
用@RunWith(SpringJUnit4ClassRunner.class)
注释 JUnit 测试类,并手动加载 Spring 配置文件。参考下文:
MachineLearningTest.java
package com.mkyong.spring;
import com.mkyong.examples.spring.AppConfig;
import com.mkyong.examples.spring.DataModelService;
import com.mkyong.examples.spring.MachineLearningService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public class MachineLearningTest {
//DI
@Autowired
@Qualifier("ml")
DataModelService ml;
@Test
public void test_ml_always_return_true() {
//assert correct type/impl
assertThat(ml, instanceOf(MachineLearningService.class));
//assert true
assertThat(ml.isValid(""), is(true));
}
}
完成了。
4.常见问题
4.1 对于 XML,请尝试:
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(locations = {
"classpath:pathTo/appConfig.xml",
"classpath:pathTo/appConfig2.xml"})
public class MachineLearningTest {
//...
}
4.2 对于多个配置文件:
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = {AppConfig.class, AppConfig2.class})
public class MachineLearningTest {
//...
}
参考
相关文章
JUnit 教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/junit-tutorials/
JUnit ,Java 中流行的单元测试框架。在本教程中,所有示例都用JUnit 4.12
进行了测试
1.JUnit 4.x 示例
- Maven + JUnit + Hamcrest 示例
- Gradle + JUnit + Hamcrest 示例
- JUnit–基本注释示例
- JUnit–预期异常测试
- JUnit–忽略测试
- JUnit–超时测试
- JUnit–套件测试,运行多个测试用例
- JUnit–参数化测试
- JUnit–如何测试列表
- JUnit–如何测试地图
- JUnit–类别测试
- JUnit + Spring 集成示例
- JUnit–以特定的顺序运行测试
- JUnit–断言一个属性是否存在于一个类中
- Intellij + Infinitest 连续测试
- 单元测试——什么是嘲讽?为什么呢?
- JUnit 4 与 TestNG–比较(已弃用)
参考
junit tutorials unit test (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190224161623/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
如何加载多个 Spring bean 配置文件
问题
在大型项目结构中,Spring 的 bean 配置文件位于不同的文件夹中,以便于维护和模块化。例如:常用文件夹中的Spring-Common.xml
、连接文件夹中的Spring-Connection.xml
、模块文件夹中的Spring-ModuleA.xml
等等。
您可以在代码中加载多个 Spring bean 配置文件:
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"Spring-Common.xml",
"Spring-Connection.xml","Spring-ModuleA.xml"});
将所有 spring xml 文件放在项目类路径下。
project-classpath/Spring-Common.xml
project-classpath/Spring-Connection.xml
project-classpath/Spring-ModuleA.xml
解决办法
上述方法缺乏组织性且容易出错,更好的方法应该是将所有的 Spring bean 配置文件组织到一个 XML 文件中。例如,创建一个Spring-All-Module.xml
文件,并像这样导入整个 Spring bean 文件:
File : Spring-All-Module.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="common/Spring-Common.xml"/>
<import resource="connection/Spring-Connection.xml"/>
<import resource="moduleA/Spring-ModuleA.xml"/>
</beans>
现在,您可以像这样加载一个 xml 文件:
ApplicationContext context =
new ClassPathXmlApplicationContext(Spring-All-Module.xml);
将该文件放在项目类路径下。
project-classpath/Spring-All-Module.xml
Note
In Spring3, the alternative solution is using JavaConfig @Import.spring (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190225095319/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Log4j hello world 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/logging/log4j-hello-world-example/
在本教程中,我们将向您展示如何使用经典的 log4j 1.2.x 来记录 Java 应用程序中的调试或错误消息。
1.项目目录
回顾最终的项目结构,一个标准的 Maven 风格的 Java 项目。
2.获取 Log4j
声明以下依赖项:
pom.xml
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
非 Maven 用户,访问 log4j 官方页面,下载 jar,手动放入项目库路径。
3.log4j.properties
创建一个log4j.properties
文件,并将其放入 resources 文件夹。请参考上面的步骤#1。
Note
- 对于独立的 Java 应用程序,确保
log4j.properties
文件在project/classes
目录下 - 对于 Java web 应用程序,确保
log4j.properties
文件在WEB-INF/classes
目录下
log4j.properties
# Root logger option
log4j.rootLogger=DEBUG, stdout, file
# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# Redirect log messages to a log file, support file rolling.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\log4j-application.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Note
To understand the symbols in the ConversionPattern
, please refer to this log4j PatternLayout guide.
让我们来分解一下:
- %d{yyyy-MM-dd HH:mm:ss} =日期和时间格式,参考 SimpleDateFormat JavaDoc。
- %-5p =日志优先级,如调试或错误。对于漂亮的打印格式,5 是可选的。
- %c{1} =我们通过 getLogger()设置的日志名称,请参考 log4j PatternLayout guide 。
- %L =记录请求的行号。
- %m%n =要记录和换行的消息。
日志消息示例:
2014-07-02 20:52:39 DEBUG className:200 - This is debug message
2014-07-02 20:52:39 DEBUG className:201 - This is debug message2
4.演示–如何记录消息?
要记录消息,首先,创建一个final static
记录器并为记录器定义一个名称,通常,我们使用完整的包类名。
final static Logger logger = Logger.getLogger(classname.class);
然后,记录具有不同优先级的消息,例如,调试、信息、警告、错误和致命。通常情况下,您只需要使用 debug 或 error。
//logs a debug message
if(logger.isDebugEnabled()){
logger.debug("This is debug");
}
//logs an error message with parameter
logger.error("This is error : " + parameter);
//logs an exception thrown from somewhere
logger.error("This is error", exception);
4.1 示例:记录器被设置为调试优先级。
log4j.properties
log4j.rootLogger=DEBUG, stdout
#...
HelloExample.java
package com.mkyong;
import org.apache.log4j.Logger;
public class HelloExample{
final static Logger logger = Logger.getLogger(HelloExample.class);
public static void main(String[] args) {
HelloExample obj = new HelloExample();
obj.runMe("mkyong");
}
private void runMe(String parameter){
if(logger.isDebugEnabled()){
logger.debug("This is debug : " + parameter);
}
if(logger.isInfoEnabled()){
logger.info("This is info : " + parameter);
}
logger.warn("This is warn : " + parameter);
logger.error("This is error : " + parameter);
logger.fatal("This is fatal : " + parameter);
}
}
输出
2014-07-02 20:52:39 DEBUG HelloExample:19 - This is debug : mkyong
2014-07-02 20:52:39 INFO HelloExample:23 - This is info : mkyong
2014-07-02 20:52:39 WARN HelloExample:26 - This is warn : mkyong
2014-07-02 20:52:39 ERROR HelloExample:27 - This is error : mkyong
2014-07-02 20:52:39 FATAL HelloExample:28 - This is fatal : mkyong
4.2 示例—记录器被设置为错误优先级。
log4j.properties
log4j.rootLogger=error, stdout
#...
再次运行HelloExample
,您将得到以下输出
2014-07-02 20:56:02 ERROR HelloExample:27 - This is error : mkyong
2014-07-02 20:56:02 FATAL HelloExample:28 - This is fatal : mkyong
复习 log4j 的Priority
类。
Priority.java
package org.apache.log4j;
public class Priority {
public final static int OFF_INT = Integer.MAX_VALUE;
public final static int FATAL_INT = 50000;
public final static int ERROR_INT = 40000;
public final static int WARN_INT = 30000;
public final static int INFO_INT = 20000;
public final static int DEBUG_INT = 10000;
//public final static int FINE_INT = DEBUG_INT;
public final static int ALL_INT = Integer.MIN_VALUE;
如果在log4j.properties
中定义了优先级,则只会记录相同或更高优先级的消息。
5.演示–如何记录异常
这个例子展示了如何使用 log4j 来记录一个异常。
HelloExample2.java
package com.mkyong;
import org.apache.log4j.Logger;
public class HelloExample2{
final static Logger logger = Logger.getLogger(HelloExample2.class);
public static void main(String[] args) {
HelloExample2 obj = new HelloExample2();
try{
obj.divide();
}catch(ArithmeticException ex){
logger.error("Sorry, something wrong!", ex);
}
}
private void divide(){
int i = 10 /0;
}
}
输出
2014-07-02 21:03:10 ERROR HelloExample2:16 - Sorry, something wrong!
java.lang.ArithmeticException: / by zero
at com.mkyong.HelloExample2.divide(HelloExample2.java:24)
at com.mkyong.HelloExample2.main(HelloExample2.java:14)
完成了。
下载源代码
Download Source Code – log4j-hello-world-example.zip(8 KB)
参考
log4j.properties 示例
我找不到太多的log4j.properties
例子,这里有几个log4j.properties
例子是我的项目中用到的,仅供分享。
1.输出到控制台
所有日志将被重定向到您的控制台。
log4j.properties
# Root logger option
log4j.rootLogger=INFO, stdout
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
3.输出到文件
所有记录将被重定向到您指定的日志文件。
log4j.properties
# Root logger option
log4j.rootLogger=INFO, file
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
#Redirect to Tomcat logs folder
#log4j.appender.file.File=${catalina.home}/logs/logging.log
log4j.appender.file.File=C:\\logigng.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
3.输出到控制台和文件
所有日志记录将被重定向到日志文件和控制台。
log4j.properties
# Root logger option
log4j.rootLogger=INFO, file, stdout
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\logging.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Note
If you prefer XML, please refer to this log4j.xml example.
参考
Log4j 教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/log4j-tutorial/
Apache log4j ,Java 中的经典日志工具。下面是一系列 Log4j 1.2 教程:
Log4j 教程
- Log4j hello world 示例
一个简单的 Log4j hello world 示例,快速入门指南。 - log4j.properties 示例
Log4j 配置中的属性文件格式。 - log4j.xml 示例
Log4j 配置 xml 文件格式。 - Spring MVC + Log4j 集成实例
在 Spring MVC 框架中启用 Log4j 日志。 - Struts 2 + Log4j 集成示例
在 Struts 2 框架中启用 Log4j 日志记录。 - Struts 1 + Log4j 集成示例
在 Struts 1 框架中启用 Log4j 日志记录。 - JSF 2 + Log4j 集成示例
在 JSF 2 框架中启用 Log4j 日志记录。使用 slf4j 桥处理程序将日志记录从 java.util.logging 重定向到 log4j 的示例。 - Wicket + Log4j 集成示例
在 Wicket 框架中启用 Log4j 日志记录。Wicket 使用 slf4j,需要 slf4j-log4j12
参考
log4j.xml 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/logging/log4j-xml-example/
下面是 log4j 属性文件的 XML 版本,仅供分享。
1.输出到控制台
将日志记录重定向到控制台。
log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true"
xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
2.输出到文件
将日志记录重定向到文件..
log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true"
xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="file" class="org.apache.log4j.RollingFileAppender">
<param name="append" value="false" />
<param name="maxFileSize" value="10KB" />
<param name="maxBackupIndex" value="5" />
<!-- For Tomcat -->
<param name="file" value="${catalina.home}/logs/myStruts1App.log" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</layout>
</appender>
<root>
<level value="ERROR" />
<appender-ref ref="file" />
</root>
</log4j:configuration>
log4j 滚动文件的例子。
3.输出到控制台和文件
将日志输出到控制台和文件的完整示例。
log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true"
xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</layout>
</appender>
<appender name="file" class="org.apache.log4j.RollingFileAppender">
<param name="append" value="false" />
<param name="maxFileSize" value="10MB" />
<param name="maxBackupIndex" value="10" />
<param name="file" value="${catalina.home}/logs/myStruts1App.log" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
</log4j:configuration>
参考
使用 jQuery 的 Mashable 浮动效果示例
Mashable 最出名的是社交媒体资源网站,当用户滚动页面时,它创造了一个令人敬畏的浮动效果。这里有一个简单的想法,用 jQuery 克隆这种浮动效果。
想法…
- 创建一个浮动框。
- 初始浮动框的位置,将其放在正文内容的旁边。
- 当用户滚动页面时,不断检查滚动条的位置。
- 如果滚动条 y 位置大于浮动框 y 位置,动态改变浮动框 y 位置。
- 当滚动条 y 位置小于浮动框 y 位置时,恢复原始位置。
- 当然是用 jQuery。
1.HTML 布局
一个简单的 HTML 布局,页眉,内容和页脚,在内容上方放置一个 div“浮动框”。
<div id="page">
<div id="header"><h1>header</h1></div>
<div id="floating-box"></div>
<div id="body">
<h1>content</h1>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script><h2>Mashable floating effect example</h2>
</div>
<div id="footer"><h1>footer</h1></div>
</div>
2.浮箱 90×200
当人们滚动盒子时,这个盒子会平稳地浮动。您可能需要调整"左边距:-100px;“有点适合你的需要。
#floating-box{
width:90px;
height:200px;
border:1px solid red;
background-color:#BBBBBB;
float:left;
margin-left:-100px;
margin-right:10px;
position:absolute;
z-index:1;
}
3.请不要有冲突
确保 jQuery 与其他库没有冲突。强烈推荐去查一下。
//avoid conflict with other script
$j=jQuery.noConflict();
$j(document).ready(function($) {
4.位置,位置,位置
绑定 jQuery scroll()事件以持续检查浏览器的滚动条位置。
$(window).scroll(function () {
var scrollY = $(window).scrollTop();
var isfixed = $floatingbox.css('position') == 'fixed';
if($floatingbox.length > 0){
if ( scrollY > bodyY && !isfixed ) {
$floatingbox.stop().css({
position: 'fixed',
left: '50%',
top: 20,
marginLeft: -500
});
} else if ( scrollY < bodyY && isfixed ) {
$floatingbox.css({
position: 'relative',
left: 0,
top: 0,
marginLeft: originalX
});
}
}
});
如果滚动条 y 位置大于浮动框 y 位置,将浮动框 y 位置改为“ marginLeft: -500 ”。您可能需要自定义该值以满足您的需要。
if ( scrollY > bodyY && !isfixed ) {
$floatingbox.stop().css({
position: 'fixed',
left: '50%',
top: 20,
marginLeft: -500
});
}
如果滚动条的 y 位置小于浮动框的 y 位置,恢复到原始位置。
if ( scrollY < bodyY && isfixed ) {
$floatingbox.css({
position: 'relative',
left: 0,
top: 0,
marginLeft: originalX
});
}
5.完成的
试着播放下面的例子来了解作品。
这个浮动效果功能是在我的Digg WordPress 插件中实现的。
你自己试试
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<style type="text/css">
#floating-box{
width:90px;
height:200px;
border:1px solid red;
background-color:#BBBBBB;
float:left;
margin-left:-100px;
margin-right:10px;
position:absolute;
z-index:1;
}
#page{
width:800px;
margin:0 auto;
}
#header{
border:1px solid blue;
height:100px;
margin:8px;
}
#body{
border:1px solid blue;
height:2400px;
margin:8px;
}
#footer{
border:1px solid blue;
height:100px;
margin:8px;
}
h1,h2{
padding:16px;
}
</style>
</head>
<body>
<div id="page">
<div id="header"><h1>header</h1></div>
<div id="floating-box">
</div>
<div id="body">
<h1>content</h1>
<h2>Mashable floating effect example</h2>
</div>
<div id="footer"><h1>footer</h1></div>
</div>
<script type="text/javascript">
//avoid conflict with other script
$j=jQuery.noConflict();
$j(document).ready(function($) {
//this is the floating content
var $floatingbox = $('#floating-box');
if($('#body').length > 0){
var bodyY = parseInt($('#body').offset().top) - 20;
var originalX = $floatingbox.css('margin-left');
$(window).scroll(function () {
var scrollY = $(window).scrollTop();
var isfixed = $floatingbox.css('position') == 'fixed';
if($floatingbox.length > 0){
$floatingbox.html("srollY : " + scrollY + ", bodyY : "
+ bodyY + ", isfixed : " + isfixed);
if ( scrollY > bodyY && !isfixed ) {
$floatingbox.stop().css({
position: 'fixed',
left: '50%',
top: 20,
marginLeft: -500
});
} else if ( scrollY < bodyY && isfixed ) {
$floatingbox.css({
position: 'relative',
left: 0,
top: 0,
marginLeft: originalX
});
}
}
});
}
});
</script>
</body>
</html>
Try Demojquery jquery effects (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190310101552/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Maven 和 JUnit 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/unittest/maven-and-junit-example/
在 Maven 中,您可以像这样声明 JUnit 依赖关系:
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
但是,它附带了一个捆绑的hamcrest-core
库副本。
$ mvn dependency:tree
...
[INFO] \- junit:junit:jar:4.12:test
[INFO] \- org.hamcrest:hamcrest-core:jar:1.3:test
...
1.Maven + JUnit + Hamcrest
Note
Not a good idea to use the default JUnit bundled copy of hamcrest-core
, better exclude it.
再次查看更新后的pom.xml
,它排除了hamcrest-core
的 JUnit 捆绑副本。另一方面,它还包括有用的hamcrest-library
:
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- This will get hamcrest-core automatically -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
再次查看依赖关系树。
$ mvn dependency:tree
...
[INFO] +- junit:junit:jar:4.12:test
[INFO] \- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] \- org.hamcrest:hamcrest-core:jar:1.3:test
...
参考
junit maven (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190215000831/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
maven——如何创建多模块项目
在本教程中,我们将向您展示如何使用 Maven 来管理包含四个模块的多模块项目:
- 密码模块–仅接口。
- 密码 md5 模块–密码模块实现,MD5 密码散列。
- 密码 sha 模块–密码模块实现,SHA 密码散列。
- Web 模块——一个简单的 MVC web 应用程序,使用 MD5 或 SHA 算法对输入进行哈希运算。
模块依赖性。
$ password
$ password <-- password-md5
$ password <-- password-sha
$ web <-- (password-md5 | password-sha) <-- password
构建多模块项目的一些命令,例如:
$ mvn -pl password compile # compile password module only
$ mvn -pl password-sha compile # compile password-sha module, also dependency - password
$ mvn -pl web compile # compile web module only
$ mvn -am -pl web compile # compile web module, also dependency - password-sha or password-md5, password
$ mvn -pl web jetty:run # run web module with Jetty
$ mvn compile # compile everything
使用的技术:
- Maven 3.5.3
- JDK 8
- 释放弹簧 5.1.0
- 百里香叶
1.目录结构
在多模块项目布局中,一个父项目包含一个父pom.xml
,每个子模块(子项目)也包含自己的pom.xml
2.Maven POM
让我们回顾一下 Maven 多模块 POM 文件。
2.1 一个父 POM 文件,打包为pom
。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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>
<!-- parent pom -->
<groupId>com.mkyong.multi</groupId>
<artifactId>java-multi-modules</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<!-- sub modules -->
<modules>
<module>web</module>
<module>password</module>
<module>password-sha</module>
<module>password-md5</module>
</modules>
</project>
2.2 在密码模块中。
password/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<!-- parent pom -->
<parent>
<artifactId>java-multi-modules</artifactId>
<groupId>com.mkyong.multi</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- password info -->
<groupId>com.mkyong.password</groupId>
<artifactId>password</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
</project>
2.3 在密码 md5 模块中。
password-md5/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<parent>
<artifactId>java-multi-modules</artifactId>
<groupId>com.mkyong.multi</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- password-md5 info -->
<groupId>com.mkyong.password</groupId>
<artifactId>password-md5</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
2.4 在密码-sha 模块中。
password-sha/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<parent>
<artifactId>java-multi-modules</artifactId>
<groupId>com.mkyong.multi</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- password-sha info -->
<groupId>com.mkyong.password</groupId>
<artifactId>password-sha</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
2.4 在 web 模块中。
web/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<!-- this is a parent pom -->
<parent>
<groupId>com.mkyong.multi</groupId>
<artifactId>java-multi-modules</artifactId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- web project info -->
<groupId>com.mkyong</groupId>
<artifactId>web</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<dependencies>
<!-- md5 or sha hashing -->
<!-- md5 hash
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password-md5</artifactId>
<version>1.0</version>
</dependency>
-->
<!-- sha -->
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password-sha</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
3.父项目
3.1 父 pom,那些属性和依赖(JDK 8,JUnit 5,Spring 5)被所有子模块共享。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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.mkyong.multi</groupId>
<artifactId>java-multi-modules</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<properties>
<!-- https://maven.apache.org/general.html#encoding-warning -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>5.3.1</junit.version>
<spring.version>5.1.0.RELEASE</spring.version>
</properties>
<modules>
<module>web</module>
<module>password</module>
<module>password-sha</module>
<module>password-md5</module>
</modules>
<dependencies>
<!-- Spring DI for all modules -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- unit test -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
</plugin>
</plugins>
</build>
</project>
4.密码模块
4.1 仅包含一个接口的模块。
4.2 POM 文件。
password/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<parent>
<artifactId>java-multi-modules</artifactId>
<groupId>com.mkyong.multi</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mkyong.password</groupId>
<artifactId>password</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
</project>
4.3 一个接口。
PasswordService.java
package com.mkyong.password;
public interface PasswordService {
String hash(String input);
String algorithm();
}
5.密码-md5 模块
5.1 密码模块实现。
5.2 POM 文件。
password-md5/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<parent>
<artifactId>java-multi-modules</artifactId>
<groupId>com.mkyong.multi</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- password-md5 info -->
<groupId>com.mkyong.password</groupId>
<artifactId>password-md5</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
5.3 MD5 散列法。
PasswordServiceImpl.java
package com.mkyong.password;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@Service
public class PasswordServiceImpl implements PasswordService {
@Override
public String hash(String input) {
return md5(input);
}
@Override
public String algorithm() {
return "md5";
}
private String md5(String input) {
StringBuilder result = new StringBuilder();
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
byte[] hashInBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
for (byte b : hashInBytes) {
result.append(String.format("%02x", b));
}
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}
return result.toString();
}
}
5.4 单元测试。
TestPasswordService.java
package com.mkyong.password;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestPasswordService {
PasswordService passwordService;
@BeforeEach
void init() {
passwordService = new PasswordServiceImpl();
}
@DisplayName("md5 -> hex")
@ParameterizedTest
@CsvSource({
"123456, e10adc3949ba59abbe56e057f20f883e",
"hello world, 5eb63bbbe01eeed093cb22bb8f5acdc3"
})
void testMd5hex(String input, String expected) {
assertEquals(expected, passwordService.hash(input));
}
}
6.密码-sha 模块
6.1 密码模块实现。
6.2 POM 文件。
password-sha/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<parent>
<artifactId>java-multi-modules</artifactId>
<groupId>com.mkyong.multi</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mkyong.password</groupId>
<artifactId>password-sha</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<commos.codec.version>1.11</commos.codec.version>
</properties>
<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commos.codec.version}</version>
</dependency>
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
6.3 SHA 与 Apache 通用编解码器库进行哈希运算
PasswordServiceImpl.java
package com.mkyong.password;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;
@Service
public class PasswordServiceImpl implements PasswordService {
@Override
public String hash(String input) {
return DigestUtils.sha256Hex(input);
}
@Override
public String algorithm() {
return "sha256";
}
}
6.4 单元测试。
TestPasswordService.java
package com.mkyong.password;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestPasswordService {
PasswordService passwordService;
@BeforeEach
void init() {
passwordService = new PasswordServiceImpl();
}
@DisplayName("sha256 -> hex")
@ParameterizedTest
@CsvSource({
"123456, 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92",
"hello world, b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
})
void testSha256hex(String input, String expected) {
assertEquals(expected, passwordService.hash(input));
}
}
7.Web 模块
7.1 一个 Spring MCV +百里香网络应用程序,用 md5 或 sha 算法散列一个输入。
7.2 POM 文件。
web/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<!-- this is a parent pom -->
<parent>
<groupId>com.mkyong.multi</groupId>
<artifactId>java-multi-modules</artifactId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- web project info -->
<groupId>com.mkyong</groupId>
<artifactId>web</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<properties>
<thymeleaf.version>3.0.10.RELEASE</thymeleaf.version>
</properties>
<dependencies>
<!-- md5 hash
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password-md5</artifactId>
<version>1.0</version>
</dependency>
-->
<!-- sha -->
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password-sha</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- logging , spring 5 no more bridge, thanks spring-jcl -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- need this for unit test -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<!-- servlet api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- thymeleaf view -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
</dependencies>
<build>
<finalName>java-web-project</finalName>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.12.v20180830</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
</plugins>
</build>
</project>
7.3 Web 模块依赖性
Terminal
$ mvn -pl web dependency:tree
[INFO] com.mkyong:web:war:1.0
[INFO] +- com.mkyong.password:password-sha:jar:1.0:compile
[INFO] | +- commons-codec:commons-codec:jar:1.11:compile
[INFO] | \- com.mkyong.password:password:jar:1.0:compile
[INFO] +- org.springframework:spring-webmvc:jar:5.1.0.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:5.1.0.RELEASE:compile
[INFO] | +- org.springframework:spring-beans:jar:5.1.0.RELEASE:compile
[INFO] | +- org.springframework:spring-core:jar:5.1.0.RELEASE:compile
[INFO] | | \- org.springframework:spring-jcl:jar:5.1.0.RELEASE:compile
[INFO] | +- org.springframework:spring-expression:jar:5.1.0.RELEASE:compile
[INFO] | \- org.springframework:spring-web:jar:5.1.0.RELEASE:compile
[INFO] +- org.springframework:spring-test:jar:5.1.0.RELEASE:compile
[INFO] +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] | +- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] | \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] +- org.thymeleaf:thymeleaf:jar:3.0.10.RELEASE:compile
[INFO] | +- ognl:ognl:jar:3.1.12:compile
[INFO] | | \- org.javassist:javassist:jar:3.20.0-GA:compile
[INFO] | +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile
[INFO] | \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile
[INFO] +- org.thymeleaf:thymeleaf-spring5:jar:3.0.10.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:5.1.0.RELEASE:compile
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.3.1:test
[INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test
[INFO] | +- org.junit.platform:junit-platform-engine:jar:1.3.1:test
[INFO] | | +- org.junit.platform:junit-platform-commons:jar:1.3.1:test
[INFO] | | \- org.opentest4j:opentest4j:jar:1.1.1:test
[INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.3.1:test
[INFO] \- org.junit.jupiter:junit-jupiter-params:jar:5.3.1:test
[INFO] ------------------------------------------------------------------------
7.4 春天的东西,整合百里香叶和配置。
SpringConfig.java
package com.mkyong.web.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
@EnableWebMvc
@Configuration
@ComponentScan({"com.mkyong"})
public class SpringConfig implements WebMvcConfigurer {
@Autowired
private ApplicationContext applicationContext;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(true);
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
}
WebInitializer.java
package com.mkyong.web;
import com.mkyong.web.config.SpringConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
WelcomeController.java
package com.mkyong.web.controller;
import com.mkyong.password.PasswordService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class WelcomeController {
private final Logger logger = LoggerFactory.getLogger(WelcomeController.class);
@Autowired
private PasswordService passwordService;
@GetMapping("/")
public String welcome(@RequestParam(name = "query",
required = false, defaultValue = "123456") String query, Model model) {
logger.debug("Welcome to mkyong.com... Query : {}", query);
model.addAttribute("query", query);
model.addAttribute("hash", passwordService.hash(query));
model.addAttribute("algorithm", passwordService.algorithm());
return "index";
}
}
7.5 Spring MVC 的单元测试。
TestWelcome.java
package com.mkyong.web;
import com.mkyong.web.config.SpringConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringJUnitWebConfig(SpringConfig.class)
@DisplayName("Test Spring MVC default view")
public class TestWelcome {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webAppContext;
@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();
}
@Test
public void testDefault() throws Exception {
this.mockMvc.perform(
get("/"))
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andExpect(model().attribute("query", "123456"));
//.andExpect(model().attribute("sha256", "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"))
//.andExpect(model().attribute("md5", "e10adc3949ba59abbe56e057f20f883e"));
}
}
七点六分。
index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h1 th:text="'Input : ' + ${query}"/>
<h1 th:text="'Algorithm : ' + ${algorithm}"/>
<h3 th:text="${hash}" />
</body>
</html>
完成了。
8.演示
8.1 在父项目中,使用标准的mvn compile
来编译所有的模块,Maven 将决定编译顺序。
Terminal
$ mvn compile
[INFO] Reactor Summary:
[INFO]
[INFO] java-multi-modules 1.0 ............................. SUCCESS [ 0.007 s]
[INFO] password ........................................... SUCCESS [ 0.539 s]
[INFO] password-sha ....................................... SUCCESS [ 0.038 s]
[INFO] web ................................................ SUCCESS [ 0.080 s]
[INFO] password-md5 1.0 ................................... SUCCESS [ 0.035 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.822 s
[INFO] Finished at: 2018-10-23T15:32:21+08:00
[INFO] ------------------------------------------------------------------------
8.2 将所有模块安装到本地存储库中。
Terminal
$ mvn install
8.3 只编译 web 模块(Maven 将从本地存储库中找到密码模块依赖项,这就是为什么我们需要mvn install
Terminal
$ mvn -pl web compile
8.4 或者,添加-am
来编译 web 模块及其依赖模块(密码-sha 和密码)。
Terminal
$ mvn -am -pl web compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] java-multi-modules [pom]
[INFO] password [jar]
[INFO] password-sha [jar]
[INFO] web [war]
......
[INFO] Reactor Summary:
[INFO]
[INFO] java-multi-modules 1.0 ............................. SUCCESS [ 0.009 s]
[INFO] password ........................................... SUCCESS [ 0.534 s]
[INFO] password-sha ....................................... SUCCESS [ 0.036 s]
[INFO] web 1.0 ............................................ SUCCESS [ 0.077 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.780 s
[INFO] Finished at: 2018-10-23T15:36:16+08:00
[INFO] ------------------------------------------------------------------------
8.5 用mvn -pl web jetty:run
命令测试网络模块。
Terminal
$ mvn install
$ mvn -pl web jetty:run
//...
[INFO] 1 Spring WebApplicationInitializers detected on classpath
[INFO] DefaultSessionIdManager workerName=node0
[INFO] No SessionScavenger set, using defaults
[INFO] node0 Scavenging every 600000ms
[INFO] Started ServerConnector@40a8a26f{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
[INFO] Started @6398ms
[INFO] Started Jetty Server
8.7 http://localhost:8080/?query=mkyong
8.8 MD5 算法更新。重启 Jetty 服务器。
web/pom.xml
<!-- md5 hash -->
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password-md5</artifactId>
<version>1.0</version>
</dependency>
<!-- sha
<dependency>
<groupId>com.mkyong.password</groupId>
<artifactId>password-sha</artifactId>
<version>1.0</version>
</dependency>
-->
8.9 http://localhost:8080/?query=mkyong
下载源代码
$ git clone https://github.com/mkyong/maven-examples.git
$ cd java-multi-modules
$ mvn install
$ mvn -pl web jetty:run
参考
- 教程:百里香叶+春天
- 使用 Spring MVC 提供 Web 内容
- 多模块项目
- Spring IO–创建多模块项目
- 使用 Maven 和 Gradle 构建多模块项目
- Maven——如何创建一个 Java 项目
- Maven–如何创建 Java web 应用项目
maven–如何强制重新下载项目依赖关系?
在 Maven 中,你可以使用 Apache Maven 依赖插件,目标dependency:purge-local-repository
从本地存储库中移除项目依赖,并再次重新下载。
Terminal
$ mvn dependency:purge-local-repository
[INFO] Scanning for projects...
[INFO]
[INFO] --------------< com.mkyong.examples:maven-code-coverage >---------------
[INFO] Building maven-code-coverage 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:purge-local-repository (default-cli) @ maven-code-coverage ---
Downloading from central: https://repo.maven.apache.org/maven2/org/junit/jupiter/junit-jupiter-engine/5.3.1/junit-jupiter-engine-5.3.1.pom
Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/jupiter/junit-jupiter-engine/5.3.1/junit-jupiter-engine-5.3.1.pom (2.4 kB at 2.1 kB/s)
Downloading from central: https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.pom
//...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.086 s
[INFO] Finished at: 2018-11-20T15:22:28+08:00
[INFO] ------------------------------------------------------------------------
参考
Tags : maven maven-faq project dependency
maven–JaCoCo 代码覆盖示例
在本文中,我们将向您展示如何使用一个 JaCoCo Maven 插件来为一个 Java 项目生成代码覆盖报告。
测试对象
- Maven 3.5.3
- JUnit 5.3.1
- jacoco-maven 插件
Note
JaCoCo is an actively developed line coverage tool, that is used to measure how many lines of our code are tested.
1.JaCoCo Maven 插件
1.1 在pom.xml
文件中声明下面的 JaCoCo 插件。
pom.xml
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- attached to Maven test phase -->
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
它将在 Maven 测试阶段运行 JaCoCo 的“报告”目标。
2.单元测试
2.1 一个简单的 Java 代码来返回一个消息,和一个空字符串检查。
MessageBuilder.java
package com.mkyong.examples;
public class MessageBuilder {
public String getMessage(String name) {
StringBuilder result = new StringBuilder();
if (name == null || name.trim().length() == 0) {
result.append("Please provide a name!");
} else {
result.append("Hello " + name);
}
return result.toString();
}
}
2.2 类以上单元测试。
TestMessageBuilder.java
package com.mkyong.examples;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestMessageBuilder {
@Test
public void testNameMkyong() {
MessageBuilder obj = new MessageBuilder();
assertEquals("Hello mkyong", obj.getMessage("mkyong"));
}
}
2.3 运行mvn test
,将在target/site/jacoco/*
生成 JaCoCo 代码覆盖报告
Terminal
$ mvn clean test
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.mkyong.examples.TestMessageBuilder
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.012 s - in com.mkyong.examples.TestMessageBuilder
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.2:report (report) @ maven-code-coverage ---
[INFO] Loading execution data file D:\maven-examples\maven-code-coverage\target\jacoco.exec
[INFO] Analyzed bundle 'maven-code-coverage' with 1 classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.164 s
[INFO] Finished at: 2018-11-14T16:48:39+08:00
[INFO] ------------------------------------------------------------------------
2.4 打开target/site/jacoco/index.html
文件,查看代码覆盖率报告:
- 绿色–代码已经过测试或被覆盖。
- 红色-代码未被测试或覆盖。
- 黄色-代码部分测试或被覆盖。
3.改进单元测试
3.1 增加一项红线测试。
TestMessageBuilder.java
package com.mkyong.examples;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestMessageBuilder {
@Test
public void testNameMkyong() {
MessageBuilder obj = new MessageBuilder();
assertEquals("Hello mkyong", obj.getMessage("mkyong"));
}
@Test
public void testNameEmpty() {
MessageBuilder obj = new MessageBuilder();
assertEquals("Please provide a name!", obj.getMessage(" "));
}
}
再次查看报告。
Terminal
$ mvn clean test
target/site/jacoco/index.html
3.2 为黄线 if 条件增加一项试验。
TestMessageBuilder.java
package com.mkyong.examples;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestMessageBuilder {
@Test
public void testNameMkyong() {
MessageBuilder obj = new MessageBuilder();
assertEquals("Hello mkyong", obj.getMessage("mkyong"));
}
@Test
public void testNameEmpty() {
MessageBuilder obj = new MessageBuilder();
assertEquals("Please provide a name!", obj.getMessage(" "));
}
@Test
public void testNameNull() {
MessageBuilder obj = new MessageBuilder();
assertEquals("Please provide a name!", obj.getMessage(null));
}
}
再次查看报告。
Terminal
$ mvn clean test
target/site/jacoco/index.html
最后,所有线路都经过测试,100%覆盖。
4.常见问题
4.1 确保线路覆盖率必须达到最低 90%。
pom.xml
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<!-- Add this checking -->
<execution>
<id>jacoco-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>PACKAGE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.9</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
jacoco:check
目标附属于 Maven 验证阶段。
Terminal
$ mvn clean verify
[INFO] Analyzed bundle 'maven-code-coverage' with 1 classes
[WARNING] Rule violated for package com.mkyong.examples: lines covered ratio is 0.8, but expected minimum is 0.9
Note
More JaCoCo check examples :
4.2 如何更新默认的 JaCoCo 输出文件夹?
pom.xml
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<!-- default target/jscoco/site/* -->
<configuration>
<outputDirectory>target/jacoco-report</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
下载源代码
$ git clone https://github.com/mkyong/maven-examples.git
$ cd maven-code-coverage
$ mvn clean test
查看“target/site/jacoco/index.html”中的报告
参考
maven–PMD 示例
原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/maven-pmd-example/
在本文中,我们将向您展示如何使用 Maven PMD 插件来分析 Java 代码。
PMD 需要 Java 1.7
1.玛文 PMD 插件
在reporting
标签中定义maven-pmd-plugin
,这样mvn site
将生成 PMD 报告。
pom.xml
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.11.0</version>
</plugin>
</plugins>
</reporting>
2.Java 代码
一个简单的 Java 代码。我们将使用 Maven PMD 插件来分析这些代码,并在报告中显示这些问题。
package com.mkyong.examples;
public class StaticCodeExample {
//Unused field
private int abc;
private String ip = "127.0.0.1";
public void test() {
String[] field = {"a", "b", "c", "s", "e"};
String s = "";
for (int i = 0; i < field.length; ++i) {
s = s + field[i];
}
System.out.println(ip);
}
}
3.Maven 站点
为了生成 Java 项目的 Maven 站点,PMD 报告将被自动生成并集成到 Maven 站点中。
$ mvn compile site
[INFO] Generating "PMD" report --- maven-pmd-plugin:3.11.0:pmd
[INFO] Generating "Dependency Information" report --- maven-project-info-reports-plugin:3.0.0:dependency-info
[INFO] Generating "About" report --- maven-project-info-reports-plugin:3.0.0:index
[INFO] Generating "Plugin Management" report --- maven-project-info-reports-plugin:3.0.0:plugin-management
[INFO] Generating "Plugins" report --- maven-project-info-reports-plugin:3.0.0:plugins
[INFO] Generating "Summary" report --- maven-project-info-reports-plugin:3.0.0:summary
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.732 s
[INFO] Finished at: 2018-11-19T15:38:56+08:00
[INFO] ------------------------------------------------------------------------
4.PMD 报告
在target/site/pmd.html
查看报告
5.常见问题
5.1 在此回顾所有 PMD 内置的 Java 规则。
下载源代码
$ git 克隆https://github.com/mkyong/maven-examples.git
$ CD maven-静态代码分析
$ mvn 编译站点
在 target/site/pmd.html 查看报告
参考
Tags : maven pmd static code analysis
Maven 配置文件示例
原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/maven-profiles-example/
在本文中,我们将向您展示几个 Maven profile 示例,为不同的环境(开发、测试或生产)传递不同的参数(服务器或数据库参数)。
用 Maven 3.5.3 测试的 PS
1.基本 Maven 配置文件
1.1 跳过单元测试的简单概要。
pom.xml
<!-- skip unit test -->
<profile>
<id>xtest</id>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
</profile>
1.2 要激活一个数据图表,添加-P
选项。
Terminal
# Activate xtest profile to skip unit test and package the project
$ mvn package -Pxtest
1.3 要激活多个配置文件:
Terminal
$ mvn package -P xtest, another-profile-id
# multi modules, same syntax
$ mvn -pl module-name package -P xtest, another-profile-id
1.4 在编译或打包阶段,总是添加maven-help-plugin
来显示活动的概要文件,这将为您节省大量调试时间。
pom.xml
<build>
<plugins>
<!-- display active profile in compile phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>show-profiles</id>
<phase>compile</phase>
<goals>
<goal>active-profiles</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
下一次,当前活动的概要文件将在编译阶段显示。
Terminal
$ mvn compile -P xtest
[INFO] --- maven-help-plugin:3.1.0:active-profiles (show-profiles) @ example1 ---
[INFO]
Active Profiles for Project 'com.mkyong:example1:jar:1.0':
The following profiles are active:
- xtest (source: com.mkyong:example1:1.0)
2.Maven 配置文件–示例 1
将不同的属性值传递给开发和生产环境的 Maven profile 示例。
2.1 属性文件。
resources/db.properties
db.driverClassName=${db.driverClassName}
db.url=${db.url}
db.username=${db.username}
db.password=${db.password}
2.2 启用过滤。Maven 将把resources/db.properties
中的${}
映射到活动的 Maven 配置文件属性。
Note
Read this Maven filteringpom.xml
<!-- map ${} variable -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
2.3 创建两个具有不同属性值的配置文件 id(dev 和 prod)。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<parent>
<artifactId>maven-profiles</artifactId>
<groupId>com.mkyong</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>example1</artifactId>
<profiles>
<profile>
<id>dev</id>
<activation>
<!-- this profile is active by default -->
<activeByDefault>true</activeByDefault>
<!-- activate if system properties 'env=dev' -->
<property>
<name>env</name>
<value>dev</value>
</property>
</activation>
<properties>
<db.driverClassName>com.mysql.jdbc.Driver</db.driverClassName>
<db.url>jdbc:mysql://localhost:3306/dev</db.url>
<db.username>mkyong</db.username>
<db.password>8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92</db.password>
</properties>
</profile>
<profile>
<id>prod</id>
<activation>
<!-- activate if system properties 'env=prod' -->
<property>
<name>env</name>
<value>prod</value>
</property>
</activation>
<properties>
<db.driverClassName>com.mysql.jdbc.Driver</db.driverClassName>
<db.url>jdbc:mysql://live01:3306/prod</db.url>
<db.username>mkyong</db.username>
<db.password>8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92</db.password>
</properties>
</profile>
</profiles>
<build>
<!-- map ${} variable -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.mkyong.example1.App1</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.4 加载属性文件并将其打印出来。
App1.java
package com.mkyong.example1;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class App1 {
public static void main(String[] args) {
App1 app = new App1();
Properties prop = app.loadPropertiesFile("db.properties");
prop.forEach((k, v) -> System.out.println(k + ":" + v));
}
public Properties loadPropertiesFile(String filePath) {
Properties prop = new Properties();
try (InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(filePath)) {
prop.load(resourceAsStream);
} catch (IOException e) {
System.err.println("Unable to load properties file : " + filePath);
}
return prop;
}
}
2.5 测试一下。
Terminal
# default profile id is 'dev'
$ mvn package
$ java -jar target/example1-1.0.jar
db.password:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
db.driverClassName:com.mysql.jdbc.Driver
db.username:mkyong
db.url:jdbc:mysql://localhost:3306/dev
# enable profile id 'prod' with -P prod or -D env=prod
$ mvn package -P prod
$ mvn package -D env=prod
$ java -jar target/example1-1.0.jar
db.password:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
db.driverClassName:com.mysql.jdbc.Driver
db.username:mkyong
db.url:jdbc:mysql://live01:3306/prod
3.Maven 配置文件–示例 2
这个 Maven 概要文件示例将把所有内容放在属性文件中。
3.1 一个属性文件,稍后 Maven 将根据配置文件 id 映射该值。
resources/config.properties
# Database Config
db.driverClassName=${db.driverClassName}
db.url=${db.url}
db.username=${db.username}
db.password=${db.password}
# Email Server
email.server=${email.server}
# Log Files
log.file.location=${log.file.location}
3.2 为开发、测试和生产环境创建不同的属性文件。
resources/env/config.dev.properties
# Database Config
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/dev
db.username=mkyong
db.password=8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
# Email Server
email.server=email-dev:8888
# Log Files
log.file.location=dev/file.log
resources/env/config.test.properties
# Database Config
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://test01:3306/test
db.username=mkyong
db.password=8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
# Email Server
email.server=email-test:8888
# Log Files
log.file.location=test/file.log
resources/env/config.prod.properties
# Database Config
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://live01:3306/prod
db.username=mkyong
db.password=8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
# Email Server
email.server=email-prod:25
# Log Files
log.file.location=prod/file.log
3.3 启用过滤。这是关键!
Note
Read this Maven filteringpom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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">
<parent>
<artifactId>maven-profiles</artifactId>
<groupId>com.mkyong</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>example2</artifactId>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>dev</env>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<env>test</env>
</properties>
</profile>
</profiles>
<build>
<!-- Loading all ${} -->
<filters>
<filter>src/main/resources/env/config.${env}.properties</filter>
</filters>
<!-- Map ${} into resources -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>*.properties</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.mkyong.example2.App2</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
3.4 加载属性文件并将其打印出来。
App1.java
package com.mkyong.example2;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class App2 {
public static void main(String[] args) {
App2 app = new App2();
Properties prop = app.loadPropertiesFile("config.properties");
prop.forEach((k, v) -> System.out.println(k + ":" + v));
}
public Properties loadPropertiesFile(String filePath) {
Properties prop = new Properties();
try (InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(filePath)) {
prop.load(resourceAsStream);
} catch (IOException e) {
System.err.println("Unable to load properties file : " + filePath);
}
return prop;
}
}
3.5 测试一下。
Terminal
# profile id dev (default)
$ mvn package
$ java -jar target/example2-1.0.jar
log.file.location:dev/file.log
db.password:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
db.driverClassName:com.mysql.jdbc.Driver
db.username:mkyong
email.server:email-dev:8888
db.url:jdbc:mysql://localhost:3306/dev
# profile id prod
$ mvn package -P prod
$ java -jar target/example2-1.0.jar
log.file.location:prod/file.log
db.password:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
db.driverClassName:com.mysql.jdbc.Driver
db.username:mkyong
email.server:email-prod:25
db.url:jdbc:mysql://live01:3306/prod
# profile id test
$ mvn package -P test
$ java -jar target/example2-1.0.jar
log.file.location:test/file.log
db.password:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
db.driverClassName:com.mysql.jdbc.Driver
db.username:mkyong
email.server:email-test:8888
db.url:jdbc:mysql://test01:3306/test
最后,让我知道你的用例🙂
下载源代码
$ git clone https://github.com/mkyong/maven-examples.git
$ cd maven-profiles
使用配置文件' prod '
$ mvn-pl example 1 package-Pprod
$ Java-jar example 1/target/example 1-1.0 . jar 测试示例 1
使用配置文件“Test”
$ mvn-pl example 2 package-Ptest
$ Java-jar example 2/target/example 2-1.0 . jar 测试示例 2
参考
maven–spot bugs 示例
原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/maven-spotbugs-example/
在本文中,我们将向您展示如何使用 SpotBugs Maven 插件来查找 Java 代码中的 bug。
Note
Findbugs is no longer maintained, and thus SpotBugs is the spiritual successor of FindBugs
P.S SpotBugs 需要 JDK 1.8
1.Maven SpotBugs 插件
在reporting
标签中定义spotbugs-maven-plugin
。这样mvn site
将生成 SpotBugs 报告。
pom.xml
<reporting>
<plugins>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>3.1.8</version>
</plugin>
</plugins>
</reporting>
2.Java 代码
一个简单的 Java 代码,带有一个未使用的字段“abc”和一个“+ string”循环中的性能问题。稍后,SpotBugs 将能够检测到它并在报告中显示出来。
package com.mkyong.examples;
public class StaticCodeExample {
//Unused field
private int abc;
private String ip = "127.0.0.1";
public void test() {
String[] field = {"a", "b", "c", "s", "e"};
//concatenates strings using + in a loop
String s = "";
for (int i = 0; i < field.length; ++i) {
s = s + field[i];
}
System.out.println(ip);
}
}
3.Maven 站点
为了生成 Java 项目的 Maven 站点,SpotBugs 报告将被自动生成并集成到 Maven 站点中。
$ mvn compile site
[INFO] Generating "SpotBugs" report --- spotbugs-maven-plugin:3.1.8:spotbugs
[INFO] Generating "Dependency Information" report --- maven-project-info-reports-plugin:3.0.0:dependency-info
[INFO] Generating "About" report --- maven-project-info-reports-plugin:3.0.0:index
[INFO] Generating "Plugin Management" report --- maven-project-info-reports-plugin:3.0.0:plugin-management
[INFO] Generating "Plugins" report --- maven-project-info-reports-plugin:3.0.0:plugins
[INFO] Generating "Summary" report --- maven-project-info-reports-plugin:3.0.0:summary
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.732 s
[INFO] Finished at: 2018-11-19T15:38:56+08:00
[INFO] ------------------------------------------------------------------------
4.SpotBugs 报告
在target/site/spotbugs.html
查看报告
5.常见问题
5.1 在此查看 SpotBugs 400 错误模式。
5.2 更多 Maven SpotBugs 插件配方在此
下载源代码
$ git 克隆https://github.com/mkyong/maven-examples.git
$ CD maven-静态代码分析
$ mvn 编译站点
在 target/site/spotbugs.html 查看报告
参考
Maven + (Spring + Hibernate)注释+ MySql 示例
Download It – Spring-Hibernate-Annotation-Example.zip
在上一篇教程中,您使用 Maven 创建了一个简单的 Java 项目结构,并演示了如何在 Spring framework 中使用 Hibernate 来完成 MySQL 数据库中的数据操作工作(插入、选择、更新和删除)。在本教程中,您将学习如何以 Spring 和 Hibernate 注释方式做同样的事情。
先决条件
–安装并配置了 Maven、MySQL 和 Eclipse IDE。
The javaee.jar library is required as well, you can get it from j2ee SDK, and include it manually, there is no full version of javaee.jar available in any of the Maven repository yet.
最终项目结构
您的最终项目文件结构应该看起来完全像下面这样,如果您在创建文件夹结构时迷失了方向,请在这里查看这个文件夹结构。
1.表格创建
在 MySQL 数据库中创建一个“股票”表。SQL 语句如下:
CREATE TABLE `mkyong`.`stock` (
`STOCK_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`STOCK_CODE` varchar(10) NOT NULL,
`STOCK_NAME` varchar(20) NOT NULL,
PRIMARY KEY (`STOCK_ID`) USING BTREE,
UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`),
UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
2.项目文件结构
用 Maven 命令' mvn 原型创建一个快速的项目文件结构:生成',参见这里的例子。将其转换为 Eclipse 项目( mvn eclipse:eclipse )并导入 Eclipse IDE。
E:\workspace>mvn archetype:generate
[INFO] Scanning for projects...
...
Choose a number:
(1/2/3....) 15: : 15
...
Define value for groupId: : com.mkyong.common
Define value for artifactId: : HibernateExample
Define value for version: 1.0-SNAPSHOT: :
Define value for package: com.mkyong.common: : com.mkyong.common
[INFO] OldArchetype created in dir: E:\workspace\HibernateExample
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
3.Pom.xml 文件配置
在 Maven 的 pom.xml 文件中添加 Spring、Hibernate、Annotation 和 MySQL 以及它们的依赖关系。
<project
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.mkyong.common</groupId>
<artifactId>SpringExample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringExample</name>
<url>http://maven.apache.org</url>
<repositories>
<repository>
<id>JBoss repository</id>
<url>http://repository.jboss.com/maven2/</url>
</repository>
</repositories>
<dependencies>
<!-- JUnit testing framework -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
<!-- Spring AOP dependency -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<!-- MySQL database driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<!-- Hibernate framework -->
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate3</artifactId>
<version>3.2.3.GA</version>
</dependency>
<!-- Hibernate annotation -->
<dependency>
<groupId>hibernate-annotations</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.0.GA</version>
</dependency>
<dependency>
<groupId>hibernate-commons-annotations</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.0.0.GA</version>
</dependency>
<!-- Hibernate library dependecy start -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
</dependency>
<!-- Hibernate library dependecy end -->
</dependencies>
</project>
4.模型&博&道
模型、业务对象 (BO)和数据访问对象 (DAO)模式有助于清楚地识别层,避免弄乱项目结构。
股票模型(注释)
存储股票数据的股票模型注释类。
package com.mkyong.stock.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
@UniqueConstraint(columnNames = "STOCK_NAME"),
@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
private Integer stockId;
private String stockCode;
private String stockName;
public Stock() {
}
public Stock(String stockCode, String stockName) {
this.stockCode = stockCode;
this.stockName = stockName;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "STOCK_ID", unique = true, nullable = false)
public Integer getStockId() {
return this.stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
@Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
public String getStockCode() {
return this.stockCode;
}
public void setStockCode(String stockCode) {
this.stockCode = stockCode;
}
@Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
public String getStockName() {
return this.stockName;
}
public void setStockName(String stockName) {
this.stockName = stockName;
}
@Override
public String toString() {
return "Stock [stockCode=" + stockCode + ", stockId=" + stockId
+ ", stockName=" + stockName + "]";
}
}
库存业务对象(BO))
股票业务对象(BO)接口和实现,它用来存储项目的业务功能,真正的数据库操作(CRUD)工作不应该涉及这个类,相反它有一个 DAO (StockDao)类来做。
package com.mkyong.stock.bo;
import com.mkyong.stock.model.Stock;
public interface StockBo {
void save(Stock stock);
void update(Stock stock);
void delete(Stock stock);
Stock findByStockCode(String stockCode);
}
使这个类成为 Spring Ioc 容器中的 bean“stock bo ”,并自动连接 stock dao 类。
package com.mkyong.stock.bo.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mkyong.stock.bo.StockBo;
import com.mkyong.stock.dao.StockDao;
import com.mkyong.stock.model.Stock;
@Service("stockBo")
public class StockBoImpl implements StockBo{
@Autowired
StockDao stockDao;
public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
}
public void save(Stock stock){
stockDao.save(stock);
}
public void update(Stock stock){
stockDao.update(stock);
}
public void delete(Stock stock){
stockDao.delete(stock);
}
public Stock findByStockCode(String stockCode){
return stockDao.findByStockCode(stockCode);
}
}
股票数据访问对象
一个股票 DAO 接口及其实现。在上一篇教程中,您的 DAO 类直接扩展了" HibernateDaoSupport ",但是在注释模式下这是不可能的,因为您无法从您的 DAO 类自动连接会话工厂 bean。解决方法是创建一个自定义类(CustomHibernateDaoSupport)并扩展“ HibernateDaoSupport ”并自动连接会话工厂,您的 DAO 类扩展了这个类。
package com.mkyong.stock.dao;
import com.mkyong.stock.model.Stock;
public interface StockDao {
void save(Stock stock);
void update(Stock stock);
void delete(Stock stock);
Stock findByStockCode(String stockCode);
}
package com.mkyong.util;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public abstract class CustomHibernateDaoSupport extends HibernateDaoSupport
{
@Autowired
public void anyMethodName(SessionFactory sessionFactory)
{
setSessionFactory(sessionFactory);
}
}
package com.mkyong.stock.dao.impl;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.mkyong.stock.dao.StockDao;
import com.mkyong.stock.model.Stock;
import com.mkyong.util.CustomHibernateDaoSupport;
@Repository("stockDao")
public class StockDaoImpl extends CustomHibernateDaoSupport implements StockDao{
public void save(Stock stock){
getHibernateTemplate().save(stock);
}
public void update(Stock stock){
getHibernateTemplate().update(stock);
}
public void delete(Stock stock){
getHibernateTemplate().delete(stock);
}
public Stock findByStockCode(String stockCode){
List list = getHibernateTemplate().find(
"from Stock where stockCode=?",stockCode
);
return (Stock)list.get(0);
}
}
5.资源配置
在‘project _ name/main/Java/’下创建一个“ resources ”文件夹,Maven 会将该文件夹下的所有文件视为资源文件。它将用于存储 Spring、Hibernate 和其他配置文件。
弹簧配置
数据库相关…
为数据库细节创建一个属性文件 (database.properties ),放入“资源/属性文件夹。将数据库细节和 Spring bean 配置分散到不同的文件中是一种很好的做法。
数据库.属性
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mkyong
jdbc.username=root
jdbc.password=password
为您的数据库创建一个“data source”bean 配置文件( DataSource.xml ),从 database.properties 导入属性,放入的“资源/数据库文件夹中。
DataSource.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>properties/database.properties</value>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</beans>
冬眠相关的…
创建一个会话工厂 bean 配置文件 (Hibernate.xml ,放入“资源/数据库文件夹。在批注中,您必须使用AnnotationSessionFactoryBean,而不是 LocalSessionFactoryBean ,并在“ annotatedClasses ”属性中指定您的批注模型类,而不是“ mappingResources ”属性。
Hibernate.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.mkyong.stock.model.Stock</value>
</list>
</property>
</bean>
</beans>
将所有 Spring 的 beans 配置文件导入到一个文件(BeanLocations.xml)中,将其放入“ resources/config 文件夹中。
BeanLocations.xml
导入 Spring 数据库配置并启用 Spring 的自动扫描特性。
<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">
<!-- Database Configuration -->
<import resource="../database/DataSource.xml"/>
<import resource="../database/Hibernate.xml"/>
<!-- Auto scan the components -->
<context:component-scan
base-package="com.mkyong.stock" />
</beans>
6.运行它
你有所有的文件和配置,运行它。
package com.mkyong.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.stock.bo.StockBo;
import com.mkyong.stock.model.Stock;
public class App
{
public static void main( String[] args )
{
ApplicationContext appContext =
new ClassPathXmlApplicationContext("spring/config/BeanLocations.xml");
StockBo stockBo = (StockBo)appContext.getBean("stockBo");
/** insert **/
Stock stock = new Stock();
stock.setStockCode("7668");
stock.setStockName("HAIO");
stockBo.save(stock);
/** select **/
Stock stock2 = stockBo.findByStockCode("7668");
System.out.println(stock2);
/** update **/
stock2.setStockName("HAIO-1");
stockBo.update(stock2);
/** delete **/
stockBo.delete(stock2);
System.out.println("Done");
}
}
输出
Hibernate: insert into mkyong.stock (STOCK_CODE, STOCK_NAME) values (?, ?)
Hibernate: select stock0_.STOCK_ID as STOCK1_0_,
stock0_.STOCK_CODE as STOCK2_0_, stock0_.STOCK_NAME as STOCK3_0_
from mkyong.stock stock0_ where stock0_.STOCK_CODE=?
Stock [stockCode=7668, stockId=11, stockName=HAIO]
Hibernate: update mkyong.stock set STOCK_CODE=?, STOCK_NAME=? where STOCK_ID=?
Hibernate: delete from mkyong.stock where STOCK_ID=?
Done
结论
所有与 Spring、Hibernate 相关的类和配置文件都被注释了,它只是把数据库细节留在 XML 文件中。如果你知道如何注释数据库配置细节,请告诉我。就我个人而言,我很少使用注释特性,因为在某些情况下,你可能需要一些变通方法,比如上面的‘CustomHibernateDaoSupport’扩展了‘HibernateDaoSupport’。Spring 和 Hibernate 中成熟开发的 XML 文件。是更优选的。
Tags : annotation hibernate maven mysql spring
Maven + Spring + Hibernate + MySql 示例
本例将使用 Maven 创建一个简单的 Java 项目结构,并演示如何在 Spring framework 中使用 Hibernate 对 MySQL 数据库进行数据操作(插入、选择、更新和删除)。
最终项目结构
您的最终项目文件结构应该看起来完全像下面这样,如果您在创建文件夹结构时迷失了方向,请在这里查看这个文件夹结构。
1.表格创建
在 MySQL 数据库中创建一个“股票”表。SQL 语句如下:
CREATE TABLE `mkyong`.`stock` (
`STOCK_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`STOCK_CODE` varchar(10) NOT NULL,
`STOCK_NAME` varchar(20) NOT NULL,
PRIMARY KEY (`STOCK_ID`) USING BTREE,
UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`),
UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
2.项目文件结构
用 Maven 命令' mvn 原型创建一个快速的项目文件结构:生成',参见这里的例子。将其转换为 Eclipse 项目( mvn eclipse:eclipse )并导入 Eclipse IDE。
E:\workspace>mvn archetype:generate
[INFO] Scanning for projects...
...
Choose a number:
(1/2/3....) 15: : 15
...
Define value for groupId: : com.mkyong.common
Define value for artifactId: : HibernateExample
Define value for version: 1.0-SNAPSHOT: :
Define value for package: com.mkyong.common: : com.mkyong.common
[INFO] OldArchetype created in dir: E:\workspace\HibernateExample
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
3.Pom.xml 文件配置
在 Maven 的 pom.xml 文件中添加 Spring、Hibernate、MySQL 及其依赖项。
<project
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.mkyong.common</groupId>
<artifactId>SpringExample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringExample</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- JUnit testing framework -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
<!-- Spring AOP dependency -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<!-- MySQL database driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<!-- Hibernate framework -->
<dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate3</artifactId>
<version>3.2.3.GA</version>
</dependency>
<!-- Hibernate library dependecy start -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
</dependency>
<!-- Hibernate library dependecy end -->
</dependencies>
</project>
4.模型&博&道
模型、业务对象 (BO)和数据访问对象 (DAO)模式有助于清楚地识别层,避免弄乱项目结构。
股票模型
稍后存储股票数据的股票模型类。
package com.mkyong.stock.model;
import java.io.Serializable;
public class Stock implements Serializable {
private static final long serialVersionUID = 1L;
private Long stockId;
private String stockCode;
private String stockName;
//getter and setter methods...
}
库存业务对象(BO))
股票业务对象(BO)接口和实现,它用来存储项目的业务功能,真正的数据库操作(CRUD)工作不应该涉及这个类,相反它有一个 DAO (StockDao)类来做。
package com.mkyong.stock.bo;
import com.mkyong.stock.model.Stock;
public interface StockBo {
void save(Stock stock);
void update(Stock stock);
void delete(Stock stock);
Stock findByStockCode(String stockCode);
}
package com.mkyong.stock.bo.impl;
import com.mkyong.stock.bo.StockBo;
import com.mkyong.stock.dao.StockDao;
import com.mkyong.stock.model.Stock;
public class StockBoImpl implements StockBo{
StockDao stockDao;
public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
}
public void save(Stock stock){
stockDao.save(stock);
}
public void update(Stock stock){
stockDao.update(stock);
}
public void delete(Stock stock){
stockDao.delete(stock);
}
public Stock findByStockCode(String stockCode){
return stockDao.findByStockCode(stockCode);
}
}
股票数据访问对象
一个库存的 dao 接口和实现,DAO 实现类扩展了 Spring 的“ HibernateDaoSupport ”,使 Hibernate 支持 Spring 框架。现在,您可以通过 getHibernateTemplate() 来执行休眠功能。
package com.mkyong.stock.dao;
import com.mkyong.stock.model.Stock;
public interface StockDao {
void save(Stock stock);
void update(Stock stock);
void delete(Stock stock);
Stock findByStockCode(String stockCode);
}
package com.mkyong.stock.dao.impl;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.mkyong.stock.dao.StockDao;
import com.mkyong.stock.model.Stock;
public class StockDaoImpl extends HibernateDaoSupport implements StockDao{
public void save(Stock stock){
getHibernateTemplate().save(stock);
}
public void update(Stock stock){
getHibernateTemplate().update(stock);
}
public void delete(Stock stock){
getHibernateTemplate().delete(stock);
}
public Stock findByStockCode(String stockCode){
List list = getHibernateTemplate().find(
"from Stock where stockCode=?",stockCode
);
return (Stock)list.get(0);
}
}
5.资源配置
在‘project _ name/main/Java/’下创建一个“ resources ”文件夹,Maven 会将该文件夹下的所有文件视为资源文件。它将用于存储 Spring、Hibernate 和其他配置文件。
休眠配置
为股票表创建一个 Hibernate 映射文件( Stock.hbm.xml ),放在“ resources/hibernate/ 文件夹下。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.mkyong.stock.model.Stock" table="stock" catalog="mkyong">
<id name="stockId" type="java.lang.Long">
<column name="STOCK_ID" />
<generator class="identity" />
</id>
<property name="stockCode" type="string">
<column name="STOCK_CODE" length="10" not-null="true" unique="true" />
</property>
<property name="stockName" type="string">
<column name="STOCK_NAME" length="20" not-null="true" unique="true" />
</property>
</class>
</hibernate-mapping>
弹簧配置
数据库相关…
为数据库细节创建一个属性文件 (database.properties ),放入“资源/属性文件夹。将数据库细节和 Spring bean 配置分散到不同的文件中是一种很好的做法。
数据库.属性
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mkyong
jdbc.username=root
jdbc.password=password
为您的数据库创建一个“data source”bean 配置文件( DataSource.xml ),从 database.properties 导入属性,放入的“资源/数据库文件夹中。
DataSource.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>properties/database.properties</value>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</beans>
冬眠相关的…
创建一个会话工厂 bean 配置文件 (Hibernate.xml ,放入“资源/数据库文件夹。这个 LocalSessionFactoryBean 类将在 Spring 应用程序上下文中设置一个共享的 Hibernate SessionFactory。
Hibernate.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>/hibernate/Stock.hbm.xml</value>
</list>
</property>
</bean>
</beans>
春豆相关…
为 BO 和 DAO 类创建一个 bean 配置文件( Stock.xml ,放入“ resources/spring 文件夹。依赖将 dao (stockDao) bean 注入到 bo (stockBo) bean 中;会话工厂豆到 stockDao。
Stock.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- Stock business object -->
<bean id="stockBo" class="com.mkyong.stock.bo.impl.StockBoImpl" >
<property name="stockDao" ref="stockDao" />
</bean>
<!-- Stock Data Access Object -->
<bean id="stockDao" class="com.mkyong.stock.dao.impl.StockDaoImpl" >
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</beans>
将所有 Spring 的 beans 配置文件导入到一个文件(BeanLocations.xml)中,将其放入“ resources/config 文件夹中。
BeanLocations.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- Database Configuration -->
<import resource="../database/DataSource.xml"/>
<import resource="../database/Hibernate.xml"/>
<!-- Beans Declaration -->
<import resource="../beans/Stock.xml"/>
</beans>
6.运行它
你有所有的文件和配置,运行它。
package com.mkyong.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.stock.bo.StockBo;
import com.mkyong.stock.model.Stock;
public class App
{
public static void main( String[] args )
{
ApplicationContext appContext =
new ClassPathXmlApplicationContext("spring/config/BeanLocations.xml");
StockBo stockBo = (StockBo)appContext.getBean("stockBo");
/** insert **/
Stock stock = new Stock();
stock.setStockCode("7668");
stock.setStockName("HAIO");
stockBo.save(stock);
/** select **/
Stock stock2 = stockBo.findByStockCode("7668");
System.out.println(stock2);
/** update **/
stock2.setStockName("HAIO-1");
stockBo.update(stock2);
/** delete **/
stockBo.delete(stock2);
System.out.println("Done");
}
}
输出
Hibernate: insert into mkyong.stock (STOCK_CODE, STOCK_NAME) values (?, ?)
Hibernate: select stock0_.STOCK_ID as STOCK1_0_,
stock0_.STOCK_CODE as STOCK2_0_, stock0_.STOCK_NAME as STOCK3_0_
from mkyong.stock stock0_ where stock0_.STOCK_CODE=?
Stock [stockCode=7668, stockId=11, stockName=HAIO]
Hibernate: update mkyong.stock set STOCK_CODE=?, STOCK_NAME=? where STOCK_ID=?
Hibernate: delete from mkyong.stock where STOCK_ID=?
Done
Download it – Spring-Hibernate-Example.zip
春天+ JDBC 的例子
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring/maven-spring-jdbc-example/
在本教程中,我们将通过添加 JDBC 支持来扩展上一个 Maven + Spring hello world 示例,使用 Spring + JDBC 将记录插入到客户表中。
1.客户表
在这个例子中,我们使用 MySQL 数据库。
CREATE TABLE `customer` (
`CUST_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`NAME` varchar(100) NOT NULL,
`AGE` int(10) unsigned NOT NULL,
PRIMARY KEY (`CUST_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
2.项目依赖性
在 Maven pom.xml
文件中添加 Spring 和 MySQL 依赖项。
文件:pom.xml
<project
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.mkyong.common</groupId>
<artifactId>SpringExample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringExample</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
<!-- MySQL database driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
</dependencies>
</project>
3.客户模型
添加客户模型以存储客户数据。
package com.mkyong.customer.model;
import java.sql.Timestamp;
public class Customer
{
int custId;
String name;
int age;
//getter and setter methods
}
4.数据访问对象(DAO)模式
客户 Dao 接口。
package com.mkyong.customer.dao;
import com.mkyong.customer.model.Customer;
public interface CustomerDAO
{
public void insert(Customer customer);
public Customer findByCustomerId(int custId);
}
客户 Dao 实现,使用 JDBC 发出简单的 insert 和 select 语句。
package com.mkyong.customer.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mkyong.customer.dao.CustomerDAO;
import com.mkyong.customer.model.Customer;
public class JdbcCustomerDAO implements CustomerDAO
{
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insert(Customer customer){
String sql = "INSERT INTO CUSTOMER " +
"(CUST_ID, NAME, AGE) VALUES (?, ?, ?)";
Connection conn = null;
try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, customer.getCustId());
ps.setString(2, customer.getName());
ps.setInt(3, customer.getAge());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
public Customer findByCustomerId(int custId){
String sql = "SELECT * FROM CUSTOMER WHERE CUST_ID = ?";
Connection conn = null;
try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, custId);
Customer customer = null;
ResultSet rs = ps.executeQuery();
if (rs.next()) {
customer = new Customer(
rs.getInt("CUST_ID"),
rs.getString("NAME"),
rs.getInt("Age")
);
}
rs.close();
ps.close();
return customer;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
}
5.弹簧豆配置
为 customerDAO 和 datasource 创建 Spring bean 配置文件。
文件:Spring-Customer.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="customerDAO" class="com.mkyong.customer.dao.impl.JdbcCustomerDAO">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
文件:Spring-Datasource.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mkyongjava" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
</beans>
文件:Spring-Module.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="database/Spring-Datasource.xml" />
<import resource="customer/Spring-Customer.xml" />
</beans>
6.检查项目结构
这个例子的完整目录结构。
7.运行它
package com.mkyong.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.customer.dao.CustomerDAO;
import com.mkyong.customer.model.Customer;
public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext("Spring-Module.xml");
CustomerDAO customerDAO = (CustomerDAO) context.getBean("customerDAO");
Customer customer = new Customer(1, "mkyong",28);
customerDAO.insert(customer);
Customer customer1 = customerDAO.findByCustomerId(1);
System.out.println(customer1);
}
}
输出
Customer [age=28, custId=1, name=mkyong]
下载源代码
Download it– SpringJDBCExample.zip (10 KB)
Apache Maven 教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/maven-tutorials/
Apache Maven 是一款创新的软件项目管理工具。它使用项目对象模型(POM)文件来管理项目的构建、依赖、报告和文档。
PS 用 Apache Maven 3.5.x 测试
1.装置
在 Windows、Ubuntu 和 MacOS 上安装 Maven
2.Java 项目
管理 JAR 项目、Web 项目(WAR)和多模块项目的 Maven 示例。
3.单元测试
Maven + JUnit 5 个例子。
4.代码覆盖率
Maven +代码覆盖报告集成。
5.静态代码分析
Maven +静态代码分析报告。
6.Maven 常见问题
- Maven 概要示例
- Maven 本地存储库在哪里
- Maven 中央存储库在哪里
- Maven 远程存储库在哪里
- Maven–如何启用代理设置
- Maven–如何强制重新下载项目依赖关系?
- 如何将基于 Maven 的 war 文件部署到 Tomcat
- 如何将自定义库纳入 maven 本地库?
源代码
$ git clone https://github.com/mkyong/maven-examples
参考
mock ITO–when()需要一个必须是“模拟上的方法调用”的参数
运行下面的 Spring Boot + JUnit 5 + Mockito 集成测试。
package com.mkyong.core.services;
import com.mkyong.core.repository.HelloRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@SpringBootTest
public class HelloServiceMockTest {
@Mock
private HelloRepository helloRepository;
@InjectMocks // auto inject helloRepository
private HelloService helloService = new HelloServiceImpl();
@BeforeEach
void setMockOutput() {
when(helloService.getDefault()).thenReturn("Hello Mockito");
}
//...
}
但是会遇到以下错误:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1\. you stub either of: final/private/equals()/hashCode() methods.
Those methods <strong>cannot</strong> be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2\. inside when() you don't call method on mock but on some other object.
解决办法
这个when(mock.getArticles()).thenReturn(articles);
需要应用在被模仿的对象上。当 Mockito 看到这个@InjectMocks
时,它并没有嘲笑它,它只是创建了一个普通的实例,所以这个when()
将会失败。
要解决它,注释@spy
来部分嘲讽它。
package com.mkyong.core.services;
import com.mkyong.core.repository.HelloRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@SpringBootTest
public class HelloServiceMockTest {
@Mock
private HelloRepository helloRepository;
@Spy // mock it partially
@InjectMocks
private HelloService helloService = new HelloServiceImpl();
@BeforeEach
void setMockOutput() {
when(helloService.getDefault()).thenReturn("Hello Mockito");
}
//...
}
参考
mock mockito spring boot (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190308020415/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
ModelAndView 的模型值不会通过 el 显示在 JSP 中
问题
在 Spring MVC 开发中,开发人员试图在模型中设置一个值,并通过 el 在 JSP 中显示该值,例如 \({msg}** ,但它只是按原样输出结果——**\) { msg },而不是存储在模型中的“值”。EL 在 JSP 中就是不工作,为什么?
弹簧控制器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
public class ABCController extends AbstractController{
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView model = new ModelAndView("HelloWorldPage");
model.addObject("msg", "hello world");
return model;
}
}
JSP 页面
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
${msg}
</body>
</html>
解决办法
这是大多数 Spring MVC hello world 示例中常见的问题。实际上这是由旧的 JSP 1.2 描述符引起的。
1.JSP 1.2
如果你使用的是由 DTD 定义的旧 JSP 1.2 描述符,例如
web . XML
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
//...
</web-app>
默认情况下,EL 被禁用或忽略,您必须手动启用它,以便它将输出存储在“msg”模型中的值。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<%@ page isELIgnored="false" %>
</head>
<body>
${msg}
</body>
</html>
2.JSP 2.0
如果你使用的是由 w3c schema 定义的**标准 JSP 2.0 描述符,例如
web.xml**
<web-app id="WebApp_ID" version="2.4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
//...
</web-app>
EL 是默认启用的,您应该看到存储在“msg”模型中的值,即“hello world”。
参考
- 编写使用指令的 JSP 代码
MongoDB 身份验证示例
本指南向您展示了如何在 MongoDB 中启用身份验证。默认情况下,身份验证是禁用的。要配置它,您必须首先向“admin”数据库添加一个用户。
> show dbs
admin #add single user to this database
testdb
Note
Users with normal access in “admin” database, HAVE read and write access to all the other databases. Users with read only access to the “admin” database HAVE only read to all databases.
这个例子使用的是 MongoDB 版本 2.2.3
认证示例
查看完整的示例,将“admin”用户添加到 admin 数据库,将普通用户添加到“testdb”数据库,以及如何执行身份验证。
Terminal 1 – Start MongoDB in secure mode, authentication is required.
$mongo --auth
Terminal 2 – MongoDB client, see comment “#” for self-explanatory
$ mongo
MongoDB shell version: 2.2.3
connecting to: test
> use admin #1\. connect to the "admin" database.
switched to db admin
> db.addUser("admin","password") #2\. add a user "admin" to the admin database.
{
"user" : "admin",
"readOnly" : false,
"pwd" : "90f500568434c37b61c8c1ce05fdf3ae",
"_id" : ObjectId("513af8cac115e7a6b4bcceb9")
}
addUser succeeded, but cannot wait for replication since we no longer have auth
> use testdb #3\. connect to the "testdb" database.
switched to db testdb
> show collections #4\. now, read and write need authentication
Sat Mar 9 16:54:57 uncaught exception: error: {
"$err" : "unauthorized db:testdb ns:testdb.system.namespaces lock type:0 client:127.0.0.1",
"code" : 10057
}
> use admin #5\. connect back to the "admin" database.
switched to db admin
> db.auth("admin","password") #6\. performs authentication, 1 means succeed, 0 means failed
1
> use testdb #7\. connect to the "testdb" database.
switched to db testdb
> show collections #8\. no problem, it shows all collections
system.indexes
user
> db.addUser("testdb","password") #9\. add another user "testdb" to the "testdb" database.
{
"user" : "testdb",
"readOnly" : false,
"pwd" : "b9ff75cbf18bd98d8554efec12c72090",
"_id" : ObjectId("513af934c115e7a6b4bcceba")
}
> show collections
system.indexes
system.users #10\. All users' data are stored in this system.users collection.
user
> db.system.users.find()
{ "_id" : ObjectId("513af934c115e7a6b4bcceba"), "user" : "testdb", "readOnly" : false, "pwd" : "b9ff75cbf18bd98d8554efec12c72090" }
>
完成了。
参考
authentication mongodb (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190308183427/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
MongoDB:无法打开/data/db/yourdb.ns 错误号:13 权限被拒绝
启动 MongoDB 服务器,它在一个数据库上显示错误“权限被拒绝”,并自动关闭服务器。
$ mongod
Fri Mar 8 22:54:46 [initandlisten] MongoDB starting : pid=13492
port=27017 dbpath=/data/db/ 64-bit host=Yongs-MacBook-Air.local
//...
Fri Mar 8 22:54:46 [initandlisten] journal dir=/data/db/journal
Fri Mar 8 22:54:46 [initandlisten] recover : no journal files present, no recovery needed
Fri Mar 8 22:54:46 [initandlisten] couldn't open /data/db/yourdb.ns errno:13 Permission denied
Fri Mar 8 22:54:46 [initandlisten] error couldn't open file /data/db/yourdb.ns terminating
Fri Mar 8 22:54:46 dbexit:
Fri Mar 8 22:54:46 [initandlisten] shutdown: going to close listening sockets...
Fri Mar 8 22:54:46 [initandlisten] shutdown: going to flush diaglog...
Fri Mar 8 22:54:46 [initandlisten] shutdown: going to close sockets...
Fri Mar 8 22:54:46 [initandlisten] shutdown: waiting for fs preallocator...
Fri Mar 8 22:54:46 [initandlisten] shutdown: lock for final commit...
Fri Mar 8 22:54:46 [initandlisten] shutdown: final commit...
Fri Mar 8 22:54:46 [initandlisten] shutdown: closing all files...
Fri Mar 8 22:54:46 [initandlisten] closeAllFiles() finished
Fri Mar 8 22:54:46 [initandlisten] journalCleanup...
Fri Mar 8 22:54:46 [initandlisten] removeJournalFiles
Fri Mar 8 22:54:46 [initandlisten] shutdown: removing fs lock...
Fri Mar 8 22:54:46 dbexit: really exiting now
解决办法
错误消息显示您无权访问yourdb.ns
数据库。查看 MongoDB 数据目录/data/db/
,数据库yourdb.ns
属于 root 用户。
$ ls -ls /data/db
0 drwxr-xr-x 2 mkyong wheel 68 Mar 8 22:54 journal
131072 -rw------- 1 root wheel 67108864 Mar 7 17:01 yourdb.0
262144 -rw------- 1 root wheel 134217728 Mar 7 16:15 yourdb.1
32768 -rw------- 1 root wheel 16777216 Mar 7 17:01 yourdb.ns
$whoami
mkyong
若要解决此问题,请为数据库分配权限。
$ sudo chown -R mkyong /data/db
$ ls -ls /data/db
0 drwxr-xr-x 2 mkyong wheel 68 Mar 8 22:54 journal
131072 -rw------- 1 mkyong wheel 67108864 Mar 7 17:01 yourdb.0
262144 -rw------- 1 mkyong wheel 134217728 Mar 7 16:15 yourdb.1
32768 -rw------- 1 mkyong wheel 16777216 Mar 7 17:01 yourdb.ns
mongodb (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190304031529/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
MongoDB hello world 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/mongodb/mongodb-hello-world-example/
一个向你展示如何在 MongoDB 中创建、更新、查找、删除记录和索引等基本操作的快速指南。这个例子使用的是 MongoDB 2.0.7,运行在 Mac OS X 10.8 上,MongoDB 客户端和服务器控制台都运行在同一台机器的本地主机上。
1.安装 MongoDB
在 Windows 、 Ubuntu 或 Mac OS X 上安装 MongoDB。安装很容易,基本上只需下载 MongoDB zip 文件,然后运行命令-$MongoDB-folder/bin/mongod
。
使用mongod
启动 MongoDB。
$./mongod
Tue Sep 11 21:55:36 [initandlisten] MongoDB starting :
pid=72280 port=27017 dbpath=/data/db/ 64-bit host=Yongs-MacBook-Air.local
Tue Sep 11 21:55:36 [initandlisten] db version v2.0.7, pdfile version 4.5
Tue Sep 11 21:55:36 [initandlisten] options: {}
Tue Sep 11 21:55:36 [initandlisten] journal dir=/data/db/journal
Tue Sep 11 21:55:36 [initandlisten] recover : no journal files present, no recovery needed
Tue Sep 11 21:55:36 [websvr] admin web console waiting for connections on port 28017
Tue Sep 11 21:55:36 [initandlisten] waiting for connections on port 27017
2.连接 MongoDB
为了连接 MongoDB,使用了$MongoDB-folder/bin/mongo
$ ./mongo
MongoDB shell version: 2.0.7
connecting to: test
3.创建数据库或表(集合)
在 MongoDB 中,数据库和表都是在第一次插入数据时自动创建的。使用use database-name
,切换到您的数据库(即使这个数据库还没有创建)。
在下面的例子中,插入一条记录后,数据库“mkyong”和表“users”被动态创建。
$ ./mongo
MongoDB shell version: 2.0.7
connecting to: test
> use mkyong
switched to db mkyong
> db.users.insert({username:"mkyong",password:"123456"})
> db.users.find()
{ "_id" : ObjectId("504f45cd17f6c778042c3c07"), "username" : "mkyong", "password" : "123456" }
你应该知道的三个数据库命令。
show dbs
–列出所有数据库。use db_name
–切换到数据库名称。show collections
–列出当前所选数据库中的所有表格。
Note
In MongoDB, collection means table in SQL.
4.插入记录
要插入一条记录,使用db.tablename.insert({data})
或db.tablename.save({data})
,两者都可以,不知道为什么 MongoDB 创建了两者。
> db.users.save({username:"google",password:"google123"})
> db.users.find()
{ "_id" : ObjectId("504f45cd17f6c778042c3c07"), "username" : "mkyong", "password" : "123456" }
{ "_id" : ObjectId("504f48ea17f6c778042c3c0a"), "username" : "google", "password" : "google123" }
5.更新记录
要更新记录,使用db.tablename.update({criteria},{$set: {new value}})
。在下面的例子中,用户名“mkyong”的密码被更新。
> db.users.update({username:"mkyong"},{$set:{password:"hello123"}})
> db.users.find()
{ "_id" : ObjectId("504f48ea17f6c778042c3c0a"), "username" : "google", "password" : "google123" }
{ "_id" : ObjectId("504f45cd17f6c778042c3c07"), "password" : "hello123", "username" : "mkyong" }
6.查找记录
要查找或查询记录,使用db.tablename.find({criteria})
。
6.1 列出表格“用户”中的所有记录。
> db.users.find()
{ "_id" : ObjectId("504f48ea17f6c778042c3c0a"), "username" : "google", "password" : "google123" }
{ "_id" : ObjectId("504f45cd17f6c778042c3c07"), "password" : "hello123", "username" : "mkyong" }
6.2 查找用户名为“google”的记录
> db.users.find({username:"google"})
{ "_id" : ObjectId("504f48ea17f6c778042c3c0a"), "username" : "google", "password" : "google123" }
6.3 查找用户名长度小于或等于 2 的记录
db.users.find({$where:"this.username.length<=2"})
6.4 查找存在用户名字段的记录。
db.users.find({username:{$exists : true}})
7.删除记录
要删除记录,使用db.tablename.remove({criteria})
。在下面的例子中,用户名“google”的记录被删除。
> db.users.remove({username:"google"})
> db.users.find()
{ "_id" : ObjectId("504f45cd17f6c778042c3c07"), "password" : "hello123", "username" : "mkyong" }
Note
To delete all records from a table, uses db.tablename.remove()
.
To drop the table, uses db.tablename.drop()
.
8.索引
索引可以帮助你提高查询数据的速度。
8.1 列出“用户”表的所有索引,默认情况下“_id”列始终是主键,是自动创建的。
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mkyong.users",
"name" : "_id_"
}
]
>
8.2 创建一个索引,使用db.tablename.ensureIndex(column)
。在下面的示例中,在“用户名”列上创建了一个索引。
> db.users.ensureIndex({username:1})
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mkyong.users",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"username" : 1
},
"ns" : "mkyong.users",
"name" : "username_1"
}
]
8.3 要降一个指标,使用db.tablename.dropIndex(column)
。在下面的示例中,列“username”上的索引被删除或丢弃。
> db.users.dropIndex({username:1})
{ "nIndexesWas" : 2, "ok" : 1 }
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mkyong.users",
"name" : "_id_"
}
]
>
8.4 创建一个唯一的索引,使用db.tablename.ensureIndex({column},{unique:true})
。在下面的示例中,在“用户名”列上创建了一个唯一索引。
> db.users.ensureIndex({username:1},{unique:true});
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mkyong.users",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"username" : 1
},
"unique" : true,
"ns" : "mkyong.users",
"name" : "username_1"
}
]
10.帮助
最后,使用help()
来指导你如何使用 MongoDB。
10.1 help
-所有可用的命令。
> help
db.help() help on db methods
db.mycoll.help() help on collection methods
rs.help() help on replica set methods
help admin administrative help
help connect connecting to a db help
help keys key shortcuts
//...
10.2 db.help()
-显示关于数据库的帮助。
> db.help()
DB methods:
db.addUser(username, password[, readOnly=false])
db.auth(username, password)
db.cloneDatabase(fromhost)
db.commandHelp(name) returns the help for the command
db.copyDatabase(fromdb, todb, fromhost)
//...
10.3 db.collection.help()
-显示关于收集的帮助(表格)。
> db.users.help()
DBCollection help
db.users.find().help() - show DBCursor help
db.users.count()
db.users.dataSize()
db.users.distinct( key ) - eg. db.users.distinct( 'x' )
db.users.drop() drop the collection
db.users.dropIndex(name)
//...
10.4 db.collection.function.help()
-显示功能帮助。
> db.users.find().help()
find() modifiers
.sort( {...} )
.limit( n )
.skip( n )
.count() - total # of objects matching query, ignores skip,limit
.size() - total # of objects cursor would return, honors skip,limit
.explain([verbose])
//...
完成了。希望 MongoDB 命令的总结可以帮助其他人。
参考
MongoDB 导入和导出示例
在本教程中,我们将向您展示如何使用命令:mongoexport
和mongoimport
备份和恢复 MongoDB。
1.使用 mongoexport 备份数据库
几个例子向你展示如何使用mongoexport
来备份数据库。
回顾一些常用选项。
$ mongoexport
Export MongoDB data to CSV, TSV or JSON files.
options:
-h [ --host ] arg mongo host to connect to ( <set name>/s1,s2 for
-u [ --username ] arg username
-p [ --password ] arg password
-d [ --db ] arg database to use
-c [ --collection ] arg collection to use (some commands)
-q [ --query ] arg query filter, as a JSON string
-o [ --out ] arg output file; if not specified, stdout is used
1.1 将所有文档(所有字段)导出到文件“domain-bk.json
”。
$ mongoexport -d webmitta -c domain -o domain-bk.json
connected to: 127.0.0.1
exported 10951 records
1.2 仅导出所有带“domain
”和“worth
”字段的文件。
$ mongoexport -d webmitta -c domain -f "domain,worth" -o domain-bk.json
connected to: 127.0.0.1
exported 10951 records
1.3 使用搜索查询导出所有文档,在这种情况下,只会导出带有“worth > 100000
”的文档。
$mongoexport -d webmitta -c domain -f "domain,worth" -q '{worth:{$gt:100000}}' -o domain-bk.json
connected to: 127.0.0.1
exported 10903 records
1.4 连接到远程服务器,如 mongolab.com,使用用户名和密码。
$ mongoexport -h id.mongolab.com:47307 -d heroku_app -c domain -u username123 -p password123 -o domain-bk.json
connected to: id.mongolab.com:47307
exported 10951 records
查看导出的文件。
$ ls -lsa
total 2144
0 drwxr-xr-x 5 mkyong staff 170 Apr 10 12:00 .
0 drwxr-xr-x+ 50 mkyong staff 1700 Apr 5 10:55 ..
2128 -rw-r--r-- 1 mkyong staff 1089198 Apr 10 12:15 domain-bk.json
Note
With mongoexport
, all exported documents will be in json format. ## 2.使用 mongoimport 恢复数据库
几个例子向你展示如何使用mongoimport
来恢复数据库。
回顾一些常用选项。
$ mongoimport
connected to: 127.0.0.1
no collection specified!
Import CSV, TSV or JSON data into MongoDB.
options:
-h [ --host ] arg mongo host to connect to ( <set name>/s1,s2 for sets)
-u [ --username ] arg username
-p [ --password ] arg password
-d [ --db ] arg database to use
-c [ --collection ] arg collection to use (some commands)
-f [ --fields ] arg comma separated list of field names e.g. -f name,age
--file arg file to import from; if not specified stdin is used
--drop drop collection first
--upsert insert or update objects that already exist
2.1 将文件“domain-bk.json
”中的所有文档导入名为“webmitta2.domain2”的 database.collection 中。将自动创建所有不存在的数据库或集合。
$ mongoimport -d webmitta2 -c domain2 --file domain-bk.json
connected to: 127.0.0.1
Wed Apr 10 13:26:12 imported 10903 objects
2.2 导入所有文档,插入或更新已经存在的对象(基于_id
)。
$ mongoimport -d webmitta2 -c domain2 --file domain-bk.json --upsert
connected to: 127.0.0.1
Wed Apr 10 13:26:12 imported 10903 objects
2.3 使用用户名和密码连接到远程服务器 mongolab.com,并将本地文件domain-bk.json
中的文档导入远程 MongoDB 服务器。
$ mongoimport -h id.mongolab.com:47307 -d heroku_app -c domain -u username123 -p password123 --file domain-bk.json
connected to: id.mongolab.com:47307
Wed Apr 10 13:26:12 imported 10903 objects
参考
JSF 2.0 中的多组件验证器
在 JSF,没有官方方法来验证多个组件或字段。为了解决这个问题,您需要创建一个定制的验证器。在本教程中,我们将向您展示两种创建验证器来验证多个组件的非官方方法——密码和确认密码。
两种方式:
1。寄存器PostValidateEvent
,将验证放入其中。
2。创建一个标准验证器,并通过f:attribute
获得其他组件。
该示例在以下技术下进行了测试:
- JSF 2.1.11
- 雄猫 6,7
- Java 1.6
- maven3
1.PostValidateEvent 中的验证
javax.faces.event.PostValidateEvent
是一个系统事件,在所有组件都通过验证后触发。这个想法是注册一个PostValidateEvent
,并附加一个验证方法。请参见以下内容:
<f:event listener="#{bean.methodToValidateMultipleFields}" type="postValidate" />
default.xhtml
<!DOCTYPE html>
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h1>Multiple-Components Validator in JSF 2.0</h1>
<h:form id="register">
<h:message for="RegisterGroupPanel" style="color:red;" />
<h:panelGrid columns="3" id="RegisterGroupPanel">
<!-- register a PostValidateEvent -->
<f:event listener="#{user.validatePassword}" type="postValidate" />
<h:outputLabel for="username" value="Username : " />
<h:inputText id="username" value="#{user.username}" required="true"
requiredMessage="Please enter username" />
<h:message for="username" style="color: red;" />
<h:outputLabel for="password" value="Password : " />
<h:inputSecret id="password" value="#{user.password}" required="true"
requiredMessage="Please enter password" />
<h:message for="password" style="color: red;" />
<h:outputLabel for="confirmPassword" value="Confirm password : " />
<h:inputSecret id="confirmPassword" required="true"
requiredMessage="Please enter confirm password" />
<h:message for="confirmPassword" style="color: red;" />
</h:panelGrid>
<h:commandButton action="thanks" value="register" />
</h:form>
</h:body>
</html>
在PostValidateEvent
中,“listener”方法必须有这个签名public void method-name(ComponentSystemEvent event)
。代码的其余部分应该是不言自明的。
UserBean.java – It has a method to validate password and confirm password components.
package com.mkyong;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
@ManagedBean(name = "user")
@SessionScoped
public class UserBean {
public String username;
public String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void validatePassword(ComponentSystemEvent event) {
FacesContext fc = FacesContext.getCurrentInstance();
UIComponent components = event.getComponent();
// get password
UIInput uiInputPassword = (UIInput) components.findComponent("password");
String password = uiInputPassword.getLocalValue() == null ? ""
: uiInputPassword.getLocalValue().toString();
String passwordId = uiInputPassword.getClientId();
// get confirm password
UIInput uiInputConfirmPassword = (UIInput) components.findComponent("confirmPassword");
String confirmPassword = uiInputConfirmPassword.getLocalValue() == null ? ""
: uiInputConfirmPassword.getLocalValue().toString();
// Let required="true" do its job.
if (password.isEmpty() || confirmPassword.isEmpty()) {
return;
}
if (!password.equals(confirmPassword)) {
FacesMessage msg = new FacesMessage("Password must match confirm password");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
fc.addMessage(passwordId, msg);
fc.renderResponse();
}
}
}
freestar.config.enabled_slots.push({ placementName: "mkyong_incontent_1", slotId: "mkyong_incontent_1" });
2.自定义验证器和属性
这个方法是从这篇文章复制来的——用于多个字段的验证器。
将“confirmPassword”组件定义为#{confirmPassword}
,通过f:attribute
附加到“Password”组件。
<h:inputSecret id="password" value="#{user.password}" required="true"
requiredMessage="Please enter password">
<f:validator validatorId="passwordValidator" />
<f:attribute name="confirmPassword" value="#{confirmPassword}" />
</h:inputSecret>
<h:inputSecret id="confirmPassword" required="true"
binding="#{confirmPassword}"
requiredMessage="Please enter confirm password" />
default.xhtml
<!DOCTYPE html>
<html
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h1>Multiple-Components Validator in JSF 2.0</h1>
<h:form id="register">
<h:message for="RegisterGroupPanel" style="color:red;" />
<h:panelGrid columns="3" id="RegisterGroupPanel">
<h:outputLabel for="username" value="Username : " />
<h:inputText id="username" value="#{user.username}" required="true"
requiredMessage="Please enter username" />
<h:message for="username" style="color: red;" />
<h:outputLabel for="password" value="Password : " />
<h:inputSecret id="password" value="#{user.password}" required="true"
requiredMessage="Please enter password">
<f:validator validatorId="passwordValidator" />
<f:attribute name="confirmPassword" value="#{confirmPassword}" />
</h:inputSecret>
<h:message for="password" style="color: red;" />
<h:outputLabel for="confirmPassword" value="Confirm password : " />
<h:inputSecret id="confirmPassword" required="true"
binding="#{confirmPassword}"
requiredMessage="Please enter confirm password" />
<h:message for="confirmPassword" style="color: red;" />
</h:panelGrid>
<h:commandButton action="thanks" value="register" />
</h:form>
</h:body>
</html>
自定义验证器类,并通过component.getAttributes
获得确认密码组件。
PasswordValidator.java – JSF Custom validator
package com.mkyong;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
@FacesValidator("passwordValidator")
public class PasswordValidator implements Validator {
@Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
String password = value.toString();
UIInput uiInputConfirmPassword = (UIInput) component.getAttributes()
.get("confirmPassword");
String confirmPassword = uiInputConfirmPassword.getSubmittedValue()
.toString();
// Let required="true" do its job.
if (password == null || password.isEmpty() || confirmPassword == null
|| confirmPassword.isEmpty()) {
return;
}
if (!password.equals(confirmPassword)) {
uiInputConfirmPassword.setValid(false);
throw new ValidatorException(new FacesMessage(
"Password must match confirm password."));
}
}
}
3.演示
以上两个解决方案做同样的事情,验证两个组件-密码和确认密码。
没有输入,required="true"
被触发。
验证多个组件/字段。确保密码等于确认密码。
下载源代码
Download It – JSF-Validator-Multiple-Components-Example.zip (27 KB)
参考
Tags : jsf2 validationfreestar.config.enabled_slots.push({ placementName: "mkyong_leaderboard_btf", slotId: "mkyong_leaderboard_btf" });
NoSuchBeanDefinitionException:没有 JobLauncherTestUtils 类型的合格 bean
遵循官方 Spring 批量单元测试指南创建一个标准的单元测试用例。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:spring/batch/jobs/job-abc.xml",
"classpath:spring/batch/config/context.xml"})
public class AppTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void launchJob() throws Exception {
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
}
}
P.S spring-batch-test.jar
被添加到类路径中。
问题
启动上述单元测试时,提示JobLauncherTestUtils
没有这样的 bean 错误信息?
org.springframework.beans.factory.BeanCreationException: Could not autowire field:
private org.springframework.batch.test.JobLauncherTestUtils com.mkyong.AppTest.jobLauncherTestUtils;
......
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
[org.springframework.batch.test.JobLauncherTestUtils] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
......
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1122)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:379)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313)
...
解决办法
将spring-batch-test.jar
添加到类路径中不会自动创建JobLauncherTestUtils
bean。
为了解决这个问题,在一个 Spring 配置文件中声明一个JobLauncherTestUtils
bean。
spring/batch/config/test-context.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean class="org.springframework.batch.test.JobLauncherTestUtils"/>
</beans>
并将它加载到单元测试中。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:spring/batch/jobs/job-abc.xml",
"classpath:spring/batch/config/context.xml",
"classpath:spring/batch/config/test-context.xml"})
public class AppTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void launchJob() throws Exception {
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
}
}
参考
Wicket 中的自定义 NotEqualInputValidator
Wicket 包含许多为开发人员提供的内置验证器,例如,EqualInputValidator
,它最适合比较两个表单组件的身份。然而,Wicket 没有为不等于验证器提供任何验证器。
NotEqualInputValidator
这里我以EqualInputValidator
为参考,创建一个新的名为“NotEqualInputValidator”的自定义验证器,用于两个表单组件的不相等比较器。
package com.mkyong.user;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.validation.AbstractFormValidator;
import org.apache.wicket.util.lang.Objects;
public class NotEqualInputValidator extends AbstractFormValidator {
private static final long serialVersionUID = 1L;
/** form components to be checked. */
private final FormComponent<?>[] components;
/**
* Construct.
*
* @param formComponent1
* a form component
* @param formComponent2
* a form component
*/
public NotEqualInputValidator(FormComponent<?> formComponent1,
FormComponent<?> formComponent2) {
if (formComponent1 == null) {
throw new IllegalArgumentException(
"argument formComponent1 cannot be null");
}
if (formComponent2 == null) {
throw new IllegalArgumentException(
"argument formComponent2 cannot be null");
}
components = new FormComponent[] { formComponent1, formComponent2 };
}
public FormComponent<?>[] getDependentFormComponents() {
return components;
}
public void validate(Form<?> form) {
// we have a choice to validate the type converted values or the raw
// input values, we validate the raw input
final FormComponent<?> formComponent1 = components[0];
final FormComponent<?> formComponent2 = components[1];
if (Objects.equal(formComponent1.getInput(), formComponent2.getInput())) {
error(formComponent2);
}
}
}
怎么用?
要使用它,只需像普通的验证器一样附加它。
private PasswordTextField passwordTF;
private PasswordTextField cpasswordTF;
add(new NotEqualInputValidator(oldpasswordTF,passwordTF));
Note
You may interest to read this “how to create a custom validator in Wicket“.wicket (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190304031826/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
旧锁文件:\data\db\mongod.lock,可能意味着不干净的关机
当启动 mongoDB 服务器时,它遇到以下错误,mongoDB 服务器无法启动。
**************
old lock file: \data\db\mongod.lock. probably means unclean shutdown
recommend removing file and running --repair
see: http://dochub.mongodb.org/core/repair for more information
*************
Mon May 09 12:37:43 [initandlisten] exception in initAndListen std::exception: old lock file,
terminating
Mon May 09 12:37:43 dbexit:
Mon May 09 12:37:43 [initandlisten] shutdown: going to close listening sockets...
Mon May 09 12:37:43 [initandlisten] shutdown: going to flush diaglog...
Mon May 09 12:37:43 [initandlisten] shutdown: going to close sockets...
Mon May 09 12:37:43 [initandlisten] shutdown: waiting for fs preallocator...
Mon May 09 12:37:43 [initandlisten] shutdown: closing all files...
Mon May 09 12:37:43 closeAllFiles() finished
Mon May 09 12:37:43 dbexit: really exiting now
解决办法
如果 mongoDB 机器崩溃或发出kill -9
命令,这是一个常见的错误消息。简而言之,你的 mongoDB 崩溃了,你得修复它。要修复它:
1.找到data-directory\mongod.lock
文件,并删除它。
2.发出mongod --repair
命令。
mongod --repair
Mon May 09 12:42:57 [initandlisten] db version v1.8.1, pdfile version 4.5
//......
Mon May 09 12:42:57 [initandlisten] shutdown: going to close listening sockets...
Mon May 09 12:42:57 [initandlisten] shutdown: going to flush diaglog...
Mon May 09 12:42:57 [initandlisten] shutdown: going to close sockets...
Mon May 09 12:42:57 [initandlisten] shutdown: waiting for fs preallocator...
Mon May 09 12:42:57 [initandlisten] shutdown: closing all files...
Mon May 09 12:42:57 closeAllFiles() finished
Mon May 09 12:42:57 [initandlisten] shutdown: removing fs lock...
Mon May 09 12:42:57 dbexit: really exiting now
Note
For more detail about how mongodb repair works, please refer to this MongoDB Durability and Repair guide.mongodb (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190220142739/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
ORA-12505,TNS:监听程序当前不知道连接描述符中给定的 SID
这是由于请求的 SID 在{ORACLE_HOME}/network/admin/tnsnames.ora
中不存在
页(page 的缩写)使用 Oracle 数据库 19c 和ojdbc8.jar
进行测试
1.JDBC
try (Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:xe", "system", "password")) {
//...
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
输出:
SQL State: 66000
Listener refused the connection with the following error:
ORA-12505, TNS:listener does not currently know of SID given in connect descriptor
SID xe
在ORACLE_HOME/network/admin/tnsnames.ora
中不存在
2. tnsnames.ora 档案
样本。
C:{ORACLE_HOME}\NETWORK\ADMIN\tnsnames.ora
# tnsnames.ora Network Configuration File: C:\{ORACLE_HOME}\NETWORK\ADMIN\tnsnames.ora
# Generated by Oracle configuration tools.
LISTENER_ORCL =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
ORACLR_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
(CONNECT_DATA =
(SID = CLRExtProc)
(PRESENTATION = RO)
)
)
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
在上面的tnsnames.ora
样本中,SID 是ORCL
要修复它,请更新代码:
try (Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl", "system", "password")) {
//...
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
参考
jQuery 的页面加载效果
JQuery 确实是一个强大而方便的 JavaScript 库。页面或内容加载效果在 jQuery 中非常容易实现。这里有一个让你的网页内容显示页面加载淡入效果的例子。它会给你的读者留下震撼的印象。🙂
想法很简单~
1.创建一个内容隐藏的 div 块
这个 div 块用于实现页面加载效果中内容淡入淡出。
<div id="page_effect" style="display:none;">
<!-- this content is hide, need jQuery to fade in -->
</div>
2.jQuery 淡入效果
当文档准备好显示时,创建一个 jQuery fadeIn 效果
$(document).ready(function(){
$('#page_effect').fadeIn(2000);
});
P.S fadeIn()是 jQuery 库的内置函数。
3.演示
完成 jQuery 代码以实现淡入加载效果。
<html>
<head>
<title>JQuery Page Loading Effect</title>
<script type="text/javascript" src="jquery.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
$('#page_effect').fadeIn(2000);
});
</script>
<body>
<div id="page_effect" style="display:none;">
<h1>JQuery Page Loading Effect</h1>
This is page loading effect with JQuery 1<BR>
This is page loading effect with JQuery 2<BR>
This is page loading effect with JQuery 3<BR>
This is page loading effect with JQuery 4<BR>
This is page loading effect with JQuery 5<BR>
This is page loading effect with JQuery 6<BR>
This is page loading effect with JQuery 7<BR>
This is page loading effect with JQuery 8<BR>
This is page loading effect with JQuery 9<BR>
This is page loading effect with JQuery 10<BR>
This is page loading effect with JQuery 11<BR>
This is page loading effect with JQuery 12<BR>
This is page loading effect with JQuery 13<BR>
This is page loading effect with JQuery 14<BR>
</div>
</body>
</html>
用 Java Dom 和 XSLT 打印漂亮的 XML
本文展示了如何使用 Java DOM 解析器 + XSLT 来格式化或打印 XML 文档。
目录
PS 用 Java 11 测试过
1。一个 XML 文件
staff-simple.xml
<?xml version="1.0" encoding="utf-8"?>
<company>
<staff id="1001">
<name>mkyong</name>
<role>support</role>
</staff>
<staff id="1002">
<name>yflow</name>
<role>admin</role>
</staff>
</company>
2。通过转换器漂亮地打印 XML
在javax.xml.transform.Transformer
中,我们可以配置OutputKeys.INDENT
属性来打印 XML 文档。
private static void transform(Document doc, OutputStream output)
throws TransformerException {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
// pretty print
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(doc), new StreamResult(output));
}
输出
Terminal
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<company>
<staff id="1001">
<name>mkyong</name>
<role>support</role>
</staff>
<staff id="1002">
<name>yflow</name>
<role>admin</role>
</staff>
</company>
但是Transformer
会在输出中增加很多空换行符(Java 11 中测试过),不确定为什么?
3。通过 XSLT 打印 XML
3.1 为了解决上述额外的空换行符问题,我们可以为漂亮打印转换添加一个xslt
文件。
staff-format.xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" cdata-section-elements="cdata-other-elements"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
3.2 XSLT 转换的 DOM 解析器示例。
XsltPrettyPrintDomParser.java
package com.mkyong.xml.dom.xslt;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
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 javax.xml.transform.stream.StreamSource;
import java.io.*;
public class XsltPrettyPrintDomParser {
private static final String XML_FILENAME
= "src/main/resources/staff-simple.xml";
private static final String XSLT_FILENAME
= "src/main/resources/xslt/staff-format.xslt";
public static void main(String[] args) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try (InputStream is = new FileInputStream(XML_FILENAME)) {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
transform(doc, System.out);
} catch (IOException | ParserConfigurationException |
SAXException | TransformerException e) {
e.printStackTrace();
}
}
private static void transform(Document doc, OutputStream output)
throws TransformerException {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
//Transformer transformer = transformerFactory.newTransformer();
// add XSLT for pretty print
Transformer transformer = transformerFactory.newTransformer(
new StreamSource(new File(XSLT_FILENAME)));
// pretty print, this will add extra new lines
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// add extra standalone to break the root node to a new line
transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
transformer.transform(new DOMSource(doc), new StreamResult(output));
}
}
输出
Terminal
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<company>
<staff id="1001">
<name>mkyong</name>
<role>support</role>
</staff>
<staff id="1002">
<name>yflow</name>
<role>admin</role>
</staff>
</company>
4。下载源代码
$ git 克隆https://github.com/mkyong/core-java
$ cd java-xml
$ CD src/main/Java/com/mkyong/XML/DOM/XSLT/
5。参考文献
- 维基百科–文档对象模型
- 维基百科–XSLT
- Oracle–文档对象模型
- Java DOM 解析器 XML 和 XSLT 示例
- 如何在 Java 中读取 XML 文件—(DOM 解析器)
- 如何用 Java 编写 XML 文件—(DOM 解析器)
- 如何在 Java 中修改 XML 文件—(DOM 解析器)
Quartz 2 调度程序教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/quartz-2-scheduler-tutorial/
Quartz ,企业调度器作业框架,帮助 Java 应用程序调度作业/任务在指定的日期和时间运行。
本教程向您展示了如何使用最新的 Quartz library 2.1.5 开发一个调度作业。
Note
Quartz 2 involves significant API changed, read this for older Quartz 1.6.3 example.
1.下载 Quartz
可以从官网或者 Maven 中央知识库获取石英库
文件:pom.xml
<dependencies>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.1.5</version>
</dependency>
</dependencies>
Note
To deploy Quartz on Application server like JBoss, oracle or weblogic, you may need addition Quartz dependency, read this guide.
2.石英工作
Quartz 作业定义了你要运行什么?
文件:HelloJob
package com.mkyong.common;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job
{
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello Quartz!");
}
}
3.石英触发器
石英触发器定义了石英什么时候会运行你上面的石英的工作?
像旧的 Quartz 一样,Quartz 2 中仍然有两种类型的触发器,但是 API 发生了变化:
- simple trigger–允许设置开始时间、结束时间和重复间隔。
- CronTrigger 允许 Unix cron 表达式指定运行作业的日期和时间。
简单触发器–每 5 秒运行一次。
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName", "group1")
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).repeatForever())
.build();
cron trigger–每 5 秒运行一次。
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
Note
Read this official documentation for more Quartz 2 trigger examples.
4.调度程序
调度器类将“作业和“触发器链接在一起并执行。
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
5.完整示例
Quartz 2 带有 SimpleTrigger 和 CronTrigger 的完整示例。
简单触发器示例–每隔 5 秒运行一次。
package com.mkyong.quartz;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
public class SimpleTriggerExample {
public static void main(String[] args) throws Exception {
// Quartz 1.6.3
// JobDetail job = new JobDetail();
// job.setName("dummyJobName");
// job.setJobClass(HelloJob.class);
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("dummyJobName", "group1").build();
//Quartz 1.6.3
// SimpleTrigger trigger = new SimpleTrigger();
// trigger.setStartTime(new Date(System.currentTimeMillis() + 1000));
// trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
// trigger.setRepeatInterval(30000);
// Trigger the job to run on the next round minute
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName", "group1")
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5).repeatForever())
.build();
// schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
CronTrigger 示例–相同,每 5 秒运行一次作业。
package com.mkyong.quartz;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
public class CronTriggerExample
{
public static void main( String[] args ) throws Exception
{
//Quartz 1.6.3
//JobDetail job = new JobDetail();
//job.setName("dummyJobName");
//job.setJobClass(HelloJob.class);
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("dummyJobName", "group1").build();
//Quartz 1.6.3
//CronTrigger trigger = new CronTrigger();
//trigger.setName("dummyTriggerName");
//trigger.setCronExpression("0/5 * * * * ?");
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
//schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
下载源代码
Download it – Quartz2Example.zip (10kb)
参考
Tags : quartz scheduler tutorials
Quartz 2 作业监听器示例
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/quartz-joblistener-example/
在本教程中,我们将向您展示如何创建一个JobListener
,来跟踪正在运行的作业状态,比如作业何时完成。
附注:本示例使用石英 2.1.5 进行测试
1.石英工作
Job,打印一条简单的消息,并抛出一个JobExecutionException
进行测试。
文件:HelloJob.java
package com.mkyong.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job
{
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello Quartz! 123");
//Throw exception for testing
throw new JobExecutionException("Testing Exception");
}
}
2.作业监听器
要创建 JobListener,只需实现JobListener
接口,并覆盖所有接口的方法。
文件:HelloJobListener.java
package com.mkyong.quartz.listener;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
public class HelloJobListener implements JobListener {
public static final String LISTENER_NAME = "dummyJobListenerName";
@Override
public String getName() {
return LISTENER_NAME; //must return a name
}
// Run this if job is about to be executed.
@Override
public void jobToBeExecuted(JobExecutionContext context) {
String jobName = context.getJobDetail().getKey().toString();
System.out.println("jobToBeExecuted");
System.out.println("Job : " + jobName + " is going to start...");
}
// No idea when will run this?
@Override
public void jobExecutionVetoed(JobExecutionContext context) {
System.out.println("jobExecutionVetoed");
}
//Run this after job has been executed
@Override
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException) {
System.out.println("jobWasExecuted");
String jobName = context.getJobDetail().getKey().toString();
System.out.println("Job : " + jobName + " is finished...");
if (!jobException.getMessage().equals("")) {
System.out.println("Exception thrown by: " + jobName
+ " Exception: " + jobException.getMessage());
}
}
}
Note
No idea what is “jobExecutionVetoed” and when will it triggered? Do comment if you know this, thanks. ## 3.克朗触发器
示例将上述HelloJobListener
附加到调度程序,并监控作业的状态。
文件:CronTriggerExample.java
package com.mkyong.quartz;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.KeyMatcher;
import com.mkyong.quartz.listener.HelloJobListener;
public class CronTriggerExample {
public static void main( String[] args ) throws Exception
{
JobKey jobKey = new JobKey("dummyJobName", "group1");
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity(jobKey).build();
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
//Listener attached to jobKey
scheduler.getListenerManager().addJobListener(
new HelloJobListener(), KeyMatcher.keyEquals(jobKey)
);
//Listener attached to group named "group 1" only.
//scheduler.getListenerManager().addJobListener(
// new HelloJobListener(), GroupMatcher.jobGroupEquals("group1")
//);
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
运行CronTriggerExample.java
,这里是输出。
jobToBeExecuted
Job : group1.dummyJobName is going to start...
Hello Quartz! 123
jobWasExecuted
Job : group1.dummyJobName is started and finished...
Exception thrown by: group1.dummyJobName Exception: Testing Exception
jobToBeExecuted
Job : group1.dummyJobName is going to start...
Hello Quartz! 123
jobWasExecuted
Job : group1.dummyJobName is started and finished...
Exception thrown by: group1.dummyJobName Exception: Testing Exception
下载源代码
Download it – Quartz2-JobListener-Example.zip (13 KB)
参考
quartz:org . quartz . scheduler config 异常:线程计数必须大于 0
使用 Quartz 2,当运行项目时,遇到以下错误信息?
org.quartz.SchedulerConfigException: Thread count must be > 0
at org.quartz.simpl.SimpleThreadPool.initialize(SimpleThreadPool.java:245)
at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1255)
at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1484)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
解决办法
您已经定义了一个“quartz.properties”文件,并覆盖了默认 quartz 的线程计数值。
要修复它,您可以:
- 删除你的“quartz.properties”,通常这个文件只在高级配置时需要。通常,简单的项目不需要这个。
- 正确定义了一个
org.quartz.threadPool.threadCount
值。
文件:quartz . properties–工作样品。
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
参考
quartz (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190222093208/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
Quartz 1.6 调度器教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/quartz-scheduler-example/
Quartz 是一个强大的高级调度框架,帮助 Java 开发者调度一个任务在指定的日期和时间运行。
本教程向您展示了如何使用 Quartz 1.6.3 开发一个调度作业。
Note
This example is a bit outdate, unless you are still using the old Quartz 1.6.3 library, otherwise, you may interest of this latest Quartz 2.1.5 example.
1.下载 Quartz
可以从官网或者 Maven 中央知识库获取石英库
文件:pom.xml
<dependencies>
<!-- Quartz API -->
<dependency>
<groupId>opensymphony</groupId>
<artifactId>quartz</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.directory.studio</groupId>
<artifactId>org.apache.commons.logging</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
2.石英工作
Quartz 作业定义了你要运行什么?
文件:HelloJob
package com.mkyong.common;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job
{
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello Quartz!");
}
}
3.石英触发器
石英触发器定义了石英什么时候会运行你上面的石英的工作?
有两种类型的石英触发器:
- simple trigger–允许设置开始时间、结束时间和重复间隔。
- CronTrigger 允许 Unix cron 表达式指定运行作业的日期和时间。
Unix cron expression
The Unix cron expression is highly flexible and powerful, you can learn and see many cron expression examples in following websites.
- http://en . Wikipedia . org/wiki/cron _ expression
- http://www.quartz-scheduler.org/docs/examples/Example3.html
simple trigger–每 30 秒运行一次。
SimpleTrigger trigger = new SimpleTrigger();
trigger.setName("dummyTriggerName");
trigger.setStartTime(new Date(System.currentTimeMillis() + 1000));
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
trigger.setRepeatInterval(30000);
cron trigger–每 30 秒运行一次。
CronTrigger trigger = new CronTrigger();
trigger.setName("dummyTriggerName");
trigger.setCronExpression("0/30 * * * * ?");
4.调度程序
调度器类将“作业和“触发器链接在一起并执行。
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
5.完整示例
下面是通过 SimpleTrigger 和 CronTrigger 使用 Quartz 的两个完整示例。
SimpleTrigger 示例
第一次执行时延时 1 秒运行 30 秒。
package com.mkyong.common;
import java.util.Date;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
public class SimpleTriggerExample
{
public static void main( String[] args ) throws Exception
{
JobDetail job = new JobDetail();
job.setName("dummyJobName");
job.setJobClass(HelloJob.class);
//configure the scheduler time
SimpleTrigger trigger = new SimpleTrigger();
trigger.setStartTime(new Date(System.currentTimeMillis() + 1000));
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
trigger.setRepeatInterval(30000);
//schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
CronTrigger 示例
相同,每 30 秒运行一次作业。
package com.mkyong.common;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.impl.StdSchedulerFactory;
public class CronTriggerExample
{
public static void main( String[] args ) throws Exception
{
JobDetail job = new JobDetail();
job.setName("dummyJobName");
job.setJobClass(HelloJob.class);
CronTrigger trigger = new CronTrigger();
trigger.setName("dummyTriggerName");
trigger.setCronExpression("0/30 * * * * ?");
//schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
下载源代码
Download it – QuartzExample.zip (14kb)
参考
Quartz 调度程序教程
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/tutorials/quartz-scheduler-tutorial/
Quartz 是一个开源任务调度框架,它允许你调度一个任务在预定的日期和时间运行。快乐学习石英🙂
1.快速启动
欢迎来到 Quartz 调度程序框架。
- Quartz 1.6 hello world example
旧的和流行的 Quartz 1.6.3,遗留系统可能还在使用这个。 - Quartz 2 hello world 示例
最新 Quartz 2.1.5 示例,很多 API 都变了。 - Quartz 2 JobListener 示例
创建一个监听器类并跟踪正在运行的作业状态。 - Quartz 中的多个作业
在 Quartz 中声明并运行多个作业。 - 列出 Quartz 中的所有工作
列出 Quartz 中现有的所有工作。 - 手动触发一个 Quartz 作业
JSF2 示例,显示所有作业,手动触发一个指定的作业。
2.综合
一些常见的 Quartz 与其他框架的集成。
- Spring 3 + Quartz 1.8 调度器示例
Spring 3 不支持 Quartz 2,但是你仍然可以使用 Quartz 1.x - JSF 2 +石英 2 调度器示例
使用QuartzInitializerListener
集成 JSF,实际上你可以使用这个类集成几乎任何 Java web 框架。 - Struts 2 + Quartz 2 调度器示例
将 Quartz 2 与 Struts 2 直接集成。 - Struts 2 + Spring 3 + Quartz 1.8 调度器示例
通过最新的 Spring 3 将 Quartz 1.8 与 Struts 2 集成。 - Struts 2+Spring 2.5.6+Quartz 1.6 调度器示例
通过 Spring 2 . 5 . 6 集成 Quartz 2 和 Struts 1.6。 - Struts 1 + Quartz 2 调度器示例
将 Quartz 2 与 Struts 1.x 直接集成。 - Struts 1+Spring 2 . 5 . 6+Quartz 1.6 调度器示例
通过 Spring 2 集成 Quartz 1.6 和 Struts 1.x..5.6,很多老系统常见的组合。
3.常见错误
- 不兼容 class change 错误:JobDetailBean 将接口 org.quartz.JobDetail 作为超类
- Java . lang . classnotfoundexception:org . spring framework . transaction . transaction exception
- Quartz:org . Quartz . scheduler config exception:线程数必须为> 0
参考
Tags : quartz scheduler tutorials
Maven + Spring hello world 示例
这个快速指南示例使用 Maven 生成一个简单的 Java 项目结构,并演示了如何检索 Spring bean 和打印“hello world”字符串。
本文中使用的技术:
- 弹簧 2.5.6
- Maven 3.0.3
- Eclipse 3.6
- 1.6.0.13 JDK
Spring 3 example
For Spring 3, refer to this Maven + Spring 3 hello world example.
1.用 Maven 生成项目结构
在命令提示符下,发出以下 Maven 命令:
mvn archetype:generate -DgroupId=com.mkyong.common -DartifactId=SpringExamples
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Maven 将为您生成所有 Java 的标准文件夹结构(除了 resources 文件夹,您需要手动创建它)
2.转换为 Eclipse 项目
键入" mvn eclipse:eclipse "将新生成的 Maven 样式项目转换为 eclipse 的样式项目。
mvn eclipse:eclipse
稍后,将转换后的项目导入 Eclipse IDE。
Create a resources folder
Create a resources “/src/main/resources” folder, the Spring’s bean xml configuration file will put here later. Maven will treat all files under this “resources” folder as resources files, and copy it to output classes automatically.
3.添加弹簧依赖项
在 Maven 的 pom.xml 文件中添加 Spring 依赖。
文件:pom.xml
<project
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.mkyong.common</groupId>
<artifactId>SpringExamples</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringExamples</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
</dependencies>
</project>
问题" mvn eclipse:eclipse "同样,Maven 将自动下载 Spring 依赖库,并将其放入 Maven 的本地存储库中。同时,Maven 会将下载的库添加到 Eclipse 的中。用于依赖目的的类路径。
4.Spring bean (Java 类)
在“src/main/Java/com/mkyong/common/hello world . Java”下创建一个普通的 Java 类(HelloWorld.java)。Spring 的 bean 只是一个普通的 Java 类,稍后在 Spring bean 配置文件中声明。
package com.mkyong.common;
/**
* Spring bean
*
*/
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public void printHello() {
System.out.println("Hello ! " + name);
}
}
5.Spring bean 配置文件
在"src/main/resources/Spring-module . xml"处创建一个 XML 文件(Spring-Module.xml)。这是 Spring 的 bean 配置文件,它声明了所有可用的 Spring beans。
文件:Spring-Module.xml
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="helloBean" class="com.mkyong.common.HelloWorld">
<property name="name" value="Mkyong" />
</bean>
</beans>
6.检查项目结构
检查并确保文件夹结构如下
7.运行它
运行App.java
,加载 Spring bean 配置文件( Spring-Module.xml ,通过getBean()
方法检索 Spring bean。
文件:App.java
package com.mkyong.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"Spring-Module.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloBean");
obj.printHello();
}
}
8.输出
Hello ! Mkyong
下载源代码
Download it – Spring-hello-world-example.zip (7KB)Tags : hello world maven spring
记住序数参数是从 1 开始的!–休眠模板
问题
休眠模板代码…
getHibernateTemplate().find("from Domain d
where d.domainName = :domainName", domainName);
当我执行上面的代码时,我遇到了下面的错误消息
java.lang.IndexOutOfBoundsException: Remember that ordinal parameters are 1-based!
...
at org.hibernate.impl.AbstractQueryImpl.determineType(AbstractQueryImpl.java:397)
at org.hibernate.impl.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:369)
解决办法
我进去研究了 HibernateTemplate.java 的文件,发现了下面的代码
public List find(final String queryString, final Object[] values) throws DataAccessException {
return (List) executeWithNativeSession(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(queryString);
prepareQuery(queryObject);
if (values != null) {
for (int i = 0; i < values.length; i++) {
queryObject.setParameter(i, values[i]);
}
}
return queryObject.list();
}
});
}
从上面的代码来看,HibernateTemplete 使用的是基于 0 的,而不是基于 1 的。这是 spring 还是 hibernate 库的问题?因为错误消息指出参数需要从 1 开始。我尝试了一些解决方案,如改变 spring 或 hibernate 库,但是不起作用...
看起来我在一个错误的方向上,我不得不从头开始寻找解决方案,首先我研究我自己的代码............!!!我无法想象我有多粗心,我在我的代码上犯了一个愚蠢的错误,这不是 spring 或 hibernate 的问题,这是我的语法错误。
从...改变
getHibernateTemplate().find("
from Domain d where d.domainName = :domainName", domainName);
到
getHibernateTemplate().find("
from Domain d where d.domainName = ?", domainName);
问题解决了,代码执行没有错误了。
Note
The error message generated by HibernateTemplate is really misleading !! (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190310093441/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
JSF 2.0 中的资源(图书馆)
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jsf2/resources-library-in-jsf-2-0/
在 JSF 2.0 中,你所有的网络资源文件,如 css、图片或 JavaScript,都应该放在你的网络应用程序根目录下的“ resources 文件夹中(与“WEB-INF
”在同一文件夹级别)。
“资源”文件夹下的子文件夹被认为是“库或者“项目主题”,以后你可以引用那些带有library
属性的“资源”。这个新的 JSF 资源管理机制非常有用,它允许开发者通过“主题/库”或“版本控制”来轻松地改变网络资源。
参见以下示例:
图 1-0:一个 JSF2 项目文件夹结构的例子。
1.正常示例
下面是一些在 JSF 2.0 中使用“资源和“库的例子。
-
Include CSS file –
h:outputStylesheet
<h:outputStylesheet library="theme1" name="css/style.css" />
HTML 输出…
<link type="text/css" rel="stylesheet" href="/JavaServerFaces/faces/javax.faces.resource/css/style.css?ln=theme1" />
-
Display images –
h:graphicImage
<h:graphicImage library="theme1" name="img/sofa.png" />
HTML 输出…
<img src="/JavaServerFaces/faces/javax.faces.resource/img/sofa.png?ln=theme1" />
-
Include JavaScript –
h:outputScript
<h:outputScript library="theme1" name="js/hello.js" />
HTML 输出…
<script type="text/javascript" src="/JavaServerFaces/faces/javax.faces.resource/js/hello.js?ln=theme1">
2.版本控制示例
参照图 1-0 ,在“库文件夹下创建一个与 regex \d+(_\d+)*
匹配的“版本文件夹,默认的 JSF [ResourceHandler](http://web.archive.org/web/20221024080629/https://docs.oracle.com/javaee/6/api/javax/faces/application/ResourceHandler.html)
会一直得到最高版本显示。
P.S 假设你的项目是图 1-0 结构
包含 CSS 文件-h:outputStylesheet
<h:outputStylesheet library="default" name="css/style.css" />
由于“默认”主题包含版本“ 1_0 ”和“ 2_0 ”,JSF 总是会从最高版本获取资源,并将版本追加到资源的末尾。
查看 HTML 输出:
<link type="text/css" rel="stylesheet"
href="/JavaServerFaces/faces/javax.faces.resource/css/style.css?ln=default&v=2_0" />
Version is optional
The version folder is optional, if you don’t have versioning, just omit it, like “newTheme” in Figure 1-0.
谢谢
感谢 BalusC 对的评论、指导和纠正,并为我之前误导的指导道歉。
参考资料
- What is JSF resource pool used for and how should it be used?
- JSF 资源处理器 JavaDoc
- [ JSF 2.0 New Function Preview Series (Part 2.1): Resource
带有 Apache HttpClient 的 RESTful Java 客户端
Apache HttpClient 是一个健壮且完整的解决方案 Java 库,用于执行 HTTP 操作,包括 RESTful 服务。在本教程中,我们将向您展示如何使用 Apache HttpClient 创建一个 RESTful Java 客户端,来执行一个“ GET 和“ POST 请求。
Note
The RESTful services from last “Jackson + JAX-RS” article will be reused.
1.获取 Apache HttpClient
Apache HttpClient 在 Maven 中央存储库中可用,只需在 Maven pom.xml
文件中声明它。
文件:pom.xml
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.1</version>
</dependency>
2.获取请求
再次回顾上次休息服务。
@Path("/json/product")
public class JSONService {
@GET
@Path("/get")
@Produces("application/json")
public Product getProductInJSON() {
Product product = new Product();
product.setName("iPad 3");
product.setQty(999);
return product;
}
//...
Apache HttpClient 发送一个“GET”请求。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
public class ApacheHttpClientGet {
public static void main(String[] args) {
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(
"http://localhost:8080/RESTfulExample/json/product/get");
getRequest.addHeader("accept", "application/json");
HttpResponse response = httpClient.execute(getRequest);
if (response.getStatusLine().getStatusCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
httpClient.getConnectionManager().shutdown();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出…
Output from Server ....
{"qty":999,"name":"iPad 3"}
3.发布请求
也回顾最后一次休息服务。
@Path("/json/product")
public class JSONService {
@POST
@Path("/post")
@Consumes("application/json")
public Response createProductInJSON(Product product) {
String result = "Product created : " + product;
return Response.status(201).entity(result).build();
}
//...
Apache HttpClient 发送一个“POST”请求。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
public class ApacheHttpClientPost {
public static void main(String[] args) {
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(
"http://localhost:8080/RESTfulExample/json/product/post");
StringEntity input = new StringEntity("{\"qty\":100,\"name\":\"iPad 4\"}");
input.setContentType("application/json");
postRequest.setEntity(input);
HttpResponse response = httpClient.execute(postRequest);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
httpClient.getConnectionManager().shutdown();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出…
Output from Server ....
Product created : Product [name=iPad 4, qty=100]
下载源代码
Download it – RESTful-Java-Client-ApacheHttpClient-Example.zip (9 KB)
参考
带有 Jersey 客户端的 RESTful Java 客户端
本教程向您展示了如何使用 Jersey 客户端 API来创建一个 RESTful Java 客户端,以执行在这个“ Jersey + Json ”示例中创建的“ GET ”和“POST”REST 服务请求。
1.Jersey 客户端依赖性
为了使用 Jersey 客户端 API,在您的pom.xml
文件中声明“ jersey-client.jar ”。
文件:pom.xml
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.8</version>
</dependency>
2.获取请求
回顾上次休息服务。
@Path("/json/metallica")
public class JSONService {
@GET
@Path("/get")
@Produces(MediaType.APPLICATION_JSON)
public Track getTrackInJSON() {
Track track = new Track();
track.setTitle("Enter Sandman");
track.setSinger("Metallica");
return track;
}
//...
Jersey 客户端发送一个“GET”请求并打印出返回的 json 数据。
package com.mkyong.client;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
public class JerseyClientGet {
public static void main(String[] args) {
try {
Client client = Client.create();
WebResource webResource = client
.resource("http://localhost:8080/RESTfulExample/rest/json/metallica/get");
ClientResponse response = webResource.accept("application/json")
.get(ClientResponse.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
String output = response.getEntity(String.class);
System.out.println("Output from Server .... \n");
System.out.println(output);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出…
Output from Server ....
{"singer":"Metallica","title":"Enter Sandman"}
3.发布请求
回顾上次休息服务。
@Path("/json/metallica")
public class JSONService {
@POST
@Path("/post")
@Consumes(MediaType.APPLICATION_JSON)
public Response createTrackInJSON(Track track) {
String result = "Track saved : " + track;
return Response.status(201).entity(result).build();
}
//...
Jersey 客户端发送一个带有 json 数据的“POST”请求,并打印出返回的输出。
package com.mkyong.client;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
public class JerseyClientPost {
public static void main(String[] args) {
try {
Client client = Client.create();
WebResource webResource = client
.resource("http://localhost:8080/RESTfulExample/rest/json/metallica/post");
String input = "{\"singer\":\"Metallica\",\"title\":\"Fade To Black\"}";
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class, input);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出…
Output from Server ....
Track saved : Track [title=Fade To Black, singer=Metallica]
下载源代码
Download it – Jersey-Client-Example.zip (8 KB)
参考
- 有球衣+杰克逊的 JSON 例子
- 新泽西客户端示例
- 采用 RESTEasy 客户端框架的 RESTful Java 客户端
- 使用 java.net.URL 的 RESTful Java 客户端
- 带 Apache HttpClient 的 RESTful Java 客户端
带有 RESTEasy 客户端框架的 RESTful Java 客户端
本教程向您展示了如何使用 RESTEasy 客户端框架创建一个 RESTful Java 客户端,来执行在上一个教程中创建的“ GET ”和“POST”REST 服务请求。
1.RESTEasy 客户端框架
RESTEasy 客户端框架包含在 RESTEasy 核心模块中,所以,你只需要在你的pom.xml
文件中声明“ resteasy-jaxrs.jar ”。
文件:pom.xml
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>2.2.1.GA</version>
</dependency>
2.获取请求
回顾上次休息服务。
@Path("/json/product")
public class JSONService {
@GET
@Path("/get")
@Produces("application/json")
public Product getProductInJSON() {
Product product = new Product();
product.setName("iPad 3");
product.setQty(999);
return product;
}
//...
RESTEasy 客户端发送一个“GET”请求。
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.http.client.ClientProtocolException;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ClientResponse;
public class RESTEasyClientGet {
public static void main(String[] args) {
try {
ClientRequest request = new ClientRequest(
"http://localhost:8080/RESTfulExample/json/product/get");
request.accept("application/json");
ClientResponse<String> response = request.get(String.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(response.getEntity().getBytes())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出…
Output from Server ....
{"qty":999,"name":"iPad 3"}
3.发布请求
也回顾最后一次休息服务。
@Path("/json/product")
public class JSONService {
@POST
@Path("/post")
@Consumes("application/json")
public Response createProductInJSON(Product product) {
String result = "Product created : " + product;
return Response.status(201).entity(result).build();
}
//...
RESTEasy 客户端发送一个“POST”请求。
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ClientResponse;
public class RESTEasyClientPost {
public static void main(String[] args) {
try {
ClientRequest request = new ClientRequest(
"http://localhost:8080/RESTfulExample/json/product/post");
request.accept("application/json");
String input = "{\"qty\":100,\"name\":\"iPad 4\"}";
request.body("application/json", input);
ClientResponse<String> response = request.post(String.class);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(response.getEntity().getBytes())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出…
Output from Server ....
Product created : Product [name=iPad 4, qty=100]
下载源代码
Download it – RESTful-Java-Client-RESTEasyt-Example.zip (9 KB)
参考
client jax-rs resteasy restful
使用 CommandLineJobRunner 运行春季批处理作业
向您展示如何使用CommandLineJobRunner
运行 Spring 批处理作业的快速指南。
1.春季批处理作业示例
一份简单的工作。
resources/spring/batch/jobs/job-read-files.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans ...
<import resource="../config/context.xml"/>
<job id="readJob" >
<step id="step1">
<tasklet>
<chunk reader="flatFileItemReader"
writer="flatFileItemWriter" commit-interval="1" />
</tasklet>
</step>
</job>
<!-- ... -->
</beans>
2.包项目
使用 Maven 将您的项目打包成一个 jar 文件-target/your-project . jar,并将所有依赖项复制到 target/dependency-jars/ 。
pom.xml
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/dependency-jars/
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
$ mvn package
3.CommandLineJobRunner 示例
用法:
CommandLineJobRunner jobPath <options> jobIdentifier (jobParameters)
要运行以上 spring 批处理作业,请键入以下命令:
$ java -cp "target/dependency-jars/*:target/your-project.jar" org.springframework.batch.core.launch.support.CommandLineJobRunner spring/batch/jobs/job-read-files.xml readJob
对于jobParameters
,附加到命令的末尾:
$ java -cp "target/dependency-jars/*:target/your-project.jar" org.springframework.batch.core.launch.support.CommandLineJobRunner spring/batch/jobs/job-read-files.xml readJob file.name=testing.cvs
要按计划运行它,通常可以将上述命令复制到一个.sh
文件中,并使用任何调度程序命令运行它,比如*nix 中的cron
。参考这个例子——在 Linux 下给 cron 添加作业。
当批处理作业在系统调度程序下运行时,确保它可以找到你的项目的类路径。
下载源代码
Download it – SpringBatch-Run-Example.zip(12 KB)
参考
在 jquery 中选择多个元素
在 jQuery 中,可以选择多个元素,用逗号“,”符号分隔。
举个例子,
$(.class1, .class2, #id1)
在上面的例子中,选择类名为“class1”和“class2”,id 为“id1”的所有元素。
jQuery 示例
在本例中,类名为“ p1 ”和“ p2 ”、id 为“ div3 ”的元素将被动态添加红色边框。
<html>
<head>
<title>Select mutiple elements example</title>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
$(".p1, .p3, #div3").css("border", "2px solid red");
});
</script>
<body>
<h1>Select mutiple elements example</h1>
<p class="p1">P1</p>
<p class="p2">P2</p>
<p class="p3">P3</p>
<p class="p4">P4</p>
<div id="div1">DIV1</div>
<div id="div2">DI2</div>
<div id="div3">DI2</div>
<div id="div4">DI2</div>
</body>
</html>
Try Demojquery jquery selector (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!'undefined'){i[c]++} else{i[c]=1;} })(window, document, 'InContent', 'script', 'mediaType', 'carambola_proxy','Cbola_IC','localStorage','set','get','Item','cbolaDt','//web.archive.org/web/20190310100517/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0')
弹簧 3 和 JSR-330 @注入和@命名示例
从 Spring 3.0 开始,Spring 支持标准的JSR 330:Java 的依赖注入。在 Spring 3 应用程序中,您可以使用标准
@Inject
代替春天的@Autowired
来注射一颗豆子。@Named
代替春天的@Component
来宣告一颗豆子。
这些 JSR-330 标准注释的扫描和检索方式与 Spring 注释相同,集成是自动进行的,只要您的类路径中有以下 jar。
pom.xml
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
1.弹簧注释
让我们看一个普通弹簧的注释例子—@Autowired
和@Component
PS@Component
、@Repository
和@Service
相同,只是在 Spring Ioc 上下文中声明了一个 bean。
CustomerDAO.java
package com.mkyong.customer.dao;
import org.springframework.stereotype.Repository;
@Repository
public class CustomerDAO
{
public void save() {
System.out.println("CustomerDAO save method...");
}
}
CustomerService.java
package com.mkyong.customer.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mkyong.customer.dao.CustomerDAO;
@Service
public class CustomerService
{
@Autowired
CustomerDAO customerDAO;
public void save() {
System.out.println("CustomerService save method...");
customerDAO.save();
}
}
2.JSR-330 注解
基本上,它的工作原理是一样的,只是有不同的注释——@Inject
和@Named
。
CustomerDAO.java
package com.mkyong.customer.dao;
import javax.inject.Named;
@Named
public class CustomerDAO
{
public void save() {
System.out.println("CustomerDAO save method...");
}
}
CustomerService.java
package com.mkyong.customer.services;
import javax.inject.Inject;
import javax.inject.Named;
import com.mkyong.customer.dao.CustomerDAO;
@Named
public class CustomerService
{
@Inject
CustomerDAO customerDAO;
public void save() {
System.out.println("CustomerService save method...");
customerDAO.save();
}
}
3.运行它
Spring 和 JSR330 注释都需要组件扫描才能工作。
Spring-AutoScan.xml – Scan bean automatically
<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-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="com.mkyong.customer" />
</beans>
App.java – Run it
package com.mkyong;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mkyong.customer.services.CustomerService;
public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"Spring-AutoScan.xml"});
CustomerService cust = (CustomerService)context.getBean("customerService");
cust.save();
}
}
以上两个例子都生成了相同的输出
CustomerService save method...
CustomerDAO save method...
4.JSR-330 的局限性
与 Spring 相比,JSR-330 有一些局限性:
@Inject
没有确保 bean 成功注入所需的属性。
*** 在 Spring 容器中,JSR-330 默认有作用域 singleton,但是你可以使用 Spring 的@Scope
来定义其他。* 不等同于春天的@Value
、@Required
或@Lazy
。**
**检查这个弹簧参考。
5.去 JSR-330
其实 Spring 的注释更强大,只是在 Spring framework 上才有。JSR-330 是一个标准规范,遵循 JSR-330 规范的所有 J2ee 环境都支持它。
对于新项目或迁移项目,总是推荐使用 JSR-330 注释,并且记住,它也适用于 Spring 3。
下载源代码
Download it – Spring-JSR330-Example.zip (27kb)
参考
- 弹簧参考:使用 JSR 330 标准注释
- for Java 的依赖注入
**
Spring 3 JavaConfig 示例
原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/spring3/spring-3-javaconfig-example/
由于 Spring 3, JavaConfig 特性包含在核心 Spring 模块中,它允许开发人员将 bean 定义和 Spring 配置从 XML 文件移到 Java 类中。
但是,您仍然可以使用经典的 XML 方式来定义 beans 和配置, JavaConfig 只是另一种替代解决方案。
查看经典 XML 定义和 JavaConfig 之间的区别,在 Spring 容器中定义 bean。
Spring XML 文件:
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloBean" class="com.mkyong.hello.impl.HelloWorldImpl">
</beans>
Java config 中的等效配置:
package com.mkyong.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.mkyong.hello.HelloWorld;
import com.mkyong.hello.impl.HelloWorldImpl;
@Configuration
public class AppConfig {
@Bean(name="helloBean")
public HelloWorld helloWorld() {
return new HelloWorldImpl();
}
}
Spring JavaConfig Hello World
现在,请看一个完整的 Spring JavaConfig 示例。
1.目录结构
请参见本示例的目录结构。
## 2.依赖库
要使用 Java config(@ Configuration),需要包含 CGLIB 库。查看依赖关系:
<!-- Spring 3 dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- JavaConfig need this library -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
3.春豆
一颗简单的豆子。
package com.mkyong.hello;
public interface HelloWorld {
void printHelloWorld(String msg);
}
package com.mkyong.hello.impl;
import com.mkyong.hello.HelloWorld;
public class HelloWorldImpl implements HelloWorld {
@Override
public void printHelloWorld(String msg) {
System.out.println("Hello : " + msg);
}
}
4.JavaConfig 注释
用@Configuration
注释告诉 Spring 这是核心的 Spring 配置文件,并通过@Bean
定义 bean。
package com.mkyong.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.mkyong.hello.HelloWorld;
import com.mkyong.hello.impl.HelloWorldImpl;
@Configuration
public class AppConfig {
@Bean(name="helloBean")
public HelloWorld helloWorld() {
return new HelloWorldImpl();
}
}
5.运行它
用AnnotationConfigApplicationContext
加载您的 JavaConfig 类。
package com.mkyong.core;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.mkyong.config.AppConfig;
import com.mkyong.hello.HelloWorld;
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HelloWorld obj = (HelloWorld) context.getBean("helloBean");
obj.printHelloWorld("Spring3 Java Config");
}
}
输出
Hello : Spring3 Java Config
下载源代码
Download It – Spring3-JavaConfig-Example.zip (6 KB)