Mkyong 中文博客翻译(十三)

原文:Mkyong

协议:CC BY-NC-SA 4.0

如何在 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 复制目录的几种常用方法。

  1. FileVisitor (Java 7+)
  2. FileUtils.copyDirectory(Apache common-io)
  3. 使用 Java 7 NIO 和 Java 8 Stream 进行自定义复制。
  4. 自定义副本,传统 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 中复制文件

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-copy-file-in-java/

本文展示了用 Java 复制文件的四种方法。

  1. Files.copy
  2. Apache commons me(Apache 公用程式)
  3. 番石榴
  4. 普通爪哇咖啡

在 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 InputStreamOutputStream来复制一个文件。

 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 解析器)

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-count-the-depth-of-xml-document-dom-example/

在 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。参考文献

如何在 Java 中计算 XML 元素

原文:http://web.archive.org/web/20230101150211/https://mkyong.com/java/how-to-count-xml-elements-in-java-dom-parser/

本文展示了如何使用 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。参考文献

maven——如何创建 Java 项目

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/how-to-create-a-java-project-with-maven/

在本教程中,我们将向您展示如何使用 Maven 来管理 Java 项目——创建、添加依赖项并将 Java 项目打包到可执行的 jar 文件中。最后,我们将创建一个可执行的 jar 文件,用 SHA-256 算法散列一个给定的字符串。

使用的技术:

  1. Maven 3.5.3
  2. JDK 8
  3. 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

参考

  1. Maven–如何创建 Java web 应用项目
  2. 阿帕奇 Maven 项目
  3. 一个简单的 Maven 项目
  4. Java SHA 哈希示例
  5. 如何创建一个 Jar 文件,thin-jar 示例
  6. 创建一个 fat Jar 文件——一个 Jar 示例
  7. 创建一个胖罐子文件——Maven Shade 插件示例

如何用 jQuery 创建表格斑马条纹效果

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-create-a-table-zebra-stripes-effect-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 类。

Try Demo

如何用 jQuery 创建工具提示

原文:http://web.archive.org/web/20230101150211/http://www.mkyong.com/jquery/how-to-create-a-tooltips-with-jquery/

这里有一个用 jQuery 创建工具提示消息的简单想法。

想法…

  1. 确定需要显示工具提示信息的“目标”。
  2. 为它创建一个工具提示消息和 CSS 样式。
  3. 三个功能,-显示工具提示隐藏工具提示改变工具提示位置
  4. 当鼠标进入目标时,使用显示工具提示显示工具提示信息,并用改变工具提示位置初始化位置。
  5. 当鼠标在“目标周围移动时,用changetooltipposition不断改变工具提示信息的位置。
  6. 当鼠标离开“目标”时,使用 hideTooltips 隐藏工具提示消息。
  7. 使用 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> 

http://web.archive.org/web/20220118011614if_/https://www.mkyong.com/wp-content/uploads/jQuery/jQuery-tooltips-example.html

Try Demo

maven——如何创建 Java web 应用程序项目

原文:http://web.archive.org/web/20230101150211/https://www.mkyong.com/maven/how-to-create-a-web-application-project-with-maven/

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本教程中,我们将向您展示如何使用 Maven 来管理 Java web 项目。最后,我们将创建一个 Spring MVC web 应用程序,在 JSP 页面上显示当前日期。

使用的技术:

  1. Maven 3.5.3
  2. JDK 8
  3. 释放弹簧 5.1.0
  4. JUnit 5
  5. 回溯 1.2.3
  6. 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

参考

  1. Maven Surefire 插件——使用 JUnit 5 平台
  2. Maven–列出项目的所有插件
  3. Maven–标准目录布局简介
  4. Apache Tomcat Maven 插件
  5. Maven——如何创建一个 Java 项目
  6. 春季 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

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值