原文:Mkyong
如何在 Java 中复制目录
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-copy-directory-in-java/
在 Java 中,我们可以使用 Java 1.7 FileVisitor
或 Apache Commons IO FileUtils.copyDirectory
来复制一个目录,其中包括它的子目录和文件。
本文展示了用 Java 复制目录的几种常用方法。
FileVisitor
(Java 7+)FileUtils.copyDirectory
(Apache common-io)- 使用 Java 7 NIO 和 Java 8 Stream 进行自定义复制。
- 自定义副本,传统 IO。
注意NIOFiles.copy
不支持复制目录内容,我们需要创建一个定制的方法来复制目录内容。
1.FileVisitor (Java 7)
这个例子展示了如何使用 FileVisitor 将目录及其内容从/home/mkyong/test/
复制到/home/mkyong/test2/
。
Terminal
$ tree /home/mkyong/test
test
├── test-a1.log
├── test-a2.log
└── test-b
├── test-b1.txt
├── test-b2.txt
├── test-c
│ ├── test-c1.log
│ └── test-c2.log
└── test-d
├── test-d1.log
└── test-d2.log
1.1 这个类扩展了SimpleFileVisitor
来提供默认值,并且只覆盖必要的方法。
TreeCopyFileVisitor.java
package com.mkyong.io.utils;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class TreeCopyFileVisitor extends SimpleFileVisitor<Path> {
private Path source;
private final Path target;
public TreeCopyFileVisitor(String source, String target) {
this.source = Paths.get(source);
this.target = Paths.get(target);
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
Path resolve = target.resolve(source.relativize(dir));
if (Files.notExists(resolve)) {
Files.createDirectories(resolve);
System.out.println("Create directories : " + resolve);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Path resolve = target.resolve(source.relativize(file));
Files.copy(file, resolve, StandardCopyOption.REPLACE_EXISTING);
System.out.println(
String.format("Copy File from \t'%s' to \t'%s'", file, resolve)
);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
System.err.format("Unable to copy: %s: %s%n", file, exc);
return FileVisitResult.CONTINUE;
}
}
1.2 这个例子使用Files.walkFileTree
遍历文件树。
CopyDirectory1.java
package com.mkyong.io.howto;
import com.mkyong.io.utils.TreeCopyFileVisitor;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CopyDirectory1 {
public static void main(String[] args) {
String fromDirectory = "/home/mkyong/test/";
String toToDirectory = "/home/mkyong/test2/";
try {
copyDirectoryFileVisitor(fromDirectory, toToDirectory);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Done");
}
public static void copyDirectoryFileVisitor(String source, String target)
throws IOException {
TreeCopyFileVisitor fileVisitor = new TreeCopyFileVisitor(source, target);
Files.walkFileTree(Paths.get(source), fileVisitor);
}
}
输出
Terminal
Create directories : /home/mkyong/test2
Copy File from '/home/mkyong/test/test-a2.log' to '/home/mkyong/test2/test-a2.log'
Copy File from '/home/mkyong/test/test-a1.log' to '/home/mkyong/test2/test-a1.log'
Create directories : /home/mkyong/test2/test-b
Copy File from '/home/mkyong/test/test-b/test-b1.txt' to '/home/mkyong/test2/test-b/test-b1.txt'
Create directories : /home/mkyong/test2/test-b/test-c
Copy File from '/home/mkyong/test/test-b/test-c/test-c2.log' to '/home/mkyong/test2/test-b/test-c/test-c2.log'
Copy File from '/home/mkyong/test/test-b/test-c/test-c1.log' to '/home/mkyong/test2/test-b/test-c/test-c1.log'
Copy File from '/home/mkyong/test/test-b/test-b2.txt' to '/home/mkyong/test2/test-b/test-b2.txt'
Create directories : /home/mkyong/test2/test-b/test-d
Copy File from '/home/mkyong/test/test-b/test-d/test-d2.log' to '/home/mkyong/test2/test-b/test-d/test-d2.log'
Copy File from '/home/mkyong/test/test-b/test-d/test-d1.log' to '/home/mkyong/test2/test-b/test-d/test-d1.log'
Done
检查新目录。
Terminal
$ tree /home/mkyong/test2
test2
├── test-a1.log
├── test-a2.log
└── test-b
├── test-b1.txt
├── test-b2.txt
├── test-c
│ ├── test-c1.log
│ └── test-c2.log
└── test-d
├── test-d1.log
└── test-d2.log
注意
官方 Java 复制示例复制一切,包括文件属性。然而,它更难阅读;此示例将方法简化为仅复制文件和目录,并排除属性。
2.fileutils . copy directory(Apache commons-io)
这个例子使用了FileUtils.copyDirectory
来复制一个目录及其内容,这是一个友好而简单的 API。
pom.xml
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
import org.apache.commons.io.FileUtils;
//...
public static void copyFileCommonIO(String from, String to)
throws IOException {
File fromDir = new File(from);
File toDir = new File(to);
FileUtils.copyDirectory(fromDir, toDir);
}
3.Java NIO 和 Stream。
这个例子使用 Java 8 Files.list
来模拟文件遍历器,使用 Java 7 NIO Files
来检查、创建和复制目录及其内容。
CopyDirectory3.java
package com.mkyong.io.howto;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;
public class CopyDirectory3 {
public static void main(String[] args) {
String fromDirectory = "/home/mkyong/test/";
String toToDirectory = "/home/mkyong/test2/";
try {
copyDirectoryJavaNIO(Paths.get(fromDirectory),
Paths.get(toToDirectory));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Done");
}
public static void copyDirectoryJavaNIO(Path source, Path target)
throws IOException {
// is this a directory?
if (Files.isDirectory(source)) {
//if target directory exist?
if (Files.notExists(target)) {
// create it
Files.createDirectories(target);
System.out.println("Directory created : " + target);
}
// list all files or folders from the source, Java 1.8, returns a stream
// doc said need try-with-resources, auto-close stream
try (Stream<Path> paths = Files.list(source)) {
// recursive loop
paths.forEach(p ->
copyDirectoryJavaNIOWrapper(
p, target.resolve(source.relativize(p)))
);
}
} else {
// if file exists, replace it
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
System.out.println(
String.format("Copy File from \t'%s' to \t'%s'", source, target)
);
}
}
// extract method to handle exception in lambda
public static void copyDirectoryJavaNIOWrapper(Path source, Path target) {
try {
copyDirectoryJavaNIO(source, target);
} catch (IOException e) {
System.err.println("IO errors : " + e.getMessage());
}
}
}
4.传统 IO
这个例子类似于方法 3。相反,它坚持使用传统的 IO java.io.*
,仅供参考。
CopyDirectory4.java
package com.mkyong.io.howto;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;
public class CopyDirectory4 {
public static void main(String[] args) {
String fromDirectory = "/home/mkyong/test/";
String toToDirectory = "/home/mkyong/test2/";
try {
copyDirectoryLegacyIO(
new File(fromDirectory),
new File(toToDirectory));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Done");
}
public static void copyDirectoryLegacyIO(File source, File target)
throws IOException {
if (source.isDirectory()) {
//if directory not exists, create it
if (!target.exists()) {
if (target.mkdir()) {
System.out.println("Directory copied from "
+ source + " to " + target);
} else {
System.err.println("Unable to create directory : " + target);
}
}
// list all the directory contents, file walker
String[] files = source.list();
if (files == null) {
return;
}
for (String file : files) {
//construct the src and dest file structure
File srcFile = new File(source, file);
File destFile = new File(target, file);
//recursive copy
copyDirectoryLegacyIO(srcFile, destFile);
}
} else {
//if file, then copy it
//Use bytes stream to support all file types
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(source);
out = new FileOutputStream(target);
byte[] buffer = new byte[1024];
int length;
//copy the file content in bytes
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
System.out.println("File copied from " + source + " to " + target);
} catch (IOException e) {
System.err.println("IO errors : " + e.getMessage());
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
}
注
Java,在 20+年之后,仍然没有官方 API 来复制一个目录,创建一个Files.copyDirectory()
有多难?
下载源代码
$ git 克隆https://github.com/mkyong/core-java
$ cd java-io
参考
- Java 复制示例
- 文件 JavaDoc
- InputStream JavaDoc
- OutputStream JavaDoc
- FileVisitor JavaDoc
- Apache common me
- 如何在 Java 中复制文件
- Java——如何列出一个目录中的所有文件?
如何在 Java 中复制文件
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-copy-file-in-java/
本文展示了用 Java 复制文件的四种方法。
Files.copy
- Apache commons me(Apache 公用程式)
- 番石榴
- 普通爪哇咖啡
在 Java 7+中,NIO Files.copy 是复制文件最简单的方法,因为它是一个内置的 API。在 Java 7 之前,Apache Commons IO FileUtils.copyFile
是一个更好的解决方案,因为遗留 IO java.io.*
没有 API 可以复制。
1.文件.副本(NIO)
1.1 这个代码片段使用 NIO 来复制文件。默认情况下,如果目标文件存在,复制会失败并抛出FileAlreadyExistsException
。
Path fromFile = Paths.get(from);
Path toFile = Paths.get(to);
Files.copy(fromFile, toFile);
1.2Files.copy
接受一个 varargs 参数:
StandardCopyOption.REPLACE_EXISTING
–如果目标文件存在,替换它。StandardCopyOption.COPY_ATTRIBUTES
–将文件属性复制到目标文件。
import java.nio.file.StandardCopyOption;
// if target or destination file exists, replace it.
Files.copy(fromFile, toFile, StandardCopyOption.REPLACE_EXISTING);
// multiple StandardCopyOption
CopyOption[] options = { StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES,
LinkOption.NOFOLLOW_LINKS };
Files.copy(fromFile, toFile, options);
下面 1.3 是一个完整的 Java NIO 复制文件的例子。
CopyFile1.java
package com.mkyong.io.howto;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class CopyFile1 {
public static void main(String[] args) {
String fromFile = "/home/mkyong/dev/db.debug.conf";
String toFile = "/home/mkyong/live/db.conf";
try {
copyFileNIO(fromFile, toFile);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Copy file is done.");
}
public static void copyFileNIO(String from, String to) throws IOException {
Path fromFile = Paths.get(from);
Path toFile = Paths.get(to);
// if fromFile doesn't exist, Files.copy throws NoSuchFileException
if (Files.notExists(fromFile)) {
System.out.println("File doesn't exist? " + fromFile);
return;
}
// if toFile folder doesn't exist, Files.copy throws NoSuchFileException
// if toFile parent folder doesn't exist, create it.
Path parent = toFile.getParent();
if(parent!=null){
if(Files.notExists(parent)){
Files.createDirectories(parent);
}
}
// default - if toFile exist, throws FileAlreadyExistsException
Files.copy(fromFile, toFile);
// if toFile exist, replace it.
// Files.copy(fromFile, toFile, StandardCopyOption.REPLACE_EXISTING);
// multiple StandardCopyOption
/*CopyOption[] options = { StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES,
LinkOption.NOFOLLOW_LINKS };
Files.copy(fromFile, toFile, options);*/
}
}
2.Apache commons me(Apache 公用程式)
在过去(Java 7 之前), commons-io 是用 Java 复制文件的最简单的解决方案。
pom.xml
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
import org.apache.commons.io.FileUtils;
public static void copyFileCommonIO(String from, String to)
throws IOException {
File fromFile = new File(from);
File toFile = new File(to);
FileUtils.copyFile(fromFile, toFile);
}
3.谷歌番石榴
很多项目开始采用的番石榴,而更喜欢番石榴的Files.copy
,与 Java NIO 同名,确保导入正确的包com.google.common.io.Files
。
pom.xml
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
public static void copyFileGuava(String from, String to) throws IOException {
File fromFile = new File(from);
File toFile = new File(to);
// @Beta?
com.google.common.io.Files.copy(fromFile, toFile);
}
番石榴的Files
类从 1.0 版本开始就有了,不知道为什么Files.copy
仍然有一个@Beta
注释在上面?
Files.java
package com.google.common.io;
public final class Files {
//..
@Beta
public static void copy(File from, File to) throws IOException {
checkArgument(!from.equals(to),
"Source %s and destination %s must be different", from, to);
asByteSource(from).copyTo(asByteSink(to));
}
4.普通爪哇咖啡
这个例子使用普通的 Java InputStream
和OutputStream
来复制一个文件。
public static void copyFilePlainJava(String from, String to) throws IOException {
InputStream inStream = null;
OutputStream outStream = null;
try {
File fromFile = new File(from);
File toFile = new File(to);
inStream = new FileInputStream(fromFile);
outStream = new FileOutputStream(toFile);
byte[] buffer = new byte[1024];
int length;
while ((length = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, length);
outStream.flush();
}
} finally {
if (inStream != null)
inStream.close();
if (outStream != null)
outStream.close();
}
}
下载源代码
$ git 克隆https://github.com/mkyong/core-java
$ cd java-io
参考
如何计算 XML 文档的深度(DOM 解析器)
在 DOM 解析器中,我们可以使用子节点的递归循环来查找或计算 XML 文档的深度。
目录
用 Java 11 测试。
注
1。一个 XML 文件
下面的 XML 文件包含 3 个深度级别。
src/main/resources/staff.xml
<?xml version="1.0" encoding="utf-8"?>
<company> <!-- Level 1 -->
<staff id="1001"> <!-- Level 2 -->
<name>mkyong</name> <!-- Level 3 -->
<role>support</role> <!-- Level 3 -->
<salary currency="USD">5000</salary>
<!-- for special characters like < &, need CDATA -->
<bio><![CDATA[HTML tag <code>testing</code>]]></bio>
</staff>
<staff id="1002">
<name>yflow</name>
<role>admin</role>
<salary currency="EUR">8000</salary>
<bio><![CDATA[a & b]]></bio>
</staff>
</company>
2。DOM 解析器+递归循环
下面的例子使用了一个 DOM 解析器和递归循环来查找 XML 级别的深度。
CountDepthXmlDom.java
package com.mkyong.xml.dom;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CountDepthXmlDom {
private static final String FILENAME = "src/main/resources/staff.xml";
private static int DEPTH_XML = 0;
public static void main(String[] args) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try (InputStream is = new FileInputStream(FILENAME)) {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
// get all elements
NodeList childNodes = doc.getChildNodes();
printNode(childNodes, 0);
System.out.println("Depth of XML : " + DEPTH_XML);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
// loop recursive
private static void printNode(NodeList nodeList, int level) {
level++;
if (nodeList != null && nodeList.getLength() > 0) {
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
String result = String.format(
"%" + level * 5 + "s : [%s]%n", node.getNodeName(), level);
System.out.print(result);
printNode(node.getChildNodes(), level);
// how depth is it?
if (level > DEPTH_XML) {
DEPTH_XML = level;
}
}
}
}
}
}
输出
Terminal
company : [1]
staff : [2]
name : [3]
role : [3]
salary : [3]
bio : [3]
staff : [2]
name : [3]
role : [3]
salary : [3]
bio : [3]
Depth of XML : 3
3。DOM 解析器+树遍历器
下面的例子使用 DOM 的TreeWalker
遍历节点并找到 XML 级别的深度。
CountDepthXmlDomTreeWalker.java
package com.mkyong.xml.dom;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CountDepthXmlDomTreeWalker {
private static final String FILENAME = "src/main/resources/staff.xml";
private static int DEPTH_XML = 0;
public static void main(String[] args) {
int depth = countDepthXml(FILENAME);
System.out.println("Depth of XML : " + depth);
}
private static int countDepthXml(String filename) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try (InputStream is = new FileInputStream(filename)) {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
DocumentTraversal traversal = (DocumentTraversal) doc;
// DOM tree walker
TreeWalker walker = traversal.createTreeWalker(
doc.getDocumentElement(),
NodeFilter.SHOW_ELEMENT,
null,
true);
traverseXmlElements(walker, 0);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
return DEPTH_XML;
}
private static void traverseXmlElements(TreeWalker walker, int level) {
level++;
Node node = walker.getCurrentNode();
String result = String.format(
"%" + level * 5 + "s : [%s]%n", node.getNodeName(), level);
System.out.print(result);
for (Node n = walker.firstChild();
n != null;
n = walker.nextSibling()) {
traverseXmlElements(walker, level);
}
walker.setCurrentNode(node);
// how depth is it?
if (level > DEPTH_XML) {
DEPTH_XML = level;
}
}
}
输出
Terminal
company : [1]
staff : [2]
name : [3]
role : [3]
salary : [3]
bio : [3]
staff : [2]
name : [3]
role : [3]
salary : [3]
bio : [3]
Depth of XML : 3
4。下载源代码
$ git 克隆https://github.com/mkyong/core-java
$ cd java-xml
$ CD src/main/Java/com/mkyong/XML/DOM/
5。参考文献
- 维基百科–文档对象模型
- Oracle–文档对象模型
- 如何在 Java 中读取 XML 文件—(DOM 解析器)
- 如何用 Java 编写 XML 文件—(DOM 解析器)
- 如何在 Java 中读取 XML 文件—(SAX 解析器)
- 如何在 Java 中读取 XML 文件—(JDOM 解析器)
- JAXB hello world 示例
如何在 Java 中计算 XML 元素
本文展示了如何使用 DOM 解析器、 SAX 解析器和 XPath 来计算 Java 中指定 XML 元素的数量。
目录
用 Java 11 测试。
1。一个 XML 文件
下面是一个测试用的 XML 文件,后面所有的例子都会统计称为“staff”的 XML 元素的个数,输出是 2。
src/main/resources/staff.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 元素(DOM 解析器)
// DOM APIs
NodeList list = doc.getElementsByTagName("staff");
System.out.println(list.getLength()); // 2
下面是一个完整的 DOM 解析器示例,用来计算 XML 文件中“staff”元素的数量。
CountElementXmlDomParser.java
package com.mkyong.xml.dom;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CountElementXmlDomParser {
private static final String FILENAME = "src/main/resources/staff.xml";
public static void main(String[] args) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try (InputStream is = new FileInputStream(FILENAME)) {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
// get all elements known as "staff"
NodeList list = doc.getElementsByTagName("staff");
System.out.println("Number of staff elements : " + list.getLength());
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
输出
Terminal
Number of staff elements : 2
3。计数 XML 元素(XPath)
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList)
xpath.evaluate("//staff", doc, XPathConstants.NODESET);
int count = nodes.getLength();
下面是一个完整的 DOM 和 XPath 示例,用来计算 XML 文件中“staff”元素的数量。
CountElementXmlDomXPath.java
package com.mkyong.xml.dom;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CountElementXmlDomXPath {
private static final String FILENAME = "src/main/resources/staff.xml";
public static void main(String[] args) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try (InputStream is = new FileInputStream(FILENAME)) {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
// get all elements known as "staff"
// xpath
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList)
xpath.evaluate("//staff", doc, XPathConstants.NODESET);
int count = nodes.getLength();
System.out.println("Number of staff elements : " + count);
} catch (ParserConfigurationException | SAXException |
IOException | XPathExpressionException e) {
e.printStackTrace();
}
}
}
输出
Terminal
Number of staff elements : 2
4。统计 XML 元素(SAX 解析器)
下面是一个完整的 SAX 解析器示例,用来计算 XML 文件中“staff”元素的数量。
4.1 我们可以创建一个 SAX 处理程序,并计算startElement()
方法中的元素。
CountElementHandlerSax.java
package com.mkyong.xml.sax.handler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class CountElementHandlerSax extends DefaultHandler {
private final String elementName;
private Integer count = 0;
public String getElementName() {
return elementName;
}
public Integer getCount() {
return count;
}
public CountElementHandlerSax(String elementName) {
this.elementName = elementName;
}
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
if (qName.equalsIgnoreCase(getElementName())) {
count++;
}
}
}
4.2 用上面的CountElementHandlerSax
运行 SAX 解析器。
ReadXmlSaxParser.java
package com.mkyong.xml.sax;
import com.mkyong.xml.sax.handler.CountElementHandlerSax;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
public class ReadXmlSaxParser {
private static final String FILENAME = "src/main/resources/staff.xml";
public static void main(String[] args) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
SAXParser saxParser = factory.newSAXParser();
// count elements name known as "staff"
CountElementHandlerSax countStaffHandler =
new CountElementHandlerSax("staff");
saxParser.parse(FILENAME, countStaffHandler);
System.out.println("Number of staff elements : "
+ countStaffHandler.getCount());
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
输出
Terminal
Number of staff elements : 2
5。下载源代码
$ git 克隆https://github.com/mkyong/core-java
$ cd java-xml
$ CD src/main/Java/com/mkyong/XML/DOM/
$ CD src/main/Java/com/mkyong/XML/sax/
6。参考文献
- 维基百科–DOM(文档对象模型)
- 维基百科–SAX(XML 简单应用编程接口)
- 维基百科–XPath
- Oracle–文档对象模型
- 如何在 Java 中读取 XML 文件—(DOM 解析器)
- 如何在 Java 中读取 XML 文件—(SAX 解析器)
- JAXB hello world 示例
- 如何统计 XML 文档的深度(DOM 解析器)
maven——如何创建 Java 项目
在本教程中,我们将向您展示如何使用 Maven 来管理 Java 项目——创建、添加依赖项并将 Java 项目打包到可执行的 jar 文件中。最后,我们将创建一个可执行的 jar 文件,用 SHA-256 算法散列一个给定的字符串。
使用的技术:
- Maven 3.5.3
- JDK 8
- Apache Commons 编解码器 1.11
1.从 Maven 模板创建项目
在终端(*uix 或 Mac)或命令提示符(Windows)中,导航到要创建 Java 项目的文件夹。键入以下命令:
mvn archetype:generate
-DgroupId={project-packaging}
-DartifactId={project-name}
-DarchetypeArtifactId={maven-template}
-DinteractiveMode=false
这告诉 Maven 从一个 Maven 模板生成一个 Java 项目。举个例子,
D:\>mvn archetype:generate -DgroupId=com.mkyong.hashing -DartifactId=java-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.992 s
[INFO] Finished at: 2018-09-27T17:15:57+08:00
[INFO] ------------------------------------------------------------------------
上面的命令将从maven-archetype-quickstart
模板生成一个 Java 项目。
2.Maven 目录布局
将创建以下项目目录结构。简而言之,源代码放在文件夹/src/main/java/
,单元测试代码放在/src/test/java/
。
P.S 上图是从 IntelliJ IDEA 抓取的,只需忽略那些.idea
文件夹。
Note
Read this Maven standard directory layout.
3.POM 文件
查看生成的pom.xml
。它很空,只有一个 jUnit 依赖项。
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.hashing</groupId>
<artifactId>java-project3</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>java-project</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
这个 POM 文件就像 Ant build.xml
文件,它描述了整个项目的信息,从目录结构,项目插件,项目依赖,如何构建这个项目等等,阅读这个官方 POM 指南。
4.更新 POM
4.1 添加编译器属性,告诉 Maven 使用指定的 JDK 版本来编译源代码。
<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>
</properties>
4.2 将 jUnit 更新到 4.12
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
4.3 为 SHA 哈希增加commons-codec
。
<!-- Dependency for hashing -->
<!-- https://search.maven.org/artifact/commons-codec/commons-codec/1.11/jar -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
4.4 完整的更新版本。
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.hashing</groupId>
<artifactId>java-project</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>java-project</name>
<url>http://maven.apache.org</url>
<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>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
</project>
5.写代码
5.1 更新App.java
以接受一个输入,并用阿沙-256 算法对其进行哈希运算。
App.java
package com.mkyong.hashing;
import org.apache.commons.codec.digest.DigestUtils;
public class App {
public static void main(String[] args) {
if (args.length < 1) {
System.err.println("Please provide an input!");
System.exit(0);
}
System.out.println(sha256hex(args[0]));
}
public static String sha256hex(String input) {
return DigestUtils.sha256Hex(input);
}
}
5.2 单元测试。
AppTest.java
package com.mkyong.hashing;
import org.junit.Assert;
import org.junit.Test;
public class AppTest {
private String INPUT = "123456";
@Test
public void testLength() {
Assert.assertEquals(64, App.sha256hex(INPUT).length());
}
@Test
public void testHex() {
String expected = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92";
Assert.assertEquals(expected, App.sha256hex(INPUT));
}
}
完成了。
6.Maven 构建
6.1 让我们用mvn package
来建造它
D:\java-project>mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< com.mkyong.hashing:java-project >-------------------
[INFO] Building java-project 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
......
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.mkyong.hashing.AppTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.067 sec
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ java-project ---
[INFO] Building jar: D:\java-project\target\java-project-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.956 s
[INFO] Finished at: 2018-09-28T12:40:18+08:00
[INFO] ------------------------------------------------------------------------
它编译、运行单元测试并将项目打包成一个jar
文件,并将其放入project/target
文件夹。
7.运行#1
7.1 运行它。哎呀…默认情况下,Maven 没有将项目依赖关系commons-codec
添加到 jar 文件中。
D:\java-project>java -cp target/java-project-1.0-SNAPSHOT.jar com.mkyong.hashing.App 123456
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/codec/digest/DigestUtils
at com.mkyong.hashing.App.sha256hex(App.java:18)
at com.mkyong.hashing.App.main(App.java:13)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.codec.digest.DigestUtils
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
... 2 more
7.2 为了解决这个问题,我们可以使用这个maven-shade-plugin
来创建一个 Uber/fat-jar——将所有的东西组合到一个 jar 文件中。
pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- Attach the shade goal into the package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
7.3 再包一次!
D:\java-project>mvn clean package
[INFO] Scanning for projects...
[...
[INFO] --- maven-shade-plugin:3.2.0:shade (default) @ java-project ---
[INFO] Including commons-codec:commons-codec:jar:1.11 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing D:\java-project\target\java-project-1.0-SNAPSHOT.jar
with D:\java-project\target\java-project-1.0-SNAPSHOT-shaded.jar
...
将生成两个 jar,检查文件大小:
D:\java-project>dir target
Volume in drive D is Samsung970
Volume Serial Number is 10DF-E63D
Directory of D:\java-project\target
28/09/2018 12:57 PM 335,643 java-project-1.0-SNAPSHOT.jar
28/09/2018 12:57 PM 3,053 original-java-project-1.0-SNAPSHOT.jar
...
8.运行#2
8.1 再运行一次。好,结果在意料之中。
D:\java-project>java -cp target/java-project-1.0-SNAPSHOT.jar com.mkyong.hashing.App 123456
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
8.2 我们能像 Jar 一样运行它吗?不,没有主类。
D:\java-project>java -jar target/java-project-1.0-SNAPSHOT.jar 123456
no main manifest attribute, in target/java-project-1.0-SNAPSHOT.jar
8.3 要解决它,像这样在maven-shade-plugin
中添加主类。
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- Attach the shade into the package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.mkyong.hashing.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
9.运行#3
9.1 再包一次!
D:\java-project>mvn clean package
9.2 将它作为 Jar 运行。
D:\java-project>java -jar target/java-project-1.0-SNAPSHOT.jar 123456
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
完成了。
10.砰的一声
最终 POM 文件。
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.hashing</groupId>
<artifactId>java-project</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>java-project</name>
<url>http://maven.apache.org</url>
<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>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- Attach the shade into the package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.mkyong.hashing.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
下载源代码
$ git clone https://github.com/mkyong/maven-examples.git
$ cd java-project
$ mvn package
$ java -jar target/java-project-1.0-SNAPSHOT.jar 123456
参考
- Maven–如何创建 Java web 应用项目
- 阿帕奇 Maven 项目
- 一个简单的 Maven 项目
- Java SHA 哈希示例
- 如何创建一个 Jar 文件,thin-jar 示例
- 创建一个 fat Jar 文件——一个 Jar 示例
- 创建一个胖罐子文件——Maven Shade 插件示例
如何用 jQuery 创建表格斑马条纹效果
下面是一个简单的例子,展示了如何用 jQuery 创建一个表格斑马条纹效果。
<html>
<head>
<title>jQuery Zebra Stripes</title>
</head>
<script type="text/javascript" src="jquery-1.2.6.min.js"></script>
<script type="text/javascript">
$(function() {
$("table tr:nth-child(even)").addClass("striped");
});
</script>
<style type="text/css">
body,td {
font-size: 10pt;
}
table {
background-color: black;
border: 1px black solid;
border-collapse: collapse;
}
th {
border: 1px outset silver;
background-color: maroon;
color: white;
}
tr {
background-color: white;
margin: 1px;
}
tr.striped {
background-color: coral;
}
td {
padding: 1px 8px;
}
</style>
<body>
<table>
<tr>
<th>ID</th>
<th>Fruit</th>
<th>Price</th>
</tr>
<tr>
<td>1</td>
<td>Apple</td>
<td>0.60</td>
</tr>
<tr>
<td>2</td>
<td>Orange</td>
<td>0.50</td>
</tr>
<tr>
<td>3</td>
<td>Banana</td>
<td>0.10</td>
</tr>
<tr>
<td>4</td>
<td>strawberry</td>
<td>0.05</td>
</tr>
<tr>
<td>5</td>
<td>carrot</td>
<td>0.10</td>
</tr>
</table>
</body>
</html>
在 jQuery 中,表格斑马条纹效果是通过一条语句实现的。
$(function() {
$("table tr:nth-child(even)").addClass("striped");
});
P.S 第 n 个孩子(偶数)”)。addClass(“striped”) =每个偶数行动态添加" striped" CSS 类。
如何用 jQuery 创建工具提示
这里有一个用 jQuery 创建工具提示消息的简单想法。
想法…
- 确定需要显示工具提示信息的“目标”。
- 为它创建一个工具提示消息和 CSS 样式。
- 三个功能,-显示工具提示,隐藏工具提示,改变工具提示位置。
- 当鼠标进入目标时,使用显示工具提示显示工具提示信息,并用改变工具提示位置初始化位置。
- 当鼠标在“目标周围移动时,用changetooltipposition不断改变工具提示信息的位置。
- 当鼠标离开“目标”时,使用 hideTooltips 隐藏工具提示消息。
- 使用 jQuery 来完成🙂
1.目标
“提示”和“用户名标签”是显示工具提示消息的目标。
<label id="username">Username : </label><input type="text" / size="50">
<span id="hint">hint (mouseover me)</span>
2.工具提示 CSS
为工具提示消息创建 CSS 样式。
.tooltip{
margin:8px;
padding:8px;
border:1px solid blue;
background-color:yellow;
position: absolute;
z-index: 2;
}
3.显示工具提示
将工具提示消息附加到“body”标签上,并在工具提示消息的位置上签名。
var showTooltip = function(event) {
$('div.tooltip').remove();
$('<div class="tooltip">I\' am tooltips! tooltips! tooltips! :)</div>')
.appendTo('body');
changeTooltipPosition(event);
};
5.更改工具提示
更改工具提示消息的位置。
var changeTooltipPosition = function(event) {
var tooltipX = event.pageX - 8;
var tooltipY = event.pageY + 8;
$('div.tooltip').css({top: tooltipY, left: tooltipX});
};
6.隐藏工具提示
隐藏工具提示消息。
var hideTooltip = function() {
$('div.tooltip').remove();
};
7.捆绑它
将鼠标事件绑定到目标。
$("span#hint,label#username'").bind({
mousemove : changeTooltipPosition,
mouseenter : showTooltip,
mouseleave: hideTooltip
});
你自己试试
在本例中,将鼠标放在提示或标签上以显示工具提示效果。
<html>
<head>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<style type="text/css">
#hint{
cursor:pointer;
}
.tooltip{
margin:8px;
padding:8px;
border:1px solid blue;
background-color:yellow;
position: absolute;
z-index: 2;
}
</style>
</head>
<body>
<h1>jQuery tooltips example</h1>
<label id="username">Username : </label><input type="text" / size="50">
<span id="hint">hint (mouseover me)</span>
<script type="text/javascript">
$(document).ready(function() {
var changeTooltipPosition = function(event) {
var tooltipX = event.pageX - 8;
var tooltipY = event.pageY + 8;
$('div.tooltip').css({top: tooltipY, left: tooltipX});
};
var showTooltip = function(event) {
$('div.tooltip').remove();
$('<div class="tooltip">I\' am tooltips! tooltips! tooltips! :)</div>')
.appendTo('body');
changeTooltipPosition(event);
};
var hideTooltip = function() {
$('div.tooltip').remove();
};
$("span#hint,label#username'").bind({
mousemove : changeTooltipPosition,
mouseenter : showTooltip,
mouseleave: hideTooltip
});
});
</script>
</body>
</html>
maven——如何创建 Java web 应用程序项目
在本教程中,我们将向您展示如何使用 Maven 来管理 Java web 项目。最后,我们将创建一个 Spring MVC web 应用程序,在 JSP 页面上显示当前日期。
使用的技术:
- Maven 3.5.3
- JDK 8
- 释放弹簧 5.1.0
- JUnit 5
- 回溯 1.2.3
- Jetty 9.4.x 或 Tomcat 8.5
1.从 Maven 模板创建一个 web 项目
从 Maven 模板创建一个 web 项目maven-archetype-webapp
mvn archetype:generate
-DgroupId={project-packaging}
-DartifactId={project-name}
-DarchetypeArtifactId={maven-template}
-DinteractiveMode=false
举个例子,
D:\>mvn archetype:generate -DgroupId=com.mkyong.web -DartifactId=java-web-project -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.0.1:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.0.1:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.0.1:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: D:\
[INFO] Parameter: package, Value: com.mkyong.web
[INFO] Parameter: groupId, Value: com.mkyong.web
[INFO] Parameter: artifactId, Value: java-web-project
[INFO] Parameter: packageName, Value: com.mkyong.web
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: D:\java-web-project
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.509 s
[INFO] Finished at: 2018-10-04T15:25:16+08:00
[INFO] ------------------------------------------------------------------------
Note
Actually, this is optional to generate a web project from a Maven web template. You can always generate those folders with the classic mkdir
command manually.
2.Maven 模板
2.1 将创建以下项目目录结构。
注:上图来自 IntelliJ IDEA,忽略掉那些 IDE 文件夹,比如.idea``java-web-project.iml
2.2 审核生成的pom.xml
。
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.web</groupId>
<artifactId>java-web-project</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>java-web-project Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>java-web-project</finalName>
</build>
</project>
P.S 生成的文件没什么价值,我们以后会全部更新。首先删除web.xml
,我们不需要这个。
3.更新 POM
3.1 更新pom.xml
文件,添加 Spring MVC for web framework、JUnit for unit test、Jetty server to test the web project 的依赖项,还有一些 Maven 配置。
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.web</groupId>
<artifactId>java-web-project</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>java-web-project Maven Webapp</name>
<url>http://maven.apache.org</url>
<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>
<spring.version>5.1.0.RELEASE</spring.version>
</properties>
<dependencies>
<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>
<!-- junit 5, unit test -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<!-- unit test -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<!-- for web servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Some containers like Tomcat don't have jstl library -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>java-web-project</finalName>
<plugins>
<!-- http://www.eclipse.org/jetty/documentation/current/jetty-maven-plugin.html -->
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.12.v20180830</version>
</plugin>
<!-- Default is too old, update to latest to run the latest Spring 5 + jUnit 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
<!-- Default 2.2 is too old, update to latest -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
</plugins>
</build>
</project>
3.2 显示项目依赖关系。
D:\> mvn dependency:tree
...
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ java-web-project ---
[INFO] com.mkyong.web:java-web-project:war:1.0-SNAPSHOT
[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-context: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.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.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] \- javax.servlet:jstl:jar:1.2:provided
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.931 s
[INFO] Finished at: 2018-10-08T15:55:08+08:00
[INFO] ------------------------------------------------------------------------
4.Spring MVC + JSP + LogBack
4.1 创建几个文件来引导 Spring MVC web 项目。
SpringConfig.java
package com.mkyong.web.config;
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.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
@EnableWebMvc
@Configuration
@ComponentScan({"com.mkyong.web"})
public class SpringConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver
= new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Date;
@Controller
public class WelcomeController {
private final Logger logger = LoggerFactory.getLogger(WelcomeController.class);
@GetMapping("/")
public String index(Model model) {
logger.debug("Welcome to mkyong.com...");
model.addAttribute("msg", getMessage());
model.addAttribute("today", new Date());
return "index";
}
private String getMessage() {
return "Hello World";
}
}
4.2 将index.jsp
文件移动到WEB-INF
文件夹中,并进行更新
index.jsp
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<html>
<body>
<h1>${msg}</h1>
<h2>Today is <fmt:formatDate value="${today}" pattern="yyy-MM-dd" /></h2>
</body>
</html>
4.3 记录到控制台。
logbacl.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<logger name="com.mkyong.web" level="debug"
additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<root level="error">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
5.单元测试
一个简单的 Spring MVC 5 + JUnit 5 例子。
TestWelcome.java
package com.mkyong.web;
import com.mkyong.web.config.SpringConfig;
import org.junit.jupiter.api.BeforeEach;
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.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringJUnitWebConfig(SpringConfig.class)
public class TestWelcome {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webAppContext;
@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();
}
@Test
public void testWelcome() throws Exception {
this.mockMvc.perform(
get("/"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andExpect(forwardedUrl("/WEB-INF/views/index.jsp"))
.andExpect(model().attribute("msg", "Hello World"));
}
}
6.目录结构
查看最终文件和目录结构。
看这个 Maven 标准目录布局。
7.演示
7.1 使用 Jetty web 服务器测试 web 项目—mvn jetty:run
D:\> mvn jetty:run
[INFO] webAppSourceDirectory not set. Trying src\main\webapp
[INFO] Reload Mechanic: automatic
[INFO] nonBlocking:false
[INFO] Classes = D:\java-web-project\target\classes
[INFO] Configuring Jetty for project: java-web-project Maven Webapp
[INFO] Logging initialized @4821ms to org.eclipse.jetty.util.log.Slf4jLog
[INFO] Context path = /
[INFO] Tmp directory = D:\java-web-project\target\tmp
[INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
[INFO] Web overrides = none
[INFO] web.xml file = null
[INFO] Webapp directory = D:\java-web-project\src\main\webapp
[INFO] jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 10.0.1+10
...
[INFO] 1 Spring WebApplicationInitializers detected on classpath
2018-10-08 15:11:50 [main] DEBUG com.mkyong.web.WebInitializer - No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context
[INFO] DefaultSessionIdManager workerName=node0
[INFO] No SessionScavenger set, using defaults
[INFO] node0 Scavenging every 660000ms
[INFO] Initializing Spring DispatcherServlet 'dispatcher'
[INFO] Started o.e.j.m.p.JettyWebAppContext@68a78f3c{/,file:///D:/java-web-project/src/main/webapp/,AVAILABLE}{file:///D:/java-web-project/src/main/webapp/}
[INFO] Started ServerConnector@3355168{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
[INFO] Started @6271ms
[INFO] Started Jetty Server
2018-10-08 15:12:01 [qtp1373051324-19] DEBUG c.m.web.controller.WelcomeController - Welcome to mkyong.com...
7.2 通过 http://localhost:8080/ 访问
P.S CTRL + C 停止 Jetty web 服务器。
8.部署
8.1 mvn package
生成 WAR 文件进行部署。
D:\> mvn package
...
[INFO] Packaging webapp
[INFO] Assembling webapp [java-web-project] in [D:\java-web-project\target\java-web-project]
[INFO] Processing war project
[INFO] Copying webapp resources [D:\java-web-project\src\main\webapp]
[INFO] Webapp assembled in [89 msecs]
[INFO] Building war: D:\java-web-project\target\java-web-project.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.844 s
[INFO] Finished at: 2018-10-08T15:31:12+08:00
[INFO] ------------------------------------------------------------------------
生成的 WAR 的默认目录是target/finalName
。完成了。
下载源代码
$ git clone https://github.com/mkyong/maven-examples.git
$ cd java-web-project
$ mvn jetty:run
http://localhost:8080
参考
- Maven Surefire 插件——使用 JUnit 5 平台
- Maven–列出项目的所有插件
- Maven–标准目录布局简介
- Apache Tomcat Maven 插件
- Maven——如何创建一个 Java 项目
- 春季 MVC 教程
Tags : jetty junit 5 maven spring mvc web project
如何用 Java 创建目录
原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-create-directory-in-java/
在 Java 中,我们可以使用 NIO Files.createDirectory
创建一个目录,或者使用Files.createDirectories
创建一个包含所有不存在的父目录的目录。
try {
Path path = Paths.get("/home/mkyong/a/b/c/");
//java.nio.file.Files;
Files.createDirectories(path);
System.out.println("Directory is created!");
} catch (IOException e) {
System.err.println("Failed to create directory!" + e.getMessage());
}
1.创建目录–Java NIO
1.1 我们可以使用Files.createDirectory
来创建一个目录。
- 如果父目录不存在,抛出
NoSuchFileException
。 - 如果目录存在,抛出
FileAlreadyExistsException
。 - 如果 IO 出错,抛出
IOException
。
Path path = Paths.get("/home/mkyong/test2/");
Files.createDirectory(path);
1.2 我们可以使用Files.createDirectories
创建一个包含所有不存在的父目录的目录。
- 如果父目录不存在,请先创建它。
- 如果目录存在,不会引发异常。
- 如果 IO 出错,抛出
IOException
Path path = Paths.get("/home/mkyong/test2/test3/test4/");
Files.createDirectories(path);
1.3 这个例子使用Files.createDirectories
创建一个目录/test4/
,其中包含所有不存在的父目录/test2/test3/
。
DirectoryCreate1.java
package com.mkyong.io.directory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class DirectoryCreate1 {
public static void main(String[] args) {
String dir = "/home/mkyong/test2/test3/test4/";
try {
Path path = Paths.get(file);
Files.createDirectories(path);
System.out.println("Directory is created!");
//Files.createDirectory(path);
} catch (IOException e) {
System.err.println("Failed to create directory!" + e.getMessage());
}
}
}
2.创建目录-传统 IO
对于遗留 IO java.io.File
,类似的方法是file.mkdir()
创建一个目录,file.mkdirs()
创建一个包含所有不存在的父目录的目录。
file.mkdir()
和file.mkdirs()
都返回一个布尔值,如果成功创建目录,则为真,否则为假,不抛出异常。
DirectoryCreate2.java
package com.mkyong.io.directory;
import java.io.File;
public class DirectoryCreate2 {
public static void main(String[] args) {
String dir = "/home/mkyong/test2/test3/test4/";
File file = new File(dir);
// true if the directory was created, false otherwise
if (file.mkdirs()) {
System.out.println("Directory is created!");
} else {
System.out.println("Failed to create directory!");
}
}
}
在传统 IO 中,创建目录时缺少抛出异常,这使得开发人员很难调试或理解为什么我们不能创建目录,这也是 Java 发布新的java.nio.Files
来抛出适当异常的原因之一。
下载源代码
$ git 克隆https://github.com/mkyong/core-java
$ cd java-io